Risoluzione dei problemi


Correggere gli errori "Traffico HTTP in testo non consentito"

Questo errore si verifica se la tua app richiede traffico HTTP in testo non criptato (ovvero, http:// anziché https://) quando la configurazione della sicurezza di rete non lo consente. Se la tua app ha come target Android 9 (livello API 28) o versioni successive, il traffico HTTP in testo non crittografato è disattivato dalla configurazione predefinita.

Se la tua app deve funzionare con il traffico HTTP in testo non crittografato, devi utilizzare una configurazione della sicurezza di rete che lo consenta. Per maggiori dettagli, consulta la documentazione sulla sicurezza di rete di Android. Per attivare tutto il traffico HTTP in testo non criptato, puoi semplicemente aggiungere android:usesCleartextTraffic="true" all'elemento application del file AndroidManifest.xml della tua app.

L'app demo ExoPlayer utilizza la configurazione della sicurezza di rete predefinita, pertanto non consente il traffico HTTP in testo non criptato. Puoi abilitarlo seguendo le istruzioni riportate sopra.

Correzione degli errori "SSLHandshakeException", "CertPathValidatorException" e "ERR_CERT_AUTHORITY_INVALID"

SSLHandshakeException, CertPathValidatorException e ERR_CERT_AUTHORITY_INVALID indicano tutti un problema con il certificato SSL del server. Questi errori non sono specifici di ExoPlayer. Per ulteriori dettagli, consulta la documentazione SSL di Android.

Perché alcuni file multimediali non sono ricercabili?

Per impostazione predefinita, ExoPlayer non supporta la ricerca nei contenuti multimediali in cui l'unico metodo per eseguire operazioni di ricerca accurate è la scansione e l'indicizzazione dell'intero file. ExoPlayer considera questi file come non ricercabili. La maggior parte dei formati contenitori multimediali moderni include metadati per la ricerca (ad esempio un indice di esempio), dispone di un algoritmo di ricerca ben definito (ad esempio, la ricerca di bisezione interpolata per Ogg) o indica che i contenuti hanno un bitrate costante. In questi casi, ExoPlayer supporta e consente operazioni di ricerca efficienti.

Se hai bisogno di cercare ma hai contenuti multimediali non ricercabili, ti consigliamo di convertire i tuoi contenuti in modo che utilizzino un formato contenitore più appropriato. Per i file MP3, ADTS e AMR, puoi anche attivare la ricerca presupponendo che i file abbiano un bitrate costante, come descritto qui.

Perché la ricerca è imprecisa in alcuni file MP3?

I file MP3 a velocità in bit variabile (VBR) non sono adatti ai casi d'uso che richiedono una ricerca esatta. Ciò può accadere per due motivi:

  1. Per la ricerca esatta, un formato contenitore dovrebbe idealmente fornire una mappatura precisa del tempo in byte in un'intestazione. Questa mappatura consente a un giocatore di mappare un tempo di ricerca richiesto all'offset di byte corrispondente e iniziare a richiedere, analizzare e riprodurre i contenuti multimediali da quell'offset. Le intestazioni disponibili per specificare questa mappatura in MP3 (ad esempio le intestazioni XING) sono, purtroppo, spesso imprecise.
  2. Per i formati contenitore che non forniscono una mappatura precisa del tempo al byte (o nessuna mappatura del tempo al byte), è comunque possibile eseguire una ricerca esatta se il contenitore include timestamp di campioni assoluti nel flusso. In questo caso, un player può mappare il tempo di ricerca a una stima approssimativa dell'offset di byte corrispondente, iniziare a richiedere i contenuti multimediali da quell'offset, analizzare il primo timestamp di esempio assoluto ed eseguire in modo efficace una ricerca binaria guidata nei contenuti multimediali finché non trova il campione giusto. Purtroppo l'MP3 non include timestamp assoluti dei campioni nel flusso, quindi questo approccio non è possibile.

Per questi motivi, l'unico modo per eseguire una ricerca esatta in un file MP3 VBR è scansionare l'intero file e creare manualmente una mappatura tempo-byte nel player. Questa strategia può essere attivata utilizzando FLAG_ENABLE_INDEX_SEEKING, che può essere impostato su un DefaultExtractorsFactory utilizzando setMp3ExtractorFlags. Tieni presente che non è scalabile per file MP3 di grandi dimensioni, soprattutto se l'utente tenta di spostarsi verso la fine dello stream poco dopo aver iniziato la riproduzione, il che richiede al player di attendere il download e l'indicizzazione dell'intero stream prima di eseguire la ricerca. In ExoPlayer, abbiamo deciso di dare la priorità alla velocità rispetto all'accuratezza in questo caso e FLAG_ENABLE_INDEX_SEEKING è pertanto disattivato per impostazione predefinita.

Se controlli i contenuti multimediali che riproduci, ti consigliamo vivamente di utilizzare un formato contenitore più appropriato, ad esempio MP4. Non siamo a conoscenza di casi d'uso in cui l'MP3 sia la scelta migliore per il formato multimediale.

Perché la riproduzione del mio video è lenta?

Quando il player cerca una nuova posizione di riproduzione in un video, deve fare due cose:

  1. Carica nel buffer i dati corrispondenti alla nuova posizione di riproduzione (potrebbe non essere necessario se questi dati sono già memorizzati nel buffer).
  2. Svuota il decodificatore video e inizia la decodifica dal frame I (keyframe) prima della nuova posizione di riproduzione, a causa della codifica intraframe utilizzata dalla maggior parte dei formati di compressione video. Per garantire che la ricerca sia accurata (ovvero, la riproduzione inizia esattamente nella posizione di ricerca), tutti i fotogrammi tra il fotogramma I precedente e la posizione di ricerca devono essere decodificati e immediatamente eliminati (senza essere mostrati sullo schermo).

La latenza introdotta da (1) può essere ridotta aumentando la quantità di dati memorizzati nel buffer della memoria dal player o memorizzando preventivamente i dati su disco.

La latenza introdotta da (2) può essere ridotta diminuendo l'accuratezza della ricerca utilizzando ExoPlayer.setSeekParameters o ricodificando il video in modo che abbia I-frame più frequenti (il che comporterà un file di output più grande).

Perché alcuni file MPEG-TS non vengono riprodotti?

Alcuni file MPEG-TS non contengono delimitatori di unità di accesso (AUD). Per impostazione predefinita, ExoPlayer si basa sulle unità di accesso (AU) per rilevare a basso costo i limiti dei frame. Allo stesso modo, alcuni file MPEG-TS non contengono keyframe IDR. Per impostazione predefinita, questo è l'unico tipo di fotogrammi chiave presi in considerazione da ExoPlayer.

ExoPlayer sembra bloccato nello stato di buffering quando gli viene chiesto di riprodurre un file MPEG-TS privo di AUD o keyframe IDR. Se devi riprodurre questi file, puoi farlo utilizzando FLAG_DETECT_ACCESS_UNITS e FLAG_ALLOW_NON_IDR_KEYFRAMES rispettivamente. Questi flag possono essere impostati su un DefaultExtractorsFactory utilizzando setTsExtractorFlags o su un DefaultHlsExtractorFactory utilizzando il costruttore. L'utilizzo di FLAG_DETECT_ACCESS_UNITS non ha effetti collaterali, se non quello di essere computazionalmente costoso rispetto al rilevamento dei limiti dei frame basato su AUD. L'utilizzo di FLAG_ALLOW_NON_IDR_KEYFRAMES potrebbe causare un danneggiamento visivo temporaneo all'inizio della riproduzione e immediatamente dopo le ricerche durante la riproduzione di alcuni file MPEG-TS.

Perché i sottotitoli codificati non vengono trovati in alcuni file MPEG-TS?

Alcuni file MPEG-TS includono tracce CEA-608, ma non le dichiarano nei metadati del contenitore, pertanto ExoPlayer non è in grado di rilevarle. Puoi specificare manualmente le tracce dei sottotitoli codificati fornendo un elenco dei formati previsti per i sottotitoli codificati a DefaultExtractorsFactory, inclusi i canali di accessibilità che possono essere utilizzati per identificarli nel flusso 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();

Perché alcuni file MP4/FMP4 vengono riprodotti in modo errato?

Alcuni file MP4/FMP4 contengono elenchi di modifiche che riscrivono la cronologia dei contenuti multimediali saltando, spostando o ripetendo elenchi di campioni. ExoPlayer supporta parzialmente l'applicazione degli elenchi di modifiche. Ad esempio, può ritardare o ripetere gruppi di campioni a partire da un campione di sincronizzazione, ma non tronca i campioni audio o i contenuti multimediali preroll per le modifiche che non iniziano con un campione di sincronizzazione.

Se noti che una parte dei contenuti multimediali è inaspettatamente mancante o ripetuta, prova a impostare Mp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS o FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS, in modo che l'estrattore ignori completamente gli elenchi di modifiche. Questi possono essere impostati su un DefaultExtractorsFactory utilizzando setMp4ExtractorFlags o setFragmentedMp4ExtractorFlags.

Perché alcuni stream non vanno a buon fine con il codice di risposta HTTP 301 o 302?

I codici di risposta HTTP 301 e 302 indicano entrambi il reindirizzamento. Brevi descrizioni sono disponibili su Wikipedia. Quando ExoPlayer effettua una richiesta e riceve una risposta con codice di stato 301 o 302, in genere segue il reindirizzamento e avvia la riproduzione normalmente. L'unico caso in cui ciò non avviene per impostazione predefinita è per i reindirizzamenti tra protocolli. Un reindirizzamento tra protocolli è un reindirizzamento da HTTPS a HTTP o viceversa (o, meno comunemente, tra un'altra coppia di protocolli). Puoi verificare se un URL causa un reindirizzamento tra protocolli utilizzando lo strumento a riga di comando wget nel seguente modo:

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

