【Android】MediaPlayer について
アプリのリソース(生リソース)に保存されたメディア ファイル、ファイルシステム内のスタンドアロン ファイル、ネットワーク接続を介したデータ ストリーミングからの音声や動画の再生を、すべて MediaPlayer API を使用して行えます。
注: 音声データは標準出力デバイスでのみ再生できます。現時点で該当するのは、モバイル デバイスのスピーカーまたは Bluetooth ヘッドセットです。通話中に音声ファイルを再生して会話の音声にすることはできません。
通話音声をソースにするといったことはできないらしい。
Android フレームワークでの音声と動画の再生には、次のクラスを使用します。
- MediaPlayer: このクラスは、音声と動画の再生においてメインとなる API です。
- AudioManager: このクラスは、デバイスの音声ソースと音声出力の管理に使用します。
簡単な使い方
リソースから再生
var mediaPlayer: MediaPlayer? = MediaPlayer.create(context, R.raw.sound_file_1)
mediaPlayer?.start() // no need to call prepare(); create() does that for you
HTTP ストリーミング再生
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()
}
非同期
MediaPlayer の使い方は、原則的には簡単です。ただし、通常の Android アプリと適切に統合するには、さらにいくつかの注意事項があります。たとえば、prepare() の呼び出しは、メディアデータのフェッチとデコードを伴う可能性があるため、実行に時間がかかる場合があります。
UI スレッドのハングを回避するには、別のスレッドを生成して MediaPlayer の準備を行い、完了したらメインスレッドに通知するようにします。このスレッド処理のロジックは、自分で記述することもできます。ただ、この処理は MediaPlayer を使用する場合にはよく行われるため、フレームワークにはそのための prepareAsync() メソッドが用意されており、これを使用するほうが便利です。このメソッドは、バックグラウンドでメディアの準備を開始すると、すぐに戻ってきます。メディアの準備が完了したら、setOnPreparedListener() で設定した MediaPlayer.OnPreparedListener の onPrepared() メソッドが呼び出されます。
状態の管理
MediaPlayer についてもう一つ忘れてはならないのが、状態ベースであるという点です。つまり、操作によっては、プレーヤーが特定の状態のときにのみ有効になります。そのため、コードを記述する際には、常に MediaPlayer の内部状態を意識する必要があります。状態に適さない操作を行うと、システムから例外がスローされるなど、望ましくない動作が発生する可能性があります。
状態に合わないメソッドの呼び出しは、よく見られるバグです。MediaPlayer オブジェクトを操作するコードを記述する際は、常に状態遷移図を念頭に置いてください。
状態遷移図

MediaPlayer の解放
MediaPlayer は、貴重なシステム リソースを消費しうるものです。 そのため、MediaPlayer インスタンスが必要以上に長く存在することのないよう、常に特別な措置を講じなければなりません。使用を終了したら必ず release() を呼び出して、割り当てられたシステム リソースが適切に解放されるようにする必要があります。
たとえば、MediaPlayer を使用中にアクティビティで onStop() 呼び出しを受け取った場合は、MediaPlayer を解放する必要があります。
例として、MediaPlayer をアクティビティ停止時に解放し忘れ、アクティビティ再開時に新しく作成した場合に起こりうる問題を考えてみましょう。ご存知のように、ユーザーが画面の向きを変更する(またはそのようにデバイス設定を変更する)と、その処理のためにシステムによってアクティビティが再起動されます(デフォルトの場合)。これにより、ユーザーがデバイスの縦向きと横向きを切り替えるたびに、大量のシステム リソースが一度に消費されることになります。向きが変わるたびに、MediaPlayer が解放されず、新たに作成されるためです。ランタイムの再起動の詳細については、構成の変更を処理するをご覧ください。
※ ミュージックプレイヤーのようにバックグラウンドで再生したい場合を除く
AudioFocus
複数の Android アプリから同じ出力ストリームに対して、同時に音声を再生できます。この場合、システムによりすべての音声がミックスされます。これは技術者から見るとすばらしいことですが、ユーザーにとっては厄介な場合があります。そこで、それぞれの音楽アプリで一斉に再生が行われるのを避けるために、Android では「音声フォーカス」という概念が導入されています。一度に 1 つのアプリのみが音声フォーカスを保持できる、という概念です。
自動ダッキング
Android 8.0(API レベル 26)では、別のアプリから AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK でフォーカスがリクエストされた際、システムによる自動での音量のダッキングと復元が可能です。その際、アプリの onAudioFocusChange() コールバックは呼び出されません。
※ 自動ダッキングとは、「BGMをしゃべっている所だけ自動で下げて聞きやすくする」というような意味