Dépannage


Corriger les erreurs "Trafic HTTP en texte clair non autorisé"

Cette erreur se produit si votre application demande un trafic HTTP en texte clair (c'est-à-dire http:// plutôt que https://) alors que sa configuration de sécurité réseau ne l'autorise pas. Si votre application cible Android 9 (niveau d'API 28) ou version ultérieure, le trafic HTTP en texte clair est désactivé par la configuration par défaut.

Si votre application doit fonctionner avec le trafic HTTP en texte clair, vous devez utiliser une configuration de sécurité réseau qui l'autorise. Pour en savoir plus, consultez la documentation sur la sécurité du réseau d'Android. Pour activer tout le trafic HTTP en texte clair, il vous suffit d'ajouter android:usesCleartextTraffic="true" à l'élément application du fichier AndroidManifest.xml de votre application.

L'application de démonstration ExoPlayer utilise la configuration de sécurité réseau par défaut et n'autorise donc pas le trafic HTTP en texte clair. Vous pouvez l'activer en suivant les instructions ci-dessus.

Corriger les erreurs "SSLHandshakeException", "CertPathValidatorException" et "ERR_CERT_AUTHORITY_INVALID"

SSLHandshakeException, CertPathValidatorException et ERR_CERT_AUTHORITY_INVALID indiquent tous un problème avec le certificat SSL du serveur. Ces erreurs ne sont pas spécifiques à ExoPlayer. Pour en savoir plus, consultez la documentation Android sur SSL.

Pourquoi certains fichiers multimédias ne sont-ils pas consultables ?

Par défaut, ExoPlayer n'est pas compatible avec la recherche dans les contenus multimédias où la seule méthode permettant d'effectuer des opérations de recherche précises consiste à ce que le lecteur analyse et indexe l'intégralité du fichier. ExoPlayer considère ces fichiers comme non recherchables. La plupart des formats de conteneur multimédia modernes incluent des métadonnées pour la recherche (comme un index d'échantillons), ont un algorithme de recherche bien défini (par exemple, une recherche par dichotomie interpolée pour Ogg) ou indiquent que leur contenu est à débit constant. Dans ces cas, les opérations de recherche efficaces sont possibles et prises en charge par ExoPlayer.

Si vous avez besoin de la fonctionnalité de recherche, mais que vos contenus multimédias ne sont pas compatibles, nous vous suggérons de les convertir dans un format de conteneur plus approprié. Pour les fichiers MP3, ADTS et AMR, vous pouvez également activer la recherche en supposant que les fichiers ont un débit constant, comme décrit dans cet article.

Pourquoi la recherche est-elle inexacte dans certains fichiers MP3 ?

Les fichiers MP3 à débit binaire variable (VBR) ne conviennent pas aux cas d'utilisation qui nécessitent une recherche exacte. Il y a deux raisons à cela :

  1. Pour une recherche précise, un format de conteneur fournira idéalement un mappage précis du temps aux octets dans un en-tête. Ce mappage permet à un lecteur de mapper une durée de recherche demandée à l'offset d'octet correspondant, et de commencer à demander, à analyser et à lire le contenu multimédia à partir de cet offset. Malheureusement, les en-têtes disponibles pour spécifier ce mappage au format MP3 (comme les en-têtes XING) sont souvent imprécis.
  2. Pour les formats de conteneur qui ne fournissent pas de mappage précis entre le temps et les octets (ou aucun mappage entre le temps et les octets), il est toujours possible d'effectuer une recherche exacte si le conteneur inclut des codes temporels d'échantillon absolus dans le flux. Dans ce cas, un lecteur peut mapper le temps de recherche à une estimation de l'offset d'octet correspondant, commencer à demander le contenu multimédia à partir de cet offset, analyser le premier code temporel absolu de l'échantillon et effectuer une recherche binaire guidée dans le contenu multimédia jusqu'à ce qu'il trouve le bon échantillon. Malheureusement, le format MP3 n'inclut pas d'horodatages absolus des échantillons dans le flux. Cette approche n'est donc pas possible.

Pour ces raisons, la seule façon d'effectuer une recherche exacte dans un fichier MP3 à débit binaire variable est d'analyser l'intégralité du fichier et de créer manuellement une mise en correspondance entre le temps et les octets dans le lecteur. Cette stratégie peut être activée à l'aide de FLAG_ENABLE_INDEX_SEEKING, qui peut être définie sur un DefaultExtractorsFactory à l'aide de setMp3ExtractorFlags. Notez que cette méthode ne s'adapte pas bien aux fichiers MP3 volumineux, en particulier si l'utilisateur tente de se rapprocher de la fin du flux peu de temps après le début de la lecture. Le lecteur doit alors attendre que l'intégralité du flux soit téléchargée et indexée avant d'effectuer la recherche. Dans ExoPlayer, nous avons décidé d'optimiser la vitesse plutôt que la précision dans ce cas, et FLAG_ENABLE_INDEX_SEEKING est donc désactivé par défaut.

Si vous contrôlez le contenu multimédia que vous lisez, nous vous recommandons vivement d'utiliser un format de conteneur plus approprié, tel que MP4. Nous n'avons connaissance d'aucun cas d'utilisation où le format MP3 est le meilleur choix.

Pourquoi la recherche dans ma vidéo est-elle lente ?

Lorsque le lecteur recherche une nouvelle position de lecture dans une vidéo, il doit effectuer deux actions :

  1. Chargez les données correspondant à la nouvelle position de lecture dans le tampon (cela peut ne pas être nécessaire si ces données sont déjà mises en mémoire tampon).
  2. Videz le décodeur vidéo et commencez le décodage à partir de l'image I (image clé) avant la nouvelle position de lecture, en raison du codage intra-image utilisé par la plupart des formats de compression vidéo. Pour s'assurer que la recherche est précise (c'est-à-dire que la lecture commence exactement à la position de recherche), toutes les images entre l'I-frame précédente et la position de recherche doivent être décodées et immédiatement supprimées (sans être affichées à l'écran).

La latence introduite par (1) peut être atténuée en augmentant la quantité de données mises en mémoire tampon par le lecteur ou en précachant les données sur le disque.

La latence introduite par (2) peut être atténuée en réduisant la précision de la recherche à l'aide de ExoPlayer.setSeekParameters ou en réencodant la vidéo pour qu'elle contienne des i-frames plus fréquentes (ce qui entraînera un fichier de sortie plus volumineux).

Pourquoi certains fichiers MPEG-TS ne sont-ils pas lus ?

Certains fichiers MPEG-TS ne contiennent pas de délimiteurs d'unité d'accès (AUD). Par défaut, ExoPlayer s'appuie sur les AUD pour détecter facilement les limites des images. De même, certains fichiers MPEG-TS ne contiennent pas d'images clés IDR. Par défaut, il s'agit du seul type d'images clés pris en compte par ExoPlayer.

ExoPlayer semble bloqué dans l'état de mise en mémoire tampon lorsqu'il est invité à lire un fichier MPEG-TS qui ne comporte pas d'AUD ni d'images clés IDR. Si vous devez lire de tels fichiers, vous pouvez le faire en utilisant respectivement FLAG_DETECT_ACCESS_UNITS et FLAG_ALLOW_NON_IDR_KEYFRAMES. Ces indicateurs peuvent être définis sur un DefaultExtractorsFactory à l'aide de setTsExtractorFlags ou sur un DefaultHlsExtractorFactory à l'aide du constructeur. L'utilisation de FLAG_DETECT_ACCESS_UNITS n'a pas d'effets secondaires, si ce n'est qu'elle est coûteuse en termes de calcul par rapport à la détection des limites de trame basée sur AUD. L'utilisation de FLAG_ALLOW_NON_IDR_KEYFRAMES peut entraîner une corruption visuelle temporaire au début de la lecture et immédiatement après les recherches lors de la lecture de certains fichiers MPEG-TS.

Pourquoi les sous-titres ne sont-ils pas disponibles dans certains fichiers MPEG-TS ?

Certains fichiers MPEG-TS incluent des pistes CEA-608, mais ne les déclarent pas dans les métadonnées du conteneur. ExoPlayer ne peut donc pas les détecter. Vous pouvez spécifier manuellement des pistes de sous-titres en fournissant une liste des formats de sous-titres attendus à DefaultExtractorsFactory, y compris les canaux d'accessibilité qui peuvent être utilisés pour les identifier dans le flux 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();

Pourquoi certains fichiers MP4/FMP4 ne sont-ils pas lus correctement ?

Certains fichiers MP4/FMP4 contiennent des listes de modifications qui réécrivent le calendrier multimédia en ignorant, déplaçant ou répétant des listes d'échantillons. ExoPlayer est partiellement compatible avec l'application de listes de modifications. Par exemple, il peut retarder ou répéter des groupes d'échantillons à partir d'un échantillon de synchronisation, mais il ne tronque pas les échantillons audio ni le média de préroll pour les modifications qui ne commencent pas par un échantillon de synchronisation.

Si vous constatez qu'une partie du contenu multimédia est manquante ou répétée de manière inattendue, essayez de définir Mp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS ou FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS, ce qui obligera l'extracteur à ignorer complètement les listes de modifications. Ils peuvent être définis sur un DefaultExtractorsFactory à l'aide de setMp4ExtractorFlags ou setFragmentedMp4ExtractorFlags.

Pourquoi certains flux échouent-ils avec le code de réponse HTTP 301 ou 302 ?

Les codes de réponse HTTP 301 et 302 indiquent tous deux une redirection. Vous trouverez de brèves descriptions sur Wikipédia. Lorsque ExoPlayer effectue une requête et reçoit une réponse avec le code d'état 301 ou 302, il suit normalement la redirection et lance la lecture comme d'habitude. La seule exception par défaut concerne les redirections inter-protocoles. Une redirection inter-protocole est une redirection de HTTPS vers HTTP ou inversement (ou, moins fréquemment, entre une autre paire de protocoles). Vous pouvez tester si une URL provoque une redirection multiprotocole à l'aide de l'outil de ligne de commande wget comme suit :

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

Le résultat devrait ressembler à ceci :

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

Dans cet exemple, il existe deux redirections. La première redirection est de https://yourserver.example.com/test.mp3 vers https://secondserver.example.net/test.mp3. Les deux URL utilisent le protocole HTTPS. Il ne s'agit donc pas d'une redirection inter-protocoles. La deuxième redirection est de https://secondserver.example.net/test.mp3 vers http://thirdserver.example.org/test.mp3. Il s'agit d'une redirection inter-protocoles, car elle redirige le trafic de HTTPS vers HTTP. ExoPlayer ne suivra pas cette redirection dans sa configuration par défaut, ce qui signifie que la lecture échouera.

Si nécessaire, vous pouvez configurer ExoPlayer pour qu'il suive les redirections multiprotocoles lors de l'instanciation des instances DefaultHttpDataSource.Factory utilisées dans votre application. Pour savoir comment sélectionner et configurer la pile réseau, cliquez ici.

Pourquoi certains flux échouent-ils avec l'exception UnrecognizedInputFormatException ?

Cette question concerne les échecs de lecture du type suivant :

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

Il existe deux causes possibles à cet échec. La cause la plus fréquente est que vous essayez de lire du contenu DASH (mpd), HLS (m3u8) ou SmoothStreaming (ism, isml), mais que le lecteur essaie de le lire en tant que flux progressif. Pour lire ces flux, vous devez dépendre du module ExoPlayer correspondant. Dans les cas où l'URI du flux ne se termine pas par l'extension de fichier standard, vous pouvez également transmettre MimeTypes.APPLICATION_MPD, MimeTypes.APPLICATION_M3U8 ou MimeTypes.APPLICATION_SS à setMimeType de MediaItem.Builder pour spécifier explicitement le type de flux.

La deuxième cause, moins fréquente, est qu'ExoPlayer n'est pas compatible avec le format de conteneur du contenu multimédia que vous essayez de lire. Dans ce cas, l'échec fonctionne comme prévu. Toutefois, n'hésitez pas à envoyer une demande de fonctionnalité à notre outil de suivi des problèmes, en incluant des informations sur le format du conteneur et un flux de test. Veuillez rechercher une demande de fonctionnalité existante avant d'en envoyer une nouvelle.

Pourquoi setPlaybackParameters ne fonctionne-t-il pas correctement sur certains appareils ?

Lorsque vous exécutez une version de débogage de votre application sur Android M ou une version antérieure, vous pouvez rencontrer des performances saccadées, des artefacts audibles et une utilisation élevée du processeur lorsque vous utilisez l'API setPlaybackParameters. En effet, une optimisation importante pour cette API est désactivée pour les versions de débogage exécutées sur ces versions d'Android.

Il est important de noter que ce problème n'affecte que les versions de débogage. Cela n'a aucune incidence sur les versions finales, pour lesquelles l'optimisation est toujours activée. Par conséquent, les versions que vous fournissez aux utilisateurs finaux ne devraient pas être affectées par ce problème.

Que signifient les erreurs "Le lecteur est accessible sur le mauvais thread" ?

Consultez Remarque sur le threading sur la page "Premiers pas".

Comment résoudre l'erreur "Unexpected status line: ICY 200 OK" ?

Ce problème peut se produire si la réponse du serveur inclut une ligne d'état ICY plutôt qu'une ligne conforme à HTTP. Les lignes d'état ICY sont obsolètes et ne doivent pas être utilisées. Si vous contrôlez le serveur, vous devez le mettre à jour pour qu'il fournisse une réponse conforme à HTTP. Si vous ne parvenez pas à le faire, l'utilisation de la bibliothèque ExoPlayer OkHttp résoudra le problème, car elle est capable de gérer correctement les lignes d'état ICY.

Comment puis-je savoir si le flux en cours de lecture est une diffusion en direct ?

Vous pouvez interroger la méthode isCurrentWindowLive du lecteur. Vous pouvez également vérifier isCurrentWindowDynamic pour savoir si la fenêtre est dynamique (c'est-à-dire si elle continue de se mettre à jour au fil du temps).

Comment faire en sorte que le contenu audio continue d'être lu lorsque mon application est en arrière-plan ?

Pour que le contenu audio continue d'être lu lorsque votre application est en arrière-plan, procédez comme suit :

  1. Vous devez disposer d'un service de premier plan en cours d'exécution. Cela empêche le système d'arrêter votre processus pour libérer des ressources.
  2. Vous devez détenir un WifiLock et un WakeLock. Elles permettent au système de maintenir le module Wi-Fi et le processeur actifs. Cela peut être fait facilement si vous utilisez ExoPlayer en appelant setWakeMode, qui acquerra et libérera automatiquement les verrous requis aux bons moments.

Il est important de libérer les verrous (si vous n'utilisez pas setWakeMode) et d'arrêter le service dès que l'audio n'est plus lu.

Pourquoi ExoPlayer est-il compatible avec mon contenu, mais pas la bibliothèque ExoPlayer Cast ?

Il est possible que le contenu que vous essayez de lire ne soit pas compatible avec CORS. Le framework Cast exige que le contenu soit compatible avec CORS pour pouvoir être lu.

Pourquoi le contenu ne se lit-il pas, mais aucune erreur n'est affichée ?

Il est possible que l'appareil sur lequel vous lisez le contenu ne soit pas compatible avec un format d'échantillon multimédia spécifique. Vous pouvez facilement le vérifier en ajoutant un EventLogger en tant qu'écouteur à votre lecteur et en recherchant une ligne semblable à celle-ci dans Logcat :

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

NO_UNSUPPORTED_TYPE signifie que l'appareil n'est pas en mesure de décoder le format d'échantillon multimédia spécifié par mimeType. Pour en savoir plus sur les formats d'échantillon compatibles, consultez la documentation sur les formats multimédias Android. L'article Comment obtenir une bibliothèque de décodage à charger et à utiliser pour la lecture ? peut également vous être utile.

Comment puis-je obtenir une bibliothèque de décodage à charger et à utiliser pour la lecture ?

  • La plupart des bibliothèques de décodage nécessitent des étapes manuelles pour extraire et compiler les dépendances. Assurez-vous donc d'avoir suivi les étapes du fichier README de la bibliothèque concernée. Par exemple, pour la bibliothèque ExoPlayer FFmpeg, il est nécessaire de suivre les instructions de libraries/decoder_ffmpeg/README.md, y compris de transmettre des indicateurs de configuration pour activer les décodeurs pour tous les formats que vous souhaitez lire.
  • Pour les bibliothèques qui comportent du code natif, assurez-vous d'utiliser la version correcte du NDK Android, comme indiqué dans le fichier README. Vérifiez également si des erreurs s'affichent lors de la configuration et de la compilation. Après avoir suivi les étapes du fichier README, vous devriez voir des fichiers .so apparaître dans le sous-répertoire libs du chemin d'accès à la bibliothèque pour chaque architecture compatible.
  • Pour essayer la lecture à l'aide de la bibliothèque dans l'application de démonstration, consultez Activer les décodeurs groupés. Consultez le fichier README de la bibliothèque pour obtenir des instructions sur son utilisation depuis votre propre application.
  • Si vous utilisez DefaultRenderersFactory, vous devriez voir une ligne de journal de niveau info, telle que "Loaded FfmpegAudioRenderer" (FfmpegAudioRenderer chargé) dans Logcat lorsque le décodeur se charge. Si elle est manquante, assurez-vous que l'application dépend de la bibliothèque de décodage.
  • Si vous voyez des journaux de niveau avertissement provenant de LibraryLoader dans Logcat, cela indique que le chargement du composant natif de la bibliothèque a échoué. Si cela se produit, vérifiez que vous avez correctement suivi les étapes du fichier README de la bibliothèque et qu'aucune erreur n'a été générée lors du suivi des instructions.

Si vous rencontrez toujours des problèmes pour utiliser les bibliothèques de décodage, veuillez consulter le suivi des problèmes Media3 pour voir si des problèmes récents sont pertinents. Si vous devez signaler un nouveau problème lié à la création de la partie native de la bibliothèque, veuillez inclure l'intégralité de la sortie de ligne de commande lors de l'exécution des instructions du fichier README pour nous aider à diagnostiquer le problème.

Puis-je lire des vidéos YouTube directement avec ExoPlayer ?

Non, ExoPlayer ne peut pas lire les vidéos YouTube, telles que les URL au format https://www.youtube.com/watch?v=.... Utilisez plutôt l'API YouTube IFrame Player, qui est la méthode officielle pour lire des vidéos YouTube sur Android.

La lecture vidéo saccade

Il est possible que l'appareil ne puisse pas décoder le contenu assez rapidement si, par exemple, le débit ou la résolution du contenu dépassent les capacités de l'appareil. Vous devrez peut-être utiliser du contenu de qualité inférieure pour obtenir de bonnes performances sur ces appareils.

Si vous rencontrez des problèmes de saccades vidéo sur un appareil exécutant une version d'Android comprise entre Android 6.0 (niveau d'API 23) et Android 11 (niveau d'API 30) inclus, en particulier lors de la lecture de contenu protégé par DRM ou à fréquence d'images élevée, vous pouvez essayer d'activer la mise en file d'attente asynchrone des tampons.

Erreurs lint d'API instables

Media3 garantit la compatibilité binaire pour un sous-ensemble de la surface de l'API. Les parties qui ne garantissent pas la compatibilité binaire sont marquées avec @UnstableApi. Pour que cette distinction soit claire, les utilisations de symboles d'API instables génèrent une erreur lint, sauf si elles sont annotées avec @OptIn.

L'annotation @UnstableApi n'implique rien quant à la qualité ou aux performances d'une API, mais indique simplement qu'elle n'est pas "gelée".

Vous avez deux options pour gérer les erreurs lint d'API instables :

  • Passez à une API stable qui permet d'obtenir le même résultat.
  • Continuez à utiliser l'API instable et annotez l'utilisation avec @OptIn, comme indiqué plus loin.
Ajouter l'annotation @OptIn

Android Studio peut vous aider à ajouter l'annotation :

Capture d'écran : ajouter l'annotation Optin
Figure 2 : Ajout d'une annotation @androidx.annotations.OptIn avec Android Studio.

Vous pouvez également annoter manuellement des sites d'utilisation spécifiques en Kotlin :

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

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

Et aussi en Java :

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

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

Vous pouvez activer des packages entiers en ajoutant un fichier package-info.java :

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

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

Vous pouvez activer des projets entiers en supprimant l'erreur lint spécifique dans leur fichier 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>

Il existe également une annotation kotlin.OptIn qui ne doit pas être utilisée. Il est important d'utiliser l'annotation androidx.annotation.OptIn.