使用SoundPool播放音频文件,使用简单

简介: 使用SoundPool播放音频文件,使用简单

背景

在项目实际开发中,可能会遇到播放一段音频文件的需求,比如播放一段话,比如连续播放来电铃声等等,下面介绍使用SoundPool播放音频文件,工具类已封装好,复制粘贴即可使用

实现目标

1、播放音频文件,播放完即停止

2、播放音频文件,循环播放

说明

播放音频文件有很多种方式,MediaPlayer播放音频,AudioTrack播放音频,Ringtone播放音频,SoundPool播放音频,此文章为SoundPool封装实例,复杂实现逻辑可以舍弃了,一句话即可实现播放音频


下边介绍下使用说明

1.播放指定音频文件,选择哪个播放哪个

AVChatSoundPlayer.instance().play(AVChatSoundPlayer.RingerTypeEnum.LY_CONNECT);

2.循环播放音频文件

public synchronized void play(RingerTypeEnum type) 
        this.ringerTypeEnum = type;
        int ringId = 0;
        switch (type) {
            case LY_CONNECT:
                ringId = R.raw.avchat_ly_connect;
                loop = false;//是否重复播放铃声
                break;
            case LY_CLOSE:
                ringId = R.raw.avchat_ly_close;
                loop = true;
                break;
        }
    }

将loop改成true,即循环播放

3.停止播放音频文件

AVChatSoundPlayer.instance().stop();

所需文件

1.新建raw目录,将所需要播放的音频文件放入,建议音频文件不要超过1M,因为在不同的系统下 SoundPool 表现可能存在不一致

1688293182858.png


raw.jpg


2.复制工具类AVChatSoundPlayer

/**
 * SoundPool 铃声尽量不要超过1M
 * 在不同的系统下 SoundPool 表现可能存在不一致
 */
public class AVChatSoundPlayer {
    private static final String TAG = "Lp_Player";
    public enum RingerTypeEnum {
        LY_CONNECT,
        LY_CLOSE,
        MEN_KAI,
        MEN_CLOSE,
        RING
        ;
    }
    private Context context;
    private SoundPool soundPool;
    private AudioManager audioManager;
    private int streamId;
    private int soundId;
    private boolean loop;
    private RingerTypeEnum ringerTypeEnum;
    private boolean isRingModeRegister = false;
    private int ringMode = -1;
    private static AVChatSoundPlayer instance = null;
    private RingModeChangeReceiver ringModeChangeReceiver;
    public static AVChatSoundPlayer instance() {
        if(instance == null) {
            synchronized (AVChatSoundPlayer.class) {
                if(instance == null) {
                    instance = new AVChatSoundPlayer();
                }
            }
        }
        return instance;
    }
    public AVChatSoundPlayer() {
        this.context = AppUMS.mContent;//全局上下文对象,getApplicationContext();
}
    public synchronized void play(RingerTypeEnum type) {
        L.e(TAG, "play type->" + type.name());
        this.ringerTypeEnum = type;
        int ringId = 0;
        switch (type) {
            case LY_CONNECT:
                ringId = R.raw.avchat_ly_connect;
                loop = false;//是否重复播放铃声
                break;
            case LY_CLOSE:
                ringId = R.raw.avchat_ly_close;
                loop = false;
                break;
            case MEN_KAI:
                ringId = R.raw.avchat_men_kai;
                loop = false;
                break;
            case MEN_CLOSE:
                ringId = R.raw.avchat_men_close;
                loop = false;
                break;
            case RING:
                ringId = R.raw.avchat_ring;
                loop = true;
                break;
        }
        if(ringId != 0) {
            play(ringId);
        }
    }
    public void stop() {
        L.e(TAG, "stop");
        if (soundPool != null) {
            if (streamId != 0) {
                soundPool.stop(streamId);
                streamId = 0;
            }
            if (soundId != 0) {
                soundPool.unload(soundId);
                soundId = 0;
            }
        }
        if (isRingModeRegister) {
            registerVolumeReceiver(false);
        }
    }
    private void play(int ringId) {
        initSoundPool();
        if (audioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL) {
            soundId = soundPool.load(context, ringId, 1);
        }
    }
    private void initSoundPool() {
        stop();
        if (soundPool == null) {
            soundPool = new SoundPool(1, AudioManager.STREAM_RING, 0);
            soundPool.setOnLoadCompleteListener(onLoadCompleteListener);
            audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
            ringMode = audioManager.getRingerMode();
        }
        registerVolumeReceiver(true);
    }
    SoundPool.OnLoadCompleteListener onLoadCompleteListener = new SoundPool.OnLoadCompleteListener() {
        @Override
        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
            if (soundId != 0 && status == 0) {
                if (audioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL) {
                    int curVolume = audioManager.getStreamVolume(AudioManager.STREAM_RING);
                    streamId = soundPool.play(soundId, curVolume, curVolume, 1, loop ? -1 : 0, 1f);
                }
            }
        }
    };
    private void registerVolumeReceiver(boolean register){
        if (ringModeChangeReceiver == null) {
            ringModeChangeReceiver = new RingModeChangeReceiver() ;
        }
        if (register) {
            isRingModeRegister = true;
            IntentFilter filter = new IntentFilter() ;
            filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION) ;
            context.registerReceiver(ringModeChangeReceiver, filter) ;
        } else {
            context.unregisterReceiver(ringModeChangeReceiver);
            isRingModeRegister = false;
        }
    }
    private class RingModeChangeReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (ringMode != -1 && ringMode != audioManager.getRingerMode()
                    && intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
                ringMode = audioManager.getRingerMode();
                play(ringerTypeEnum);
            }
        }
    }
}

