Live streaming

ExoPlayer riproduce la maggior parte dei live streaming adattivi senza alcuna configurazione speciale. Per maggiori dettagli, consulta la pagina Formati supportati.

I live streaming adattivi offrono una finestra di contenuti multimediali disponibili che viene aggiornata a intervalli regolari per seguire l'andamento in tempo reale. Ciò significa che la posizione di riproduzione sarà sempre all'interno di questa finestra, nella maggior parte dei casi vicino al tempo reale attuale in cui viene prodotto lo stream. La differenza tra la posizione di riproduzione e la posizione in tempo reale attuale è chiamata offset live.

Rilevare e monitorare le riproduzioni live

Ogni volta che una finestra live viene aggiornata, le istanze Player.Listener registrate riceveranno un evento onTimelineChanged. Puoi recuperare i dettagli sulla riproduzione live corrente eseguendo query su vari metodi Player e Timeline.Window, come elencato di seguito e mostrato nella figura seguente.

Finestra live

  • Player.isCurrentWindowLive indica se l'elemento multimediale attualmente in riproduzione è un live streaming. Questo valore è ancora valido anche se il live streaming è terminato.
  • Player.isCurrentWindowDynamic indica se l'elemento multimediale attualmente in riproduzione è ancora in fase di aggiornamento. Questo vale in genere per i live streaming che non sono ancora terminati. Tieni presente che questo flag è vero anche per i contenuti non in live streaming in alcuni casi.
  • Player.getCurrentLiveOffset restituisce l'offset tra l'ora in tempo reale corrente e la posizione di riproduzione (se disponibile).
  • Player.getDuration restituisce la durata della finestra live corrente.
  • Player.getCurrentPosition restituisce la posizione di riproduzione relativa all'inizio della finestra live.
  • Player.getCurrentMediaItem restituisce l'elemento multimediale corrente, dove MediaItem.liveConfiguration contiene gli override forniti dall'app per i parametri di offset live e di aggiustamento dell'offset live di destinazione.
  • Player.getCurrentTimeline restituisce la struttura dei media corrente in un Timeline. L'Timeline.Window corrente può essere recuperato da Timeline utilizzando Player.getCurrentMediaItemIndex e Timeline.getWindow. All'interno di Window:
    • Window.liveConfiguration contiene i parametri di offset live di destinazione e di aggiustamento dell'offset live. Questi valori si basano sulle informazioni nei contenuti multimediali e su eventuali override forniti dall'app impostati in MediaItem.liveConfiguration.
    • Window.windowStartTimeMs è il tempo trascorso dall'epoca Unix in cui inizia la finestra live.
    • Window.getCurrentUnixTimeMs è il tempo trascorso dall'epoca Unix dell'ora in tempo reale corrente. Questo valore può essere corretto in base a una differenza di orologio nota tra il server e il client.
    • Window.getDefaultPositionMs è la posizione nella finestra live in cui il player avvierà la riproduzione per impostazione predefinita.

Ricerca nei live streaming

Puoi spostarti in qualsiasi punto della finestra live utilizzando Player.seekTo. La posizione di ricerca passata è relativa all'inizio della finestra live. Ad esempio, seekTo(0) andrà all'inizio della finestra live. Il player tenterà di mantenere lo stesso offset live della posizione raggiunta dopo una ricerca.

La finestra live ha anche una posizione predefinita in cui la riproduzione dovrebbe iniziare. Questa posizione si trova di solito vicino al bordo vivo. Puoi tornare alla posizione predefinita chiamando il numero Player.seekToDefaultPosition.

UI di riproduzione live

I componenti UI predefiniti di ExoPlayer mostrano la durata della finestra live e la posizione di riproduzione corrente al suo interno. Ciò significa che la posizione sembrerà saltare indietro ogni volta che la finestra live viene aggiornata. Se hai bisogno di un comportamento diverso, ad esempio mostrare l'ora Unix o l'offset live corrente, puoi creare un fork di PlayerControlView e modificarlo in base alle tue esigenze.

Configurazione dei parametri di riproduzione live

ExoPlayer utilizza alcuni parametri per controllare l'offset della posizione di riproduzione dal bordo live e l'intervallo di velocità di riproduzione che possono essere utilizzati per regolare questo offset.

ExoPlayer ottiene i valori di questi parametri da tre posizioni, in ordine di priorità decrescente (viene utilizzato il primo valore trovato):

  • Per MediaItem valori passati a MediaItem.Builder.setLiveConfiguration.
  • Valori predefiniti globali impostati il giorno DefaultMediaSourceFactory.
  • Valori letti direttamente dai contenuti multimediali.

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);

