کنترل رسانه از طریق MediaSession

1. مقدمه

آخرین به روز رسانی: 09-09-2020

مزایای اضافه کردن MediaSession در زمینه پخش ویدیو چیست؟

جلسات رسانه پیوندی جدایی ناپذیر بین پلتفرم اندروید و برنامه های رسانه ای هستند. نه تنها به Android اطلاع می دهد که رسانه در حال پخش است - به طوری که می تواند اقدامات رسانه ای را به جلسه صحیح ارسال کند - بلکه به پلتفرم اطلاع می دهد که چه چیزی در حال پخش است و چگونه می توان آن را کنترل کرد.

نمایش MediaSession از طریق برنامه شما مزایای مختلفی دارد که کاربران از آن لذت خواهند برد. در اینجا چند نمونه عالی آورده شده است.

دستیار گوگل

کاربران به راحتی می توانند از طریق دستورات صوتی مانند "مکث"، "ازسرگیری" و "بعدی" با رسانه های موجود در برنامه شما تعامل داشته باشند. همچنین می‌توان از فراداده‌های رسانه‌تان برای دریافت پاسخ‌هایی درباره آنچه در حال پخش است استفاده کرد.

Android TV

در تجربه‌هایی با صفحه نمایش بزرگ، برنامه Android TV شما می‌تواند از کنترل‌های از راه دور معمولی برای کاربرانی که تلویزیون‌هایی از HDMI-CEC پشتیبانی می‌کنند استفاده کند. دستورات صادر شده توسط دکمه های پخش/مکث، توقف، بعدی و قبلی به برنامه شما منتقل می شود.

کنترل های رسانه روی صفحه

با شروع Android 4.0 (سطح API 14)، این سیستم می‌تواند به وضعیت پخش و فراداده یک جلسه رسانه دسترسی داشته باشد. این عملکرد صفحه قفل را قادر می سازد تا کنترل های رسانه و آثار هنری را نمایش دهد. این رفتار بسته به نسخه اندروید متفاوت است.

رسانه پس زمینه

رسانه ها را می توان در هر یک از این سناریوها کنترل کرد، حتی اگر برنامه پخش کننده رسانه در پس زمینه اجرا شود.

محاسبات محیطی

افشای رسانه خود با داده‌هایی درباره آنچه در حال پخش است و نحوه کنترل آن می‌تواند بین دستگاه‌ها پل ارتباطی برقرار کند تا کاربران بتوانند به روش‌های مختلف با آن تعامل داشته باشند.

چیزی که خواهی ساخت

در این کد لبه، شما قصد دارید نمونه Exoplayer موجود را گسترش دهید تا پشتیبانی جلسه رسانه را اضافه کنید. برنامه شما:

  • وضعیت فعال جلسه رسانه را به درستی منعکس کنید
  • کنترل‌های رسانه را به ExoPlayer منتقل کنید
  • ابرداده موارد موجود در صف را به جلسه رسانه ارسال کنید

چیزی که یاد خواهید گرفت

  • چرا جلسات رسانه تجربه غنی تری را به کاربران ارائه می دهند
  • نحوه ایجاد یک جلسه رسانه و مدیریت وضعیت آن
  • نحوه اتصال یک جلسه رسانه به ExoPlayer
  • نحوه گنجاندن ابرداده موارد در صف پخش در جلسه رسانه
  • نحوه اضافه کردن اقدامات اضافی (سفارشی)

این کد لبه روی MediaSession SDK تمرکز دارد. مفاهیم غیر مرتبط و بلوک‌های کد، از جمله جزئیات مربوط به پیاده‌سازی ExoPlayer، مورد بحث قرار نگرفته‌اند، اما برای شما ارائه شده‌اند تا به سادگی کپی و جای‌گذاری کنید.

آنچه شما نیاز دارید

  • نسخه اخیر Android Studio (3.5 یا بالاتر)
  • دانش اولیه توسعه برنامه های اندروید

2. راه اندازی

نقطه شروع ما چیست؟

نقطه شروع ما نسخه ی نمایشی اصلی از ExoPlayer است. این نسخه نمایشی حاوی ویدیوهایی با کنترل‌های پخش روی صفحه است، اما از جلسات رسانه خارج از جعبه استفاده نمی‌کند. این یک مکان عالی برای ما برای شیرجه رفتن و اضافه کردن آنها است!

