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

لاستخدام إطار عمل MediaRouter في تطبيقك، يجب أن تحصل على مثال لكائن MediaRouter وإرفاق كائن MediaRouter.Callback للاستماع إلى أحداث التوجيه. المحتوى المُرسل عبر مسار وسائط يمر عبر MediaRouteProvider المرتبطة (باستثناء بعض الحالات الخاصة، مثل جهاز إخراج بلوتوث). يقدم الشكل 1 عرضًا عالي المستوى الفئات المستخدمة لتوجيه المحتوى بين الأجهزة.

الشكل 1. نظرة عامة على فئات أجهزة توجيه الوسائط الرئيسية التي تستخدمها التطبيقات.

ملاحظة: إذا كنت تريد أن يتوافق تطبيقك أجهزة Google Cast يجب استخدام حزمة تطوير البرامج (SDK) للبث وإنشاء تطبيقك كمرسل للبث. اتّبِع التوجيهات الواردة في مستندات البث بدلاً من استخدام إطار عمل MediaRouter مباشرةً.

زر مسار الوسائط

يجب أن تستخدم تطبيقات Android زر مسار الوسائط للتحكّم في توجيه الوسائط. إطار عمل MediaRouter توفر واجهة قياسية للزر، مما يساعد المستخدمين على التعرف على التوجيه واستخدامه عندما يكون متاحًا. عادة ما يتم وضع زر مسار الوسائط على الجانب الأيمن من شريط إجراءات التطبيق، كما هو موضح في الشكل 2.

الشكل 2. زر مسار الوسائط في شريط الإجراءات.

عندما يضغط المستخدم على زر مسار الوسائط، تظهر مسارات الوسائط المتاحة في قائمة كما هو موضح في الشكل 3.

الشكل 3. قائمة بمسارات الوسائط المتاحة، تظهر بعد الضغط على زر مسار الوسائط.

اتبع الخطوات التالية لإنشاء زر مسار الوسائط:

  1. استخدام AppCompatActivity
  2. تحديد عنصر القائمة لزر مسار الوسائط
  3. إنشاء MediaRouteSelector
  4. إضافة زر مسار الوسائط إلى شريط الإجراءات
  5. إنشاء وإدارة طرق MediaRouter.Callback في مراحل نشاطك

يصف هذا القسم الخطوات الأربع الأولى. يصف القسم التالي طرق معاودة الاتصال.

استخدام AppCompatActivity

عندما تستخدم إطار عمل جهاز توجيه الوسائط في نشاط يجب تمديده النشاط من "AppCompatActivity" واستيراد الحزمة رقم androidx.appcompat.app. يجب إضافة androidx.appcompat:appcompat وandroidx.mediarouter:mediarouter مكتبات الدعم لمشروع تطوير التطبيقات. لمزيد من المعلومات حول إضافة مكتبات الدعم على مشروعك، يُرجى الاطّلاع على مقالة بدء استخدام Android Jetpack.

تنبيه: احرص على استخدام androidx. تنفيذ إطار عمل موجه الوسائط. عدم استخدام حزمة android.media القديمة

أنشِئ ملف XML يحدّد عنصر قائمة لزر مسار الوسائط. يجب أن يكون إجراء العنصر هو الفئة MediaRouteActionProvider. إليك مثال على ملف:

// myMediaRouteButtonMenuItem.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      >

    <item android:id="@+id/media_route_menu_item"
        android:title="@string/media_route_menu_title"
        app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
        app:showAsAction="always"
    />
</menu>

إنشاء MediaRouteSelector

يتم تحديد المسارات التي تظهر في قائمة أزرار مسار الوسائط من قِبل MediaRouteSelector. زيادة نشاطك بدءًا من AppCompatActivity وإنشاء أداة الاختيار عند إنشاء نشاط استدعاء "MediaRouteSelector.Builder" من طريقة onCreate() كما هو موضح في عينة التعليمة البرمجية التالية. تجدر الإشارة إلى أنّه يتم حفظ أداة الاختيار في متغيّر الفئة، وقد تم تحديد أنواع المسارات المسموح بها. من خلال إضافة MediaControlIntent عنصر:

Kotlin

class MediaRouterPlaybackActivity : AppCompatActivity() {

