Interfejs odtwarzacza

Odtwarzacz to komponent aplikacji, który umożliwia odtwarzanie elementów multimedialnych. 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,
  • konfigurować właściwości odtwarzania, takie 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 playlist są wysyłane na urządzenie Player za pomocą urządzenia MediaSession.
MediaBrowser Oprócz funkcji oferowanych przez MediaController używa też MediaLibrarySession, aby przeglądać dostępne treści multimedialne.
ForwardingPlayer Implementacja Player, która przekazuje wywołania metod do innej Player. Używaj tej klasy, aby pomijać lub modyfikować określone operacje przez zastąpienie odpowiednich metod.
SimpleBasePlayer Player, która minimalizuje liczbę metod do zaimplementowania. Przydatne, gdy używasz niestandardowego odtwarzacza, który chcesz połączyć z MediaSession.
CastPlayer Implementacja Player, która komunikuje się z aplikacją odbiornika Cast. Sposób działania zależy od używanej sesji przesyłania.

Chociaż MediaSession nie implementuje interfejsu Player, wymaga utworzenia Player. Jego zadaniem jest zapewnienie dostępu do obiektu Player z 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ą interfejs MediaController, który ułatwia łączenie się z sesją multimediów oraz wysyłanie żądań 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. Jeśli to zrobisz, możesz oddzielić odtwarzacz od sekcji Aktywność w aplikacji, która zawiera interfejs 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 z elementami multimedialnymi
  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 wstrzymania odtwarzania: informacja o przyczynach wstrzymania odtwarzania (jeśli ma to zastosowanie), nawet jeśli parametr playWhenReady ma wartość true.
    • isPlaying: informacja o tym, czy odtwarzacz obecnie odtwarza. Ta wartość będzie mieć wartość true tylko wtedy, gdy stan odtwarzania to STATE_READY, playWhenReady ma wartość 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.

Nasłuchiwanie zmian

Użyj Player.Listener, aby nasłuchiwać zmian w Player. Szczegółowe informacje o tym, jak utworzyć detektor i jak używać detektora, 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, np. skonfigurować interfejs paska postępu, wysyłaj zapytania dotyczące bieżącej pozycji 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ć zasób SimpleBasePlayer zawarty w Media3. Ta klasa stanowi podstawową implementację interfejsu Player, aby ograniczyć do minimum liczbę metod, które trzeba wdrożyć.

Zacznij od zastąpienia metody getState(). Ta metoda po wywołaniu powinna wypełniać bieżący stan odtwarzacza, 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 on również obsługiwać detektory i informować słuchaczy 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.