يتيح إطار عمل جهاز توجيه وسائط Android للشركات المصنّعة إمكانية تشغيل المحتوى على أجهزتهم.
من خلال واجهة موحّدة تُسمى MediaRouteProvider
.
يحدد موفر المسار واجهة مشتركة لتشغيل الوسائط على جهاز الاستقبال، مما يجعلها
إمكانية تشغيل الوسائط على جهازك من أي تطبيق Android يتيح تشغيل الوسائط
والمسارات.
يناقش هذا الدليل كيفية إنشاء مزوّد مسار وسائط لجهاز الاستقبال وجعله
متوفرًا لتطبيقات تشغيل الوسائط الأخرى التي تعمل على نظام التشغيل Android. لاستخدام واجهة برمجة التطبيقات هذه،
على دراية بالفئات الرئيسية
MediaRouteProvider
،
MediaRouteProviderDescriptor
و
RouteController
نظرة عامة
يتيح إطار عمل جهاز توجيه الوسائط لنظام التشغيل Android لمطوّري تطبيقات الوسائط وأجهزة تشغيل الوسائط
الشركات المصنّعة للاتصال من خلال واجهة برمجة تطبيقات مشتركة وواجهة مستخدم مشتركة. مطورو التطبيقات الذين
تنفيذ واجهة MediaRouter
حتى يمكن الاتصال
إطار عمل تشغيل المحتوى على الأجهزة التي تشارك في إطار عمل موجِّه الوسائط. الوسائط
يمكن للشركات المصنّعة لأجهزة التشغيل المشاركة في إطار العمل من خلال نشر MediaRouteProvider
يسمح للتطبيقات الأخرى بالاتصال
تشغيل الوسائط على أجهزة الاستقبال يوضح الشكل 1 كيفية اتصال أحد التطبيقات بجهاز استقبال
الجهاز من خلال إطار عمل موجه الوسائط.
عند إنشاء موفر مسار وسائط لجهاز الاستقبال، يقدّم المزوّد للأغراض التالية:
- صِف إمكانيات جهاز الاستقبال وانشرها لتتمكّن التطبيقات الأخرى من اكتشافها. واستخدام ميزات التشغيل الخاصة به
- التفاف واجهة برمجة جهاز الاستقبال وطريقة الاتصال به آليات نقل لجعل الجهاز متوافقًا مع إطار عمل جهاز توجيه الوسائط.
توزيع مزوّدي المسارات
يتم توزيع موفِّر مسار الوسائط كجزء من تطبيق Android. يمكن أن يكون مزوّد المسار
إتاحتها للتطبيقات الأخرى من خلال تمديد
MediaRouteProviderService
أو الانتهاء من تنفيذ
MediaRouteProvider
بخدمتك الخاصة والإقرار بنية الشراء
عامل تصفية لمزود مسار الوسائط. تسمح هذه الخطوات للتطبيقات الأخرى باكتشاف
مسار الوسائط.
ملاحظة: يمكن أن يتضمّن التطبيق الذي يحتوي على موفِّر مسار الوسائط أيضًا واجهة MediaRouter موفر المسار، ولكن هذا ليس مطلوبًا.
مكتبة دعم MediaRouter
يتم تحديد واجهات برمجة التطبيقات لموجه الوسائط في مكتبة MediaRouter في AndroidX يجب إضافة هذه المكتبة إلى مشروع تطوير التطبيقات الخاص بك. لمزيد من المعلومات حول إضافة مكتبات الدعم إلى راجع إعداد مكتبة الدعم.
تنبيه: احرص على استخدام AndroidX
.
تنفيذ إطار عمل موجه الوسائط.
عدم استخدام حزمة android.media
القديمة
إنشاء خدمة مقدّم خدمة
يجب أن يتمكّن إطار عمل جهاز توجيه الوسائط من اكتشاف مزوّد مسار الوسائط والاتصال به
للسماح للتطبيقات الأخرى باستخدام مسارك. وللقيام بذلك، يتطلب
إطار عمل موجه الوسائط
يبحث عن التطبيقات التي تعلن عن إجراء موجَّه لموجّه الوسائط. عندما يريد تطبيق آخر
الاتصال بمزود الخدمة، يجب أن يكون إطار العمل قادرًا على استدعاءه والاتصال به، حتى يتمكن مقدم الخدمة
يجب تغليفها في Service
.
يوضح الرمز في المثال التالي إعلان خدمة موفر مسار الوسائط فلتر الأهداف في بيان، يسمح باكتشافه واستخدامه بواسطة جهاز توجيه الوسائط إطار العمل:
<service android:name=".provider.SampleMediaRouteProviderService" android:label="@string/sample_media_route_provider_service" android:process=":mrp"> <intent-filter> <action android:name="android.media.MediaRouteProviderService" /> </intent-filter> </service>
يوضِّح مثال البيان هذا خدمة تتضمّن فئات موفّري مسارات الوسائط الفعلية.
يوفر إطار عمل جهاز توجيه وسائط Android
فئة واحدة (MediaRouteProviderService
) يمكن استخدامها كخدمة تضمين في
ومقدمي مسارات الوسائط. يوضح المثال التالي كيفية استخدام برنامج تضمين هذا.
الفئة:
Kotlin
class SampleMediaRouteProviderService : MediaRouteProviderService() { override fun onCreateMediaRouteProvider(): MediaRouteProvider { return SampleMediaRouteProvider(this) } }
Java
public class SampleMediaRouteProviderService extends MediaRouteProviderService { @Override public MediaRouteProvider onCreateMediaRouteProvider() { return new SampleMediaRouteProvider(this); } }
تحديد إمكانات المسار
يمكن للتطبيقات المتصلة بإطار عمل جهاز توجيه الوسائط اكتشاف مسار الوسائط من خلال البيانات الوصفية للتطبيق، ولكنها بحاجة أيضًا إلى معرفة إمكانات مسارات الوسائط التي الجديدة. قد تكون مسارات الوسائط من أنواع مختلفة وتتميز بميزات مختلفة وتطبيقات أخرى. يجب أن يكونوا قادرين على اكتشاف هذه التفاصيل لتحديد ما إذا كانت متوافقة مع مسارك أم لا.
يتيح لك إطار عمل جهاز توجيه الوسائط تحديد إمكانات الوسائط الخاصة بك ونشرها.
مسار عبر عناصر IntentFilter
وكائنات MediaRouteDescriptor
وMediaRouteProviderDescriptor
. يوضح هذا القسم كيفية استخدام
الفئات لنشر تفاصيل مسار الوسائط في التطبيقات الأخرى.
فئات المسارات
كجزء من الوصف الآلي لمزوّد مسار الوسائط، يجب تحديد سواء كان موفر الخدمة يتيح التشغيل عن بُعد أو الإخراج الثانوي أو كليهما هذه هي المسارات الفئات التي يوفرها إطار عمل جهاز توجيه الوسائط:
CATEGORY_LIVE_AUDIO
— إخراج الصوت إلى جهاز إخراج ثانوي، مثل نظام تشغيل الموسيقى لاسلكيًاCATEGORY_LIVE_VIDEO
— إخراج الفيديو إلى جهاز إخراج ثانوي، مثل أجهزة العرض اللاسلكية.CATEGORY_REMOTE_PLAYBACK
: تشغيل الفيديو أو الصوت على جهاز منفصل يعالج الوسائط استرجاعها وفك ترميزها وتشغيلها مثل أجهزة Chromecast.
لتضمين هذه الإعدادات في وصف مسار الوسائط، يمكنك إدراجها في
عنصر IntentFilter
، ويمكنك إضافته لاحقًا إلى
كائن MediaRouteDescriptor
:
Kotlin
class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) { companion object { private val CONTROL_FILTERS_BASIC: ArrayList<IntentFilter> = IntentFilter().run { addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) arrayListOf(this) } } }
Java
public final class SampleMediaRouteProvider extends MediaRouteProvider { private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC; static { IntentFilter videoPlayback = new IntentFilter(); videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>(); CONTROL_FILTERS_BASIC.add(videoPlayback); } }
إذا حددت الغرض CATEGORY_REMOTE_PLAYBACK
، يجب أيضًا تحديد أنواع الوسائط
عناصر التحكّم في التشغيل متوافقة مع مزوّد مسار الوسائط. يصف القسم التالي كيفية
تحديد هذه الإعدادات لجهازك.
أنواع الوسائط والبروتوكولات
يجب أن يحدّد موفر مسار الوسائط لجهاز تشغيل عن بُعد أنواع الوسائط وعمليات النقل
والبروتوكولات التي يتوافق معها. يمكنك تحديد هذه الإعدادات باستخدام IntentFilter
الفئة وaddDataScheme()
addDataType()
طريقة لهذا الكائن. تشير رسالة الأشكال البيانية
يوضح مقتطف الرمز التالي كيفية تحديد فلتر أهداف لدعم الفيديوهات عن بُعد.
التشغيل باستخدام بروتوكول http وhttps وبروتوكول البث في الوقت الفعلي (RTSP):
Kotlin
class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) { companion object { private fun IntentFilter.addDataTypeUnchecked(type: String) { try { addDataType(type) } catch (ex: IntentFilter.MalformedMimeTypeException) { throw RuntimeException(ex) } } private val CONTROL_FILTERS_BASIC: ArrayList<IntentFilter> = IntentFilter().run { addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) addAction(MediaControlIntent.ACTION_PLAY) addDataScheme("http") addDataScheme("https") addDataScheme("rtsp") addDataTypeUnchecked("video/*") arrayListOf(this) } } ... }
Java
public final class SampleMediaRouteProvider extends MediaRouteProvider { private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC; static { IntentFilter videoPlayback = new IntentFilter(); videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); videoPlayback.addAction(MediaControlIntent.ACTION_PLAY); videoPlayback.addDataScheme("http"); videoPlayback.addDataScheme("https"); videoPlayback.addDataScheme("rtsp"); addDataTypeUnchecked(videoPlayback, "video/*"); CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>(); CONTROL_FILTERS_BASIC.add(videoPlayback); } ... private static void addDataTypeUnchecked(IntentFilter filter, String type) { try { filter.addDataType(type); } catch (MalformedMimeTypeException ex) { throw new RuntimeException(ex); } } }
عناصر التحكّم في التشغيل
على موفر مسار الوسائط الذي يوفر إمكانية التشغيل عن بُعد تحديد أنواع عناصر التحكم في الوسائط التي يدعمها. في ما يلي أنواع عناصر التحكُّم العامة التي يمكن أن توفِّرها مسارات الوسائط:
- عناصر التحكّم في التشغيل، مثل التشغيل والإيقاف المؤقت والترجيع والتقديم السريع
- ميزات إضافة العناصر إلى "قائمة المحتوى التالي" التي تسمح لتطبيق الإرسال بإضافة العناصر وإزالتها من قائمة تشغيل يحتفظ بها جهاز الاستقبال
- ميزات الجلسات، التي تمنع إرسال التطبيقات من التداخل مع كل أخرى من خلال توجيه جهاز المُستلِم إلى تقديم معرّف جلسة للتطبيق الذي قدّم الطلب ثمّ التحقّق هذا المعرّف مع كل طلب لاحق للتحكم في التشغيل.
يوضح مثال الرمز التالي كيفية إنشاء فلتر أهداف لدعم عناصر التحكم الأساسية في تشغيل مسار الوسائط:
Kotlin
class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) { companion object { ... private val CONTROL_FILTERS_BASIC: ArrayList<IntentFilter> = run { val videoPlayback: IntentFilter = ... ... val playControls = IntentFilter().apply { addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) addAction(MediaControlIntent.ACTION_SEEK) addAction(MediaControlIntent.ACTION_GET_STATUS) addAction(MediaControlIntent.ACTION_PAUSE) addAction(MediaControlIntent.ACTION_RESUME) addAction(MediaControlIntent.ACTION_STOP) } arrayListOf(videoPlayback, playControls) } } ... }
Java
public final class SampleMediaRouteProvider extends MediaRouteProvider { private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC; static { ... IntentFilter playControls = new IntentFilter(); playControls.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); playControls.addAction(MediaControlIntent.ACTION_SEEK); playControls.addAction(MediaControlIntent.ACTION_GET_STATUS); playControls.addAction(MediaControlIntent.ACTION_PAUSE); playControls.addAction(MediaControlIntent.ACTION_RESUME); playControls.addAction(MediaControlIntent.ACTION_STOP); CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>(); CONTROL_FILTERS_BASIC.add(videoPlayback); CONTROL_FILTERS_BASIC.add(playControls); } ... }
لمزيد من المعلومات حول أهداف التحكم في التشغيل المتاحة، راجع
صف واحد (MediaControlIntent
).
MediaRouteProviderDescriptor
بعد تحديد إمكانات مسار الوسائط باستخدام كائنات IntentFilter
، يمكنك إنشاء عنصر واصف للنشر عليه
إطار عمل جهاز توجيه وسائط Android. يحتوي عنصر الواصف هذا على تفاصيل الوسائط
إمكانات المسار كي تتمكن التطبيقات الأخرى من تحديد طريقة التفاعل مع الوسائط
المسار الصحيح.
يوضح رمز المثال التالي كيفية إضافة فلاتر الأهداف التي تم إنشاؤها سابقًا إلى
MediaRouteProviderDescriptor
وتعيين الواصف لاستخدامه في
إطار عمل جهاز توجيه الوسائط:
Kotlin
class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) { init { publishRoutes() } private fun publishRoutes() { val resources = context.resources val routeName: String = resources.getString(R.string.variable_volume_basic_route_name) val routeDescription: String = resources.getString(R.string.sample_route_description) // Create a route descriptor using previously created IntentFilters val routeDescriptor: MediaRouteDescriptor = MediaRouteDescriptor.Builder(VARIABLE_VOLUME_BASIC_ROUTE_ID, routeName) .setDescription(routeDescription) .addControlFilters(CONTROL_FILTERS_BASIC) .setPlaybackStream(AudioManager.STREAM_MUSIC) .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) .setVolumeMax(VOLUME_MAX) .setVolume(mVolume) .build() // Add the route descriptor to the provider descriptor val providerDescriptor: MediaRouteProviderDescriptor = MediaRouteProviderDescriptor.Builder() .addRoute(routeDescriptor) .build() // Publish the descriptor to the framework descriptor = providerDescriptor } ... }
Java
public SampleMediaRouteProvider(Context context) { super(context); publishRoutes(); } private void publishRoutes() { Resources r = getContext().getResources(); // Create a route descriptor using previously created IntentFilters MediaRouteDescriptor routeDescriptor = new MediaRouteDescriptor.Builder( VARIABLE_VOLUME_BASIC_ROUTE_ID, r.getString(R.string.variable_volume_basic_route_name)) .setDescription(r.getString(R.string.sample_route_description)) .addControlFilters(CONTROL_FILTERS_BASIC) .setPlaybackStream(AudioManager.STREAM_MUSIC) .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) .setVolumeMax(VOLUME_MAX) .setVolume(mVolume) .build(); // Add the route descriptor to the provider descriptor MediaRouteProviderDescriptor providerDescriptor = new MediaRouteProviderDescriptor.Builder() .addRoute(routeDescriptor) .build(); // Publish the descriptor to the framework setDescriptor(providerDescriptor); }
للمزيد من المعلومات حول إعدادات الوصف المتوفّرة، يُرجى الاطّلاع على المستندات المرجعية.
معلومات تسجيل الدخول إلى MediaRouteDescriptor
وMediaRouteProviderDescriptor
التحكم في المسارات
عند اتصال تطبيق بموفِّر مسار الوسائط، يتلقّى مقدّم الخدمة التشغيل
الأوامر من خلال إطار عمل جهاز توجيه الوسائط الذي ترسله تطبيقات أخرى إلى مسارك. للتعامل مع هذه الأمور
الطلبات، يجب تنفيذ فئة MediaRouteProvider.RouteController
تعالج الأوامر.
ويعالج الاتصال الفعلي بجهاز الاستقبال.
يستدعي إطار عمل جهاز توجيه الوسائط onCreateRouteController()
لمزود المسار للحصول على نسخة افتراضية من هذه الفئة ومن ثم توجيه الطلبات إليه.
هذه هي الطرق الرئيسية لفئة MediaRouteProvider.RouteController
، والتي يجب تنفيذها
مزوّد مسار الوسائط:
onSelect()
— يتم استدعاء هذا الإجراء عندما يختار أحد التطبيقات مسار التشغيل. تستخدم هذه الطريقة لإجراء أي أعمال تحضيرية قد تكون مطلوبة قبل بدء تشغيل الوسائط.onControlRequest()
- لإرسال أوامر تشغيل محدّدة إلى الجهاز المستلِمonSetVolume()
— يرسل طلبًا إلى الجهاز المستلِم لضبط مستوى صوت التشغيل على قيمة محددة.onUpdateVolume()
— لإرسال طلب إلى الجهاز المُستلِم لتعديل التشغيل الحجم بمقدار محدد.onUnselect()
— يتم الاتصال عند إلغاء اختيار أحد المسارات لمسار.onRelease()
— يتم استدعاء هذا الإجراء عندما لا يكون المسار مطلوبًا من قِبل إطار العمل، ما يتيح له إتاحة الموارد.
يتم توجيه جميع طلبات عناصر التحكّم في التشغيل إلى onControlRequest()
، باستثناء التغييرات في مستوى الصوت.
. يجب أن يحلّل تنفيذ هذه الطريقة طلبات التحكّم ويردّ عليها.
بشكل مناسب. إليك مثال على تنفيذ هذه الطريقة التي تعالج أوامر
مسار وسائط التشغيل عن بُعد:
Kotlin
private class SampleRouteController : MediaRouteProvider.RouteController() { ... override fun onControlRequest( intent: Intent, callback: MediaRouter.ControlRequestCallback? ): Boolean { return if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { val action = intent.action when (action) { MediaControlIntent.ACTION_PLAY -> handlePlay(intent, callback) MediaControlIntent.ACTION_ENQUEUE -> handleEnqueue(intent, callback) MediaControlIntent.ACTION_REMOVE -> handleRemove(intent, callback) MediaControlIntent.ACTION_SEEK -> handleSeek(intent, callback) MediaControlIntent.ACTION_GET_STATUS -> handleGetStatus(intent, callback) MediaControlIntent.ACTION_PAUSE -> handlePause(intent, callback) MediaControlIntent.ACTION_RESUME -> handleResume(intent, callback) MediaControlIntent.ACTION_STOP -> handleStop(intent, callback) MediaControlIntent.ACTION_START_SESSION -> handleStartSession(intent, callback) MediaControlIntent.ACTION_GET_SESSION_STATUS -> handleGetSessionStatus(intent, callback) MediaControlIntent.ACTION_END_SESSION -> handleEndSession(intent, callback) else -> false }.also { Log.d(TAG, sessionManager.toString()) } } else { false } } ... }
Java
private final class SampleRouteController extends MediaRouteProvider.RouteController { ... @Override public boolean onControlRequest(Intent intent, ControlRequestCallback callback) { String action = intent.getAction(); if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { boolean success = false; if (action.equals(MediaControlIntent.ACTION_PLAY)) { success = handlePlay(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_ENQUEUE)) { success = handleEnqueue(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_REMOVE)) { success = handleRemove(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_SEEK)) { success = handleSeek(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_GET_STATUS)) { success = handleGetStatus(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_PAUSE)) { success = handlePause(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_RESUME)) { success = handleResume(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_STOP)) { success = handleStop(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_START_SESSION)) { success = handleStartSession(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_GET_SESSION_STATUS)) { success = handleGetSessionStatus(intent, callback); } else if (action.equals(MediaControlIntent.ACTION_END_SESSION)) { success = handleEndSession(intent, callback); } Log.d(TAG, sessionManager.toString()); return success; } return false; } ... }
من المهم أن تفهم أنّ الفئة MediaRouteProvider.RouteController
تكون بمثابة برنامج تضمين
لواجهة برمجة التطبيقات إلى جهاز تشغيل الوسائط. يُعد تنفيذ الطرق في هذه الفئة
تعتمد كليًا على الواجهة الآلية التي يوفرها الجهاز المستلم.
نموذج التعليمات البرمجية
MediaRouter يعرض النموذج كيفية إنشاء موفر مسار وسائط مخصص.