    private var mSelector: MediaRouteSelector? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Create a route selector for the type of routes your app supports.
        mSelector = MediaRouteSelector.Builder()
                // These are the framework-supported intents
                .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
                .build()
    }
}

Java

public class MediaRouterPlaybackActivity extends AppCompatActivity {
    private MediaRouteSelector mSelector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Create a route selector for the type of routes your app supports.
        mSelector = new MediaRouteSelector.Builder()
                // These are the framework-supported intents
                .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
                .build();
    }
}

بالنسبة لمعظم التطبيقات، فإن الطريقة الوحيدة نوع المسار المطلوب هو CATEGORY_REMOTE_PLAYBACK. يتعامل نوع المسار هذا مع الجهاز الذي يُشغِّل تطبيقك على أنّه جهاز تحكُّم عن بُعد. يتولّى جهاز الاستقبال المتصل عمليات استرداد جميع بيانات المحتوى وفك ترميزها وتشغيلها. هذه هي الطريقة التي تتوافق بها التطبيقات التي تتوافق مع Google Cast، مثل Chromecast

توفر بعض الشركات المصنعة خيار توجيه خاصًا يسمى "الإخراج الثانوي". باستخدام هذا التوجيه، يصبح الوسائط التي يسترجع الفيديو أو الموسيقى ويعرضه ويبثه مباشرةً إلى الشاشة و/أو مكبرات الصوت في جهاز الاستقبال البعيد المحدد. استخدام إخراج ثانوي لإرسال المحتوى إلى أنظمة تشغيل موسيقية أو شاشات فيديو لاسلكية لتمكين اكتشاف اختيار هذه الأجهزة، يجب إضافة CATEGORY_LIVE_AUDIO أو CATEGORY_LIVE_VIDEO فئات التحكم في MediaRouteSelector. يجب أيضًا إنشاء مربّع حوار Presentation الخاص بك والتعامل معه.

إضافة زر مسار الوسائط إلى شريط الإجراءات

من خلال قائمة مسارات الوسائط وتحديد MediaRouteSelector، يمكنك الآن إضافة زر مسار الوسائط إلى أحد الأنشطة. لإضافة خيارات، يجب إلغاء طريقة onCreateOptionsMenu() لكل نشاط من أنشطتك. القائمة.

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    super.onCreateOptionsMenu(menu)

    // Inflate the menu and configure the media router action provider.
    menuInflater.inflate(R.menu.sample_media_router_menu, menu)

    // Attach the MediaRouteSelector to the menu item
    val mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item)
    val mediaRouteActionProvider =
            MenuItemCompat.getActionProvider(mediaRouteMenuItem) as MediaRouteActionProvider

    // Attach the MediaRouteSelector that you built in onCreate()
    selector?.also(mediaRouteActionProvider::setRouteSelector)

    // Return true to show the menu.
    return true
}

Java

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);

    // Inflate the menu and configure the media router action provider.
    getMenuInflater().inflate(R.menu.sample_media_router_menu, menu);

    // Attach the MediaRouteSelector to the menu item
    MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item);
    MediaRouteActionProvider mediaRouteActionProvider =
            (MediaRouteActionProvider)MenuItemCompat.getActionProvider(
            mediaRouteMenuItem);
    // Attach the MediaRouteSelector that you built in onCreate()
    mediaRouteActionProvider.setRouteSelector(selector);

    // Return true to show the menu.
    return true;
}

لمزيد من المعلومات حول تنفيذ شريط الإجراءات في تطبيقك، راجِع شريط الإجراءات دليل المطوِّرين.

يمكنك أيضًا إضافة زر مسار الوسائط كـ MediaRouteButton في أي مشاهدة. يجب إرفاق MediaRouteSelector بالزرّ باستخدام طريقة setRouteSelector(). يمكنك الاطّلاع على قائمة التحقّق من تصميم Google Cast للحصول على إرشادات حول دمج زر مسار الوسائط في تطبيقك.

عمليات معاودة الاتصال بجهاز MediaRouter

