2013年7月4日木曜日

SoundPoolとMediaPlayerの使い分け

Androidで音を再生するにはSoundPoolとMediaPlayerの2つの方法があります。

1. SoundPoolとMediaPlayerの違い

SoundPool
SoundPoolは、再生時間が短い効果音などを扱うときに最適です。オーディオファイルがメモリに展開されている状態で再生を行うので、遅延がほとんどありません。また、複数の音声を同時に再生することができます。ただし、長いオーディをファイルを扱った場合、ファイルサイズが100kbを超えてしまうと、OutOfMemoryExceptionが発生してしまいます。

MediaPlayer
MediaPlayerは、BGMなど長い曲を再生するときに最適です。オーディオファイルは、毎回呼ばれるたびにメモリにロードされるので、メモリを節約することができます。しかし、再生を行う際に若干の遅延が生じてしまいます。MediaPlayerはオーディオだけでなくビデオも再生することができます。アプリのresourcesだけでなくSDカードにあるオーディオファイルやHTTPサーバに置かれたMP3ファイルを再生することができます。

2. SoundPoolの使い方

SoundExampleというActivityクラスを持つ以下のプログラムで説明していきます。ボタンを押した時に音声が鳴るというプログラムです。
public class SoundExample extends Activity implements OnClickListener{
 
 private SoundPool soundPool;
 private int[] soundRes = {R.raw.sample1, R.raw.sample2, R.raw.sample3};
 private int[] soundID;
 private Button btnSPPlay;
 private int index = 0;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.sound_example);
  //Setting Play Button
  btnSPPlay = (Button) findViewById(R.id.btnplay);
  btnSPPlay.setOnClickListener(this);
 }
 
 @Override
    protected void onResume() {
        super.onResume();
        //Setting SoundPool
  soundPool = new SoundPool(soundRes.length, AudioManager.STREAM_MUSIC, 0);
  soundID = new int[soundRes.length];
  for(int i = 0; i < soundRes.length; i++){
   //Loading sound files
   soundID[i] = soundPool.load(this, soundRes[i], 1);
  }
 }
 
 @Override
    protected void onPause() {
        super.onPause();
        //Releasing SoundPool
        soundPool.release();
 }
 
 @Override
 public void onClick(View v) {
  if(soundRes.length <= index) index = 0;
  if(v == btnSPPlay){
   //Playing Sound
    soundPool.play(soundID[index], 1.0F, 1.0F, 0, 0, 1.0F);
    ++index;
  }
 }
}
onResume()でSoundPoolを初期化しファイルをload()し、効果音を鳴らしたいイベントが発生をしたときにplay()をします。最後にonPause()でrelease()させます。SoundPoolはloadしたときにデータをメモリに展開します。よって、毎回アプリを起動させた時にファイルをloadし、終了したときにメモリを解放させたほうがメモリ効率がよくなります。

1. SoundPoolのインスタンス
まず最初にSoundPoolのインスタンスを生成します。
new SoundPool(soundRes.length, AudioManager.STREAM_MUSIC, 0);
  • maxStreams: 扱うファイルの最大数
  • streamType: Streamのタイプ(STREAM_MUSIC)
  • srcQuality:サンプリングレートのクオリティ(現在使用不可、デフォルト 0)
2. Load()
次に音声ファイルをloadしていきます。ファイルは/res/raw/に置きます。今回は3つのオーディオファイル(sample1.ogg, sample2.ogg, sample3.ogg)を用意しました。
SoundPool.load(this, soundRes[i], 1);
  • context: コンテキスト
  • resId: オーディオファイルのリソースID
  • priority: 優先度サンプルレートのクオリティ。(現在使用不可、デフォルト 1)
3. play()
音声を鳴らしたいイベントにplay()を設定します。複数のオーディオファイルを扱うには、soundIDで識別します。
soundPool.play(soundID[index], 1.0F, 1.0F, 0, 0, 1.0F);
  • soundID … load()で返された soundID
  • leftVolume … 左の音量 (0.0~1.0)
  • rightVolume … 右の音量 (0.0~1.0)
  • priority … ストリームの優先度 (0: 優先度最低)
  • loop … ループ回数 (0: ループ無し、-1: 無限ループ)
  • rate … 再生レート (0.5~2.0 1.0が標準)
4. release()
最後onPause()でSoundPoolをrelease()します。ファイルをメモリから解放します。
soundPool.release();

Android 4.3ではSoundPoolのloopが効かないバグの報告があります。

3. MediaPlayerの使い方
SoundMPExampleというActivityクラスを持つ以下のプログラムで説明していきます。スタートボタンで音声が流れ、Pauseボタンで停止をします。

public class MediaPlayerExample extends Activity implements OnClickListener{
 private MediaPlayer mediaPlayer;
 private Button btnPlay, btnPause;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.sound_example);
  
  //From Resource
  mediaPlayer = MediaPlayer.create(this, R.raw.sample);
  
  //Setting Button
  btnPlay = (Button) findViewById(R.id.btnplay);
  btnPlay.setOnClickListener(this);
  btnPlay = (Button) findViewById(R.id.btnpause);
  btnPlay.setOnClickListener(this);
 }

 @Override
 public void onClick(View v) {
  if(v == btnPlay){
   //Start playing a sound
   mediaPlayer.start();
  }
  if(v == btnPause){
   //Pause playing a sound
   mediaPlayer.pause();
  }
 }
 
 @Override
    protected void onPause() {
        super.onPause();
        //Pause playing a sound
        mediaPlayer.pause();
 }
 
 @Override
    protected void onDestroy() {
        super.onDestroy();
        //Releasing SoundPool
        mediaPlayer.stop();
        mediaPlayer.release();
        mediaPlayer = null;
      
 }
}
onCreate()でMadiaPlayerを初期化します。play()で再生、pause()で停止します。

1. MadiaPlayerの初期化
リソースからの場合
オーディオファイルは/res/raw/以下に置きます。ここでは/res/raw/sample.mp3としています。
MediaPlayer.create(this, R.raw.sample);
  • Context: コンテキスト
  • resId: リソースID
ローカル/htmlからの場合
ローカルファイルを扱う場合には、setDataSource()を使用します。setDataSource()の後にprepare()が必要になります。
ファイルパスを使用する場合
String url = Environment.getExternalStorageDirectory() + "/sample.mp3";
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare();
Uriを使用する場合
Uri mUri = Uri.parse(Environment.getExternalStorageDirectory() + "/sample.mp3");
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(getApplicationContext(), mUri);
mediaPlayer.prepare();
2. start()
start()で再生されます。

3. pause()
pause()で停止します。stop()でも停止しますが、stop()を使用した時には後に再生する前にprepare()が必要になります。