Android音频之SoundPool
14 Sep 2013Android提供了两种不同的框架来处理音频,分别是:
MediaPlayer / MediaRecoder
:处理音频的标准方法,但数据源必须是文件或者基于流的数据。使用这个类处理音频文件的时候须有创建自己的线程运行。本文要说的SoundPool类就是使用了这个框架。AudioTrack / AudioRecoder
:该框架支持直接访问原始音频文件。用于在内存中处理音频文件,或者开始播放音频的同时写入缓冲区,或者在其他不需要文件和数据流的场合中使用。运行过程中不需要创建新线程。
SoundPool
和MediaPlayer主要用来播放一些长音频不同,SoundPool一般用来处理一些短的但是带有重叠,回放等特效的音频。这是因为SoundPool带有一个音频缓冲区,可以很方便的支持音频的回放、快放和慢放。
使用SoundPool的基本步骤
- 初始化
- 加载资源
- 播放
- 释放资源
测试SoundPool
我在测试过程中发现不能播放大于1M的音频文件,所以这里使用一个900K的sound.wav做测试。在点击Play后,音乐将重复播放5次(mySP.play(soundId, 1f, 1f, 1, 5, rate)中的第5个参数指定),每重复点击Play按钮,音乐会降低一半速率播放(mySP.play(soundId, 1f, 1f, 1, 5, rate)中的第6个参数指定)。测试程序同时最大可以叠加10个音频(SoundPool(10, AudioManager.STREAM_MUSIC, 0)中的第1个参数指定)。
public class AudioExamplesSP extends Activity {
static float rate = 2f;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button playButton = (Button) findViewById(R.id.play_pause);
final SoundPool mySP = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
final int soundId = mySP.load(this, R.raw.sound, 1);
playButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
rate = rate / 2;
mySP.play(soundId, 1f, 1f, 1, 5, rate);
}
});
}
}
可能的问题
如果在播放中出现下面的错误:
sample 1 not READY
原因是SoundPool需要自己在后台启动一个线程来做音频回放,当调用SoundPool.load()加载资源后立即调用SoundPool.play()进行播放的时候,有可能出现资源加载未完成的情况,在这种情况下就可能出现上面的错误。解决的方法如下:
- 把启动播放的事件跟一个用户事件关联起来。如上面的例子。
- 重复测试Sound.play()的返回值,例如:
int sid = 0;
for(int i = 0; i < 1000; i++) {
if(sid == 0) {
try {
rate = rate / 2;
sid = mySP.play(soundId, 1f, 1f, 1, 5, rate);
Thread.sleep(1);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
break;
}
}
为SoundPool设置OnLoadCompleteListener:
这个监听器需要Android2.2
以上才能使用。例如:
mySP.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
@Override
public void onLoadComplete(SoundPool arg0, int arg1, int arg2) {
mySP.play(soundId, 1f, 1f, 1, 5, rate);
}
});