跳转到内容

语音技术

语音技术目前支持 ASR 与 TTS 两种技术。

ASR,自动语音识别技术(Automatic Speech Recognition)是一种将人的语音转换为文本的技术, 支持实时短语音识别与长语音听写。 TTS,文字转语音技术(Text to Speech)是一种将文字转成语音的技术,可将上传的单句文本转成播报音频,包含了短音频生成和长音频生成能力。

该接口底层依赖以下接口实现,开发者使用前需要在 manifest.json 中声明以下接口:

{ "name": "blueos.network.webSocket" }
{ "name": "blueos.media.audio.mediaManager" }
import speech from "@blueos.ai.speech"
接口名称接口说明
createAsr创建 ASR 语音识别服务实例 AsrInstance
createTts创建 TTS 文字转语音服务实例 TtsInstance
接口名称接口说明
start()开启语音识别服务
send(data:ArrayBufferTypedArray)
finish()结束语音识别服务
onMessage = (result:ShortModeResultLongModeResult) =>{}
onStarted = () =>{}语音识别服务开启成功的回调。在服务开启成功后,语音识别服务将开始处理通过 send() 接口发送的数据
onFinished = () =>{}语音识别服务结束回调。该回调可通过调用 finish()接口触发或者 endVadTime 超时自动触发
onError = (data:string, code: number) =>{}语音识别服务异常回调
接口名称接口说明
connect()连接文本转语音服务
disconnect()断开文本转语音服务,并且释放网络资源与相关播放器资源,建议在应用销毁时调用。
send(data:string)发送文本内容
pauseAudio()tts 实例服务暂停播放音频
resumeAudio()tts 实例服务恢复播放音频
onMessage = (result:TtsResult) =>{}文本识别信息回调。通过 send()接口发送文本内容后,文本识别结果将通过该回调事件返回
onConnected = () =>{}文字转语音服务连接成功的回调。在调用 connect() 连接服务成功后触发。服务连接成功后,文字转语音服务将开始处理通过 send() 接口发送的文本内容。
onSpeakStarted()播放开始回调
onSpeakPaused()播放暂停回调,调用了TtsInstance.pauseAudio()后会触发此回调
onSpeakProgress(progress:string)播放进度信息回调。开始播放后,播放进度信息会通过该回调多次触发,直到播放完毕
onSpeakFinished()播放完毕回调
onSpeakResumed()恢复播放回调,调用了TtsInstance.resumeAudio()后会触发此回调
onError = (data:string, code: number) =>{}文字转语音服务异常回调

createAsr(asrParams: AsrParams):AsrInstance

Section titled “createAsr(asrParams: AsrParams):AsrInstance”

创建 ASR 实例

属性必填类型默认值说明
authAuth请求的身份验证信息,确保请求来源合法
modelAsrModelAsrModel.ShortInput使用的 ASR 模型,支持短语音与长语句模型。
configAsrConfig初始化 ASR 客户端相关配置
属性必填类型说明
appIdstring应用 appId
appKeystring应用 appKey

注: appId & appKey,需要在 vivo 开发者平台 申请

属性说明
ShortInputt短语音,输入法模型。
ShortJovi短语音,语音助手模型
LongListen长语句,听说模型。
LongSubtitle长语句,字幕模型
  1. 短语音指单轮识别时长在 60s 之内。
  2. 长语句指单轮识别不限制时长。
参数类型说明必填默认值备注
audioTypeAudioType音频类型AudioType.Pcm使用的音频类型
isWithPunctuationboolean是否打开标点符号true
endVadTimenumber后端检测时间1000单位:毫秒, 仅实时短语音支持该参数
isChinese2digitalboolean是否打开汉字转数字true仅实时短语音支持该参数
langAsrLang语言AsrLang.Cn仅长语音听写支持该参数
属性说明
Pcmpcm 音频类型
Opusopus 音频类型
属性说明
Cn中文
En英文

开启语音识别服务

AsrInstance.send(data:ArrayBuffer|TypedArray)

Section titled “AsrInstance.send(data:ArrayBuffer|TypedArray)”

发送语音数据,语音数据建议分帧发送,每帧包含的语音时长是 40 毫秒,单句不超过 60s

