Le sessioni multimediali forniscono un modo universale di interagire con un player audio o video. In Media3, il player predefinito è la classe ExoPlayer, che implementa l'interfaccia Player. Il collegamento della sessione multimediale al player consente a un'app di pubblicizzare la riproduzione di contenuti multimediali esternamente e di ricevere comandi di riproduzione da fonti esterne.
I comandi possono provenire da pulsanti fisici, come il pulsante di riproduzione su un headset o sul telecomando TV. Potrebbero anche provenire da app client che dispongono di un controller multimediale, ad esempio il comando "pausa" per l'Assistente Google. La sessione multimediale delega questi comandi al player dell'app multimediale.
Quando scegliere una sessione multimediale
Quando implementi MediaSession, consenti agli utenti di controllare la riproduzione:
- Tramite le cuffie. Spesso sono presenti pulsanti o interazioni touch che un utente può eseguire sulle cuffie per riprodurre o mettere in pausa i contenuti multimediali o passare alla traccia successiva o precedente.
- Parlando con l'Assistente Google. Un pattern comune è dire "Hey Google, metti in pausa" per mettere in pausa i contenuti multimediali attualmente in riproduzione sul dispositivo.
- Tramite il loro smartwatch Wear OS. In questo modo, gli utenti possono accedere più facilmente ai controlli di riproduzione più comuni durante la riproduzione sul proprio smartphone.
- Tramite i controlli multimediali. Questo carosello mostra i controlli per ogni sessione multimediale in esecuzione.
- Sulla TV. Consente azioni con pulsanti di riproduzione fisici, controllo della riproduzione della piattaforma e gestione dell'alimentazione (ad esempio, se la TV, la soundbar o il ricevitore A/V si spegne o l'ingresso viene cambiato, la riproduzione deve interrompersi nell'app).
- Tramite i controlli multimediali di Android Auto. In questo modo è possibile controllare la riproduzione in sicurezza durante la guida.
- E qualsiasi altro processo esterno che deve influenzare la riproduzione.
Questo è ottimo per molti casi d'uso. In particolare, dovresti prendere seriamente in considerazione l'utilizzo di MediaSession quando:
- Stai trasmettendo in streaming contenuti video nel formato lungo, come film o TV in diretta.
- Stai riproducendo in streaming contenuti audio nel formato lungo, come podcast o playlist musicali.
- Stai creando un'app TV.
Tuttavia, non tutti i casi d'uso sono adatti a MediaSession. Potresti voler utilizzare solo Player nei seguenti casi:
- Stai mostrando contenuti nel formato breve, per i quali non è necessario il controllo esterno o la riproduzione in background.
- Non esiste un singolo video attivo, ad esempio l'utente sta scorrendo un elenco e vengono visualizzati più video sullo schermo contemporaneamente.
- Stai riproducendo un video introduttivo o esplicativo una tantum che l'utente dovrebbe guardare attivamente senza bisogno di controlli di riproduzione esterni.
- I tuoi contenuti sono sensibili alla privacy e non vuoi che processi esterni accedano ai metadati dei contenuti multimediali (ad esempio la modalità Incognito in un browser).
Se il tuo caso d'uso non rientra in nessuno di quelli elencati sopra, valuta se è accettabile che la tua app continui la riproduzione quando l'utente non interagisce attivamente con i contenuti. Se la risposta è sì, probabilmente ti conviene scegliere MediaSession. Se la risposta è no, probabilmente è meglio utilizzare Player.
Crea una sessione multimediale
Una sessione multimediale coesiste con il player che gestisce. Puoi creare una sessione multimediale con un oggetto Context e un oggetto Player. Devi creare e inizializzare una sessione multimediale quando è necessario, ad esempio il metodo del ciclo di vita onStart() o onResume() di Activity o Fragment oppure il metodo onCreate() di Service che possiede la sessione multimediale e il relativo player associato.
Per creare una sessione multimediale, inizializza un Player e forniscilo a MediaSession.Builder in questo modo:
Kotlin
val player = ExoPlayer.Builder(context).build() val mediaSession = MediaSession.Builder(context, player).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build(); MediaSession mediaSession = new MediaSession.Builder(context, player).build();
Gestione automatica dello stato
La libreria Media3 aggiorna automaticamente la sessione multimediale utilizzando lo stato del player. Pertanto, non è necessario gestire manualmente la mappatura dal player alla sessione.
Questo è diverso dalla sessione multimediale della piattaforma in cui dovevi creare e
mantenere un PlaybackState indipendentemente dal player stesso, ad esempio per
indicare eventuali errori.
ID sessione univoco
Per impostazione predefinita, MediaSession.Builder crea una sessione con una stringa vuota come ID sessione. Questo è sufficiente se un'app intende creare una sola istanza di sessione, che è il caso più comune.
Se un'app vuole gestire più istanze di sessione contemporaneamente, deve assicurarsi che l'ID sessione di ogni sessione sia univoco. L'ID sessione può essere impostato durante la creazione della sessione con MediaSession.Builder.setId(String id).
Se vedi un IllegalStateException che causa l'arresto anomalo della tua app con il messaggio di errore IllegalStateException: Session ID must be unique. ID=, è probabile che sia stata creata inaspettatamente una sessione prima che venisse rilasciata un'istanza creata in precedenza con lo stesso ID. Per evitare che le sessioni vengano divulgate a causa di un errore di programmazione, questi casi vengono rilevati e notificati generando un'eccezione.
Concedi il controllo ad altri client
La sessione multimediale è la chiave per controllare la riproduzione. Ti consente di indirizzare i comandi da fonti esterne al player che riproduce i tuoi contenuti multimediali. Queste sorgenti possono essere pulsanti fisici, come il pulsante di riproduzione su un paio di cuffie o sul telecomando TV, oppure comandi indiretti, come l'istruzione "metti in pausa" per l'Assistente Google. Allo stesso modo, potresti voler concedere l'accesso al sistema Android per facilitare i controlli delle notifiche e della schermata di blocco o a uno smartwatch Wear OS per controllare la riproduzione dal quadrante. I client esterni possono utilizzare un controller multimediale per inviare comandi di riproduzione alla tua app multimediale. Questi vengono ricevuti dalla sessione multimediale, che infine delega i comandi al media player.
Quando un controller sta per connettersi alla tua sessione multimediale, viene chiamato il metodo onConnect(). Puoi utilizzare il ControllerInfo fornito per decidere se accettare o rifiutare la richiesta. Per un esempio di accettazione di una richiesta di connessione, consulta la sezione Dichiara comandi personalizzati.
Dopo la connessione, un controller può inviare comandi di riproduzione alla sessione. La sessione delega quindi questi comandi al player. I comandi di riproduzione e playlist definiti nell'interfaccia Player vengono gestiti automaticamente dalla sessione.
Altri metodi di callback ti consentono di gestire, ad esempio, le richieste di comandi personalizzati e la modifica della playlist. Questi callback includono anche un oggetto ControllerInfo, in modo da poter modificare il modo in cui rispondi a ogni richiesta in base al controller.
Modifica la playlist
Una sessione multimediale può modificare direttamente la playlist del suo player, come spiegato nella
guida di ExoPlayer per le playlist.
I controller possono anche modificare la playlist se il controller ha accesso a COMMAND_SET_MEDIA_ITEM o COMMAND_CHANGE_MEDIA_ITEMS.
Quando aggiungi nuovi elementi alla playlist, il player in genere richiede istanze MediaItem con un URI definito per renderli riproducibili. Per impostazione predefinita, gli elementi appena aggiunti vengono inoltrati automaticamente ai metodi del player come player.addMediaItem se hanno un URI definito.
Se vuoi personalizzare le istanze MediaItem aggiunte al player, puoi eseguire l'override di onAddMediaItems().
Questo passaggio è necessario se vuoi supportare i controller che richiedono contenuti multimediali senza un URI definito. Invece, MediaItem in genere ha uno o più dei seguenti campi impostati per descrivere i contenuti multimediali richiesti:
MediaItem.id: un ID generico che identifica i contenuti multimediali.MediaItem.RequestMetadata.mediaUri: un URI della richiesta che potrebbe utilizzare uno schema personalizzato e non è necessariamente riproducibile direttamente dal player.MediaItem.RequestMetadata.searchQuery: una query di ricerca testuale, ad esempio dall'Assistente Google.MediaItem.MediaMetadata: metadati strutturati come "titolo" o "artista".
Per ulteriori opzioni di personalizzazione per playlist completamente nuove, puoi anche eseguire l'override di onSetMediaItems(), che ti consente di definire l'elemento iniziale e la posizione nella playlist. Ad esempio, puoi espandere un singolo elemento richiesto in un'intera playlist e indicare al player di iniziare dall'indice dell'elemento richiesto originariamente. Un'implementazione di esempio di onSetMediaItems() con questa funzionalità è disponibile nell'app demo della sessione.
Gestisci le preferenze dei pulsanti multimediali
Ogni controller, ad esempio l'interfaccia utente di sistema, Android Auto o Wear OS, può prendere le proprie decisioni su quali pulsanti mostrare all'utente. Per indicare i controlli di riproduzione che vuoi mostrare all'utente, puoi specificare le preferenze dei pulsanti multimediali su MediaSession. Queste preferenze sono costituite da un elenco ordinato di istanze CommandButton, ognuna delle quali definisce una preferenza per un pulsante nell'interfaccia utente.
Definisci i pulsanti di comando
Le istanze CommandButton vengono utilizzate per definire le preferenze dei pulsanti multimediali. Ogni pulsante definisce tre aspetti dell'elemento UI desiderato:
- L'icona, che definisce l'aspetto visivo. L'icona deve essere impostata su una delle costanti predefinite durante la creazione di un
CommandButton.Builder. Tieni presente che non si tratta di una risorsa bitmap o immagine effettiva. Una costante generica aiuta i controller a scegliere una risorsa appropriata per un aspetto coerente all'interno della propria UI. Se nessuna delle costanti delle icone predefinite è adatta al tuo caso d'uso, puoi utilizzaresetCustomIconResId. - Il comando, che definisce l'azione attivata quando l'utente interagisce con il pulsante. Puoi utilizzare
setPlayerCommandper unPlayer.CommandosetSessionCommandper unSessionCommandpredefinito o personalizzato. - Slot, che definisce dove deve essere posizionato il pulsante nell'interfaccia utente del controller. Questo campo è facoltativo e viene impostato automaticamente in base a Icona e Comando. Ad esempio, consente di specificare che un pulsante deve essere visualizzato nell'area di navigazione "Avanti" della UI anziché nell'area "Overflow" predefinita.
Kotlin
val button = CommandButton.Builder(CommandButton.ICON_SKIP_FORWARD_15) .setPlayerCommand(Player.COMMAND_SEEK_FORWARD) .setSlots(CommandButton.SLOT_FORWARD) .build()
Java
CommandButton button = new CommandButton.Builder(CommandButton.ICON_SKIP_FORWARD_15) .setPlayerCommand(Player.COMMAND_SEEK_FORWARD) .setSlots(CommandButton.SLOT_FORWARD) .build();
Quando le preferenze dei pulsanti multimediali vengono risolte, viene applicato il seguente algoritmo:
- Per ogni
CommandButtonnelle preferenze dei pulsanti multimediali, posiziona il pulsante nel primo slot disponibile e consentito. - Se uno degli slot centrale, avanti e indietro non è occupato da un pulsante, aggiungi i pulsanti predefiniti per questo slot.
Puoi utilizzare CommandButton.DisplayConstraints per generare un'anteprima di come verranno risolte le preferenze dei pulsanti multimediali in base ai vincoli di visualizzazione della UI.
Imposta le preferenze del pulsante multimediale
Il modo più semplice per impostare le preferenze dei pulsanti multimediali è definire l'elenco durante la creazione di MediaSession. In alternativa, puoi eseguire l'override di MediaSession.Callback.onConnect per personalizzare le preferenze dei pulsanti multimediali per ogni controller connesso.
Kotlin
val mediaSession = MediaSession.Builder(context, player) .setMediaButtonPreferences(ImmutableList.of(likeButton, favoriteButton)) .build()
Java
MediaSession mediaSession = new MediaSession.Builder(context, player) .setMediaButtonPreferences(ImmutableList.of(likeButton, favoriteButton)) .build();
Aggiorna le preferenze del pulsante dei contenuti multimediali dopo un'interazione dell'utente
Dopo aver gestito un'interazione con il player, potresti voler aggiornare i pulsanti visualizzati nell'interfaccia utente del controller. Un esempio tipico è un pulsante di attivazione/disattivazione che cambia icona e azione dopo l'attivazione dell'azione associata al pulsante. Per aggiornare le preferenze dei pulsanti multimediali, puoi utilizzare
MediaSession.setMediaButtonPreferences per aggiornare le preferenze per
tutti i controller o per un controller specifico:
Kotlin
// Handle "favoritesButton" action, replace by opposite button mediaSession.setMediaButtonPreferences(ImmutableList.of(likeButton, removeFromFavoritesButton))
Java
// Handle "favoritesButton" action, replace by opposite button mediaSession.setMediaButtonPreferences(ImmutableList.of(likeButton, removeFromFavoritesButton));
Aggiungi comandi personalizzati e personalizza il comportamento predefinito
I comandi del player disponibili possono essere estesi con comandi personalizzati ed è anche possibile intercettare i comandi del player e i pulsanti multimediali in arrivo per modificare il comportamento predefinito.
Dichiara e gestisci i comandi personalizzati
Le applicazioni multimediali possono definire comandi personalizzati che, ad esempio, possono essere utilizzati nelle
preferenze dei pulsanti multimediali. Ad esempio, potresti voler implementare pulsanti che consentano all'utente di salvare un elemento multimediale in un elenco di elementi preferiti. MediaController invia comandi personalizzati e MediaSession.Callback li riceve.
Per definire i comandi personalizzati, devi eseguire l'override di MediaSession.Callback.onConnect() per impostare i comandi personalizzati disponibili per ogni controller connesso.
Kotlin
private class CustomMediaSessionCallback : MediaSession.Callback { // Configure commands available to the controller in onConnect() override fun onConnectAsync( session: MediaSession, controller: ControllerInfo, ): ListenableFuture<ConnectionResult> { val sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(SessionCommand(SAVE_TO_FAVORITES, Bundle.EMPTY)) .build() return Futures.immediateFuture( AcceptedResultBuilder(session, controller) .setAvailableSessionCommands(sessionCommands) .build() ) } }
Java
private static class CustomMediaSessionCallback implements MediaSession.Callback { // Configure commands available to the controller in onConnect() @Override public ListenableFuture<ConnectionResult> onConnectAsync( MediaSession session, ControllerInfo controller) { SessionCommands sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS .buildUpon() .add(new SessionCommand(SAVE_TO_FAVORITES, new Bundle())) .build(); return Futures.immediateFuture( new AcceptedResultBuilder(session, controller) .setAvailableSessionCommands(sessionCommands) .build()); } }
Per ricevere richieste di comandi personalizzati da un MediaController, esegui l'override del metodo onCustomCommand() in Callback.
Kotlin
private class CustomCallback : MediaSession.Callback { // ... override fun onCustomCommand( session: MediaSession, controller: ControllerInfo, customCommand: SessionCommand, args: Bundle, ): ListenableFuture<SessionResult> { if (customCommand.customAction == SAVE_TO_FAVORITES) { // Do custom logic here saveToFavorites(session.player.currentMediaItem) return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS)) } // ... return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS)) } }
Java
private static class CustomCallback implements MediaSession.Callback { // ... @Override public ListenableFuture<SessionResult> onCustomCommand( MediaSession session, ControllerInfo controller, SessionCommand customCommand, Bundle args) { if (customCommand.customAction.equals(SAVE_TO_FAVORITES)) { // Do custom logic here saveToFavorites(session.getPlayer().getCurrentMediaItem()); return Futures.immediateFuture(new SessionResult(SessionResult.RESULT_SUCCESS)); } // ... return Futures.immediateFuture(new SessionResult(SessionResult.RESULT_SUCCESS)); } }
Puoi monitorare quale controller multimediale sta effettuando una richiesta utilizzando la proprietà packageName dell'oggetto MediaSession.ControllerInfo che viene passato ai metodi Callback. In questo modo puoi personalizzare il comportamento della tua app in risposta a un determinato comando se proviene dal sistema, dalla tua app o da altre app client.
Personalizza i comandi predefiniti del player
Tutti i comandi predefiniti e la gestione dello stato sono delegati alla Player che si trova su
MediaSession. Per personalizzare il comportamento di un comando definito nell'interfaccia Player, ad esempio play() o seekToNext(), inserisci Player in un ForwardingSimpleBasePlayer prima di passarlo a MediaSession:
Kotlin
val forwardingPlayer = object : ForwardingSimpleBasePlayer(player) { // Customizations } val mediaSession = MediaSession.Builder(context, forwardingPlayer).build()
Java
ForwardingSimpleBasePlayer forwardingPlayer = new ForwardingSimpleBasePlayer(player) { // Customizations }; MediaSession mediaSession = new MediaSession.Builder(context, forwardingPlayer).build();
Per ulteriori informazioni su ForwardingSimpleBasePlayer, consulta la guida di ExoPlayer sulla personalizzazione.
Identifica il controller richiedente di un comando del player
Quando una chiamata a un metodo Player viene generata da un MediaController, puoi identificare l'origine con MediaSession.controllerForCurrentRequest e acquisire ControllerInfo per la richiesta corrente:
Kotlin
private class CallerAwarePlayer(player: Player) : ForwardingSimpleBasePlayer(player) { private lateinit var session: MediaSession override fun handleSeek( mediaItemIndex: Int, positionMs: Long, seekCommand: Int, ): ListenableFuture<*> { Log.d( "caller", "seek operation from package ${session.controllerForCurrentRequest?.packageName}", ) return super.handleSeek(mediaItemIndex, positionMs, seekCommand) } }
Java
private static final class CallerAwarePlayer extends ForwardingSimpleBasePlayer { private MediaSession session; public CallerAwarePlayer(Player player) { super(player); } @Override protected ListenableFuture<?> handleSeek(int mediaItemIndex, long positionMs, int seekCommand) { Log.d( "caller", "seek operation from package: " + session.getControllerForCurrentRequest().getPackageName()); return super.handleSeek(mediaItemIndex, positionMs, seekCommand); } }
Personalizza la gestione dei pulsanti multimediali
I pulsanti multimediali sono pulsanti hardware presenti sui dispositivi Android e su altre periferiche, come il pulsante di riproduzione/pausa su un paio di cuffie Bluetooth. Media3 gestisce gli eventi dei pulsanti multimediali quando arrivano alla sessione e chiama il metodo Player appropriato sul player della sessione.
Ti consigliamo di gestire tutti gli eventi dei pulsanti multimediali in arrivo nel metodo Player corrispondente. Per casi d'uso più avanzati, gli eventi dei pulsanti multimediali possono essere intercettati in MediaSession.Callback.onMediaButtonEvent(Intent).
Gestione e segnalazione degli errori
Esistono due tipi di errori che una sessione genera e segnala ai controller. Gli errori irreversibili segnalano un errore tecnico di riproduzione del player della sessione che interrompe la riproduzione. Gli errori irreversibili vengono segnalati automaticamente al controller quando si verificano. Gli errori non irreversibili sono errori non tecnici o relativi alle norme che non interrompono la riproduzione e vengono inviati ai controller dall'applicazione manualmente.
Errori di riproduzione irreversibili
Un errore di riproduzione irreversibile viene segnalato alla sessione dal player e poi
ai controller per la chiamata tramite
Player.Listener.onPlayerError(PlaybackException) e
Player.Listener.onPlayerErrorChanged(@Nullable PlaybackException).
In questo caso, lo stato di riproduzione passa a STATE_IDLE e
MediaController.getPlaybackError() restituisce l'oggetto PlaybackException che ha causato
la transizione. Un controller può ispezionare PlayerException.errorCode per ottenere informazioni sul motivo dell'errore.
Impostazione di un errore del player personalizzato
Oltre agli errori irreversibili segnalati dal player, un'applicazione può impostare un PlaybackException personalizzato a livello di MediaSession utilizzando MediaSession.setPlaybackException(PlaybackException). In questo modo, l'applicazione può segnalare uno stato di errore ai controller connessi. L'eccezione può essere impostata per tutti i controller connessi o per un ControllerInfo specifico.
Quando un'app imposta un PlaybackException utilizzando questa API:
Le istanze
MediaControllerconnesse riceveranno una notifica. I callbackListener.onPlayerError(PlaybackException)eListener.onPlayerErrorChanged(@Nullable PlaybackException)sul controller verranno richiamati con l'eccezione fornita.Il metodo
MediaController.getPlayerError()restituirà il valorePlaybackExceptionimpostato dall'applicazione.Lo stato di riproduzione dei controller interessati cambierà in
Player.STATE_IDLE.I comandi disponibili verranno rimossi e rimarranno solo i comandi di lettura come
COMMAND_GET_TIMELINE, se sono già stati concessi. Ad esempio, lo stato diTimelineviene bloccato allo stato in cui l'eccezione è stata applicata al controller. I comandi che tentano di modificare lo stato del player, comeCOMMAND_PLAY, vengono rimossi finché l'app non rimuove l'eccezione di riproduzione per il controller specificato.
Per cancellare un PlaybackException personalizzato impostato in precedenza e ripristinare la normale segnalazione dello stato del player, un'app può chiamare MediaSession.setPlaybackException(/* playbackException= */ null) o MediaSession.setPlaybackException(ControllerInfo,
/* playbackException= */ null).
Personalizzazione degli errori irreversibili
Per fornire all'utente informazioni localizzate e significative, puoi personalizzare il codice di errore, il messaggio di errore e gli extra di errore di un errore di riproduzione irreversibile proveniente dal player effettivo. Puoi farlo utilizzando un ForwardingPlayer durante la creazione della sessione:
Kotlin
val session = MediaSession.Builder(context, ErrorForwardingPlayer(context, player)).build()
Java
MediaSession session = new MediaSession.Builder(context, new ErrorForwardingPlayer(context, player)).build();
Il player di inoltro può utilizzare ForwardingSimpleBasePlayer per intercettare l'errore e personalizzare il codice di errore, il messaggio o gli extra. Allo stesso modo, puoi anche generare nuovi errori che non esistono nel player originale:
Kotlin
private class ErrorForwardingPlayer(private val context: Context, player: Player) : ForwardingSimpleBasePlayer(player) { override fun getState(): State { var state = super.getState() if (state.playerError != null) { state = state.buildUpon().setPlayerError(customizePlaybackException(state.playerError!!)).build() } return state } private fun customizePlaybackException(error: PlaybackException): PlaybackException { val buttonLabel: String val errorMessage: String when (error.errorCode) { PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW -> { buttonLabel = context.getString(R.string.err_button_label_restart_stream) errorMessage = context.getString(R.string.err_msg_behind_live_window) } else -> { buttonLabel = context.getString(R.string.err_button_label_ok) errorMessage = context.getString(R.string.err_message_default) } } val extras = Bundle() extras.putString("button_label", buttonLabel) return PlaybackException(errorMessage, error.cause, error.errorCode, extras) } }
Java
private static class ErrorForwardingPlayer extends ForwardingSimpleBasePlayer { private final Context context; public ErrorForwardingPlayer(Context context, Player player) { super(player); this.context = context; } @Override protected State getState() { State state = super.getState(); if (state.playerError != null) { state = state.buildUpon().setPlayerError(customizePlaybackException(state.playerError)).build(); } return state; } private PlaybackException customizePlaybackException(PlaybackException error) { String buttonLabel; String errorMessage; switch (error.errorCode) { case PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW: buttonLabel = context.getString(R.string.err_button_label_restart_stream); errorMessage = context.getString(R.string.err_msg_behind_live_window); break; default: buttonLabel = context.getString(R.string.err_button_label_ok); errorMessage = context.getString(R.string.err_message_default); break; } Bundle extras = new Bundle(); extras.putString("button_label", buttonLabel); return new PlaybackException(errorMessage, error.getCause(), error.errorCode, extras); } }
Errori non irreversibili
Gli errori non irreversibili che non hanno origine da un'eccezione tecnica possono essere inviati da un'app a tutti i controller o a un controller specifico:
Kotlin
val sessionError = SessionError( SessionError.ERROR_SESSION_AUTHENTICATION_EXPIRED, context.getString(R.string.error_message_authentication_expired), ) // Option 1: Sending a nonfatal error to all controllers. mediaSession.sendError(sessionError) // Option 2: Sending a nonfatal error to the media notification controller only // to set the error code and error message in the playback state of the platform // media session. mediaSession.mediaNotificationControllerInfo?.let { mediaSession.sendError(it, sessionError) }
Java
SessionError sessionError = new SessionError( SessionError.ERROR_SESSION_AUTHENTICATION_EXPIRED, context.getString(R.string.error_message_authentication_expired)); // Option 1: Sending a nonfatal error to all controllers. mediaSession.sendError(sessionError); // Option 2: Sending a nonfatal error to the media notification controller only // to set the error code and error message in the playback state of the platform // media session. ControllerInfo mediaNotificationControllerInfo = mediaSession.getMediaNotificationControllerInfo(); if (mediaNotificationControllerInfo != null) { mediaSession.sendError(mediaNotificationControllerInfo, sessionError); }
Quando un errore non irreversibile viene inviato al controller delle notifiche multimediali, il codice e il messaggio di errore vengono replicati nella sessione multimediale della piattaforma, mentre PlaybackState.state non viene modificato in STATE_ERROR.
Ricevi errori non irreversibili
Un MediaController riceve un errore non irreversibile implementando
MediaController.Listener.onError:
Kotlin
val future = MediaController.Builder(context, sessionToken) .setListener( object : MediaController.Listener { override fun onError(controller: MediaController, sessionError: SessionError) { // Handle nonfatal error. } } ) .buildAsync()
Java
MediaController.Builder future = new MediaController.Builder(context, sessionToken) .setListener( new MediaController.Listener() { @Override public void onError(MediaController controller, SessionError sessionError) { // Handle nonfatal error. } });