MediaPlayer の概要

Android マルチメディア フレームワークは、音声、動画、画像のアプリへの統合を容易に行えるようにするため、一般に使用されているさまざまなメディアタイプの再生をサポートしています。アプリのリソース(生リソース)に保存されたメディア ファイル、ファイルシステム内のスタンドアロン ファイル、ネットワーク接続を介したデータ ストリーミングからの音声や動画の再生を、すべて MediaPlayer API を使用して行えます。

このドキュメントでは、優れたパフォーマンスと快適なユーザー エクスペリエンスが得られるようユーザーおよびシステムとやりとりを行うメディア再生アプリの作成方法を説明します。

注: 音声データは標準出力デバイスでのみ再生できます。現時点で該当するのは、モバイル デバイスのスピーカーまたは 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? = 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? = MediaPlayer().apply {
        setAudioStreamType(AudioManager.STREAM_MUSIC)
        setDataSource(applicationContext, myUri)
        prepare()
        start()
    }
    

Java

    Uri myUri = ....; // initialize Uri here
    MediaPlayer mediaPlayer = new MediaPlayer();
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    mediaPlayer.setDataSource(getApplicationContext(), myUri);
    mediaPlayer.prepare();
    mediaPlayer.start();
    

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

Kotlin

    val url = "http://........" // your URL here
    val mediaPlayer: MediaPlayer? = MediaPlayer().apply {
        setAudioStreamType(AudioManager.STREAM_MUSIC)
        setDataSource(url)
        prepare() // might take long! (for buffering, etc)
        start()
    }
    

Java

    String url = "http://........"; // your URL here
    MediaPlayer mediaPlayer = new MediaPlayer();
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    mediaPlayer.setDataSource(url);
    mediaPlayer.prepare(); // might take long! (for buffering, etc)
    mediaPlayer.start();
    

注: URL を渡してオンライン メディア ファイルをストリーミングする場合は、そのファイルがプログレッシブ ダウンロード可能でなければなりません。

注意: 参照するファイルが存在しない可能性もあるため、setDataSource() を使用する場合は、IllegalArgumentExceptionIOException を catch または pass する必要があります。

非同期での準備

MediaPlayer の使い方は、原則的には簡単です。ただし、通常の Android アプリと適切に統合するには、さらにいくつかの注意事項があります。たとえば、prepare() の呼び出しは、メディアデータのフェッチとデコードを伴う可能性があるため、実行に時間がかかる場合があります。そのため、実行に時間がかかる可能性のある他のメソッドと同様、アプリの UI スレッドから呼び出さないようにしなければなりません。UI スレッドから呼び出してしまうと、メソッドが返されるまで UI がハングし、ユーザー エクスペリエンスの低下や ANR(アプリケーション応答なし)エラーを招く可能性があるためです。リソースの読み込みはすぐに終わると思われる場合でも、UI のレスポンスに 1/10 秒以上かかると顕著な一時停止が発生すること、ユーザーに遅いアプリという印象を与えることを忘れないでください。

UI スレッドのハングを回避するには、別のスレッドを生成して MediaPlayer の準備を行い、完了したらメインスレッドに通知するようにします。このスレッド処理のロジックは、自分で記述することもできます。ただ、この処理は MediaPlayer を使用する場合にはよく行われるため、フレームワークにはそのための prepareAsync() メソッドが用意されており、これを使用するほうが便利です。このメソッドは、バックグラウンドでメディアの準備を開始すると、すぐに戻ってきます。メディアの準備が完了したら、setOnPreparedListener() で設定した MediaPlayer.OnPreparedListeneronPrepared() メソッドが呼び出されます。

状態の管理

MediaPlayer についてもう一つ忘れてはならないのが、状態ベースであるという点です。つまり、操作によっては、プレーヤーが特定の状態のときにのみ有効になります。そのため、コードを記述する際には、常に MediaPlayer の内部状態を意識する必要があります。状態に適さない操作を行うと、システムから例外がスローされるなど、望ましくない動作が発生する可能性があります。

MediaPlayer クラスのドキュメントには完全な状態遷移図が示されており、 の状態がどのメソッドによりどう変わるかがわかるようになっています。 たとえば、新たに作成された MediaPlayer は「アイドル」状態です。その時点で、setDataSource() を呼び出して初期化する必要がありますが、それにより「初期化済み」状態になります。その後、prepare() メソッドまたは prepareAsync() メソッドを使用して準備する必要があります。MediaPlayer の準備が完了すると、「準備完了」状態になります。つまり、start() を呼び出してメディアを再生できます。図が示すように、この時点では、start()pause()seekTo() などのメソッドを呼び出すことで、「開始済み」、「一時停止」、「再生完了」の各状態間を行き来できます。ただし、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 が解放されず、新たに作成されるためです。ランタイムの再起動の詳細については、構成の変更を処理するをご覧ください。

