通过WebSocket的长连接实现语音搜索功能(整理中。。)
如果发现 有问题 或者觉得 有遗漏 的地方,欢迎留言讨论
关于WebSocket的优缺点
这个网上文档太多了,自行查阅 推荐入口
准备
之前是准备用 STOMPJS 流文本定向消息协议开发,但涉及到语音转文字,emmm...
所以此功能的语音部分涉及到语音识别器,语音识别器语音转文字是调用第三方的 SpeechRecognizer
,版权原因这里不讲第三方的,大家可以自己去集成第三方sdk;这里可以分享两个接入语音识别器踩到的几个坑,如下:
工程在 Chrome 浏览器打开,获取音频设备权限问题
Vue 工程在 Chrome 浏览器打开,无法获取音视频设备,控制台提示获取音频设备权限问题, 我们可以通过以下方式解决:
一、网页使用https方式访问
此操作需要依赖web服务提供者实现https的访问方式。(需要安全证书)
二、修改浏览器安全配置(最直接、简单)
- 浏览器地址栏输入:
chrome://flags/#unsafely-treat-insecure-origin-as-secure
- 开启Insecure origins treated as secure
在输入栏内输入你需要访问音频设备的地址url,然后将右侧Disabled 改成 Enabled,浏览器会提示重启(Relaunch)
3. 浏览器会提示重启(Relaunch),Relaunch 即可
关于谷歌浏览器的禁止autoplay政策
autoplay
: 这个属性是<video><audio>
所属的,表示在用户进入页面的时候自动开始播放声音或者播放视频,但是,这个属性会在谷歌浏览器中失效,因为谷歌浏览器在用户体验和安全性方面做出自己的限制,默认阻止音视频的自动播放。
解决方法也很简单,修改下权限就可以了~
新版本里面不叫 Autoplay policy了,而是声音,它会检测页面是否有video或audio标签,如果有的话,就会直接在上图显示,选择允许,就可以实现和上面一样的效果。如果上面没有声音选项,你也可以点击上图的 网站设置,里面有所有的浏览器的主要权限设置。
点进去,找到声音选项,一样可以设定允许自动播放。
注意:这里的设定只能生效于当前的页面,无法生效所有页面。
以上就是语音识别器部分
接下来是封装的webSocket 接收语音指令部分,直接上代码
class Socket {
/**
* @description: 初始化实例属性,保存参数
*
*/
constructor (options) {
this.url = options.url // 语音连接url
this.callback = options.received // 返回函数
this.name = options.name || 'default'
this.ws = null
this.status = null
// 心跳定时器
this.pingInterval = null
// 心跳检测频率
this.timeout = options.time
this.isHeart = options.isHeart
this.isReconnection = options.isReconnection
}
connect (data) {
this.ws = new WebSocket(this.url)
// 建立连接
this.ws.onopen = (e) => {
this.status = e.type
console.log('success', e)
if (this.isHeart) {
// 心跳
this.heartCheck()
}
// 给后台发送数据
if (data !== undefined) {
return this.ws.send(JSON.stringify({ type: data.type }))
}
}
// 接受服务器返回的信息
this.ws.onmessage = (e) => {
if (typeof this.callback === 'function') {
return this.callback(e.data)
} else {
console.log('参数的类型必须为函数')
}
}
// 关闭连接
this.ws.onclose = (e) => {
console.log('onclose', e)
}
// 报错
this.onerror = (e) => {
console.log('onerror', e)
this.closeSocket(e)
}
}
sendMsg (data) {
const msg = JSON.stringify(data)
return this.ws.send(msg)
}
resetHeart () {
clearInterval(this.pingInterval)
return this
}
heartCheck () {
this.pingInterval = setInterval(() => {
if (this.ws.readyState === 1) {
console.log('Im alive')
this.ws.send(JSON.stringify({ type: 'ping' }))
}
}, this.timeout * 8)
}
closeSocket (e) {
this.resetHeart()
if (this.status !== 'close') {
console.log('disconnect and reconnect', e)
// if (this.isReconnection) {
// 重连
this.connect()
// }
} else {
console.log('close manually', e)
}
}
close () {
this.status = 'close'
this.resetHeart()
console.log('998899')
return this.ws.close()
}
}
export default Socket
订阅
window.ws = new Socket({
url: `${this.socketUrl}${id}`,// url和参数
name: '',
isHeart: true, // 是否心跳
time: 60000,
received: (data) => {
if (typeof this.callbackMsg === 'function') {
return this.callbackMsg(data)
} else {
console.log('参数的类型必须为函数')
}
}
})
// this.ws = ws
const data = {
type: 'init'
}
window.ws.connect(data)
这里的socket只是做接收指令,发送指令是通过接入的收音设备,发送语音流到数据中控
转载自:https://juejin.cn/post/7145736862538137631