التحكّم في الوسائط من خلال MediaSession

1. مقدمة

تاريخ آخر تعديل: 2020-09-09

ما هي مزايا إضافة MediaSession حول تشغيل الفيديو؟

تُعدّ جلسات الوسائط رابطًا أساسيًا بين نظام Android الأساسي وتطبيقات الوسائط. لا يقتصر دورها على إعلام Android بأنّه يتم تشغيل الوسائط، كي يتمكّن من إعادة توجيه إجراءات الوسائط إلى الجلسة الصحيحة، بل تُعلم المنصة أيضًا بالمحتوى الذي يتم تشغيله وكيفية التحكّم فيه.

يوفّر عرض MediaSession من خلال تطبيقك مزايا متعدّدة سيستفيد منها المستخدمون. في ما يلي بعض الأمثلة الرائعة.

مساعد Google

يمكن للمستخدمين التفاعل بسهولة مع الوسائط في تطبيقك من خلال طلبات صوتية، مثل "إيقاف مؤقت" و"استئناف" و "التالي". يمكن أيضًا استخدام البيانات الوصفية من الوسائط للحصول على إجابات عن المحتوى الذي يتم تشغيله حاليًا.

Android TV

في تجارب الشاشة الكبيرة، يمكن لتطبيق Android TV الاستفادة من أجهزة التحكّم عن بُعد التقليدية للمستخدمين الذين لديهم أجهزة تلفزيون متوافقة مع HDMI-CEC. يتم نقل الأوامر الصادرة عن أزرار التشغيل/الإيقاف المؤقت والإيقاف والتالي والسابق إلى تطبيقك.

أدوات التحكّم في الوسائط على الشاشة

بدءًا من الإصدار 4.0 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 14)، يمكن للنظام الوصول إلى حالة التشغيل والبيانات الوصفية لجلسة وسائط. تتيح هذه الوظيفة لشاشة القفل عرض أدوات التحكّم في الوسائط والأعمال الفنية. يختلف هذا السلوك حسب إصدار Android.

وسائط الخلفية

يمكن التحكّم في الوسائط في أيّ من هذه الحالات حتى إذا كان التطبيق الذي يشغّل الوسائط يعمل في الخلفية.

الحوسبة المحيطية

يمكن أن يؤدي عرض الوسائط مع بيانات حول ما يتم تشغيله وكيفية التحكّم فيه إلى الربط بين الأجهزة، ما يتيح للمستخدمين التفاعل معها بطرق متنوعة يفضلونها.

ما ستنشئه

في هذا الدرس التطبيقي حول الترميز، ستوسّع نموذج ExoPlayer الحالي لإضافة إمكانية استخدام جلسة وسائط. سيتم إجراء ما يلي في تطبيقك:

  • عرض حالة جلسة الوسائط النشطة بشكل صحيح
  • إرسال أدوات التحكّم في الوسائط إلى ExoPlayer
  • تمرير البيانات الوصفية للعناصر في قائمة الانتظار إلى جلسة الوسائط

ما ستتعلمه

  • سبب توفير جلسات الوسائط تجربة أكثر ثراءً للمستخدمين
  • كيفية إنشاء جلسة وسائط وإدارة حالتها
  • كيفية ربط جلسة وسائط بـ ExoPlayer
  • كيفية تضمين البيانات الوصفية للعناصر في قائمة التشغيل في جلسة الوسائط
  • كيفية إضافة إجراءات إضافية (مخصّصة)

يركّز هذا الدرس التطبيقي حول الترميز على حزمة تطوير البرامج (SDK) الخاصة بـ MediaSession. لا يتم تناول المفاهيم ومجموعات الرموز غير ذات الصلة، بما في ذلك تفاصيل حول تنفيذ ExoPlayer، ولكن يتم توفيرها لك لنسخها ولصقها ببساطة.

المتطلبات

  • إصدار حديث من "استوديو Android" (الإصدار 3.5 أو إصدار أحدث)
  • معرفة أساسية بتطوير تطبيقات Android

2. الإعداد

ما هي نقطة البداية؟

نقطة البداية هي العرض التوضيحي الرئيسي من ExoPlayer. يحتوي هذا العرض التوضيحي على فيديوهات تتضمّن عناصر تحكّم في التشغيل على الشاشة، ولكنّه لا يستخدم جلسات الوسائط بشكلٍ مباشر. وهو مكان رائع للبدء وإضافة هذه الأفكار.