L'output dovrebbe essere simile al seguente:

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

In questo esempio, ci sono due reindirizzamenti. Il primo reindirizzamento è da https://yourserver.example.com/test.mp3 a https://secondserver.example.net/test.mp3. Entrambi sono HTTPS, quindi non si tratta di un reindirizzamento tra protocolli diversi. Il secondo reindirizzamento è da https://secondserver.example.net/test.mp3 a http://thirdserver.example.org/test.mp3. Questo reindirizzamento da HTTPS a HTTP è quindi un reindirizzamento cross-protocollo. ExoPlayer non seguirà questo reindirizzamento nella sua configurazione predefinita, il che significa che la riproduzione non andrà a buon fine.

Se necessario, puoi configurare ExoPlayer in modo che segua i reindirizzamenti tra protocolli quando crei istanze DefaultHttpDataSource.Factory utilizzate nella tua applicazione. Scopri di più sulla selezione e la configurazione dello stack di rete qui.

Perché alcuni stream non vanno a buon fine e viene visualizzato l'errore UnrecognizedInputFormatException?

Questa domanda riguarda gli errori di riproduzione del seguente modulo:

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

Esistono due possibili cause di questo errore. La causa più comune è che stai tentando di riprodurre contenuti DASH (mpd), HLS (m3u8) o Smooth Streaming (ism, isml), ma il player tenta di riprodurli come stream progressivo. Per riprodurre questi stream, devi fare affidamento sul rispettivo modulo ExoPlayer. Nei casi in cui l'URI dello stream non termina con l'estensione del file standard, puoi anche passare MimeTypes.APPLICATION_MPD, MimeTypes.APPLICATION_M3U8 o MimeTypes.APPLICATION_SS a setMimeType di MediaItem.Builder per specificare esplicitamente il tipo di stream.

