Il framework Android Media Router consente ai produttori di abilitare la riproduzione sui loro dispositivi
attraverso un'interfaccia standardizzata denominata MediaRouteProvider
.
Un provider di route definisce un'interfaccia comune per la riproduzione di contenuti multimediali su un dispositivo ricevitore, rendendola
possibile riprodurre contenuti multimediali sul tuo apparecchio da qualsiasi applicazione Android che supporti
route.
Questa guida illustra come creare un provider di routing multimediale per un dispositivo ricevitore
disponibile per altre applicazioni di riproduzione
contenuti multimediali eseguite su Android. Per utilizzare questa API,
è necessario conoscere le classi chiave
MediaRouteProvider
,
MediaRouteProviderDescriptor
e
RouteController
Panoramica
Il framework Android Media Router consente agli sviluppatori di app multimediali e ai dispositivi di riproduzione multimediali
ai produttori di connettersi tramite un'API e un'interfaccia utente comuni. Gli sviluppatori di app che
implementare un'interfaccia MediaRouter
può quindi connettersi
e riproducono contenuti sui dispositivi che partecipano al framework Media router. Contenuti multimediali
i produttori di dispositivi di riproduzione possono partecipare al framework pubblicando un MediaRouteProvider
che consente ad altre applicazioni di connettersi e
riprodurre contenuti multimediali sui dispositivi ricevitori. La Figura 1 illustra come un'app si collega a un
tramite il framework Media router.
Quando crei un provider di route multimediale per il dispositivo ricevitore, quest'ultimo gestisce il le seguenti finalità:
- Descrivere e pubblicare le funzionalità del dispositivo destinatario in modo che altre app possano rilevarlo e usare le sue funzionalità di riproduzione.
- Aggrega l'interfaccia di programmazione del dispositivo ricevente e la sua comunicazione meccanismi di trasporto per rendere il dispositivo compatibile con il framework del router multimediale.
Distribuzione di fornitori di rotte
Un provider di route multimediali viene distribuito come parte di un'app per Android. Il fornitore del percorso può essere
reso disponibile ad altre app estendendo
MediaRouteProviderService
o il wrapping della tua implementazione
MediaRouteProvider
con il tuo servizio e che dichiara un intent
per il fornitore di route multimediali. Questi passaggi consentono ad altre app di rilevare e utilizzare
il tuo percorso multimediale.
Nota:l'app contenente il fornitore di percorsi multimediali può anche includere un MediaRouter all'interfaccia il provider di route, ma non è obbligatorio.
Libreria di supporto MediaRouter
Le API del router multimediale sono definite Libreria MediaRouter di AndroidX Devi aggiungere questa libreria al tuo progetto di sviluppo dell'app. Per ulteriori informazioni sull'aggiunta di librerie di supporto ai tuoi consulta Configurazione della Libreria di supporto.
Attenzione: assicurati di utilizzare AndroidX
dell'implementazione del framework Media router.
Non utilizzare il pacchetto android.media
precedente.
Creazione di un servizio del provider
Il framework del media router deve essere in grado di rilevare e connettersi al provider di route multimediali
per consentire ad altre applicazioni di utilizzare la tua route. A questo scopo, il framework Media router
cerca le app che dichiarano un'azione per intent del fornitore di route multimediali. Quando un'altra app vuole
connettersi al provider, il framework deve essere in grado di richiamare e connettersi,
deve essere incapsulato in un file Service
.
Il codice di esempio seguente mostra la dichiarazione di un servizio fornitore di route multimediali filtro per intent in un manifest, che ne consente il rilevamento e l'utilizzo da parte del router multimediale :
<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>
Questo esempio di manifest dichiara un servizio che aggrega le classi effettive del provider di route multimediali.
Il framework Android Media Router offre
Classe MediaRouteProviderService
da utilizzare come wrapper di servizio per
dei media route. Il seguente codice di esempio mostra come utilizzare questo wrapper
classe:
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); } }
Specifica delle funzionalità di route
Le app che si connettono al framework del router multimediale possono rilevare il percorso multimediale attraverso il tuo dichiarazioni manifest dell'app, ma devono anche conoscere le funzionalità delle route multimediali che offre. I percorsi multimediali possono essere di vari tipi e avere funzionalità diverse, oltre ad altre app devi poter scoprire questi dettagli per determinare se sono compatibili con il tuo percorso.
Il framework Media router ti consente di definire e pubblicare le funzionalità dei tuoi contenuti multimediali
percorso attraverso IntentFilter
oggetti, MediaRouteDescriptor
oggetti e un MediaRouteProviderDescriptor
. In questa sezione viene spiegato come utilizzare questi
per pubblicare i dettagli del percorso multimediale per altre app.
Categorie di route
Nell'ambito della descrizione programmatica del fornitore di route media, devi specificare se il tuo provider supporta la riproduzione remota, l'output secondario o entrambi. Questi sono i percorsi categorie fornite dal framework Media router:
CATEGORY_LIVE_AUDIO
— Uscita di audio a un dispositivo di uscita secondario, come un sistema musicale wireless.CATEGORY_LIVE_VIDEO
— Uscita video su un dispositivo di output secondario, come i dispositivi di visualizzazione wireless.CATEGORY_REMOTE_PLAYBACK
: riproduci video o audio su un dispositivo separato che gestisce i contenuti multimediali di recupero, decodifica e riproduzione, come Dispositivi Chromecast.
Per includere queste impostazioni in una descrizione del percorso multimediale, devi inserirle in
un oggetto IntentFilter
, che aggiungerai in seguito a un
Oggetto 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); } }
Se specifichi l'intent CATEGORY_REMOTE_PLAYBACK
, devi definire anche i tipi di media e
I controlli di riproduzione sono supportati dal fornitore del percorso multimediale. Nella sezione successiva viene descritto come
specificare queste impostazioni per il tuo dispositivo.
Protocolli e tipi di media
Un fornitore di route multimediale per un dispositivo di riproduzione remoto deve specificare i tipi di contenuti multimediali e trasferire
i protocolli che supporta. Puoi specificare queste impostazioni utilizzando l'IntentFilter
e i addDataScheme()
e
addDataType()
di quell'oggetto. La
il seguente snippet di codice illustra come definire un filtro per intent per supportare i video remoti
usando i protocolli http, https e RTSP (Real Time Streaming Protocol):
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); } } }
Controlli di riproduzione
Un fornitore di route multimediali che offre riproduzione remota deve specificare i tipi di controlli multimediali che supporta. Ecco i tipi generali di controllo che le route multimediali possono offrire:
- Controlli di riproduzione, ad esempio per riprodurre, mettere in pausa, riavvolgere e mandare avanti veloce.
- Funzionalità di coda, che consentono all'app di invio di aggiungere e rimuovere elementi da una playlist gestita dal dispositivo ricevente.
- Funzionalità di sessione, che impediscono all'invio di app di interferire con ogni oppure chiedere al dispositivo destinatario di fornire un ID sessione all'app richiedente e quindi controllare lo stesso ID per ogni richiesta successiva di controllo di riproduzione.
Il seguente esempio di codice mostra come creare un filtro per intent a supporto Controlli di riproduzione del percorso multimediale di base:
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); } ... }
Per ulteriori informazioni sugli intent di controllo di riproduzione disponibili, consulta la sezione
MediaControlIntent
corso.
Descriptor MediaRouteProvider
Dopo aver definito le funzionalità del percorso multimediale utilizzando gli oggetti IntentFilter
, puoi creare un oggetto descrittore da pubblicare su
il framework Android Media Router. Questo oggetto descrittore contiene le specifiche dei tuoi contenuti multimediali
di routing in modo che altre applicazioni possano determinare come interagire con i tuoi contenuti multimediali
percorso.
Il codice di esempio seguente mostra come aggiungere i filtri di intent creati in precedenza a un
MediaRouteProviderDescriptor
e imposta il descrittore per l'utilizzo da parte di
il framework Media router:
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); }
Per ulteriori informazioni sulle impostazioni del descrittore disponibili, consulta la documentazione di riferimento
per MediaRouteDescriptor
e MediaRouteProviderDescriptor
.
Controllo delle route
Quando un'applicazione si connette al provider di routing multimediale, il provider riceve la riproduzione
tramite il framework del router multimediale inviati al tuo percorso da altre app. Per gestire questi aspetti,
devi fornire un'implementazione di una classe MediaRouteProvider.RouteController
, che elabora i comandi
e gestisce la comunicazione effettiva con il dispositivo ricevitore.
Il framework Media router chiama onCreateRouteController()
del tuo fornitore di route per ottenere un'istanza di questa classe e quindi instradare le richieste a quest'ultima.
Questi sono i metodi chiave della classe MediaRouteProvider.RouteController
, che devi implementare per
il tuo fornitore di percorsi multimediali:
onSelect()
— Richiamato quando un'applicazione seleziona il percorso per la riproduzione. Questo metodo viene usato per eventuali operazioni di preparazione necessarie prima dell'inizio della riproduzione dei contenuti multimediali.onControlRequest()
: invia comandi di riproduzione specifici al dispositivo ricevente.onSetVolume()
- Invia una richiesta al dispositivo ricevente per impostare il volume di riproduzione su un un valore specifico.onUpdateVolume()
- Invia una richiesta al dispositivo ricevente per modificare la riproduzione volume per una quantità specificata.onUnselect()
: viene chiamato quando un'applicazione deseleziona una route.onRelease()
— Chiamato quando il percorso non è più necessario dalla struttura, consentendogli di liberare Google Cloud.
Tutte le richieste di controllo della riproduzione, ad eccezione delle variazioni di volume, vengono indirizzate all'onControlRequest()
. L'implementazione di questo metodo deve analizzare le richieste di controllo e rispondere
in modo appropriato. Di seguito è riportato un esempio di implementazione di questo metodo che elabora i comandi per un
percorso multimediale per la riproduzione remota:
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; } ... }
È importante capire che la classe MediaRouteProvider.RouteController
funge da wrapper
per l'API alla tua apparecchiatura di riproduzione multimediale. L'implementazione dei metodi in questa classe
completamente dall'interfaccia di pubblicità programmatica fornita dal dispositivo ricevente.
Codice di esempio
MediaRouter esempio mostra come creare un provider di route media personalizzato.