Khung bộ định tuyến nội dung đa phương tiện của Android cho phép nhà sản xuất phát trên thiết bị của họ
thông qua một giao diện chuẩn hoá có tên là MediaRouteProvider
.
Trình cung cấp tuyến định nghĩa một giao diện chung để phát nội dung nghe nhìn trên thiết bị nhận, giúp
có thể phát phương tiện trên thiết bị của bạn từ bất kỳ ứng dụng Android nào hỗ trợ phương tiện
tuyến đường.
Hướng dẫn này thảo luận cách tạo trình cung cấp định tuyến nội dung đa phương tiện cho thiết bị nhận và cách tạo trình cung cấp đó
có sẵn cho các ứng dụng phát nội dung nghe nhìn khác chạy trên Android. Để sử dụng API này, bạn
nên làm quen với các lớp chính
MediaRouteProvider
!
MediaRouteProviderDescriptor
và
RouteController
.
Tổng quan
Khung bộ định tuyến nội dung đa phương tiện của Android cho phép các nhà phát triển ứng dụng đa phương tiện và thiết bị phát nội dung đa phương tiện
để kết nối thông qua một API chung và giao diện người dùng chung. Nhà phát triển ứng dụng
triển khai giao diện MediaRouter
, sau đó có thể kết nối với
khung và phát nội dung tới các thiết bị tham gia vào khung bộ định tuyến đa phương tiện. Nội dung đa phương tiện
nhà sản xuất thiết bị phát có thể tham gia khung này bằng cách phát hành một MediaRouteProvider
cho phép các ứng dụng khác kết nối và
phát nội dung nghe nhìn trên thiết bị nhận. Hình 1 minh hoạ cách một ứng dụng kết nối với một dịch vụ nhận
thông qua khung bộ định tuyến phương tiện.
Khi bạn tạo nhà cung cấp tuyến nội dung đa phương tiện cho thiết bị nhận, nhà cung cấp đó sẽ phân phát mục đích sau đây:
- Mô tả và công bố chức năng của thiết bị nhận để các ứng dụng khác có thể khám phá và sử dụng các tính năng phát của YouTube.
- Gói giao diện lập trình của thiết bị nhận và hoạt động giao tiếp của thiết bị nhận cơ chế truyền tải để thiết bị tương thích với khung bộ định tuyến đa phương tiện.
Phân phối các nhà cung cấp tuyến đường
Nhà cung cấp tuyến nội dung nghe nhìn được phân phối như một phần của ứng dụng Android. Nhà cung cấp tuyến đường của bạn có thể là
cung cấp cho các ứng dụng khác bằng cách mở rộng
MediaRouteProviderService
hoặc gói việc triển khai của bạn
MediaRouteProvider
bằng dịch vụ của riêng bạn và khai báo ý định
cho nhà cung cấp định tuyến nội dung đa phương tiện. Các bước này giúp các ứng dụng khác khám phá và sử dụng
tuyến nội dung đa phương tiện của bạn.
Lưu ý: Ứng dụng chứa trình cung cấp tuyến nội dung đa phương tiện cũng có thể bao gồm Giao diện MediaRouter sang nhà cung cấp tuyến đường, nhưng điều này là không bắt buộc.
Thư viện hỗ trợ MediaRouter
API bộ định tuyến phương tiện được xác định trong Thư viện AndroidX MediaRouter Bạn phải thêm thư viện này vào dự án phát triển ứng dụng của mình. Để biết thêm thông tin về cách thêm thư viện hỗ trợ vào hãy xem phần Thiết lập Thư viện hỗ trợ.
Thận trọng: Hãy nhớ sử dụng AndroidX
khung bộ định tuyến phương tiện.
Không sử dụng gói android.media
cũ.
Tạo Dịch vụ của nhà cung cấp
Khung bộ định tuyến nội dung đa phương tiện phải có khả năng tìm thấy và kết nối với nhà cung cấp định tuyến nội dung đa phương tiện của bạn
để cho phép các ứng dụng khác sử dụng tuyến đường của bạn. Để thực hiện việc này, khung bộ định tuyến phương tiện
tìm các ứng dụng khai báo thao tác theo ý định của trình cung cấp tuyến nội dung đa phương tiện. Khi một ứng dụng khác muốn
kết nối với nhà cung cấp của bạn, khung phải có thể gọi và kết nối với nó, để nhà cung cấp của bạn
phải được gói gọn trong Service
.
Đoạn mã ví dụ sau đây cho thấy phần khai báo dịch vụ nhà cung cấp định tuyến nội dung đa phương tiện và bộ lọc ý định trong tệp kê khai, qua đó bộ định tuyến nội dung đa phương tiện có thể phát hiện và sử dụng bộ lọc này khung:
<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>
Ví dụ về tệp kê khai này khai báo một dịch vụ bao bọc các lớp thực tế của trình cung cấp định tuyến phương tiện.
Khung bộ định tuyến nội dung đa phương tiện của Android cung cấp
Lớp MediaRouteProviderService
để dùng làm trình bao bọc dịch vụ cho
nhà cung cấp định tuyến nội dung đa phương tiện. Mã ví dụ sau đây minh hoạ cách sử dụng trình bao bọc này
lớp:
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); } }
Chỉ định khả năng định tuyến
Các ứng dụng kết nối với khung bộ định tuyến phương tiện có thể khám phá tuyến phương tiện của bạn thông qua nội dung khai báo tệp kê khai của ứng dụng, nhưng chúng cũng cần biết khả năng của các tuyến nội dung đa phương tiện mà bạn đang cung cấp. Các tuyến nội dung đa phương tiện có thể thuộc nhiều loại và có các tính năng khác nhau cũng như các ứng dụng khác cần phải khám phá những chi tiết này để xác định xem chúng có tương thích với tuyến đường của bạn hay không.
Khung bộ định tuyến nội dung đa phương tiện cho phép bạn xác định và xuất bản khả năng của nội dung nghe nhìn
định tuyến qua đối tượng IntentFilter
, đối tượng MediaRouteDescriptor
và MediaRouteProviderDescriptor
. Phần này giải thích cách sử dụng
để xuất bản chi tiết về tuyến nội dung đa phương tiện của bạn cho các ứng dụng khác.
Danh mục tuyến đường
Trong phần mô tả có lập trình của nhà cung cấp định tuyến phương tiện, bạn phải chỉ định nhà cung cấp của bạn hỗ trợ phát từ xa, đầu ra phụ hay cả hai. Đây là tuyến đường có các danh mục do khung bộ định tuyến phương tiện cung cấp:
CATEGORY_LIVE_AUDIO
— Đầu ra âm thanh sang thiết bị đầu ra phụ, chẳng hạn như hệ thống phát nhạc hỗ trợ không dây.CATEGORY_LIVE_VIDEO
— Đầu ra video sang thiết bị đầu ra phụ, chẳng hạn như các thiết bị Hiển thị không dây.CATEGORY_REMOTE_PLAYBACK
– Phát video hoặc âm thanh trên một thiết bị riêng biệt có chức năng xử lý nội dung nghe nhìn truy xuất, giải mã và phát lại, chẳng hạn như Thiết bị Chromecast.
Để đưa những chế độ cài đặt này vào nội dung mô tả tuyến đường truyền thông của bạn, hãy chèn các chế độ cài đặt này vào
đối tượng IntentFilter
mà sau đó bạn thêm vào một đối tượng
Đối tượng 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); } }
Nếu chỉ định ý định CATEGORY_REMOTE_PLAYBACK
, bạn cũng phải xác định loại nội dung đa phương tiện và
bộ điều khiển chế độ phát được nhà cung cấp định tuyến nội dung nghe nhìn của bạn hỗ trợ. Phần tiếp theo mô tả cách
chỉ định các chế độ cài đặt này cho thiết bị của bạn.
Loại phương tiện và giao thức
Nhà cung cấp tuyến nội dung đa phương tiện cho thiết bị phát từ xa phải chỉ định loại nội dung nghe nhìn và quá trình chuyển
các giao thức mà nó hỗ trợ. Bạn chỉ định các chế độ cài đặt này bằng IntentFilter
lớp này cũng như addDataScheme()
và
Phương thức addDataType()
của đối tượng đó. Chiến lược phát hành đĩa đơn
đoạn mã sau đây minh hoạ cách xác định bộ lọc ý định để hỗ trợ video từ xa
phát lại bằng http, https và Giao thức truyền trực tuyến theo thời gian thực (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); } } }
Bộ điều khiển chế độ phát
Nhà cung cấp định tuyến nội dung nghe nhìn có thể phát từ xa phải chỉ định các loại chế độ điều khiển nội dung nghe nhìn mà nó hỗ trợ. Dưới đây là các loại quyền kiểm soát chung mà các tuyến nội dung đa phương tiện có thể cung cấp:
- Các nút điều khiển chế độ phát, chẳng hạn như phát, tạm dừng, tua lại và tua đi.
- Các tính năng xếp hàng đợi, cho phép ứng dụng gửi thêm và xoá các mục từ một danh sách phát do thiết bị nhận duy trì.
- Tính năng phiên, giúp ngăn chặn việc gửi các ứng dụng can thiệp vào từng tính năng khác bằng cách yêu cầu thiết bị nhận cung cấp id phiên cho ứng dụng yêu cầu, sau đó kiểm tra mã đó với mỗi yêu cầu điều khiển phát tiếp theo.
Ví dụ về mã sau đây minh hoạ cách tạo bộ lọc ý định để hỗ trợ bộ điều khiển chế độ phát định tuyến nội dung nghe nhìn cơ bản:
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); } ... }
Để biết thêm thông tin về các ý định điều khiển chế độ phát hiện có, hãy xem
Lớp MediaControlIntent
.
MediaRouteProviderDescriptor
Sau khi xác định khả năng của tuyến nội dung đa phương tiện bằng đối tượng IntentFilter
, bạn có thể tạo đối tượng mô tả để xuất bản lên
khung bộ định tuyến nội dung đa phương tiện của Android. Đối tượng mô tả này chứa các thông tin cụ thể về nội dung nghe nhìn của bạn
định tuyến để các ứng dụng khác có thể xác định cách tương tác với nội dung nghe nhìn của bạn
tuyến đường.
Mã ví dụ sau đây minh hoạ cách thêm các bộ lọc ý định đã tạo trước đó vào một
MediaRouteProviderDescriptor
và đặt phần mô tả để sử dụng theo
khung bộ định tuyến phương tiện:
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); }
Để biết thêm thông tin về các chế độ cài đặt mã mô tả có sẵn, hãy xem tài liệu tham khảo
cho MediaRouteDescriptor
và MediaRouteProviderDescriptor
.
Kiểm soát tuyến đường
Khi một ứng dụng kết nối với nhà cung cấp định tuyến nội dung đa phương tiện của bạn, ứng dụng sẽ nhận được chế độ phát
thông qua khung bộ định tuyến phương tiện do ứng dụng khác gửi đến tuyến đường của bạn. Để xử lý những vấn đề này
các yêu cầu, bạn phải cung cấp phương thức triển khai một lớp MediaRouteProvider.RouteController
, lớp này sẽ xử lý các lệnh
và xử lý hoạt động giao tiếp thực tế đến thiết bị thu của bạn.
Khung bộ định tuyến nội dung đa phương tiện sẽ gọi onCreateRouteController()
của trình cung cấp định tuyến của bạn để lấy một thực thể của lớp này rồi định tuyến các yêu cầu đến đó.
Dưới đây là các phương thức chính của lớp MediaRouteProvider.RouteController
mà bạn phải triển khai
nhà cung cấp tuyến nội dung đa phương tiện của bạn:
onSelect()
– Được gọi khi một ứng dụng chọn tuyến đường để phát. Bạn sử dụng phương thức này để thực hiện mọi công việc chuẩn bị có thể cần thiết trước khi bắt đầu phát nội dung nghe nhìn.onControlRequest()
– Gửi các lệnh phát cụ thể đến thiết bị nhận.onSetVolume()
– Gửi yêu cầu đến thiết bị nhận để đặt âm lượng phát thành giá trị cụ thể.onUpdateVolume()
– Gửi yêu cầu đến thiết bị nhận để sửa đổi chế độ phát theo số lượng cụ thể.onUnselect()
– Được gọi khi một ứng dụng bỏ chọn một tuyến.onRelease()
– Được gọi khi khung không cần tuyến đường nữa, cho phép khung giải phóng của chúng tôi.
Tất cả yêu cầu về bộ điều khiển chế độ phát, ngoại trừ yêu cầu thay đổi âm lượng, đều được chuyển hướng đến onControlRequest()
. Khi triển khai phương thức này, bạn phải phân tích cú pháp các yêu cầu kiểm soát và phản hồi các yêu cầu đó
một cách phù hợp. Dưới đây là một ví dụ về cách triển khai phương thức này, phương thức này sẽ xử lý các lệnh cho một
tuyến phương tiện phát lại từ xa:
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; } ... }
Điều quan trọng là bạn phải hiểu rằng lớp MediaRouteProvider.RouteController
được dùng để đóng vai trò là trình bao bọc
cho API đến thiết bị phát nội dung đa phương tiện của bạn. Cách triển khai các phương thức trong lớp này
hoàn toàn phụ thuộc vào giao diện có lập trình do thiết bị nhận của bạn cung cấp.
Mã mẫu
MediaRouter mẫu cho biết cách tạo trình cung cấp tuyến nội dung đa phương tiện tuỳ chỉnh.