在项目开发过程中,如果需要播放音频,我们通常会用MediaPlayer。但是MediaPlayer用起来并不是很方便,使用中也会遇到一些问题。对于一些短音频,比如一些提示音,像这种短音频我们可以使用SoundPool。
一,SoundPool基本介绍
1,创建SoundPool实例
SoundPool(int maxStream, int streamType, int srcQuality)
- maxStream —— 同时播放的流的最大数量
- streamType —— 流的类型,一般为STREAM_MUSIC(具体在AudioManager类中列出)
- srcQuality —— 采样率转化质量,当前无效果,使用0作为默认值
初始化一个实例
SoundPool soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
2,加载资源
通常我们会把音频文件放在raw下,SoundPool推荐的语音格式是OGG,不过mp3文件也没问题,最好还是按推荐的来。
可以通过四种途径来记载一个音频资源:
- int load(AssetFileDescriptor afd, int priority)
通过一个AssetFileDescriptor对象 - int load(Context context, int resId, int priority)
通过一个资源ID通过一个资源ID - int load(String path, int priority)
通过指定的路径加载通过指定的路径加载 - int load(FileDescriptor fd, long offset, long length, int priority)
通过FileDescriptor加载
其中的priority参数目前没有效果,建议设置为1
注意:SoundPool的加载过程是一个将音频解压为原始16位PCM数据的过程,由一个后台线程来进行处理异步,所以初始化后不能立即播放,需要等待一点时间
3,流程控制
①,播放
final int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)
soundID:播放音频ID,比如同时load多个资源,那么第一个就是1,以此类推。
leftVolume:左声道音量
rightVolume:右声道音量
priority :流的优先级,值越大优先级高,影响当同时播放数量超出了最大支持数时SoundPool对该流的处理
loop :循环播放的次数,0为只播放一次,-1为无限循环,其他值为播放loop+1次(例如,3为一共播放4次).
rate : 播放的速率,范围0.5-2.0(0.5为一半速率,1.0为正常速率,2.0为两倍速率)
②,暂停
final void pause(int streamID)
③,继续
final void resume(int streamID)
④,停止
final void stop(int streamID)
⑤,释放资源
final void release()
需要注意: 在调用暂停,停止,继续的时候,传入的streamID需要是play返回的值。
4,其他调用方法
- final void setLoop(int streamID, int loop)
设置指定播放流的循环 - final void setVolume(int streamID, float leftVolume, floatrightVolume)
设置指定播放流的音量 - final void setPriority(int streamID, int priority)
设置指定播放流的优先级 - final void setRate(int streamID, float rate)
设置指定播放流的速率
5,资源加载监听
soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
@Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
Log.i(TAG, "onLoadComplete: 资源加载完成");
}
});
二,封装工具类
public class SoundPlayUtils {
// SoundPool对象
private static SoundPool mSoundPlayer = new SoundPool(10,AudioManager.STREAM_SYSTEM, 5);
private static volatile SoundPlayUtils soundPlayUtils;
/**
* 初始化
*
* @param context
*/
public static SoundPlayUtils init(Context context) {
if (soundPlayUtils == null) {
synchronized (SoundPlayUtils.class) {
if (soundPlayUtils == null) {
soundPlayUtils = new SoundPlayUtils(context);
}
}
}
return soundPlayUtils;
}
public SoundPlayUtils(Context context) {
//加载3个音频文件
mSoundPlayer.load(context, R.raw.one, 1);//1
mSoundPlayer.load(context, R.raw.two, 1);//2
mSoundPlayer.load(context, R.raw.three, 1);//3
}
/**
* 播放声音
*
* @param soundID
*/
public void play(int soundID) {
Log.d("####","play voice:"+soundID);
mSoundPlayer.play(soundID, 1, 1, 0, 0, 1);
}
在需要的时候调用该工具类,代码如下:
SoundPool.init(mApplication).play(1);//调用第一个音频文件
那么问题来了,如果这样第一次调用会播放无效,原因是因为load加载资源是在子线程中进行的,会有一定延时,资源没有加载完成是无法播放的。当然如果我先调用SoundPool.init(mApplication)进行加载,之后再进行播放也是可以的。