نمونه ExoPlayer را دریافت کنید

برای شروع، اجازه دهید با نمونه ExoPlayer شروع کنیم. با اجرای کد زیر، مخزن GitHub را کلون کنید.

git clone https://github.com/google/ExoPlayer.git

دمو را باز کنید

در Android Studio، پروژه آزمایشی اصلی را که در زیر demos/main قرار دارد باز کنید.

Android Studio از شما می خواهد که مسیر SDK را تنظیم کنید. اگر با مشکلی مواجه شدید، ممکن است بخواهید توصیه‌های مربوط به به‌روزرسانی ابزارهای IDE و SDK را دنبال کنید.

10e3b5c652186d57.png

اگر از شما خواسته شد از آخرین نسخه Gradle استفاده کنید، آن را به روز کنید.

چند لحظه وقت بگذارید تا درک اولیه ای از نحوه طراحی برنامه به دست آورید. توجه داشته باشید که دو فعالیت وجود دارد: SampleChooserActivity و PlayerActivity. ما باقیمانده از Codelab را در PlayerActivity می گذرانیم، جایی که رسانه در واقع پخش می شود، بنابراین این کلاس را باز کنید و به بخش بعدی بروید.

3. یک جلسه رسانه ایجاد کنید و وضعیت آن را مدیریت کنید

جلسه رسانه ای ایجاد کنید

PlayerActivity.java را باز کنید. این کلاس ExoPlayer را ایجاد می کند و عملکردهای آن را مدیریت می کند، مانند رندر کردن ویدیو روی صفحه. در این فعالیت، ExoPlayer را به یک جلسه رسانه متصل خواهیم کرد.

دو فیلد زیر را در بالای کلاس اعلام کنید. ما از این فیلدها در سراسر این بخش استفاده خواهیم کرد.

private MediaSessionCompat mediaSession;
private MediaSessionConnector mediaSessionConnector;

شما باید وابستگی پروژه "extension-mediasession" را به build.gradle سطح ماژول برای "Module: demo" اضافه کنید:

implementation project(path: ':extension-mediasession')

توجه داشته باشید که اگر در حل MediaSessionConnector خطا را روی آن قرار دهید، Android Studio می‌تواند در افزودن خودکار این وابستگی به شما کمک کند:

60055e4ad54fbb97.png

در نهایت، وارد کردن کلاس را با اضافه کردن موارد زیر حل کنید:

import android.support.v4.media.session.MediaSessionCompat;
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;

وقتی اکتیویتی ایجاد شد، می خواهیم یک جلسه رسانه و یک رابط جلسه رسانه ایجاد کنیم که به عنوان واسطه بین جلسه رسانه و ExoPlayer عمل می کند.

مکان ایده آل برای درج این مکان جایی است که ExoPlayer نیز ایجاد می شود. در برنامه آزمایشی خود، می‌توانیم کد خود را به انتهای initializePlayer() اضافه کنیم. مطمئن شوید که این منطق را بعد از نمونه سازی بازیکن اضافه کنید!

private void initializePlayer() {
  if (player == null) {
    ...
    player = ...
    ...
    mediaSession = new MediaSessionCompat(this, "sample");
    mediaSessionConnector = new MediaSessionConnector(mediaSession);
    mediaSessionConnector.setPlayer(player);
  }
  ...
}

جلسه رسانه را منتشر کنید

هنگامی که دیگر نیازی به جلسه رسانه نیست، آن را آزاد کنید. وقتی ExoPlayer را در releasePlayer() منتشر می‌کنیم، می‌توانیم کد زیر را نیز برای این کار اضافه کنیم:

private void releasePlayer() {
  if (mediaSession != null) {
    mediaSession.release();
  }
  ...
}

وضعیت جلسه رسانه را مدیریت کنید

اکنون که جلسه رسانه را نمونه‌سازی کرده‌ایم، باید مطمئن شویم که وضعیت آن به‌طور صحیح در تعامل کاربر با فعالیت منعکس می‌شود.

هنگامی که کاربر فعالیت را شروع می کند، جلسه رسانه باید فعال شود:

@Override
public void onStart() {
  ...
  if (mediaSession != null) {
    mediaSession.setActive(true);
  }
}

از آنجایی که برنامه ما رسانه را در پس‌زمینه پخش نمی‌کند، اطمینان از غیرفعال شدن جلسه رسانه با خروج کاربر از فعالیت ضروری است:

