MediaPlayer の概要

Android マルチメディア フレームワークは、一般的なさまざまな種類のメディアの再生をサポートしているため、音声、動画、画像をアプリケーションに簡単に統合できます。MediaPlayer API を使用して、アプリのリソースに保存されているメディア ファイル(未加工リソース)、ファイル システム内のスタンドアロン ファイル、ネットワーク接続経由で到着するデータ ストリームから音声や動画を再生できます。

このドキュメントでは、優れたパフォーマンスと快適なユーザー エクスペリエンスを実現するために、MediaPlayer を使用して、ユーザーとシステムとやり取りするメディア再生アプリを作成する方法について説明します。または、ExoPlayer を使用することもできます。これは、MediaPlayer では使用できない高性能機能をサポートする、カスタマイズ可能なオープンソース ライブラリです。

注: 音声データは標準出力デバイスでのみ再生できます。現時点で該当するのは、モバイル デバイスのスピーカーまたは Bluetooth ヘッドセットです。通話中に会話の音声でサウンド ファイルを再生することはできません。

基本情報

Android フレームワークでの音声と動画の再生には、次のクラスを使用します。

MediaPlayer
このクラスは、音声と動画の再生においてメインとなる API です。
AudioManager
このクラスは、デバイスの音声ソースと音声出力の管理に使用します。

マニフェストの宣言

MediaPlayer を使用してアプリの開発を開始する前に、関連機能の使用を許可する適切な宣言がマニフェスト内に記述されていることを確認してください。

  • インターネット権限 - MediaPlayer を使用してネットワーク ベースのコンテンツをストリーミングする場合、アプリはネットワーク アクセスをリクエストする必要があります。
    <uses-permission android:name="android.permission.INTERNET" />
    
  • wake lock 権限 - プレーヤー アプリで画面が暗くならない、プロセッサがスリープ状態にならないようにする必要がある場合、または MediaPlayer.setScreenOnWhilePlaying() メソッドまたは MediaPlayer.setWakeMode() メソッドを使用する場合は、この権限をリクエストする必要があります。
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    

MediaPlayer の使用

メディア フレームワークの最も重要なコンポーネントの一つは、MediaPlayer クラスです。このクラスのオブジェクトは、最小限の設定で音声と動画の両方を取得、デコード、再生できます。次のようなさまざまなメディアソースがサポートされています。

  • ローカル リソース
  • コンテンツ リゾルバから取得できるような内部 URI
  • 外部 URL(ストリーミング)

Android がサポートするメディア形式の一覧については、サポートされているメディア形式のページをご覧ください。

次の例は、ローカルの未加工リソースとして利用可能な音声(アプリの res/raw/ ディレクトリに保存されます)を再生しています。

Kotlin

var mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1)
mediaPlayer.start() // no need to call prepare(); create() does that for you

Java

MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1);
mediaPlayer.start(); // no need to call prepare(); create() does that for you

この場合、「未加工」リソースとは、システムが特定の方法で解析を試みないファイルです。ただし、このリソースのコンテンツは未加工音声であってはなりません。サポートされている形式のいずれかで、適切にエンコードされフォーマットされたメディア ファイルである必要があります。

また、次のようにして、システムでローカルで利用可能な URI(たとえばコンテンツ リゾルバから取得したもの)から再生します。

Kotlin

val myUri: Uri = .... // initialize Uri here
val mediaPlayer = MediaPlayer().apply {
    setAudioAttributes(
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()
    )
    setDataSource(applicationContext, myUri)
    prepare()
    start()
}

Java

Uri myUri = ....; // initialize Uri here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(
    new AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .build()
);
mediaPlayer.setDataSource(getApplicationContext(), myUri);
mediaPlayer.prepare();
mediaPlayer.start();

リモート URL から HTTP ストリーミングで再生する方法は次のとおりです。

Kotlin

val url = "http://........" // your URL here
val mediaPlayer = MediaPlayer().apply {
    setAudioAttributes(
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()
    )
    setDataSource(url)
    prepare() // might take long! (for buffering, etc)
    start()
}

Java

String url = "http://........"; // your URL here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(
    new AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .build()
);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.start();

注: URL を渡してオンライン メディア ファイルをストリーミングする場合は、そのファイルがプログレッシブ ダウンロードに対応している必要があります。

