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

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

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

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

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

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

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

على الرغم من أنّ 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

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

Java

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(looper: Looper) : SimpleBasePlayer(looper) {
  override fun getState(): State {
    return State.Builder()
      .setAvailableCommands(Commands.EMPTY) // 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

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

  @Override
  protected State getState() {
    return new State.Builder()
        .setAvailableCommands(Commands.EMPTY) // 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 باستخدام مجموعة صالحة من قيم الحالة. وسيتعامل أيضًا مع المستمعين وإبلاغ المستمعين بتغييرات الحالة. إذا كنت بحاجة إلى بدء تحديث الحالة يدويًا، يمكنك استدعاء invalidateState().

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

تعديل عمليات تنفيذ Player

بدلاً من إنشاء Player مخصّص بالكامل، يمكنك استخدام ForwardingSimpleBasePlayer لتعديل حالة وسلوك Player حالي. لمزيد من التفاصيل، يُرجى الاطّلاع على الدليل في صفحة التخصيص.