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

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

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

توفّر 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 يتواصل مع تطبيق استقبال Cast. يعتمد السلوك على جلسة 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

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 باستخدام مجموعة صالحة من قيم الحالة. سيتولّى أيضًا معالجة أدوات الاستماع وإعلام أدوات الاستماع بالتغييرات في الحالة. إذا كنت بحاجة إلى تفعيل تعديل الحالة يدويًا، اتّصِل بالرقم invalidateState().

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

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

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