@Override
public void onStop() {
  super.onStop();
  if (mediaSession != null) {
    mediaSession.setActive(false);
  }
  ...
}

بیایید نسخه ی نمایشی را اجرا کنیم

  1. یک دستگاه Android را ضمیمه کنید یا یک شبیه ساز راه اندازی کنید.
  2. مطمئن شوید که "دمو" برای اجرا از نوار ابزار Android Studio انتخاب شده است. cb1ec4e50886874f.png
  3. کلیک کنید 9d8fb3a9ddf12827.png از نوار ابزار Android Studio.
  4. هنگامی که برنامه در دستگاه شما راه اندازی شد، یک جریان ویدیویی را برای پخش انتخاب کنید.
  5. پس از شروع پخش، با استفاده از دستورات adb زیر برای کنترل جلسه رسانه کاوش کنید:
adb shell media dispatch pause
adb shell media dispatch play
adb shell media dispatch play-pause
adb shell media dispatch fast-forward
adb shell media dispatch rewind
  1. همچنین بررسی کنید که Android چگونه جلسه رسانه شما را می بیند. به طور خاص، می توانید با مشاهده فیلد اقدام بررسی کنید که کدام اقدامات پشتیبانی می شوند. عددی که در اینجا می بینید ترکیبی از شناسه های عمل است که در شی PlaybackState اعلام شده است. برای مشاهده اجرای جلسه رسانه: adb shell dumpsys media_session
  2. اگر از یک دستگاه فیزیکی با میکروفون استفاده می‌کنید، دستیار Google را فراخوانی کنید و دستورات صوتی مانند «مکث» را صادر کنید. "رزومه." "فست جلو 1 دقیقه."

b8dda02a6fb0f6a4.png نمونه ExoPlayer در حال اجرا در Android TV.

4. از جمله ابرداده موارد در صف پخش

اکنون می‌توانیم ویژگی‌های پشتیبانی‌شده از جلسه رسانه خود را در جایی که قبلا MediaSessionConnector خود را در initializePlayer() ایجاد کرده بودیم، گسترش دهیم.

اضافه کردن TimelineQueueNavigator

ExoPlayer ساختار رسانه را به عنوان یک جدول زمانی نشان می دهد. برای جزئیات بیشتر در مورد نحوه عملکرد، کمی وقت بگذارید و درباره شی Timeline ExoPlayer مطالعه کنید. با استفاده از این ساختار، می‌توانیم از تغییر محتوا مطلع شویم و در صورت درخواست، ابرداده‌هایی را که در حال حاضر پخش می‌شود، در معرض دید قرار دهیم.

برای انجام این کار، یک TimelineQueueNavigator تعریف می کنیم. نمونه سازی MediaSessionConnector را در initializePlayer() بیابید و پس از مقداردهی اولیه mediaSession یک پیاده سازی از TimelineQueueNavigator اضافه کنید.

mediaSessionConnector.setQueueNavigator(new TimelineQueueNavigator(mediaSession) {
  @Override
  public MediaDescriptionCompat getMediaDescription(Player player, int windowIndex) {
    return new MediaDescriptionCompat.Builder()
            .setTitle(player.getCurrentMediaItem().mediaMetadata.title)
            .setDescription("MediaDescription description for " + windowIndex)
            .setSubtitle("MediaDescription subtitle")
            .build();
  }
});

وارد کردن کلاس را با اضافه کردن حل کنید:

import android.support.v4.media.MediaDescriptionCompat;
import com.google.android.exoplayer2.ext.mediasession.TimelineQueueNavigator;

توجه داشته باشید که پارامتر windowIndex با آیتم آن شاخص در صف پخش مطابقت دارد.

اکنون که برخی از متادیتاها را اضافه کرده‌اید، می‌توانید آزمایش کنید که «دستیار» چه چیزی در حال پخش است را می‌فهمد. هنگام پخش یک ویدیو در Android TV، دستیار را فراخوانی کنید و بپرسید "What's playing?"

6c7fc0cb853cbc38.png

5. سفارشی کردن اقدامات

شاید پخش کننده شما از برخی اقدامات پشتیبانی نمی کند یا می خواهید برای کارهای بیشتری نیز پشتیبانی را در نظر بگیرید؟ بیایید اکنون کمی عمیق تر به جلسه رسانه ای که قبلا MediaSessionConnector خود را در initializePlayer() ایجاد کرده بودیم، بپردازیم.

