当前位置: 首页 > 工具软件 > RAW > 使用案例 >

Android SoundPool 播放raw目录下的音频文件

孙和安
2023-12-01

这几天公司开发了一款应用,业务中需要实时播放提示语音,并且要求检测是否正在播放中,不允许“七嘴八舌”。网上查了一些资料,但是不是很好用。借鉴了百度人脸识别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目录下的音频文件的功能

欢迎评论区留言

 类似资料: