Android使用SoundPool播放语音,并实现按顺序延时播放

简介: Android使用SoundPool播放语音,并实现按顺序延时播放

项目中有一个需求需要实现播报一连串的语音叫号。


如果有免费的tts文字转语音功能就好了,但是这些功能都是收费的,于是只能一个个有限的语音拼接起来。


使用SoundPool播放语音是异步的,如果不加控制没法达到效果,按顺序依次播放:请 XXX 号到XXXX 窗口 XX。


借助Rxjava很简单的就实现了这个功能,如下:


/**
 * @author yangyongzhen
 * @date 2021/6/11
 * @version 1.0.0
 * @desc  语音播报
 */
fun playTakeMealVoice(bean: OrderedHistorySecRecord){
        var orderno =  bean.orderno
        val windowid = dyPara?.windowId
        var listVoice = arrayListOf<Int>()
        val numbers = mapOf(
                "0" to R.raw.n0,
                "1" to R.raw.n1,
                "2" to R.raw.n2,
                "3" to R.raw.n3,
                "4" to R.raw.n4,
                "5" to R.raw.n5,
                "6" to R.raw.n6,
                "7" to R.raw.n7,
                "8" to R.raw.n8,
                "9" to  R.raw.n9)
        listVoice.add(R.raw.qing)
        if (orderno != null) {
            for ((index, chars) in orderno.withIndex()) {
                numbers["$chars"]?.let { listVoice.add(it) }
            }
        }
        listVoice.add(R.raw.hao)
        listVoice.add(R.raw.dao)
        if (windowid != null) {
            for ((index, chars) in windowid.withIndex()) {
                numbers["$chars"]?.let { listVoice.add(it) }
            }
        }
        listVoice.add(R.raw.chuangkou)
        listVoice.add(R.raw.qucan)
        var count = listVoice.size.toLong()
        Observable.interval(500, TimeUnit.MILLISECONDS).take(count).subscribe(object: Observer<Long> {
            override fun onComplete() {
                Log.d(TAG,"onComplete");
            }
            override fun onSubscribe(d: Disposable) {
                Log.d(TAG,"onSubscribe:")
            }
            override fun onNext(t: Long) {
                Log.d(TAG,"onNext:$t")
                SoundUtil.playMusic(iBillyView.getActivity(), listVoice[t.toInt()])
            }
            override fun onError(e: Throwable) {
                Log.d(TAG,"onError:" + e.message)
            }
        })
    }


以下是封装的SoundUtil工具类。


object SoundUtil {
    private var soundId: Int = 0
    private var soundPool: SoundPool? = null
    private val soundMap = hashMapOf<Int, Int>()
    fun playMusic(context: Context, mid: Int) {
        if (soundPool == null) {
            val mAudioAttributes = AudioAttributes.Builder().setLegacyStreamType(AudioManager.STREAM_MUSIC)
                    .build()
            soundPool = SoundPool.Builder().setMaxStreams(10).setAudioAttributes(mAudioAttributes).build()
        }
        try {
            if (soundMap.containsKey(mid)) {
                soundPool!!.play(soundMap[mid]!!, 1.0f, 1.0f, 1, 0, 1.0f)
            } else {
                soundId = soundPool!!.load(context, mid, 1)
                soundPool!!.setOnLoadCompleteListener { pool, _, _ ->
                    soundMap[mid] = soundId
                    //  加载完成
                    try {
                        pool.play(soundId, 1.0f, 1.0f, 1, 0, 1.0f)
                    } catch (e: Exception) {
                    }
                }
            }
        } catch (ex: Exception) {
            ex.printStackTrace()
        }
    }
    fun releaseMusic() {
        if (soundPool != null) {
            soundPool!!.release()
            soundPool = null
        }
        soundMap.clear()
    }
}


想打断语音播报怎么办?也很简单。


在playTakeMealVoice所在的类里面,定义个伴生对象companion object,里面声明个disposable


在每次播放前先来个  disposable?.dispose()


companion object {
        var disposable:Disposable?=null
    }


