توفّر جلسات الوسائط طريقة عالمية للتفاعل مع مشغّل ملف صوتي أو فيديو. في Media3، يكون المشغّل التلقائي هو فئة ExoPlayer
التي تنفّذ
واجهة Player
. يتيح ربط جلسة الوسائط بالمشغّل للتطبيق
الإعلان عن تشغيل الوسائط خارجيًا وتلقّي أوامر التشغيل من
مصادر خارجية.
قد تأتي الأوامر من أزرار فعلية، مثل زر التشغيل على سماعة الرأس أو جهاز التحكّم عن بُعد بالتلفزيون. وقد تأتي أيضًا من تطبيقات العميل التي تتضمّن جهاز تحكّم في الوسائط، مثل توجيه "إيقاف مؤقت" إلى "مساعد Google". وتفوّض جلسة الوسائط هذه الطلبات إلى مشغّل تطبيق الوسائط.
حالات اختيار جلسة وسائط
عند تنفيذ MediaSession
، تسمح للمستخدمين بالتحكم في التشغيل:
- من خلال سماعات الرأس غالبًا ما تتضمّن سمّاعات الرأس أزرارًا أو تفاعلات تعمل باللمس يمكن للمستخدِم تنفيذها لتشغيل الوسائط أو إيقافها مؤقتًا أو الانتقال إلى المقطع الصوتي التالي أو السابق.
- من خلال التحدّث إلى مساعد Google من الأنماط الشائعة قول "Ok Google، أريد إيقاف الوسائط مؤقتًا" لإيقاف أي وسائط يتم تشغيلها حاليًا على الجهاز مؤقتًا.
- من خلال ساعة Wear OS يتيح ذلك للمستخدمين الوصول بسهولة إلى عناصر التحكّم الأكثر استخدامًا في التشغيل أثناء تشغيل المحتوى على هواتفهم.
- من خلال عناصر التحكّم في الوسائط تعرِض لوحة العرض الدوّارة هذه عناصر التحكّم في كل جلسة وسائط تتم إعادة تشغيلها.
- على التلفزيون السماح بتنفيذ الإجراءات باستخدام أزرار التشغيل المادية والتحكّم في تشغيل المنصة وإدارة الطاقة (على سبيل المثال، إذا تم إيقاف تشغيل التلفزيون أو مكبّر الصوت العمودي أو جهاز استقبال A/V أو تم تبديل مصدر الإدخال، يجب إيقاف التشغيل في التطبيق)
- وأي عمليات خارجية أخرى تحتاج إلى التأثير في التشغيل
وهذا مفيد في العديد من حالات الاستخدام. وعلى وجه الخصوص، ننصحك بشدة باستخدامMediaSession
في الحالات التالية:
- إذا كنت تبث محتوى فيديو طويلًا، مثل الأفلام أو البث التلفزيوني المباشر
- إذا كنت تبث محتوى صوتيًا طويلاً، مثل ملفات البودكاست أو قوائم تشغيل الموسيقى
- إذا كنت بصدد إنشاء تطبيق تلفزيوني
ومع ذلك، لا تتوافق بعض حالات الاستخدام مع MediaSession
. قد تحتاج إلى
استخدام الرمز Player
فقط في الحالات التالية:
- إذا كنت تعرض محتوى قصيرًا لا يتطلّب التحكّم الخارجي أو تشغيله في الخلفية
- لا يتوفّر فيديو نشط واحد، مثلاً عندما ينتقل المستخدم للأسفل أو للأعلى في قائمة ويُعرَض فيديوهات متعدّدة على الشاشة في الوقت نفسه.
- إذا كنت تشغّل فيديو تعريفيًا أو توضيحيًا لمرة واحدة، تتوقع أن يشاهده المستخدم بنشاط بدون الحاجة إلى عناصر تحكّم خارجية في التشغيل
- إذا كان المحتوى حساسًا من حيث الخصوصية ولا تريد أن تحصل العمليات الخارجية على الوصول إلى البيانات الوصفية للوسائط (مثل وضع التصفّح المتخفي في المتصفّح)
إذا لم يكن وضع الاستخدام الخاص بك يتطابق مع أي من الحالات المذكورة أعلاه، ننصحك بالتفكير في ما إذا كان
يناسبك أن يواصل تطبيقك تشغيل المحتوى عندما لا يتفاعل المستخدم معه
بنشاط. إذا كانت الإجابة "نعم"، عليك على الأرجح اختيار
MediaSession
. إذا كانت الإجابة "لا"، ننصحك باستخدام Player
بدلاً من ذلك.
إنشاء جلسة وسائط
تُعرض جلسة الوسائط بجانب المشغّل الذي تديره. يمكنك إنشاء
جلسة وسائط باستخدام عنصرَي Context
وPlayer
. يجب إنشاء جلسة وسائط و
تهيئةها عند الحاجة، مثل onStart()
أو
onResume()
طريقة دورة حياة Activity
أو Fragment
أو onCreate()
طريقة Service
التي تملك جلسة الوسائط ومشغّلها المرتبط بها.
لإنشاء جلسة وسائط، عليك بدء Player
وإرسالها إلى
MediaSession.Builder
على النحو التالي:
Kotlin
val player = ExoPlayer.Builder(context).build() val mediaSession = MediaSession.Builder(context, player).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build(); MediaSession mediaSession = new MediaSession.Builder(context, player).build();
معالجة الحالة التلقائية
تعدّل مكتبة Media3 جلسة الوسائط تلقائيًا باستخدام حالة المشغّل. وبالتالي، لا تحتاج إلى إجراء عملية الربط يدويًا من المشغّل إلى الجلسة.
يختلف ذلك عن جلسة وسائط المنصة التي كنت بحاجة فيها إلى إنشاء PlaybackState
وتدبيرها بشكل مستقل عن المشغّل نفسه، على سبيل المثال للتوضيح
أي أخطاء.
معرّف الجلسة الفريد
ينشئ MediaSession.Builder
تلقائيًا جلسة باستخدام سلسلة فارغة كأحد مكونات
معرّف الجلسة. وهذا كافٍ إذا كان التطبيق يريد إنشاء مثيل واحد فقط
للجلسة، وهو الإجراء الأكثر شيوعًا.
إذا أراد التطبيق إدارة عدّة نُسخ من الجلسة في الوقت نفسه، عليه
التأكّد من أنّ معرّف الجلسة لكل جلسة فريد. يمكن
ضبط معرّف الجلسة عند إنشاء الجلسة باستخدام MediaSession.Builder.setId(String id)
.
إذا ظهرت لك رسالة خطأ IllegalStateException
تشير إلى تعطُّل تطبيقك IllegalStateException: Session ID must be unique. ID=
، من المرجّح أنّه تم إنشاء جلسة بشكل غير متوقّع قبل إنهاء جلسة سابقة تم إنشاؤها باستخدام رقم التعريف نفسه. لتجنّب تسرُّب الجلسات بسبب خطأ في المعالجة، يتم رصد هذه الحالات وإرسال إشعار بها من خلال طرح أحد
الاستثناءات.
منح عناصر التحكّم لعملاء آخرين
جلسة الوسائط هي مفتاح التحكّم في التشغيل. يتيح لك توجيه الطلبات من مصادر خارجية إلى المشغّل الذي يشغّل الوسائط. يمكن أن تكون هذه المصادر أزرارًا مادية، مثل زر التشغيل على سماعة الرأس أو جهاز التحكّم عن بُعد في التلفزيون، أو طلبات غير مباشرة، مثل توجيه "إيقاف مؤقت" إلى "مساعد Google". وبالمثل، قد تحتاج إلى منح الإذن بالوصول إلى نظام Android لتسهيل استخدام عناصر التحكّم في الإشعارات وشاشة القفل، أو إلى ساعة Wear OS لكي تتمكّن من التحكّم في التشغيل من خلفية شاشة الساعة. يمكن للعملاء الخارجيين استخدام وحدة تحكّم في الوسائط لإصدار أوامر التشغيل إلى تطبيق الوسائط. ويتم تلقّي هذه الأوامر من خلال جلسة الوسائط التي تفوض الأوامر في نهاية المطاف إلى مشغّل الوسائط.

