Android SDK
本文介紹了如何使用阿里云離線語音合成服務(wù)提供的Android NUI SDK,包括下載安裝SDK和語音包、SDK關(guān)鍵接口及代碼示例。
前提條件
閱讀接口說明,詳情請(qǐng)參見接口說明。
已獲取項(xiàng)目Appkey,詳情請(qǐng)參見創(chuàng)建項(xiàng)目。
已獲取AccessKey ID和 AccessKey Secret,詳情請(qǐng)參見開通服務(wù)。
下載安裝
- 重要
下載后在樣例初始化代碼中替換您的阿里云賬號(hào)信息、Appkey才可運(yùn)行。
類別
兼容范圍
系統(tǒng)
支持Android 4.0 以上版本,API LEVEL 14
架構(gòu)
armeabi-v7a,arm64-v8a,x86,x86_64
此SDK還包含如下功能,若未支持您想要的功能,請(qǐng)前往對(duì)應(yīng)文檔獲取SDK。
功能
是否支持
一句話識(shí)別
是
實(shí)時(shí)語音識(shí)別
是
語音合成
是
實(shí)時(shí)長(zhǎng)文本語音合成
是
流式文本語音合成
是
離線語音合成
是
錄音文件識(shí)別極速版
是
喚醒及命令詞
否
聽悟?qū)崟r(shí)推流
是
下載語音包,詳情請(qǐng)參見接口說明中的語音包列表。
重要SDK和語音包是完全獨(dú)立的,下載SDK后并不能直接使用,需要下載語音包,并設(shè)置語音包存放路徑。
解壓ZIP包,在
app/libs
目錄下獲取AAR格式的SDK包。若需要Android CPP接入方式,則可在ZIP包的android_libs和android_include中獲得動(dòng)態(tài)庫和頭文件。使用Android Studio打開此工程。其中語音合成示例代碼為TtsLocalActivity.java文件。
SDK關(guān)鍵接口
tts_initialize:初始化SDK。
/** * 初始化SDK,離線合成暫不支持多實(shí)例,請(qǐng)先釋放后再次進(jìn)行初始化。請(qǐng)勿在UI線程調(diào)用,可能會(huì)引起阻塞。 * 初始化是耗時(shí)操作,不需要合成一個(gè)任務(wù)就進(jìn)行該操作;在啟動(dòng)和退出時(shí)進(jìn)行一次即可。 * @param callback:事件監(jiān)聽回調(diào),參見下文具體回調(diào)。 * @param ticket:json string形式的初始化參數(shù),參見下方說明或接口說明:http://bestwisewords.com/document_detail/204185.html。 * @param level:log打印級(jí)別,值越小打印越多。 * @param save_log:是否保存log為文件,存儲(chǔ)目錄為ticket中的debug_path字段值。注意,log文件無上限,請(qǐng)注意持續(xù)存儲(chǔ)導(dǎo)致磁盤存滿。 * @return:參見錯(cuò)誤碼:http://bestwisewords.com/document_detail/459864.html。 */ public synchronized int tts_initialize(INativeTtsCallback callback, String ticket, final Constants.LogLevel level, boolean save_log);
INativeTtsCallback類型包含如下回調(diào):
onTtsEventCallback:SDK事件回調(diào)。
/** * 事件回調(diào) * @param event:回調(diào)事件,參見如下事件列表。 * @param task_id:請(qǐng)求的任務(wù)ID。 * @param ret_code:參見錯(cuò)誤碼,出現(xiàn)TTS_EVENT_ERROR事件時(shí)有效,可查閱http://bestwisewords.com/document_detail/459864.html。 */ void onTtsEventCallback(TtsEvent event, String task_id, int ret_code);
事件列表:
名稱
說明
TTS_EVENT_START
語音合成開始,準(zhǔn)備播放。
TTS_EVENT_END
語音合成結(jié)束,合成數(shù)據(jù)已全部拋出,但并不表示播放結(jié)束。
TTS_EVENT_CANCEL
取消語音合成。
TTS_EVENT_PAUSE
語音合成暫停。
TTS_EVENT_RESUME
語音合成恢復(fù)。
TTS_EVENT_ERROR
語音合成發(fā)生錯(cuò)誤。可通過getparamTts("error_msg")獲得詳細(xì)錯(cuò)誤消息。
onTtsDataCallback:合成數(shù)據(jù)回調(diào)。
/** * @param info:使用時(shí)間戳功能時(shí),返回JSON格式的時(shí)間戳結(jié)果。 * @param info_len:info字段的數(shù)據(jù)長(zhǎng)度,暫不使用。 * @param data:合成的音頻數(shù)據(jù),寫入播放器。 */ void onTtsDataCallback(String info, int info_len, byte[] data);
其中,ticket內(nèi)容參數(shù)說明,生成示例參見下方代碼示例:
參數(shù)
類型
是否必選
說明
workspace
String
是
工作目錄路徑,SDK從該路徑讀取配置文件。需要有讀寫權(quán)限。
app_key
String
是
管控臺(tái)創(chuàng)建項(xiàng)目的appkey。
ak_id
String
是
阿里云賬號(hào)的AccessKey中的AccessKey ID,用于標(biāo)識(shí)用戶。或?yàn)榘⒗镌芐TS(Security Token Service)的AccessKey ID。具體可見代碼示例中賬號(hào)鑒權(quán)相關(guān)說明。
ak_secret
String
是
阿里云賬號(hào)的AccessKey中的AccessKey Secret,用于驗(yàn)證用戶的密鑰。AccessKey Secret必須保密。或?yàn)榘⒗镌芐TS(Security Token Service)的AccessKey Secret。具體可見代碼示例中賬號(hào)鑒權(quán)相關(guān)說明。
token
String
否
訪問令牌(Access Token)。若使用阿里云賬號(hào)的AccessKey,則使用此參數(shù)token。若使用阿里云STS(Security Token Service)的AccessKey,則使用sts_token。具體可見代碼示例中賬號(hào)鑒權(quán)相關(guān)說明。
sts_token
String
否
臨時(shí)安全令牌(STS Token)。若使用阿里云STS(Security Token Service)的AccessKey,則使用此參數(shù)sts_token。若使用阿里云賬號(hào)的AccessKey,則使用token。具體可見代碼示例中賬號(hào)鑒權(quán)相關(guān)說明。
device_id
String
是
用戶層面的賬戶號(hào)。此為扣費(fèi)依據(jù),若device_id重復(fù)則會(huì)被認(rèn)為非法ID,導(dǎo)致離線語音合成無法工作。若device_id隨機(jī)變化,則會(huì)出現(xiàn)重復(fù)計(jì)費(fèi)的情況。請(qǐng)保證此device_id唯一性且不會(huì)變化。
mode_type
String
是
設(shè)置成離線語音合成模式,語音合成必須設(shè)置成“0”,這個(gè)設(shè)置很重要, 遺漏會(huì)導(dǎo)致無法運(yùn)行
setparamTts:設(shè)置參數(shù)。
/** * 以鍵值對(duì)形式設(shè)置參數(shù), 參見接口說明:http://bestwisewords.com/document_detail/204185.html * @param param:參數(shù)名,參見接口說明。 * @param value:參數(shù)值,參見接口說明。 * @return:參見錯(cuò)誤碼:http://bestwisewords.com/document_detail/459864.html。 */ public synchronized int setparamTts(String param, String value);
getparamTts:獲取參數(shù)。
/** * 獲取參數(shù)值 * @param param:參數(shù)名,參考接口說明:http://bestwisewords.com/document_detail/204185.html。 * @return:參數(shù)值。 */ public String getparamTts(String param);
startTts:開始合成。
/** * 開始合成任務(wù) * @param priority:任務(wù)優(yōu)先級(jí),請(qǐng)使用"1"。 * @param taskid:任務(wù)ID,可傳入32個(gè)字節(jié)的uuid,或傳入空內(nèi)容由SDK自動(dòng)生成。 * @param text:播放的文本內(nèi)容。 * @return:參見錯(cuò)誤碼:http://bestwisewords.com/document_detail/459864.html。 */ public synchronized int startTts(String priority, String taskid, String text);
cancelTts:取消合成。
/** * 取消合成任務(wù) * @param taskid:傳入想要停止的任務(wù)ID,如果為空則取消所有任務(wù)。 * @return:參見錯(cuò)誤碼:http://bestwisewords.com/document_detail/459864.html。 */ public synchronized int cancelTts(String taskid);
pauseTts:暫停合成。
/** * 暫停合成任務(wù) * @return:參見錯(cuò)誤碼:http://bestwisewords.com/document_detail/459864.html。 */ public synchronized int pauseTts();
resumeTts:恢復(fù)合成。
/** * 恢復(fù)暫停的任務(wù) * @return:參見錯(cuò)誤碼:http://bestwisewords.com/document_detail/459864.html。 */ public synchronized int resumeTts();
tts_release:釋放SDK資源。
/** * 釋放SDK * @return:參見錯(cuò)誤碼:http://bestwisewords.com/document_detail/459864.html。 */ public synchronized int tts_release();
調(diào)用步驟
初始化SDK和播放組件。
根據(jù)業(yè)務(wù)需求設(shè)置參數(shù)。
調(diào)用startTts進(jìn)行播放。
在合成數(shù)據(jù)回調(diào)中,將數(shù)據(jù)寫入播放器進(jìn)行播放,建議使用流式播放。
收到語音合成結(jié)束的回調(diào)。
代碼示例
語音合成初始化。
//設(shè)置默認(rèn)目的地路徑最下級(jí)目錄名字 // 比如設(shè)置當(dāng)前 /data/user/0/mit.alibaba.nuidemo/files/asr_my // 未調(diào)用此接口, 則默認(rèn)為 /data/user/0/mit.alibaba.nuidemo/files/asr_my CommonUtils.setTargetDataDir("asr_my"); //這里獲得當(dāng)前nuisdk.aar中assets可以搬運(yùn)的默認(rèn)目的地路徑, // 比如 /data/user/0/mit.alibaba.nuidemo/files/asr_my path = CommonUtils.getModelPath(this); Log.i(TAG, "workpath:" + path); //這里主動(dòng)調(diào)用完成SDK配置文件的拷貝目的地為CommonUtils.getModelPath(this); // 比如當(dāng)前為 /data/user/0/mit.alibaba.nuidemo/files/asr_my if (CommonUtils.copyTtsAssetsData(this)) { Log.i(TAG, "copy assets data done"); } else { Log.e(TAG, "copy assets failed"); ToastText("從aar的assets拷貝資源文件失敗, 請(qǐng)檢查資源文件是否存在, 詳情可通過日志確認(rèn)。"); return; } // 注意: 比如鑒權(quán)文件為 /data/user/0/mit.alibaba.nuidemo/files/asr_my/tts/ttset.bin // 切勿覆蓋和刪除asr_my內(nèi)文件 //SDK初始化 NativeNui nui_tts_instance = new NativeNui(Constants.ModeType.MODE_TTS); int ret = nui_tts_instance.tts_initialize(new INativeTtsCallback() {}, genInitParams(path), Constants.LogLevel.LOG_LEVEL_VERBOSE, true);
其中,genInitParams生成為String JSON字符串,包含資源目錄和用戶信息。其中用戶信息包含如下字段。
說明精品版sdk_code為software_nls_tts_offline
普通版sdk_code為software_nls_tts_offline_standard
/** * ticket生成示例,詳見Demo工程中代碼示例 */ private String genInitParams(String workpath) { String str = ""; try { //鄭重提示: // 語音交互服務(wù)需要先準(zhǔn)備好賬號(hào),并開通相關(guān)服務(wù)。具體步驟請(qǐng)查看: // http://bestwisewords.com/zh/isi/getting-started/start-here // //原始賬號(hào): // 賬號(hào)(子賬號(hào))信息主要包括AccessKey ID(后續(xù)簡(jiǎn)稱為ak_id)和AccessKey Secret(后續(xù)簡(jiǎn)稱為ak_secret)。 // 此賬號(hào)信息一定不可存儲(chǔ)在app代碼中或移動(dòng)端側(cè),以防賬號(hào)信息泄露造成資費(fèi)損失。 // //STS臨時(shí)憑證: // 由于賬號(hào)信息下發(fā)給客戶端存在泄露的可能,阿里云提供的一種臨時(shí)訪問權(quán)限管理服務(wù)STS(Security Token Service)。 // STS是由賬號(hào)信息ak_id和ak_secret,通過請(qǐng)求生成臨時(shí)的sts_ak_id/sts_ak_secret/sts_token // (為了區(qū)別原始賬號(hào)信息和STS臨時(shí)憑證, 命名前綴sts_表示STS生成的臨時(shí)憑證信息) //什么是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調(diào)用示例:http://bestwisewords.com/zh/ram/developer-reference/use-the-sts-openapi-example // //賬號(hào)需求說明: // 若使用離線功能(離線語音合成、喚醒), 則必須app_key、ak_id和ak_secret,或app_key、sts_ak_id、sts_ak_secret和sts_token // 若使用在線功能(語音合成、實(shí)時(shí)轉(zhuǎn)寫、一句話識(shí)別、錄音文件轉(zhuǎn)寫等), 則只需app_key和token JSONObject initObject = Auth.getTicket(Auth.GetTicketMethod.GET_STS_ACCESS_FROM_SERVER_FOR_OFFLINE_FEATURES); if (!object.containsKey("token")) { Log.e(TAG, "Cannot get token!!!"); } object.put("url", "wss://nls-gateway.cn-shanghai.aliyuncs.com:443/ws/v1"); // 默認(rèn) //工作目錄路徑,SDK從該路徑讀取配置文件 object.put("workspace", workpath); // 必填, 且需要有讀寫權(quán)限 initObject.put("mode_type", Constants.TtsModeTypeLocal); // 必填 // 特別說明: 鑒權(quán)所用的id是由以下device_id,與手機(jī)內(nèi)部的一些唯一碼進(jìn)行組合加密生成的。 // 更換手機(jī)或者更換device_id都會(huì)導(dǎo)致重新鑒權(quán)計(jì)費(fèi)。 // 此外, 以下device_id請(qǐng)?jiān)O(shè)置有意義且具有唯一性的id, 比如用戶賬號(hào)(手機(jī)號(hào)、IMEI等), // 傳入相同或隨機(jī)變換的device_id會(huì)導(dǎo)致鑒權(quán)失敗或重復(fù)收費(fèi)。 object.put("device_id", "empty_device_id"); // 必填, 推薦填入具有唯一性的id, 方便定位問題 str = object.toString(); } catch (JSONException e) { e.printStackTrace(); } Log.i(TAG, "UserContext:" + str); return str; }
根據(jù)需求設(shè)置參數(shù)。
//設(shè)置本地發(fā)音人,如下載的aicheng語音包放在目錄/sdcard/idst/目錄下,那么命令為”/sdcard/idst/aicheng“ // 語音包和SDK是隔離的,需要先設(shè)置語音包 // 如果切換發(fā)音人:SDK可使用語音包與鑒權(quán)賬號(hào)相關(guān),由購買時(shí)獲得的語音包使用權(quán)限決定 // 如已經(jīng)購買aijia,按下邊方式調(diào)用后,發(fā)音人將切為aijia // 語音包下載地址:http://bestwisewords.com/document_detail/204185.html // 語音包試聽:https://www.aliyun.com/activity/intelligent/offline_tts // 特別說明:離線語音合成的發(fā)音人, 并不一定也存在于在線語音合成;同理, 在線語音合成的發(fā)音人, 并不一定也存在于離線語音合成 //aar中的資源目錄中自帶了一個(gè)發(fā)音人aijia, /data/user/0/mit.alibaba.nuidemo/files/asr_my/tts/voices/aijia String fullName = workspace + "/tts/voices/" + mFontName; //切換發(fā)音人:一定要輸入全路徑名稱 Log.i(TAG, "use extend_font_name:" + fullName); ret = nui_tts_instance.setparamTts("extend_font_name", fullName); if (ret != Constants.NuiResultCode.SUCCESS) { Log.e(TAG, "setparamTts extend_font_name " + fullName + " failed, ret:" + ret); String errmsg = nui_tts_instance.getparamTts("error_msg"); return ret; } // 設(shè)置發(fā)音人對(duì)應(yīng)的語音合成采樣率, 設(shè)置后也請(qǐng)?jiān)O(shè)置播放器的對(duì)應(yīng)采樣率, 否則無法播放出正常音頻。 nui_tts_instance.setparamTts("sample_rate", "16000"); // 調(diào)整語速 // nui_tts_instance.setparamTts("speed_level", "1"); // 調(diào)整音調(diào) // nui_tts_instance.setparamTts("pitch_level", "0"); // 調(diào)整音量 // nui_tts_instance.setparamTts("volume", "1.0");
啟動(dòng)語音合成。
nui_tts_instance.startTts("1", "", ttsText);
回調(diào)處理。
onTtsEventCallback:語音合成事件回調(diào),根據(jù)語音合成狀態(tài)控制播放器。
public void onTtsEventCallback(INativeTtsCallback.TtsEvent event, String task_id, int ret_code) { Log.i(TAG, "tts event:" + event + " task id " + task_id + " ret " + ret_code); if (event == INativeTtsCallback.TtsEvent.TTS_EVENT_START) { mAudioTrack.play(); Log.i(TAG, "start play"); } else if (event == INativeTtsCallback.TtsEvent.TTS_EVENT_END) { /* * 提示: TTS_EVENT_END事件表示TTS已經(jīng)合成完并通過回調(diào)傳回了所有音頻數(shù)據(jù), 而不是表示播放器已經(jīng)播放完了所有音頻數(shù)據(jù)。 */ Log.i(TAG, "play end"); // 表示推送完數(shù)據(jù), 當(dāng)播放器播放結(jié)束則會(huì)有playOver回調(diào) mAudioTrack.isFinishSend(true); } else if (event == TtsEvent.TTS_EVENT_PAUSE) { mAudioTrack.pause(); Log.i(TAG, "play pause"); } else if (event == TtsEvent.TTS_EVENT_RESUME) { mAudioTrack.play(); } else if (event == TtsEvent.TTS_EVENT_ERROR) { // 表示推送完數(shù)據(jù), 當(dāng)播放器播放結(jié)束則會(huì)有playOver回調(diào) mAudioTrack.isFinishSend(true); String error_msg = nui_tts_instance.getparamTts("error_msg"); Log.e(TAG, "TTS_EVENT_ERROR error_code:" + ret_code + " errmsg:" + error_msg); ToastText(Utils.getMsgWithErrorCode(ret_code, "error")); ToastText("錯(cuò)誤碼:" + ret_code + " 錯(cuò)誤信息:" + error_msg); } }
onTtsDataCallback:語音合成數(shù)據(jù)回調(diào),將回調(diào)中的合成數(shù)據(jù)寫入播放器進(jìn)行播放。
public void onTtsDataCallback(String info, int info_len, byte[] data) { if (info.length() > 0) { Log.i(TAG, "info: " + info); } if (data.length > 0) { mAudioTrack.setAudioData(data); Log.i(TAG, "write:" + data.length); } }
取消語音合成。
nui_tts_instance.cancelTts("");
退出語音合成。
nui_tts_instance.tts_release();
常見問題
使用離線語音合成Android SDK,語音播報(bào)時(shí)出現(xiàn)不合理斷句,該如何處理?
您可以通過SSML標(biāo)記語言嘗試解決。
調(diào)用Android SDK時(shí),手機(jī)報(bào)錯(cuò)提示“audio recorder not init”。
您可以通過以下方式排查:
檢查AudioRecord是否初始化正常。
檢查語音播放器是否有問題。
編寫AudioRecord錄音代碼,測(cè)試是否正常。
在模擬器上運(yùn)行下載的Android程序,程序出現(xiàn)閃退現(xiàn)象,是什么原因?
模擬器可能會(huì)出現(xiàn)未知問題,建議您使用真機(jī)測(cè)試。
int ret = nui_instance.initialize(this, genInitParams(assets_path,debug_path), Constants.LogLevel.LOG_LEVEL_VERBOSE, true)。在該段代碼中,錄音權(quán)限是打開的,但代碼仍然報(bào)錯(cuò)240021。
表示FILE_ACCESS_FAIL文件訪問錯(cuò)誤。你需要檢查:
是否有文件讀寫權(quán)限。
是否完成SDK配置文件的拷貝,檢查是否拷貝完成的代碼示例如下:
if (CommonUtils.copyAssetsData(this)) { Log.i(TAG, "copy assets data done"); } else { Log.i(TAG, "copy assets failed"); return; }