fun playTakeMealVoice(orderno:String?,winid:String?){
        Log.d(TAG,"playTakeMealVoice")
        disposable?.dispose()


在每次的订阅中,来个赋值:


......
Observable.interval(500, TimeUnit.MILLISECONDS).take(count).subscribeOn(Schedulers.io()).subscribe(object: Observer<Long> {
            override fun onComplete() {
                Log.d(TAG,"onComplete");
            }
            override fun onSubscribe(d: Disposable) {
                Log.d(TAG,"onSubscribe:")
                disposable = d //来个赋值
            }
......
相关文章
|
7月前
|
开发工具 Android开发
Android平台GB28181设备接入端语音广播技术探究和填坑指南
GB/T28181-2016官方规范和交互流程,我们不再赘述。
|
7月前
|
开发工具 Android开发
Android平台GB28181设备接入端语音广播支持PS格式
对接Android平台GB28181设备接入端语音广播的时候,我们有遇到过INVITE SDP需要PCMA格式的audio,对方同时回了PS和PCMA两种,然后,发数据的时候,直接发了PS的。
132 0
|
7月前
|
编解码 Android开发 数据安全/隐私保护
Android平台外部编码数据(H264/H265/AAC/PCMA/PCMU)实时预览播放技术实现
好多开发者可能疑惑,外部数据实时预览播放,到底有什么用? 是的,一般场景是用不到的,我们在开发这块前几年已经开发了非常稳定的RTMP、RTSP直播播放模块,不过也遇到这样的场景,部分设备输出编码后(视频:H.264/H.265,音频:AAC/PCMA/PCMU)的数据,比如无人机或部分智能硬件设备,回调出来的H.264/H.265数据,除了想转推到RTMP、轻量级RTSP服务或GB28181外,还需要本地预览甚至对数据做二次处理(视频分析、实时水印字符叠加等,然后二次编码),基于这样的场景诉求,我们开发了Android平台外部编码数据实时预览播放模块。
|
4月前
|
XML Java Android开发
Android Studio App开发中使用录音机、MediaRecorder录制音频和MediaPlayer播放音频讲解及实战(附源码)
Android Studio App开发中使用录音机、MediaRecorder录制音频和MediaPlayer播放音频讲解及实战(附源码)
75 0
|
4天前
|
Android开发 内存技术
Android 通过tinyalsa调试解决录制和播放音频问题
Android 通过tinyalsa调试解决录制和播放音频问题
21 1
|
4月前
|
JSON 自然语言处理 Java
Android App开发语音处理之系统自带的语音引擎、文字转语音、语音识别的讲解及实战(超详细 附源码)
Android App开发语音处理之系统自带的语音引擎、文字转语音、语音识别的讲解及实战(超详细 附源码)
123 0
|
7月前
|
编解码 网络协议 Android开发
Android平台GB28181设备接入端如何支持跨网段语音对讲
如果你是音视频开发者亦或寻求这块技术方案的公司,在探讨这个问题之前,你可能网上看了太多关于语音广播和语音对讲相关的资料,大多文章认为语音对讲和语音广播无本质区别,实现思路也大同小异。
|
4月前
|
机器学习/深度学习 TensorFlow 语音技术
【Android +Tensroflow Lite】实现从基于机器学习语音中识别指令讲解及实战(超详细 附源码和演示视频)
【Android +Tensroflow Lite】实现从基于机器学习语音中识别指令讲解及实战(超详细 附源码和演示视频)
28 0
|
4月前
|
XML Java 调度
Android开发音效增强中铃声播放Ringtone及声音池调度SoundPool的讲解及实战(超详细 附源码)
Android开发音效增强中铃声播放Ringtone及声音池调度SoundPool的讲解及实战(超详细 附源码)
57 0
|
4月前
|
XML Java Android开发
Android App开发实战项目之仿手机QQ动感影集动画播放(附源码和演示视频 可直接使用)
Android App开发实战项目之仿手机QQ动感影集动画播放(附源码和演示视频 可直接使用)
29 0