AsrInstance.onMessage = (result:ShortModeResult|LongModeResult) =>{}

Section titled “AsrInstance.onMessage = (result:ShortModeResult|LongModeResult) =>{}”

语音识别信息回调。通过 send()接口发送语音数据后,语音识别结果将通过该回调事件返回

参数类型说明
textstringasr 识别结果
resultIdnumber结果序列号
reformationnumberasr 识别返回, 1 代表修正 0 代表追加
isLastboolean是否为本次会话最后一条结果
参数类型说明
codeResultCodeEnum结果代码描述
midPointstring识别中间 midPoint 结果即一句话中间结果
endPointstring识别中间 rec 结果即完整一句话或者最后一句结果
beginTimenumber开始时间,单位毫秒
endTimenumber结束时间,单位毫秒
speakernumber当有角色分离时返回 0 表示当前说话人, 非 0 表示角色 id,有角色变化
属性说明
0表示本次返回为识别中间结果,即一句话的完整结果,整个过程就是一句话中间结果,一句话完整结果…结束
8表示本次返回为识别中间 midPoint 结果,即一句话的中间结果。
9表示为客户端发完语音数据后的最后一句,客户端可以断开链接。

比如有两句话,一句是“今天天气怎么样”,下一句是“明天天气怎么样”, 第一次返回“今天”,就是 8 第二次返回“今天天气怎么样”,就是 0,表示一句话的结束 第三次返回“明天”,就是 8 第四次返回“明天天气怎么样”,就是 9 然后就结束了

语音识别服务开启成功的回调。在服务开启成功后,语音识别服务将开始处理通过 send() 接口发送的数据

语音识别服务结束回调。该回调可通过调用 finish()接口触发或者 endVadTime 超时自动触发

AsrInstance.onError = (data:string, code: number) =>{}

Section titled “AsrInstance.onError = (data:string, code: number) =>{}”

语音识别服务异常回调

属性类型说明
datastring失败信息描述
codeFailCodeEnum失败业务码
属性说明
10000参数校验失败
10002引擎服务异常
10003获取中间识别结果失败
10004获取最终识别结果失败
10005解析引擎数据异常
10006引擎内部错误
10007请求 nlu 出错
10008音频超长
50001使用超量
import media from "@blueos.media.audio.mediaManager";
import speech from "@blueos.ai.speech";
/**
* 录音状态
* @enum {number}
*/
const AudioRecordState = {
/** 录音中 */
record: 1,
/** 录音结束 */
stop: 2,
ready: 3,
};
export default {
data: {
result: "结果",
auth: {
appId: "xxx",
appKey: "xxxx",
},
asr: null,
model: "",
pagraph: "",
audioRecorder: null,
audioRecordState: AudioRecordState.stop,
},
createAsr() {
this.model = speech.AsrModel.ShortInput;
const asr = speech.createAsr({
auth: this.auth,
model: this.model,
config: {
audioType: speech.AudioType.Pcm,
isWithPunctuation: true,
endVadTime: 1000,
isChinese2digital: false,
},
});
const arrs = [];
asr.onMessage = (data) => {
console.log(`onmessage data :${JSON.stringify(data)}`);
if (this.model === speech.AsrModel.LongListen || this.model === speech.AsrModel.LongSubtitle ) {
if (data.midPoint) {
this.result = data.midPoint;
} else if (data.endPoint) {
arrs.push(data.endPoint);
this.pagraph = arrs.join("\n");
this.result = "";
}
} else {
this.result = data.text;
}
};
asr.onStarted = () => {
console.log("onstarted");
this.audioRecordState = AudioRecordState.ready;
};
this.asr = asr;
},
async recordAudio() {
console.log("recordAudio start");
if (this.audioRecordState == AudioRecordState.record) {
console.log(`正在录音中,不允许重复录音`);
return;
}
if (this.audioRecordState != AudioRecordState.ready) {
console.log(`asr 接口还没ready ,请稍后`);
return;
}
const audioRecorder = media.createAudioRecord({
channelConfig: 1,
sampleRateInHz: 16000,
});
this.audioRecordState = AudioRecordState.record;
audioRecorder.read({
callback: (buffer) => {
this.asr.send(buffer);
},
});
this.asr.onError = (data, code) => {
console.log(`ux ws.onError data:${data};code:${code}`);
this.audioRecordState = AudioRecordState.stop;
audioRecorder.stop();
audioRecorder.release();
};
this.asr.onFinished = (reason) => {
console.log(`ux onFinished ${reason}`);
this.audioRecordState = AudioRecordState.stop;
audioRecorder.stop();
audioRecorder.release();
};
this.audioRecorder = audioRecorder;
},
startWebsocket() {
this.asr.start();
},
releaseRecord() {
if (this.audioRecorder) {
this.audioRecorder.stop();
this.audioRecorder.release();
this.asr && this.asr.finish();
}
this.audioRecordState = AudioRecordState.stop;
},
};

