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

2022-01-07 15:25:01 浏览数 (1)

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

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

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

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

代码语言:javascript复制
/**
 * @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工具类。

代码语言:javascript复制
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()

代码语言:javascript复制
companion object {
        var disposable:Disposable?=null
    }
代码语言:javascript复制
fun playTakeMealVoice(orderno:String?,winid:String?){
        Log.d(TAG,"playTakeMealVoice")
        disposable?.dispose()

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

代码语言:javascript复制
......
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 //来个赋值
            }
......

0 人点赞