ユーザーがアクティビティを離れた場合でも、組み込みの音楽アプリで行うのと同様に、「バックグラウンド メディア」の再生を続けたい場合はどうすればよいか、という疑問が生じるかもしれません。その場合は、次のセクションで説明するように、サービスで制御する MediaPlayer が必要になります。

サービス内での MediaPlayer の使用

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

このクライアント サーバーのセットアップには注意が必要です。バックグラウンド サービスで実行されるプレーヤーと、システムの他の部分とのやりとりの方法に、いくつかの前提があるためです。アプリがこれらの前提を満たさない場合は、ユーザー エクスペリエンスが低下する可能性があります。詳細については、オーディオ アプリの作成をご覧ください。

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

非同期での実行

まず大事なことは、Activity と同様に、Service 内の作業はデフォルトですべて単一のスレッドで行われるということです。実際に、アクティビティとサービスを同じアプリから実行すると、デフォルトでは両方とも同じスレッド(「メインスレッド」)を使用します。そのため、サービスでは受信インテントを迅速に処理し、応答に時間がかかる計算は行わないようにする必要があります。負荷の高い作業や進行を妨げる呼び出しになると予測されるタスクは、非同期で実行する必要があります。そのためには、別のスレッドを自分で実装するか、Android フレームワークがサポートするさまざまな非同期処理用の仕組みを使用します。

たとえば、メインスレッドから 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 は「エラー」状態に移行し(完全な状態遷移図については クラスのドキュメントを参照)、再び使用するにはリセットが必要になるので注意してください。

wake lock の使用

バックグラウンドでメディアを再生するアプリを設計する際には、サービスの実行中にデバイスがスリープ状態になることも考慮する必要があります。Android システムでは、デバイスのスリープ中は電池を節約するため、CPU や Wi-Fi のハードウェアなど、不要なスマートフォン機能がすべてオフになります。 しかし、サービスで音楽を再生またはストリーミングしている場合は、それがシステムにより妨げられないようにする必要があります。

このような状況下でもサービスが実行され続けるようにするには、「wake lock」を使用する必要があります。wake lock とは、スマートフォンがアイドル状態でも、アプリで使用中の機能はそのまま使用可能にしておく必要があることをシステムに伝える方法です。

注意: wake lock は、常に慎重に判断のうえ、本当に必要な場合にのみ使用してください。これを使用すると、デバイスの電池寿命が大幅に短くなるためです。

MediaPlayer の再生中は CPU が実行され続けるようにするには、 の初期化時に 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 も保持すべきですが、これについては手動で取得と解除を行う必要があります。Wi-Fi ロックの作成と取得は、リモート URL を使用して MediaPlayer の準備を開始するときに行います。 コード例を以下に示します。

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 で保護されたリモート(またはストリーミング)メディア ファイル

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

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();
    

まずは、通常どおり setDataSource() を使用してソースの設定を行い、MediaPlayer オブジェクトを初期化します。次に、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 になります。このキーセット ID を使用して restoreKeys() を呼び出すことにより、キーを新しいセッションに復元できます。
    • ストリーミングまたは解放のリクエストに対するレスポンスの場合、結果は null になります。

非同期での prepareDrm() の実行

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

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 では、共通暗号化スキーム(CENC)と、基本的なストリーミング タイプである H.264 および AAC 用の HLS サンプルレベル暗号化メディア(METHOD=SAMPLE-AES)の復号も可能です。以前は、フルセグメント暗号化メディア(METHOD = AES-128)がサポートされていました。

ContentResolver からのメディアの取得

メディア プレーヤー アプリでもう一つ便利なのは、ユーザーがデバイスに保存した音楽を取得できる機能です。これを行うには、次のように、外部メディアの 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 {
        setAudioStreamType(AudioManager.STREAM_MUSIC)
        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.setAudioStreamType(AudioManager.STREAM_MUSIC);
    mediaPlayer.setDataSource(getApplicationContext(), contentUri);

    // ...prepare and start...
    

サンプルコード

BasicMediaDecoder サンプルと DeviceOwner サンプルは、このページで説明した API の使用方法を示しています。

詳細

下記のページでは、音声と動画の記録、保存、再生について説明しています。