La seconda causa, meno comune, è che ExoPlayer non supporta il formato contenitore dei contenuti multimediali che stai tentando di riprodurre. In questo caso, l'errore funziona come previsto, ma non esitare a inviare una richiesta di funzionalità al nostro Issue Tracker, includendo i dettagli del formato del contenitore e un flusso di test. Cerca una richiesta di funzionalità esistente prima di inviarne una nuova.

Perché setPlaybackParameters non funziona correttamente su alcuni dispositivi?

Quando esegui una build di debug della tua app su Android M e versioni precedenti, potresti riscontrare prestazioni instabili, artefatti udibili e un elevato utilizzo della CPU quando utilizzi l'API setPlaybackParameters. Questo perché un'ottimizzazione importante per questa API è disattivata per le build di debug in esecuzione su queste versioni di Android.

È importante notare che questo problema riguarda solo le build di debug. Non influisce sulle build di rilascio, per le quali l'ottimizzazione è sempre attivata. Pertanto, le release che fornisci agli utenti finali non dovrebbero essere interessate da questo problema.

Che cosa significano gli errori "Player is accessed on the wrong thread"?

Consulta la sezione Una nota sui thread nella pagina Guida introduttiva.

Come faccio a risolvere il problema "Unexpected status line: ICY 200 OK"?