تتشارك جميع التطبيقات التي تعمل على الجهاز نفسه في نسخة افتراضية واحدة من "MediaRouter" ومساراته. (تتم فلترته لكل تطبيق من خلال MediaRouteSelector الخاص بالتطبيق). يتصل كل نشاط بجهاز MediaRouter. باستخدام تطبيقه الخاص لـ MediaRouter.Callback الطرق. يطلب جهاز MediaRouter طرق معاودة الاتصال عندما يختار المستخدم مسارًا أو يغيّره أو يقطعه.

هناك عدة طرق في معاودة الاتصال يمكنك تجاوزها لتلقي معلومات عن أحداث التوجيه. يجب على الأقل أن تلغي تنفيذ الفئة MediaRouter.Callback onRouteSelected() و onRouteUnselected()

بما أنّ MediaRouter هو مورد مشترك، يحتاج تطبيقك إلى إدارة عمليات معاودة الاتصال الخاصة به على MediaRouter. استجابةً لعمليات الاستدعاء في مراحل نشاط النشاط المعتادة:

  • عند إنشاء النشاط (onCreate(Bundle))، مرِّر مؤشر الماوس إلى MediaRouter واحتفظ به طوال فترة استخدام التطبيق.
  • إرفاق عمليات معاودة الاتصال بـ MediaRouter عندما يصبح النشاط مرئيًا (onStart())، وفصلها عندما يكون مخفيًا (onStop()).

يوضح نموذج التعليمة البرمجية التالي كيفية لإنشاء كائن معاودة الاتصال وحفظه، وكيفية الحصول على مثال MediaRouter، وكيفية إدارة عمليات الاسترداد. لاحظ استخدام علامة CALLBACK_FLAG_REQUEST_DISCOVERY عند إرفاق استدعاءات في onStart(). يسمح هذا لأداة MediaRouteSelector بإعادة تحميل أزرار مسار الوسائط. قائمة المسارات المتاحة.

Kotlin

class MediaRouterPlaybackActivity : AppCompatActivity() {

    private var mediaRouter: MediaRouter? = null
    private var mSelector: MediaRouteSelector? = null

    // Variables to hold the currently selected route and its playback client
    private var mRoute: MediaRouter.RouteInfo? = null
    private var remotePlaybackClient: RemotePlaybackClient? = null

    // Define the Callback object and its methods, save the object in a class variable
    private val mediaRouterCallback = object : MediaRouter.Callback() {

        override fun onRouteSelected(router: MediaRouter, route: MediaRouter.RouteInfo) {
            Log.d(TAG, "onRouteSelected: route=$route")
            if (route.supportsControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
                // Stop local playback (if necessary)
                // ...

                // Save the new route
                mRoute = route

                // Attach a new playback client
                remotePlaybackClient =
                    RemotePlaybackClient(this@MediaRouterPlaybackActivity, mRoute)

                // Start remote playback (if necessary)
                // ...
            }
        }

        override fun onRouteUnselected(
                router: MediaRouter,
                route: MediaRouter.RouteInfo,
                reason: Int
        ) {
            Log.d(TAG, "onRouteUnselected: route=$route")
            if (route.supportsControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {

                // Changed route: tear down previous client
                mRoute?.also {
                    remotePlaybackClient?.release()
                    remotePlaybackClient = null
                }

                // Save the new route
                mRoute = route

                when (reason) {
                    MediaRouter.UNSELECT_REASON_ROUTE_CHANGED -> {
                        // Resume local playback (if necessary)
                        // ...
                    }
                }
            }
        }
    }


    // Retain a pointer to the MediaRouter
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Get the media router service.
        mediaRouter = MediaRouter.getInstance(this)
        ...
    }

    // Use this callback to run your MediaRouteSelector to generate the
    // list of available media routes
    override fun onStart() {
        mSelector?.also { selector ->
            mediaRouter?.addCallback(selector, mediaRouterCallback,
                    MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY)
        }
        super.onStart()
    }

    // Remove the selector on stop to tell the media router that it no longer
    // needs to discover routes for your app.
    override fun onStop() {
        mediaRouter?.removeCallback(mediaRouterCallback)
        super.onStop()
    }
    ...
}

Java

public class MediaRouterPlaybackActivity extends AppCompatActivity {
    private MediaRouter mediaRouter;
    private MediaRouteSelector mSelector;

    // Variables to hold the currently selected route and its playback client
    private MediaRouter.RouteInfo mRoute;
    private RemotePlaybackClient remotePlaybackClient;

