Interfejs odtwarzacza

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

  • wpływ na elementy sterujące odtwarzaniem, takie jak odtwarzanie, wstrzymywanie i przewijanie;
  • wykonywanie zapytań o właściwości aktualnie odtwarzanych multimediów, np. o pozycję odtwarzania;
  • Zarządzanie playlistą lub kolejką elementów multimedialnych
  • konfigurowanie właściwości odtwarzania, takich jak odtwarzanie losowe, powtarzanie, szybkość 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 Player implementuje kilka komponentów w Media3, np.:

Komponent Opis i uwagi dotyczące zachowania
ExoPlayer Interfejs API odtwarzacza multimediów i domyślna implementacja interfejsu Player.
MediaController Współpracuje z MediaSession, aby wysyłać polecenia odtwarzania. Jeśli elementy PlayerMediaSession znajdują się w Service oddzielonym od Activity lub Fragment, w którym znajduje się interfejs odtwarzacza, możesz przypisać element MediaController jako odtwarzacz dla interfejsu PlayerView. Wywołania metod odtwarzania i playlist są wysyłane na urządzenie Player przez urządzenie MediaSession.
MediaBrowser Oprócz funkcji oferowanych przez MediaController wchodzi w interakcję z  MediaLibrarySession, aby przeglądać dostępne treści multimedialne.
SimpleBasePlayer Implementacja Player, która zmniejsza liczbę metod do zaimplementowania do minimum. Przydatne, gdy używasz niestandardowego odtwarzacza, który chcesz połączyć z MediaSession.
ForwardingSimpleBasePlayer SimpleBasePlayer podklasa zaprojektowana do przekazywania operacji odtwarzania do innego elementu Player, która umożliwia te same spójne dostosowania zachowania co SimpleBasePlayer. Użyj tej klasy, aby pominąć lub zmodyfikować określone operacje odtwarzania.
RemoteCastPlayer Implementacja Player do sterowania odtwarzaniem w zdalnej aplikacji odbiornika Cast.
CastPlayer Implementacja Player do sterowania odtwarzaniem Cast zarówno lokalnie, jak i zdalnie.

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

Architektura odtwarzania Media3

Jeśli masz dostęp do Player, wywołuj jego metody bezpośrednio, aby wydawać polecenia odtwarzania. Możesz reklamować odtwarzanie i przyznawać źródłom zewnętrznym kontrolę nad odtwarzaniem, wdrażając MediaSession. Te źródła zewnętrzne implementują MediaController, który ułatwia łączenie się z sesją multimedialną i wydawanie żądań poleceń odtwarzania.

Podczas odtwarzania multimediów w tle sesja multimedialna i odtwarzacz muszą znajdować się w MediaSessionService lub MediaLibraryService, które działają jako usługa na pierwszym planie. Dzięki temu możesz oddzielić odtwarzacz od aktywności w aplikacji, która zawiera interfejs sterowania odtwarzaniem. Może to wymagać użycia opcji sterowania multimediami.

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

Stan odtwarzacza

Stan odtwarzacza multimediów implementującego interfejs Player składa się głównie z 4 kategorii informacji:

  1. Stan odtwarzania
  2. Playlista elementów multimedialnych
  3. właściwości odtwarzania/wstrzymywania, takie jak:
    • playWhenReady: określa, czy użytkownik chce, aby multimedia były odtwarzane, gdy jest to możliwe, czy mają pozostać wstrzymane.
    • Przyczyna wstrzymania odtwarzania: wskazanie przyczyny wstrzymania odtwarzania (w odpowiednich przypadkach), nawet jeśli playWhenReady ma wartość true.
    • isPlaying: informacja o tym, czy odtwarzacz aktualnie odtwarza film. Wartość ta będzie równa true tylko wtedy, gdy stan odtwarzania to STATE_READY, wartość playWhenReady to true, a odtwarzanie nie jest wstrzymane.
  4. Pozycja odtwarzania, w tym:

Dodatkowo interfejs Player umożliwia dostęp do dostępnych ścieżek, metadanych multimediów, szybkości odtwarzania, głośności i innych właściwości pomocniczych odtwarzania.

Sprawdzanie zmian

Użyj Player.Listener, aby monitorować zmiany w Player. Więcej informacji o tworzeniu i używaniu detektora znajdziesz w dokumentacji ExoPlayera dotyczącej zdarzeń odtwarzacza.

Pamiętaj, że interfejs odbiornika nie zawiera żadnych wywołań zwrotnych do śledzenia normalnego postępu odtwarzania. Aby stale monitorować postęp odtwarzania, np. w celu skonfigurowania interfejsu paska postępu, należy w odpowiednich odstępach czasu wysyłać zapytania o bieżącą pozycję.

Kotlin

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

Java

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 manipulowania stanem i sterowania odtwarzaniem:

Implementacje niestandardowe Player

Aby utworzyć niestandardowy odtwarzacz, możesz rozszerzyć klasę SimpleBasePlayer zawartą w Media3. Ta klasa zapewnia podstawową implementację interfejsu Player, aby zredukować do minimum liczbę metod, które musisz zaimplementować.

Zacznij od zastąpienia metody getState(). Ta metoda powinna wypełniać stan bieżącego odtwarzacza po wywołaniu, w tym:

  • Zestaw dostępnych poleceń
  • właściwości odtwarzania, takie jak to, czy odtwarzacz ma rozpocząć odtwarzanie, gdy stan odtwarzania to STATE_READY, indeks obecnie odtwarzanego elementu multimedialnego i pozycja odtwarzania w bieżącym elemencie;

Kotlin

class CustomPlayer(looper: Looper) : SimpleBasePlayer(looper) {
  override fun getState(): State {
    return State.Builder()
      .setAvailableCommands(Commands.EMPTY) // 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

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

  @Override
  protected State getState() {
    return new State.Builder()
        .setAvailableCommands(Commands.EMPTY) // 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 elementu State z prawidłową kombinacją wartości stanu. Zajmuje się też odbiorcami i informowaniem ich o zmianach stanu. Jeśli musisz ręcznie wywołać aktualizację stanu, wywołaj funkcję invalidateState().

Oprócz metody getState() musisz wdrożyć tylko te metody, które są używane w przypadku poleceń, które odtwarzacz deklaruje jako dostępne. Znajdź metodę obsługi, którą można zastąpić, odpowiadającą funkcji, którą chcesz zaimplementować. Możesz na przykład zastąpić metodę handleSeek(), aby obsługiwać operacje takie jak COMMAND_SEEK_IN_CURRENT_MEDIA_ITEMCOMMAND_SEEK_TO_NEXT_MEDIA_ITEM.

Modyfikowanie implementacji Player

Zamiast tworzyć całkowicie niestandardowy Player, możesz użyć ForwardingSimpleBasePlayer, aby zmodyfikować stan i zachowanie istniejącego Player. Więcej informacji znajdziesz w przewodniku na stronie dostosowywania.