Interfejs odtwarzacza

Odtwarzacz to element aplikacji, który umożliwia odtwarzanie elementów multimedialnych. Interfejs Media3 Player określa zarys funkcji zwykle obsługiwanych przez odtwarzacz. Obejmuje to:

  • Wpływ na elementy sterujące odtwarzaniem, takie jak odtwarzanie, wstrzymywanie i przewijanie
  • Zapytanie o właściwości aktualnie odtwarzanych multimediów, takie jak pozycja odtwarzania
  • Zarządzanie playlistą lub kolejką elementów multimedialnych
  • Konfigurowanie właściwości odtwarzania, takich jak losowe, powtarzanie, prędkość i głośność
  • Renderowanie filmu na ekranie

Media3 udostępnia też implementację interfejsu Player o nazwie ExoPlayer.

Wspólny interfejs między komponentami

Interfejs odtwarzacza jest implementowany przez kilka komponentów Media3, np.:

Komponent Opis i informacje o działaniu
ExoPlayer Interfejs API odtwarzacza multimediów i domyślna implementacja interfejsu Player.
MediaController Wchodzi w interakcję z elementem MediaSession, aby wysłać polecenia odtwarzania. Jeśli Twoje Player i MediaSession znajdują się w Service innej niż Activity lub Fragment, gdzie działa interfejs odtwarzacza, możesz przypisać MediaController jako odtwarzacz w swoim interfejsie PlayerView. Wywołania metody odtwarzania i playlist są wysyłane na urządzenie Player przez MediaSession.
MediaBrowser Oprócz funkcji oferowanych przez MediaController korzysta też z MediaLibrarySession, aby przeglądać dostępne treści multimedialne.
ForwardingPlayer Implementacja Player, która przekierowuje wywołania metody do innego komponentu Player. Użyj tej klasy do pomijania lub modyfikowania określonych operacji przez zastąpienie odpowiednich metod.
SimpleBasePlayer Implementacja Player, która zmniejsza do minimum liczbę metod implementacji. Przydaje się, gdy korzystasz z niestandardowego odtwarzacza, który chcesz połączyć z urządzeniem MediaSession.
CastPlayer Implementacja Player, która komunikuje się z aplikacją odbiornika. Sposób działania zależy od sesji przesyłania.

Chociaż element MediaSession nie implementuje interfejsu Player, do jego tworzenia wymagany jest element Player. Jego celem jest zapewnienie dostępu do Player z poziomu innych procesów lub wątków.

Architektura odtwarzania Media3

Jeśli masz dostęp do obiektu Player, wywołaj jego metody bezpośrednio, aby wysyłać polecenia odtwarzania. Możesz zareklamować odtwarzanie i przyznać kontrolę odtwarzania w przypadku źródeł zewnętrznych, implementując MediaSession. Te źródła zewnętrzne implementują MediaController, który ułatwia nawiązanie połączenia z sesją multimediów i wydawanie żądań odtwarzania.

Gdy odtwarzasz multimedia w tle, musisz przechowywać sesję multimediów i odtwarzacz w interfejsie MediaSessionService lub MediaLibraryService, które działają jako usługa na pierwszym planie. W ten sposób możesz oddzielić odtwarzacz od aktywności w aplikacji, która zawiera interfejs sterowania odtwarzaniem. Może to wymagać użycia kontrolera multimediów.

Schemat pokazujący, jak komponenty odtwarzania Media3 pasują do architektury aplikacji do multimediów.
Rysunek 1. Interfejs Player odgrywa kluczową rolę w architekturze Media3.

Stan odtwarzacza

