トラブルシューティング


「クリアテキスト HTTP トラフィックは許可されていません」エラーの修正

このエラーは、ネットワーク セキュリティ構成で許可されていない場合に、アプリがクリアテキスト HTTP トラフィック(https:// ではなく http://)をリクエストすると発生します。アプリが Android 9(API レベル 28)以降をターゲットとしている場合、クリアテキスト HTTP トラフィックはデフォルトの構成で無効になっています。

アプリがクリアテキスト HTTP トラフィックを処理する必要がある場合は、それを許可するネットワーク セキュリティ構成を使用する必要があります。詳しくは、Android のネットワーク セキュリティに関するドキュメントをご覧ください。すべてのクリアテキスト HTTP トラフィックを有効にするには、アプリの AndroidManifest.xml の application 要素に android:usesCleartextTraffic="true" を追加するだけです。

ExoPlayer デモアプリはデフォルトのネットワーク セキュリティ構成を使用するため、クリアテキスト HTTP トラフィックは許可されません。上記の手順で有効にできます。

「SSLHandshakeException」、「CertPathValidatorException」、「ERR_CERT_AUTHORITY_INVALID」エラーの修正

SSLHandshakeException、CertPathValidatorException、ERR_CERT_AUTHORITY_INVALID はすべて、サーバーの SSL 証明書に問題があることを示しています。これらのエラーは ExoPlayer に固有のものではありません。詳しくは、Android の SSL に関するドキュメントをご覧ください。

一部のメディア ファイルがシークできないのはなぜですか?

デフォルトでは、ExoPlayer は、プレーヤーがファイル全体をスキャンしてインデックスを作成することが正確なシーク オペレーションを実行する唯一の方法であるメディアでのシークをサポートしていません。ExoPlayer は、このようなファイルをシーク不可と見なします。最新のメディア コンテナ フォーマットのほとんどは、シーク用のメタデータ(サンプル インデックスなど)を含んでいるか、明確に定義されたシーク アルゴリズム(Ogg の補間二分探索など)を備えているか、コンテンツが固定ビットレートであることを示しています。このような場合、効率的なシーク オペレーションが可能であり、ExoPlayer でサポートされています。

シークが必要なのにシークできないメディアがある場合は、より適切なコンテナ形式を使用するようにコンテンツを変換することをおすすめします。MP3、ADTS、AMR ファイルの場合、こちらで説明されているように、ファイルが一定のビットレートであると仮定してシークを有効にすることもできます。

一部の MP3 ファイルでシークが不正確なのはなぜですか?

可変ビットレート(VBR)の MP3 ファイルは、正確なシークを必要とするユースケースには基本的に適していません。これには、次の 2 つの理由があります。

  1. 正確なシークを行うには、コンテナ形式でヘッダーに正確な時間からバイトへのマッピングを提供することが理想的です。このマッピングにより、プレーヤーはリクエストされたシーク時間を対応するバイト オフセットにマッピングし、そのオフセットからメディアのリクエスト、解析、再生を開始できます。残念ながら、MP3 でこのマッピングを指定するために使用できるヘッダー(XING ヘッダーなど)は、不正確なことがよくあります。
  2. 正確な時間からバイトへのマッピング(または時間からバイトへのマッピング)を提供しないコンテナ形式の場合でも、コンテナにストリーム内の絶対サンプル タイムスタンプが含まれていれば、正確なシークを実行できます。この場合、プレーヤーはシーク時間を対応するバイト オフセットの最適な推定値にマッピングし、そのオフセットからメディアのリクエストを開始して、最初の絶対サンプル タイムスタンプを解析し、適切なサンプルが見つかるまでメディアへのガイド付きバイナリ検索を効果的に実行できます。残念ながら、MP3 にはストリーム内の絶対サンプル タイムスタンプが含まれていないため、この方法は不可能です。

このような理由から、VBR MP3 ファイルで正確なシークを行うには、ファイル全体をスキャンして、プレーヤーで時間とバイトのマッピングを手動で構築するしかありません。この戦略は、FLAG_ENABLE_INDEX_SEEKING を使用して有効にできます。これは、setMp3ExtractorFlags を使用して DefaultExtractorsFactory に設定できます。大きな MP3 ファイルにはあまり適していません。特に、再生開始直後にユーザーがストリームの末尾付近にシークしようとすると、プレーヤーはシークを実行する前に、ストリーム全体をダウンロードしてインデックスに登録するまで待機する必要があります。ExoPlayer では、このケースでは精度よりも速度を優先して最適化することにしました。そのため、FLAG_ENABLE_INDEX_SEEKING はデフォルトで無効になっています。

再生するメディアを制御する場合は、MP4 などのより適切なコンテナ形式を使用することを強くおすすめします。MP3 がメディア形式として最適なユースケースは、Google が把握している限りありません。

動画のシークが遅いのはなぜですか?

プレーヤーが動画内の新しい再生位置にシークする場合、次の 2 つの処理を行う必要があります。

  1. 新しい再生位置に対応するデータをバッファに読み込みます(このデータがすでにバッファリングされている場合は、この処理は必要ありません)。
  2. 動画デコーダをフラッシュし、新しい再生位置の前の I フレーム(キーフレーム)からデコードを開始します。これは、ほとんどの動画圧縮形式で使用されるフレーム内コーディングによるものです。シークを正確にする(つまり、シーク位置から正確に再生を開始する)には、前の I フレームとシーク位置の間にあるすべてのフレームをデコードし、すぐに破棄する必要があります(画面には表示されません)。

(1)によって発生するレイテンシは、プレーヤーがメモリにバッファリングするデータの量を増やすか、データをディスクに事前キャッシュすることで軽減できます。

(2)によって発生するレイテンシは、ExoPlayer.setSeekParameters を使用してシークの精度を下げるか、動画を再エンコードして I フレームの頻度を増やす(出力ファイルのサイズが大きくなる)ことで軽減できます。

一部の MPEG-TS ファイルが再生されないのはなぜですか?

一部の MPEG-TS ファイルには、アクセス ユニット デリミタ(AUD)が含まれていません。デフォルトでは、ExoPlayer は AUD を使用してフレーム境界を低コストで検出します。同様に、一部の MPEG-TS ファイルには IDR キーフレームが含まれていません。デフォルトでは、ExoPlayer が考慮するキーフレームは、このタイプのみです。

AUD または IDR キーフレームがない MPEG-TS ファイルを再生するように求められると、ExoPlayer はバッファリング状態で停止しているように見えます。このようなファイルを再生する必要がある場合は、それぞれ FLAG_DETECT_ACCESS_UNITS と FLAG_ALLOW_NON_IDR_KEYFRAMES を使用して再生できます。これらのフラグは、setTsExtractorFlags を使用して DefaultExtractorsFactory に設定するか、コンストラクタを使用して DefaultHlsExtractorFactory に設定できます。FLAG_DETECT_ACCESS_UNITS の使用には、AUD ベースのフレーム境界検出と比較して計算コストが高いという点以外に副作用はありません。FLAG_ALLOW_NON_IDR_KEYFRAMES を使用すると、一部の MPEG-TS ファイルの再生時に、再生開始時とシーク直後に一時的に映像が乱れることがあります。

一部の MPEG-TS ファイルで字幕が見つからないのはなぜですか?

一部の MPEG-TS ファイルには CEA-608 トラックが含まれていますが、コンテナ メタデータで宣言されていないため、ExoPlayer はそれらを検出できません。字幕トラックを手動で指定するには、想定される字幕形式のリストを DefaultExtractorsFactory に提供します。これには、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();

一部の MP4/FMP4 ファイルが正しく再生されないのはなぜですか?

一部の MP4 / FMP4 ファイルには、サンプルのリストをスキップ、移動、または繰り返すことでメディア タイムラインを書き換える編集リストが含まれています。ExoPlayer は、編集リストの適用を部分的にサポートしています。たとえば、同期サンプルで始まるサンプルのグループを遅延または繰り返すことはできますが、同期サンプルで始まらない編集のためにオーディオ サンプルを切り捨てたり、メディアをプリロールしたりすることはありません。

メディアの一部が予期せず欠落している、または繰り返されている場合は、Mp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS または FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS を設定してみてください。これにより、エクストラクタは編集リストを完全に無視するようになります。これらは、setMp4ExtractorFlags または setFragmentedMp4ExtractorFlags を使用して DefaultExtractorsFactory に設定できます。

一部のストリームが HTTP レスポンス コード 301 または 302 で失敗するのはなぜですか?

HTTP レスポンス コード 301 と 302 は、どちらもリダイレクトを示します。簡単な説明については、Wikipedia をご覧ください。ExoPlayer がリクエストを送信し、ステータス コード 301 または 302 のレスポンスを受信すると、通常はリダイレクトに従って再生を開始します。デフォルトでこの処理が行われないケースとして、クロスプロトコル リダイレクトがあります。クロスプロトコル リダイレクトとは、HTTPS から HTTP へのリダイレクト、またはその逆のリダイレクト(または、あまり一般的ではありませんが、別のプロトコルのペア間のリダイレクト)です。URL がクロスプロトコル リダイレクトを引き起こすかどうかをテストするには、次のように wget コマンドライン ツールを使用します。

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

出力結果は次のようになります。

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

この例では、2 つのリダイレクトがあります。最初のリダイレクトは https://yourserver.example.com/test.mp3 から https://secondserver.example.net/test.mp3 です。どちらも HTTPS であるため、これはクロスプロトコル リダイレクトではありません。2 番目のリダイレクトは https://secondserver.example.net/test.mp3 から http://thirdserver.example.org/test.mp3 へのリダイレクトです。これは HTTPS から HTTP にリダイレクトするため、クロスプロトコル リダイレクトです。ExoPlayer は、デフォルトの構成ではこのリダイレクトに従わないため、再生は失敗します。

必要に応じて、アプリで使用される DefaultHttpDataSource.Factory インスタンスをインスタンス化するときに、クロスプロトコル リダイレクトに従うように ExoPlayer を構成できます。ネットワーク スタックの選択と構成については、こちらをご覧ください。

一部のストリームが UnrecognizedInputFormatException で失敗するのはなぜですか?

この質問は、次の形式の再生エラーに関連しています。

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

このエラーの原因として、次の 2 つが考えられます。最も一般的な原因は、DASH(mpd)、HLS(m3u8)、SmoothStreaming(ism、isml)のコンテンツを再生しようとしているのに、プレーヤーがプログレッシブ ストリームとして再生しようとしていることです。このようなストリームを再生するには、それぞれの ExoPlayer モジュールに依存する必要があります。ストリーム URI が標準のファイル拡張子で終わらない場合は、MimeTypes.APPLICATION_MPD、MimeTypes.APPLICATION_M3U8、MimeTypes.APPLICATION_SS のいずれかを MediaItem.Builder の setMimeType に渡して、ストリームのタイプを明示的に指定することもできます。

2 つ目の原因(あまり一般的ではありません)は、再生しようとしているメディアのコンテナ形式を ExoPlayer がサポートしていないことです。この場合、エラーは想定どおりに動作していますが、コンテナ形式とテスト ストリームの詳細を記載した機能リクエストを Issue Tracker に送信してください。新しい機能リクエストを送信する前に、既存の機能リクエストを検索してください。

一部のデバイスで setPlaybackParameters が正常に動作しないのはなぜですか?

Android M 以前でアプリのデバッグビルドを実行している場合、setPlaybackParameters API を使用すると、パフォーマンスの低下、音声アーティファクト、CPU 使用率の上昇が発生することがあります。これは、この API にとって重要な最適化が、これらのバージョンの Android で実行されるデバッグビルドでは無効になっているためです。

この問題はデバッグビルドにのみ影響します。リリースビルドには影響しません。リリースビルドでは、最適化は常に有効になっています。したがって、エンドユーザーに提供するリリースは、この問題の影響を受けません。

「プレーヤーが間違ったスレッドでアクセスされている」というエラーの意味

スタートガイドのスレッドに関する注記をご覧ください。

「予期しないステータス行: ICY 200 OK」を修正するにはどうすればよいですか?

この問題は、サーバー レスポンスに HTTP 準拠のステータス行ではなく、ICY ステータス行が含まれている場合に発生することがあります。ICY ステータス行は非推奨であり、使用しないでください。サーバーを管理している場合は、HTTP 準拠のレスポンスを提供するように更新する必要があります。これができない場合は、ExoPlayer OkHttp ライブラリを使用すると、ICY ステータス行を正しく処理できるため、問題が解決します。

再生中のストリームがライブ ストリームかどうかをクエリするにはどうすればよいですか?

プレーヤーの isCurrentWindowLive メソッドをクエリできます。また、isCurrentWindowDynamic を確認して、ウィンドウが動的(時間の経過とともに更新される)かどうかを判断できます。

アプリがバックグラウンドに移行しても音声の再生を継続するにはどうすればよいですか?

アプリがバックグラウンドにあるときに音声の再生を継続する手順は次のとおりです。

  1. フォアグラウンド サービスが実行されている必要があります。これにより、システムがリソースを解放するためにプロセスを強制終了するのを防ぐことができます。
  2. WifiLock と WakeLock を保持する必要があります。これにより、システムは Wi-Fi 無線と CPU を起動したままにします。ExoPlayer を使用している場合は、setWakeMode を呼び出すことで、必要なロックを適切なタイミングで自動的に取得、解放できます。

setWakeMode を使用していない場合は、音声の再生が終了したらすぐにロックを解除してサービスを停止することが重要です。

ExoPlayer はコンテンツをサポートしているのに、ExoPlayer Cast ライブラリはサポートしていないのはなぜですか?

再生しようとしているコンテンツで CORS が有効になっていない可能性があります。Cast フレームワークでコンテンツを再生するには、コンテンツで CORS が有効になっている必要があります。

コンテンツが再生されないのに、エラーが表示されないのはなぜですか?

コンテンツを再生しているデバイスが、特定のメディア サンプル形式をサポートしていない可能性があります。これは、EventLogger をリスナーとしてプレーヤーに追加し、Logcat で次のような行を探すことで簡単に確認できます。

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

NO_UNSUPPORTED_TYPE は、mimeType で指定されたメディア サンプル形式をデバイスがデコードできないことを意味します。サポートされているサンプル形式については、Android メディア形式のドキュメントをご覧ください。デコード ライブラリを読み込んで再生に使用するにはどうすればよいですか?も参考になります。

デコード ライブラリを読み込んで再生に使用するにはどうすればよいですか?

  • ほとんどのデコーダ ライブラリには、依存関係をチェックアウトしてビルドする手動の手順があります。関連するライブラリの README の手順に沿って操作してください。たとえば、ExoPlayer FFmpeg ライブラリの場合は、libraries/decoder_ffmpeg/README.md の手順に沿って、再生する形式のデコーダを有効にする構成フラグを渡す必要があります。
  • ネイティブ コードを含むライブラリの場合は、README で指定されている正しいバージョンの Android NDK を使用していることを確認し、構成中およびビルド中にエラーが発生していないか確認してください。README の手順に沿って操作すると、サポートされているアーキテクチャごとに、ライブラリのパスの libs サブディレクトリに .so ファイルが表示されます。
  • デモ アプリケーションでライブラリを使用して再生を試すには、バンドルされたデコーダを有効にするをご覧ください。独自のアプリからライブラリを使用する手順については、ライブラリの README をご覧ください。
  • DefaultRenderersFactory を使用している場合、デコーダが読み込まれると、Logcat に「Loaded FfmpegAudioRenderer」などの情報レベルのログ行が表示されます。見つからない場合は、アプリケーションがデコード ライブラリに依存していることを確認します。
  • Logcat に LibraryLoader からの警告レベルのログが表示されている場合、ライブラリのネイティブ コンポーネントの読み込みに失敗したことを示しています。この問題が発生した場合は、ライブラリの README の手順を正しく実行していること、手順の実行中にエラーが出力されていないことを確認してください。

デコード ライブラリの使用時に問題が引き続き発生する場合は、Media3 のIssue Trackerで、関連する最近の問題を確認してください。新しい問題を報告する必要があり、それがライブラリのネイティブ部分のビルドに関連している場合は、問題の診断に役立つように、README の手順を実行した際の完全なコマンドライン出力を記載してください。

ExoPlayer で YouTube 動画を直接再生できますか?

いいえ。ExoPlayer は、https://www.youtube.com/watch?v=... 形式の URL など、YouTube の動画を再生できません。代わりに、Android で YouTube 動画を再生する公式の方法である YouTube IFrame Player API を使用する必要があります。

動画の再生が途切れる

たとえば、コンテンツのビットレートや解像度がデバイスの機能を超えている場合、デバイスはコンテンツを十分に高速にデコードできない可能性があります。このようなデバイスで良好なパフォーマンスを得るには、低品質のコンテンツを使用する必要があるかもしれません。

Android 6.0(API レベル 23)から Android 11(API レベル 30)までのバージョンの Android を搭載したデバイスで、特に DRM で保護されたコンテンツや高フレームレートのコンテンツを再生しているときに動画が途切れる場合は、非同期バッファ キューイングを有効にすることを試してください。

不安定な API lint エラー

Media3 は、API サーフェスのサブセットに対してバイナリ互換性を保証します。バイナリ互換性を保証しない部分は、@UnstableApi でマークされています。この区別を明確にするため、不安定な API シンボルを使用すると、@OptIn でアノテーションが付けられていない限り、lint エラーが生成されます。

@UnstableApi アノテーションは、API の品質やパフォーマンスについては何も示さず、API が「API 凍結」されていないという事実のみを示します。

不安定な API lint エラーを処理するには、次の 2 つの方法があります。

  • 同じ結果が得られる安定した API の使用に切り替えます。
  • 不安定な API を引き続き使用し、後述のように @OptIn で使用状況にアノテーションを付ける。
@OptIn アノテーションを追加する

Android Studio でアノテーションを追加できます。

スクリーンショット: Optin アノテーションを追加する方法
図 2: Android Studio で @androidx.annotations.OptIn アノテーションを追加する。

特定の使用サイトに手動でアノテーションを付けることもできます。

Kotlin

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

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

Java

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

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

package-info ファイルを追加することで、パッケージ全体をオプトインできます。

Kotlin

// In your package-info.kt
@OptIn(UnstableApi::class)
package name.of.your.package

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

Java

// In your package-info.java
@OptIn(markerClass = UnstableApi.class)
package name.of.your.package;

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

プロジェクト全体をオプトインするには、lint.xml ファイルで特定の lint エラーを抑制します。

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

kotlin.OptIn アノテーションもありますが、これは使用しないでください。androidx.annotation.OptIn アノテーションを使用することが重要です。

新しい最適化や機能によって発生した問題をテストまたは特定するにはどうすればよいですか?

Media3 には、新しく導入された機能と最適化が Canary モードでデフォルトで有効になるフィーチャー トグル インフラストラクチャが含まれています。

アプリの問題や回帰が、新しく導入された機能や最適化に関連していると思われる場合は、カナリアモードを一時的に無効にできます。

Flags.setCanaryModeEnabled(false);

または、Flags.disableFlag(flagId) を使用して、特定のフィーチャー トグルを個別に無効にします。カナリアモードの構成、フラグのオーバーライド、リモート キルスイッチの設定の詳細については、フィーチャー トグルとカナリアモードのガイドをご覧ください。