注意: 参照しているファイルが存在しない可能性があるため、setDataSource() を使用する場合は、IllegalArgumentExceptionIOException をキャッチするか渡す必要があります。

非同期での準備

原則として、MediaPlayer の使用は簡単です。ただし、一般的な Android アプリと正しく統合するには、他にもいくつかの必要があることに留意する必要があります。たとえば、prepare() の呼び出しはメディアデータの取得とデコードを含むことがあるため、実行に時間がかかることがあります。そのため、実行に時間がかかるメソッドと同様に、アプリの UI スレッドからは決して呼び出さないでください。そのようにすると、メソッドが戻るまで UI がハングし、ユーザー エクスペリエンスが非常に悪くなり、ANR(アプリケーション応答なし)エラーが発生する可能性があります。リソースの読み込みが速くなることが期待できる場合でも、UI の応答に 10 分の 1 以上かかると、著しい一時停止が発生し、アプリが低速であるという印象をユーザーに与えることに留意してください。

UI スレッドがハングアップするのを回避するには、別のスレッドを生成して MediaPlayer を準備し、完了時にメインスレッドに通知します。スレッド ロジックは自分で記述することもできますが、このパターンは MediaPlayer を使用する場合にはよく見られるため、フレームワークでは prepareAsync() メソッドを使用してこのタスクを実行する便利な方法を提供しています。このメソッドは、バックグラウンドでメディアの準備を開始し、すぐに戻ります。メディアの準備が完了すると、setOnPreparedListener() で構成された MediaPlayer.OnPreparedListeneronPrepared() メソッドが呼び出されます。

状態の管理

MediaPlayer のもう 1 つの特長は、状態ベースであることです。つまり、MediaPlayer には、プレーヤーが特定の状態の場合にのみ有効なオペレーションがあるため、コードを記述するときに常に注意しなければならない内部状態があります。誤った状態のときにオペレーションを実行すると、システムが例外をスローしたり、他の望ましくない動作を引き起こす可能性があります。

MediaPlayer クラスのドキュメントでは、完全な状態図を示しており、どのメソッドが MediaPlayer をある状態から別の状態に移行するかを明確に示しています。たとえば、新しい MediaPlayer を作成すると、アイドル状態になります。その時点で setDataSource() を呼び出して初期化し、初期化済み状態にする必要があります。その後、prepare() または prepareAsync() メソッドを使用して準備する必要があります。MediaPlayer は準備が完了すると「準備完了」状態になります。つまり、start() を呼び出してメディアを再生できるようになります。この時点で、図に示すように、start()pause()seekTo() などのメソッドを呼び出すことにより、StartedPausedPlaybackCompleted の各状態間を移動できます。ただし、stop() を呼び出す際は、MediaPlayer を再度準備するまで、start() を再度呼び出すことはできません。

MediaPlayer オブジェクトとやり取りするコードを記述する際は、状態図を常に念頭に置いてください。誤った状態からメソッドを呼び出すと、バグのよくある原因となります。

MediaPlayer の解放

MediaPlayer は貴重なシステム リソースを消費する可能性があります。したがって、MediaPlayer インスタンスに必要以上に長くハングアップしないように、常に細心の注意を払う必要があります。終了したら、必ず release() を呼び出して、割り当てられたシステム リソースが適切に解放されるようにしてください。たとえば、MediaPlayer を使用していて、アクティビティが onStop() への呼び出しを受け取った場合は、MediaPlayer を解放する必要があります。アクティビティがユーザーとのやり取りをしていない間は、保持しても意味がほとんどないため(次のセクションでメディアを再生している場合を除きます)。もちろん、アクティビティを再開または再起動する場合は、新しい MediaPlayer を作成して、再生を再開する前に再度準備する必要があります。

MediaPlayer の解放と無効化は次のように行います。

Kotlin

mediaPlayer?.release()
mediaPlayer = null

Java

mediaPlayer.release();
mediaPlayer = null;

例として、アクティビティが停止したときに MediaPlayer を解放し忘れたが、アクティビティが再開したときに新しいものを作成した場合に発生する可能性がある問題を考えてみましょう。ご存じのとおり、ユーザーが画面の向きを変更する(または別の方法でデバイス構成を変更する)と、システムはアクティビティを再起動して(デフォルト)、それを処理するため、ユーザーがデバイスを縦向きと横向きの間で回転させると、すべてのシステム リソースを短時間で消費する可能性があります。これは、向きが変わるたびに解放されない新しい MediaPlayer が作成されるためです。ランタイムの再起動の詳細については、構成の変更を処理するをご覧ください。

