本文介绍了如何使用阿里云智能语音服务提供的Android NUI SDK,包括SDK下载安装、关键接口及代码示例。
前提条件
下载安装
- 重要
请下载后在样例初始化代码中替换您的阿里云账号信息、Appkey和Token才可运行。
类别
兼容范围
系统
支持Android 4.0以上版本,API LEVEL 14
架构
armeabi-v7a,arm64-v8a,x86,x86_64
此SDK还包含如下功能,若未支持您想要的功能,请前往对应文档获取SDK。
功能
是否支持
一句话识别
是
实时语音识别
是
语音合成
是
实时长文本语音合成
是
流式文本语音合成
是
离线语音合成
否
录音文件识别极速版
是
唤醒及命令词
否
听悟实时推流
是
解压ZIP包,在app/libs目录下获取AAR格式的SDK包,将AAR包集成到您的工程项目中进行依赖。如果需要Android CPP接入方式,可在ZIP包的android_libs和android_include中获得动态库和头文件。
使用Android Studio打开此工程查看参考代码实现,其中一句话识别示例代码为SpeechRecognizerActivity.java文件,替换Appkey和Token后可直接运行。
SDK关键接口
initialize:初始化SDK。
/** * 初始化SDK,SDK为单例,请先释放后再次进行初始化。请勿在UI线程调用,可能会引起阻塞。 * @param callback:事件监听回调,参见下文具体回调。 * @param parameters:json string形式的初始化参数,参见下方说明或接口说明:https://help.aliyun.com/document_detail/173298.html。 * @param level:log打印级别,值越小打印越多。 * @param save_log:是否保存log为文件,存储目录为ticket中的debug_path字段值。注意,log文件无上限,请注意持续存储导致磁盘存满。 * @return:参见错误码:https://help.aliyun.com/document_detail/459864.html。 */ public synchronized int initialize(final INativeNuiCallback callback, String parameters, final Constants.LogLevel level, final boolean save_log)
其中,INativeNuiCallback类型包含如下回调。
onNuiAudioStateChanged:根据音频状态进行录音功能的开关。
/** * 当start/stop/cancel等接口调用时,SDK通过此回调通知App进行录音的开关操作。 * @param state:录音需要的状态(打开/关闭) */ void onNuiAudioStateChanged(AudioState state);
onNuiNeedAudioData:在回调中提供音频数据。
/** * 开始识别时,此回调被连续调用,App需要在回调中进行语音数据填充。 * @param buffer:填充语音的存储区。 * @param len:需要填充语音的字节数。 * @return:实际填充的字节数。 */ int onNuiNeedAudioData(byte[] buffer, int len);
onNuiEventCallback:SDK事件回调。
/** * SDK主要事件回调 * @param event:回调事件,参见如下事件列表。 * @param resultCode:参见错误码,在出现EVENT_ASR_ERROR事件时有效。 * @param arg2:保留参数。 * @param kwsResult:语音唤醒功能(暂不支持)。 * @param asrResult:语音识别结果。 */ void onNuiEventCallback(NuiEvent event, final int resultCode, final int arg2, KwsResult kwsResult, AsrResult asrResult);
onNuiAudioRMSChanged:音频能量值回调。
/** * 音频能量值回调 * @param val: 音频数据能量值回调,范围-160至0,一般用于UI展示语音动效 */ public void onNuiAudioRMSChanged(float val);
事件列表:
名称
说明
EVENT_VAD_START
检测到人声起点。
EVENT_VAD_END
检测到人声尾点。
EVENT_ASR_PARTIAL_RESULT
语音识别中间结果。
EVENT_ASR_RESULT
语音识别最终结果。
EVENT_ASR_ERROR
根据错误码信息判断出错原因。
EVENT_MIC_EEROR
录音错误,表示SDK连续2秒未收到任何音频,可检查录音系统是否正常。
setParams:以JSON格式设置SDK参数。
/** * 以JSON格式设置参数 * @param params:参见接口说明:https://help.aliyun.com/document_detail/173298.html。 * @return:参见错误码:https://help.aliyun.com/document_detail/459864.html。 */ public synchronized int setParams(String params);
startDialog:开始识别。
/** * 开始识别 * @param vad_mode:多种模式,对于识别场景,请使用P2T。 * @param dialog_params:json string形式的对话参数,参见接口说明:https://help.aliyun.com/document_detail/173298.html。 * @return:参见错误码:https://help.aliyun.com/document_detail/459864.html。 */ public synchronized int startDialog(VadMode vad_mode, String dialog_params);
stopDialog:结束识别。
/** * 结束识别,调用该接口后,服务端将返回最终识别结果并结束任务。 * @return:参见错误码:https://help.aliyun.com/document_detail/459864.html。 */ public synchronized int stopDialog();
cancelDialog:立即结束识别。
/** * 立即结束识别,调用该接口后,不等待服务端返回最终识别结果就立即结束任务。 * @return:参见错误码:https://help.aliyun.com/document_detail/459864.html。 */ public synchronized int cancelDialog();
release:释放SDK。
/** * 释放SDK资源 * @return:参见错误码:https://help.aliyun.com/document_detail/459864.html。 */ public synchronized int release();
GetVersion:获得当前SDK版本信息。
/** * 获得当前SDK版本信息 * @return: 字符串形式的SDK版本信息 */ public synchronized String GetVersion();
调用步骤
初始化SDK、录音实例。
根据业务需求设置参数。
调用startDialog开始识别。
根据音频状态回调onNuiAudioStateChanged,打开录音机。
在onNuiNeedAudioData回调中提供录音数据。
在EVENT_ASR_PARTIAL_RESULT事件回调中获取识别中间结果。
调用stopDialog结束识别,并从EVENT_ASR_RESULT事件回调中获得最终识别结果。
结束调用,使用release接口释放SDK资源。
Proguard配置
如果代码使用了混淆,请在proguard-rules.pro中配置:
-keep class com.alibaba.idst.nui.*{*;}
代码示例
您如果有多个需求,也可以直接new对象进行使用。也可采用GetInstance获得单例。
NUI SDK初始化
//这里获得资源路径, 即工作路径
// 内部通过context.getApplicationContext().getFilesDir().toString() + "/asr_my" 创建工作路径,
// 例如 /data/user/0/mit.alibaba.nuidemo/files/asr_my
String asset_path = CommonUtils.getModelPath(this);
//创建debug路径
String debug_path = getExternalCacheDir().getAbsolutePath() + "/debug_" + System.currentTimeMillis();
Utils.createDir(debug_path);
//从nuisdk.aar中assets资源拷贝到workspace中
CommonUtils.copyAssetsData(this);
//初始化SDK,注意用户需要在genInitParams中填入相关ID信息才可以使用。
NativeNui nui_instance = new NativeNui();
int ret = nui_instance.initialize(this, genInitParams(asset_path, debug_path), Constants.LogLevel.LOG_LEVEL_VERBOSE, true);
其中,genInitParams生成String JSON字符串,包含资源目录和用户信息。其中用户信息包含如下字段。
private String genInitParams(String workpath, String debugpath) {
String str = "";
try{
//获取账号访问凭证:
// getTicket为示例工程中提供了多种可能的方式,请选择适合自身业务的安全方式
//
//注意:
// 语音交互服务需要先准备好账号,并开通相关服务。具体步骤请查看:
// 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
JSONObject object = Auth.getTicket(Auth.GetTicketMethod.GET_TOKEN_FROM_SERVER_FOR_ONLINE_FEATURES);
if (!object.containsKey("token")) {
Log.e(TAG, "Cannot get token!!!");
}
object.put("device_id", Utils.getDeviceId()); // 必填, 推荐填入具有唯一性的id, 方便定位问题
object.put("url", "wss://nls-gateway.cn-shanghai.aliyuncs.com:443/ws/v1"); // 默认
object.put("workspace", workpath); // 必填, 且需要有读写权限
object.put("sample_rate", "16000");
object.put("format", "opus");
//当初始化SDK时的save_log参数取值为true时,该参数生效。表示是否保存音频debug,该数据保存在debug目录中,需要确保debug_path有效可写。
//object.put("save_wav", "true");
//debug目录,当初始化SDK时的save_log参数取值为true时,该目录用于保存中间音频文件。
object.put("debug_path", debugpath);
//AsrCloud = 4 // 在线一句话识别可以选这个
object.put("service_mode", Constants.ModeAsrCloud); // 必填
str = object.toString();
} catch (JSONException e) {
e.printStackTrace();
}
Log.i(TAG, "InsideUserContext:" + str);
return str;
}
参数设置
以JSON字符串形式进行设置。
//设置相关识别参数,具体参考API文档
// initialize()之后startDialog之前调用
nui_instance.setParams(genParams());
private String genParams() {
String params = "";
try {
JSONObject nls_config = new JSONObject();
nls_config.put("enable_intermediate_result", true);
//参数可根据实际业务进行配置
//接口说明可见: https://help.aliyun.com/document_detail/173298.html
//查看 2.开始识别
//由于对外的SDK(01B版本)不带有本地VAD模块(仅带有唤醒功能(029版本)的SDK具有VAD模块),
//若要使用VAD模式,则需要设置nls_config参数启动在线VAD模式(见genParams())
//
//模式说明:
//若使用P2T模式,即按下开始说话,放开结束说话的模式,则不启动enable_voice_detection。
//若使用VAD模式,即自动判断用户说完一句话,则启动enable_voice_detection。
if (vadMode.get()) {
nls_config.put("enable_voice_detection", true);
nls_config.put("max_start_silence", 10000);
nls_config.put("max_end_silence", 800);
}
//nls_config.put("enable_punctuation_prediction", true);
//nls_config.put("enable_inverse_text_normalization", true);
//nls_config.put("enable_voice_detection", true);
//nls_config.put("customization_id", "test_id");
//nls_config.put("vocabulary_id", "test_id");
//nls_config.put("max_start_silence", 10000);
//nls_config.put("max_end_silence", 800);
//nls_config.put("sample_rate", 16000);
//nls_config.put("sr_format", "opus");
/*若文档中不包含某些参数,但是此功能支持这个参数,可以用如下万能接口设置参数*/
//JSONObject extend_config = new JSONObject();
//extend_config.put("custom_test", true);
//nls_config.put("extend_config", extend_config);
JSONObject parameters = new JSONObject();
parameters.put("nls_config", nls_config);
parameters.put("service_type", Constants.kServiceTypeASR); // 必填
//如果有HttpDns则可进行设置
//parameters.put("direct_ip", Utils.getDirectIp());
params = parameters.toString();
} catch (JSONException e) {
e.printStackTrace();
}
return params;
}
开始识别
通过startDialog接口开启监听。
//默认使用Constants.VadMode.TYPE_P2T。
//Constants.VadMode.TYPE_VAD只在具有离线功能的SDK中支持,若想要启动VAD,请设置参数enable_voice_detection。
NativeNui.GetInstance().startDialog(Constants.VadMode.TYPE_P2T, genDialogParams());
private String genDialogParams() {
String params = "";
try {
JSONObject dialog_param = new JSONObject();
//运行过程中可以在startDialog时更新参数,尤其是更新过期token
//dialog_param.put("token", "");
params = dialog_param.toString();
} catch (JSONException e) {
e.printStackTrace();
}
return params;
}
回调处理
onNuiAudioStateChanged:录音状态回调,SDK内部维护录音状态,调用时根据该状态的回调进行录音机的开关操作。
public void onNuiAudioStateChanged(Constants.AudioState state) { Log.i(TAG, "onNuiAudioStateChanged"); if (state == Constants.AudioState.STATE_OPEN) { Log.i(TAG, "audio recorder start"); mAudioRecorder.startRecording(); } else if (state == Constants.AudioState.STATE_CLOSE) { Log.i(TAG, "audio recorder close"); mAudioRecorder.release(); } else if (state == Constants.AudioState.STATE_PAUSE) { Log.i(TAG, "audio recorder pause"); mAudioRecorder.stop(); } }
onNuiNeedAudioData:录音数据回调,在该回调中填充录音数据。
public int onNuiNeedAudioData(byte[] buffer, int len) { int ret = 0; if (mAudioRecorder.getState() != AudioRecord.STATE_INITIALIZED) { Log.e(TAG, "audio recorder not init"); return -1; } ret = mAudioRecorder.read(buffer, 0, len); //返回值告知SDK读到了多少数据。 //如果返回<0,则表示出错。 //返回0,则表示无录音数据,连续2s返回0,会触发事件EVENT_MIC_ERROR。 return ret; }
onNuiEventCallback:NUI SDK事件回调,请勿在事件回调中调用SDK的接口,可能引起死锁。
public void onNuiEventCallback(Constants.NuiEvent event, final int resultCode, final int arg2, KwsResult kwsResult, AsrResult asrResult) { Log.i(TAG, "event=" + event + " resultCode=" + resultCode); // asrResult包含task_id,task_id有助于排查问题,请用户进行记录保存。 // // 新版本新增asrResult.allResponse,若为非nullptr和非空,则给出json格式字符串的完整信息。 if (event == Constants.NuiEvent.EVENT_ASR_RESULT) { // 例如展示识别结果 showText(asrView, asrResult.asrResult); } else if (event == Constants.NuiEvent.EVENT_ASR_PARTIAL_RESULT) { // 例如展示识别中间结果 showText(asrView, asrResult.asrResult); } else if (event == Constants.NuiEvent.EVENT_ASR_ERROR) { // asrResult在EVENT_ASR_ERROR中为错误信息,搭配错误码resultCode和其中的task_id更易排查问题,请用户进行记录保存。 } else if (event == Constants.NuiEvent.EVENT_MIC_ERROR) { // EVENT_MIC_ERROR表示2s未传入音频数据,请检查录音相关代码、权限或录音模块是否被其他应用占用。 } else if (event == Constants.NuiEvent.EVENT_DIALOG_EX) { /* unused */ // 此事件可不用关注 } }
结束识别
nui_instance.stopDialog();
释放SDK
nui_instance.release();