Transmisje na żywo

ExoPlayer od razu wyświetla większość adaptacyjnych transmisji na żywo bez żadnej specjalnej konfiguracji. Więcej informacji znajdziesz na stronie Obsługiwane formaty.

W adaptacyjnych transmisjach na żywo wyświetla się okno dostępnych multimediów, które są aktualizowane w regularnych odstępach czasu w celu dostosowania do bieżących wydarzeń w czasie rzeczywistym. Oznacza to, że pozycja odtwarzania zawsze znajduje się gdzieś w tym oknie, w większości przypadków w czasie zbliżonym do bieżącego czasu, w którym jest tworzony strumień. Różnica między bieżącymi sytuacjami w czasie rzeczywistym a pozycją odtwarzania to opóźnienie transmisji na żywo.

Wykrywanie i monitorowanie odtworzeń na żywo

Za każdym razem, gdy zaktualizujesz okno transmisji na żywo, zarejestrowane instancje Player.Listener otrzymają zdarzenie onTimelineChanged. Szczegółowe informacje o bieżącym odtwarzaniu na żywo możesz uzyskać, wysyłając zapytania do różnych metod Player i Timeline.Window, jak pokazano to na ilustracjach poniżej.

Okres wyświetlania

  • Player.isCurrentWindowLive wskazuje, czy aktualnie odtwarzany element multimedialny to transmisja na żywo. Ta wartość obowiązuje nawet po zakończeniu transmisji na żywo.
  • Player.isCurrentWindowDynamic wskazuje, czy aktualnie odtwarzany element multimedialny jest nadal aktualizowany. Zwykle dotyczy to transmisji na żywo, które jeszcze się nie zakończyły. Pamiętaj, że w niektórych przypadkach ta flaga dotyczy też transmisji na żywo.
  • Player.getCurrentLiveOffset zwraca przesunięcie między bieżącą pozycją odtwarzania a pozycją odtwarzania (jeśli jest dostępna).
  • Player.getDuration zwraca długość bieżącego okna transmisji na żywo.
  • Player.getCurrentPosition zwraca pozycję odtwarzania względem początku okna transmisji na żywo.
  • Funkcja Player.getCurrentMediaItem zwraca bieżący element multimedialny, gdzie MediaItem.liveConfiguration zawiera dostarczone przez aplikację zastąpienia docelowego opóźnienia transmisji na żywo i parametrów korekty przesunięcia na żywo.
  • Funkcja Player.getCurrentTimeline zwraca bieżącą strukturę mediów w elemencie Timeline. Bieżący stan Timeline.Window można pobrać z Timeline za pomocą funkcji Player.getCurrentWindowIndex i Timeline.getWindow. W obrębie Window:
    • Window.liveConfiguration zawiera parametry docelowe przesunięcia na żywo i korekty przesunięcia rzeczywistego. Wartości te są oparte na informacjach z multimediów i wszelkich zastąpieniach dostarczanych przez aplikację w MediaItem.liveConfiguration.
    • Window.windowStartTimeMs to czas od epoki uniksowej, w której rozpoczyna się okno transmisji na żywo.
    • Window.getCurrentUnixTimeMs to czas od początku epoki uniksowej bieżącego czasu rzeczywistego. Ta wartość może być skorygowana przez znaną różnicę zegara między serwerem a klientem.
    • Window.getDefaultPositionMs to miejsce w oknie transmisji na żywo, od którego odtwarzacz domyślnie rozpoczyna odtwarzanie.

Szukam w transmisjach na żywo

Za pomocą funkcji Player.seekTo możesz przewinąć do dowolnego miejsca w oknie transmisji na żywo. Przekazana pozycja przewijania jest zależna od początku okna transmisji na żywo. Na przykład seekTo(0) wyszuka początek okna transmisji na żywo. Odtwarzacz będzie starał się zachować takie samo przesunięcie transmisji, jakie ma być wyświetlane po wyszukaniu.