ユーザーがアクティビティを離れた場合でも、「バックグラウンド メディア」の再生を継続したい場合、組み込みの音楽アプリの動作とほぼ同じ方法で、どうなるのか疑問に思われるかもしれません。この場合、次のセクションで説明するように、Service によって制御される MediaPlayer が必要になります。

サービス内での MediaPlayer の使用

アプリが画面にないときでもメディアをバックグラウンドで再生したい場合(つまり、ユーザーが他のアプリを操作している間も再生を続行したい場合)は、サービスを開始し、そこから MediaPlayer インスタンスを制御する必要があります。MediaPlayer を MediaBrowserServiceCompat サービスに埋め込み、別のアクティビティの MediaBrowserCompat とやり取りする必要があります。

このクライアント サーバーのセットアップには注意が必要です。バックグラウンド サービスで実行中のプレーヤーが、システムの他の部分とどのようにやり取りするかについて、想定された事項があります。アプリがこれらの期待に応えないと、ユーザー エクスペリエンスが低下する可能性があります。詳細については、オーディオ アプリの作成をご覧ください。

このセクションでは、サービス内に実装された MediaPlayer を管理する際の特別な手順について説明します。

非同期での実行

まず、Activity と同様に、Service 内の処理はすべて、デフォルトでは 1 つのスレッドで実行されます。実際、同じアプリからアクティビティとサービスを実行している場合、デフォルトでは同じスレッド(「メインスレッド」)を使用します。そのため、サービスは受信インテントを迅速に処理し、応答時に長時間の計算を実行しないようにする必要があります。負荷の高い処理やブロッキング呼び出しが予想される場合は、自分で実装する別のスレッドから、またはフレームワークの多くの機能を使用して非同期処理を行い、これらのタスクを非同期で実行する必要があります。

たとえば、メインスレッドから MediaPlayer を使用する場合、準備が完了してプレイを開始できるようになったときに通知を受け取れるように、prepare() ではなく prepareAsync() を呼び出し、MediaPlayer.OnPreparedListener を実装する必要があります。次に例を示します。

Kotlin

private const val ACTION_PLAY: String = "com.example.action.PLAY"

class MyService: Service(), MediaPlayer.OnPreparedListener {

    private var mMediaPlayer: MediaPlayer? = null

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        ...
        val action: String = intent.action
        when(action) {
            ACTION_PLAY -> {
                mMediaPlayer = ... // initialize it here
                mMediaPlayer?.apply {
                    setOnPreparedListener(this@MyService)
                    prepareAsync() // prepare async to not block main thread
                }

            }
        }
        ...
    }

    /** Called when MediaPlayer is ready */
    override fun onPrepared(mediaPlayer: MediaPlayer) {
        mediaPlayer.start()
    }
}

Java

public class MyService extends Service implements MediaPlayer.OnPreparedListener {
    private static final String ACTION_PLAY = "com.example.action.PLAY";
    MediaPlayer mediaPlayer = null;

    public int onStartCommand(Intent intent, int flags, int startId) {
        ...
        if (intent.getAction().equals(ACTION_PLAY)) {
            mediaPlayer = ... // initialize it here
            mediaPlayer.setOnPreparedListener(this);
            mediaPlayer.prepareAsync(); // prepare async to not block main thread
        }
    }

    /** Called when MediaPlayer is ready */
    public void onPrepared(MediaPlayer player) {
        player.start();
    }
}

非同期エラーの処理

同期オペレーションでは、通常、エラーは例外またはエラーコードで通知されますが、非同期リソースを使用するときは常に、アプリケーションにエラーが適切に通知されるようにする必要があります。MediaPlayer の場合は、MediaPlayer.OnErrorListener を実装して MediaPlayer インスタンスに設定することで、これを実現できます。

Kotlin

class MyService : Service(), MediaPlayer.OnErrorListener {

    private var mediaPlayer: MediaPlayer? = null

    fun initMediaPlayer() {
        // ...initialize the MediaPlayer here...
        mediaPlayer?.setOnErrorListener(this)
    }