Questo problema può verificarsi se la risposta del server include una riga di stato ICY, anziché una conforme al protocollo HTTP. Le righe di stato ICY sono obsolete e non devono essere utilizzate, quindi se controlli il server devi aggiornarlo per fornire una risposta conforme a HTTP. Se non riesci a farlo, l'utilizzo della libreria ExoPlayer OkHttp risolverà il problema, in quanto è in grado di gestire correttamente le righe di stato ICY.

Come faccio a verificare se lo stream in riproduzione è un live streaming?

Puoi eseguire query sul metodo isCurrentWindowLive del giocatore. Inoltre, puoi controllare isCurrentWindowDynamic per scoprire se la finestra è dinamica (ovvero se continua ad aggiornarsi nel tempo).

Come faccio a mantenere la riproduzione audio quando la mia app è in background?

Segui questi passaggi per garantire la riproduzione continua dell'audio quando l'app è in background:

  1. Devi avere un servizio in primo piano in esecuzione. In questo modo il sistema non interromperà il processo per liberare risorse.
  2. Devi disporre di un WifiLock e di un WakeLock. Questi assicurano che il sistema mantenga attivi la radio Wi-Fi e la CPU. Questa operazione può essere eseguita facilmente se utilizzi ExoPlayer chiamando setWakeMode, che acquisirà e rilascerà automaticamente i blocchi richiesti al momento giusto.

È importante rilasciare i blocchi (se non si utilizza setWakeMode) e interrompere il servizio non appena l'audio non viene più riprodotto.

Perché ExoPlayer supporta i miei contenuti, ma la libreria ExoPlayer Cast no?

È possibile che i contenuti che stai cercando di riprodurre non siano abilitati per CORS. Il framework Cast richiede che i contenuti siano abilitati per CORS per poter essere riprodotti.

Perché la riproduzione dei contenuti non riesce, ma non viene visualizzato alcun errore?

È possibile che il dispositivo su cui stai riproducendo i contenuti non supporti un formato specifico di esempio multimediale. Puoi verificarlo facilmente aggiungendo un EventLogger come listener al tuo lettore e cercando una riga simile a questa in Logcat:

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

NO_UNSUPPORTED_TYPE significa che il dispositivo non è in grado di decodificare il formato di esempio multimediale specificato da mimeType. Per informazioni sui formati di esempio supportati, consulta la documentazione sui formati multimediali di Android. Come posso ottenere una libreria di decodifica da caricare e utilizzare per la riproduzione? potrebbe esserti utile.

