نظرة عامة على MediaRouteProvider

يتيح إطار عمل جهاز توجيه وسائط Android للشركات المصنّعة إمكانية تشغيل المحتوى على أجهزتهم. من خلال واجهة موحّدة تُسمى MediaRouteProvider. يحدد موفر المسار واجهة مشتركة لتشغيل الوسائط على جهاز الاستقبال، مما يجعلها إمكانية تشغيل الوسائط على جهازك من أي تطبيق Android يتيح تشغيل الوسائط والمسارات.

يناقش هذا الدليل كيفية إنشاء مزوّد مسار وسائط لجهاز الاستقبال وجعله متوفرًا لتطبيقات تشغيل الوسائط الأخرى التي تعمل على نظام التشغيل Android. لاستخدام واجهة برمجة التطبيقات هذه، على دراية بالفئات الرئيسية MediaRouteProvider، MediaRouteProviderDescriptor و RouteController

نظرة عامة

يتيح إطار عمل جهاز توجيه الوسائط لنظام التشغيل Android لمطوّري تطبيقات الوسائط وأجهزة تشغيل الوسائط الشركات المصنّعة للاتصال من خلال واجهة برمجة تطبيقات مشتركة وواجهة مستخدم مشتركة. مطورو التطبيقات الذين تنفيذ واجهة MediaRouter حتى يمكن الاتصال إطار عمل تشغيل المحتوى على الأجهزة التي تشارك في إطار عمل موجِّه الوسائط. الوسائط يمكن للشركات المصنّعة لأجهزة التشغيل المشاركة في إطار العمل من خلال نشر MediaRouteProvider يسمح للتطبيقات الأخرى بالاتصال تشغيل الوسائط على أجهزة الاستقبال يوضح الشكل 1 كيفية اتصال أحد التطبيقات بجهاز استقبال الجهاز من خلال إطار عمل موجه الوسائط.

الشكل 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 يعرض النموذج كيفية إنشاء موفر مسار وسائط مخصص.