نمای کلی MediaRouter

به منظور استفاده از چارچوب MediaRouter در برنامه خود، باید یک نمونه از شی MediaRouter دریافت کنید و یک شی MediaRouter.Callback را برای گوش دادن به رویدادهای مسیریابی پیوست کنید. محتوای ارسال شده از طریق یک مسیر رسانه از طریق MediaRouteProvider مرتبط با مسیر عبور می کند (به جز در چند مورد خاص، مانند دستگاه خروجی بلوتوث). شکل 1 نمای سطح بالایی از کلاس های مورد استفاده برای مسیریابی محتوا بین دستگاه ها را ارائه می دهد.

شکل 1. نمای کلی کلاس های کلیدی روتر رسانه ای که توسط برنامه ها استفاده می شود.

توجه: اگر می‌خواهید برنامه شما از دستگاه‌های Google Cast پشتیبانی کند، باید از Cast SDK استفاده کنید و برنامه خود را به‌عنوان فرستنده Cast بسازید. به جای استفاده مستقیم از چارچوب MediaRouter، دستورالعمل‌های موجود در مستندات Cast را دنبال کنید.

دکمه مسیر رسانه

برنامه های اندروید باید از دکمه مسیر رسانه برای کنترل مسیریابی رسانه استفاده کنند. چارچوب MediaRouter یک رابط استاندارد برای دکمه فراهم می‌کند که به کاربران کمک می‌کند مسیریابی را زمانی که در دسترس است تشخیص دهند و از آن استفاده کنند. همانطور که در شکل 2 نشان داده شده است، دکمه مسیر رسانه معمولاً در سمت راست نوار عملکرد برنامه شما قرار می گیرد.

شکل 2. دکمه مسیر رسانه در نوار عمل.

هنگامی که کاربر دکمه مسیر رسانه را فشار می دهد، مسیرهای رسانه موجود در لیستی مانند شکل 3 ظاهر می شوند.

شکل 3. فهرستی از مسیرهای رسانه موجود که پس از فشار دادن دکمه مسیر رسانه نشان داده شده است.

برای ایجاد دکمه مسیر رسانه این مراحل را دنبال کنید:

  1. از AppCompatActivity استفاده کنید
  2. آیتم منو دکمه مسیر رسانه را تعریف کنید
  3. یک MediaRouteSelector ایجاد کنید
  4. دکمه مسیر رسانه را به نوار اقدام اضافه کنید
  5. روش های MediaRouter.Callback را در چرخه عمر فعالیت خود ایجاد و مدیریت کنید

این بخش چهار مرحله اول را شرح می دهد. بخش بعدی روش های 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 ایجاد شد، انتخابگر را بسازید. توجه داشته باشید که انتخابگر در یک متغیر کلاس ذخیره می شود و انواع مسیرهای مجاز با افزودن اشیاء MediaControlIntent مشخص می شوند:

کاتلین

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()
    }
}

جاوا

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() را برای هر یک از فعالیت های خود نادیده بگیرید تا یک منوی گزینه اضافه کنید.

کاتلین

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
}

جاوا

@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;
}

برای اطلاعات بیشتر در مورد اجرای نوار اقدام در برنامه خود، به راهنمای توسعه دهنده Action Bar مراجعه کنید.

همچنین می توانید یک دکمه مسیر رسانه را به عنوان MediaRouteButton در هر نما اضافه کنید. شما باید یک MediaRouteSelector را با استفاده از متد setRouteSelector() به دکمه متصل کنید. برای دستورالعمل‌های مربوط به گنجاندن دکمه مسیر رسانه در برنامه خود، به چک لیست طراحی Google Cast مراجعه کنید.

تماس های MediaRouter

همه برنامه‌هایی که روی یک دستگاه اجرا می‌شوند، یک نمونه MediaRouter و مسیرهای آن را به اشتراک می‌گذارند (فیلتر شده در هر برنامه توسط MediaRouteSelector برنامه). هر فعالیت با استفاده از روش های MediaRouter.Callback خود با MediaRouter ارتباط برقرار می کند. MediaRouter هر زمان که کاربر مسیری را انتخاب کند، تغییر دهد یا قطع کند، روش‌های برگشت تماس را فراخوانی می‌کند.

روش‌های مختلفی در callback وجود دارد که می‌توانید برای دریافت اطلاعات در مورد رویدادهای مسیریابی، آنها را لغو کنید. حداقل، پیاده‌سازی کلاس MediaRouter.Callback شما باید روی onRouteSelected() و onRouteUnselected() را لغو کند.

از آنجایی که MediaRouter یک منبع مشترک است، برنامه شما باید در پاسخ به تماس‌های معمول چرخه حیات فعالیت، تماس‌های MediaRouter خود را مدیریت کند:

  • وقتی اکتیویتی ایجاد شد ( onCreate(Bundle) ) یک اشاره گر به MediaRouter بگیرید و برای تمام طول عمر برنامه روی آن نگه دارید.
  • وقتی اکتیویتی قابل مشاهده است ( onStart() ) فراخوان ها را به MediaRouter وصل کنید، و زمانی که مخفی شد ( onStop() ) آنها را جدا کنید.

نمونه کد زیر نحوه ایجاد و ذخیره شئ برگشت تماس، نحوه به دست آوردن نمونه ای از MediaRouter و نحوه مدیریت تماس های برگشتی را نشان می دهد. به استفاده از پرچم CALLBACK_FLAG_REQUEST_DISCOVERY هنگام پیوست کردن تماس‌های برگشتی در onStart() توجه کنید. این به MediaRouteSelector شما اجازه می‌دهد تا فهرست مسیرهای موجود دکمه مسیر رسانه را بازخوانی کند.

کاتلین

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()
    }
    ...
}

جاوا

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 API را بیشتر نشان می دهد.