اعلام اقدامات پشتیبانی شده

سعی کنید از mediaSessionConnector.setEnabledPlaybackActions() استفاده کنید تا اعمالی را که می خواهید جلسه رسانه پشتیبانی کند، سفارشی کنید.

توجه داشته باشید که مجموعه کامل به شرح زیر است:

mediaSessionConnector.setEnabledPlaybackActions(
        PlaybackStateCompat.ACTION_PLAY_PAUSE
                | PlaybackStateCompat.ACTION_PLAY
                | PlaybackStateCompat.ACTION_PAUSE
                | PlaybackStateCompat.ACTION_SEEK_TO
                | PlaybackStateCompat.ACTION_FAST_FORWARD
                | PlaybackStateCompat.ACTION_REWIND
                | PlaybackStateCompat.ACTION_STOP
                | PlaybackStateCompat.ACTION_SET_REPEAT_MODE
                | PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE
);

بیایید دوباره ببینیم که چگونه این داده ها در معرض پلتفرم قرار می گیرند:

  1. مانند قبل، یک ویدیو را شروع کنید.
  2. با اجرای: adb shell dumpsys media_session کاوش کنید که Android چگونه ابرداده‌های جلسه رسانه شما را می‌بیند
  3. خط حاوی فراداده را پیدا کنید و توجه کنید که عنوان و توضیحات با com.google.android.exoplayer2.demo/sample همراه و مرتبط هستند.

افزودن اقدامات اضافی

ما می توانیم جلسه رسانه ای خود را با برخی اقدامات اضافی گسترش دهیم. در این بخش، ما فقط برای زیرنویس ها پشتیبانی می کنیم.

پشتیبانی از زیرنویس

افزودن پشتیبانی از شرح‌ها به جلسات رسانه به کاربران امکان می‌دهد آنها را به صورت صوتی تغییر دهند. در جایی که اتصال دهنده جلسه رسانه را مقداردهی کرده اید، موارد زیر را اضافه کنید:

mediaSessionConnector.setCaptionCallback(new MediaSessionConnector.CaptionCallback() {
      @Override
      public void onSetCaptioningEnabled(Player player, boolean enabled) {
        Log.d("MediaSession", "onSetCaptioningEnabled: enabled=" + enabled);
      }

      @Override
      public boolean hasCaptions(Player player) {
        return true;
      }

      @Override
      public boolean onCommand(Player player, ControlDispatcher controlDispatcher, String command, Bundle extras, ResultReceiver cb) {
        return false;
      }
    }
);

در نهایت، هرگونه واردات گمشده را برطرف کنید.

می‌توانید این مورد را با فراخوانی دستیار Google در Android TV و گفتن «فعال کردن زیرنویس‌ها» آزمایش کنید. Logcat را برای پیام‌ها بررسی کنید تا ببینید چگونه این کد شما را فراخوانی می‌کند.

6. تبریک می گویم

تبریک می‌گوییم، شما با موفقیت جلسات رسانه‌ای را به نمونه اضافه کردید!

شما به مقدار قابل توجهی از قابلیت های زیر دست یافته اید:

  • افزودن یک جلسه رسانه،
  • اتصال جلسات رسانه به یک نمونه از ExoPlayer،
  • افزودن متادیتا و اقدامات اضافی

اکنون مراحل کلیدی مورد نیاز برای غنی سازی یک برنامه رسانه و ارائه تجربه همه کاره تر به کاربران را می دانید!

تذکر پایانی

این کد لبه بر روی نمونه ای از کد منبع ExoPlayer ساخته شده است. نیازی به استفاده از ExoPlayer از منبع نیست، و توصیه می‌شود در عوض وابستگی‌های ExoPlayer و MediaSessionConnector را حذف کنید تا راحت‌تر با آخرین نسخه‌ها به‌روز باشید.

برای انجام این کار، به سادگی وابستگی های پروژه مانند:

implementation project(modulePrefix + 'library-core')
implementation project(path: ':extension-mediasession')

برای کشیدن از مخازن Maven، مانند:

implementation 'com.google.android.exoplayer:exoplayer-core:2.+'
implementation 'com.google.android.exoplayer:extension-mediasession:2.+'

اسناد مرجع