createTts(auth:Auth,engineId:string,clientInfo:ClientInfo):TtsInstance

Section titled “createTts(auth:Auth,engineId:string,clientInfo:ClientInfo):TtsInstance”

创建 TTS 文字转语音服务实例

属性必填类型默认值说明
authAuth请求的身份验证信息,确保请求来源合法
modelTtsModelTtsModel.LongDefaultTTS 音频生成模型,支持短音频模型与长音频生成模型
configTtsConfig初始化 TTS 客户端相关配置
isNeedPlaybooleanfalse设置是否让TTS实例来播放声音,如果不需要TTS实例播放声音,则可以通过回调方法onMessage中 TtsResult.audio 获得合成语音的PCM类型数据
属性必填类型说明
appIdstring应用 appId
appKeystring应用 appKey

注: appId & appKey,需要在 vivo 开发者平台 申请

属性说明
ShortJovi短音频生成,适用于对话合成场景,比如语音助手的应用场景
LongDefault长音频生成,适用于长文本合成场景,比如小说阅读,屏幕朗读
参数类型说明必填默认值
engineTypeEngineType引擎类型, 支持中英文与优化效果EngineType.normal
audioTypeAudioType音频类型AudioType.Pcm
sampleRatenumber采样率。采样率越高,语音合成播放的效果越好,但是占用流量更多。可选值:[8000,16000,24000]24000
speakerShortSpeakerLongSpeaker语音合成的发音人
speednumber语速,可选值:[0-100]50
volumenumber音量,可选值:[1-100]50
isStreamboolean是否按照流式方式返回音频,假如设置为 false 则按标点分段返回true
属性说明
normal普通效果
enZh中英文
en英文
optimized优化效果
属性说明
Pcmpcm 音频类型
Opusopus 音频类型
属性说明
yiwen奕雯
yunye云野-温柔
wanqing婉清
xiaofu晓芙-少女
yigeChild小萌-女童
yige依格
yiyi依依
xiaoming小茗
属性说明
yiwen奕雯
yunye云野-温柔
yunyeNews云野-稳重
yige依格-甜美
yigeNews依格-稳重
huaibin怀斌-浑厚
zhaokun兆坤-成熟
yaheng亚恒-磁性
haiwei海蔚-大气
qianqian倩倩-清甜
enFemale英文女声
xiaoyun晓云-稳重

连接文本转语音服务

断开文本转语音服务,并且释放网络资源与相关播放器资源。建议在应用销毁时调用。

发送文本内容

tts 实例服务暂停播放音频

tts 实例服务恢复播放音频

文字转语音服务连接成功的回调。在调用 connect() 连接服务成功后触发。服务连接成功后,文字转语音服务将开始处理通过 send() 接口发送的文本内容。

TtsInstance.onMessage = (result:TtsResult) =>{}

Section titled “TtsInstance.onMessage = (result:TtsResult) =>{}”

文本识别信息回调。通过 send()接口发送文本内容后,文本识别结果将通过该回调事件返回

参数类型说明
audioUnit8Array合成后的音频片段
statusnumber当前音频流状态,0 表示开始合成(返回的第一帧数据),1 表示合成中,2 表示合成结束(返回的最后一帧数据)
progressstring合成进度,指当前合成文本的字符数-总的字符数。注:请注意合成是以句为单位切割的,若文本只有一句话,则每次返回结果是相同的。
sliceint返回的第几帧数据

