文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处http://blog.csdn.net/flowingflying/以及作者@恺风Wei。
MediaPlayer在一个时间只能处理一个音频或视频文件,如果我们需要同时播放多个音频文件,可以创建多个MediaPlayer。如果我们有若干个的音频需要播放,还可以使用SoundPool类,SoundPool类使用了MediaPlayer,但我们不需要访问MediaPlayer API,而是简洁使用SoundPool API。
SoundPool只能处理本地媒体资源。SoundPool为了提高播放性能,使用了内存,使用总量限制为1MB。放入内存多少,和比特率、采样频率、channel数(单声道、双声道,杜比的5.1声道)以及音频的长度有关,如果太大,可能会导致加载失败。SoundPool适合短小但经常反复播放的若干音频。
我们有5个音频资源,4个位于res/raw,1个位于assets/下面,这些都是时间很短的音频文件。crickets.mp3作为背景音乐不断地循环放松,而其他的4个音乐分别隔某个时间间隔(例如5秒)播放一次。
UI很简单,上面是一个ToggleButton,在暂停和播放之间切换,下面是debug信息的显示。
我们重点关注代码如何具体利用SoundPool来实现音频播放、循环播放、暂停、继续播放的控制。
public class SoundPoolActivity extends Activity implements SoundPool.OnLoadCompleteListener{
private SoundPool soundpool = null;
private AudioManager audioManager = null;
private int sid_background,sid_roar,sid_chimp,sid_rooster,sid_bark;
… …
@Override
protected void onResume() {
super.onResume();
/* 【1】创建我们的SoundPool对象:第一个参数是SoundPool同时共同播放多上个音乐,注意是最大的同时播放数,而不是由多少音频资源。第二参数是音频类型,一般为STREAM_MUSIC;第三个参数目前没有使用,reference建议为0 。*/
soundpool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
/* 【3.pre】将资源load()到SoundPool后,才可以进行播放,因此,需要完成load的回调函数。*/
soundpool.setOnLoadCompleteListener(this);
// 用于获取当前的音量,后面有用
audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
/* 【2】SoundPool load入音频资源,音频流会从文件中解码,放入内存,这提高了SoundPool的性能。我们给出了用资源和fd方式。对于SD卡,可以用soundpool.load("/mnt/sdcard/abc.mp3",1); load()参数的最后一位是PRIORITY,目前没有真正使用,reference建议设置为1,以便兼容未来版本。*/
sid_background = soundpool.load(this, R.raw.crickets, 1);
sid_roar = soundpool.load(this, R.raw.roar, 1);
sid_rooster = soundpool.load(this, R.raw.rooster, 1);
sid_chimp = soundpool.load(this, R.raw.chimp, 1);
try{
AssetFileDescriptor afd = getAssets().openFd("dogbark.mp3");
sid_bark = soundpool.load(afd.getFileDescriptor(), 0, afd.getLength(), SOUNDPOOL_LOAD_PRIORITY);
afd.close();
}catch(Exception e){
e.printStackTrace();
}
debug(… …);
}
@Override
protected void onPause() {
soundpool.release(); //停止并释放资源,而停止某个媒体流的播放可以是用stop(sid);SoundPool会释放该媒体流的资源。
soundpool = null;
super.onPause();
}
public void doClick(View v){
debug … …
if(((ToggleButton)v).isChecked()){
soundpool.autoResume(); //恢复停止播放的音频流,在本例,在某些情况下,不能重新播放背景音,这是因为我们设置了最大同时播放数为5个,假设5个音频同时播放时,我们按了暂停,resume()是刚好又轮到某个音频流再次播放,这时同时播放数会超过设置的最大数,SoundPool会让出最早的音频流,腾出位置给新的声音。
}else{
soundpool.autoPause(); //会暂停当前播放的音频流,在本例,背景音频流会播放,但是对于通过queueSound()的未来播放不会被终止。
}
}
@Override //load完后,进行播放,
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
debug("sid " + sampleId + " status=" + status);
if(status != 0)
return;
// 获取当前音量,音量范围:0-1.0
final float currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
/ (float)audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
// 如果是背景声音,则不断循环播放,如果是其他,则已某个间隔时间播放
/* play() 第一个参数是音频的id;第二和第三个分别是左右音量;第四个参数是音频流的优先级别,0是最低的基本;第5参数标识是否循环播放,0标识不循环,-1表示循环;第6个参数是播放速率,1.0标识按正常速率播放,有效范围是0.5-2.0。如果成功返回音频流的Id,失败返回0 */
if(soundPool.play(sid_background, currentVolume, currentVolume, 1, -1, 1.0f) == 0){
debug("Failed to start sound " + sampleId);
}else if(sampleId == sid_chimp){
queueSound(sampleId,5000,currentVolume); //延后定期发送
}else if(sampleId == sid_rooster){
queueSound(sampleId, 17000, currentVolume);
}else if(sampleId == sid_roar){
queueSound(sampleId, 12000, currentVolume);
}else if(sampleId == sid_bark){
queueSound(sampleId, 7000, currentVolume);
}
}
//利用handler实现固定时间间隔的播放,不同的音频流的间隔时间均不同,我们可以听到1~5个音频的混音效果。
private void queueSound(final int sid , final long delay , final float volume){
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
debug("sid " + sid + " queueSound() run in " + Thread.currentThread().getName());
if(soundpool == null) //如果已经onPause(),即soundpool==null,将停止播放及未来播放
return;
if(soundpool.play(sid, volume, volume, 1, 0, 1.0f) == 0){
debug("Fail to start sound " + sid);
}
//每隔delay的时间,重复播放
queueSound(sid, delay, volume);
}
}, delay);
}
private void debug(String info){
… …
}
}
小例子代码在:Pro Android学习:media framworks小例子
相关链接:我的Android开发相关文章