在Vue项目中用Audio实现语音的播放
跟据项目的需求,有些时候我们需要实现,通过后台获取语音流,然后网页进行语音播放,在网页播放语音就可以避免用户的本地语音库的安装。
从后台获取语音流,生成Audio标签并赋值
这里我用了axios请求
getAudio() {
this.$axios({
url: "api/system/tts",//获取语音流的api
data: { data},//这个是给后台传送需要播放的语音信息
method: "post",
responseType: "blob"//后台返回的为语音的流数据
})
.then(res => {
let url = URL.createObjectURL(res.data);//通过这个API让语音数据转为成一个url地址
let audio = new Audio();//在VUE中使用audio标签
audio.src = url;//设置audio的src为上面生成的url
let playPromiser = audio.play();//进行播放
//在谷歌内核中,audio.play()会返回一个promise的值,在IE内核中就不会返回任何的值
//所以如果你要分浏览器,可以判断playPromiser的值来进行操作哦
audio.onended = () => {
//onended可以检测语音是否播完
//dosometing
};
})
.catch(err => {});
},
思路就是向后台发送需要播放的语音信息(文字),然后后台返回给你的语音流数据,通过URL.createObjectURL(data)
这个API生成一个URL,然后给audio标签附上url。
防止因为快速的请求语音数据造成语音播放叠在一起
上面的方法是获取语音并播放,有时候用户会进行多次点击或请求,然后语音就会叠在一起播放,那就炸了(这里其实可以让后端做一个排队的队列,一个一个播,这里我前端也做了一个排队队列)
对上面的方法进行改造改造
getAudio() {
if (this.callmsg.length > 0) {//如果队列是有人在排队的,这进行播放操作
this.$axios({
url: "api/system/tts",
data: { data },
method: "post",
responseType: "blob"
})
.then(res => {
let url = URL.createObjectURL(res.data);
let audio = new Audio();
audio.src = url;
let playPromiser = audio.play();
localStorage.setItem("audio", "1");//在这里我用一个标志,设置语音开始播放
audio.onended = () => {
this.callmsg.splice(0, 1);//队列的第一个播放完毕,所以删除
localStorage.setItem("audio", "0");//这里是语音播放完毕
this.getAudio();//进行下一个请求并播放
};
})
.catch(err => {});
} else {
//this.audio是一个data数据,用来记录是否有人排队
this.audio = true; //如果队列没人排队,就告诉外面已经读完啦
}
下面是用户的操作,就是触发播放函数的地方
this.callmsg.push(data);//this.callmsg就是排队队列,点击一次,放进去一个需要播放的信息
if (this.audio) {//如果没人
this.audio = false;//改为有人排队了
this.getAudio();//进行播放操作
}
一开始的this.audio设置为true
思路是一开始为没人,需要播放信息时,将标志设置为有人,并向队列里面加入数据,然后进行请求,如果在播放中途有新的信息需要播放,就会再插入,但是标志不变,所以上面的递归函数会继续执行,直到队列为空,标志就会改回来。