Stan odtwarzacza multimedialnego z implementacją interfejsu Player obejmuje głównie 4 kategorie informacji:

  1. Stan odtwarzania:
  2. Playlista z elementami multimedialnymi
  3. Usługi odtwarzania/wstrzymywania, takie jak:
    • playWhenReady: wskazanie, czy użytkownik chce odtwarzać multimedia, gdy to możliwe, czy ma być wstrzymane.
    • Przyczyna wstrzymania odtwarzania: wskazanie przyczyny wstrzymania odtwarzania (w stosownych przypadkach), nawet jeśli parametr playWhenReady ma wartość true
    • isPlaying: informacja o tym, czy odtwarzacz w danej chwili gra. Ma wartość true, jeśli stan odtwarzania to STATE_READY, playWhenReady to true, a odtwarzanie nie jest wstrzymane.
  4. Pozycja odtwarzania, w tym:

Oprócz tego interfejs Player zapewnia dostęp do dostępnych ścieżek, metadanych multimediów, prędkości odtwarzania, głośności i innych właściwości pomocniczych związanych z odtwarzaniem.

Wykrywaj zmiany

Użyj funkcji Player.Listener, aby nasłuchiwać zmian w elemencie Player. Szczegółowe informacje o tym, jak utworzyć detektor i używać go, znajdziesz w dokumentacji ExoPlayer dotyczącej zdarzeń odtwarzacza.

Pamiętaj, że interfejs odbiornika nie zawiera żadnych wywołań zwrotnych umożliwiających śledzenie normalnego postępu odtwarzania. Aby stale monitorować postęp odtwarzania, np. skonfigurować interfejs paska postępu, wysyłaj zapytania o bieżącą pozycję w odpowiednich odstępach czasu.

Kotlin

val handler = Handler(Looper.getMainLooper())
fun checkPlaybackPosition(delayMs: Long): Boolean =
  handler.postDelayed(
    {
      val currentPosition = player.currentPosition
      // Update UI based on currentPosition
      checkPlaybackPosition(delayMs)
    },
    delayMs)

Java

Handler handler = new Handler(Looper.getMainLooper());
boolean checkPlaybackPosition(long delayMs) {
    return handler.postDelayed(() -> {
        long currentPosition = player.getCurrentPosition();
        // Update UI based on currentPosition
        checkPlaybackPosition(delayMs);
    }, delayMs);
}

Sterowanie odtwarzaniem

Interfejs Player oferuje wiele sposobów na manipulowanie stanem i odtwarzaniem:

Niestandardowe implementacje typu Player

Aby utworzyć własny odtwarzacz, możesz rozszerzyć SimpleBasePlayer z Media3. Ta klasa udostępnia podstawową implementację interfejsu Player, która pozwala do minimum ograniczyć liczbę metod, które trzeba wdrożyć.

Zacznij od zastąpienia metody getState(). Po wywołaniu metoda ta powinna zapełniać bieżący stan odtwarzacza, w tym:

  • Zestaw dostępnych poleceń
  • Właściwości odtwarzania: np. czy odtwarzacz powinien rozpocząć odtwarzanie, gdy stan odtwarzania to STATE_READY, indeks aktualnie odtwarzanego elementu multimedialnego i pozycja odtwarzania w bieżącym elemencie

Kotlin

class CustomPlayer : SimpleBasePlayer(looper) {
  override fun getState(): State {
    return State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build()
  }
}

Java

public class CustomPlayer extends SimpleBasePlayer {
  public CustomPlayer(Looper looper) {
    super(looper);
  }

  @Override
  protected State getState() {
    return new State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build();
  }
}

SimpleBasePlayer wymusi utworzenie State z prawidłową kombinacją wartości stanu. Będzie też obsługiwać słuchaczy i informować słuchaczy o zmianach w poszczególnych stanach. Jeśli musisz ręcznie aktywować aktualizację stanu, wywołaj metodę invalidateState().

Oprócz metody getState() musisz implementować tylko metody używane w poleceniach zadeklarowanych przez odtwarzacz jako dostępne. Znajdź metodę zastępowania z możliwością zastępowania odpowiadającą funkcji, którą chcesz zaimplementować. Na przykład zastąp metodę handleSeek(), aby obsługiwać operacje takie jak COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM i COMMAND_SEEK_TO_NEXT_MEDIA_ITEM.