播放开始回调

播放暂停回调,调用了TtsInstance.pauseAudio()后会触发此回调

TtsInstance.onSpeakProgress = (progress:string) =>{}

Section titled “TtsInstance.onSpeakProgress = (progress:string) =>{}”

播放进度信息回调。开始播放后,播放进度信息会通过该回调多次触发,直到播放完毕。

参数类型说明
progressstring播放进度,指当前播放文本的字符数-总的字符数。注:请注意合成是以句为单位切割的,若文本只有一句话,则每次返回结果是相同的。

播放完毕回调

恢复播放回调,调用了TtsInstance.resumeAudio()后会触发此回调

TtsInstance.onError = (data:string, code: number) =>{}

Section titled “TtsInstance.onError = (data:string, code: number) =>{}”

文字转语音服务异常回调

属性类型说明
datastring失败信息描述
codeFailCodeEnum失败业务码
属性说明
10000缺少请求参数或者签名错误 (http 协议返回,status=400)
10001升级到 websocket 协议失败(http 协议返回,status=400)
10010发送数据不是 json 格式
10011发送文本时,缺少必要的参数
10012发送文本时,签名错误
以下是逻辑层服务器错误
10030发送文本到引擎时错误
10031获取 audio 数据发生错误
10032无可用的引擎服务器
以下是引擎层服务器错误
11001负载过大,拒绝新的请求
11002请求头协议错误
11003设置合成文本的请求参数错误
11004获取 andio 数据的请求参数错误
11005session 重复了
11006获取数据时,找到不到 session
11007创建引擎错误
11008向算法引擎获取数据时出错
11009opus 压缩出现问题
11010输入的合成文本不合法
以下是语音服务层错误
20000语音正在合成中,不允许发送新的文字
20010语音缓存已满
20030语音服务已经断连
import media from "@blueos.media.audio.mediaManager";
import speech from "@blueos.ai.speech";
/**
* 录音状态
* @enum {number}
*/
const AudioRecordState = {
/** 录音结束 */
init: 0,
inited: 1,
play: 1,
stop: 2,
release: 3,
};
export default {
data: {
title: "欢迎体验 AI 服务",
inputtext: "你好",
auth: {
appId: "您的appId",
appKey: "您的appKey",
},
tts: null,
model: "",
audioRecorder: null,
audioRecordState: AudioRecordState.stop,
},
createShort() {
this.model = speech.TtsModel.ShortJovi;
this.createTts();
},
createLong() {
this.model = speech.TtsModel.LongDefault;
this.createTts();
},
createTts() {
const tts = speech.createTts({
auth: this.auth,
model: this.model,
config: {
speaker: speech.ShortSpeaker.yige,
sampleRate: 24000,
isStream: false,
},
});
tts.onMessage = (data) => {
if (this.audioRecorder) {
this.audioRecorder.write({
buffer: data.audio.buffer,
});
}
};
tts.onConnected = () => {
logtool("onConnected");
this.modetext = "短语音实例已连接"
};
this.tts = tts;
},
async createAudio() {
const audioRecorder = media.createAudioTrack({
sampleRateInHz: 24000,
contentType: "speech",
channelConfig: 1,
audioFormat: 16,
});
audioRecorder.onError = function () {
logtool(`createAudioRecord error`);
this.audioRecordState = AudioRecordState.stop;
};
this.audioRecordState = AudioRecordState.inited;
logtool(`createAudioRecord success`);
this.audioRecorder = audioRecorder;
},
connect() {
this.tts && this.tts.connect()
},
send() {
this.tts && this.tts.send(this.inputtext);
},
stop() {
this.audioRecordState = AudioRecordState.stop
this.audioRecorder && this.audioRecorder.stop();
},
release() {
this.audioRecordState = AudioRecordState.release
this.audioRecorder && this.audioRecorder.release();
},
play() {
this.audioRecordState = AudioRecordState.play
this.audioRecorder && this.audioRecorder.play();
},
releaseRecord() {
if (this.audioRecorder) {
this.audioRecorder.stop();
this.audioRecorder.release();
}
},
};