项目中有一个需求需要实现播报一连串的语音叫号。
如果有免费的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 //来个赋值
}
......