最后,祝大家开发顺利!


相关文章
一日一技:使用 asyncio 如何限制协程的并发数
一日一技:使用 asyncio 如何限制协程的并发数
1289 0
一日一技:使用 asyncio 如何限制协程的并发数
|
存储 前端开发 开发工具
Git Hooks实战:提交前检查修改文件中是否包含调试代码
Git Hooks实战:提交前检查修改文件中是否包含调试代码
283 0
|
7月前
|
资源调度 监控 物联网
《深入探秘:分布式软总线自发现、自组网技术原理》
分布式软总线是实现设备高效互联的关键技术,其自发现与自组网功能为多设备协同奠定了基础。通过融合Wi-Fi、蓝牙、NFC等通信技术,设计针对性发现协议,并采用统一接口封装,简化开发复杂度。自组网技术解决异构网络互联互通问题,支持混合拓扑结构,优化通信资源调度,引入软时钟确保时间同步。这些特性使分布式软总线成为构建万物互联智能时代的核心支撑,推动智能家居、智能办公等领域创新发展,提升生活与工作效率。
461 8
|
XML 编解码 算法
Android开发音效中录制WAV音频和录制MP3音频的讲解及实战(超详细 附源码)
Android开发音效中录制WAV音频和录制MP3音频的讲解及实战(超详细 附源码)
560 0
|
并行计算 数据可视化
ECCV 2024:JHU上交等提出首个可渲染X光3DGS!推理速度73倍NeRF,性能提升6.5dB
【10月更文挑战第8天】近日,约翰斯•霍普金斯大学和上海交通大学等机构的研究人员提出了一种名为X-Gaussian的新型3D Gaussian Splatting框架,用于X光新视角合成。该框架通过优化辐射性Gaussian点云模型和可微分辐射光栅化技术,显著提升了X光成像的渲染质量,同时大幅减少了训练时间和推理时间。实验结果显示,X-Gaussian在性能上比现有方法提升了6.5dB,训练时间减少了85%,推理速度提高了73倍。此外,该框架在稀疏视角CT重建中也展现出巨大潜力。
307 4
|
数据库 Kotlin
Kotlin中的冷流和热流以及如何让Flow停下来
本文介绍了Kotlin中`Flow`的概念及其类型,包括冷流(Cold Flow)、热流`SharedFlow`及具有最新值的`StateFlow`。文中详细描述了每种类型的特性与使用场景,并提供了停止`Flow`的方法,如取消协程、使用操作符过滤及异常处理。通过示例代码展示了如何运用这些概念。
481 2
|
移动开发 前端开发 UED
深入理解Rem适配:移动端网页设计的利器
深入理解Rem适配:移动端网页设计的利器
|
监控 网络协议 iOS开发
程序退到后台的时候,所有线程被挂起,系统回收所有的socket资源问题及解决方案
程序退到后台的时候,所有线程被挂起,系统回收所有的socket资源问题及解决方案
541 0
|
缓存 Java 开发工具
简记一个错误
简记一个错误
1160 0