O ExoPlayer reproduz a maioria das transmissões ao vivo adaptáveis sem nenhuma configuração especial. Consulte a página de formatos compatíveis para mais detalhes.
As transmissões ao vivo adaptáveis oferecem uma janela de mídia disponível que é atualizada em intervalos regulares para acompanhar o tempo real. Isso significa que a posição de reprodução sempre estará em algum lugar nessa janela, na maioria dos casos, perto do tempo real atual em que o stream está sendo produzido. A diferença entre a posição atual em tempo real e a posição de reprodução é chamada de deslocamento em tempo real.
Como detectar e monitorar a reprodução ao vivo
Sempre que uma janela ativa é atualizada, as instâncias de Player.Listener
registradas recebem um evento onTimelineChanged
. É possível recuperar detalhes sobre a
reprodução ao vivo atual consultando vários métodos Player
e Timeline.Window
, conforme listados abaixo e mostrados na figura a seguir.
Player.isCurrentWindowLive
indica se o item de mídia que está sendo reproduzido é uma transmissão ao vivo. Esse valor ainda é verdadeiro mesmo que a transmissão ao vivo tenha terminado.Player.isCurrentWindowDynamic
indica se o item de mídia em reprodução ainda está sendo atualizado. Isso geralmente é verdade para transmissões ao vivo que ainda não foram encerradas. Esse flag também é verdadeiro para transmissões que não são ao vivo em alguns casos.Player.getCurrentLiveOffset
retorna o deslocamento entre o tempo real atual e a posição de reprodução (se disponível).Player.getDuration
retorna a duração da janela 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 queMediaItem.liveConfiguration
contém substituições fornecidas pelo app para os parâmetros de ajuste de deslocamento ao vivo e de deslocamento ao vivo de destino.Player.getCurrentTimeline
retorna a estrutura de mídia atual em umTimeline
. OTimeline.Window
atual pode ser recuperado doTimeline
usandoPlayer.getCurrentMediaItemIndex
eTimeline.getWindow
. NoWindow
:Window.liveConfiguration
contém o deslocamento ativo de destino e os parâmetros de ajuste de deslocamento ativo. Esses valores são baseados nas informações na mídia e em todas as substituições fornecidas pelo app definidas emMediaItem.liveConfiguration
.Window.windowStartTimeMs
é o tempo desde a época do Unix em que a janela ativa começa.Window.getCurrentUnixTimeMs
é o tempo desde a época do Unix do tempo real atual. Esse valor pode ser corrigido por uma diferença de horário conhecida entre o servidor e o cliente.Window.getDefaultPositionMs
é a posição na janela ao vivo em que o player iniciará a reprodução por padrão.
Buscando em transmissões ao vivo
É possível procurar em qualquer lugar na janela ao vivo usando Player.seekTo
. A posição de busca
transmitida é relativa ao início da janela de transmissão ao vivo. Por exemplo,
seekTo(0)
vai buscar o início da janela ao vivo. O player vai tentar
manter o mesmo deslocamento ao vivo da posição procurada 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 perto da borda ativa. Para procurar
a posição padrão, chame Player.seekToDefaultPosition
.
interface de reprodução ao vivo
Os componentes de IU padrão do ExoPlayer mostram a duração da janela ativa e
a posição de reprodução atual nela. Isso significa que a posição vai parecer
voltar sempre que a janela ao vivo for atualizada. Se você precisar de um comportamento
diferente, por exemplo, mostrar o horário Unix ou o deslocamento em tempo real atual, poderá
criar uma bifurcação de PlayerControlView
e modificá-la de acordo com suas necessidades.
Como configurar parâmetros de reprodução ao vivo
O ExoPlayer usa alguns parâmetros para controlar o deslocamento da posição de reprodução da borda ao vivo e o intervalo de velocidades de reprodução que podem ser usados para ajustar esse deslocamento.
O ExoPlayer recebe valores para esses parâmetros de três lugares, em ordem decrescente de prioridade (o primeiro valor encontrado é usado):
- Valores por
MediaItem
transmitidos paraMediaItem.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 player vai tentar chegar perto desse deslocamento ao vivo durante a reprodução, se possível.minOffsetMs
: o deslocamento mínimo permitido em tempo real. Mesmo ao ajustar o deslocamento para as condições atuais de rede, o player não tentará ficar abaixo desse deslocamento durante a reprodução.maxOffsetMs
: o deslocamento em tempo real máximo permitido. Mesmo ao ajustar o deslocamento para as condições atuais da rede, o player não vai tentar ultrapassar esse deslocamento durante a reprodução.minPlaybackSpeed
: a velocidade mínima de reprodução que o player pode usar como fallback ao tentar alcançar o deslocamento ao vivo de destino.maxPlaybackSpeed
: a velocidade máxima de reprodução que o player pode usar para se atualizar ao tentar alcançar o deslocamento em tempo real desejado.
Ajuste da velocidade de reprodução
Em uma transmissão ao vivo de baixa latência, o ExoPlayer ajusta o deslocamento ao vivo mudando levemente a velocidade da reprodução. O player vai tentar corresponder ao deslocamento ao vivo de destino fornecido pela mídia ou pelo app, mas também vai tentar reagir às condições de rede em mudança. Por exemplo, se ocorrerem rebuffers durante a reprodução, o player vai desacelerar um pouco para se afastar do limite ao vivo. Se a rede se tornar estável o suficiente para permitir a reprodução mais próxima da extremidade ativa novamente, o player vai acelerar a reprodução para voltar ao deslocamento ativo de destino.
Se você não quiser usar o ajuste automático da velocidade do vídeo, defina as propriedades minPlaybackSpeed
e maxPlaybackSpeed
como 1.0f
para desativá-lo.
Da mesma forma, ele pode ser ativado para transmissões ao vivo que não têm baixa latência definindo-as
explicitamente para valores diferentes de 1.0f
. Consulte
a seção de configuração acima para
mais detalhes sobre como definir essas propriedades.
Personalizar o algoritmo de ajuste da velocidade de reprodução
Se o ajuste de velocidade estiver ativado, um LivePlaybackSpeedControl
vai definir quais
ajustes são feitos. É possível implementar um
LivePlaybackSpeedControl
personalizado ou personalizar a implementação padrão, que é
DefaultLivePlaybackSpeedControl
. Em ambos os casos, uma instância pode ser definida ao
criar o 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
efallbackMaxPlaybackSpeed
: as velocidades de reprodução mínima e máxima que podem ser usadas para ajuste se nem a mídia nem oMediaItem
fornecido pelo app definirem limites.proportionalControlFactor
: controla a fluidez do ajuste de velocidade. Um valor alto torna os ajustes mais repentinos e reativos, mas também mais propensos a ser audíveis. Um valor menor resulta em uma transição mais suave entre as velocidades, em detrimento da velocidade.targetLiveOffsetIncrementOnRebufferMs
: esse valor é adicionado ao deslocamento em tempo real de destino sempre que ocorre um buffering, para proceder com mais cautela. Esse recurso pode ser desativado definindo o valor como 0.minPossibleLiveOffsetSmoothingFactor
: um fator de suavização exponencial que é usado para rastrear o mínimo possível de deslocamento em tempo real com base na mídia armazenada em buffer no momento. Um valor muito próximo de 1 significa que a estimativa é mais cautelosa e pode levar mais tempo para se ajustar a condições de rede melhores, enquanto um valor mais baixo significa que a estimativa será ajustada mais rápido com um risco maior de encontrar rebuffers.
BehindLiveWindowException e ERROR_CODE_CAMPAIGNS_LIVE_WINDOW
A posição de reprodução pode ficar para trás na janela ativa, por exemplo, se o player
estiver pausado ou armazenado em buffer por um período longo o suficiente. Se isso acontecer,
a reprodução vai falhar e uma exceção com o código de erro
ERROR_CODE_BEHIND_LIVE_WINDOW
será informada por
Player.Listener.onPlayerError
. O código do aplicativo pode processar esses
erros retomando a reprodução na posição padrão. A PlayerActivity do
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 } }