عندما يكون جهاز التحكّم على وشك الاتصال بجلسة الوسائط، يتمّ استدعاء الأسلوب
onConnect()
. يمكنك استخدام رمز ControllerInfo
المتوفر لتحديد ما إذا كنت تريد قبول
الطلب أو رفضه. يمكنك الاطّلاع على مثال لقبول طلب ربط في قسم Declare
الطلبات المخصّصة.
بعد الاتصال، يمكن لوحدة التحكّم إرسال أوامر التشغيل إلى الجلسة. بعد ذلك، تفوّض الجلسة هذه الأوامر إلى المشغّل. تعالج الجلسة تلقائيًا تعليمات التشغيل وقائمة التشغيل
المحدّدة في واجهة Player
.
تتيح لك طرق الاستدعاء الأخرى معالجة طلبات سمات
مخصّصة وتعديل قائمة التشغيل، على سبيل المثال. تتضمّن هذه الدوال المُعاد الاتصال بها أيضًا عنصر ControllerInfo
حتى تتمكّن من تعديل كيفية الردّ على كل طلب على أساس كل وحدة تحكّم.
تعديل قائمة التشغيل
يمكن لجلسة الوسائط تعديل قائمة تشغيل مشغّلها مباشرةً كما هو موضّح في
دليل ExoPlayer لقوائم التشغيل.
يمكن لمسؤولي التحكّم أيضًا تعديل قائمة التشغيل إذا كان الخياران
COMMAND_SET_MEDIA_ITEM
أو COMMAND_CHANGE_MEDIA_ITEMS
متاحَين
لمسؤول التحكّم.
عند إضافة عناصر جديدة إلى قائمة التشغيل، يتطلّب المشغّل عادةً MediaItem
نُسخًا تتضمّن
معرّف موارد موحّد
لتشغيلها. يتم تلقائيًا إعادة توجيه العناصر التي تمت إضافتها حديثًا
إلى طرق المشغّل، مثل player.addMediaItem
، إذا تم تحديد عنوان URL لها.
إذا أردت تخصيص مواضع تكرار MediaItem
التي تمت إضافتها إلى المشغّل، يمكنك
تجاوز
onAddMediaItems()
.
تكون هذه الخطوة مطلوبة عندما تريد إتاحة عناصر التحكّم التي تطلب الوسائط بدون معرّف موارد منتظم (URI) محدّد. بدلاً من ذلك، يحتوي MediaItem
عادةً على
حقل واحد أو أكثر من الحقول التالية تم ضبطها لوصف الوسائط المطلوبة:
MediaItem.id
: معرّف عام يحدِّد الوسائطMediaItem.RequestMetadata.mediaUri
: معرّف الموارد المنتظم (URI) للطلب الذي قد يستخدم ملف شخصي مخصّصًا ولا يمكن تشغيله مباشرةً من خلال المشغّل.MediaItem.RequestMetadata.searchQuery
: طلب بحث نصي، على سبيل المثال من "مساعد Google"MediaItem.MediaMetadata
: البيانات الوصفية المنظَّمة، مثل "العنوان" أو "الفنان"
لمزيد من خيارات التخصيص لقوائم تشغيل جديدة تمامًا، يمكنك
إلغاء
onSetMediaItems()
الذي يتيح لك تحديد العنصر الأول والموضع في قائمة التشغيل. على سبيل المثال،
يمكنك توسيع عنصر واحد تم طلبه إلى قائمة تشغيل كاملة وتوجيه
المشغّل للبدء من فهرس العنصر الذي تم طلبه في الأصل. يمكن العثور على
نموذج لتنفيذ onSetMediaItems()
مع هذه الميزة في تطبيق الجلسة التجريبي.
إدارة الإعدادات المفضّلة لأزرار الوسائط
يمكن لكل وحدة تحكّم، مثل واجهة المستخدم أو Android Auto أو Wear OS، اتخاذ
قراراتها الخاصة بشأن الأزرار التي سيتم عرضها للمستخدم. للإشارة إلى عناصر التحكّم في التشغيل التي تريد إتاحتها للمستخدم، يمكنك تحديد إعدادات buttons media
الفضّلة في MediaSession
. تتألف هذه الإعدادات المفضّلة من قائمة مرتبة
لمثيلات CommandButton
، يحدّد كلّ منها إعدادًا مفضّلاً لزرّ في
واجهة المستخدم.
تحديد أزرار الأوامر
تُستخدَم نُسخ CommandButton
لتحديد الإعدادات المفضّلة لزرّات الوسائط. يحدِّد كل زر
ثلاثة جوانب من عنصر واجهة المستخدم المطلوب:
- الرمز الذي يحدّد المظهر المرئي يجب ضبط الرمز على أحد
الثوابت المحدّدة مسبقًا عند إنشاء
CommandButton.Builder
. يُرجى العلم أنّه ليس هذا ملف رسومات نقطية أو مرجع صورة فعلي. تساعد القيمة الثابتة العامة في اختيار عناصر تحكّم مناسبة لمظهر ومتعة متّسقة داخل واجهة المستخدم الخاصة بهم. إذا لم يكن أيّ من الثوابت المحدّدة مسبقًا للرمز مناسبًا لحال استخدامك، يمكنك استخدامsetCustomIconResId
بدلاً من ذلك. - الأمر الذي يحدّد الإجراء الذي يتم تفعيله عندما يتفاعل المستخدِم مع
الزر يمكنك استخدام
setPlayerCommand
لرمزPlayer.Command
أوsetSessionCommand
لرمزSessionCommand
محدّد مسبقًا أو مخصّص. - المكان، لتحديد موضع الزر في واجهة مستخدم وحدة التحكّم. هذا الحقل اختياري ويتم ضبطه تلقائيًا استنادًا إلى الرمز و الأمر. على سبيل المثال، يسمح هذا العنصر بتحديد أنّه يجب عرض زر في منطقة التنقّل "إلى الأمام" لواجهة المستخدم بدلاً من المنطقة التلقائية "overflow".
Kotlin
val button = CommandButton.Builder(CommandButton.ICON_SKIP_FORWARD_15) .setSessionCommand(SessionCommand(CUSTOM_ACTION_ID, Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD) .build()
Java
CommandButton button = new CommandButton.Builder(CommandButton.ICON_SKIP_FORWARD_15) .setSessionCommand(new SessionCommand(CUSTOM_ACTION_ID, Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD) .build();
عند حلّ الإعدادات المفضّلة لزرّات الوسائط، يتم تطبيق الخوارزمية التالية:
- لكل
CommandButton
في الإعدادات المفضّلة لزرّات الوسائط، ضَع الزر في أول خانة متاحة ومسموح بها. - إذا لم يتم ملء أي من المواضع المركزية والاتجاه إلى الأمام والخلف بأحد buttons، أضِف أزرارًا تلقائية لهذه الموضع.
يمكنك استخدام CommandButton.DisplayConstraints
لإنشاء معاينة لكيفية حلّ
الإعدادات المفضّلة لزرّات الوسائط استنادًا إلى قيود شاشة واجهة المستخدم.
ضبط الإعدادات المفضّلة لزر الوسائط
إنّ أسهل طريقة لضبط الإعدادات المفضّلة لأزرار الوسائط هي تحديد القائمة عند
إنشاء MediaSession
. بدلاً من ذلك، يمكنك إلغاء الإعدادات في الخطوة
MediaSession.Callback.onConnect
لتخصيص الإعدادات المفضّلة لزرّات الوسائط لكل وحدة تحكّم متصلة.
Kotlin
val mediaSession = MediaSession.Builder(context, player) .setMediaButtonPreferences(ImmutableList.of(likeButton, favoriteButton)) .build()
Java
MediaSession mediaSession = new MediaSession.Builder(context, player) .setMediaButtonPreferences(ImmutableList.of(likeButton, favoriteButton)) .build();
تعديل الإعدادات المفضّلة لزر الوسائط بعد تفاعل المستخدم
بعد معالجة تفاعل مع المشغّل، قد تحتاج إلى تعديل
الزرّات المعروضة في واجهة مستخدِم وحدة التحكّم. ومن الأمثلة الشائعة على ذلك زر الإيقاف/التفعيل الذي يغيّر رمزه وإجراءه بعد بدء الإجراء المرتبط بهذا الزر. لتعديل الإعدادات المفضّلة لأزرار الوسائط، يمكنك استخدام رمز
MediaSession.setMediaButtonPreferences
لتعديل الإعدادات المفضّلة ل
جميع أجهزة التحكّم أو جهاز تحكّم معيّن:
Kotlin
// Handle "favoritesButton" action, replace by opposite button mediaSession.setMediaButtonPreferences( ImmutableList.of(likeButton, removeFromFavoritesButton))
Java
// Handle "favoritesButton" action, replace by opposite button mediaSession.setMediaButtonPreferences( ImmutableList.of(likeButton, removeFromFavoritesButton));
إضافة أوامر مخصّصة وتخصيص السلوك التلقائي
يمكن توسيع أوامر المشغّل المتاحة باستخدام أوامر مخصّصة، ومن الم possible أيضًا اعتراض أوامر المشغّل والأزرار الخاصة بالوسائط الواردة لتغيير السلوك default.
تحديد الأوامر المخصّصة ومعالجتها
يمكن لتطبيقات الوسائط تحديد أوامر مخصّصة يمكن استخدامها مثلاً في الإعدادات المفضّلة لأزرار الوسائط. على سبيل المثال، قد تحتاج إلى
تنفيذ أزرار تتيح للمستخدم حفظ عنصر وسائط في قائمة
بالعناصر المفضّلة. يُرسِل MediaController
أوامر مخصّصة ويتلقّاها
MediaSession.Callback
.
لتحديد الأوامر المخصّصة، عليك إلغاء
MediaSession.Callback.onConnect()
لضبط الأوامر المخصّصة المتاحة
لكل وحدة تحكّم متصلة.
Kotlin
private class CustomMediaSessionCallback: MediaSession.Callback { // Configure commands available to the controller in onConnect() override fun onConnect( session: MediaSession, controller: MediaSession.ControllerInfo ): MediaSession.ConnectionResult { val sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(SessionCommand(SAVE_TO_FAVORITES, Bundle.EMPTY)) .build() return AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build() } }
Java
class CustomMediaSessionCallback implements MediaSession.Callback { // Configure commands available to the controller in onConnect() @Override public ConnectionResult onConnect( MediaSession session, ControllerInfo controller) { SessionCommands sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(new SessionCommand(SAVE_TO_FAVORITES, new Bundle())) .build(); return new AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build(); } }
لتلقّي طلبات أوامر مخصّصة من MediaController
، يمكنك إلغاء أسلوب
onCustomCommand()
في Callback
.
Kotlin
private class CustomMediaSessionCallback: MediaSession.Callback { ... override fun onCustomCommand( session: MediaSession, controller: MediaSession.ControllerInfo, customCommand: SessionCommand, args: Bundle ): ListenableFuture<SessionResult> { if (customCommand.customAction == SAVE_TO_FAVORITES) { // Do custom logic here saveToFavorites(session.player.currentMediaItem) return Futures.immediateFuture( SessionResult(SessionResult.RESULT_SUCCESS) ) } ... } }
Java
class CustomMediaSessionCallback implements MediaSession.Callback { ... @Override public ListenableFuture<SessionResult> onCustomCommand( MediaSession session, ControllerInfo controller, SessionCommand customCommand, Bundle args ) { if(customCommand.customAction.equals(SAVE_TO_FAVORITES)) { // Do custom logic here saveToFavorites(session.getPlayer().getCurrentMediaItem()); return Futures.immediateFuture( new SessionResult(SessionResult.RESULT_SUCCESS) ); } ... } }
يمكنك تتبُّع وحدة التحكّم في الوسائط التي تقدّم طلبًا باستخدام سمة
packageName
لكائن MediaSession.ControllerInfo
الذي يتم
تمريره إلى طرق Callback
. يتيح لك ذلك تخصيص سلوك
تطبيقك استجابةً لأمر معيّن إذا كان مصدره هو النظام أو
تطبيقك الخاص أو تطبيقات العميل الأخرى.
تخصيص أوامر اللاعبين التلقائية
يتم تفويض جميع الأوامر التلقائية ومعالجة الحالات إلى Player
الذي يكون على
MediaSession
. لتخصيص سلوك أمر محدّد في واجهة
Player
، مثل play()
أو seekToNext()
، عليك لفّ Player
في
ForwardingSimpleBasePlayer
قبل تمريره إلى MediaSession
:
Kotlin
val player = (logic to build a Player instance) val forwardingPlayer = object : ForwardingSimpleBasePlayer(player) { // Customizations } val mediaSession = MediaSession.Builder(context, forwardingPlayer).build()
Java
ExoPlayer player = (logic to build a Player instance) ForwardingSimpleBasePlayer forwardingPlayer = new ForwardingSimpleBasePlayer(player) { // Customizations }; MediaSession mediaSession = new MediaSession.Builder(context, forwardingPlayer).build();
لمزيد من المعلومات حول ForwardingSimpleBasePlayer
، يُرجى الاطّلاع على دليل ExoPlayer
عن
التخصيص.
تحديد وحدة التحكّم التي تطلب أمرًا من اللاعب
عندما يبدأ طلب Player
من MediaController
، يمكنك
تحديد مصدره باستخدام MediaSession.controllerForCurrentRequest
والحصول على ControllerInfo
للطلب الحالي:
Kotlin
class CallerAwarePlayer(player: Player) : ForwardingSimpleBasePlayer(player) { override fun handleSeek( mediaItemIndex: Int, positionMs: Long, seekCommand: Int, ): ListenableFuture<*> { Log.d( "caller", "seek operation from package ${session.controllerForCurrentRequest?.packageName}", ) return super.handleSeek(mediaItemIndex, positionMs, seekCommand) } }
Java
public class CallerAwarePlayer extends ForwardingSimpleBasePlayer { public CallerAwarePlayer(Player player) { super(player); } @Override protected ListenableFuture<?> handleSeek( int mediaItemIndex, long positionMs, int seekCommand) { Log.d( "caller", "seek operation from package: " + session.getControllerForCurrentRequest().getPackageName()); return super.handleSeek(mediaItemIndex, positionMs, seekCommand); } }
تخصيص طريقة معالجة أزرار الوسائط
أزرار الوسائط هي أزرار أجهزة خارجية موجودة على أجهزة Android وغيرها من الأجهزة الملحقة، مثل زر التشغيل/الإيقاف المؤقت على سماعة رأس بلوتوث. يعالج Media3
أحداث أزرار الوسائط نيابةً عنك عند وصولها إلى الجلسة ويُطلِب
طريقة Player
المناسبة في مشغّل الجلسة.
ننصحك بمعالجة جميع أحداث زرّات الوسائط الواردة في Player
corresponding method. بالنسبة إلى حالات الاستخدام الأكثر تقدمًا، يمكن اعتراض أحداث buttons
في MediaSession.Callback.onMediaButtonEvent(Intent)
.
معالجة الأخطاء والإبلاغ عنها
هناك نوعان من الأخطاء التي تُرسِلها الجلسة وتُبلغ بها أدوات التحكّم. تشير الأخطاء المميتة إلى حدوث خطأ فني في تشغيل جلسة المشغّل يؤدي إلى مقاطعة التشغيل. يتم تلقائيًا إبلاغ وحدة التحكّم بالأخطاء المميتة عند حدوثها. الأخطاء غير الفادحة هي أخطاء غير فنية أو أخطاء تتعلّق بالسياسة ولا تؤدي إلى إيقاف التشغيل، ويتم إرسالها إلى وحدات التحكّم من قِبل التطبيق يدويًا.
أخطاء فادحة في التشغيل
يُبلغ المشغّل الجلسة عن خطأ تشغيل خطير، ثم يتم إعلام وحدات التحكّم بالخطأ لإجراء مكالمة من خلال Player.Listener.onPlayerError(PlaybackException)
وPlayer.Listener.onPlayerErrorChanged(@Nullable PlaybackException)
.
في هذه الحالة، يتم نقل حالة التشغيل إلى STATE_IDLE
وMediaController.getPlaybackError()
يعرض PlaybackException
الذي تسبب في النقل. يمكن لجهاز التحكّم فحص PlayerException.errorCode
للحصول على
معلومات عن سبب الخطأ.
من أجل التشغيل التفاعلي، يتم تكرار الخطأ الفادح في جلسة المنصة من خلال
نقل حالتها إلى STATE_ERROR
وضبط رمز الخطأ والرسالة
وفقًا للحالة PlaybackException
.
تخصيص الأخطاء المميتة
لتقديم معلومات مترجَمة ومفيدة للمستخدم، يمكن تخصيص رمز الخطأ،
ورسالة الخطأ، ومعلومات إضافية عن الخطأ في حال حدوث خطأ فادح في التشغيل، وذلك باستخدام ForwardingPlayer
عند إنشاء الجلسة:
Kotlin
val forwardingPlayer = ErrorForwardingPlayer(player) val session = MediaSession.Builder(context, forwardingPlayer).build()
Java
Player forwardingPlayer = new ErrorForwardingPlayer(player); MediaSession session = new MediaSession.Builder(context, forwardingPlayer).build();
يمكن للاعب الذي يعيد توجيه البث استخدام ForwardingSimpleBasePlayer
لرصد
الخطأ وتخصيص رمز الخطأ أو الرسالة أو الإضافات. وبالطريقة نفسها، يمكنك
أيضًا إنشاء أخطاء جديدة لا تظهر في المشغّل الأصلي:
Kotlin
class ErrorForwardingPlayer (private val context: Context, player: Player) : ForwardingSimpleBasePlayer(player) { override fun getState(): State { var state = super.getState() if (state.playerError != null) { state = state.buildUpon() .setPlayerError(customizePlaybackException(state.playerError!!)) .build() } return state } fun customizePlaybackException(error: PlaybackException): PlaybackException { val buttonLabel: String val errorMessage: String when (error.errorCode) { PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW -> { buttonLabel = context.getString(R.string.err_button_label_restart_stream) errorMessage = context.getString(R.string.err_msg_behind_live_window) } else -> { buttonLabel = context.getString(R.string.err_button_label_ok) errorMessage = context.getString(R.string.err_message_default) } } val extras = Bundle() extras.putString("button_label", buttonLabel) return PlaybackException(errorMessage, error.cause, error.errorCode, extras) } }
Java
class ErrorForwardingPlayer extends ForwardingSimpleBasePlayer { private final Context context; public ErrorForwardingPlayer(Context context, Player player) { super(player); this.context = context; } @Override protected State getState() { State state = super.getState(); if (state.playerError != null) { state = state.buildUpon() .setPlayerError(customizePlaybackException(state.playerError)) .build(); } return state; } private PlaybackException customizePlaybackException(PlaybackException error) { String buttonLabel; String errorMessage; switch (error.errorCode) { case PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW: buttonLabel = context.getString(R.string.err_button_label_restart_stream); errorMessage = context.getString(R.string.err_msg_behind_live_window); break; default: buttonLabel = context.getString(R.string.err_button_label_ok); errorMessage = context.getString(R.string.err_message_default); break; } Bundle extras = new Bundle(); extras.putString("button_label", buttonLabel); return new PlaybackException(errorMessage, error.getCause(), error.errorCode, extras); } }
الأخطاء غير المميتة
يمكن أن يرسل التطبيق أخطاء غير قاتلة لا تنشأ عن استثناء فني، ويرسلها إلى جميع وحدات التحكّم أو إلى وحدة تحكّم معيّنة:
Kotlin
val sessionError = SessionError( SessionError.ERROR_SESSION_AUTHENTICATION_EXPIRED, context.getString(R.string.error_message_authentication_expired), ) // Option 1: Sending a nonfatal error to all controllers. mediaSession.sendError(sessionError) // Option 2: Sending a nonfatal error to the media notification controller only // to set the error code and error message in the playback state of the platform // media session. mediaSession.mediaNotificationControllerInfo?.let { mediaSession.sendError(it, sessionError) }
Java
SessionError sessionError = new SessionError( SessionError.ERROR_SESSION_AUTHENTICATION_EXPIRED, context.getString(R.string.error_message_authentication_expired)); // Option 1: Sending a nonfatal error to all controllers. mediaSession.sendError(sessionError); // Option 2: Sending a nonfatal error to the media notification controller only // to set the error code and error message in the playback state of the platform // media session. ControllerInfo mediaNotificationControllerInfo = mediaSession.getMediaNotificationControllerInfo(); if (mediaNotificationControllerInfo != null) { mediaSession.sendError(mediaNotificationControllerInfo, sessionError); }
عند إرسال خطأ غير مميت إلى وحدة التحكّم في إشعارات الوسائط، يتم تكرار رمز الخطأ
ورسالة الخطأ في جلسة وسائط المنصة، مع عدم
تغيير PlaybackState.state
إلى STATE_ERROR
.
تلقّي أخطاء غير قاتلة
يتلقّى MediaController
خطأً غير مميت من خلال تنفيذ
MediaController.Listener.onError
:
Kotlin
val future = MediaController.Builder(context, sessionToken) .setListener(object : MediaController.Listener { override fun onError(controller: MediaController, sessionError: SessionError) { // Handle nonfatal error. } }) .buildAsync()
Java
MediaController.Builder future = new MediaController.Builder(context, sessionToken) .setListener( new MediaController.Listener() { @Override public void onError(MediaController controller, SessionError sessionError) { // Handle nonfatal error. } });