Panoramica di MediaRouteProvider

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.

Figura 1. Panoramica del modo in cui le classi dei provider di route multimediali forniscono la comunicazione da un'app multimediale a un dispositivo ricevitore.

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.