    override fun onError(mp: MediaPlayer, what: Int, extra: Int): Boolean {
        // ... react appropriately ...
        // The MediaPlayer has moved to the Error state, must be reset!
    }
}

Java

public class MyService extends Service implements MediaPlayer.OnErrorListener {
    MediaPlayer mediaPlayer;

    public void initMediaPlayer() {
        // ...initialize the MediaPlayer here...
        mediaPlayer.setOnErrorListener(this);
    }

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        // ... react appropriately ...
        // The MediaPlayer has moved to the Error state, must be reset!
    }
}

エラーが発生すると、MediaPlayerエラー状態に移行します(完全な状態図については MediaPlayer クラスのドキュメントをご覧ください)。再び使用するには、リセットする必要があります。

wake lock の使用

バックグラウンドでメディアを再生するアプリを設計する場合、サービスの実行中にデバイスがスリープ状態になる可能性があります。Android システムはデバイスのスリープ時にバッテリーを節約しようとするため、CPU や Wi-Fi ハードウェアなど、スマートフォンの不要な機能を無効にしようとします。ただし、サービスで再生またはストリーミングしている場合は、システムが再生に干渉しないようにする必要があります。

このような条件下でもサービスの実行を継続するには、「wake lock」を使用する必要があります。wake lock は、スマートフォンがアイドル状態でも利用可能なままにすべき機能をアプリが使用していることをシステムに通知する方法です。

注: デバイスのバッテリー駆動時間が大幅に短くなるため、wake lock は慎重に使用し、本当に必要な期間だけ保持するようにしてください。

MediaPlayer の再生中も CPU が動作し続けるようにするには、MediaPlayer を初期化する際に setWakeMode() メソッドを呼び出します。この操作を行うと、MediaPlayer は指定されたロックを再生中に保持し、一時停止または停止時にロックを解除します。

Kotlin

mediaPlayer = MediaPlayer().apply {
    // ... other initialization here ...
    setWakeMode(applicationContext, PowerManager.PARTIAL_WAKE_LOCK)
}

Java

mediaPlayer = new MediaPlayer();
// ... other initialization here ...
mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);

ただし、この例で取得した wake lock では、CPU が実行され続けることのみが保証されます。ネットワーク経由でメディアをストリーミングし、Wi-Fi を使用している場合は、WifiLock も保持することをおすすめします。これは手動で取得および解放する必要があります。そのため、リモート URL を使用して MediaPlayer の準備を開始するときは、Wi-Fi ロックを作成して取得する必要があります。次に例を示します。

Kotlin

val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
val wifiLock: WifiManager.WifiLock =
    wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock")

wifiLock.acquire()

Java

WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
    .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");

wifiLock.acquire();

メディアを一時停止または停止するとき、またはネットワークが不要になったときは、ロックを解除する必要があります。

Kotlin

wifiLock.release()

Java

wifiLock.release();

クリーンアップの実施

前述のように、MediaPlayer オブジェクトはシステム リソースを大量に消費する可能性があるため、必要な期間だけ保持し、作業が終了したら release() を呼び出すようにしてください。ガベージ コレクタが MediaPlayer を回収するまでにしばらく時間がかかる可能性があるため、システムのガベージ コレクションに依存せずに、このクリーンアップ メソッドを明示的に呼び出すことが重要です。メモリのニーズにのみ影響し、他のメディア関連リソースの不足には影響しないためです。そのため、サービスを使用している場合は、必ず onDestroy() メソッドをオーバーライドして MediaPlayer を解放する必要があります。

Kotlin

class MyService : Service() {

    private var mediaPlayer: MediaPlayer? = null
    // ...

    override fun onDestroy() {
        super.onDestroy()
        mediaPlayer?.release()
    }
}

Java

public class MyService extends Service {
   MediaPlayer mediaPlayer;
   // ...

   @Override
   public void onDestroy() {
       super.onDestroy();
       if (mediaPlayer != null) mediaPlayer.release();
   }
}

MediaPlayer を解放する他の機会も常に探してください。シャットダウン時に解放する場合もあります。たとえば、音声フォーカスを失った後などにメディアを長時間再生できなくなることが予想される場合は、既存の MediaPlayer を解放し、後で再作成する必要があります。一方、再生を停止するまでの時間が非常に短い場合は、再度の作成と準備にかかるオーバーヘッドを回避するために、MediaPlayer をそのまま保持することをおすすめします。