    // Define the Callback object and its methods, save the object in a class variable
    private final MediaRouter.Callback mediaRouterCallback =
            new MediaRouter.Callback() {

        @Override
        public void onRouteSelected(MediaRouter router, RouteInfo route) {
            Log.d(TAG, "onRouteSelected: route=" + route);

            if (route.supportsControlCategory(
                MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){
                // Stop local playback (if necessary)
                // ...

                // Save the new route
                mRoute = route;

                // Attach a new playback client
                remotePlaybackClient = new RemotePlaybackClient(this, mRoute);

                // Start remote playback (if necessary)
                // ...
            }
        }

        @Override
        public void onRouteUnselected(MediaRouter router, RouteInfo route, int reason) {
            Log.d(TAG, "onRouteUnselected: route=" + route);

            if (route.supportsControlCategory(
                MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){

                // Changed route: tear down previous client
                if (mRoute != null && remotePlaybackClient != null) {
                    remotePlaybackClient.release();
                    remotePlaybackClient = null;
                }

                // Save the new route
                mRoute = route;

                if (reason != MediaRouter.UNSELECT_REASON_ROUTE_CHANGED) {
                    // Resume local playback  (if necessary)
                    // ...
                }
            }
        }
    }


    // Retain a pointer to the MediaRouter
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Get the media router service.
        mediaRouter = MediaRouter.getInstance(this);
        ...
    }

    // Use this callback to run your MediaRouteSelector to generate the list of available media routes
    @Override
    public void onStart() {
        mediaRouter.addCallback(mSelector, mediaRouterCallback,
                MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
        super.onStart();
    }

    // Remove the selector on stop to tell the media router that it no longer
    // needs to discover routes for your app.
    @Override
    public void onStop() {
        mediaRouter.removeCallback(mediaRouterCallback);
        super.onStop();
    }
    ...
}

يوفر إطار عمل موجه الوسائط أيضًا MediaRouteDiscoveryFragment، تهتم بإضافة أو إزالة رد الاتصال لأحد الأنشطة.

ملاحظة: إذا كنت تكتب تطبيقًا لتشغيل الموسيقى وتريد تشغيل التطبيق الموسيقى أثناء تشغيلها في الخلفية، يجب إنشاء Service لتشغيلها. والاتصال بإطار عمل جهاز توجيه الوسائط من عمليات معاودة الاتصال بمراحل نشاط الخدمة.

التحكم في مسار تشغيل عن بُعد

عند اختيار مسار تشغيل عن بُعد، يعمل تطبيقك كوحدة تحكّم عن بُعد. الجهاز في الطرف الآخر من المسار تتعامل مع جميع وظائف استرجاع بيانات المحتوى وفك ترميزها وتشغيلها. تتواصل عناصر التحكّم في واجهة مستخدم التطبيق مع الجهاز المستلِم باستخدام عنصر RemotePlaybackClient.

توفّر الفئة RemotePlaybackClient طرقًا إضافية. لإدارة تشغيل المحتوى في ما يلي بعض طُرق التشغيل الرئيسية من الفئة RemotePlaybackClient:

  • play() — تشغيل أغنية محدّدة ملف وسائط محدد بواسطة Uri.
  • pause() — إيقاف يتم تشغيل مقطع وسائط حاليًا.
  • resume() — متابعة تشغيل المسار الحالي بعد أمر إيقاف مؤقت.
  • seek(): الانتقال إلى مكان محدّد الموضع في المسار الحالي.
  • release() — تمزيق الاتصال من تطبيقك بجهاز التشغيل عن بُعد.

يمكنك استخدام هذه الطرق لإرفاق إجراءات بعناصر التحكم في التشغيل التي توفرها في التطبيق. تتيح لك معظم هذه الطرق أيضًا تضمين كائن رد اتصال حتى تتمكن من مراقبة مستوى تقدم مهمة التشغيل أو طلب التحكم.

تتيح الفئة RemotePlaybackClient أيضًا وضع ملفات وسائط متعددة لتشغيل وإدارة قائمة انتظار الوسائط.

نموذج التعليمات البرمجية

جهاز Android BasicMediaRouter وMediaRouter توضح استخدام واجهة برمجة التطبيقات MediaRouter بشكل أكبر.