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

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

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

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

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

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

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

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