デジタル著作権管理(DRM)

Android 8.0(API レベル 26)以降、MediaPlayer には、DRM で保護されたマテリアルの再生をサポートする API が含まれています。MediaDrm が提供する低レベル API に似ていますが、高レベルで動作し、基盤となる extractor オブジェクト、drm オブジェクト、crypto オブジェクトは公開しません。

MediaPlayer DRM API は、MediaDrm のすべての機能を提供していませんが、最も一般的なユースケースをサポートしています。現在の実装では、次のコンテンツ タイプを処理できます。

  • Widevine で保護されたローカル メディア ファイル
  • Widevine で保護されたリモート(またはストリーミング)メディア ファイル

次のコード スニペットは、単純な同期実装で新しい DRM MediaPlayer メソッドを使用する方法を示しています。

DRM で制御されたメディアを管理するには、次に示すように、MediaPlayer 呼び出しの通常のフローに加えて新しいメソッドを含める必要があります。

Kotlin

mediaPlayer?.apply {
    setDataSource()
    setOnDrmConfigHelper() // optional, for custom configuration
    prepare()
    drmInfo?.also {
        prepareDrm()
        getKeyRequest()
        provideKeyResponse()
    }

    // MediaPlayer is now ready to use
    start()
    // ...play/pause/resume...
    stop()
    releaseDrm()
}

Java

setDataSource();
setOnDrmConfigHelper(); // optional, for custom configuration
prepare();
if (getDrmInfo() != null) {
  prepareDrm();
  getKeyRequest();
  provideKeyResponse();
}

// MediaPlayer is now ready to use
start();
// ...play/pause/resume...
stop();
releaseDrm();

まず、MediaPlayer オブジェクトを初期化し、通常どおり setDataSource() を使用してそのソースを設定します。次に、DRM を使用するために、次の操作を行います。

  1. アプリでカスタム構成を行う場合は、OnDrmConfigHelper インターフェースを定義し、setOnDrmConfigHelper() を使用してプレーヤーにアタッチします。
  2. prepare() を呼び出します。
  3. getDrmInfo() を呼び出します。ソースに DRM コンテンツがある場合、このメソッドは null 以外の MediaPlayer.DrmInfo 値を返します。

MediaPlayer.DrmInfo が存在する場合:

  1. 使用可能な UUID のマップを調べ、1 つを選択します。
  2. prepareDrm() を呼び出して、現在のソースに対する DRM 設定を準備します。
    • OnDrmConfigHelper コールバックを作成して登録した場合、このコールバックは prepareDrm() の実行中に呼び出されます。これにより、DRM セッションを開く前に DRM プロパティのカスタム構成を実行できます。コールバックは、prepareDrm() を呼び出したスレッドで同期的に呼び出されます。DRM プロパティにアクセスするには、getDrmPropertyString()setDrmPropertyString() を呼び出します。長時間の操作は避けてください。
    • デバイスがまだプロビジョニングされていない場合、prepareDrm() はプロビジョニング サーバーにアクセスしてデバイスをプロビジョニングします。これには、ネットワーク接続によって異なります。
  3. ライセンス サーバーに送信する不透明なキー リクエストのバイト配列を取得するには、getKeyRequest() を呼び出します。
  4. ライセンス サーバーから受信した鍵レスポンスについて DRM エンジンに通知するには、provideKeyResponse() を呼び出します。結果は、鍵リクエストの種類によって異なります。
    • オフライン キーリクエストに対するレスポンスの場合、結果はキーセット ID になります。この鍵セットの識別子を restoreKeys() とともに使用すると、鍵を新しいセッションに復元できます。
    • ストリーミングまたは解放のリクエストに対するレスポンスの場合、結果は null になります。

非同期での prepareDrm() の実行

デフォルトでは、prepareDrm() は同期的に実行され、準備が完了するまでブロックされます。ただし、新しいデバイスで最初に行う DRM 準備では、プロビジョニングが必要になることもあります。これは prepareDrm() によって内部で処理され、関連するネットワーク操作のため、完了までに時間がかかることがあります。MediaPlayer.OnDrmPreparedListener を定義および設定すると、prepareDrm() でブロックを回避できます。

