001package com.aispeech.dui.dds.agent; 002 003import android.text.TextUtils; 004 005import com.aispeech.dui.BaseNode; 006import com.aispeech.dui.BusClient; 007import com.aispeech.dui.BusClient.RPCResult; 008import com.aispeech.dui.dds.DDS; 009import com.aispeech.dui.dds.agent.tts.TTSEngine; 010import com.aispeech.dui.dds.exceptions.DDSNotInitCompleteException; 011import com.aispeech.dui.manager.AIJavaException; 012import com.aispeech.dui.manager.AILog; 013import com.aispeech.libbase.bussiness.JSONObjectUtil; 014import com.aispeech.libcomm.business.LocalKeys; 015import com.aispeech.libcomm.business.LocalKeysUtil; 016import com.aispeech.libcomm.business.call.AsrppCallUtil; 017import com.aispeech.libcomm.business.call.DmsCallUtil; 018import com.aispeech.libcomm.business.call.VadCallUtils; 019import com.aispeech.libcomm.business.config.PlayerConfig; 020import com.aispeech.libcomm.business.topic.DmsTopicUtil; 021import com.aispeech.libcomm.business.topic.RecorderTopicUtil; 022import com.aispeech.libcomm.business.topic.Topic; 023import com.aispeech.libcomm.business.topic.VadTopicUtil; 024 025import org.json.JSONArray; 026import org.json.JSONException; 027import org.json.JSONObject; 028 029/** 030 * Created by Jinrui on 2017/11/8. 031 */ 032 033public class ASREngine { 034 public static final String TAG = "ASREngine"; 035 036 private final String[] mTopics = new String[]{ 037 Topic.Processor.ASR_SPEECH_TEXT, 038 Topic.Processor.ASR_SPEECH_RESULT, 039 Topic.Pcm.StreamData.TOPIC_NAME, 040 Topic.Dms.AsrVolume.TOPIC_NAME, 041 Topic.Vad.LocalVadTimeout.TOPIC_NAME, 042 Topic.Sys.SysDialogError.TOPIC_NAME, 043 Topic.Sys.SysVadBegin.TOPIC_NAME, 044 Topic.Sys.SysVadEnd.TOPIC_NAME 045 }; 046 private boolean mIsUserSubscribe = false;// 用户注册消息判断位 047 048 public enum AsrppType { 049 GENDER, AGE, EMOTION; 050 } 051 052 private volatile static ASREngine mInstance; 053 private Callback mCallbackOnce; 054 private ASREngine.DDSAsrCallback mDDSAsrListener; 055 private final InnerAsr mInnerAsr = new InnerAsr(); 056 057 private class InnerAsr { 058 String mAppendVar = ""; 059 060 private void reset() { 061 mAppendVar = ""; 062 } 063 064 protected String mockVarInputText(JSONObject asrObj) { 065 if(asrObj == null) return ""; 066 String from = asrObj.optString("from"); 067 if(!TextUtils.equals(from,"liteAsr")) { 068 AILog.d(TAG,"not from liteAsr"); 069 return ""; 070 } 071 String showText = ""; 072 String var = asrObj.optString("var", ""); 073 String text = asrObj.optString("text", ""); 074 int eof = asrObj.optInt("eof"); 075 076 if(eof == 0) { 077 if (!TextUtils.isEmpty(var)) { 078 showText = mAppendVar + var; 079 } else if (!TextUtils.isEmpty(text)) { 080 mAppendVar += text; 081 showText = mAppendVar; 082 } else { 083 showText = mAppendVar; 084 } 085 } 086 087 asrObj.remove("text"); 088 try { 089 asrObj.put("var", showText); 090 } catch (JSONException exception) { 091 exception.printStackTrace(); 092 } 093 AILog.d(TAG, "mockVarInputText after data =", asrObj.toString()); 094 return asrObj.toString(); 095 } 096 } 097 098 private final BaseNode mNode = new BaseNode() { 099 @Override 100 public String getName() { 101 return "ASREngine"; 102 } 103 104 @Override 105 public void onMessage(String topic, Object... parts) { 106 if (Topic.Processor.ASR_SPEECH_TEXT.equals(topic)) { 107 onPartialResults(mInnerAsr.mockVarInputText((JSONObject) parts[0])); 108 } else if (Topic.Processor.ASR_SPEECH_RESULT.equals(topic)) { 109 JSONObject dataObj = (JSONObject) parts[0]; 110 if(dataObj != null) { 111 mInnerAsr.reset(); 112 String from = dataObj.optString("from"); 113 if(!TextUtils.equals(from,"liteAsr")) { 114 AILog.d(TAG,"not from liteAsr"); 115 return; 116 } 117 onFinalResults(dataObj.toString()); 118 } 119 } else if (Topic.Dms.AsrVolume.TOPIC_NAME.equals(topic)) { 120 JSONObject dataObj = (JSONObject) parts[0]; 121 onRmsChanged((float) dataObj.optInt(Topic.Dms.AsrVolume.VOLUME)); 122 } else if (Topic.Sys.SysVadBegin.TOPIC_NAME.equals(topic)) { 123 onBeginningOfSpeech(); 124 if(mDDSAsrListener != null) { 125 mDDSAsrListener.onVadBegin(); 126 } 127 } else if (Topic.Sys.SysVadEnd.TOPIC_NAME.equals(topic)) { 128 onEndOfSpeech(); 129 if(mDDSAsrListener != null) { 130 mDDSAsrListener.onVadEnd(); 131 } 132 } else if (Topic.Pcm.StreamData.TOPIC_NAME.equals(topic)) { 133 byte[] data = (byte[]) parts[0]; 134 if (data.length != 0) { 135 onBufferReceived(data); 136 } 137 } else if (Topic.Sys.SysDialogError.TOPIC_NAME.equals(topic)) { 138 JSONObject dataObj = (JSONObject) parts[0]; 139 AILog.e(TAG, dataObj.toString()); 140 JSONObject error = dataObj.optJSONObject("error"); 141 String errorStr = error.toString(); 142 AILog.e(TAG, "error:",error.toString()); 143 onError(errorStr); 144 } else if(Topic.Pcm.LocalVadPcm.TOPIC_NAME.equals(topic)) { 145 if(mDDSAsrListener != null) { 146 mDDSAsrListener.receivedAsrData((byte[]) parts[0]); 147 } 148 } else if(Topic.Pcm.LocalRecorderPcm.TOPIC_NAME.equals(topic)) { 149 if(mDDSAsrListener != null) { 150 mDDSAsrListener.receivedAsrData((byte[]) parts[0]); 151 } 152 } else if(Topic.Dms.DmsSpeechCtrl.TOPIC_NAME.equals(topic)) { 153 JSONObject data = (JSONObject) parts[0]; 154 String recordId = data.optString("recordId"); 155 if(mDDSAsrListener != null) { 156 mDDSAsrListener.onStreamStart(recordId); 157 } 158 } 159 } 160 161 @Override 162 public RPCResult onCall(String url, byte[]... args) throws Exception { 163 return null; 164 } 165 166 @Override 167 public void onExit() { 168 asrUnsubscribe(); 169 } 170 }; 171 172 private void asrSubscribe() { 173 if (mNode.getBusClient() != null && mIsUserSubscribe) { 174 mNode.getBusClient().subscribe(mTopics); 175 } 176 } 177 178 private void asrUnsubscribe() { 179 if (mNode.getBusClient() != null && mIsUserSubscribe) { 180 mNode.getBusClient().unsubscribe(mTopics); 181 mIsUserSubscribe = false; 182 } 183 } 184 185 protected ASREngine() { 186 mNode.start(); 187 } 188 189 public static ASREngine getInstance() { 190 ASREngine localResource = mInstance; 191 if (localResource == null) { 192 synchronized (ASREngine.class) { 193 localResource = mInstance; 194 if (localResource == null) { 195 mInstance = localResource = new ASREngine(); 196 } 197 } 198 } 199 return localResource; 200 } 201 202 /** 203 * 获取 ASREngine 实例快照 204 * 205 * @return ASREngine 206 */ 207 public static ASREngine getInstanceSnapshot() { 208 return mInstance; 209 } 210 211 private void checkInitComplete() throws DDSNotInitCompleteException { 212 if (DDS.getInstance().getInitStatus() != DDS.INIT_COMPLETE_FULL) { 213 throw new DDSNotInitCompleteException(); 214 } 215 } 216 217 private void onPartialResults(String data) { 218 AILog.d(TAG,"onPartialResults data =",data,",has mCallbackOnce = ",mCallbackOnce != null); 219 if (null != mCallbackOnce) { 220 mCallbackOnce.partialResults(data); 221 } 222 } 223 224 private void onFinalResults(String data) { 225 AILog.d(TAG,"onFinalResults data =",data,",has mCallbackOnce = ",mCallbackOnce != null); 226 if (null != mCallbackOnce) { 227 asrUnsubscribe(); 228 mCallbackOnce.finalResults(data); 229 mCallbackOnce = null; 230 } 231 } 232 233 private void onBeginningOfSpeech() { 234 if (null != mCallbackOnce) { 235 mCallbackOnce.beginningOfSpeech(); 236 } 237 } 238 239 private void onBufferReceived(byte[] data) { 240 if (null != mCallbackOnce) { 241 mCallbackOnce.bufferReceived(data); 242 } 243 } 244 245 private void onRmsChanged(float rmsdB) { 246 if (null != mCallbackOnce) { 247 mCallbackOnce.rmsChanged(rmsdB); 248 } 249 } 250 251 private void onEndOfSpeech() { 252 if (null != mCallbackOnce) { 253 mCallbackOnce.endOfSpeech(); 254 } 255 } 256 257 private void onError(String error) { 258 if (null != mCallbackOnce) { 259 mCallbackOnce.error(error); 260 mCallbackOnce = null; 261 } 262 } 263 264 /** 265 * 主动开始识别 266 * <p> 267 * 调用后直接进入识别,识别结果通过{@link Callback}返回。 268 * 若当前正在对话中,会先结束当前对话,再开启识别。 269 * 若开启VAD,用户结束说话之后会自动结束识别,无须调用{@link ASREngine#stopListening()} 270 * 271 * @param callback 识别结果通的回调接口。识别结束或取消后,将被清除。 272 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 273 */ 274 public void startListening(Callback callback) throws DDSNotInitCompleteException { 275 startListening(new ListeningParams(), callback); 276 } 277 278 /** 279 * 主动开始识别 280 * <p> 281 * 调用后直接进入识别,识别结果通过{@link Callback}返回。 282 * 若开启VAD,用户结束说话之后会自动结束识别,无须调用{@link ASREngine#stopListening()} 283 * 284 * @param callback 识别结果通的回调接口。识别结束或取消后,将被清除。 285 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 286 */ 287 public void startListening(ListeningParams params, Callback callback) throws DDSNotInitCompleteException { 288 checkInitComplete(); 289 AILog.userI(TAG, "startListening input =", (params != null ? params.getJsonObject() : "null")); 290 mCallbackOnce = callback; 291 mIsUserSubscribe = true; 292 asrSubscribe(); 293 mInnerAsr.reset(); 294 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 295 if (bc != null) { 296 RecorderTopicUtil.publishRecorderCtrl(bc, "start", "asr", false); 297 JSONObject asrObj = params != null ? params.getJsonObject() : new ListeningParams().getJsonObject(); 298 try { 299 asrObj.put(Topic.Dms.AsrCtrl.CTRL, "start"); 300 } catch (JSONException e) { 301 e.printStackTrace(); 302 } 303 DmsTopicUtil.publishAsrCtrl(bc, asrObj); 304 } else { 305 AILog.e(TAG, "startListening failed due to null busclient"); 306 } 307 } 308 309 /** 310 * 设置VAD前端超时时间的接口 311 * <p> 312 * 若VAD启动,一直未检测到用户说话,超过一定时间,发出sys.vad.timeout消息,结束录音。 313 * 设置成功后,vad再次启动生效 314 * 315 * @param mills 前端超时时间,单位为毫秒。默认值为8000毫秒。 316 * @return true-设置成功;false-设置失败 317 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 318 */ 319 public boolean setVadTimeout(long mills) throws DDSNotInitCompleteException { 320 checkInitComplete(); 321 AILog.userI(TAG, "setVadTimeout input =", mills); 322 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 323 if (bc != null) { 324 VadTopicUtil.publishVadSetTimeOut(bc, mills); 325 return true; 326 } else { 327 AILog.e(TAG, "setVadTimeout failed due to null busclient"); 328 return false; 329 } 330 } 331 332 /** 333 * 在全双工模式下,跳过Vad的超时检测 334 * <p> 335 * 全双工模式下, VAD启动后调用此接口会清除VAD的超时机制, 人声检测超时机制交由服务端来判断 336 * 此接口只在全双工模式下生效, 并在当前对话时生效, 开启新的对话后此状态会恢复为默认的vad超时检测 337 * 338 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 339 */ 340 public void killVadTimeoutInFullDuplex() throws DDSNotInitCompleteException { 341 checkInitComplete(); 342 AILog.userI(TAG, "killVadTimeoutInFullDuplex"); 343 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 344 if (bc != null) { 345 VadTopicUtil.publishKillVadTimeout(bc, true); 346 } else { 347 AILog.e(TAG, "killVadTimeoutInFullDuplex failed due to null busclient"); 348 } 349 } 350 351 /** 352 * 在全双工模式下,实时开启Vad的超时检测 353 * 在调用killVadTimeoutInFullDuplex之后,如果想在本轮对话中再次开启Vad的超时检测机制,则调用此接口 354 * <p> 355 * 356 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 357 */ 358 public void startVadTimeoutInFullDuplex() throws DDSNotInitCompleteException { 359 checkInitComplete(); 360 AILog.userI(TAG, "startVadTimeoutInFullDuplex"); 361 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 362 if (bc != null) { 363 VadTopicUtil.publishKillVadTimeout(bc, false); 364 } else { 365 AILog.e(TAG, "killVadTimeoutInFullDuplex failed due to null busclient"); 366 } 367 } 368 369 /** 370 * 获取VAD前端超时时间的接口 371 * 372 * @return millis 前端超时时间,单位为毫秒。 373 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 374 */ 375 public long getVadTimeout() throws DDSNotInitCompleteException { 376 checkInitComplete(); 377 long pauseTime = 8000; 378 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 379 if (bc != null) { 380 pauseTime = VadCallUtils.callVadGetTimeout(bc); 381 } else { 382 AILog.e(TAG, "getVadTimeout failed due to null busclient"); 383 } 384 AILog.userI(TAG, "getVadTimeout result =", pauseTime); 385 return pauseTime; 386 } 387 388 /** 389 * 设置VAD后端停顿时间的接口 390 * <p> 391 * 若VAD在用户说话时停顿超过一定的时间,则认为用户已经说完,发出sys.vad.end消息,结束录音。 392 * 393 * @param millis 后端停顿时间,单位为毫秒。默认值为500毫秒。 394 * @return true-设置成功;false-设置失败 395 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 396 */ 397 public boolean setVadPauseTime(long millis) throws DDSNotInitCompleteException { 398 checkInitComplete(); 399 AILog.userI(TAG, "setVadPauseTime input =", millis); 400 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 401 if (bc != null) { 402 VadTopicUtil.publishVadSetPauseTime(bc, millis); 403 return true; 404 } else { 405 AILog.e(TAG, "setVadPauseTime failed due to null busclient"); 406 return false; 407 } 408 } 409 410 /** 411 * 获取VAD后端停顿时间的接口 412 * 413 * @return millis 后端停顿时间,单位为毫秒。 414 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 415 */ 416 public long getVadPauseTime() throws DDSNotInitCompleteException { 417 checkInitComplete(); 418 long pauseTime = 500; 419 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 420 if (bc != null) { 421 pauseTime = VadCallUtils.callVadGetPauseTime(bc); 422 } else { 423 AILog.e(TAG, "getVadPauseTime failed due to null busclient"); 424 } 425 AILog.userI(TAG, "getVadPauseTime result =", pauseTime); 426 return pauseTime; 427 } 428 429 430 /** 431 * 获取vad版本:lua版本 - c版本 接口 432 * 433 * @return vadVersion vad版本信息 434 * @throws DDSNotInitCompleteException 435 */ 436 public String getVadVersion() throws DDSNotInitCompleteException { 437 checkInitComplete(); 438 String vadVersion = ""; 439 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 440 if (bc != null) { 441 vadVersion = VadCallUtils.callVadGetVersion(bc); 442 } else { 443 AILog.e(TAG, "getVadVersion failed due to null busclient"); 444 } 445 AILog.userI(TAG, "getVadVersion result =", vadVersion); 446 return vadVersion; 447 } 448 449 450 /** 451 * 获取vad dump info 452 * 453 * @return vadDump vad dmp info 454 * @throws DDSNotInitCompleteException 455 */ 456 public String getVadDump() throws DDSNotInitCompleteException { 457 checkInitComplete(); 458 String vadDump = ""; 459 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 460 if (bc != null) { 461 vadDump = VadCallUtils.callVadDump(bc); 462 } else { 463 AILog.e(TAG, "getVadDump failed due to null busclient"); 464 } 465 AILog.userI(TAG, "getVadDump result =", vadDump); 466 return vadDump; 467 } 468 469 470 /** 471 * 设置使用VAD检测接口 472 * 473 * @return true-设置成功;false-设置失败 474 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 475 */ 476 public boolean enableVad() throws DDSNotInitCompleteException { 477 checkInitComplete(); 478 AILog.userI(TAG, "enableVad"); 479 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 480 if (bc != null) { 481 VadTopicUtil.publishVadEnable(bc); 482 return true; 483 } else { 484 AILog.e(TAG, "setVadEnable failed due to null busclient"); 485 return false; 486 } 487 } 488 489 /** 490 * 设置取消VAD检测接口 491 * 492 * @return true-设置成功;false-设置失败 493 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 494 */ 495 public boolean disableVad() throws DDSNotInitCompleteException { 496 checkInitComplete(); 497 AILog.userI(TAG, "disableVad"); 498 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 499 if (bc != null) { 500 VadTopicUtil.publishVadDisable(bc); 501 return true; 502 } else { 503 AILog.e(TAG, "setVadDisable failed due to null busclient"); 504 return false; 505 } 506 } 507 508 509 /** 510 * 主动结束识别 511 * <p> 512 * 调用后,最终识别结果会通过{@link Callback#finalResults(String)}回调,然后{@link Callback}将会被清除。 513 * 514 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 515 */ 516 public void stopListening() throws DDSNotInitCompleteException { 517 checkInitComplete(); 518 AILog.userI(TAG, "stopListening"); 519 mInnerAsr.reset(); 520 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 521 if (bc != null) { 522 RecorderTopicUtil.publishRecorderCtrl(bc, "stop", "asr", false); 523 DmsTopicUtil.publishAsrCtrl(bc, JSONObjectUtil.create() 524 .put(Topic.Dms.AsrCtrl.CTRL, "stop") 525 .build()); 526 } else { 527 AILog.e(TAG, "stopListening failed due to null busclient"); 528 } 529 } 530 531 /** 532 * 取消此次识别 533 * <p> 534 * 调用后,{@link Callback}将会被清除,并不再触发任何回调。 535 * 536 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 537 */ 538 public void cancel() throws DDSNotInitCompleteException { 539 checkInitComplete(); 540 AILog.userI(TAG, "cancel"); 541 mInnerAsr.reset(); 542 mCallbackOnce = null; 543 asrUnsubscribe(); 544 mInnerAsr.reset(); 545 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 546 if (bc != null) { 547 RecorderTopicUtil.publishRecorderCtrl(bc, "stop", "asr", false); 548 DmsTopicUtil.publishAsrCtrl(bc, JSONObjectUtil.create() 549 .put(Topic.Dms.AsrCtrl.CTRL, "cancel") 550 .build()); 551 } else { 552 AILog.e(TAG, "cancel failed due to null busclient"); 553 } 554 } 555 556 private void setPunctuation(boolean enable) throws DDSNotInitCompleteException { 557 checkInitComplete(); 558 AILog.userI(TAG, "setPunctuation input =", enable); 559 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 560 if (bc != null) { 561 DmsTopicUtil.publishUpdateAsrEnablePunctuation(bc, enable); 562 } else { 563 AILog.e(TAG, "setPunctuation failed due to null busclient"); 564 } 565 } 566 567 private void setCensorEnable(boolean enable) throws DDSNotInitCompleteException { 568 checkInitComplete(); 569 AILog.userI(TAG, "setCensorEnable input =", enable); 570 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 571 if (bc != null) { 572 DmsTopicUtil.publishUpdateAsrEnableCensor(bc, enable); 573 } else { 574 AILog.e(TAG, "setCensorEnable failed due to null busclient"); 575 } 576 } 577 578 579 /** 580 * 打开识别支持标点符号的特性 581 * 582 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 583 */ 584 public void enablePunctuation() throws DDSNotInitCompleteException { 585 setPunctuation(true); 586 } 587 588 589 /** 590 * 关闭识别支持标点符号的特性 591 * 592 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 593 */ 594 public void disablePunctuation() throws DDSNotInitCompleteException { 595 setPunctuation(false); 596 } 597 598 599 /** 600 * 打开识别敏感词 601 * 602 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 603 */ 604 public void enableCensor() throws DDSNotInitCompleteException { 605 setCensorEnable(true); 606 } 607 608 /** 609 * 打开识别敏感词 610 * 611 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 612 */ 613 public void disableCensor() throws DDSNotInitCompleteException { 614 setCensorEnable(false); 615 } 616 617 618 /** 619 * 更新云端识别的模型名字, 620 * 在调用完该接口后,下一次对话开始时生效,并一直用该模型,除非客户端再调用该接口设置为其他的模型 621 * 622 * @param asrModel 云端识别的模型名字,有aihome, airobot等, 623 * 默认为dui控制台配置的模型资源, 624 * 如果填null,则表示清除之前本地配置的模型名,之后会使用dui控制台配置的模型资源 625 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 626 */ 627 public void updateAsrModel(String asrModel) throws DDSNotInitCompleteException { 628 checkInitComplete(); 629 AILog.userI(TAG, "updateAsrModel input =", asrModel); 630 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 631 if (bc != null) { 632 DmsTopicUtil.publishUpdateAsrModel(bc, asrModel); 633 } else { 634 AILog.e(TAG, "updateAsrRes failed due to null busclient"); 635 } 636 } 637 638 /** 639 * 获取当前使用的云端识别的模型 640 * 641 * @return asrModel 当前使用的云端识别的模型, 如果失败会返回null,或者抛出DDSNotInitCompleteException 642 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 643 */ 644 public String getAsrModel() throws DDSNotInitCompleteException { 645 checkInitComplete(); 646 AILog.d(TAG, "getAsrModel : "); 647 String asrModel = ""; 648 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 649 if (bc != null) { 650 asrModel = DmsCallUtil.callGetAsrModel(bc); 651 } else { 652 AILog.e(TAG, "updateAsrRes failed due to null busclient"); 653 } 654 AILog.userI(TAG, "getAsrModel result =", asrModel); 655 return asrModel; 656 } 657 658 /** 659 * 获取音频对应的性别/年龄/情绪 660 * 661 * @param pcm 一次性输入识别的单路音频(建议输入1.2~1.5秒的有效音频,有效音频不得少于0.6秒) 662 * @return 返回音频识别结果: 性别/年龄/情绪字段 663 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 664 */ 665 @Deprecated 666 public String getGenderWithPcm(byte[] pcm) throws DDSNotInitCompleteException { 667 return getAsrppWithPcm(pcm, AsrppType.GENDER); 668 } 669 670 /** 671 * 获取音频对应的性别/年龄/情绪 672 * 673 * @param pcm 一次性输入识别的单路音频(建议输入1.2~1.5秒的有效音频,有效音频不得少于0.6秒) 674 * @return 返回音频识别结果: 性别/年龄/情绪字段 675 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 676 */ 677 public String getAsrppWithPcm(byte[] pcm, AsrppType... types) throws DDSNotInitCompleteException { 678 checkInitComplete(); 679 int pcmLength = pcm.length; 680 if (pcmLength < (6 * 3200)) {// 判断小于0.6秒的音频就返回null 681 AILog.e(TAG, "getAsrppWithPcm failed : pcm is too small"); 682 return null; 683 } 684 AILog.d(TAG, "getAsrppWithPcm length = " + pcmLength); 685 String genderStr = null; 686 long start = System.currentTimeMillis(); 687 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 688 689 if (bc != null) { 690 String params = ""; 691 if (types != null) { 692 for (AsrppType asrppType : types) { 693 String typeStr = asrppType.name().toLowerCase(); 694 params += "," + typeStr; 695 } 696 } 697 params = params.replaceFirst(",", ""); 698 // lua 的 topic: "/gender/getasrpp_result"; 699 genderStr = AsrppCallUtil.callAsrppResult(bc, pcm, params); 700 } else { 701 AILog.e(TAG, "getAsrppWithPcm failed due to null busclient"); 702 } 703 long disTime = System.currentTimeMillis() - start; 704 AILog.d(TAG, "getAsrppWithPcm time = " + disTime); 705 AILog.userI(TAG, "getAsrppWithPcm result =", genderStr); 706 return genderStr; 707 } 708 709 /** 710 * 设置时时回传音量大小, 默认为true 711 * 712 * @param enable true/false true:支持时时回传音量 false:关闭时时回传音量 713 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 714 */ 715 public void enableVolume(boolean enable) throws DDSNotInitCompleteException { 716 checkInitComplete(); 717 AILog.userI(TAG, "enableVolume input =", enable); 718 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 719 if (bc != null) { 720 RecorderTopicUtil.publishEnableVolume(bc, enable, 1); 721 } else { 722 AILog.e(TAG, "setEnableVolume failed due to null busclient"); 723 } 724 } 725 726 /** 727 * 设置时时回传音量大小, 默认为true 728 * 729 * @param enable true/false true:支持时时回传音量 false:关闭时时回传音量 730 * @param frequency 每几次计算一次音量, 默认 1 731 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 732 */ 733 public void enableVolume(boolean enable, int frequency) throws DDSNotInitCompleteException { 734 checkInitComplete(); 735 AILog.userI(TAG, "enableVolume enable =", enable, ", frequency =", frequency); 736 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 737 if (bc != null) { 738 RecorderTopicUtil.publishEnableVolume(bc, enable, frequency > 1 ? frequency : 1); 739 } else { 740 AILog.e(TAG, "setEnableVolume failed due to null busclient"); 741 } 742 } 743 744 /** 745 * 动态设置录音通道是否反转 746 * 747 * @param isReversedChannel true or false 748 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 749 */ 750 public void setReversedChannel(boolean isReversedChannel) throws DDSNotInitCompleteException { 751 checkInitComplete(); 752 AILog.userI(TAG, "setReversedChannel input =", isReversedChannel); 753 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 754 if (bc != null) { 755 RecorderTopicUtil.publishRecorderCtrl(bc, "reversedChannel", "Agent", isReversedChannel); 756 } else { 757 AILog.e(TAG, "setReversedChannel failed due to null busclient"); 758 } 759 } 760 761 /** 762 * 设置三路模型标识 763 * 764 * @param cLmId 模型id new JSONArray().put("123").put("234"); 765 */ 766 public void setCLmId(JSONArray cLmId) throws DDSNotInitCompleteException { 767 checkInitComplete(); 768 AILog.userI(TAG, "setCLmId input =", cLmId); 769 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 770 if (bc != null) { 771 JSONObject jsonObject = new JSONObject(); 772 try { 773 jsonObject.put(Topic.Dms.UpdateAsrParams.CLMID, cLmId); 774 DmsTopicUtil.publishUpdateAsrParams(bc, jsonObject); 775 } catch (Exception e) { 776 e.printStackTrace(); 777 } 778 } else { 779 AILog.e(TAG, "setCLmId failed due to null busclient"); 780 } 781 } 782 783 /** 784 * 设置识别声纹参数 785 * 786 * @param asrPlus 787 */ 788 public void setAsrPlus(AsrPlusRequestBean asrPlus) throws DDSNotInitCompleteException { 789 checkInitComplete(); 790 String asrPlusStr = ""; 791 if (asrPlus != null) { 792 JSONObject asrPlusObj = asrPlus.getAsrPlusObj(); 793 asrPlusStr = asrPlusObj.toString(); 794 } 795 AILog.d(TAG, "asrPlusObj : " + asrPlusStr); 796 LocalKeysUtil.getInstance().put(LocalKeys.Asr.LOCAL_KEY_ASR_ASRPLUS, asrPlusStr); 797 } 798 799 /** 800 * 设置二路模型标识 801 * 802 * @param abLmId 模型id new JSONArray().put("123").put("234"); 803 */ 804 public void setAbLmId(JSONArray abLmId) throws DDSNotInitCompleteException { 805 checkInitComplete(); 806 AILog.userI(TAG, "setAbLmId input =", abLmId); 807 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 808 if (bc != null) { 809 JSONObject jsonObject = new JSONObject(); 810 try { 811 jsonObject.put(Topic.Dms.UpdateAsrParams.ABLMID, abLmId); 812 DmsTopicUtil.publishUpdateAsrParams(bc, jsonObject); 813 } catch (Exception e) { 814 e.printStackTrace(); 815 } 816 } else { 817 AILog.e(TAG, "setAbLmId failed due to null busclient"); 818 } 819 } 820 821 /** 822 * 是否开启nlu_rec 823 * 824 * @param enableNluRec 取值 true or false 825 */ 826 public void setEnableNluRec(boolean enableNluRec) throws DDSNotInitCompleteException { 827 checkInitComplete(); 828 AILog.userI(TAG, "setEnableNluRec input =", enableNluRec); 829 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 830 if (bc != null) { 831 JSONObject jsonObject = new JSONObject(); 832 try { 833 jsonObject.put(Topic.Dms.UpdateAsrParams.ENABLENLUREC, enableNluRec); 834 DmsTopicUtil.publishUpdateAsrParams(bc, jsonObject); 835 } catch (Exception e) { 836 e.printStackTrace(); 837 } 838 } else { 839 AILog.e(TAG, "setEnableNluRec failed due to null busclient"); 840 } 841 } 842 843 /** 844 * 是否开启enableAlignment 845 * 846 * @param enableAlignment 取值 true or false 847 */ 848 public void setEnableAlignment(boolean enableAlignment) throws DDSNotInitCompleteException { 849 checkInitComplete(); 850 AILog.userI(TAG, "setEnableAlignment input =", enableAlignment); 851 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 852 if (bc != null) { 853 JSONObject jsonObject = new JSONObject(); 854 try { 855 jsonObject.put(Topic.Dms.UpdateAsrParams.ENABLEALIGNMENT, enableAlignment); 856 DmsTopicUtil.publishUpdateAsrParams(bc, jsonObject); 857 } catch (Exception e) { 858 e.printStackTrace(); 859 } 860 } else { 861 AILog.e(TAG, "setEnableAlignment failed due to null busclient"); 862 } 863 } 864 865 /** 866 * 动态设置Asrpp是否打开,下一轮对话生效 867 * @param enable 默认是false,如果用户配置,取用户配置的值 868 * @throws DDSNotInitCompleteException 869 */ 870 public void setEnableCloudAsrPP(boolean enable) throws DDSNotInitCompleteException { 871 checkInitComplete(); 872 AILog.userI(TAG, "setEnableCloudAsrPP enable =", enable); 873 874 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 875 try { 876 DmsTopicUtil.publishCloudAsrPPEnable(bc, enable); 877 } catch (Exception e) { 878 e.printStackTrace(); 879 } 880 } 881 882 public interface Callback { 883 884 /** 885 * 当用户开始说话时的回调, 产品开启VAD时有效 886 */ 887 void beginningOfSpeech(); 888 889 /** 890 * 检测到用户结束说话的回调, 产品开启VAD时有效 891 */ 892 void endOfSpeech(); 893 894 /** 895 * 采集到音频数据的回调 896 */ 897 void bufferReceived(byte[] buffer); 898 899 /** 900 * 实时识别结果的回调 901 */ 902 void partialResults(String results); 903 904 /** 905 * 最终识别结果的回调 906 */ 907 void finalResults(String results); 908 909 /** 910 * 识别过程发生错误的回调 911 */ 912 void error(String error); 913 914 /** 915 * 音量变化的回调 916 */ 917 void rmsChanged(float rmsdB); 918 } 919 920 public static class ListeningParams { 921 private boolean vadEnable = true; 922 private boolean volumeEnable = true; 923 private int noSpeechTimeOut = 8000; 924 private long vadPauseTime = 300; 925 private boolean enablePunctuation = true; 926 private boolean enableCensor= true; 927 private boolean enableNumberConvert = false; 928 private String resource; 929 private int maxSpeechTimeS = -1; 930 931 public long getVadPauseTime() { 932 return vadPauseTime; 933 } 934 935 public void setVadPauseTime(int vadPauseTime) { 936 this.vadPauseTime = vadPauseTime; 937 } 938 939 public int getMaxSpeechTimeS() { 940 return maxSpeechTimeS; 941 } 942 943 public void setMaxSpeechTimeS(int maxSpeechTimeS) { 944 this.maxSpeechTimeS = maxSpeechTimeS; 945 } 946 947 public void setVadEnable(boolean vadEnable) { 948 this.vadEnable = vadEnable; 949 } 950 951 public void setVolumeEnable(boolean volumeEnable) { 952 this.volumeEnable = volumeEnable; 953 } 954 955 public void setNoSpeechTimeOut(int noSpeechTimeOut) { 956 this.noSpeechTimeOut = noSpeechTimeOut; 957 } 958 959 public void setEnablePunctuation(boolean enablePunctuation) { 960 this.enablePunctuation = enablePunctuation; 961 } 962 963 public void setEnableCensor(boolean enableCensor) { 964 this.enableCensor = enableCensor; 965 } 966 967 public void setEnableNumberConvert(boolean enableNumberConvert) { 968 this.enableNumberConvert = enableNumberConvert; 969 } 970 971 public void setResource(String resource) { 972 this.resource = resource; 973 } 974 975 private JSONObject getJsonObject() { 976 return JSONObjectUtil.create() 977 .put(Topic.Dms.AsrCtrl.ENABLE_VAD, vadEnable) 978 .put(Topic.Dms.AsrCtrl.TIME_OUT, noSpeechTimeOut) 979 .put(Topic.Dms.AsrCtrl.ENABLE_VOLUME, volumeEnable) 980 .put(Topic.Dms.AsrCtrl.ENABLE_PUNCTUATION, enablePunctuation) 981 .put(Topic.Dms.AsrCtrl.ENABLE_CENSOR, enableCensor) 982 .put(Topic.Dms.AsrCtrl.ENABLE_NUMBER_CONVERT, enableNumberConvert) 983 .put(Topic.Dms.AsrCtrl.RESOURCE, resource) 984 .put(Topic.Dms.AsrCtrl.VAD_PAUSE_TIME, vadPauseTime) 985 .put(Topic.Dms.AsrCtrl.MAX_SPEECH_TIME_S, maxSpeechTimeS) 986 .build(); 987 } 988 } 989 990 protected void destroy() { 991 if (mInstance != null) { 992 if (mInstance.mNode != null) { 993 mInstance.mNode.stop(); 994 } 995 mInstance = null; 996 } 997 } 998 999 private void subscribeDDSAsr() { 1000 1001 } 1002 1003 /** 1004 * 设置全链路相关事件的监听 1005 * 1006 * @param listener 回调各事件 1007 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 1008 */ 1009 public void setDDSAsrListener(ASREngine.DDSAsrCallback listener) throws DDSNotInitCompleteException { 1010 AILog.userI(TAG, "setCallbackListener input =", (listener != null)); 1011 checkInitComplete(); 1012 mDDSAsrListener = listener; 1013 1014 boolean vadEnable = LocalKeysUtil.getInstance().getBoolean(LocalKeys.Asr.LOCAL_KEY_VAD_ENABLE,true); 1015 1016 String pcmNameTopic = ""; 1017 if (vadEnable) { 1018 pcmNameTopic = Topic.Pcm.LocalVadPcm.TOPIC_NAME; 1019 } else { 1020 pcmNameTopic = Topic.Pcm.LocalRecorderPcm.TOPIC_NAME; 1021 } 1022 1023 String[] topics = new String[]{ 1024 pcmNameTopic, 1025 Topic.Sys.SysVadBegin.TOPIC_NAME, 1026 Topic.Sys.SysVadEnd.TOPIC_NAME, 1027 Topic.Dms.DmsSpeechCtrl.TOPIC_NAME, 1028 }; 1029 BusClient bc = mNode.getBusClient(); 1030 if (bc != null && mDDSAsrListener != null) { 1031 bc.subscribe(topics); 1032 } else { 1033 if (bc == null) { 1034 AILog.e(TAG, "subscribe error -> bc is null"); 1035 } 1036 if (mDDSAsrListener == null) { 1037 AILog.w(TAG, "subscribe error -> Listener is null"); 1038 } 1039 } 1040 } 1041 1042 public interface DDSAsrCallback { 1043 /** 1044 * 请求云端 1045 * 1046 * @param recordId 当前对话的recordId 1047 */ 1048 void onStreamStart(String recordId); 1049 1050 void onVadBegin(); 1051 1052 void onVadEnd(); 1053 1054 /** 1055 * 识别的音频数据的回调,可能会返回多次 1056 * 1057 * @param data 音频数据 1058 */ 1059 void receivedAsrData(byte[] data); 1060 1061 } 1062 1063 // 识别声纹请求业务bean 1064 public static class AsrPlusRequestBean { 1065 private boolean enableAsrPlus; 1066 private boolean enableVprPassThrough; 1067 private String groupId; 1068 private String organization; 1069 private JSONArray users; 1070 1071 public AsrPlusRequestBean setEnableAsrPlus(boolean enableAsrPlus) { 1072 this.enableAsrPlus = enableAsrPlus; 1073 return this; 1074 } 1075 1076 public AsrPlusRequestBean setEnableVprPassThrough(boolean enableVprPassThrough) { 1077 this.enableVprPassThrough = enableVprPassThrough; 1078 return this; 1079 } 1080 1081 public AsrPlusRequestBean setGroupId(String groupId) { 1082 this.groupId = groupId; 1083 return this; 1084 } 1085 1086 public AsrPlusRequestBean setOrganization(String organization) { 1087 this.organization = organization; 1088 return this; 1089 } 1090 1091 public AsrPlusRequestBean addUserId(String userId) { 1092 if (users == null) { 1093 users = new JSONArray(); 1094 } 1095 users.put(userId); 1096 return this; 1097 } 1098 1099 public JSONObject getAsrPlusObj() { 1100 return JSONObjectUtil.create() 1101 .put("enableAsrPlus", enableAsrPlus) 1102 .put("enableVprPassThrough", enableVprPassThrough) 1103 .put("groupId", groupId) 1104 .put("organization", organization) 1105 .put("users", users) 1106 .build(); 1107 } 1108 1109 } 1110}