I valori di configurazione disponibili sono:

  • targetOffsetMs: L'offset live di destinazione. Il player tenterà di avvicinarsi a questo offset live durante la riproduzione, se possibile.
  • minOffsetMs: l'offset live minimo consentito. Anche quando si regola l'offset in base alle condizioni di rete attuali, il player non tenterà di scendere al di sotto di questo offset durante la riproduzione.
  • maxOffsetMs: l'offset live massimo consentito. Anche quando si regola l'offset in base alle condizioni di rete attuali, il player non tenterà di superare questo offset durante la riproduzione.
  • minPlaybackSpeed: la velocità di riproduzione minima che il player può utilizzare come fallback quando tenta di raggiungere l'offset live di destinazione.
  • maxPlaybackSpeed: la velocità di riproduzione massima che il player può utilizzare per recuperare quando tenta di raggiungere l'offset live target.

Regolazione della velocità di riproduzione

Quando riproduce un live streaming a bassa latenza, ExoPlayer regola l'offset live modificando leggermente la velocità di riproduzione. Il player tenterà di abbinare l'offset live di destinazione fornito dai contenuti multimediali o dall'app, ma cercherà anche di reagire alle condizioni di rete variabili. Ad esempio, se si verificano ribuffer durante la riproduzione, il player rallenterà leggermente la riproduzione per allontanarsi ulteriormente dal bordo live. Se la rete diventa di nuovo sufficientemente stabile per supportare la riproduzione più vicina al bordo live, il player velocizzerà la riproduzione per tornare verso l'offset live di destinazione.

Se non vuoi la regolazione automatica della velocità di riproduzione, puoi disattivarla impostando le proprietà minPlaybackSpeed e maxPlaybackSpeed su 1.0f. Analogamente, può essere abilitato per i live streaming non a bassa latenza impostando questi valori in modo esplicito su valori diversi da 1.0f. Per maggiori dettagli su come impostare queste proprietà, consulta la sezione di configurazione precedente.

Personalizzare l'algoritmo di regolazione della velocità di riproduzione

Se la regolazione della velocità è attivata, un LivePlaybackSpeedControl definisce quali regolazioni vengono apportate. È possibile implementare un LivePlaybackSpeedControl personalizzato o personalizzare l'implementazione predefinita, ovvero DefaultLivePlaybackSpeedControl. In entrambi i casi, è possibile impostare un'istanza durante la creazione del giocatore:

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();

I parametri di personalizzazione pertinenti di DefaultLivePlaybackSpeedControl sono:

  • fallbackMinPlaybackSpeed e fallbackMaxPlaybackSpeed: la velocità di riproduzione minima e massima che può essere utilizzata per la regolazione se né i contenuti multimediali né l'app fornita MediaItem definiscono limiti.
  • proportionalControlFactor: controlla la fluidità della regolazione della velocità. Un valore elevato rende le regolazioni più improvvise e reattive, ma anche più probabile che siano udibili. Un valore più basso comporta una transizione più fluida tra le velocità, a discapito della velocità.
  • targetLiveOffsetIncrementOnRebufferMs: questo valore viene aggiunto all'offset live di destinazione ogni volta che si verifica un rebuffer, per procedere con maggiore cautela. Questa funzionalità può essere disattivata impostando il valore su 0.
  • minPossibleLiveOffsetSmoothingFactor: un fattore di livellamento esponenziale utilizzato per monitorare l'offset live minimo possibile in base ai contenuti multimediali attualmente memorizzati nel buffer. Un valore molto vicino a 1 indica che la stima è più cauta e potrebbe richiedere più tempo per adattarsi alle migliori condizioni di rete, mentre un valore più basso indica che la stima si adatterà più rapidamente con un rischio maggiore di incorrere in ribuffer.

BehindLiveWindowException e ERROR_CODE_BEHIND_LIVE_WINDOW

La posizione di riproduzione potrebbe rimanere indietro rispetto alla finestra live, ad esempio se il player è in pausa o in buffering per un periodo di tempo sufficientemente lungo. In questo caso, la riproduzione non andrà a buon fine e verrà segnalata un'eccezione con il codice di errore ERROR_CODE_BEHIND_LIVE_WINDOW tramite Player.Listener.onPlayerError. Il codice dell'applicazione potrebbe voler gestire questi errori riprendendo la riproduzione dalla posizione predefinita. L'attività del giocatore dell'app demo esemplifica questo approccio.

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
  }
}