Interfejs odtwarzacza

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

  • wpływają na elementy sterujące odtwarzaniem, takie jak odtwarzanie, wstrzymywanie i przewijanie;
  • właściwości odtwarzanych obecnie multimediów, takie jak pozycja odtwarzania;
  • zarządzanie playlistą lub kolejką multimediów,
  • konfigurowanie właściwości odtwarzania, takich jak losowanie, 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 odtwarzacza jest implementowany w kilku komponentach Media3, na przykład:

Komponent Opis i uwagi dotyczące zachowania
ExoPlayer Interfejs API odtwarzacza multimediów i domyślna implementacja interfejsu Player.
MediaController Interakcja z przyciskiem MediaSession w celu wysłania poleceń odtwarzania. Jeśli PlayerMediaSession znajdują się w Service oddzielnym od Activity lub Fragment, w którym znajduje się interfejs użytkownika gracza, możesz przypisać MediaController jako gracza dla interfejsu PlayerView. Wywołania metody odtwarzania i playlisty są wysyłane do Player przez MediaSession.
MediaBrowser Oprócz funkcji oferowanych przez komponent MediaController współdziała z komponentem MediaLibrarySession, aby przeglądać dostępne treści multimedialne.
SimpleBasePlayer Player, która minimalizuje liczbę metod do implementacji. Przydatne, gdy używasz niestandardowego odtwarzacza, który chcesz połączyć z MediaSession.
ForwardingSimpleBasePlayer Podklasa SimpleBasePlayer, która ma za zadanie przekazywać operacje odtwarzania do innej klasy Player, umożliwiając jednocześnie takie same spersonalizowane zachowania jak SimpleBasePlayer. Użyj tej klasy, aby pominąć lub zmodyfikować określone operacje odtwarzania.
CastPlayer Implementacja Player, która komunikuje się z aplikacją odbiorczą Cast. Jej działanie zależy od sesji Cast.

Chociaż MediaSession nie implementuje interfejsu Player, wymaga utworzenia Player. Jego zadaniem jest zapewnienie dostępu do Playerz innych procesów lub wątków.

Architektura odtwarzania Media3

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

Podczas odtwarzania multimediów w tle musisz umieścić sesję multimediów i odtwarzacz w ramach MediaSessionService lub MediaLibraryService, który działa jako usługa na pierwszym planie. Dzięki temu możesz oddzielić odtwarzacz od aktywności w aplikacji, która zawiera interfejs do sterowania odtwarzaniem. Może to wymagać użycia kontrolera multimediów.

Schemat pokazujący, jak elementy odtwarzania Media3 pasują do architektury aplikacji multimedialnej.
Ilustracja 1. Interfejs Player odgrywa kluczową rolę w architekturze Media3.

Stan gracza

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: Wskazanie, czy użytkownik chce, aby multimedia były odtwarzane, gdy to możliwe, czy mają pozostać wstrzymane.
    • Przyczyna wyłączenia odtwarzania: wskazanie, dlaczego odtwarzanie zostało wyłączone (jeśli to możliwe), nawet jeśli playWhenReady to true.
    • isPlaying: wskazanie, czy odtwarzacz jest obecnie odtwarzany. Będzie to true tylko wtedy, gdy stan odtwarzania to STATE_READY, playWhenReady to true, a odtwarzanie nie jest tłumione.
  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.

Nasłuchiwanie zmian

Użyj Player.Listener, aby nasłuchiwać zmian w Player. Szczegółowe informacje o tworzeniu i używaniu listenera znajdziesz w dokumentacji ExoPlayer dotyczącej zdarzeń odtwarzacza.

Pamiętaj, że interfejs listenera nie zawiera żadnych wywołań zwrotnych do śledzenia normalnego odtwarzania. Aby stale monitorować postęp odtwarzania, na przykład w celu skonfigurowania paska postępu w interfejsie, należy odpytywać 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 sterowanie odtwarzaniem:

Implementacje niestandardowe Player

Aby utworzyć odtwarzacz niestandardowy, możesz rozszerzyć komponent SimpleBasePlayer, który jest dostępny w Media3. Ta klasa zapewnia podstawową implementację interfejsu Player, aby zminimalizować liczbę metod, które musisz zaimplementować.

Zacznij od zastąpienia metody getState(). Ta metoda powinna wypełniać bieżący stan gracza podczas wywołania, w tym:

  • zestaw dostępnych poleceń;
  • właściwości odtwarzania, takie jak to, czy odtwarzacz powinien rozpocząć odtwarzanie, gdy stan odtwarzania to STATE_READY, indeks aktualnie odtwarzanego elementu multimedialnego oraz 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 spowoduje, że State zostanie utworzony z poprawną kombinacją wartości stanu. Będzie też obsługiwać subskrybentów i informować ich o zmianach stanu. Jeśli chcesz ręcznie zaktualizować stan, zadzwoń pod numer invalidateState().

Oprócz metody getState() musisz zaimplementować tylko te metody, które są używane do poleceń, które Twój odtwarzacz deklaruje jako dostępne. Znajdź metodę obsługi, którą można zastąpić, odpowiadającą funkcji, którą chcesz zaimplementować. Na przykład: zastąpić metodę handleSeek(), aby obsługiwać operacje takie jak COMMAND_SEEK_IN_CURRENT_MEDIA_ITEMi COMMAND_SEEK_TO_NEXT_MEDIA_ITEM.