Okno transmisji na żywo ma też domyślną pozycję, od której powinno się rozpocząć odtwarzanie. Ta pozycja znajduje się zwykle blisko krawędzi. Możesz przewinąć do pozycji domyślnej, wywołując funkcję Player.seekToDefaultPosition.

Interfejs odtwarzania na żywo

Domyślne komponenty interfejsu ExoPlayera pokazują czas trwania okna transmisji na żywo i bieżącą pozycję odtwarzania w nim. Oznacza to, że przy każdej aktualizacji okna transmisji na żywo będzie ona pojawiać się jako przeskok wstecz. Jeśli potrzebujesz innego sposobu działania, na przykład pokazywania czasu uniksowego lub bieżącego przesunięcia czasu rzeczywistego, możesz utworzyć rozwidlenie PlayerControlView i dostosować go do swoich potrzeb.

Konfigurowanie parametrów odtwarzania na żywo

ExoPlayer używa określonych parametrów do kontrolowania przesunięcia pozycji odtwarzania od krawędzi aktywnej oraz zakresu szybkości odtwarzania, których można użyć do dostosowania tego przesunięcia.

ExoPlayer pobiera wartości tych parametrów z 3 miejsc w kolejności malejącej według priorytetu (używana jest pierwsza znaleziona wartość):

  • Na MediaItem wartości przekazane do MediaItem.Builder.setLiveConfiguration.
  • Globalne wartości domyślne ustawione w systemie DefaultMediaSourceFactory.
  • Wartości są odczytywane bezpośrednio z multimediów.

Kotlin

// Global settings.
val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000))
    .build()

// Per MediaItem settings.
val mediaItem =
  MediaItem.Builder()
    .setUri(mediaUri)
    .setLiveConfiguration(
      MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build()
    )
    .build()
player.setMediaItem(mediaItem)

Java

// Global settings.
ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000))
        .build();

// Per MediaItem settings.
MediaItem mediaItem =
    new MediaItem.Builder()
        .setUri(mediaUri)
        .setLiveConfiguration(
            new MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build())
        .build();
player.setMediaItem(mediaItem);

Dostępne wartości konfiguracyjne:

  • targetOffsetMs: docelowe przesunięcie czasu rzeczywistego. W miarę możliwości odtwarzacz spróbuje zbliżyć się do tego opóźnienia transmisji na żywo.
  • minOffsetMs: minimalne dozwolone opóźnienie transmisji na żywo. Nawet jeśli dostosujesz przesunięcie do bieżących warunków sieciowych, podczas odtwarzania odtwarzacz nie będzie próbował przejść poniżej tego przesunięcia.
  • maxOffsetMs: maksymalne dozwolone opóźnienie transmisji na żywo. Nawet jeśli dostosujesz przesunięcie do bieżących warunków sieciowych, podczas odtwarzania odtwarzacz nie będzie próbował przekroczyć tego przesunięcia.
  • minPlaybackSpeed: minimalna szybkość odtwarzania, przy użyciu której odtwarzacz może użyć kreacji zastępczej przy próbie osiągnięcia docelowej opóźnienia transmisji na żywo.
  • maxPlaybackSpeed: maksymalna szybkość odtwarzania, której odtwarzacz może użyć, aby nadrobić zaległości podczas próby osiągnięcia docelowego przesunięcia transmisji na żywo.

Regulacja szybkości odtwarzania

Podczas odtwarzania transmisji na żywo z małym opóźnieniem ExoPlayer dostosowuje opóźnienie transmisji na żywo, lekko zmieniając prędkość odtwarzania. Odtwarzacz będzie próbował dopasować docelowe opóźnienie transmisji na żywo dostarczane przez multimedia lub aplikację, ale także spróbuje reagować na zmiany warunków sieciowych. Jeśli na przykład podczas odtwarzania wystąpi ponowne buforowanie, odtwarzacz zwolni nieco z powodu odtwarzania, aby odsunąć się od krawędzi transmisji. Jeśli sieć stanie się na tyle stabilna, że będzie można kontynuować odtwarzanie bliżej krawędzi transmisji na żywo, odtwarzacz przyspieszy odtwarzanie i wróci do docelowego przesunięcia transmisji na żywo.

