本文介紹了如何使用阿里云智能語音服務提供的HarmonyOS Next NUI SDK,包括SDK下載安裝、關鍵接口及代碼示例。
前提條件
下載安裝
下載V1.5.016.napi.001.003_5d87aea0fa4f42e1b5bb254573fbbcc6af546c6b.tar.gz。
說明下載后請在樣例初始化代碼中替換您的阿里云賬號信息、
Appkey
和Token
才可運行。類別
兼容范圍
系統
支持HarmonyOS Next 5.0 版本,API LEVEL 12, DevEco Studio版本號5.0.3.403
架構
arm64-v8a
此SDK還包含如下功能,若未支持您想要的功能,請去對應文檔獲取SDK。
功能
是否支持
一句話識別
是
實時語音識別
是
語音合成
是
實時長文本語音合成
是
流式文本語音合成
是
離線語音合成
否
錄音文件識別極速版
是
喚醒及命令詞
否
聽悟實時推流
是
以arkts HAR包的形式進行集成。解壓壓縮包,其中entry/libs/neonui.har 是SDK生成的HAR包文件,在用戶工程項目中導入調用即可。如果需要HarmonyOS Next CPP接入方式,可在壓縮包的native/libs和native/include中獲得動態庫和頭文件。
使用DevEco Studio打開工程,其中流式TTS示例代碼為StreamTTSPage.ets文件,替換UserKey.ets中 UserKeyStreamTTS類的Appkey和Token后,即可直接運行。(流式TTS工程測試流向為 Index.ets->StreamTTSPage.ets->StreamTTS.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:參見錯誤碼:http://bestwisewords.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事件時有效,可查閱http://bestwisewords.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:參見錯誤碼:http://bestwisewords.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:參見錯誤碼:http://bestwisewords.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 {
//鄭重提示:
// 語音交互服務需要先準備好賬號,并開通相關服務。具體步驟請查看:
// http://bestwisewords.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:http://bestwisewords.com/zh/ram/product-overview/what-is-sts
//STS SDK概覽:http://bestwisewords.com/zh/ram/developer-reference/sts-sdk-overview
//STS Python SDK調用示例:http://bestwisewords.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"); } }