トラブルシューティング


「クリアテキスト 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 フレームの頻度を増やす(出力ファイルのサイズが大きくなります)ことで軽減できます。

ユーザーがシークバーをドラッグしているときにシークが遅い場合は、スクラブモード(ExoPlayer.setScrubbingModeEnabled)を有効にします。これにより、高速シークが統合され、デコーダのスループットが向上し、UI スクラブ幅に基づいて部分的なシーク許容値を設定できるようになります。

一部の 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 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) を使用して、特定のフィーチャー トグルを個別に無効にします。カナリアモードの構成、フラグのオーバーライド、リモート キルスイッチの設定の詳細については、フィーチャー トグルとカナリアモードのガイドをご覧ください。