标签:性能 bsp item listen 延时 this get data 二进制
final int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)
如果应用程序经常播放密集、急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了。因为MediaPlayer存在如下缺点:
- 1) 延时时间较长,且资源占用率高。
- 2) 不支持多个音频同时播放。
Android中除了MediaPlayer播放音频之外还提供了SoundPool来播放音效,SoundPool使用【音效池】的概念来管理多个短促的音效,例如它可以开始就加载20个音效,以后在程序中按音效的ID进行播放。SoundPool主要用于播放一些较短的声音片段,与MediaPlayer相比,SoundPool的优势在于CPU资源占用量低和反应延迟小。SoundPool和其他声音播放类相比,其特点是可以自行设置声音的品质、音量、播放比率等参数。并且它可以同时管理多个音频流,每个流都有独自的ID,对某个音频流的管理都是通过ID进行的。实际使用SoundPool播放声音时需要注意:
- SoundPool最大只能申请1M的内存空间,这就意味着我们只能用一些很短的声音片段,而不是用它来播放歌曲或者做游戏背景音乐。
- SoundPool提供了pause和stop方法,但这些方法建议最好不要轻易使用,因为有些时候它们可能会使你的程序莫名其妙的终止。有些朋友反映它们不会立即中止播放声音,而是把缓冲区里的数据播放完才会停下来,也许会多播放一秒钟。
- 流的加载过程是一个将音频解压为原始16位PCM数据的过程,由一个后台线程来进行异步处理,所以初始化后不能立即播放,需要等待一点时间。
- SoundPool的效率在这些播放类中算是很好的了,但也不是绝对不存在延迟问题,尤其在那些性能不太好的手机中,SoundPool的延迟问题可能会很严重。
public class SoundPoolActivity extends ListActivity {
private SoundPool soundPool;
private List<Integer> soundIdList = new ArrayList<>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] array = {
//0-6
"通过一个资源ID:R.raw.s1_message,无限循环",
"通过一个资源ID:R.raw.s10_42kb,能完整播放,循环2次,速度1.5倍,音量右0.1",
"通过一个资源ID:caravan_15s_59kb,能完整播放,速度0.5倍,音量左0.1",
"通过一个资源ID:R.raw.s8_67kb,虽然时间短,占空间也小,但是不能完全播放",
"通过一个资源ID:ljsw_35s_68kb,虽然时间比较长,但是能完整播放",
"通过一个资源ID:ljsw_49s_102kb,但是这个就不能完整播放了",
"通过一个资源ID:hellow_tomorrow_6s_237kb,虽然占空间比较大,但是也能完整播放",
//7-10
"通过指定的路径:文件路径,caravan.mp3(不能播放网络资源)",
"通过AssetFileDescriptor:assets目录下的文件,caravan_15s_59kb.mp3",
"通过FileDescriptor:assets目录下的文件,可以播放文件指定的某一部分",
"通过AssetFileDescriptor:raw目录下的文件,R.raw.s1_system",
//11-14
"全部流的暂停播放",
"恢复播放",
"卸载指定soundId的音频资源",
"释放全部资源"
};
for (int i = 0; i < array.length; i++) {
array[i] = i + "、" + array[i];
}
setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, new ArrayList<>(Arrays.asList(array))));
soundPool = new SoundPool.Builder()
.setMaxStreams(5)
.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build())
.build();
soundPool.setOnLoadCompleteListener((soundPool1, sampleId, status) -> {
Log.i("bqt", "【onLoadComplete】" + sampleId + " " + status);//status : 0 = success
});
new Thread(this::initReseResources).start();//在子线程中初始化,特别是当有大量资源需要初始化时
}
private void initReseResources() {
Context context = this.getApplicationContext();//不管使用哪个Context,退出当前Activity后都会且会在延迟几秒钟后停止播放
//0-6,通过一个资源ID:Context context, int resId, int priority
soundIdList.add(soundPool.load(context, R.raw.s1_message, 0));
soundIdList.add(soundPool.load(context, R.raw.s10_42kb, 0));
soundIdList.add(soundPool.load(context, R.raw.caravan_15s_59kb, 0));
soundIdList.add(soundPool.load(context, R.raw.s8_67kb, 0));
soundIdList.add(soundPool.load(context, R.raw.ljsw_35s_68kb, 0));
soundIdList.add(soundPool.load(context, R.raw.ljsw_49s_102kb, 0));
soundIdList.add(soundPool.load(context, R.raw.hellow_tomorrow_6s_237kb, 0));
//7,通过指定的路径:String path, int priority
soundIdList.add(soundIdList.size(), 0);//如果文件不存在,则就不能set,否则会throw IndexOutOfBoundsException
String path = Environment.getExternalStorageDirectory() + File.separator + "caravan.mp3";
soundIdList.set(soundIdList.size() - 1, soundPool.load(path, 0));//注意:add和set时传入的index是不一样的!
//8-9,通过AssetFileDescriptor:AssetFileDescriptor afd, int priority
try {
soundIdList.add(soundIdList.size(), 0);//为防止异常后后续的代码执行不到导致index错乱,我们在一开始就直接add两个
soundIdList.add(soundIdList.size(), 0);
AssetFileDescriptor afd = getAssets().openFd("voice/caravan_15s_59kb.mp3");//openNonAssetFd
soundIdList.set(soundIdList.size() - 2, soundPool.load(afd, 0));
//通过FileDescriptor:FileDescriptor fd, long offset, long length, int priority
FileDescriptor fd = afd.getFileDescriptor();
long offset = afd.getStartOffset(), length = afd.getLength();
Log.i("bqt", "【afd】offset=" + offset + ",length=" + length);//offset=40786180,length=60480
soundIdList.set(soundIdList.size() - 1, soundPool.load(fd, offset + length / 2, length / 2, 0));
} catch (IOException e) {
e.printStackTrace();
}
//10
soundIdList.add(soundPool.load(getResources().openRawResourceFd(R.raw.s1_global), 0));
}
@Override
protected void onDestroy() {
super.onDestroy();
soundPool.release();//释放所有资源
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
if (position <= 10) {
int soundID = soundIdList.get(position);
int loop = 0;//0 = no loop, -1 = loop forever
if (position == 0) loop = -1;
else if (position == 1) loop = 2;//3次
//播放指定soundID的音频:【int soundID】, float leftVolume, float rightVolume,int priority, 【int loop】, float rate
int streamID = soundPool.play(soundID, 1.0f, 1.0f, 1, loop, 1.0f);
Toast.makeText(this, "soundID=" + soundID + " streamID=" + streamID, Toast.LENGTH_SHORT).show();
//指定streamID的参数进行设置,这些参数都可以在播放时指定
soundPool.setLoop(streamID, 1);//实践证明,这里设置无效
switch (position) {
case 1:
soundPool.setRate(streamID, 1.5f);//大小并没有限制,但是一般不要小于0.5,不要大于1.5,否则声音严重失真
soundPool.setVolume(streamID, 1.0f, 0.1f);//只能降低,不能提高。The value must be in the range of 0.0 to 1.0
break;
case 2:
soundPool.setRate(streamID, 0.5f);
soundPool.setVolume(streamID, 0.1f, 1.0f);
break;
}
} else {
switch (position) {
case 11:
soundPool.autoPause();//可以多次调用,每次都是把当前正在播放的音乐暂停,并加入同一个列表中
break;
case 12:
soundPool.autoResume();//将所有暂停的音乐从暂停位置重新开始播放
break;
case 13:
Toast.makeText(this, "" + soundPool.unload(soundIdList.get(0)) + " " + soundPool.unload(soundIdList.get(1))
, Toast.LENGTH_SHORT).show();//unload并不能停止正在播放的音乐,特别是loop=-1的,仍会循环播放
break;
case 14:
soundPool.release();//会停止正在播放的所有音乐
break;
}
}
}
}
标签:性能 bsp item listen 延时 this get data 二进制
原文地址:http://www.cnblogs.com/baiqiantao/p/7145305.html