Le sessioni multimediali offrono un modo universale di interagire con un audio o un video
un player. In Media3, il player predefinito è la classe ExoPlayer
, che implementa
l'interfaccia di Player
. La connessione della sessione multimediale al player consente a un'app
per pubblicizzare la riproduzione di contenuti multimediali esternamente e per ricevere comandi di riproduzione dalle
da fonti esterne.
I comandi possono provenire da pulsanti fisici come il pulsante di riproduzione su un cuffie o telecomando della TV. Potrebbero anche provenire da app client che hanno un controller multimediale, ad esempio mettendo in pausa all'Assistente Google. I contenuti multimediali sessione 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 ci sono interazioni di pulsanti o tocco l'utente può eseguire sulle cuffie per riprodurre o mettere in pausa i contenuti multimediali oppure per passare o traccia precedente.
- Parlando con l'Assistente Google. Spesso si dice "OK" Google, metti in pausa" per mettere in pausa tutti i contenuti multimediali attualmente in riproduzione sul dispositivo.
- Tramite il suo smartwatch Wear OS. Ciò consente di accedere più facilmente i controlli di riproduzione più comuni mentre gioca sullo 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 e riproduzione piattaforma e la gestione dell'alimentazione (ad esempio, se la TV, la soundbar o il ricevitore A/V viene disattivata o l'ingresso viene cambiato, la riproduzione dovrebbe interrompersi nell'app).
- E qualsiasi altro processo esterno che debba influenzare la riproduzione.
È un ottimo modo per molti casi d'uso. In particolare, devi considerare attentamente
utilizzo di MediaSession
quando:
- Stai trasmettendo in streaming contenuti video nel formato lungo, come film o TV in diretta.
- Stai trasmettendo in streaming contenuti audio di durata estesa, ad esempio podcast o musica. playlist.
- Stai creando un'app TV.
Tuttavia, non tutti i casi d'uso si adattano bene a MediaSession
. Potresti voler
utilizza solo Player
nei seguenti casi:
- Stai mostrando contenuti nel formato breve in cui il coinvolgimento e l'interazione degli utenti è fondamentale.
- Non è presente un solo video attivo, ad esempio l'utente sta scorrendo un elenco. e vengono visualizzati più video contemporaneamente sullo schermo.
- Stai riproducendo un video introduttivo o esplicativo, che si aspettano che l'utente guardi attivamente.
- I tuoi contenuti sono riservati alla privacy e non vuoi che i processi esterni Accedere ai metadati multimediali (ad esempio la modalità di navigazione in incognito in un browser)
Se il tuo caso d'uso non rientra tra quelli elencati sopra, valuta se stai
Ok che la riproduzione dell'app continui anche quando l'utente non sta interagendo attivamente
con i contenuti. Se la risposta è sì, probabilmente vorrai scegliere
MediaSession
. Se la risposta è no, probabilmente ti consigliamo di utilizzare lo strumento Player
.
Creare una sessione multimediale
Una sessione multimediale si trova accanto al player che gestisce. Puoi creare un
sessione multimediale con un oggetto Context
e un Player
. Devi creare e gestire
inizializzare una sessione multimediale quando è necessario, ad esempio onStart()
o
onResume()
metodo del ciclo di vita di Activity
, Fragment
o onCreate()
del Service
proprietario della sessione multimediale e del player associato.
Per creare una sessione multimediale, inizializza un Player
e forniscilo a
MediaSession.Builder
nel seguente 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. Di conseguenza, non è necessario gestire manualmente il mapping player alla sessione.
Si tratta di una interruzione dall'approccio legacy in cui dovevi creare e mantenere
a PlaybackStateCompat
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
l'ID sessione. È sufficiente se un'app intende creare solo un singolo
di sessione, che è il caso più comune.
Se un'app vuole gestire contemporaneamente più istanze di sessione,
deve garantire che l'ID sessione di ogni sessione sia univoco. L'ID sessione può
da impostare durante la creazione della sessione con MediaSession.Builder.setId(String id)
.
Se vedi un IllegalStateException
che arresta l'arresto anomalo della tua app con l'errore
messaggio IllegalStateException: Session ID must be unique. ID=
, allora
è probabile che una sessione sia stata creata in modo imprevisto prima di una
è stata rilasciata un'istanza con lo stesso ID. Per evitare che le sessioni vengano divulgate da un
un errore di programmazione, questi casi vengono rilevati e notificati con un messaggio
.
Concedi il controllo ad altri clienti
La sessione multimediale è la chiave per controllare la riproduzione. Ti permette di indirizzare da fonti esterne al player che si occupa di riprodurre i tuoi contenuti multimediali. Queste sorgenti possono essere pulsanti fisici, come il pulsante di riproduzione su cuffie o telecomando della TV oppure comandi indiretti come "metti in pausa" all'Assistente Google. Analogamente, potresti voler concedere l'accesso ai per agevolare i controlli delle notifiche e della schermata di blocco o su Wear OS per controllare la riproduzione dal quadrante orologio. I client esterni possono usa un controller multimediale per impartire comandi di riproduzione alla tua app multimediale. Si tratta di ricevuta dalla sessione multimediale, che alla fine delega i comandi alla lettore multimediale.
di Gemini Advanced.Quando un controller sta per connettersi alla tua sessione multimediale,
onConnect()
. Puoi utilizzare il ControllerInfo
fornito
decidere se accettare
o rifiuta
la richiesta. Per un esempio di accettazione di una richiesta di collegamento, vedi la sezione Dichiarazione
disponibili.
Dopo la connessione, un controller può inviare comandi di riproduzione alla sessione. La
poi delega questi comandi al player. Riproduzione e playlist
I comandi definiti nell'interfaccia Player
vengono gestiti automaticamente
durante la sessione.
Altri metodi di callback ti consentono di gestire, ad esempio, le richieste di
comandi di riproduzione personalizzati e
modificando la playlist).
Questi callback includono in modo simile un oggetto ControllerInfo
che puoi modificare
il modo in cui rispondi a ogni richiesta in base al titolare.
Modificare la playlist
Una sessione multimediale può modificare direttamente la playlist del relativo player come spiegato in
il
Guida di ExoPlayer per le playlist.
I controller possono anche modificare la playlist se:
COMMAND_SET_MEDIA_ITEM
o COMMAND_CHANGE_MEDIA_ITEMS
sia disponibile per il controller.
Quando aggiungi nuovi elementi alla playlist, il player in genere richiede 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
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 l'elemento multimediale richiesto:
MediaItem.id
: un ID generico che identifica i contenuti multimediali.MediaItem.RequestMetadata.mediaUri
: un URI della richiesta che può utilizzare una richiesta 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 "title" o "artista".
Per ulteriori opzioni di personalizzazione per playlist completamente nuove, puoi
sostituire ulteriormente
onSetMediaItems()
che ti consente di definire l'elemento iniziale e la posizione nella playlist. Ad esempio:
puoi espandere un singolo elemento richiesto a un'intera playlist e indicare al
player in modo che inizi dall'indice dell'elemento originariamente richiesto. R
implementazione di esempio di onSetMediaItems()
disponibili nell'app demo della sessione.
Gestire il layout e i comandi personalizzati
Le seguenti sezioni descrivono come pubblicizzare un layout personalizzato i pulsanti di comando alle app client e autorizza i controller a inviare tramite comandi SQL.
Definisci il layout personalizzato della sessione
Per indicare alle app client i controlli di riproduzione che vuoi mostrare ai
L'utente, imposta il layout personalizzato della sessione
quando crei MediaSession
nel metodo onCreate()
della tua
completamente gestito di Google Cloud.
Kotlin
override fun onCreate() { super.onCreate() val likeButton = CommandButton.Builder() .setDisplayName("Like") .setIconResId(R.drawable.like_icon) .setSessionCommand(SessionCommand(SessionCommand.COMMAND_CODE_SESSION_SET_RATING)) .build() val favoriteButton = CommandButton.Builder() .setDisplayName("Save to favorites") .setIconResId(R.drawable.favorite_icon) .setSessionCommand(SessionCommand(SAVE_TO_FAVORITES, Bundle())) .build() session = MediaSession.Builder(this, player) .setCallback(CustomMediaSessionCallback()) .setCustomLayout(ImmutableList.of(likeButton, favoriteButton)) .build() }
Java
@Override public void onCreate() { super.onCreate(); CommandButton likeButton = new CommandButton.Builder() .setDisplayName("Like") .setIconResId(R.drawable.like_icon) .setSessionCommand(new SessionCommand(SessionCommand.COMMAND_CODE_SESSION_SET_RATING)) .build(); CommandButton favoriteButton = new CommandButton.Builder() .setDisplayName("Save to favorites") .setIconResId(R.drawable.favorite_icon) .setSessionCommand(new SessionCommand(SAVE_TO_FAVORITES, new Bundle())) .build(); Player player = new ExoPlayer.Builder(this).build(); mediaSession = new MediaSession.Builder(this, player) .setCallback(new CustomMediaSessionCallback()) .setCustomLayout(ImmutableList.of(likeButton, favoriteButton)) .build(); }
Dichiara i comandi personalizzati e del player disponibili
Le applicazioni multimediali possono definire comandi personalizzati che, ad esempio, possono essere utilizzati
un layout personalizzato. Ad esempio, potresti voler implementare pulsanti che consentano alla
utente per salvare un elemento multimediale in un elenco di elementi preferiti. MediaController
invia comandi personalizzati e l'MediaSession.Callback
li riceve.
Puoi definire quali comandi di sessione personalizzati rendere disponibili
MediaController
quando si connette alla sessione multimediale. Per farlo,
eseguendo l'override di MediaSession.Callback.onConnect()
. Configura e restituisci
l'insieme di comandi disponibili quando si accetta una richiesta di connessione da un
MediaController
nel metodo di callback onConnect
:
Kotlin
private inner class CustomMediaSessionCallback: MediaSession.Callback { // Configure commands available to the controller in onConnect() override fun onConnect( session: MediaSession, controller: MediaSession.ControllerInfo ): MediaSession.ConnectionResult { val sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(SessionCommand(SAVE_TO_FAVORITES, Bundle.EMPTY)) .build() return AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build() } }
Java
class CustomMediaSessionCallback implements MediaSession.Callback { // Configure commands available to the controller in onConnect() @Override public ConnectionResult onConnect( MediaSession session, ControllerInfo controller) { SessionCommands sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(new SessionCommand(SAVE_TO_FAVORITES, new Bundle())) .build(); return new AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build(); } }
Per ricevere richieste di comandi personalizzati da un MediaController
, esegui l'override di
onCustomCommand()
in Callback
.
Kotlin
private inner class CustomMediaSessionCallback: MediaSession.Callback { ... override fun onCustomCommand( session: MediaSession, controller: MediaSession.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) ) } ... } }
Java
class CustomMediaSessionCallback 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) ); } ... } }
Puoi tenere traccia del controller multimediale che sta effettuando una richiesta utilizzando il comando
Proprietà packageName
dell'oggetto MediaSession.ControllerInfo
che è
passati ai metodi Callback
. Questo ti consente di personalizzare
comportamento in risposta a un dato comando, se proviene dal sistema,
della tua app o di altre app client.
Aggiornare il layout personalizzato dopo un'interazione dell'utente
Dopo aver gestito un comando personalizzato o qualsiasi altra interazione con il player,
potrebbe voler aggiornare il layout visualizzato nell'interfaccia utente del controller. Un esempio tipico
è un pulsante di attivazione/disattivazione che cambia la propria icona dopo aver attivato l'azione associata
con questo pulsante. Per aggiornare il layout, puoi utilizzare
MediaSession.setCustomLayout
:
Kotlin
val removeFromFavoritesButton = CommandButton.Builder() .setDisplayName("Remove from favorites") .setIconResId(R.drawable.favorite_remove_icon) .setSessionCommand(SessionCommand(REMOVE_FROM_FAVORITES, Bundle())) .build() mediaSession.setCustomLayout(ImmutableList.of(likeButton, removeFromFavoritesButton))
Java
CommandButton removeFromFavoritesButton = new CommandButton.Builder() .setDisplayName("Remove from favorites") .setIconResId(R.drawable.favorite_remove_icon) .setSessionCommand(new SessionCommand(REMOVE_FROM_FAVORITES, new Bundle())) .build(); mediaSession.setCustomLayout(ImmutableList.of(likeButton, removeFromFavoritesButton));
Personalizza il comportamento del comando di riproduzione
Per personalizzare il comportamento di un comando definito nell'interfaccia Player
, ad esempio
come play()
o seekToNext()
, racchiudi Player
in un ForwardingPlayer
.
Kotlin
val player = ExoPlayer.Builder(context).build() val forwardingPlayer = object : ForwardingPlayer(player) { override fun play() { // Add custom logic super.play() } override fun setPlayWhenReady(playWhenReady: Boolean) { // Add custom logic super.setPlayWhenReady(playWhenReady) } } val mediaSession = MediaSession.Builder(context, forwardingPlayer).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build(); ForwardingPlayer forwardingPlayer = new ForwardingPlayer(player) { @Override public void play() { // Add custom logic super.play(); } @Override public void setPlayWhenReady(boolean playWhenReady) { // Add custom logic super.setPlayWhenReady(playWhenReady); } }; MediaSession mediaSession = new MediaSession.Builder(context, forwardingPlayer).build();
Per ulteriori informazioni su ForwardingPlayer
, consulta la guida di ExoPlayer su
Personalizzazione.
Identifica il controller che richiede un comando del player
Quando una chiamata a un metodo Player
proviene da un MediaController
, puoi
identificare la fonte di origine con MediaSession.controllerForCurrentRequest
e acquisisci ControllerInfo
per la richiesta corrente:
Kotlin
class CallerAwareForwardingPlayer(player: Player) : ForwardingPlayer(player) { override fun seekToNext() { Log.d( "caller", "seekToNext called from package ${session.controllerForCurrentRequest?.packageName}" ) super.seekToNext() } }
Java
public class CallerAwareForwardingPlayer extends ForwardingPlayer { public CallerAwareForwardingPlayer(Player player) { super(player); } @Override public void seekToNext() { Log.d( "caller", "seekToNext called from package: " + session.getControllerForCurrentRequest().getPackageName()); super.seekToNext(); } }
Rispondi ai pulsanti multimediali
I pulsanti multimediali sono pulsanti hardware presenti su dispositivi Android e altre periferiche
dispositivi, ad esempio il pulsante di riproduzione/pausa sulle cuffie Bluetooth. Handle Media3
degli eventi del pulsante multimediale quando arrivano alla sessione e chiamano
metodo Player
appropriato nel player della sessione.
Un'app può eseguire l'override del comportamento predefinito
MediaSession.Callback.onMediaButtonEvent(Intent)
. In questo caso, l'app
gestire tutte le specifiche delle API in autonomia.
Gestione e reporting degli errori
Esistono due tipi di errori generati da una sessione e segnalati ai controller. Gli errori irreversibili segnalano un errore tecnico di riproduzione della sessione player che interrompe la riproduzione. Gli errori irreversibili vengono segnalati al controller automaticamente quando si verificano. Gli errori non irreversibili non sono tecnici o normativi errori che non interrompono la riproduzione e che vengono inviati ai controller manualmente l'applicazione.
Errori di riproduzione irreversibili
Il giocatore segnala un errore di riproduzione irreversibile alla sessione, dopodiché
segnalato ai controller di chiamare tramite
Player.Listener.onPlayerError(PlaybackException)
e
Player.Listener.onPlayerErrorChanged(@Nullable PlaybackException)
.
In questo caso, lo stato di riproduzione viene trasferito a STATE_IDLE
e
MediaController.getPlaybackError()
restituisce PlaybackException
che ha causato
la transizione. Un controller può ispezionare PlayerException.errorCode
per ottenere
le informazioni sul motivo dell'errore.
Per l'interoperabilità, un errore irreversibile viene replicato nell'PlaybackStateCompat
della sessione della piattaforma eseguendo la transizione dello stato a STATE_ERROR
e impostando
codice di errore e il messaggio in base a PlaybackException
.
Personalizzazione di un errore irreversibile
Per fornire all'utente informazioni localizzate e significative, il codice di errore,
il messaggio di errore e gli elementi extra relativi a un errore di riproduzione irreversibile possono essere personalizzati
utilizzando ForwardingPlayer
durante la creazione della sessione:
Kotlin
val forwardingPlayer = ErrorForwardingPlayer(player) val session = MediaSession.Builder(context, forwardingPlayer).build()
Java
Player forwardingPlayer = new ErrorForwardingPlayer(player); MediaSession session = new MediaSession.Builder(context, forwardingPlayer).build();
Il player di inoltro registra un Player.Listener
nel player effettivo
e intercetta i callback che segnalano un errore. Un modello personalizzato
PlaybackException
viene quindi delegato ai listener che
sono registrati nel player di inoltro. Affinché questa operazione funzioni, il player di inoltro
esegue l'override di Player.addListener
e Player.removeListener
per avere accesso
listener con cui inviare codici di errore, messaggi o extra personalizzati:
Kotlin
class ErrorForwardingPlayer(private val context: Context, player: Player) : ForwardingPlayer(player) { private val listeners: MutableList<Player.Listener> = mutableListOf() private var customizedPlaybackException: PlaybackException? = null init { player.addListener(ErrorCustomizationListener()) } override fun addListener(listener: Player.Listener) { listeners.add(listener) } override fun removeListener(listener: Player.Listener) { listeners.remove(listener) } override fun getPlayerError(): PlaybackException? { return customizedPlaybackException } private inner class ErrorCustomizationListener : Player.Listener { override fun onPlayerErrorChanged(error: PlaybackException?) { customizedPlaybackException = error?.let { customizePlaybackException(it) } listeners.forEach { it.onPlayerErrorChanged(customizedPlaybackException) } } override fun onPlayerError(error: PlaybackException) { listeners.forEach { it.onPlayerError(customizedPlaybackException!!) } } 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) } // Apps can customize further error messages by adding more branches. 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) } override fun onEvents(player: Player, events: Player.Events) { listeners.forEach { it.onEvents(player, events) } } // Delegate all other callbacks to all listeners without changing arguments like onEvents. } }
Java
private static class ErrorForwardingPlayer extends ForwardingPlayer { private final Context context; private List<Player.Listener> listeners; @Nullable private PlaybackException customizedPlaybackException; public ErrorForwardingPlayer(Context context, Player player) { super(player); this.context = context; listeners = new ArrayList<>(); player.addListener(new ErrorCustomizationListener()); } @Override public void addListener(Player.Listener listener) { listeners.add(listener); } @Override public void removeListener(Player.Listener listener) { listeners.remove(listener); } @Nullable @Override public PlaybackException getPlayerError() { return customizedPlaybackException; } private class ErrorCustomizationListener implements Listener { @Override public void onPlayerErrorChanged(@Nullable PlaybackException error) { customizedPlaybackException = error != null ? customizePlaybackException(error, context) : null; for (int i = 0; i < listeners.size(); i++) { listeners.get(i).onPlayerErrorChanged(customizedPlaybackException); } } @Override public void onPlayerError(PlaybackException error) { for (int i = 0; i < listeners.size(); i++) { listeners.get(i).onPlayerError(checkNotNull(customizedPlaybackException)); } } private PlaybackException customizePlaybackException( PlaybackException error, Context context) { 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; // Apps can customize further error messages by adding more case statements. 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); } @Override public void onEvents(Player player, Events events) { for (int i = 0; i < listeners.size(); i++) { listeners.get(i).onEvents(player, events); } } // Delegate all other callbacks to all listeners without changing arguments like onEvents. } }
Errori non irreversibili
È possibile inviare errori non irreversibili che non derivano da un'eccezione tecnica da un'app a tutti o a un controller specifico:
Kotlin
val sessionError = SessionError( SessionError.ERROR_SESSION_AUTHENTICATION_EXPIRED, context.getString(R.string.error_message_authentication_expired), ) // Sending a nonfatal error to all controllers. mediaSession.sendError(sessionError) // Interoperability: Sending a nonfatal error to the media notification controller 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)); // Sending a nonfatal error to all controllers. mediaSession.sendError(sessionError); // Interoperability: Sending a nonfatal error to the media notification controller 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); }
Un errore non irreversibile inviato al controller di notifica multimediale viene replicato nel
PlaybackStateCompat
della sessione sulla piattaforma. Di conseguenza, solo il codice di errore e
il messaggio di errore viene impostato di conseguenza su PlaybackStateCompat
,
PlaybackStateCompat.state
non modificato in STATE_ERROR
.
Ricevi errori non irreversibili
Un MediaController
riceve un errore non irreversibile tramite l'implementazione
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. } });