这几天公司开发了一款应用,业务中需要实时播放提示语音,并且要求检测是否正在播放中,不允许“七嘴八舌”。网上查了一些资料,但是不是很好用。借鉴了百度人脸识别sdk中的做法,提取出一套可用的音频播放模块,趁着项目基本结项,时间暂时相对充足,整理分享给大家。
直接放代码
1.SoundPoolHelper
主要是用来处理判断是否当前正在播放,如果是则直接拒绝播放新的音频的逻辑
public class SoundPoolHelper {
private static final String TAG = SoundPoolHelper.class.getSimpleName();
private Context mContext;
private SoundEnum mPlaySoundStatusNewEnum;
private volatile long mPlayDuration = 0L;
private volatile long mPlayTime = 0L;
private volatile boolean mIsPlaying = false;
private volatile boolean mIsEnableSound = true;
private HashMap<Integer, Long> mPlayDurationMap = new HashMap();
public SoundPoolHelper(Context context) {
this.mContext = context;
}
public void setEnableSound(boolean flag) {
this.mIsEnableSound = flag;
}
public boolean getEnableSound() {
return this.mIsEnableSound;
}
public long getPlayDuration() {
return this.mPlayDuration;
}
public boolean playSound(SoundEnum status) {
if (!this.mIsEnableSound) {
SoundPlayer.release();
}
this.mIsPlaying = System.currentTimeMillis() - SoundPlayer.playTime < this.mPlayDuration;
if (this.mIsPlaying || this.mPlaySoundStatusNewEnum == status && System.currentTimeMillis() - this.mPlayTime < SoundEnvironment.TIME_TIPS_REPEAT) {
return false;
} else {
this.mIsPlaying = true;
this.mPlaySoundStatusNewEnum = status;
this.mPlayDuration = 0L;
this.mPlayTime = System.currentTimeMillis();
int resId = SoundEnvironment.getSoundId(status);
if (resId > 0) {
this.mPlayDuration = this.getSoundDuration(resId);
SoundPlayer.playTime = System.currentTimeMillis();
if (this.mIsEnableSound) {
SoundPlayer.play(this.mContext, resId);
}
}
return this.mIsPlaying;
}
}
private long getSoundDuration(int rawId) {
long duration = 600L;
long durationStep = 0L;
if (this.mPlayDurationMap.containsKey(rawId)) {
duration = (Long)this.mPlayDurationMap.get(rawId);
} else {
long time = System.currentTimeMillis();
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
try {
Uri uri = Uri.parse("android.resource://" + this.mContext.getPackageName() + "/" + rawId);
mmr.setDataSource(this.mContext, uri);
String d = mmr.extractMetadata(9);
duration = Long.valueOf(d) + durationStep;
this.mPlayDurationMap.put(rawId, duration);
} catch (IllegalArgumentException var11) {
var11.printStackTrace();
} catch (IllegalStateException var12) {
var12.printStackTrace();
} catch (Exception var13) {
var13.printStackTrace();
}
}
return duration;
}
public void release() {
SoundPlayer.release();
this.mPlayDuration = 0L;
this.mPlayTime = 0L;
this.mContext = null;
}
public void clear(){
SoundPlayer.release();
this.mPlayDuration = 0L;
this.mPlayTime = 0L;
}
}
2.SoundPlayer
调用SoundPool处理音频文件的播放
public class SoundPlayer {
private SoundPool mSoundPool = new SoundPool(5, 3, 0);
private SparseIntArray mSoundPoolCache = new SparseIntArray();
private static SoundPlayer sSoundPlayer;
public static long playTime = 0L;
private SoundPlayer() {
playTime = 0L;
}
@SuppressLint({"NewApi"})
public static void play(Context context, int resId) {
if (null == sSoundPlayer) {
sSoundPlayer = new SoundPlayer();
}
int id = sSoundPlayer.mSoundPoolCache.get(resId);
if (0 == id) {
final int soundId = sSoundPlayer.mSoundPool.load(context, resId, 1);
sSoundPlayer.mSoundPoolCache.put(resId, soundId);
if (Build.VERSION.SDK_INT >= 8) {
sSoundPlayer.mSoundPool.setOnLoadCompleteListener((soundPool, sampleId, status) -> {
if (0 == status && soundId == sampleId) {
try {
SoundPlayer.playTime = System.currentTimeMillis();
SoundPlayer.sSoundPlayer.mSoundPool.play(soundId, 1.0F, 1.0F, 5, 0, 1.0F);
} catch (Exception e) {
e.printStackTrace();
}
}
});
} else {
try {
Thread.currentThread().join(100L);
} catch (InterruptedException e) {
e.printStackTrace();
}
playTime = System.currentTimeMillis();
sSoundPlayer.mSoundPool.play(soundId, 1.0F, 1.0F, 5, 0, 1.0F);
}
} else {
try {
sSoundPlayer.mSoundPool.play(id, 1.0F, 1.0F, 5, 0, 1.0F);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void release() {
if (null != sSoundPlayer) {
int i = 0;
for (int n = sSoundPlayer.mSoundPoolCache.size(); i < n; ++i) {
sSoundPlayer.mSoundPool.unload(sSoundPlayer.mSoundPoolCache.valueAt(i));
}
sSoundPlayer.mSoundPool.release();
sSoundPlayer.mSoundPool = null;
sSoundPlayer.mSoundPoolCache.clear();
sSoundPlayer.mSoundPoolCache = null;
sSoundPlayer = null;
}
playTime = 0L;
}
}
3.SoundEnvironment
定义了音频文件和相对应的文字提示的数组的赋值和取值方法
public class SoundEnvironment {
public static long TIME_TIPS_REPEAT = 3000L;
private static int[] mSoundIds;
private static int[] mTipsTextIds;
public SoundEnvironment() {
}
public static void setSoundId(SoundEnum status, int soundId) {
if (mSoundIds != null) {
try {
mSoundIds[status.ordinal()] = soundId;
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static int getSoundId(SoundEnum status) {
int soundId = mSoundIds[status.ordinal()];
return soundId;
}
public static void setTipsId(SoundEnum status, int tipsId) {
if (mTipsTextIds != null) {
try {
mTipsTextIds[status.ordinal()] = tipsId;
} catch (Exception var3) {
var3.printStackTrace();
}
}
}
public static int getTipsId(SoundEnum status) {
int tipsId = mTipsTextIds[status.ordinal()];
return tipsId;
}
static {
mSoundIds = new int[SoundEnum.values().length];
mTipsTextIds = new int[SoundEnum.values().length];
for (int i = 0; i < mSoundIds.length; ++i) {
mSoundIds[i] = 0;
mTipsTextIds[i] = 0;
}
}
}
4.SoundEnum
枚举类
public enum SoundEnum {
//请保持面部在取景框内
PLEASE_KEEP_FACE_IN,
//请摘掉口罩或移除遮挡物
PLEASE_REMOVE_MASK,
//请摆正头部姿态,正视摄像头
PLEASE_LOOK_AT_CAMERA,
//图片模糊,请保持不动
PLEASE_DO_NOT_MOVE,
//图片光照不足
PICTURE_LESS_LIGHT,
//请向前靠近镜头
PLEASE_CLOSE_TO_CAMREA,
//请向后远离镜头
PLEASE_FAR_AWAY_CAMERA,
//采集成功,正在上传
UPLOADING,
//抠图失败
CUT_PIC_FAILED,
//获取特征值失败
GET_FEATURE_FAILED
}
具体调用:
(1)在项目中需要初始化的地方,调用SoundEnvironment中的赋值soundId和文字提示的数组方法,初始化音频数据源
private void initSound() {
SoundEnvironment.setSoundId(SoundEnum.PLEASE_KEEP_FACE_IN,
R.raw.keep_face_in);
SoundEnvironment.setSoundId(SoundEnum.PLEASE_REMOVE_MASK,
R.raw.remove_mask);
SoundEnvironment.setSoundId(SoundEnum.PLEASE_LOOK_AT_CAMERA,
R.raw.look_at_camera);
SoundEnvironment.setSoundId(SoundEnum.PLEASE_DO_NOT_MOVE,
R.raw.do_not_move);
SoundEnvironment.setSoundId(SoundEnum.PICTURE_LESS_LIGHT,
R.raw.less_light);
SoundEnvironment.setSoundId(SoundEnum.PLEASE_CLOSE_TO_CAMREA,
R.raw.close_to_camera);
SoundEnvironment.setSoundId(SoundEnum.PLEASE_FAR_AWAY_CAMERA,
R.raw.far_away_camera);
SoundEnvironment.setSoundId(SoundEnum.UPLOADING,
R.raw.uploading);
SoundEnvironment.setTipsId(SoundEnum.PLEASE_KEEP_FACE_IN,
R.string.keep_face_in);
SoundEnvironment.setTipsId(SoundEnum.PLEASE_REMOVE_MASK,
R.string.remove_mask);
SoundEnvironment.setTipsId(SoundEnum.PLEASE_LOOK_AT_CAMERA,
R.string.look_at_camera);
SoundEnvironment.setTipsId(SoundEnum.PLEASE_DO_NOT_MOVE,
R.string.do_not_move);
SoundEnvironment.setTipsId(SoundEnum.PICTURE_LESS_LIGHT,
R.string.less_light);
SoundEnvironment.setTipsId(SoundEnum.PLEASE_CLOSE_TO_CAMREA,
R.string.close_to_camera);
SoundEnvironment.setTipsId(SoundEnum.PLEASE_FAR_AWAY_CAMERA,
R.string.far_away_camera);
SoundEnvironment.setTipsId(SoundEnum.UPLOADING,
R.string.uploading);
SoundEnvironment.setTipsId(SoundEnum.CUT_PIC_FAILED,
R.string.cut_pic_failed);
SoundEnvironment.setTipsId(SoundEnum.GET_FEATURE_FAILED,
R.string.get_feature_failed);
}
(2)业务类
private SoundPoolHelper soundPoolHelper;
soundPoolHelper = new SoundPoolHelper(this);
//定义一个方法,供业务中调用,传入SoundEnum值,播放音频,显示提示文字
private void showErrorTips(SoundEnum soundEnum) {
binding.tvTips.setText("");
binding.tvTips.setVisibility(View.GONE);
binding.rlErrorMsg.setVisibility(View.VISIBLE);
binding.tvErrorTips.setText(SoundEnvironment.getTipsId(soundEnum));
soundPoolHelper.playSound(soundEnum);
}
//调用示例
showErrorTips(SoundEnum.PLEASE_KEEP_FACE_IN);
showErrorTips(SoundEnum.PLEASE_REMOVE_MASK);
至此,就完成了Android调用SoundPool 播放raw目录下的音频文件的功能
欢迎评论区留言