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

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

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

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

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

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

المكوّن ملاحظات الوصف والسلوك
ExoPlayer واجهة برمجة تطبيقات لمشغّل الوسائط والتنفيذ التلقائي لواجهة Player
MediaController للتفاعل مع MediaSession لإرسال أوامر تشغيل إذا كانت كلّ من Player وMediaSession في Service بشكل منفصل عن Activity أو Fragment في واجهة مستخدم المشغّل، يمكنك تعيين MediaController كمشغّل في واجهة مستخدم PlayerView. يتم إرسال المكالمات استنادًا إلى طرق التشغيل وقوائم التشغيل إلى Player من خلال MediaSession.
MediaBrowser بالإضافة إلى الوظائف التي يوفّرها MediaController، يتفاعل الجهاز مع MediaLibrarySession لتصفّح محتوى الوسائط المتوفّر.
ForwardingPlayer عملية تنفيذ Player تعيد توجيه استدعاءات الطريقة إلى Player أخرى. يمكنك استخدام هذه الفئة لإيقاف عمليات محدّدة أو تعديلها من خلال إلغاء الطرق ذات الصلة.
SimpleBasePlayer عملية تنفيذ Player تقلل من عدد الطرق المطلوب تنفيذها إلى أدنى حد. هذه الميزة مفيدة عند استخدام مشغّل مخصّص تريد ربطه بـ MediaSession.
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 باستخدام مجموعة صالحة من قيم الحالات. وسيتعامل أيضًا مع المستمعين وإعلام المستمعين بتغييرات الدولة. إذا أردت تفعيل عملية تعديل الحالة يدويًا، اتّصِل بالرقم invalidateState().

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