OnDrmPreparedListener を設定すると、prepareDrm() はプロビジョニング(必要な場合)と準備をバックグラウンドで実行します。プロビジョニングと準備が完了すると、リスナーが呼び出されます。呼び出しシーケンスやリスナーが実行されるスレッドについては推測しないでください(リスナーがハンドラ スレッドに登録されている場合を除きます)。リスナーは、prepareDrm() が返される前か後に呼び出すことができます。

非同期での DRM の設定

DRM 準備用の MediaPlayer.OnDrmInfoListener とプレーヤーを起動する MediaPlayer.OnDrmPreparedListener を作成および登録することで、DRM を非同期で初期化できます。これらは、以下に示すように prepareAsync() と連携して機能します。

Kotlin

setOnPreparedListener()
setOnDrmInfoListener()
setDataSource()
prepareAsync()
// ...

// If the data source content is protected you receive a call to the onDrmInfo() callback.
override fun onDrmInfo(mediaPlayer: MediaPlayer, drmInfo: MediaPlayer.DrmInfo) {
    mediaPlayer.apply {
        prepareDrm()
        getKeyRequest()
        provideKeyResponse()
    }
}

// When prepareAsync() finishes, you receive a call to the onPrepared() callback.
// If there is a DRM, onDrmInfo() sets it up before executing this callback,
// so you can start the player.
override fun onPrepared(mediaPlayer: MediaPlayer) {
    mediaPlayer.start()
}

Java

setOnPreparedListener();
setOnDrmInfoListener();
setDataSource();
prepareAsync();
// ...

// If the data source content is protected you receive a call to the onDrmInfo() callback.
onDrmInfo() {
  prepareDrm();
  getKeyRequest();
  provideKeyResponse();
}

// When prepareAsync() finishes, you receive a call to the onPrepared() callback.
// If there is a DRM, onDrmInfo() sets it up before executing this callback,
// so you can start the player.
onPrepared() {

start();
}

暗号化メディアの処理

Android 8.0(API レベル 26)以降では、MediaPlayer で、H.264 と AAC のエレメンタリー ストリーム タイプの共通暗号化スキーム(CENC)と HLS サンプルレベル暗号化メディア(METHOD=SAMPLE-AES)を復号することもできます。以前は、フルセグメント暗号化メディア(METHOD = AES-128)がサポートされていました。

ContentResolver からのメディアの取得

メディア プレーヤー アプリで役立つもう 1 つの機能は、ユーザーがデバイス上にある音楽を取得する機能です。これを行うには、次のように、外部メディアの ContentResolver にクエリを送信します。

Kotlin

val resolver: ContentResolver = contentResolver
val uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val cursor: Cursor? = resolver.query(uri, null, null, null, null)
when {
    cursor == null -> {
        // query failed, handle error.
    }
    !cursor.moveToFirst() -> {
        // no media on the device
    }
    else -> {
        val titleColumn: Int = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE)
        val idColumn: Int = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID)
        do {
            val thisId = cursor.getLong(idColumn)
            val thisTitle = cursor.getString(titleColumn)
            // ...process entry...
        } while (cursor.moveToNext())
    }
}
cursor?.close()

Java

ContentResolver contentResolver = getContentResolver();
Uri uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = contentResolver.query(uri, null, null, null, null);
if (cursor == null) {
    // query failed, handle error.
} else if (!cursor.moveToFirst()) {
    // no media on the device
} else {
    int titleColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);
    int idColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
    do {
       long thisId = cursor.getLong(idColumn);
       String thisTitle = cursor.getString(titleColumn);
       // ...process entry...
    } while (cursor.moveToNext());
}

これを MediaPlayer で使用するには、次のようにします。

Kotlin

val id: Long = /* retrieve it from somewhere */
val contentUri: Uri =
    ContentUris.withAppendedId(android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id )

mediaPlayer = MediaPlayer().apply {
    setAudioAttributes(
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()
    )
    setDataSource(applicationContext, contentUri)
}

// ...prepare and start...

Java

long id = /* retrieve it from somewhere */;
Uri contentUri = ContentUris.withAppendedId(
        android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);

mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(
    new AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .build()
);
mediaPlayer.setDataSource(getApplicationContext(), contentUri);

// ...prepare and start...

詳細

以下は音声と動画の録音、録画、保存、再生に関するトピックを扱うページです。