Solução de problemas


Corrigir erros de "Tráfego HTTP em texto simples não permitido"

Esse erro vai ocorrer se o app solicitar tráfego HTTP de texto simples (ou seja, http:// em vez de https://) quando a configuração de segurança de rede não permitir isso. Se o app for destinado ao Android 9 (API de nível 28) ou mais recente, o tráfego HTTP de texto simples será desativado pela configuração padrão.

Se o app precisar funcionar com tráfego HTTP de texto não criptografado, use uma configuração de segurança de rede que permita isso. Consulte a documentação de segurança de rede do Android para mais detalhes. Para ativar todo o tráfego HTTP de texto simples, basta adicionar android:usesCleartextTraffic="true" ao elemento application do AndroidManifest.xml do app.

O app de demonstração do ExoPlayer usa a configuração de segurança de rede padrão e, portanto, não permite tráfego HTTP de texto não criptografado. Para ativar, siga as instruções acima.

Corrigir erros "SSLHandshakeException", "CertPathValidatorException" e "ERR_CERT_AUTHORITY_INVALID"

SSLHandshakeException, CertPathValidatorException e ERR_CERT_AUTHORITY_INVALID indicam um problema com o certificado SSL do servidor. Esses erros não são específicos do ExoPlayer. Consulte a documentação SSL do Android para mais detalhes.

Por que alguns arquivos de mídia não podem ser pesquisados?

Por padrão, o ExoPlayer não oferece suporte à busca em mídias em que o único método para realizar operações de busca precisas é o player verificar e indexar o arquivo inteiro. O ExoPlayer considera esses arquivos como não pesquisáveis. A maioria dos formatos de contêiner de mídia modernos inclui metadados para busca (como um índice de amostra), tem um algoritmo de busca bem definido (por exemplo, pesquisa de bisseção interpolada para Ogg) ou indica que o conteúdo tem taxa de bits constante. Operações de busca eficientes são possíveis e compatíveis com o ExoPlayer nesses casos.

Se você precisar buscar, mas tiver mídia que não pode ser buscada, sugerimos converter seu conteúdo para usar um formato de contêiner mais adequado. Para arquivos MP3, ADTS e AMR, também é possível ativar a busca supondo que os arquivos tenham uma taxa de bits constante, conforme descrito aqui.

Por que a busca é imprecisa em alguns arquivos MP3?

Arquivos MP3 com taxa de bits variável (VBR) não são adequados para casos de uso que exigem busca exata. Isso acontece por dois motivos:

  1. Para a busca exata, o ideal é que um formato de contêiner forneça um mapeamento preciso de tempo para byte em um cabeçalho. Esse mapeamento permite que um jogador mapeie um tempo de busca solicitado para o deslocamento de byte correspondente e comece a solicitar, analisar e reproduzir mídia a partir desse deslocamento. Infelizmente, os cabeçalhos disponíveis para especificar esse mapeamento em MP3 (como cabeçalhos XING) costumam ser imprecisos.
  2. Para formatos de contêiner que não fornecem um mapeamento preciso de tempo para byte (ou nenhum mapeamento de tempo para byte), ainda é possível realizar uma busca exata se o contêiner incluir carimbos de data/hora de amostra absolutos no fluxo. Nesse caso, um player pode mapear o tempo de busca para uma melhor estimativa do deslocamento de bytes correspondente, começar a solicitar mídia desse deslocamento, analisar o primeiro carimbo de data/hora absoluto da amostra e realizar uma pesquisa binária guiada na mídia até encontrar a amostra certa. Infelizmente, o MP3 não inclui carimbos de data/hora absolutos de amostra no stream. Portanto, essa abordagem não é possível.

Por esses motivos, a única maneira de fazer uma busca exata em um arquivo MP3 VBR é analisar o arquivo inteiro e criar manualmente um mapeamento de tempo para byte no player. Essa estratégia pode ser ativada usando FLAG_ENABLE_INDEX_SEEKING, que pode ser definida em um DefaultExtractorsFactory usando setMp3ExtractorFlags. Ele não é adequado para arquivos MP3 grandes, principalmente se o usuário tentar buscar perto do final da transmissão logo após iniciar a reprodução. Isso exige que o player espere até que toda a transmissão seja baixada e indexada antes de realizar a busca. No ExoPlayer, decidimos otimizar a velocidade em vez da precisão nesse caso, e FLAG_ENABLE_INDEX_SEEKING fica desativado por padrão.

Se você controla a mídia que está reproduzindo, recomendamos usar um formato de contêiner mais adequado, como MP4. Não conhecemos casos de uso em que o MP3 seja a melhor opção de formato de mídia.

Por que a busca no meu vídeo está lenta?

Quando o player busca uma nova posição de reprodução em um vídeo, ele precisa fazer duas coisas:

  1. Carregue os dados correspondentes à nova posição de reprodução no buffer. Isso pode não ser necessário se os dados já estiverem armazenados em buffer.
  2. Limpe o decodificador de vídeo e comece a decodificar do I-frame (keyframe) antes da nova posição de reprodução, devido à codificação intraframe usada pela maioria dos formatos de compactação de vídeo. Para garantir que a busca seja precisa (ou seja, a reprodução começa exatamente na posição de busca), todos os frames entre o I-frame anterior e a posição de busca precisam ser decodificados e descartados imediatamente (sem serem mostrados na tela).

A latência introduzida por (1) pode ser reduzida aumentando a quantidade de dados armazenados em buffer na memória pelo player ou armazenando em cache os dados no disco.

A latência introduzida por (2) pode ser reduzida diminuindo a precisão da busca usando ExoPlayer.setSeekParameters ou recodificando o vídeo para ter mais frames-I (o que vai resultar em um arquivo de saída maior).

Por que alguns arquivos MPEG-TS não são reproduzidos?

Alguns arquivos MPEG-TS não contêm delimitadores de unidade de acesso (AUDs). Por padrão, o ExoPlayer usa AUDs para detectar limites de frames de maneira econômica. Da mesma forma, alguns arquivos MPEG-TS não contêm keyframes IDR. Por padrão, esses são os únicos tipos de quadros-chave considerados pelo ExoPlayer.

O ExoPlayer vai parecer travado no estado de buffer quando solicitado a reproduzir um arquivo MPEG-TS sem AUDs ou keyframes IDR. Se você precisar reproduzir esses arquivos, use FLAG_DETECT_ACCESS_UNITS e FLAG_ALLOW_NON_IDR_KEYFRAMES, respectivamente. Essas flags podem ser definidas em um DefaultExtractorsFactory usando setTsExtractorFlags ou em um DefaultHlsExtractorFactory usando o constructor. O uso de FLAG_DETECT_ACCESS_UNITS não tem efeitos colaterais além de ser computacionalmente caro em relação à detecção de limites de frames com base em AUD. O uso de FLAG_ALLOW_NON_IDR_KEYFRAMES pode resultar em corrupção visual temporária no início da reprodução e imediatamente após buscas ao reproduzir alguns arquivos MPEG-TS.

Por que as legendas não são encontradas em alguns arquivos MPEG-TS?

Alguns arquivos MPEG-TS incluem faixas CEA-608, mas não as declaram nos metadados do contêiner. Por isso, o ExoPlayer não consegue detectá-las. É possível especificar manualmente as faixas de legenda fornecendo uma lista de formatos de legenda esperados para o DefaultExtractorsFactory, incluindo os canais de acessibilidade que podem ser usados para identificá-los no stream MPEG-TS:

Kotlin

val extractorsFactory =
  DefaultExtractorsFactory()
    .setTsSubtitleFormats(
      listOf(
        Format.Builder()
          .setSampleMimeType(MimeTypes.APPLICATION_CEA608)
          .setAccessibilityChannel(accessibilityChannel)
          // Set other subtitle format info, such as language.
          .build()
      )
    )
val player: Player =
  ExoPlayer.Builder(context, DefaultMediaSourceFactory(context, extractorsFactory)).build()

Java

DefaultExtractorsFactory extractorsFactory =
    new DefaultExtractorsFactory()
        .setTsSubtitleFormats(
            ImmutableList.of(
                new Format.Builder()
                    .setSampleMimeType(MimeTypes.APPLICATION_CEA608)
                    .setAccessibilityChannel(accessibilityChannel)
                    // Set other subtitle format info, such as language.
                    .build()));
Player player =
    new ExoPlayer.Builder(context, new DefaultMediaSourceFactory(context, extractorsFactory))
        .build();

Por que alguns arquivos MP4/FMP4 são reproduzidos incorretamente?

Alguns arquivos MP4/FMP4 contêm listas de edição que reescrevem a linha do tempo da mídia pulando, movendo ou repetindo listas de amostras. O ExoPlayer tem suporte parcial para aplicar listas de edição. Por exemplo, ele pode atrasar ou repetir grupos de amostras a partir de uma amostra de sincronização, mas não trunca amostras de áudio nem mídia de pré-roll para edições que não começam em uma amostra de sincronização.

Se você notar que parte da mídia está faltando ou repetida inesperadamente, tente definir Mp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS ou FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS, o que fará com que o extrator ignore completamente as listas de edição. Eles podem ser definidos em um DefaultExtractorsFactory usando setMp4ExtractorFlags ou setFragmentedMp4ExtractorFlags.

Por que alguns fluxos falham com o código de resposta HTTP 301 ou 302?

Os códigos de resposta HTTP 301 e 302 indicam redirecionamento. Breves descrições podem ser encontradas na Wikipédia. Quando o ExoPlayer faz uma solicitação e recebe uma resposta com o código de status 301 ou 302, ele normalmente segue o redirecionamento e inicia a reprodução normalmente. O único caso em que isso não acontece por padrão é para redirecionamentos entre protocolos. Um redirecionamento entre protocolos é aquele que redireciona de HTTPS para HTTP ou vice-versa (ou, menos comumente, entre outro par de protocolos). Para testar se um URL causa um redirecionamento entre protocolos, use a ferramenta de linha de comando wget da seguinte maneira:

wget "https://yourserver.example.com/test.mp3" 2>&1  | grep Location

A resposta será semelhante a esta:

Location: https://secondserver.example.net/test.mp3 [following]
Location: http://thirdserver.example.org/test.mp3 [following]

Neste exemplo, há dois redirecionamentos. O primeiro redirecionamento é de https://yourserver.example.com/test.mp3 para https://secondserver.example.net/test.mp3. Ambos são HTTPS, então não é um redirecionamento entre protocolos. O segundo redirecionamento é de https://secondserver.example.net/test.mp3 para http://thirdserver.example.org/test.mp3. Isso redireciona de HTTPS para HTTP e, portanto, é um redirecionamento entre protocolos. O ExoPlayer não vai seguir esse redirecionamento na configuração padrão, o que significa que a reprodução vai falhar.

Se necessário, configure o ExoPlayer para seguir redirecionamentos entre protocolos ao instanciar DefaultHttpDataSource.Factory usadas no seu aplicativo. Saiba como selecionar e configurar a pilha de rede aqui.

Por que algumas transmissões falham com UnrecognizedInputFormatException?

Esta pergunta se refere a falhas de reprodução do seguinte tipo:

UnrecognizedInputFormatException: None of the available extractors
(MatroskaExtractor, FragmentedMp4Extractor, ...) could read the stream.

Há duas causas possíveis para essa falha. A causa mais comum é que você está tentando reproduzir conteúdo DASH (mpd), HLS (m3u8) ou SmoothStreaming (ism, isml), mas o player tenta reproduzir como um stream progressivo. Para reproduzir esses streams, você precisa depender do módulo do ExoPlayer correspondente. Nos casos em que o URI do stream não termina com a extensão de arquivo padrão, também é possível transmitir MimeTypes.APPLICATION_MPD, MimeTypes.APPLICATION_M3U8 ou MimeTypes.APPLICATION_SS para setMimeType de MediaItem.Builder para especificar explicitamente o tipo de stream.

O segundo motivo, menos comum, é que o ExoPlayer não é compatível com o formato do contêiner da mídia que você está tentando reproduzir. Nesse caso, a falha está funcionando conforme o esperado. No entanto, envie uma solicitação de recurso para nosso rastreador de problemas, incluindo detalhes do formato do contêiner e um fluxo de teste. Pesquise uma solicitação de recurso existente antes de enviar uma nova.

Por que o setPlaybackParameters não funciona corretamente em alguns dispositivos?

Ao executar um build de depuração do app no Android M e em versões anteriores, você pode ter um desempenho instável, artefatos audíveis e alta utilização da CPU ao usar a API setPlaybackParameters. Isso acontece porque uma otimização importante para essa API é desativada em builds de depuração executados nessas versões do Android.

É importante observar que esse problema afeta apenas builds de depuração. Ele não afeta builds de lançamento, em que a otimização está sempre ativada. Portanto, as versões que você fornece aos usuários finais não serão afetadas por esse problema.

O que significam os erros "Player is accessed on the wrong thread"?

Consulte Uma observação sobre threading na página de primeiros passos.

Como corrigir "Linha de status inesperada: ICY 200 OK"?

Esse problema pode ocorrer se a resposta do servidor incluir uma linha de status ICY, em vez de uma compatível com HTTP. As linhas de status ICY estão descontinuadas e não devem ser usadas. Portanto, se você controla o servidor, atualize-o para fornecer uma resposta compatível com HTTP. Se não for possível fazer isso, use a biblioteca ExoPlayer OkHttp para resolver o problema, já que ela consegue processar linhas de status ICY corretamente.

Como posso consultar se a transmissão em reprodução é ao vivo?

É possível consultar o método isCurrentWindowLive do player. Além disso, você pode verificar isCurrentWindowDynamic para saber se a janela é dinâmica (ou seja, ainda está sendo atualizada com o tempo).

Como faço para manter o áudio tocando quando meu app está em segundo plano?

Siga estas etapas para garantir a reprodução contínua de áudio quando o app estiver em segundo plano:

  1. Você precisa ter um serviço em primeiro plano em execução. Isso evita que o sistema encerre seu processo para liberar recursos.
  2. Você precisa ter um WifiLock e um WakeLock. Isso garante que o sistema mantenha o rádio Wi-Fi e a CPU ativos. Isso pode ser feito facilmente se você usar ExoPlayer chamando setWakeMode, que vai adquirir e liberar automaticamente os bloqueios necessários nos momentos certos.

É importante liberar os bloqueios (se não estiver usando setWakeMode) e interromper o serviço assim que o áudio não estiver mais sendo reproduzido.

Por que o ExoPlayer é compatível com meu conteúdo, mas a biblioteca ExoPlayer Cast não?

É possível que o conteúdo que você está tentando reproduzir não esteja ativado para CORS. A estrutura do Cast exige que o conteúdo seja compatível com CORS para ser reproduzido.

Por que o conteúdo não é reproduzido, mas nenhum erro aparece?

É possível que o dispositivo em que você está reproduzindo o conteúdo não seja compatível com um formato específico de amostra de mídia. Para confirmar isso, adicione um EventLogger como listener ao player e procure uma linha semelhante a esta no Logcat:

[ ] Track:x, id=x, mimeType=mime/type, ... , supported=NO_UNSUPPORTED_TYPE

NO_UNSUPPORTED_TYPE significa que o dispositivo não consegue decodificar o formato de amostra de mídia especificado pelo mimeType. Consulte a documentação de formatos de mídia do Android para informações sobre formatos de amostra compatíveis. Como posso conseguir uma biblioteca de decodificação para carregar e ser usada na reprodução? também pode ser útil.

Como posso carregar e usar uma biblioteca de decodificação para reprodução?

  • A maioria das bibliotecas de decodificador tem etapas manuais para fazer o check-out e criar as dependências. Portanto, siga as etapas no README da biblioteca relevante. Por exemplo, para a biblioteca FFmpeg do ExoPlayer, é necessário seguir as instruções em libraries/decoder_ffmpeg/README.md, incluindo a transmissão de flags de configuração para ativar decodificadores em todos os formatos que você quer reproduzir.
  • Para bibliotecas com código nativo, verifique se você está usando a versão correta do Android NDK, conforme especificado no README, e procure erros que apareçam durante a configuração e a criação. Depois de seguir as etapas no README, você vai ver arquivos .so aparecerem no subdiretório libs do caminho da biblioteca para cada arquitetura compatível.
  • Para testar a reprodução usando a biblioteca no aplicativo de demonstração, consulte como ativar decodificadores agrupados. Consulte o README da biblioteca para instruções sobre como usar a biblioteca no seu próprio app.
  • Se você estiver usando DefaultRenderersFactory, uma linha de registro em nível de informação como "Loaded FfmpegAudioRenderer" vai aparecer no Logcat quando o decodificador for carregado. Se estiver faltando, verifique se o aplicativo tem uma dependência da biblioteca de decodificação.
  • Se você encontrar registros no nível de aviso de LibraryLoader no Logcat, isso indica que o carregamento do componente nativo da biblioteca falhou. Se isso acontecer, verifique se você seguiu as etapas no README da biblioteca corretamente e se não houve erros ao seguir as instruções.

Se você ainda estiver com problemas ao usar bibliotecas de decodificação, consulte o rastreador de problemas do Media3 para ver se há problemas relevantes recentes. Se você precisar registrar um novo problema relacionado à criação da parte nativa da biblioteca, inclua a saída completa da linha de comando ao executar as instruções do README para nos ajudar a diagnosticar o problema.

Posso reproduzir vídeos do YouTube diretamente com o ExoPlayer?

Não, o ExoPlayer não pode reproduzir vídeos do YouTube, como URLs do formato https://www.youtube.com/watch?v=.... Em vez disso, use a API YouTube IFrame Player, que é a maneira oficial de reproduzir vídeos do YouTube no Android.

A reprodução de vídeo está travando

Por exemplo, se a taxa de bits ou a resolução do conteúdo excederem as capacidades do dispositivo, ele não poderá decodificar o conteúdo com rapidez suficiente. Talvez seja necessário usar conteúdo de qualidade inferior para ter um bom desempenho nesses dispositivos.

Se você estiver enfrentando problemas de travamento de vídeo em um dispositivo com uma versão do Android do Android 6.0 (nível da API 23) até o Android 11 (nível da API 30), principalmente ao reproduzir conteúdo protegido por DRM ou com alta taxa de frames, tente ativar o enfileiramento assíncrono de buffers.

Erros de lint de API instáveis

O Media3 garante a compatibilidade binária para um subconjunto da plataforma de API. As partes que não garantem a compatibilidade binária são marcadas com @UnstableApi. Para deixar essa distinção clara, os usos de símbolos de API instáveis geram um erro de lint, a menos que sejam anotados com @OptIn.

A anotação @UnstableApi não implica nada sobre a qualidade ou o desempenho de uma API, apenas o fato de que ela não está "congelada".

Você tem duas opções para lidar com erros instáveis de lint da API:

  • Mude para uma API estável que tenha o mesmo resultado.
  • Continue usando a API instável e anote o uso com @OptIn, conforme mostrado mais adiante.
Adicione a anotação @OptIn.

O Android Studio pode ajudar você a adicionar a anotação:

Captura de tela: como adicionar a anotação "Optin"
Figura 2: como adicionar uma anotação @androidx.annotations.OptIn com o Android Studio.

Também é possível anotar manualmente sites de uso específicos em Kotlin:

import androidx.annotation.OptIn
import androidx.media3.common.util.UnstableApi

@OptIn(UnstableApi::class)
fun functionUsingUnstableApi() { ... }

E também em Java:

import androidx.annotation.OptIn;
import androidx.media3.common.util.UnstableApi;

@OptIn(markerClass = UnstableApi.class)
private void methodUsingUnstableApis() { ... }

Para ativar pacotes inteiros, adicione um arquivo package-info.java:

@OptIn(markerClass = UnstableApi.class)
package name.of.your.package;

import androidx.annotation.OptIn;
import androidx.media3.common.util.UnstableApi;

Para ativar projetos inteiros, suprima o erro específico do lint no arquivo lint.xml:

 <?xml version="1.0" encoding="utf-8"?>
 <lint>
   <issue id="UnsafeOptInUsageError">
     <option name="opt-in" value="androidx.media3.common.util.UnstableApi" />
   </issue>
 </lint>

Há também uma anotação kotlin.OptIn que não deve ser usada. É importante usar a anotação androidx.annotation.OptIn.