Sesje multimedialne to uniwersalny sposób na interakcję z dźwiękiem lub filmem
. W Media3 domyślnym odtwarzaczem jest klasa ExoPlayer
, która implementuje
w interfejsie Player
. Połączenie sesji multimediów z odtwarzaczem zezwala aplikacji
do reklamowania treści multimedialnych podczas odtwarzania na zewnątrz i otrzymywania poleceń odtwarzania
ze źródeł zewnętrznych.
Polecenia mogą pochodzić z fizycznych przycisków, takich jak przycisk odtwarzania na zestawu słuchawkowego lub pilota do telewizora. Mogą one też pochodzić z aplikacji klienckich, które mają kontroler multimediów, np. instrukcja „wstrzymanie” do Asystenta Google. Media sesja przekazuje te polecenia do odtwarzacza aplikacji do multimediów.
Kiedy wybrać sesję multimediów
Gdy wdrożysz MediaSession
, umożliwisz użytkownikom sterowanie odtwarzaniem:
- Przez słuchawki. Często są to przyciski albo interakcje dotykowe, użytkownik może wykonać na słuchawkach, aby odtworzyć lub wstrzymać multimedia albo przejść do następnego elementu lub poprzedniego utworu.
- Rozmawiając z Asystentem Google. Częstym wzorcem jest mówienie „OK” Google, wstrzymaj", aby wstrzymać multimedia odtwarzane aktualnie na urządzeniu.
- Na zegarku z Wear OS. Ułatwia to dostęp do typowe elementy sterujące odtwarzaniem podczas grania na telefonie.
- Za pomocą opcji sterowania multimediami. Ta karuzela przedstawia elementy sterujące: podczas prowadzenia sesji multimediów.
- Na telewizorze. Umożliwia wykonywanie działań za pomocą fizycznych przycisków odtwarzania, odtwarzanie na platformie sterowania i zarządzania zasilaniem (jeśli na przykład telewizor, soundbar lub amplituner A/V wyłączy się lub źródło sygnału zostanie przełączone, odtwarzanie w aplikacji powinno zostać zatrzymane).
- oraz wszelkie inne procesy zewnętrzne, które muszą wpłynąć na odtwarzanie.
Taka konfiguracja sprawdza się w wielu zastosowaniach. Szczególnie ważne jest,
przy użyciu funkcji MediaSession
, gdy:
- Prowadzisz długie treści wideo, np. filmy lub telewizję na żywo.
- Odtwarzasz długie treści audio, np. podcasty lub muzykę playlistach.
- Tworzysz aplikację telewizyjną.
Jednak nie wszystkie przypadki użycia dobrze pasują do MediaSession
. Możesz
użyj Player
tylko w tych przypadkach:
- Wyświetlasz krótkie treści, w których interakcja i zaangażowanie użytkowników ma kluczowe znaczenie.
- nie ma żadnego aktywnego filmu, na przykład użytkownik przewija listę. Na ekranie wyświetla się wiele filmów w tym samym czasie.
- Grasz w jednorazowy film z wprowadzeniem lub wyjaśnieniem, oczekuje, że użytkownik będzie aktywnie oglądać treści.
- Twoje treści mają ochronę prywatności i nie chcesz, aby zewnętrzne procesy wykonywały dostęp do metadanych multimediów (np. w trybie incognito w przeglądarce),
Jeśli Twój przypadek użycia nie pasuje do żadnej z powyższych kategorii,
a Twoja aplikacja może kontynuować odtwarzanie, gdy użytkownik nie wykonuje aktywnie działań
z treścią. Jeśli odpowiedź jest twierdząca,
MediaSession
Jeśli odpowiedź jest przecząca, skorzystaj prawdopodobnie z narzędzia Player
.
Tworzenie sesji multimediów
Sesja multimedialna działa razem z odtwarzaczem, którym zarządza. Możesz utworzyć
sesja multimediów z obiektami Context
i Player
. Należy tworzyć
zainicjować sesję multimediów, gdy jest potrzebna, np. onStart()
lub
Metoda cyklu życia onResume()
Activity
, Fragment
lub onCreate()
metody Service
, do której należy sesja multimediów i powiązany z nią odtwarzacz.
Aby utworzyć sesję multimediów, zainicjuj obiekt Player
i przekaż go do funkcji
MediaSession.Builder
lubi to:
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();
Automatyczna obsługa stanów
Biblioteka Media3 automatycznie aktualizuje sesję multimediów za pomocą o stanie gracza. W związku z tym nie musisz ręcznie obsługiwać mapowania z do sesji.
To przerwa od starszego podejścia, które wymagało tworzenia i utrzymywania
PlaybackStateCompat
niezależnie od odtwarzacza, na przykład do
i wskazywać jakieś błędy.
Unikalny identyfikator sesji
Domyślnie MediaSession.Builder
tworzy sesję z pustym ciągiem znaków:
identyfikator sesji. To wystarczy, jeśli aplikacja zamierza utworzyć tylko jeden
wystąpienia sesji, co jest najczęstszym przypadkiem.
Jeśli aplikacja chce zarządzać wieloma wystąpieniami sesji jednocześnie,
musi zapewnić niepowtarzalny identyfikator każdej sesji. Identyfikator sesji może
być ustawiana podczas tworzenia sesji w narzędziu MediaSession.Builder.setId(String id)
.
Jeśli widzisz błąd IllegalStateException
powodujący awarię aplikacji
wyślij wiadomość do: IllegalStateException: Session ID must be unique. ID=
, to jest
sesja została nieoczekiwanie utworzona przed
opublikowano instancję o tym samym identyfikatorze. Aby uniknąć wycieku sesji przez
błąd programowania, takie przypadki są wykrywane i powiadamiane
wyjątek.
Przyznaj kontrolę innym klientom
Sesja multimediów to klucz do sterowania odtwarzaniem. Umożliwia kierowanie poleceń ze źródeł zewnętrznych do odtwarzacza, który odpowiada za odtwarzanie multimediów. Źródłem tych mogą być przyciski fizyczne, takie jak przycisk odtwarzania na zestaw słuchawkowy lub pilot do telewizora, a także polecenia pośrednie, takie jak instrukcja „wstrzymaj” do Asystenta Google. Możesz też zechcieć udzielić dostępu do konta do obsługi powiadomień i ekranu blokady lub Wear OS i sterować odtwarzaniem z tarczy zegarka. Klienci zewnętrzni mogą używać kontrolera multimediów do wydawania poleceń odtwarzania w aplikacji do multimediów. Są to w ramach sesji multimediów, która przekazuje polecenia do odtwarzacza multimediów.
.Gdy kontroler ma się połączyć z sesją multimediów,
onConnect()
. Za pomocą tego narzędzia możesz: ControllerInfo
podjąć decyzję o zaakceptowaniu
lub odrzuć
do danej prośby. Przykład akceptowania prośby o połączenie znajdziesz w sekcji Deklarowanie
dostępnych poleceń.
Po połączeniu kontroler może wysyłać do sesji polecenia odtwarzania.
sesja, następnie przekazuje te polecenia do odtwarzacza. Odtwarzanie i playlista
polecenia zdefiniowane w interfejsie Player
są automatycznie obsługiwane przez
.
Inne metody wywołania zwrotnego umożliwiają obsługę na przykład żądań dotyczących
własnych poleceń odtwarzania
zmieniając playlistę).
Te wywołania zwrotne podobnie zawierają obiekt ControllerInfo
, więc możesz go zmodyfikować
jak reagować na poszczególne żądania z uwzględnieniem każdego administratora.
Modyfikowanie playlisty
Sesja multimediów może bezpośrednio modyfikować playlistę w odtwarzaczu, jak opisano w tym artykule:
Przewodnik po playlistach w ExoPlayer.
Kontrolery mogą też modyfikować playlistę, jeśli:
COMMAND_SET_MEDIA_ITEM
lub COMMAND_CHANGE_MEDIA_ITEMS
jest dostępna dla kontrolera.
Podczas dodawania nowych elementów do playlisty odtwarzacz zwykle wymaga dodatku MediaItem
z instancjami z
zdefiniowany identyfikator URI
aby można było grać w nich. Domyślnie nowo dodane elementy są automatycznie przekazywane dalej
do metod odtwarzacza, takich jak player.addMediaItem
, jeśli mają zdefiniowany identyfikator URI.
Jeśli chcesz dostosować instancje MediaItem
dodane do odtwarzacza, możesz
zastąpić
onAddMediaItems()
Ten krok jest potrzebny, gdy chcesz obsługiwać kontrolery, które wysyłają żądania multimediów
bez zdefiniowanego identyfikatora URI. Zamiast tego MediaItem
zwykle ma
ustawiono co najmniej jedno z tych pól opisujących żądane multimedia:
MediaItem.id
: ogólny identyfikator identyfikujący multimedia.MediaItem.RequestMetadata.mediaUri
: identyfikator URI żądania, który może zawierać niestandardowy i nie musi być bezpośrednio odtwarzany przez odtwarzacz.MediaItem.RequestMetadata.searchQuery
: zapytanie tekstowe, np. za pomocą Asystenta Google.MediaItem.MediaMetadata
: uporządkowane metadane, np. „tytuł”. lub „artist”.
Aby zyskać więcej opcji dostosowywania zupełnie nowych playlist,
dodatkowo zastąp
onSetMediaItems()
który pozwala określić
początek playlisty i jej pozycję. Przykład:
możesz rozwinąć żądaną pozycję
do całej playlisty i poinstruować się
w celu rozpoczęcia od indeksu pierwotnie żądanego elementu. O
przykładowa implementacja onSetMediaItems()
z tą funkcją znajdziesz w aplikacji demonstracyjnej sesji.
Zarządzanie układem niestandardowym i poleceniami niestandardowymi
W poniższych sekcjach opisano, jak reklamować niestandardowy układ strony do aplikacji klienckich i autoryzacji kontrolerów do wysyłania poleceń.
Zdefiniuj niestandardowy układ sesji
Aby wskazać aplikacjom klienckim, które elementy sterujące odtwarzaniem chcesz udostępnić
ustaw niestandardowy układ sesji.
podczas tworzenia MediaSession
w metodzie onCreate()
Twojego
posprzedażna.
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(); }
Zadeklaruj dostępny odtwarzacz i polecenia niestandardowe
Aplikacje multimedialne mogą definiować polecenia niestandardowe, których można używać na przykład
lub układ niestandardowy. Możesz na przykład utworzyć przyciski, które umożliwiają użycie
aby zapisać element multimedialny na liście ulubionych. MediaController
wysyła polecenia niestandardowe, a MediaSession.Callback
je otrzymuje.
Możesz określić, które niestandardowe polecenia sesji będą dostępne dla
MediaController
, gdy połączy się z sesją multimediów. Jest to możliwe dzięki
zastępując MediaSession.Callback.onConnect()
. Skonfiguruj i zwróć
zestawu poleceń dostępnych podczas akceptowania żądania połączenia
MediaController
w metodzie wywołania zwrotnego 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(); } }
Aby otrzymywać niestandardowe polecenia z MediaController
, zastąp
onCustomCommand()
w 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) ); } ... } }
Możesz prześledzić, który kontroler multimediów wysyła żądanie, używając
Właściwość packageName
obiektu MediaSession.ControllerInfo
, który jest
przekazywane do metod Callback
. Dzięki temu możesz dostosować
w odpowiedzi na dane polecenie, jeśli pochodzi ono z systemu,
do własnych aplikacji lub do innych aplikacji klienckich.
Aktualizacja układu niestandardowego po interakcji użytkownika
Po obsługi polecenia niestandardowego lub innej interakcji z odtwarzaczem
może chcieć zaktualizować układ wyświetlany w interfejsie kontrolera. Typowy przykład
to przycisk przełączania, który zmienia swoją ikonę po uruchomieniu powiązanego działania
klikając ten przycisk. Aby zaktualizować układ, możesz użyć
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));
Dostosowywanie działania poleceń odtwarzania
Aby dostosować działanie polecenia zdefiniowanego w interfejsie Player
:
jako play()
lub seekToNext()
, umieść Player
w: 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();
Więcej informacji na temat ForwardingPlayer
znajdziesz w przewodniku ExoPlayer na stronie
Dostosowywanie.
Identyfikowanie kontrolera żądającego polecenia odtwarzacza
Jeśli wywołanie metody Player
jest inicjowane przez usługę MediaController
, możesz
określ źródło pochodzenia za pomocą parametru MediaSession.controllerForCurrentRequest
i pobierz ControllerInfo
dla bieżącego żądania:
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(); } }
Reagowanie na przyciski multimediów
Przyciski multimediów to przyciski sprzętowe dostępne na urządzeniach z Androidem i innych urządzeniach peryferyjnych
urządzeniach takich jak przycisk odtwarzania/wstrzymywania na słuchawkach Bluetooth. Uchwyty Media3
zdarzenia związane z przyciskiem multimedialnym po dotarciu do sesji i wywołaniu funkcji
odpowiednią metodę Player
w odtwarzaczu w sesji.
Aplikacja może zastąpić domyślne działanie przez zastąpienie
MediaSession.Callback.onMediaButtonEvent(Intent)
W takim przypadku aplikacja
może/musi samodzielnie radzić sobie ze wszystkimi specyfikami interfejsu API.
Obsługa błędów i raportowanie
Istnieją 2 typy błędów, które sesja generuje i zgłasza kontrolery. Błędy krytyczne zgłaszają niepowodzenie techniczne podczas odtwarzania sesji. który przerywa odtwarzanie. Błędy krytyczne są zgłaszane do kontrolera automatycznie, gdy tylko wystąpią. Błędy niekrytyczne nie są związane z naruszeniem zasad ani technicznymi które nie przerywają odtwarzania i są wysyłane do kontrolerów przez aplikacji ręcznie.
Krytyczne błędy odtwarzania
Odtwarzacz zgłasza do sesji błąd krytyczny podczas odtwarzania, a następnie
przekazywane kontrolerom na potrzeby połączenia
Player.Listener.onPlayerError(PlaybackException)
i
Player.Listener.onPlayerErrorChanged(@Nullable PlaybackException)
W takim przypadku stan odtwarzania jest zmieniany na STATE_IDLE
i
MediaController.getPlaybackError()
zwraca błąd PlaybackException
, który spowodował
o przeniesieniu. Kontroler może sprawdzać PlayerException.errorCode
, aby uzyskać
o przyczynie błędu.
W przypadku interoperacyjności błąd krytyczny jest replikowany w PlaybackStateCompat
sesji platformy przez zmianę jej stanu na STATE_ERROR
i ustawienie
z kodem błędu i komunikatem zgodnie z dokumentem PlaybackException
.
Dostosowywanie błędu krytycznego
Aby udostępnić użytkownikowi zlokalizowane i wartościowe informacje, kod błędu
w komunikatach o błędach i elementach dodatkowych o krytycznym błędzie odtwarzania można dostosować,
za pomocą funkcji ForwardingPlayer
podczas budowania sesji:
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();
Odtwarzacz przekierowujący rejestruje Player.Listener
w odtwarzaczu
i przechwytuje wywołania zwrotne, które zgłaszają błąd. Profil niestandardowy
Pole PlaybackException
jest przekazywane detektorom,
są zarejestrowane w odtwarzaczu przekierowania. Aby to działało, odtwarzacz przekierowujący
zastępuje Player.addListener
i Player.removeListener
, aby mieć dostęp do
detektory, za pomocą których można wysłać dostosowany kod błędu, komunikat lub dodatki:
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. } }
Błędy niekrytyczne
Mogą zostać wysłane błędy niekrytyczne, które nie pochodzą z wyjątku technicznego. przez aplikację do wszystkich lub określonego kontrolera:
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); }
Błąd niekrytyczny wysyłany do kontrolera powiadomień o multimediach jest replikowany do
PlaybackStateCompat
sesji na platformie. Oznacza to, że jedynie kod błędu
komunikat o błędzie jest odpowiednio ustawiony na PlaybackStateCompat
, podczas gdy
Pole PlaybackStateCompat.state
nie zostało zmienione na wartość STATE_ERROR
.
Otrzymuj błędy niekrytyczne
W przypadku MediaController
występuje błąd niekrytyczny po wdrożeniu
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. } });