Come faccio a caricare una libreria di decodifica e a utilizzarla per la riproduzione?

  • La maggior parte delle librerie di decodifica prevede passaggi manuali per estrarre e creare le dipendenze, quindi assicurati di aver seguito i passaggi descritti nel file README della libreria pertinente. Ad esempio, per la libreria ExoPlayer FFmpeg è necessario seguire le istruzioni riportate in libraries/decoder_ffmpeg/README.md, incluso il passaggio dei flag di configurazione per attivare i decoder per tutti i formati che vuoi riprodurre.
  • Per le librerie con codice nativo, assicurati di utilizzare la versione corretta dell'NDK Android come specificato nel file README e presta attenzione a eventuali errori visualizzati durante la configurazione e la creazione. Dovresti vedere i file .so nella sottodirectory libs del percorso della libreria per ogni architettura supportata dopo aver seguito i passaggi descritti nel file README.
  • Per provare la riproduzione utilizzando la libreria nell'applicazione demo, consulta la sezione Attivazione dei decoder in bundle. Consulta il file README della libreria per istruzioni sull'utilizzo della libreria dalla tua app.
  • Se utilizzi DefaultRenderersFactory, in Logcat dovresti visualizzare una riga di log a livello di informazioni come "Loaded FfmpegAudioRenderer" quando il decodificatore viene caricato. Se manca, assicurati che l'applicazione abbia una dipendenza dalla libreria di decodifica.
  • Se in Logcat visualizzi log a livello di avviso da LibraryLoader, significa che il caricamento del componente nativo della libreria non è riuscito. In questo caso, verifica di aver seguito correttamente i passaggi descritti nel file README della libreria e che non siano stati generati errori durante l'esecuzione delle istruzioni.

Se continui a riscontrare problemi con l'utilizzo delle librerie di decodifica, consulta lo strumento di monitoraggio dei problemi di Media3 per eventuali problemi recenti pertinenti. Se devi segnalare un nuovo problema relativo alla creazione della parte nativa della libreria, includi l'output completo della riga di comando dell'esecuzione delle istruzioni del file README, per aiutarci a diagnosticare il problema.

Posso riprodurre i video di YouTube direttamente con ExoPlayer?

No, ExoPlayer non può riprodurre video di YouTube, ad esempio URL del tipo https://www.youtube.com/watch?v=.... Devi invece utilizzare l'API YouTube iFrame Player, che è il modo ufficiale per riprodurre i video di YouTube su Android.

La riproduzione del video è a scatti

Il dispositivo potrebbe non essere in grado di decodificare i contenuti abbastanza velocemente se, ad esempio, la velocità in bit o la risoluzione dei contenuti superano le capacità del dispositivo. Potresti dover utilizzare contenuti di qualità inferiore per ottenere buone prestazioni su questi dispositivi.

Se riscontri problemi di riproduzione dei video su un dispositivo con una versione di Android da Android 6.0 (livello API 23) fino ad Android 11 (livello API 30) incluso, in particolare durante la riproduzione di contenuti protetti da DRM o con frame rate elevato, puoi provare a attivare l'accodamento asincrono dei buffer.

Errori di linting API instabili

Media3 garantisce la compatibilità binaria per un sottoinsieme della superficie API. Le parti che non garantiscono la compatibilità binaria sono contrassegnate con @UnstableApi. Per rendere chiara questa distinzione, gli utilizzi di simboli API instabili generano un errore di lint, a meno che non siano annotati con @OptIn.

L'annotazione @UnstableApi non implica nulla in merito alla qualità o al rendimento di un'API, ma solo il fatto che non è "API-frozen".

Hai due opzioni per gestire gli errori di linting API instabili:

  • Passa all'utilizzo di un'API stabile che ottenga lo stesso risultato.
  • Continua a utilizzare l'API instabile e annota l'utilizzo con @OptIn, come mostrato in seguito.
Aggiungere l'annotazione @OptIn

Android Studio può aiutarti ad aggiungere l'annotazione:

Screenshot: come aggiungere l'annotazione Optin
Figura 2: aggiunta di un'annotazione @androidx.annotations.OptIn con Android Studio.

Puoi anche annotare manualmente siti di utilizzo specifici in Kotlin:

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

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

E anche in Java:

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

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

È possibile attivare interi pacchetti aggiungendo un file package-info.java:

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

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

È possibile attivare interi progetti eliminando l'errore di lint specifico nel file 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>

Esiste anche un'annotazione kotlin.OptIn che non deve essere utilizzata. È importante utilizzare l'annotazione androidx.annotation.OptIn.