چارچوب مسیریاب رسانه Android به سازندگان امکان میدهد پخش را در دستگاههایشان
ازطریق میانای استانداردشدهای بهنام MediaRouteProvider فعال کنند.
ارائهدهنده مسیر، رابط مشترکی برای پخش رسانه در دستگاه گیرنده تعریف میکند و امکان پخش رسانه در تجهیزات شما را از هر برنامه Android که از مسیرهای رسانه پشتیبانی میکند فراهم میکند.
این راهنما نحوه ایجاد ارائهدهنده مسیر رسانه برای دستگاه گیرنده و دردسترس قرار دادن آن برای سایر برنامههای بازپخش رسانه را که در Android اجرا میشوند توضیح میدهد. برای استفاده از این میانای برنامهسازی کاربردی،
باید با کلاسهای کلیدی
MediaRouteProvider،
MediaRouteProviderDescriptor، و
RouteController آشنا باشید.
نمای کلی
چارچوب مسیریاب رسانه Android به توسعهدهندگان برنامه رسانه و سازندگان دستگاه پخش رسانه امکان میدهد
ازطریق میانای برنامهسازی کاربردی مشترک و میانای کاربر مشترک به یکدیگر متصل شوند. توسعهدهندگان برنامهای که
میانای MediaRouter را پیادهسازی میکنند میتوانند به
چارچوب متصل شوند و محتوا را در دستگاههایی که در چارچوب مسیریاب رسانه مشارکت دارند پخش کنند. سازندگان دستگاههای بازپخش رسانه میتوانند با انتشار MediaRouteProvider در چارچوب شرکت کنند که به برنامههای دیگر اجازه میدهد به دستگاههای گیرنده متصل شوند و رسانه پخش کنند. شکل ۱ نشان میدهد که چگونه یک برنامه ازطریق چارچوب مسیریاب رسانه به یک دستگاه گیرنده متصل میشود.
شکل ۱. نمای کلی از نحوه ارائه ارتباط از برنامه رسانه به دستگاه گیرنده توسط کلاسهای ارائهدهنده مسیر رسانه.
وقتی ارائهدهنده مسیر رسانه را برای دستگاه گیرنده میسازید، ارائهدهنده اهداف زیر را دنبال میکند:
- قابلیتهای دستگاه گیرنده را شرح دهید و منتشر کنید تا برنامههای دیگر بتوانند آن را پیدا کنند و از ویژگیهای بازپخش آن استفاده کنند.
- میانای برنامهنویسی دستگاه گیرنده و سازوکارهای انتقال ارتباط آن را بپوشانید تا دستگاه با چارچوب رهیاب رسانه سازگار شود.
توزیع ارائهدهندگان مسیر
ارائهدهنده مسیر رسانه بهعنوان بخشی از برنامه Android توزیع میشود. ارائهدهنده مسیر شما میتواند
با گسترش دادن
MediaRouteProviderService یا پیچیدن پیادهسازی شما از
MediaRouteProvider با سرویس خودتان و اعلام فیلتر قصد
برای ارائهدهنده مسیر رسانه، برای برنامههای دیگر دردسترس قرار گیرد. این مراحل به برنامههای دیگر اجازه میدهد مسیر رسانه شما را پیدا کنند و از آن استفاده کنند.
توجه: برنامهای که حاوی ارائهدهنده مسیر رسانه است میتواند شامل یک میانای MediaRouter به ارائهدهنده مسیر باشد، اما این الزامی نیست.
کتابخانه پشتیبانی MediaRouter
APIهای مسیریاب رسانه در کتابخانه AndroidX MediaRouter تعریف شدهاند باید این کتابخانه را به پروژه توسعه برنامهتان اضافه کنید. برای اطلاعات بیشتر درباره افزودن کتابخانههای پشتیبانی به پروژهتان، به راهاندازی کتابخانه پشتیبانی مراجعه کنید.
احتیاط: حتماً از پیادهسازی 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 را برای استفاده بهعنوان پوشاننده سرویس برای ارائهدهندگان مسیر رسانه ارائه میدهد. کد نمونه زیر نحوه استفاده از این کلاس پوشاننده را نشان میدهد:
کاتلین
class SampleMediaRouteProviderService : MediaRouteProviderService() { override fun onCreateMediaRouteProvider(): MediaRouteProvider { return SampleMediaRouteProvider(this) } }
جاوا
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 اضافه میکنید:
کاتلین
class SampleMediaRouteProvider(context: Context) : MediaRouteProvider(context) { companion object { private val CONTROL_FILTERS_BASIC: ArrayList<IntentFilter> = IntentFilter().run { addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) arrayListOf(this) } } }
جاوا
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) تعریف کنید:
کاتلین
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) } } ... }
جاوا
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); } } }
کنترلهای بازپخش
ارائهدهنده مسیر رسانهای که بازپخش از راه دور ارائه میدهد باید انواع کنترلهای رسانهای را که پشتیبانی میکند مشخص کند. اینها انواع کلی کنترلهایی هستند که مسیرهای رسانه میتوانند ارائه دهند:
- کنترلهای بازپخش، مانند پخش، مکث، عقب بردن، و جلو بردن سریع.
- ویژگیهای صفبندی که به برنامه ارسالکننده اجازه میدهد موارد را به فهرست پخشی که توسط دستگاه گیرنده نگهداری میشود اضافه یا از آن حذف کند.
- ویژگیهای جلسه که با ارائه شناسه جلسه به برنامه درخواستکننده توسط دستگاه گیرنده و سپس بررسی آن شناسه با هر درخواست کنترل بازپخش بعدی، از تداخل برنامههای ارسالکننده با یکدیگر جلوگیری میکند.
نمونه کد زیر نشان میدهد که چگونه میتوان فیلتر قصدی برای پشتیبانی از کنترلهای بازپخش مسیر رسانه پایه ساخت:
کاتلین
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) } } ... }
جاوا
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 اضافه کنید و توصیفگر را برای استفاده توسط
چارچوب مسیریاب رسانه تنظیم کنید:
کاتلین
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 } ... }
جاوا
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()— Called when an application unselects a route.onRelease()— زمانی فراخوانی میشود که چارچوب دیگر به مسیر نیاز نداشته باشد و به آن اجازه میدهد منابع خود را آزاد کند.
همه درخواستهای کنترل بازپخش، بهجز تغییرات میزان صدا، به روش onControlRequest()
هدایت میشوند. پیادهسازی شما از این روش باید درخواستهای کنترل را تجزیه کند و بهطور مناسب به آنها پاسخ دهد. در اینجا نمونهای از پیادهسازی این روش آورده شده است که فرمانهای مربوط به
مسیر رسانه بازپخش از راه دور را پردازش میکند:
کاتلین
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 } } ... }
جاوا
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 نحوه ایجاد ارائهدهنده مسیر رسانه سفارشی را نشان میدهد.