الحصول على عيّنة ExoPlayer

للبدء بسرعة، لنبدأ بنموذج ExoPlayer. استنسِخ مستودع GitHub من خلال تشغيل الرمز أدناه.

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

فتح العرض التوضيحي

في "استوديو Android"، افتح مشروع العرض التوضيحي الرئيسي ضِمن demos/main.

سيطلب منك "استوديو Android" ضبط مسار حزمة تطوير البرامج (SDK). ننصحك باتّباع الاقتراحات بشأن تحديث أدوات بيئة التطوير المتكاملة وحزمة تطوير البرامج (SDK) في حال واجهت أي مشاكل.

10e3b5c652186d57.png

إذا طُلب منك استخدام أحدث إصدار من Gradle، يمكنك المتابعة وتحديثه.

يُرجى تخصيص بعض الوقت للتعرّف على التصميم الأساسي للتطبيق. يُرجى العِلم أنّ هناك نشاطَين: SampleChooserActivity وPlayerActivity. سنقضي بقية وقت الدرس التطبيقي حول الترميز في PlayerActivity، حيث يتم تشغيل الوسائط فعليًا، لذا افتح هذه الفئة وانتقِل إلى القسم التالي.

3- إنشاء جلسة وسائط وإدارة حالتها

إنشاء جلسة الوسائط

فتح "PlayerActivity.java" ينشئ هذا الصف ExoPlayer ويدير وظائفه، مثل عرض الفيديو على الشاشة. في هذا النشاط، سنربط ExoPlayer بجلسة وسائط.

عليك تعريف الحقلَين التاليَين في أعلى الفئة. سنستخدم هذه الحقول في جميع أنحاء هذا القسم.

private MediaSessionCompat mediaSession;
private MediaSessionConnector mediaSessionConnector;

عليك إضافة تبعية مشروع "extension-mediasession" إلى ملف build.gradle على مستوى الوحدة النمطية "الوحدة النمطية: العرض التوضيحي".

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

تجدر الإشارة إلى أنّ استوديو Android يمكن أن يساعدك في إضافة هذه الاعتمادية تلقائيًا إذا مرّرت مؤشر الماوس فوق الخطأ الذي يواجهك عند حلّ MediaSessionConnector:

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". cb1ec4e50886874f.png
  3. انقر على 9d8fb3a9ddf12827.png من شريط أدوات استوديو Android.
  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" وإصدار طلبات صوتية، مثل "إيقاف مؤقت". استئناف ("Resume") قدِّم سريعًا بمقدار دقيقة واحدة ("Fast-forward 1 minute").

b8dda02a6fb0f6a4.pngنموذج ExoPlayer يعمل على Android TV

4. تضمين البيانات الوصفية للعناصر في قائمة التشغيل

يمكننا الآن توسيع الميزات المتوافقة لجلسة الوسائط التي أنشأنا فيها MediaSessionConnector سابقًا في initializePlayer().

إضافة TimelineQueueNavigator

يمثّل ExoPlayer بنية الوسائط كخط زمني. للحصول على تفاصيل حول طريقة عمل ذلك، يُرجى الاطّلاع على عنصر المخطط الزمني في ExoPlayer. من خلال الاستفادة من هذه البنية، يمكننا تلقّي إشعارات عند حدوث تغييرات في المحتوى وعرض البيانات الوصفية للمحتوى الذي يتم تشغيله حاليًا عند الطلب.

لتحقيق ذلك، سنحدّد TimelineQueueNavigator. ابحث عن إنشاء MediaSessionConnector في initializePlayer() وأضِف عملية تنفيذ TimelineQueueNavigator بعد mediaSession.

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 تتوافق مع العنصر الذي يحمل هذا الفهرس في قائمة التشغيل.

بعد إضافة بعض البيانات الوصفية، يمكنك اختبار ما إذا كان "مساعد Google" يفهم ما يتم تشغيله. أثناء تشغيل فيديو على Android TV، اطلب من "مساعد Google" معرفة المحتوى المعروض حاليًا من خلال قول "ما هو المحتوى المعروض حاليًا؟".

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. استكشِف كيف يرى Android البيانات الوصفية من جلسة الوسائط من خلال تنفيذ ما يلي: adb shell dumpsys media_session
  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.+'

المستندات المرجعية