<template>
<div class="home">
<!-- <button @click="getWebsocketUrl">获取WSS地址</button> -->
<!-- <button @click="connectWebSocket">连接WSS地址</button>
<button @click="audioPlay">播放</button> -->
</div>
</template>
<script>
// @ is an alias to /src
import CryptoJS from 'crypto-js'
import {Base64} from "js-base64";
export default {
name: 'Home',
data() {
return {
webSocketUrl: '',
ttsWS: null,
audioContent: null,
audioDataOffset: 0,
transWorker: null,
audioData: [],
}
},
created(){
this.getWebsocketUrl()
},
methods: {
getWebsocketUrl() {
return new Promise((resolve, reject) => {
var apiKey = "自己的key"
var apiSecret = "自己的api"
var url = 'wss://tts-api.xfyun.cn/v2/tts'
var host = location.host
var date = new Date().toGMTString()
var algorithm = 'hmac-sha256'
var headers = 'host date request-line'
var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/tts HTTP/1.1`
var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret)
var signature = CryptoJS.enc.Base64.stringify(signatureSha)
var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`
var authorization = btoa(authorizationOrigin)
url = `${url}?authorization=${authorization}&date=${date}&host=${host}`
this.$data.webSocketUrl = url
resolve(url)
})
},
// 建立连接
connectWebSocket(value) {
// alert(value)
this.$data.ttsWS=null
this.$data.audioContent=null
this.$data.audioDataOffset=0
this.$data.transWorker=null
this.$data.audioData=[]
this.$data.audioContext=null
if ('WebSocket' in window) {
this.$data.ttsWS = new WebSocket(this.$data.webSocketUrl)
} else if ('MozWebSocket' in window) {
this.$data.ttsWS = new MozWebSocket(this.$data.webSocketUrl)
} else {
alert('浏览器不支持WebSocket')
return
}
this.$data.ttsWS.onopen = e => {
this.webSocketSend(value)
this.playTimeout = setTimeout(() => {
this.audioPlay()
}, 1000)
}
this.$data.ttsWS.onmessage = e => {
this.result(e.data)
}
this.$data.ttsWS.onerror = e => {
clearTimeout(this.playTimeout)
alert('WebSocket报错,请f12查看详情')
console.error(`详情查看:${encodeURI(url.replace('wss:', 'https:'))}`)
}
this.$data.ttsWS.onclose = e => {
console.log(e)
}
},
webSocketSend(value) {
var params = {
common: {
app_id: "自己的id", // APPID
},
business: {
aue: 'raw',
auf: 'audio/L16;rate=16000',
vcn: 'xiaoyan',
speed: 50,
pitch: 50,
bgs: 0,
tte: 'UTF8',
},
data: {
status: 2,
text: this.encodeText(value,'')
},
}
this.$data.ttsWS.send(JSON.stringify(params)) //向wedbsocket发送数据
},
encodeText(text, encoding) {
switch (encoding) {
case 'utf16le' : {
let buf = new ArrayBuffer(text.length * 4)
let bufView = new Uint16Array(buf)
for (let i = 0, strlen = text.length; i < strlen; i++) {
bufView[i] = text.charCodeAt(i)
}
return buf
}
case 'buffer2Base64': {
let binary = ''
let bytes = new Uint8Array(text)
let len = bytes.byteLength
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i])
}
return window.btoa(binary)
}
case 'base64&utf16le' : {
return this.encodeText(this.encodeText(text, 'utf16le'), 'buffer2Base64')
}
default : {
return Base64.encode(text)
}
}
},
result(resultData) {
// console.log(resultData,"resumePlayDurationresumePlayDurationresumePlayDuration")
let jsonData = JSON.parse(resultData)
// 合成失败
if (jsonData.code !== 0) {
alert(`合成失败: ${jsonData.code}:${jsonData.message}`)
console.error(`${jsonData.code}:${jsonData.message}`)
this.resetAudio()
return
}
let output1 = this.transToAudioData(jsonData.data.audio)
// console.log(output1)
this.audioData.push(output1)
if (jsonData.code === 0 && jsonData.data.status === 2) {
this.ttsWS.close()
}
},
// 播放
audioPlay() {
// alert("播放")
let audioData=[]
let res = this.audioData.slice(this.audioDataOffset)
// console.log(audioData)
res.forEach((item)=>{
item.forEach((itemone)=>{
audioData.push(itemone)
})
})
this.audioDataOffset += audioData.length
// console.log(audioData.length)
let audioBuffer = this.audioContext.createBuffer(1, audioData.length, 22050)
let nowBuffering = audioBuffer.getChannelData(0)
if (audioBuffer.copyToChannel) {
audioBuffer.copyToChannel(new Float32Array(audioData), 0, 0)
} else {
for (let i = 0; i < audioData.length; i++) {
nowBuffering[i] = audioData[i]
}
}
// let bufferSource = this.bufferSource = this.audioContext.createBufferSource()
let bufferSource = this.audioContext.createBufferSource()
bufferSource.buffer = audioBuffer
bufferSource.connect(this.audioContext.destination)
bufferSource.start()
// bufferSource.onended = event => {
// if (this.audioDataOffset < this.audioData.length) {
// this.audioPlay()
// } else {
// // this.audioStop()
// }
// }
},
transToAudioData: function (audioDataStr, fromRate = 16000, toRate = 22505) {
let outputS16 = this.base64ToS16(audioDataStr)
let output = this.transS16ToF32(outputS16)
output = this.transSamplingRate(output, fromRate, toRate)
output = Array.from(output)
return output
},
base64ToS16: function (base64AudioData) {
base64AudioData = atob(base64AudioData)
const outputArray = new Uint8Array(base64AudioData.length)
for (let i = 0; i < base64AudioData.length; ++i) {
outputArray[i] = base64AudioData.charCodeAt(i)
}
return new Int16Array(new DataView(outputArray.buffer).buffer)
},
transS16ToF32: function (input) {
var tmpData = []
for (let i = 0; i < input.length; i++) {
var d = input[i] < 0 ? input[i] / 0x8000 : input[i] / 0x7fff
tmpData.push(d)
}
return new Float32Array(tmpData)
},
transSamplingRate: function (data, fromRate = 44100, toRate = 16000) {
var fitCount = Math.round(data.length * (toRate / fromRate))
var newData = new Float32Array(fitCount)
var springFactor = (data.length - 1) / (fitCount - 1)
newData[0] = data[0]
for (let i = 1; i < fitCount - 1; i++) {
var tmp = i * springFactor
var before = Math.floor(tmp).toFixed()
var after = Math.ceil(tmp).toFixed()
var atPoint = tmp - before
newData[i] = data[before] + (data[after] - data[before]) * atPoint
}
newData[fitCount - 1] = data[data.length - 1]
return newData
},
},
mounted() {
let AudioContext = window.AudioContext || window.webkitAudioContext
if (AudioContext) {
console.log('Audio Context初始化')
this.audioContext = new AudioContext()
this.audioContext.resume()
this.audioDataOffset = 0
}
},
components: {}
}
</script>
科大讯飞在线语音播报vue模块
最新推荐文章于 2024-08-08 08:23:11 发布
本文详细描述了如何通过JavaScript利用WebSocket与TTS服务进行安全通信,涉及加密技术和音频数据处理过程。
摘要由CSDN通过智能技术生成