واجهة المشغّل

مشغّل الوسائط هو مكوّن تطبيقك الذي يسهّل تشغيل عناصر الوسائط. واجهة Media3 Player: تُعدّ هذه الواجهة مخطّطًا تفصيليًا للوظائف التي يعالجها المشغّل بشكل عام. ويشمل ذلك:

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

يوفّر Media3 أيضًا تنفيذًا لواجهة Player، يُعرف باسم ExoPlayer.

واجهة مشتركة بين المكوّنات

تُنفِّذ عدّة مكوّنات في Media3 واجهة Player، على سبيل المثال:

المكوّن ملاحظات حول الوصف والسلوك
ExoPlayer واجهة برمجة تطبيقات لمشغّل الوسائط، وطريقة التنفيذ التلقائية لواجهة Player
MediaController التفاعل مع MediaSession لإرسال أوامر التشغيل إذا كان كل من Player وMediaSession في Service منفصل عن Activity أو Fragment حيث يتوفّر واجهة المستخدم الخاصة بالمشغّل، يمكنك تعيين MediaController كمشغّل لواجهة PlayerView. يتم إرسال طلبات تشغيل الموسيقى وقوائم التشغيل إلى Player من خلال MediaSession.
MediaBrowser بالإضافة إلى الوظائف التي يوفّرها MediaController، يتفاعل مع MediaLibrarySession لتصفّح محتوى الوسائط المتاح.
SimpleBasePlayer تنفيذ Player يقلل من عدد الطرق التي يجب تنفيذها إلى الحد الأدنى يكون هذا الخيار مفيدًا عند استخدام مشغّل مخصّص تريد ربطه بـ MediaSession.
ForwardingSimpleBasePlayer فئة فرعية من SimpleBasePlayer مصمّمة لإعادة توجيه عمليات التشغيل إلى Player آخر مع السماح بالإجراءات المخصّصة المتسقة نفسها مثل SimpleBasePlayer. استخدِم هذه الفئة لإيقاف عمليات تشغيل معيّنة أو تعديلها.
CastPlayer تنفيذ Player يتواصل مع تطبيق تلقي البث. يعتمد السلوك على جلسة البث الأساسية.

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

بنية تشغيل Media3

إذا كان بإمكانك الوصول إلى Player، عليك استدعاء طرقه مباشرةً لإصدار تعليمات التشغيل. يمكنك الإعلان عن ميزة التشغيل ومنح مصادر خارجية إذن التحكّم في التشغيل من خلال تنفيذ MediaSession. تنفِّذ هذه المصادر الخارجية MediaController، ما يسهِّل الاتصال بجلسة وسائط وإصدار طلبات أوامر التشغيل.

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

رسم بياني يوضّح كيفية ملاءمة مكوّنات تشغيل Media3 في بنية تطبيق الوسائط
الشكل 1: تؤدي واجهة Player دورًا أساسيًا في بنية Media3.

حالة المشغّل

تتكون حالة مشغّل الوسائط الذي ينفِّذ واجهة Player بشكل أساسي من 4 فئات من المعلومات:

  1. حالة التشغيل
  2. قائمة تشغيل تتضمّن ملفات وسائط
    • تسلسل من MediaItem مثيل لتشغيله
    • الاسترداد باستخدام getCurrentTimeline()
    • يمكن أن تقدّم عناصر Player طرقًا لإجراء عمليات على قوائم التشغيل، مثل إضافة أو إزالة MediaItem وطرقًا سهلة الاستخدام مثل getCurrentMediaItem().
  3. سمات التشغيل/الإيقاف المؤقت، مثل:
    • playWhenReady: يشير ذلك إلى ما إذا كان المستخدم يريد تشغيل الوسائط عند الإمكان أو إبقائها في وضع الإيقاف المؤقت.
    • سبب إيقاف التشغيل: يشير هذا الحقل إلى سبب إيقاف التشغيل، إن أمكن، حتى إذا كان playWhenReady هو true.
    • isPlaying: يشير هذا الرمز إلى ما إذا كان المشغّل يشغّل المحتوى حاليًا، ولن يظهر سوى true إذا كانت حالة التشغيل هي STATE_READY وplayWhenReady هي true ولم يتم إيقاف التشغيل
  4. موضع التشغيل، بما في ذلك:

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

الاستماع إلى التغييرات

استخدِم Player.Listener للاستماع إلى التغييرات في Player. اطّلِع على مستندات ExoPlayer حول أحداث المشغّل للحصول على تفاصيل عن كيفية إنشاء مستمع واستخدامه.

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

Kotlin

val handler = Handler(Looper.getMainLooper())
fun checkPlaybackPosition(delayMs: Long): Boolean =
  handler.postDelayed(
    {
      val currentPosition = player.currentPosition
      // Update UI based on currentPosition
      checkPlaybackPosition(delayMs)
    },
    delayMs)

Java

Handler handler = new Handler(Looper.getMainLooper());
boolean checkPlaybackPosition(long delayMs) {
    return handler.postDelayed(() -> {
        long currentPosition = player.getCurrentPosition();
        // Update UI based on currentPosition
        checkPlaybackPosition(delayMs);
    }, delayMs);
}

تحكُّم في التشغيل بخطوات بسيطة

توفّر واجهة Player العديد من الطرق للتلاعب بالحالة والتحكّم في التشغيل:

عمليات تنفيذ Player المخصّصة

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

ابدأ بإلغاء طريقة getState(). يجب أن تملأ هذه الطريقة حالة اللاعب الحالية عند استدعائها، بما في ذلك:

  • مجموعة الطلبات المتاحة
  • سمات التشغيل، مثل ما إذا كان يجب أن يبدأ المشغّل التشغيل عندما تكون حالة التشغيل هي STATE_READY، فهرس عنصر الوسائط الذي يتم تشغيله حاليًا، وموضع التشغيل ضمن العنصر الحالي

Kotlin

class CustomPlayer : SimpleBasePlayer(looper) {
  override fun getState(): State {
    return State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build()
  }
}

Java

public class CustomPlayer extends SimpleBasePlayer {
  public CustomPlayer(Looper looper) {
    super(looper);
  }

  @Override
  protected State getState() {
    return new State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build();
  }
}

سيفرض SimpleBasePlayer إنشاء State باستخدام تركيبة válida من قيم الحالة. وسيتولى أيضًا التعامل مع المستمعين وإعلامهم بتغييرات الحالة. إذا كنت بحاجة إلى بدء تحديث حالة يدويًا، تواصَل مع invalidateState().

بالإضافة إلى طريقة getState()، ما عليك سوى تنفيذ الطرق المستخدَمة للطلبات التي يعلن مشغّل الوسائط أنّها متاحة. ابحث عن طريقة معالِج القابلة للاستبدال التي تتوافق مع الوظيفة التي تريد تنفيذها. على سبيل المثال، يمكنك إلغاء طريقة handleSeek() لتفعيل عمليات مثل COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM وCOMMAND_SEEK_TO_NEXT_MEDIA_ITEM.