Transmissão ao vivo

O ExoPlayer reproduz a maioria das transmissões ao vivo adaptáveis imediatamente, sem nenhum configuração do Terraform. Consulte a página Formatos compatíveis para mais detalhes.

As transmissões ao vivo adaptáveis oferecem uma janela de mídia disponível que é atualizada intervalos regulares para acompanhar o tempo real atual. Isso significa que a reprodução posição sempre estará em algum lugar nesta janela, na maioria dos casos próximo ao no momento em que o stream é produzido. A diferença entre o tempo real atual e a posição da reprodução são chamadas de compensação ao vivo.

Como detectar e monitorar reproduções ao vivo

Sempre que uma janela ativa for atualizada, instâncias de Player.Listener registradas vai receber um evento onTimelineChanged. Você pode recuperar detalhes sobre o a reprodução ao vivo atual consultando vários Player e Timeline.Window métodos, como listado abaixo e mostrado na figura a seguir.

Janela ativa

  • Player.isCurrentWindowLive indica se a mídia em reprodução no momento é uma transmissão ao vivo. Esse valor ainda será verdadeiro mesmo se a transmissão ao vivo tiver acabou.
  • Player.isCurrentWindowDynamic indica se a mídia em reprodução no momento o item ainda está sendo atualizado. Isso geralmente é verdade para transmissões ao vivo que são ainda não terminou. Esse sinalizador também é válido para transmissões que não são ao vivo em alguns casos de uso diferentes.
  • Player.getCurrentLiveOffset retorna o deslocamento entre o real atual. tempo de reprodução e a posição da reprodução (se disponível).
  • Player.getDuration retorna a duração da janela ativa atual.
  • Player.getCurrentPosition retorna a posição de reprodução em relação ao início da janela ativa.
  • Player.getCurrentMediaItem retorna o item de mídia atual, em que MediaItem.liveConfiguration contém substituições fornecidas pelo app para o destino parâmetros de ajuste de deslocamento ao vivo e de ajuste em tempo real.
  • Player.getCurrentTimeline retorna a estrutura de mídia atual em uma Timeline. O Timeline.Window atual pode ser recuperado do Timeline. usando Player.getCurrentWindowIndex e Timeline.getWindow. Dentro do Window:
    • Window.liveConfiguration contém o deslocamento em tempo real desejado e o deslocamento em tempo real parâmetros de ajuste. Esses valores são baseados nas informações da mídia e todas as substituições fornecidas pelo app definidas em MediaItem.liveConfiguration.
    • Window.windowStartTimeMs é o horário desde a Era Unix em que o a janela ativa é iniciada.
    • Window.getCurrentUnixTimeMs é a hora desde a Era Unix da em tempo real. Este valor pode ser corrigido por uma diferença conhecida no relógio entre o servidor e o cliente.
    • Window.getDefaultPositionMs é a posição na janela ativa em que o player iniciará a reprodução por padrão.

Buscando em transmissões ao vivo

Você pode procurar qualquer lugar dentro da janela ao vivo usando Player.seekTo. A busca a posição transmitida é relativa ao início da janela ativa. Por exemplo: seekTo(0) vai buscar o início da janela ativa. O jogador tentará manter o mesmo deslocamento em tempo real da posição buscada após uma busca.

A janela ao vivo também tem uma posição padrão em que a reprodução precisa começar. Essa posição geralmente fica próxima à borda ativa. Você pode procurar para a posição padrão chamando Player.seekToDefaultPosition.

interface de reprodução ao vivo

Os componentes de interface padrão do ExoPlayer mostram a duração da janela ativa e a posição de reprodução atual dentro dele. Isso significa que a posição aparecerá voltar sempre que a janela ao vivo for atualizada. Se você precisar de por exemplo, mostrando o horário Unix ou o deslocamento atual, será possível bifurcar PlayerControlView e modificá-la para atender às suas necessidades.

Como configurar parâmetros de reprodução ao vivo

O ExoPlayer usa alguns parâmetros para controlar o deslocamento da posição da reprodução. da borda ao vivo e a faixa de velocidades de reprodução que pode ser usada para ajustar esse deslocamento.

O ExoPlayer recebe valores para esses parâmetros de três lugares, em ordem decrescente Ordem de prioridade (o primeiro valor encontrado é usado):

  • De acordo com os valores MediaItem transmitidos para MediaItem.Builder.setLiveConfiguration.
  • Valores padrão globais definidos em DefaultMediaSourceFactory.
  • Valores lidos diretamente da mídia.

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

