001package com.aispeech.dui.dds.agent.tts; 002 003import android.text.TextUtils; 004 005import com.aispeech.aigson.AIGson; 006import com.aispeech.aigson.reflect.TypeToken; 007import com.aispeech.dui.BaseNode; 008import com.aispeech.dui.BusClient; 009import com.aispeech.dui.dds.DDS; 010import com.aispeech.dui.dds.agent.tts.bean.CustomAudioBean; 011import com.aispeech.dui.dds.exceptions.DDSNotInitCompleteException; 012import com.aispeech.dui.manager.AILog; 013import com.aispeech.libbase.bussiness.JSONObjectUtil; 014import com.aispeech.libcomm.business.call.TtsCallUtil; 015import com.aispeech.libcomm.business.config.AIConfig; 016import com.aispeech.libcomm.business.topic.PlayerTopicUtil; 017import com.aispeech.libcomm.business.topic.Topic; 018import com.aispeech.libcomm.business.topic.TtsTopicUtil; 019 020import org.json.JSONException; 021import org.json.JSONObject; 022 023import java.lang.reflect.Type; 024import java.util.ArrayList; 025import java.util.List; 026 027 028/** 029 * Created by nemo on 17-12-13. 030 */ 031 032public class TTSEngine { 033 034 private static final String TAG = "TTSEngine"; 035 036 public static final int LOCAL = 0; 037 public static final int CLOUD = 1; 038 039 public static final String TEXT = "text"; 040 public static final String SSML = "ssml"; 041 042 private volatile static TTSEngine mInstance; 043 private Callback mListener; 044 private String mBusServerAddr = ""; 045 private AIGson mAIGson = new AIGson(); 046 private BusClient mBc; 047 private String[] mTopics; 048 049 private final BaseNode mNode = new BaseNode() { 050 051 @Override 052 public String getName() { 053 return "TTSEngine"; 054 } 055 056 @Override 057 public BusClient.RPCResult onCall(String url, Object... args) throws Exception { 058 return null; 059 } 060 061 @Override 062 public void onJoin() { 063 super.onJoin(); 064 mBc = bc; 065 subscribe(); 066 } 067 068 @Override 069 public void onMessage(String topic, Object... parts) { 070 if (Topic.Sys.TtsBegin.TOPIC_NAME.equals(topic)) { 071 JSONObject jsonObject = (JSONObject) parts[0]; 072 String ttsId = jsonObject.optString(Topic.Sys.TtsBegin.TTS_ID); 073 String recordId = jsonObject.optString(Topic.Sys.TtsBegin.RECORD_ID); 074 if (TextUtils.isEmpty(ttsId)) { 075 ttsId = "0"; 076 } 077 synthesizeBegin(ttsId); 078 synthesizeBeginWithRecordId(ttsId,recordId); 079 } else if (Topic.Pcm.LocalTtsPcm.TOPIC_NAME.equals(topic) || Topic.Pcm.LocalTtsSpeakPcm.TOPIC_NAME.equals(topic)) { 080 received((byte[]) parts[0]); 081 } else if (Topic.Sys.TtsError.TOPIC_NAME.equals(topic)) { 082 String data = parts[0].toString(); 083 error(data); 084 } else if (Topic.Sys.TtsPhoneReturn.TOPIC_NAME.equals(topic)) { 085 String data = parts[0].toString(); 086 phoneReturn(data); 087 } else if (Topic.Sys.PlayerBegin.TOPIC_NAME.equals(topic)) { 088 JSONObject jsonObject = (JSONObject) parts[0]; 089 String ttsId = jsonObject.optString(Topic.Sys.PlayerEnd.TTS_ID, "0"); 090 playBegin(ttsId); 091 } else if (Topic.Sys.PlayerEnd.TOPIC_NAME.equals(topic)) { 092 JSONObject jsonObject = (JSONObject) parts[0]; 093 String ttsId = jsonObject.optString(Topic.Sys.PlayerEnd.TTS_ID, "0"); 094 int status = jsonObject.optInt(Topic.Sys.PlayerEnd.STATUS, 0); 095 playEnd(ttsId, status); 096 } else if (Topic.Sys.TtsEnd.TOPIC_NAME.equals(topic)) { 097 JSONObject jsonObject = (JSONObject) parts[0]; 098 String ttsId = jsonObject.optString(Topic.Sys.TtsEnd.TTS_ID); 099 int status = jsonObject.optInt(Topic.Sys.TtsEnd.STATUS); 100 String recordId = jsonObject.optString(Topic.Sys.TtsEnd.RECORD_ID); 101 synthesizeEnd(ttsId, status); 102 synthesizeEndWithRecord(ttsId,status,recordId); 103 } else if (Topic.Sys.PlayerProcess.TOPIC_NAME.equals(topic)) { 104 if (mListener != null && mListener instanceof CallbackOptimize.InnerCallback) { 105 JSONObject jsonObject = (JSONObject) parts[0]; 106 String ttsId = jsonObject.optString(Topic.Sys.PlayerProcess.TTS_ID); 107 int currentFrame = jsonObject.optInt(Topic.Sys.PlayerProcess.CURRENT_FRAME); 108 int totalFrame = jsonObject.optInt(Topic.Sys.PlayerProcess.TOTAL_FRAME); 109 boolean isDataEnd = jsonObject.optBoolean(Topic.Sys.PlayerProcess.IS_DATA_END); 110 ((CallbackOptimize.InnerCallback) mListener).onSpeechProgress(ttsId, currentFrame, totalFrame, isDataEnd); 111 } 112 } 113 } 114 115 @Override 116 public void onExit() { 117 if (mTopics != null && bc != null) { 118 bc.unsubscribe(mTopics); 119 } 120 } 121 }; 122 123 private TTSEngine() { 124 mNode.start(); 125 } 126 127 /** 128 * 获取TTSEngine 129 * 130 * @return TTSEngine实例 131 */ 132 public static TTSEngine getInstance() { 133 TTSEngine localResource = mInstance; 134 if (localResource == null) { 135 synchronized (TTSEngine.class) { 136 localResource = mInstance; 137 if (localResource == null) { 138 mInstance = localResource = new TTSEngine(); 139 } 140 } 141 } 142 return localResource; 143 } 144 145 protected TTSEngine(String lBridgeAddr) { 146 mBusServerAddr = lBridgeAddr; 147 mNode.start(); 148 } 149 150 /** 151 * 获取TTSEngine 152 * 153 * @param lBridgeAddr 指定busserver地址 154 * @return TTSEngine实例 155 */ 156 public static TTSEngine getInstance(String lBridgeAddr) { 157 TTSEngine localResource = mInstance; 158 if (localResource == null) { 159 synchronized (TTSEngine.class) { 160 localResource = mInstance; 161 if (localResource == null) { 162 mInstance = localResource = new TTSEngine(lBridgeAddr); 163 } 164 } 165 } 166 return localResource; 167 } 168 169 private void subscribe() { 170 if (mBc != null && mListener != null && mTopics != null) { 171 mBc.subscribe(mTopics); 172 } else { 173 if (mBc == null) { 174 AILog.e(TAG, "subscribe error -> bc is null"); 175 } 176 } 177 } 178 179 /** 180 * 获取 TTSEngine 实例快照 181 * 182 * @return TTSEngine 183 */ 184 public static TTSEngine getInstanceSnapshot() { 185 return mInstance; 186 } 187 188 /** 189 * 设置TTS相关事件的监听 190 * 191 * @param listener 回调各事件 192 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 193 */ 194 public void setListener(Callback listener) throws DDSNotInitCompleteException { 195 AILog.userI(TAG, "setCallbackListener input =", (listener != null)); 196 checkInitComplete(); 197 mListener = listener; 198 mTopics = new String[]{ 199 Topic.Sys.TtsBegin.TOPIC_NAME, 200 Topic.Sys.TtsEnd.TOPIC_NAME, 201 Topic.Pcm.LocalTtsPcm.TOPIC_NAME, 202 Topic.Pcm.LocalTtsSpeakPcm.TOPIC_NAME, 203 Topic.Sys.TtsError.TOPIC_NAME, 204 Topic.Sys.TtsPhoneReturn.TOPIC_NAME, 205 Topic.Sys.PlayerBegin.TOPIC_NAME, 206 Topic.Sys.PlayerEnd.TOPIC_NAME}; 207 208 subscribe(); 209 } 210 211 /** 212 * 设置TTS相关事件的监听, 精减音频的回调 213 * 214 * @param listener 回调各事件 215 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 216 */ 217 public void setListener(CallbackOptimize listener) throws DDSNotInitCompleteException { 218 AILog.userI(TAG, "setCallbackOptimizeListener input =", (listener != null)); 219 checkInitComplete(); 220 mListener = listener.mInnerCallback; 221 mTopics = new String[]{ 222 Topic.Sys.TtsBegin.TOPIC_NAME, 223 Topic.Sys.TtsEnd.TOPIC_NAME, 224 Topic.Sys.TtsError.TOPIC_NAME, 225 Topic.Sys.TtsPhoneReturn.TOPIC_NAME, 226 Topic.Sys.PlayerBegin.TOPIC_NAME, 227 Topic.Sys.PlayerEnd.TOPIC_NAME}; 228 subscribe(); 229 } 230 231 /** 232 * 设置TTS相关事件的监听, 精减音频的回调 233 * 234 * @param listener 回调各事件 235 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 236 */ 237 public void setListenerByProcess(CallbackOptimize listener) throws DDSNotInitCompleteException { 238 checkInitComplete(); 239 AILog.userI(TAG, "setListenerByProcess input =", (listener != null)); 240 boolean enable = false; 241 if (listener == null) { 242 mListener = null; 243 } else { 244 mListener = listener.mInnerCallback; 245 enable = true; 246 } 247 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 248 if (bc != null) { 249 PlayerTopicUtil.publishSetPlayerEnableProcess(bc, enable); 250 } else { 251 AILog.e(TAG, "setListenerByProcress failed due to null busclient"); 252 } 253 mTopics = new String[]{ 254 Topic.Sys.TtsBegin.TOPIC_NAME, 255 Topic.Sys.TtsEnd.TOPIC_NAME, 256 Topic.Sys.TtsError.TOPIC_NAME, 257 Topic.Sys.PlayerBegin.TOPIC_NAME, 258 Topic.Sys.PlayerEnd.TOPIC_NAME, 259 Topic.Sys.TtsPhoneReturn.TOPIC_NAME, 260 Topic.Sys.PlayerProcess.TOPIC_NAME}; 261 subscribe(); 262 } 263 264 private void synthesizeBegin(String ttsId) { 265 if (mListener != null) { 266 mListener.synthesizeBegin(ttsId); 267 } 268 } 269 270 private void synthesizeBeginWithRecordId(String ttsId,String recordId) { 271 if (mListener != null) { 272 mListener.synthesizeBeginWithRecord(ttsId,recordId); 273 } 274 } 275 276 private void received(byte[] data) { 277 if (mListener != null) { 278 mListener.received(data); 279 } 280 } 281 282 private void phoneReturn(String phoneReturn) { 283 if (mListener != null) { 284 mListener.phoneReturnReceived(phoneReturn); 285 } 286 } 287 288 private void synthesizeEnd(String ttsId,int status) { 289 if (mListener != null) { 290 mListener.synthesizeEnd(ttsId,status); 291 } 292 } 293 294 private void playBegin(String ttsId) { 295 if (mListener != null) { 296 mListener.playBegin(ttsId); 297 } 298 } 299 300 private void playEnd(String ttsId, int status) { 301 if (mListener != null) { 302 mListener.playEnd(ttsId, status); 303 } 304 } 305 306 private void synthesizeEndWithRecord(String ttsId, int status,String recordId) { 307 if (mListener != null) { 308 mListener.synthesizeEndWithRecordId(ttsId, status,recordId); 309 } 310 } 311 312 private void error(String error) { 313 if (mListener != null) { 314 mListener.error(error); 315 } 316 } 317 318 /** 319 * 播报文本,支持SSML 320 * <p> 321 * 当DDSConfig.K_TTS_MODE设置为"external"时,该接口无效,请直接调用外部TTS引擎的对应接口。 322 * 323 * @param text 播报文本 324 * @param priority 优先级 325 * <ul> 326 * <li>优先级0-保留,与aios语音交互同级,仅限内部使用</li> 327 * <li>优先级1-正常,默认选项,同级按序播放</li> 328 * <li>优先级2-重要,可以插话优先级1,同级按序播放,播报完毕后继续播报刚才被插话的优先级1</li> 329 * <li>优先级3-紧急,可以打断优先级1或优先级2,同级按序播放,播报完毕后播报下一句优先级2</li> 330 * </ul> 331 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 332 */ 333 public void speak(String text, int priority) throws DDSNotInitCompleteException { 334 speak(text, priority, "0", -1, TTSEngine.TEXT); 335 } 336 337 /** 338 * 播报文本,支持SSML 339 * <p> 340 * 当DDSConfig.K_TTS_MODE设置为"external"时,该接口无效,请直接调用外部TTS引擎的对应接口。 341 * 342 * @param text 播报文本 343 * @param priority 优先级 344 * @param type 文本的类型,{@link TTSEngine#TEXT} or {@link TTSEngine#SSML} 345 * <ul> 346 * <li>优先级0-保留,与aios语音交互同级,仅限内部使用</li> 347 * <li>优先级1-正常,默认选项,同级按序播放</li> 348 * <li>优先级2-重要,可以插话优先级1,同级按序播放,播报完毕后继续播报刚才被插话的优先级1</li> 349 * <li>优先级3-紧急,可以打断优先级1或优先级2,同级按序播放,播报完毕后播报下一句优先级2</li> 350 * </ul> 351 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 352 */ 353 public void speak(String text, int priority, String type) throws DDSNotInitCompleteException { 354 speak(text, priority, "0", -1, type); 355 } 356 357 /** 358 * 播报文本,支持SSML 359 * <p> 360 * 当DDSConfig.K_TTS_MODE设置为"external"时,该接口无效,请直接调用外部TTS引擎的对应接口。 361 * 362 * @param text 播报文本 363 * @param priority 优先级 364 * <ul> 365 * <li>优先级0-保留,与aios语音交互同级,仅限内部使用;</li> 366 * <li>优先级1-正常,默认选项,同级按序播放;</li> 367 * <li>优先级2-重要,可以插话优先级1,同级按序播放,播报完毕后继续播报刚才被插话的优先级1</li> 368 * <li>优先级3-紧急,可以打断优先级1或优先级2,同级按序播放,播报完毕后播报下一句优先级2</li> 369 * </ul> 370 * @param ttsId 用于追踪该次播报的id,建议使用UUID. 371 * @param audioFocus 该次播报的音频焦 372 * <ul> 373 * <li>priority == 0 374 * {@link android.media.AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}</li> 375 * <li>priority != 0 376 * {@link android.media.AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}</li> 377 * </ul> 378 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 379 */ 380 public void speak(String text, int priority, String ttsId, int audioFocus) throws DDSNotInitCompleteException { 381 speak(text, priority, ttsId, audioFocus, TTSEngine.TEXT); 382 } 383 384 /** 385 * 播报文本,支持SSML 386 * <p> 387 * 当DDSConfig.K_TTS_MODE设置为"external"时,该接口无效,请直接调用外部TTS引擎的对应接口。 388 * 389 * @param text 播报文本 390 * @param priority 优先级 391 * <ul> 392 * <li>优先级0-保留,与aios语音交互同级,仅限内部使用;</li> 393 * <li>优先级1-正常,默认选项,同级按序播放;</li> 394 * <li>优先级2-重要,可以插话优先级1,同级按序播放,播报完毕后继续播报刚才被插话的优先级1</li> 395 * <li>优先级3-紧急,可以打断优先级1或优先级2,同级按序播放,播报完毕后播报下一句优先级2</li> 396 * </ul> 397 * @param ttsId 用于追踪该次播报的id,建议使用UUID. 398 * @param audioFocus 该次播报的音频焦 399 * @param type 文本的类型,{@link TTSEngine#TEXT} or {@link TTSEngine#SSML} 400 * <ul> 401 * <li>priority == 0 402 * {@link android.media.AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}</li> 403 * <li>priority != 0 404 * {@link android.media.AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}</li> 405 * </ul> 406 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 407 */ 408 public void speak(String text, int priority, String ttsId, int audioFocus, String type) throws DDSNotInitCompleteException { 409 checkInitComplete(); 410 AILog.userI(TAG, "speak input =", text, ", priority =", priority, ", ttsId =", ttsId, ", audioFocus =", audioFocus, ", type =", type); 411 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 412 if (bc != null) { 413 TtsTopicUtil.publishSpeak(bc, text, priority, ttsId, audioFocus, type); 414 } else { 415 AILog.e(TAG, "speak failed due to null busclient"); 416 } 417 } 418 419 /** 420 * 播放器静音 421 * 422 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 423 */ 424 public void mutePlayer() throws DDSNotInitCompleteException { 425 checkInitComplete(); 426 AILog.userI(TAG, "mutePlayer"); 427 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 428 if (bc != null) { 429 PlayerTopicUtil.publishSetPlayerVolume(bc, "mute"); 430 } else { 431 AILog.e(TAG, "mutePlayer failed due to null busclient"); 432 } 433 } 434 435 /** 436 * 播放器恢复声音播放 437 * 438 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 439 */ 440 public void unmutePlayer() throws DDSNotInitCompleteException { 441 checkInitComplete(); 442 AILog.userI(TAG, "unmutePlayer"); 443 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 444 if (bc != null) { 445 PlayerTopicUtil.publishSetPlayerVolume(bc, "unmute"); 446 } else { 447 AILog.e(TAG, "unmutePlayer failed due to null busclient"); 448 } 449 } 450 451 /** 452 * 停止播报接口 453 * <p> 454 * 当DDSConfig.K_TTS_MODE设置为"external"时,该接口无效,请直接调用外部TTS引擎的对应接口。 455 * 456 * @param ttsId 和 {@link #speak(String, int, String, int)} ttsId.一致 457 * ttsId与speak接口的ttsId一致,则停止或者移除该播报; 458 * ttsId为空, 停止所有播报; 459 * ttsId为"0",停止当前播报. 460 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 461 */ 462 public void shutup(String ttsId) throws DDSNotInitCompleteException { 463 checkInitComplete(); 464 AILog.userI(TAG, "shutup input =", ttsId); 465 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 466 if (bc != null) { 467 TtsTopicUtil.publishShutup(bc, ttsId == null ? "" : ttsId); 468 } else { 469 AILog.e(TAG, "shutup failed due to null busclient"); 470 } 471 } 472 473 /** 474 * 设置TTS播报类型的接口 475 * <p> 476 * <p> 477 * 调用此接口则云端配置的合成音类型失效,此后的合成音类型都将由此接口来托管 478 * 479 * @param speaker 取值如:zhilingf, gdgm等,若取为null,则使用产品配置的音色 480 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 481 */ 482 public void setSpeaker(String speaker) throws DDSNotInitCompleteException { 483 setSpeaker(speaker, ""); 484 } 485 486 /** 487 * 设置TTS播报类型的接口 488 * <p> 489 * <p> 490 * 调用此接口则云端配置的合成音类型失效,此后的合成音类型都将由此接口来托管 491 * 492 * @param requestBean tts的请求参数,包括音色,采样率等信息 493 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 494 */ 495 public void setSpeaker(TtsSpeakerRequestBean requestBean) throws DDSNotInitCompleteException { 496 checkInitComplete(); 497 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 498 if (bc != null) { 499 String ttsSpeakerStr = ""; 500 if (requestBean != null) { 501 JSONObject ttsSpeakerObj = requestBean.getTtsSpeakObj(); 502 ttsSpeakerStr = ttsSpeakerObj.toString(); 503 AILog.userI(TAG, "setSpeaker input =", ttsSpeakerStr); 504 TtsTopicUtil.publishSetSpeaker(bc, requestBean.getTtsSpeakObj()); 505 } 506 } else { 507 AILog.e(TAG, "setSpeaker failed due to null busclient"); 508 } 509 } 510 511 /** 512 * 设置TTS播报类型的接口 513 * <p> 514 * <p> 515 * 调用此接口则云端配置的合成音类型失效,此后的合成音类型都将由此接口来托管 516 * @param speaker 取值如:zhilingf, gdgm等,若取为null,则使用产品配置的音色 517 * @param resPath 合成资源的全路径: sdcard/aispeech/zhilingf.bin 518 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 519 */ 520 public void setSpeaker(String speaker, String resPath) throws DDSNotInitCompleteException { 521 setSpeaker(speaker, resPath, ""); 522 } 523 524 /** 525 * 设置TTS播报采样率,适配云端24K,默认云端不返回采样率 526 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 527 */ 528 public void setSpeakerSampleRate(int sampleSize) throws DDSNotInitCompleteException { 529 setSpeakerSampleRate(sampleSize,false); 530 } 531 532 /** 533 * 设置TTS播报采样率,适配云端24K,默认云端不返回采样率 534 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 535 */ 536 public void setSpeakerSampleRate(int sampleSize,boolean syncCloud) throws DDSNotInitCompleteException { 537 checkInitComplete(); 538 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 539 if (bc != null) { 540 TtsTopicUtil.publishSetSpeakerSampleRate(bc, sampleSize,syncCloud); 541 TtsTopicUtil.publishSetSpeakerSampleRateForPlayer(mBc, sampleSize); 542 } else { 543 AILog.e(TAG, "setSpeaker failed due to null busclient"); 544 } 545 } 546 547 /** 548 * 设置TTS是否返回音素信息,因为历史遗留音素,会存在下列问题 549 * 部分音色会忽略音素设置,设置为true依旧不会返回信息,并抛出错误码72205, 550 * 如anonyg hbrinf hyanif lunaif_ctn lzyinf swkm zxcm zzxiangm等 551 * 部分音素支持返回音素, 552 * 如cyangfp dyb gdfanfp gqlanfp hthy jjingfp jlshim lanyuf lchuam lili1f_yubo lucyfa 553 * lzliafp madoufp_wenrou madoufp_yubo xbekef xijunma xjingfp xyb xynmamp ychanmp yhchu 554 * zhilingfp zhilingfp_huankuai zsmeif dksjif ybyuaf sqksaf zxiyum aningfp lmyanm 555 * wqingf_csn ppangf_csn hchunf_ctn mamif xmguof等 556 * 其余的音色不支持音素,不会返回音素信息,但是也不会抛出错误码 557 * @param phoneReturn 音素开关; 558 */ 559 public void setPhoneReturn(boolean phoneReturn) throws DDSNotInitCompleteException { 560 checkInitComplete(); 561 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 562 if (bc != null) { 563 TtsTopicUtil.publishSetPhoneReturn(bc, phoneReturn); 564 } else { 565 AILog.e(TAG, "setPhoneReturn failed due to null busclient"); 566 } 567 568 } 569 570 private void setSpeaker(String speaker, String resPath, String userId) throws DDSNotInitCompleteException { 571 checkInitComplete(); 572 AILog.userI(TAG, "setSpeaker input =", speaker, ", resPath =", resPath, ", userId =", userId); 573 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 574 if (bc != null) { 575 TtsTopicUtil.publishSetSpeaker(bc, speaker, resPath, userId); 576 } else { 577 AILog.e(TAG, "setSpeaker failed due to null busclient"); 578 } 579 } 580 581 /** 582 * 动态设置人声复刻的server地址和userId 583 * 584 * @param speaker String 人声复刻voiceId 585 * @param userId String 人声复刻voiceId对应的userId 586 */ 587 public void setSpeakerAndUserId(String speaker, String userId) throws DDSNotInitCompleteException { 588 setSpeaker(speaker, "", userId); 589 } 590 591 /** 592 * 设置TTS人设 593 * 相对的api {@link TTSEngine#removeStyle()} 594 * 595 * @param style 风格,humor:幽默;calm:沉稳;common:普通;简短:short; 596 */ 597 public void setStyle(String style) throws DDSNotInitCompleteException { 598 checkInitComplete(); 599 AILog.userI(TAG, "setStyle input =", style); 600 if (TextUtils.isEmpty(style)) { 601 AILog.w(TAG, "setStyle style is Empty!!!"); 602 return; 603 } 604 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 605 if (bc != null) { 606 TtsTopicUtil.publishSetStyle(bc, style, "update"); 607 } else { 608 AILog.e(TAG, "setStyle failed due to null busclient"); 609 } 610 611 } 612 613 /** 614 * 清除TTS人设 615 * 相对的api {@link TTSEngine#setStyle(String)} 616 */ 617 public void removeStyle() throws DDSNotInitCompleteException { 618 checkInitComplete(); 619 AILog.userI(TAG, "removeStyle"); 620 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 621 if (bc != null) { 622 TtsTopicUtil.publishSetStyle(bc, "", "remove"); 623 } else { 624 AILog.e(TAG, "removeStyle failed due to null busclient"); 625 } 626 } 627 628 /** 629 * 设置自定义TTS播报录音的接口 630 * <p> 631 * <p> 632 * 调用此接口则表态配置的播报录音失效,以动态设置的为准 633 * 634 * @param customAudioList 取值如:自定义播报音频列表 635 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 636 */ 637 public void setCustomAudio(List<CustomAudioBean> customAudioList) throws DDSNotInitCompleteException { 638 checkInitComplete(); 639 String customAudioJson = "[]"; 640 if (customAudioList != null) { 641 customAudioJson = mAIGson.toJson(customAudioList); 642 } 643 AILog.userI(TAG, "setCustomAudio input =", customAudioJson); 644 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 645 if (bc != null) { 646 TtsTopicUtil.publishSetCustomAudio(bc, customAudioJson); 647 } else { 648 AILog.e(TAG, "setCustomAudio failed due to null busclient"); 649 } 650 } 651 652 /** 653 * 获取自定义TTS播报录音的接口 654 * <p> 655 * <p> 656 * 657 * @return 自定义TTS播报录音 658 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 659 */ 660 public List<CustomAudioBean> getCustomAudio() throws DDSNotInitCompleteException { 661 checkInitComplete(); 662 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 663 if (bc != null) { 664 String customAudios = TtsCallUtil.callGetCustomAudio(bc); 665 if (!TextUtils.isEmpty(customAudios)) { 666 Type listType = new TypeToken<ArrayList<CustomAudioBean>>() { 667 }.getType(); 668 AILog.userI(TAG, "getCustomAudio result =", customAudios); 669 return mAIGson.fromJson(customAudios, listType); 670 } 671 } else { 672 AILog.e(TAG, "getCustomAudio failed due to null busclient"); 673 } 674 AILog.userI(TAG, "getCustomAudio result = null"); 675 return null; 676 } 677 678 /** 679 * 设置TTS播报音量的接口 680 * <p> 681 * <p> 682 * 调用此接口则云端配置的合成音音量失效,此后的合成音音量都将由此接口来托管 683 * 684 * @param volume 音量大小,取值1-500 685 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 686 */ 687 public void setVolume(int volume) throws DDSNotInitCompleteException { 688 checkInitComplete(); 689 AILog.userI(TAG, "setVolume input =", volume); 690 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 691 if (bc != null) { 692 TtsTopicUtil.publishSetVolume(bc, "absolute", volume); 693 } else { 694 AILog.e(TAG, "setVolume failed due to null busclient"); 695 } 696 } 697 698 699 /** 700 * 获取dui平台的tts配置 701 * 702 * @return {"speaker":"zhilingf","volume":50,"type":"mode","speed":0.85} 703 */ 704 public String getTtsAIConf() { 705 String aiconf = AIConfig.getInstance().getCustomConfig("tts"); 706 try { 707 JSONObject aiconfJo = new JSONObject(aiconf); 708 String voice = aiconfJo.optString("voice"); 709 String mode = aiconfJo.optString("type"); 710 int volume = aiconfJo.optInt("volume"); 711 double speed = aiconfJo.optDouble("speed"); 712 JSONObject retJo = new JSONObject(); 713 retJo.put("speaker", voice); 714 retJo.put("mode", mode); 715 retJo.put("volume", volume); 716 retJo.put("speed", speed); 717 AILog.userI(TAG, "getTtsAIConf result =", retJo.toString()); 718 return retJo.toString(); 719 } catch (JSONException e) { 720 com.aispeech.dui.manager.AIJavaException.printException(e); 721 } 722 AILog.userI(TAG, "getTtsAIConf result =", aiconf); 723 724 return aiconf; 725 } 726 727 728 /** 729 * 设置TTS播报语速的接口 730 * <p> 731 * <p> 732 * 调用此接口则云端配置的合成音语速失效,此后的合成音语速都将由此接口来托管 733 * 734 * @param speed 语速,取值0.5-2.0,0.5语速最快,2.0语速最慢 735 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 736 */ 737 public void setSpeed(float speed) throws DDSNotInitCompleteException { 738 checkInitComplete(); 739 AILog.userI(TAG, "setSpeed input =", speed); 740 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 741 if (bc != null) { 742 TtsTopicUtil.publishSetSpeed(bc, "absolute", speed); 743 } else { 744 AILog.e(TAG, "setSpeed failed due to null busclient"); 745 } 746 } 747 748 /** 749 * 获取当前TTS人设 750 * 751 * @return String 当前 TTS 人设的类型 752 */ 753 public String getStyle() throws DDSNotInitCompleteException { 754 checkInitComplete(); 755 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 756 String style = null; 757 if (bc != null) { 758 style = TtsCallUtil.callGetStyle(bc); 759 } else { 760 AILog.e(TAG, "getStyle failed due to null busclient"); 761 } 762 AILog.userI(TAG, "getStyle result =", style); 763 return style; 764 } 765 766 767 /** 768 * 获取当前使用的合成音类型 769 * <p> 770 * 771 * @return String 当前使用的合成音类型,如:"zhilingf",获取失败返回null 772 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 773 */ 774 public String getSpeaker() throws DDSNotInitCompleteException { 775 checkInitComplete(); 776 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 777 String speaker = null; 778 if (bc != null) { 779 speaker = TtsCallUtil.callGetspeaker(bc); 780 } else { 781 AILog.e(TAG, "getCurrentSpeaker failed due to null busclient"); 782 } 783 AILog.userI(TAG, "getSpeaker result =", speaker); 784 return speaker; 785 } 786 787 /** 788 * 获取当前使用的合成音语速 789 * <p> 790 * 791 * @return float 当前合成音语速,返回值0.5-2.0,0.5语速最快,2.0语速最慢,获取失败返回 0 792 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 793 */ 794 public float getSpeed() throws DDSNotInitCompleteException { 795 checkInitComplete(); 796 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 797 float speed = 0; 798 if (bc != null) { 799 speed = TtsCallUtil.callGetspeed(bc); 800 } else { 801 AILog.e(TAG, "getCurrentSpeed failed due to null busclient"); 802 } 803 AILog.userI(TAG, "getSpeed result =", speed); 804 return speed; 805 } 806 807 /** 808 * 获取当前使用的合成音音量 809 * <p> 810 * 811 * @return int 当前合成音音量,返回值1-100,获取失败返回 0 812 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 813 */ 814 public int getVolume() throws DDSNotInitCompleteException { 815 checkInitComplete(); 816 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 817 int volume = 0; 818 if (bc != null) { 819 volume = TtsCallUtil.callGetvolume(bc); 820 } else { 821 AILog.e(TAG, "getCurrentVolume failed due to null busclient"); 822 } 823 AILog.userI(TAG, "getVolume result =", volume); 824 return volume; 825 } 826 827 /** 828 * 设置合成音为本地合成或者云端合成 829 * 830 * @param mode 取值 TTSEngine.LOCAL(本地合成) 831 * TTSEngine.CLOUD(云端合成) 832 * @throws DDSNotInitCompleteException 如果DDS没有初始化完成,会抛出exception 833 */ 834 public void setMode(int mode) throws DDSNotInitCompleteException { 835 checkInitComplete(); 836 AILog.userI(TAG, "setMode input =", mode); 837 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 838 if (mode != LOCAL && mode != CLOUD) { 839 AILog.e(TAG, "setMode param is no support, ignore"); 840 return; 841 } 842 if (bc != null) { 843 TtsTopicUtil.publishSetMode(bc, mode == LOCAL ? "local" : "cloud"); 844 } else { 845 AILog.e(TAG, "setMode failed due to null busclient"); 846 } 847 } 848 849 /** 850 * 设备抢焦点,默认为抢焦点 851 * 852 * @param enable true/false true: 抢焦点 false: 不抢焦点 853 */ 854 public void enableFocus(boolean enable) throws DDSNotInitCompleteException { 855 checkInitComplete(); 856 AILog.userI(TAG, "enableFocus input =", enable); 857 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 858 if (bc != null) { 859 PlayerTopicUtil.publishSetPlayerEnableFocus(bc, enable); 860 } else { 861 AILog.e(TAG, "enableFocus failed due to null busclient"); 862 } 863 } 864 865 /** 866 * 动态设置 云端tts 合成地址 867 * 868 * @param tts_server String 869 */ 870 public void setTtsServer(String tts_server) throws DDSNotInitCompleteException { 871 checkInitComplete(); 872 AILog.userI(TAG, "setTtsServer input =", tts_server); 873 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 874 if (bc != null) { 875 TtsTopicUtil.publishSetServer(bc, tts_server); 876 } else { 877 AILog.e(TAG, "setTtsServer failed due to null busclient"); 878 } 879 } 880 881 /** 882 * 设置TTS结束后延迟时间,单位ms 883 * 884 * @param afterTime 885 * @throws DDSNotInitCompleteException 886 */ 887 public void setPlayAfterTime(int afterTime) throws DDSNotInitCompleteException { 888 checkInitComplete(); 889 AILog.userI(TAG, "setPlayAfterTime input =", afterTime); 890 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 891 if (bc != null) { 892 PlayerTopicUtil.publishSetPlayerAfterTime(bc, afterTime); 893 } else { 894 AILog.e(TAG, "setPlayAfterTime failed due to null busclient"); 895 } 896 } 897 898 /** 899 * 设置TTS播报的通道 900 * 901 * @param streamType 902 * @throws DDSNotInitCompleteException 903 */ 904 public void setStreamType(int streamType) throws DDSNotInitCompleteException { 905 checkInitComplete(); 906 AILog.userI(TAG, "setStreamType input =", streamType); 907 908 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 909 if (bc != null) { 910 TtsTopicUtil.publishSetStream(bc, streamType); 911 } else { 912 AILog.e(TAG, "setStreamType failed due to null busclient"); 913 } 914 } 915 916 /** 917 * 设置TTS播报的通道 918 * 919 * @param usage 取值: AudioAttributes.USAGE_* 920 * @param contentType 取值: AudioAttributes.CONTENT_TYPE_* 921 * @throws DDSNotInitCompleteException 922 */ 923 public void setUsage(int usage, int contentType) throws DDSNotInitCompleteException { 924 checkInitComplete(); 925 AILog.userI(TAG, "setUsage usage =", usage, ", contentType =", contentType); 926 927 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 928 if (bc != null) { 929 TtsTopicUtil.publishSetUsage(bc, usage, contentType); 930 } else { 931 AILog.e(TAG, "setContentType failed due to null busclient"); 932 } 933 } 934 935 public void setGainType(int gainType) throws DDSNotInitCompleteException { 936 checkInitComplete(); 937 AILog.userI(TAG, "setGainType input =", gainType); 938 939 BusClient bc = DDS.getInstance().getAgent().getBusClient(); 940 if (bc != null) { 941 TtsTopicUtil.publishSetGainType(bc, gainType); 942 } else { 943 AILog.e(TAG, "setGainType failed due to null busclient"); 944 } 945 } 946 947 private void checkInitComplete() throws DDSNotInitCompleteException { 948 if (DDS.getInstance().getInitStatus() != DDS.INIT_COMPLETE_FULL) { 949 throw new DDSNotInitCompleteException(); 950 } 951 } 952 953 public interface Callback { 954 /** 955 * 开始合成时的回调 956 * 957 * @param ttsId 当前TTS的id, 对话过程中的播报ttsid默认为0,通过speak接口调用的播报,ttsid由speak接口指定。 958 */ 959 void synthesizeBegin(String ttsId); 960 961 void synthesizeBeginWithRecord(String ttsId,String recordId); 962 963 /** 964 * 合成的音频数据的回调,可能会返回多次,data长度为0表示音频结束 965 * 966 * @param data 音频数据 967 */ 968 void received(byte[] data); 969 970 /** 971 * TTS播报完成的回调 972 * 973 * @param ttsId 当前TTS的id, 对话过程中的播报ttsid默认为0,通过speak接口调用的播报,ttsid由speak接口指定。 974 * @param status 播报结束的状态。 975 * 正常播报结束为0 976 * 播报中途被打断结束为1 977 */ 978 void synthesizeEnd(String ttsId, int status); 979 980 void synthesizeEndWithRecordId(String ttsId,int status,String recordId); 981 982 void playBegin(String ttsId); 983 984 void playEnd(String ttsId, int status); 985 986 /** 987 * 合成过程中出现错误的回调s 988 * 989 * @param error 错误信息 990 */ 991 void error(String error); 992 993 /** 994 * 合成的音素数据的回调,可能会返回多次 995 * 996 * @param phoneReturn 返回的音素信息 997 */ 998 void phoneReturnReceived(String phoneReturn); 999 } 1000 1001 public static abstract class CallbackOptimize { 1002 private InnerCallback mInnerCallback; 1003 1004 public CallbackOptimize() { 1005 mInnerCallback = new InnerCallback(this); 1006 } 1007 1008 public void received(byte[] data) { 1009 1010 } 1011 1012 /** 1013 * 开始合成时的回调 1014 * 1015 * @param ttsId 当前TTS的id, 对话过程中的播报ttsid默认为0,通过speak接口调用的播报,ttsid由speak接口指定。 1016 */ 1017 public void synthesizeBegin(String ttsId) { 1018 1019 } 1020 1021 public void synthesizeBeginWidthRecordId(String ttsId,String recordId) { 1022 1023 } 1024 1025 /** 1026 * TTS播报完成的回调 1027 * 1028 * @param ttsId 当前TTS的id, 对话过程中的播报ttsid默认为0,通过speak接口调用的播报,ttsid由speak接口指定。 1029 * @param status 播报结束的状态。 1030 * 正常播报结束为0 1031 * 播报中途被打断结束为1 1032 */ 1033 public void synthesizeEnd(String ttsId, int status) { 1034 1035 } 1036 1037 public void synthesizeEndWithRecordId(String ttsId, int status,String recordId) { 1038 1039 } 1040 1041 public void playBegin(String ttsId) { 1042 1043 } 1044 1045 public void playEnd(String ttsId, int status) { 1046 1047 } 1048 1049 1050 /** 1051 * TTS播报进度的回调 1052 * 1053 * @param ttsId 当前TTS的id, 对话过程中的播报ttsid默认为0,通过speak接口调用的播报,ttsid由speak接口指定。 1054 * @param currentFrame 当前播放器已经播放的帧数 1055 * @param totalFrame 当前tts总下载帧数 1056 * @param isDataReady 数据是否下载完成 1057 */ 1058 public void onSpeechProgress(String ttsId, int currentFrame, int totalFrame, boolean isDataReady) { 1059 } 1060 1061 /** 1062 * 合成过程中出现错误的回调 1063 * 1064 * @param error 错误信息 1065 */ 1066 public void error(String error) { 1067 1068 } 1069 1070 /** 1071 * 合成的音素数据的回调,可能会返回多次 1072 * 1073 * @param phoneReturn 返回的音素信息 1074 */ 1075 public void phoneReturnReceived(String phoneReturn) { 1076 1077 } 1078 1079 private static class InnerCallback implements Callback { 1080 CallbackOptimize optimize; 1081 1082 public InnerCallback(CallbackOptimize optimize) { 1083 this.optimize = optimize; 1084 } 1085 1086 @Override 1087 public void synthesizeBegin(String ttsId) { 1088 optimize.synthesizeBegin(ttsId); 1089 } 1090 1091 @Override 1092 public void synthesizeBeginWithRecord(String ttsId, String recordId) { 1093 optimize.synthesizeBeginWidthRecordId(ttsId,recordId); 1094 } 1095 1096 @Override 1097 public void received(byte[] data) { 1098 optimize.received(data); 1099 } 1100 1101 @Override 1102 public void synthesizeEnd(String ttsId, int status) { 1103 optimize.synthesizeEnd(ttsId,status); 1104 } 1105 1106 @Override 1107 public void synthesizeEndWithRecordId(String ttsId, int status, String recordId) { 1108 optimize.synthesizeEndWithRecordId(ttsId,status,recordId); 1109 } 1110 1111 @Override 1112 public void playBegin(String ttsId) { 1113 optimize.playBegin(ttsId); 1114 } 1115 1116 @Override 1117 public void playEnd(String ttsId, int status) { 1118 optimize.playEnd(ttsId,status); 1119 } 1120 1121 public void onSpeechProgress(String ttsId, int currentFrame, int totalFrame, boolean isDataReady) { 1122 optimize.onSpeechProgress(ttsId, currentFrame, totalFrame, isDataReady); 1123 } 1124 1125 @Override 1126 public void error(String error) { 1127 optimize.error(error); 1128 } 1129 1130 @Override 1131 public void phoneReturnReceived(String phoneReturn) { 1132 optimize.phoneReturnReceived(phoneReturn); 1133 } 1134 } 1135 } 1136 1137 public interface SpeechProcessorListener { 1138 void onSpeechProgress(String ttsId, int currentFrame, int totalFrame, boolean isDataReady); 1139 } 1140 1141 public void destroy() { 1142 if (mInstance != null) { 1143 if (mInstance.mNode != null) { 1144 mInstance.mNode.stop(); 1145 } 1146 mInstance = null; 1147 } 1148 } 1149 1150 // 识别声纹请求业务bean 1151 public static class TtsSpeakerRequestBean { 1152 private String speaker = ""; 1153 private String resPath = ""; 1154 private String userId = ""; 1155 private int sampleRate = 16000; 1156 private int localSampleRate = 16000; 1157 1158 public TtsSpeakerRequestBean setSpeaker(String speaker) { 1159 this.speaker = speaker; 1160 return this; 1161 } 1162 1163 public TtsSpeakerRequestBean setResPath(String resPath) { 1164 this.resPath = resPath; 1165 return this; 1166 } 1167 1168 public TtsSpeakerRequestBean setUserId(String userId) { 1169 this.userId = userId; 1170 return this; 1171 } 1172 1173 public TtsSpeakerRequestBean setSampleRate(int sampleRate) { 1174 this.sampleRate = sampleRate; 1175 return this; 1176 } 1177 1178 public TtsSpeakerRequestBean setLocalSampleRate(int localSampleRate) { 1179 this.localSampleRate = localSampleRate; 1180 return this; 1181 } 1182 1183 public JSONObject getTtsSpeakObj() { 1184 return JSONObjectUtil.create() 1185 .put("value", speaker) 1186 .put("resPath", resPath) 1187 .put("userId", userId) 1188 .put("sampleRate", sampleRate) 1189 .put("localSampleRate", localSampleRate) 1190 .build(); 1191 } 1192 } 1193}