トラブルシューティング


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

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

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

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

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

SSLHandshakeExceptionCertPathValidatorExceptionERR_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 を使用して有効にできます。FLAG_ENABLE_INDEX_SEEKINGsetMp3ExtractorFlags を使用して DefaultExtractorsFactory に設定できます。この方法は、大きな MP3 ファイルにはうまく対応できません。特に、ユーザーが再生開始直後にストリームの終わりに近い位置にシークしようとすると、プレーヤーはシークを実行する前にストリーム全体がダウンロードされてインデックス登録されるまで待つ必要があります。ExoPlayer では、このケースでは精度よりも速度を優先することにしたため、FLAG_ENABLE_INDEX_SEEKING はデフォルトで無効になっています。

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

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

プレーヤーが動画内の新しい再生位置にシークするときは、次の 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_UNITSFLAG_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_MPDMimeTypes.APPLICATION_M3U8、または MimeTypes.APPLICATION_SSMediaItem.BuildersetMimeType に渡して、ストリームのタイプを明示的に指定することもできます。

2 番目の原因は、ExoPlayer が再生しようとしているメディアのコンテナ形式をサポートしていないことです。この場合、障害は意図したとおりに動作しています。ただし、コンテナ形式とテスト ストリームの詳細を含めて、公開バグトラッカーに機能リクエストを送信することは可能です。新しい機能をリクエストする前に、既存のリクエストを検索してください。

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

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

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

「Player is accessed on the wrong thread」エラーは何を意味しますか?

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

「Unexpected status line: ICY 200 OK」を修正するにはどうすればよいですか?

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

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

プレーヤーの isCurrentWindowLive メソッドをクエリできます。また、isCurrentWindowDynamic をチェックして、ウィンドウが動的かどうか(つまり、時間とともに更新され続けているかどうか)を確認することもできます。

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

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

  1. フォアグラウンド サービスが実行されている必要があります。これにより、リソースを解放するためにシステムがプロセスを強制終了するのを防ぐことができます。
  2. WifiLockWakeLock を保持する必要があります。これにより、システムは 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 の問題トラッカーで関連する最近の問題がないか確認してください。新しい問題を報告する必要があり、それがライブラリのネイティブ部分のビルドに関連する場合は、問題を診断するうえで役立つよう、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-frozen」ではないという事実のみを意味します。

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

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

Android Studio を使用すると、アノテーションを追加できます。

スクリーンショット: オプトイン アノテーションを追加する方法
図 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.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 アノテーションを使用することが重要です。