Os valores de configuração disponíveis são:

  • targetOffsetMs: o deslocamento desejado em tempo real. O jogador tentará obter próximo a esse deslocamento ao vivo durante a reprodução, se possível.
  • minOffsetMs: o deslocamento mínimo permitido em tempo real. Mesmo ao ajustar para as condições atuais da rede, o player não tentará ficar abaixo esse deslocamento durante a reprodução.
  • maxOffsetMs: o deslocamento máximo permitido em tempo real. Mesmo ao ajustar para as condições atuais da rede, o player não tentará passar esse deslocamento durante a reprodução.
  • minPlaybackSpeed: a velocidade mínima de reprodução que o player pode usar para reverter. ao tentar alcançar o deslocamento desejado em tempo real.
  • maxPlaybackSpeed: a velocidade máxima de reprodução que o player pode usar para atingir a velocidade máxima ao tentar alcançar o deslocamento desejado em tempo real.

Ajuste da velocidade do vídeo

Em uma transmissão ao vivo de baixa latência, o ExoPlayer ajusta o deslocamento ao vivo pela mudando levemente a velocidade do vídeo. O jogador tentará fazer a correspondência com o alvo deslocamento em tempo real fornecido pela mídia ou pelo app, mas também tentará reagir ao as condições de rede. Por exemplo, se o buffer ocorrer durante a reprodução, o player diminuirá um pouco a velocidade da reprodução para se afastar da transmissão ao vivo borda Se a rede se tornar estável o suficiente para permitir a reprodução perto do ao vivo novamente, o player acelerará a reprodução para voltar à deslocamento desejado em tempo real.

Se o ajuste automático da velocidade do vídeo não for desejado, ele pode ser desativado definindo as propriedades minPlaybackSpeed e maxPlaybackSpeed como 1.0f. Da mesma forma, ele pode ser ativado para transmissões ao vivo de baixa latência. Para isso, configure esses explicitamente a valores diferentes de 1.0f. Consulte seção de configuração acima para mais detalhes sobre como essas propriedades podem ser definidas.

Como personalizar o algoritmo de ajuste da velocidade de reprodução

Se o ajuste de velocidade estiver ativado, uma LivePlaybackSpeedControl definirá o que ajustes são feitos. É possível implementar um modelo LivePlaybackSpeedControl ou para personalizar a implementação padrão, que é DefaultLivePlaybackSpeedControl. Em ambos os casos, é possível definir uma instância a criação do player:

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

Os parâmetros de personalização relevantes de DefaultLivePlaybackSpeedControl são:

  • fallbackMinPlaybackSpeed e fallbackMaxPlaybackSpeed: os valores mínimos e as velocidades máximas de reprodução que podem ser usadas para ajuste se nem a mídia nem a MediaItem fornecida pelo app definem os limites.
  • proportionalControlFactor: controla a fluidez do ajuste de velocidade. Um com alto valor torna os ajustes mais repentinos e reativos, mas também mais propensos ser audível. Um valor menor resulta em uma transição mais suave entre velocidades, mas acabam ficando mais lentas.
  • targetLiveOffsetIncrementOnRebufferMs: este valor é adicionado ao destino deslocamento ao vivo sempre que ocorrer um buffering, para proceder com mais cautela. Para desativar esse recurso, defina o valor como 0.
  • minPossibleLiveOffsetSmoothingFactor: um fator de suavização exponencial que é usado para rastrear o mínimo possível de deslocamento ao vivo com base no mídia em buffer. Um valor muito próximo de 1 significa que a estimativa é mais cautelosa e pode levar mais tempo para se ajustar às condições de rede aprimoradas, enquanto um valor menor significa que a estimativa se ajustará mais rapidamente, com um risco maior de em execução em buffer.

BehindLiveWindowException e ERROR_CODE_CAMPAIGNS_LIVE_WINDOW

A posição de reprodução pode ficar atrás da janela ao vivo, por exemplo, se o player estiver pausada ou armazenando em buffer por um período suficiente. Se isso acontecer, a reprodução falhará e uma exceção com código de erro ERROR_CODE_BEHIND_LIVE_WINDOW será informado por meio de Player.Listener.onPlayerError. O código do aplicativo pode querer processar retomando a reprodução na posição padrão. A PlayerActivity do o app de demonstração exemplifica essa abordagem.

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