本文介绍了如何使用阿里云智能语音服务提供的HarmonyOS Next NUI SDK,包括SDK下载安装、关键接口及代码示例。
前提条件
下载安装
下载harmony.zip。
说明下载后请在样例初始化代码中替换您的阿里云账号信息、
Appkey
和Token
才可运行。类别
兼容范围
系统
支持HarmonyOS Next 5.0 版本,API LEVEL 12, DevEco Studio版本号5.0.3.403
架构
arm64-v8a
此SDK还包含如下功能,若未支持您想要的功能,请去对应文档获取SDK。
功能
是否支持
一句话识别
是
实时语音识别
是
语音合成
是
实时长文本语音合成
是
流式文本语音合成
是
离线语音合成
否
录音文件识别极速版
是
唤醒及命令词
否
听悟实时推流
是
以arkts HAR包的形式进行集成。解压ZIP包,其中nuisdk-release/neonui.har 是SDK生成的HAR包文件,在用户工程项目中导入调用即可。如果需要HarmonyOS Next CPP接入方式,可在ZIP包的harmonyos_libs和harmonyos_include中获得动态库和头文件。
使用DevEco Studio打开harmony_nlsdemo目录下工程查看参考代码实现,其中流式TTS示例代码为StreamTTSClass.ets文件,替换UserKey.ets中 UserKeyStreamTTS类的Appkey和Token后,即可直接运行。(流式TTS工程测试流向为 home.ets->StreamTTSThread.ets->WorkerStreamTTSClass.ets->StreamTTSClass.ets)
关键接口
startStreamInputTts:开始运行流式TTS。
/** * 开始运行流式TTS。请勿在UI线程调用,可能会引起阻塞。 * @param callback:事件监听回调,参见下文具体回调。 * @param ticket:json string形式的初始化参数,参见下方说明。 * @param parameters:json string形式的初始化参数,参见下方说明。 * @param session_id:当前会话的id,若客户端请求时传入则原样返回,否则由服务端自动生成32位唯一ID。 * @param level:log打印级别,值越小打印越多。 * @param save_log:是否保存log为文件,存储目录为ticket中的debug_path字段值。注意,log文件无上限,请注意持续存储导致磁盘存满。 * @return:参见错误码:https://help.aliyun.com/document_detail/459864.html。 */ public startStreamInputTts( callback:INativeStreamInputTtsCallback, ticket:string, parameters:string, session_id:string, log_level:number, save_log:boolean):number
其中,INativeStreamInputTtsCallback类型包含如下回调。
onStreamInputTtsEventCallback:SDK事件回调。
/** * 事件回调 * @param event:回调事件,参见如下事件列表。 * @param task_id:整个实时语音合成会话的任务ID,整个请求中需要保持一致,32位唯一ID。 * @param session_id:当前会话的id,若客户端请求时传入则原样返回,否则由服务端自动生成32位唯一ID。 * @param ret_code:参见错误码,出现STREAM_INPUT_TTS_EVENT_TASK_FAILED事件时有效,可查阅https://help.aliyun.com/document_detail/459864.html。 * @param error_msg:详细错误信息,出现STREAM_INPUT_TTS_EVENT_TASK_FAILED事件时有效。 * @param timestamp:合成结果中时间戳相关信息。 * @param all_response:完整的json string格式返回消息,可从中解析需要的信息。 */ onStreamInputTtsEventCallback(event:StreamInputTtsEvent, task_id:string, session_id:string, ret_code:number, error_msg:string, timestamp:string, all_response:string):void;
事件列表:
名称
说明
STREAM_INPUT_TTS_EVENT_SYNTHESIS_STARTED
语音合成开始,准备播放。
STREAM_INPUT_TTS_EVENT_SENTENCE_BEGIN
服务端检测到了一句话的开始。
STREAM_INPUT_TTS_EVENT_SENTENCE_SYNTHESIS
增量返回语音合成的结果,包含最新的音频和时间戳,句内全量,句间增量。
STREAM_INPUT_TTS_EVENT_SENTENCE_END
服务端检测到了一句话的结束,返回该句的全量时间戳。
STREAM_INPUT_TTS_EVENT_SYNTHESIS_COMPLETE
服务端检测到了一句话的结束,返回该句的全量时间戳。
STREAM_INPUT_TTS_EVENT_TASK_FAILED
语音合成发生错误,详见ret_code和error_msg。
onStreamInputTtsDataCallback:合成数据回调。
/** * 合成数据回调。 * @param data:合成的音频数据,写入播放器。 */ onStreamInputTtsDataCallback(data:ArrayBuffer|null):void
其中,ticket初始化相关参数说明,生成示例参见下方代码示例:
参数
类型
是否必选
说明
url
String
否
服务地址,默认使用北京服务。
app_key
String
是
管控台创建项目的appkey。
token
String
是
请确保该Token可以使用并在有效期内。
debug_path
String
否
当save_log为true时,将会把运行日志存储在此路径下。
complete_waiting_ms
Integer
否
调用stop后等待STREAM_INPUT_TTS_EVENT_SYNTHESIS_COMPLETE的超时时间,单位ms,默认10s。
parameters任务相关参数说明,生成示例参见下方代码示例:
参数
类型
是否必选
说明
voice
String
是
说话人音色。
format
String
否
音频编码格式,如
pcm
、wav
、mp3
。sample_rate
Integer
否
音频采样率,24000,可选择8000、16000、24000、48000。
volume
Integer
否
朗读音量,范围是0~100,默认50。
speech_rate
Integer
否
朗读语速,范围是-500~500,默认是0。
pitch_rate
Integer
否
朗读语调,范围是-500~500,默认是0。
enable_subtitle
Boolean
否
开启字级别时间戳。更多使用方法,请参见时间戳功能介绍。
stopStreamInputTts: 停止语音合成
/** * 停止语音合成,等待接收完所有合成数据直到STREAM_INPUT_TTS_EVENT_SYNTHESIS_COMPLETE。 * @param flag_async:stop过程是否使用异步过程。 true表示stopStreamInputTts接口调用是异步的,函数调用可以快速返回,合成COMPLETE事件异步返回。false表示接口调用会block指定时间,直到合成COMPLETE事件或者FAILED事件。默认为true,避免block引起用户线程堵塞超时。 * @return:参见错误码:https://help.aliyun.com/document_detail/459864.html。 */ public stopStreamInputTts(flag_async:boolean=true):number
sendStreamInputTts:发送待合成文本
/** * 发送待合成文本 * @param text:待合成文本,仅支持采用UTF-8编码的文本输入。单次合成推荐少于5000字,总计不超过10万字,其中1个汉字、1个英文字母、1个标点或1个句子中间空格均算作1个字符。 * @return:参见错误码:https://help.aliyun.com/document_detail/459864.html。 */ public sendStreamInputTts(text:string):number
调用步骤
创建SDK类对象实例
初始化SDK和播放组件。
根据业务需求设置参数。
调用startStreamInputTts开始进行流式文本语音合成。
调用sendStreamInputTts持续发送待合成文本。在合成数据回调中,将数据写入播放器进行播放,建议使用流式播放。
调用stopStreamInputTts表示文本发送完成,等待合成完毕。
收到语音合成结束的回调或者合成出错的回调,进行对应响应。
代码示例
开始语音合成
//SDK初始化
//导入所需的SDK模块
import {Constants, NativeNui, INativeStreamInputTtsCallback, StreamInputTtsEvent} from 'neonui'
//实现回调处理函数。 具体实现见文档最下面回调代码部分
const g_ttscallback_instance:INativeStreamInputTtsCallback = {
onStreamInputTtsEventCallback: cb_tts_event_callback,
onStreamInputTtsDataCallback: cb_tts_user_data_callback
};
//创建SDK类对象实例
NativeNui stream_input_tts_instance = new NativeNui(Constants.ModeType.MODE_STREAM_INPUT_TTS);
//调用startStreamInputTts开始进行流式文本语音合成。
let ret:number = this.stream_input_tts_instance.startStreamInputTts(
g_ttscallback_instance,
genTicketTTS(),
genParameters(this.fontname), "",
Constants.LogLevel.toInt(Constants.LogLevel.LOG_LEVEL_VERBOSE), false )
其中genTicketTTS生成为String JSON串,包含用户信息。其中用户信息包含如下字段,获取方式请参考接口说明文档。
/**
* ticket生成示例,详见Demo工程中代码示例
*/
function genTicketTTS():string {
//郑重提示:
// 语音交互服务需要先准备好账号,并开通相关服务。具体步骤请查看:
// https://help.aliyun.com/zh/isi/getting-started/start-here
//
//原始账号:
// 账号(子账号)信息主要包括AccessKey ID(后续简称为ak_id)和AccessKey Secret(后续简称为ak_secret)。
// 此账号信息一定不可存储在app代码中或移动端侧,以防账号信息泄露造成资费损失。
//
//STS临时凭证:
// 由于账号信息下发给客户端存在泄露的可能,阿里云提供的一种临时访问权限管理服务STS(Security Token Service)。
// STS是由账号信息ak_id和ak_secret,通过请求生成临时的sts_ak_id/sts_ak_secret/sts_token
// (为了区别原始账号信息和STS临时凭证, 命名前缀sts_表示STS生成的临时凭证信息)
//什么是STS:https://help.aliyun.com/zh/ram/product-overview/what-is-sts
//STS SDK概览:https://help.aliyun.com/zh/ram/developer-reference/sts-sdk-overview
//STS Python SDK调用示例:https://help.aliyun.com/zh/ram/developer-reference/use-the-sts-openapi-example
//
//账号需求说明:
// 若使用离线功能(离线语音合成、唤醒), 则必须app_key、ak_id和ak_secret,或app_key、sts_ak_id、sts_ak_secret和sts_token
// 若使用在线功能(语音合成、实时转写、一句话识别、录音文件转写等), 则只需app_key和token
let str:string = "";
//获取token方式:
let object:object = Object({
"appkey" : UserKeyStreamTTS.app_key,
"token" : UserKeyStreamTTS.token,
"url" : UserKeyStreamTTS.url
})
str = JSON.stringify(object);
console.info("in genTicketTTS, UserContext:" + str);
return str;
}
genParameters生成为String JSON串,包含参数信息,请参考接口说明文档。
function genParameters(voice:string):string {
let str:string = "";
let object:object = Object({
"enable_subtitle" : "1",
"voice" : "zhixiaoxia",
"format" : "pcm",
"sample_rate" : "16000",
"volume" : "50",
"speech_rate" : "0",
"pitch_rate" : "0"
})
str = JSON.stringify(object);
console.info("in genParameters, UserContext:" + str);
return str;
}
流式发送合成文本
let ttstext1:string = "番茄炒蛋怎么做?";
let ttstext2:string = "必须是色香味俱全的做法哦。";
console.log(`womx ttstext1 is ${ttstext1}`);
this.stream_input_tts_instance.sendStreamInputTts(ttstext1)
console.log(`womx ttstext2 is ${ttstext2}`);
this.stream_input_tts_instance.sendStreamInputTts(ttstext2)
结束语音合成
this.stream_input_tts_instance.stopStreamInputTts()
回调处理
onStreamInputTtsEventCallback:流式文本语音合成事件回调,根据语音合成状态控制播放器。
//实现回调处理函数 let countNumber:number = 0 function cb_tts_event_callback(event:StreamInputTtsEvent, task_id:string, session_id:string, ret_code:number, error_msg:string, timestamp:string, all_response:string):void{ //console.info("womx cb_tts_event_callback %d %s %d", event, task_id, code); console.info( "stream input tts event:" + event + " session id " + session_id + " session id " + task_id + " ret " + ret_code); if (event == StreamInputTtsEvent.STREAM_INPUT_TTS_EVENT_SYNTHESIS_STARTED) { console.info("STREAM_INPUT_TTS_EVENT_SYNTHESIS_STARTED"); //waitinginit() //返回合成开始 事件时,初始化播放器,以免播放器过早初始化引起状态异常。 countNumber=0 console.info("start play"); } else if (event == StreamInputTtsEvent.STREAM_INPUT_TTS_EVENT_SENTENCE_SYNTHESIS) { console.info("STREAM_INPUT_TTS_EVENT_SENTENCE_SYNTHESIS:" + timestamp); } else if (event == StreamInputTtsEvent.STREAM_INPUT_TTS_EVENT_SYNTHESIS_COMPLETE || event == StreamInputTtsEvent.STREAM_INPUT_TTS_EVENT_TASK_FAILED) { /* * 提示: STREAM_INPUT_TTS_EVENT_SYNTHESIS_COMPLETE事件表示TTS已经合成完并通过回调传回了所有音频数据, 而不是表示播放器已经播放完了所有音频数据。 */ //合成完毕或者合成出错。进行响应 console.info("play end"); // 表示推送完数据 //AudioRenderer.voiceEnd() //合成结束,通知播放器数据结束,等待播放完毕即可。 is_started = false; if (event == StreamInputTtsEvent.STREAM_INPUT_TTS_EVENT_TASK_FAILED) { console.info("STREAM_INPUT_TTS_EVENT_TASK_FAILED error_code:" + ret_code + " errmsg:" + error_msg); //AudioRenderer.voiceStop(true) //合成出错,直接停止播放器播报 } } else if (event == StreamInputTtsEvent.STREAM_INPUT_TTS_EVENT_SENTENCE_BEGIN) { console.info("STREAM_INPUT_TTS_EVENT_SENTENCE_BEGIN:" + all_response); } else if (event == StreamInputTtsEvent.STREAM_INPUT_TTS_EVENT_SENTENCE_END) { console.info("STREAM_INPUT_TTS_EVENT_SENTENCE_END:" + all_response); } }
onStreamInputTtsDataCallback:语音合成数据回调,将回调中的合成数据写入播放器进行播放。
function cb_tts_user_data_callback(buffer:ArrayBuffer|null):void{ console.log(`womx cb_tts_user_data_callback uid[${process.uid}] pid[${process.pid}] tid[${process.tid}]`); countNumber+=1 if (1==countNumber) { //waitingstart() //返回合成的第一帧数据,此时启动播放器 } if (buffer){ console.info("womx cb_tts_user_data_callback %d. times=%d", buffer.byteLength, countNumber); if (buffer.byteLength > 0) { //合成的数据送到播放器模块进行实时播放。注意,合成的数据是短时间内生成较多数据,需要控制数据缓存与播放器的流式播报进度之间的匹配度 /*if (gFlagAudioRendererUseCallback) { AudioRenderer.setVoiceArrayBuffer(buffer as ArrayBuffer) } else { AudioRenderer.writePlayerData(buffer) }*/ } } else { console.info("womx cb_tts_user_data_callback undefined"); } }