Jeśli nie chcesz korzystać z automatycznej korekty szybkości odtwarzania, możesz ją wyłączyć, ustawiając właściwości minPlaybackSpeed i maxPlaybackSpeed na 1.0f. Podobnie można go włączyć w przypadku transmisji na żywo o małym czasie oczekiwania, ustawiając dla nich wartości inne niż 1.0f. Więcej informacji o ustawianiu tych właściwości znajdziesz w sekcji konfiguracji powyżej.

Dostosowywanie algorytmu korekty szybkości odtwarzania

Gdy włączona jest korekta prędkości, LivePlaybackSpeedControl określa, jakie poprawki są wprowadzane. Możesz wdrożyć niestandardowy element LivePlaybackSpeedControl lub dostosować implementację domyślną, czyli DefaultLivePlaybackSpeedControl. W obu przypadkach podczas kompilowania odtwarzacza można ustawić instancję:

Kotlin

val player =
  ExoPlayer.Builder(context)
    .setLivePlaybackSpeedControl(
      DefaultLivePlaybackSpeedControl.Builder().setFallbackMaxPlaybackSpeed(1.04f).build()
    )
    .build()

Java

ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setLivePlaybackSpeedControl(
            new DefaultLivePlaybackSpeedControl.Builder()
                .setFallbackMaxPlaybackSpeed(1.04f)
                .build())
        .build();

Istotne parametry dostosowania DefaultLivePlaybackSpeedControl:

  • fallbackMinPlaybackSpeed i fallbackMaxPlaybackSpeed: minimalna i maksymalna szybkość odtwarzania, której można użyć do korekty, jeśli ani multimedia, ani MediaItem nie określają limitów.
  • proportionalControlFactor: określa płynność regulacji szybkości. Wysoka wartość powoduje, że korekty są bardziej nagłe i reaktywne, ale z większym prawdopodobieństwem będą słyszalne. Mniejsza wartość zapewnia płynniejsze przejście między szybkościami, ale kosztem spowolnienia.
  • targetLiveOffsetIncrementOnRebufferMs: ta wartość jest dodawana do docelowego opóźnienia transmisji na żywo przy każdym ponownym buforowaniu, co pozwala zachować ostrożność. Można wyłączyć tę funkcję, ustawiając wartość na 0.
  • minPossibleLiveOffsetSmoothingFactor: współczynnik wygładzania wykładniczego używany do śledzenia minimalnego możliwego opóźnienia transmisji na podstawie aktualnie buforowanych multimediów. Wartość bardzo bliska 1 oznacza, że oszacowanie jest bardziej ostrożne i dostosowanie się do lepszych warunków sieciowych może potrwać dłużej, a mniejsza wartość oznacza, że oszacowanie zostanie skorygowane szybciej, co zwiększy ryzyko ponownego buforowania.

BehindLiveWindowWyjątek i ERROR_CODE_TEMPLATE_LIVE_WINDOW

Pozycja odtwarzania może pojawić się poza oknem transmisji na żywo, np. jeśli odtwarzacz jest wstrzymany lub buforowany na wystarczająco długo. Jeśli tak się stanie, odtwarzanie się nie uda, a wyjątek z kodem błędu ERROR_CODE_BEHIND_LIVE_WINDOW zostanie zgłoszony w usłudze Player.Listener.onPlayerError. Kod aplikacji może obsłużyć takie błędy, wznawiając odtwarzanie w pozycji domyślnej. Przykładem takich działań jest element PlayerActivity w aplikacji w wersji demonstracyjnej.

Kotlin

override fun onPlayerError(error: PlaybackException) {
  if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) {
    // Re-initialize player at the live edge.
    player.seekToDefaultPosition()
    player.prepare()
  } else {
    // Handle other errors
  }
}

Java

@Override
public void onPlayerError(PlaybackException error) {
  if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) {
    // Re-initialize player at the live edge.
    player.seekToDefaultPosition();
    player.prepare();
  } else {
    // Handle other errors
  }
}