数字人
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

411 lines
21 KiB

  1. package com.aispeech.nativedemo;
  2. import android.annotation.TargetApi;
  3. import android.app.Notification;
  4. import android.app.PendingIntent;
  5. import android.app.Service;
  6. import android.content.Context;
  7. import android.content.Intent;
  8. import android.media.AudioFormat;
  9. import android.media.AudioManager;
  10. import android.os.Build;
  11. import android.os.Environment;
  12. import android.os.Handler;
  13. import android.os.IBinder;
  14. import android.os.Looper;
  15. import android.telephony.TelephonyManager;
  16. import android.text.TextUtils;
  17. import android.util.Base64;
  18. import android.util.Log;
  19. import android.widget.Toast;
  20. import com.aispeech.dui.dds.DDS;
  21. import com.aispeech.dui.dds.DDSAuthListener;
  22. import com.aispeech.dui.dds.DDSConfig;
  23. import com.aispeech.dui.dds.DDSConfigBuilder;
  24. import com.aispeech.dui.dds.DDSInitListener;
  25. import com.aispeech.dui.dds.DDSMode;
  26. import com.aispeech.dui.dds.agent.tts.TTSEngine;
  27. import com.aispeech.dui.dds.exceptions.DDSNotInitCompleteException;
  28. import com.aispeech.nativedemo.face.FaceManager;
  29. import com.aispeech.nativedemo.log.Logger;
  30. import com.aispeech.nativedemo.mqtt.MqttManager;
  31. import com.aispeech.nativedemo.network.ws.MessageUtils;
  32. import com.aispeech.nativedemo.network.ws.WebSocketManager;
  33. import com.aispeech.nativedemo.ui.LauncherActivity;
  34. import com.aispeech.nativedemo.config.Config;
  35. import org.json.JSONException;
  36. import org.json.JSONObject;
  37. import java.io.File;
  38. import java.io.IOException;
  39. import java.util.UUID;
  40. /**
  41. * 参见Android SDK集成文档: https://www.dui.ai/docs/operation/#/ct_common_Andriod_SDK
  42. */
  43. public class DDSService extends Service {
  44. public static final String TAG = "DDSService";
  45. private static boolean isStarted = false;
  46. public static int initCompleted = 0;
  47. public DDSService() {
  48. }
  49. public static Intent newDDSServiceIntent(Context context, String action) {
  50. Intent intent = new Intent(context, DDSService.class);
  51. intent.setAction(action);
  52. return intent;
  53. }
  54. @Override
  55. public void onCreate() {
  56. Log.i(TAG, "DDSService on create");
  57. isStarted = false;
  58. setForeground();
  59. super.onCreate();
  60. }
  61. @Override
  62. public IBinder onBind(Intent intent) {
  63. throw new UnsupportedOperationException("Not yet implemented");
  64. }
  65. @TargetApi(Build.VERSION_CODES.O)
  66. private void setForeground() {
  67. Intent intent = new Intent(DDSService.this, LauncherActivity.class);
  68. PendingIntent pi = PendingIntent.getActivity(DDSService.this, 0, intent, 0);
  69. Notification notification = Util.pupNotification(DDSService.this, pi, "DUI ...");
  70. startForeground(1, notification);
  71. }
  72. @Override
  73. public int onStartCommand(Intent intent, int flags, int startId) {
  74. if (intent != null) {
  75. String action = intent.getAction();
  76. Log.i(TAG, "action:" + action);
  77. if (TextUtils.equals(action, "start")) {
  78. if (isStarted) {
  79. Log.i(TAG, "already started");
  80. return super.onStartCommand(intent, flags, startId);
  81. }
  82. init();
  83. isStarted = true;
  84. } else if (TextUtils.equals(action, "stop")) {
  85. //关闭timerstopRefreshTokenTimer()
  86. if (!isStarted) {
  87. Log.i(TAG, "already stopped");
  88. return super.onStartCommand(intent, flags, startId);
  89. }
  90. isStarted = false;
  91. DDS.getInstance().releaseSync();
  92. }
  93. }
  94. return super.onStartCommand(intent, flags, startId);
  95. }
  96. // 初始化dds组件
  97. private void init() {
  98. // DDS.getInstance().setDebugMode(2); //在调试时可以打开sdk调试日志,在发布版本时,请关闭
  99. DDS.getInstance().init(getApplicationContext(), createConfig(), mInitListener, mAuthListener);
  100. }
  101. // dds初始状态监听器,监听init是否成功
  102. private DDSInitListener mInitListener = new DDSInitListener() {
  103. @Override
  104. public void onInitComplete(boolean isFull) {
  105. Logger.e("思必驰初始化成功:onInitComplete " + isFull);
  106. if (isFull) {
  107. // 发送一个init成功的广播
  108. Logger.e("init face sdk");
  109. FaceManager.getInstance(DuiApplication.getContext()).initEngine();
  110. Logger.e("init face sdk over");
  111. sendBroadcast(new Intent("ddsdemo.intent.action.init_complete"));
  112. initCompleted = 1;
  113. try {
  114. DDS.getInstance().getAgent().getTTSEngine().setMode(TTSEngine.LOCAL);
  115. // DDS.getInstance().getAgent().getTTSEngine().setMode(DDSMode.TTS_SILENCE);
  116. // DDS.getInstance().getAgent().getTTSEngine().setSpeaker("zhilingfp");
  117. DDS.getInstance().getAgent().getTTSEngine().setSpeaker("hqqiaf","hqqiaf_lstm_210909.bin");
  118. } catch (DDSNotInitCompleteException e) {
  119. throw new RuntimeException(e);
  120. }
  121. Logger.e("思必驰--------");
  122. } else{
  123. Logger.e("思必驰++++++++++++++++++++");
  124. }
  125. DDS.getInstance().setAudioDebug(true);
  126. // startTtsListening();
  127. }
  128. @Override
  129. public void onError(int what, final String msg) {
  130. Logger.e("思必驰初始化失败:Init onError: " + what + ", error: " + msg);
  131. new Handler(Looper.getMainLooper()).post(new Runnable() {
  132. @Override
  133. public void run() {
  134. Toast.makeText(getApplicationContext(), "初始化失败...", Toast.LENGTH_SHORT).show();
  135. }
  136. });
  137. }
  138. };
  139. // dds认证状态监听器,监听auth是否成功
  140. private DDSAuthListener mAuthListener = new DDSAuthListener() {
  141. @Override
  142. public void onAuthSuccess() {
  143. Log.d(TAG, "onAuthSuccess");
  144. }
  145. @Override
  146. public void onAuthFailed(final String errId, final String error) {
  147. Logger.e("思必驰认证成功:onAuthFailed: " + errId + ", error:" + error);
  148. new Handler(Looper.getMainLooper()).post(new Runnable() {
  149. @Override
  150. public void run() {
  151. MqttManager.getInstance(MainActivity.instance).getFileUploadPath(Config.ErrorEvent.ERROR_UPLOAD_WARNING, Config.ErrorEvent.ERROR_LEVEL_2, "speech_sdk_err_code", TAG);
  152. Toast.makeText(getApplicationContext(),
  153. "授权错误:" + errId + ":\n" + error + "\n请查看手册处理", Toast.LENGTH_SHORT).show();
  154. }
  155. });
  156. // 发送一个认证失败的广播
  157. sendBroadcast(new Intent("ddsdemo.intent.action.auth_failed"));
  158. }
  159. };
  160. @Override
  161. public void onDestroy() {
  162. super.onDestroy();
  163. // 在退出app时将dds组件注销
  164. isStarted = false;
  165. DDS.getInstance().releaseSync();
  166. }
  167. // 创建dds配置信息
  168. private DDSConfig createConfig() {
  169. // 用户设置自己实现的单个功能,目前支持 wakeup 和 vad。WakeupII.class 是一个使用示例
  170. // DDS.getInstance().setOutsideEngine(IEngine.Name.WAKEUP_SINGLE_MIC, WakeupII.class);
  171. // DDSConfigBuilder builder = new DDSConfigBuilder(
  172. // "279616521",
  173. // "test",
  174. // "d797bc5edc9778f7d0ca8242643fa41a",
  175. // "e98db68bd807accc8eb12144c54ef1a1",
  176. // "6d7db9adbc8dbb5efd89e4d5bf46db7f",
  177. // "duicore.zip"
  178. // );
  179. // builder.createTtsBuilder().setAudioFocusMode("external");
  180. // DDSConfig config = builder.build();
  181. DDSConfig config = new DDSConfig();
  182. // 基础配置项
  183. // config.addConfig(DDSConfig.K_PRODUCT_ID, "279615550"); // 产品ID -- 必填
  184. // config.addConfig(DDSConfig.K_USER_ID, "aispeech"); // 用户ID -- 必填
  185. // config.addConfig(DDSConfig.K_ALIAS_KEY, "test"); // 产品的发布分支 -- 必填
  186. // config.addConfig(DDSConfig.K_PRODUCT_KEY, "1fc9d84d79c5b1861bbecbdae698d5a4");// Product Key -- 必填
  187. // config.addConfig(DDSConfig.K_PRODUCT_SECRET, "92c15b48b15820bace5b1c0cf4af614d");// Product Secre -- 必填
  188. // config.addConfig(DDSConfig.K_API_KEY, "0d78cbc00447ef5719a518d363b7ba8b"); // 产品授权秘钥,服务端生成,用于产品授权 -- 必填
  189. // config.addConfig(DDSConfig.K_DEVICE_ID, getDeviceId(getApplicationContext()));//填入唯一的deviceId -- 选填
  190. // config.addConfig(DDSConfig.K_PRODUCT_ID, "279617275"); // 产品ID -- 必填
  191. // config.addConfig(DDSConfig.K_USER_ID, "aispeech"); // 用户ID -- 必填
  192. // config.addConfig(DDSConfig.K_ALIAS_KEY, "test"); // 产品的发布分支 -- 必填
  193. // config.addConfig(DDSConfig.K_PRODUCT_KEY, "12b64c4441d654ecc0cc98e9797f9d28");// Product Key -- 必填
  194. // config.addConfig(DDSConfig.K_PRODUCT_SECRET, "2f8bdd769cc7de7294b061b0c1e0f89d");// Product Secre -- 必填
  195. // config.addConfig(DDSConfig.K_API_KEY, "d709678a1595dcf1e18956da6440cd6c"); // 产品授权秘钥,服务端生成,用于产品授权 -- 必填
  196. // config.addConfig(DDSConfig.K_DEVICE_ID, getDeviceId(getApplicationContext()));//填入唯一的deviceId -- 选填
  197. config.addConfig(DDSConfig.K_PRODUCT_ID, "279616521"); // 产品ID -- 必填
  198. config.addConfig(DDSConfig.K_USER_ID, "aispeech"); // 用户ID -- 必填
  199. config.addConfig(DDSConfig.K_ALIAS_KEY, "test"); // 产品的发布分支 -- 必填
  200. config.addConfig(DDSConfig.K_PRODUCT_KEY, "e98db68bd807accc8eb12144c54ef1a1");// Product Key -- 必填
  201. config.addConfig(DDSConfig.K_PRODUCT_SECRET, "6d7db9adbc8dbb5efd89e4d5bf46db7f");// Product Secre -- 必填
  202. config.addConfig(DDSConfig.K_API_KEY, "d797bc5edc9778f7d0ca8242643fa41a"); // 产品授权秘钥,服务端生成,用于产品授权 -- 必填
  203. config.addConfig(DDSConfig.K_DEVICE_ID, getDeviceId(getApplicationContext()));//填入唯一的deviceId -- 选填
  204. config.addConfig(DDSConfig.K_DEVICE_NAME, getDeviceId(getApplicationContext()));//填入唯一的deviceId -- 选填
  205. // config.addConfig(DDSConfig.K_AUDIO_FOCUS_MODE, "external");//填入唯一的deviceId -- 选填
  206. // config.addConfig(DDSConfig.K_PRODUCT_ID, "279617278"); // 产品ID -- 必填
  207. // config.addConfig(DDSConfig.K_USER_ID, "aispeech"); // 用户ID -- 必填
  208. // config.addConfig(DDSConfig.K_ALIAS_KEY, "test"); // 产品的发布分支 -- 必填
  209. // config.addConfig(DDSConfig.K_PRODUCT_KEY, "da09e6ff1a4ca4de4a6a447e596ed41e");// Product Key -- 必填
  210. // config.addConfig(DDSConfig.K_PRODUCT_SECRET, "6def485b9e41c80e1a24a9ca4d1865f4");// Product Secre -- 必填
  211. // config.addConfig(DDSConfig.K_API_KEY, "c27a9e478c3bbe8f87b03b266440e2ff"); // 产品授权秘钥,服务端生成,用于产品授权 -- 必填
  212. // config.addConfig(DDSConfig.K_DEVICE_ID, getDeviceId(getApplicationContext()));//填入唯一的deviceId -- 选填
  213. // 更多高级配置项,请参考文档: https://www.dui.ai/docs/ct_common_Andriod_SDK 中的 --> 四.高级配置项
  214. config.addConfig(DDSConfig.K_DUICORE_ZIP, "duicore.zip"); // 预置在指定目录下的DUI内核资源包名, 避免在线下载内核消耗流量, 推荐使用
  215. config.addConfig(DDSConfig.K_USE_UPDATE_DUICORE, "false"); //设置为false可以关闭dui内核的热更新功能,可以配合内置dui内核资源使用
  216. // 资源更新配置项
  217. config.addConfig(DDSConfig.K_CUSTOM_ZIP, "product.zip"); // 预置在指定目录下的DUI产品配置资源包名, 避免在线下载产品配置消耗流量, 推荐使用
  218. config.addConfig(DDSConfig.K_USE_UPDATE_NOTIFICATION, "false"); // 是否使用内置的资源更新通知栏
  219. // 录音配置项
  220. // config.addConfig(DDSConfig.K_RECORDER_MODE, "internal"); //录音机模式:external(使用外置录音机,需主动调用拾音接口)、internal(使用内置录音机,DDS自动录音)
  221. // config.addConfig(DDSConfig.K_IS_REVERSE_AUDIO_CHANNEL, "false"); // 录音机通道是否反转,默认不反转
  222. // config.addConfig(DDSConfig.K_AUDIO_SOURCE, AudioSource.DEFAULT); // 内置录音机数据源类型
  223. // config.addConfig(DDSConfig.K_AUDIO_BUFFER_SIZE, (16000 * 1 * 16 * 100 / 1000)); // 内置录音机读buffer的大小
  224. // TTS配置项
  225. // config.addConfig(DDSConfig.K_STREAM_TYPE, AudioManager.STREAM_MUSIC); // 内置播放器的STREAM类型
  226. // config.addConfig(DDSConfig.K_TTS_MODE, "internal"); // TTS模式:external(使用外置TTS引擎,需主动注册TTS请求监听器)、internal(使用内置DUI TTS引擎)
  227. // config.addConfig(DDSConfig.K_CUSTOM_TIPS, "{\"71304\":\"请讲话\",\"71305\":\"不知道你在说什么\",\"71308\":\"咱俩还是聊聊天吧\"}"); // 指定对话错误码的TTS播报。若未指定,则使用产品配置。
  228. //唤醒配置项
  229. // config.addConfig(DDSConfig.K_WAKEUP_ROUTER, "dialog"); //唤醒路由:partner(将唤醒结果传递给partner,不会主动进入对话)、dialog(将唤醒结果传递给dui,会主动进入对话)
  230. // config.addConfig(DDSConfig.K_WAKEUP_BIN, "/sdcard/wakeup.bin"); //商务定制版唤醒资源的路径。如果开发者对唤醒率有更高的要求,请联系商务申请定制唤醒资源。
  231. // config.addConfig(DDSConfig.K_ONESHOT_MIDTIME, "500");// OneShot配置:
  232. // config.addConfig(DDSConfig.K_ONESHOT_ENDTIME, "2000");// OneShot配置:
  233. //识别配置项
  234. // config.addConfig(DDSConfig.K_ASR_ENABLE_PUNCTUATION, "false"); //识别是否开启标点
  235. // config.addConfig(DDSConfig.K_ASR_ROUTER, "dialog"); //识别路由:partner(将识别结果传递给partner,不会主动进入语义)、dialog(将识别结果传递给dui,会主动进入语义)
  236. // config.addConfig(DDSConfig.K_VAD_TIMEOUT, 5000); // VAD静音检测超时时间,默认8000毫秒
  237. // config.addConfig(DDSConfig.K_ASR_ENABLE_TONE, "true"); // 识别结果的拼音是否带音调
  238. // config.addConfig(DDSConfig.K_ASR_TIPS, "true"); // 识别完成是否播报提示音
  239. // config.addConfig(DDSConfig.K_VAD_BIN, "/sdcard/vad.bin"); // 商务定制版VAD资源的路径。如果开发者对VAD有更高的要求,请联系商务申请定制VAD资源。
  240. // 麦克风阵列配置项
  241. // config.addConfig(DDSConfig.K_RECORDER_MODE, "internal"); //(适配了hal之后选内部,或者不写这一条,SDK默认是内部---录音机模式:external(使用外置录音机,需主动调用拾音接口)、internal(使用内置录音机,DDS自动录音)
  242. // config.addConfig(DDSConfig.K_MIC_TYPE, 2); // (根据麦克风实际类型进行配置)设置硬件采集模组的类型 0:无。默认值。 1:单麦回消 2:线性四麦 3:环形六麦 4:车载双麦 5:家具双麦 6: 环形四麦 7: 新车载双麦 8: 线性6麦
  243. //
  244. // config.addConfig(DDSConfig.K_USE_SSPE,"true");//如果资源是SSPE资源,则需要将此配置置为true
  245. // config.addConfig(DDSConfig.K_MIC_ARRAY_SSPE_BIN,"sspe_aec_ula_wkp_35mm_ch6_mic4_ref2_v2.0.0.130.bin");//SSPE资源(放在test/src/main/assert文件夹下,或放到机器上指定绝对路径)(已包含aec算法)绝对路径,请务必保证绝对路径有可读写权限
  246. // //config.addConfig(DDSConfig.K_WAKEUP_BIN, "wakeup_s20_zhihuijingling_20230103.bin"); //商务定制版唤醒资源的路径。如果开发者对唤醒率有更高的要求,请联系商务申请定制唤醒资源。
  247. // config.addConfig(DDSConfig.K_AEC_MODE, "internal");//AEC模式,HAL层未集成AEC算法时,选择"internal"。HAL已经集成AEC算法时,选择"external"
  248. config.addConfig(DDSConfig.K_MIC_TYPE, 2);
  249. config.addConfig(DDSConfig.K_MIC_ARRAY_SSPE_BIN, "sspe_aec_ula_wkp_35mm_ch6_mic4_ref2_v2.0.0.130.bin");
  250. // config.addConfig(DDSConfig.K_MIC_ARRAY_SSPE_BIN, "sspe_aec_ula_wkp_35mm_ch6_mic4_ref2_v2.0.0.130_post_20230530.bin");
  251. config.addConfig(DDSConfig.K_MIC_ECHO_CHANNEL_NUM, 2);
  252. config.addConfig(DDSConfig.K_AUDIO_SOURCE, 6);
  253. config.addConfig(DDSConfig.K_AUDIO_CHANNEL_COUNT, 6);
  254. config.addConfig(DDSConfig.K_AUDIO_CHANNEL_CONF, AudioFormat.CHANNEL_IN_MONO);
  255. config.addConfig(DDSConfig.K_AUDIO_SAMPLERATE, 32000);
  256. // config.addConfig(DDSConfig.K_VAD_BIN, "vad_modify.bin");
  257. // config.addConfig(DDSConfig.K_MIC_ARRAY_AEC_CFG, "/data/aec.bin"); // 麦克风阵列aec资源的磁盘绝对路径,需要开发者确保在这个路径下这个资源存在
  258. // config.addConfig(DDSConfig.K_MIC_ARRAY_BEAMFORMING_CFG, "/data/beamforming.bin"); // 麦克风阵列beamforming资源的磁盘绝对路径,需要开发者确保在这个路径下这个资源存在
  259. // 全双工/半双工配置项
  260. // config.addConfig(DDSConfig.K_DUPLEX_MODE, "HALF_DUPLEX");// 半双工模式
  261. // config.addConfig(DDSConfig.K_DUPLEX_MODE, "FULL_DUPLEX");// 全双工模式
  262. // 声纹配置项
  263. // config.addConfig(DDSConfig.K_VPRINT_ENABLE, "true");// 是否使用声纹
  264. // config.addConfig(DDSConfig.K_USE_VPRINT_IN_WAKEUP, "true");// 是否与唤醒结合使用声纹
  265. // config.addConfig(DDSConfig.K_VPRINT_BIN, "/sdcard/vprint.bin");// 声纹资源的绝对路径
  266. // asrpp配置荐
  267. // config.addConfig(DDSConfig.K_USE_GENDER, "true");// 使用性别识别
  268. // config.addConfig(DDSConfig.K_USE_AGE, "true");// 使用年龄识别
  269. Log.i(TAG, "config->" + config.toString());
  270. return config;
  271. }
  272. // 获取手机的唯一标识符: deviceId
  273. private String getDeviceId(Context context) {
  274. TelephonyManager telephonyMgr = (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE);
  275. String imei = null;
  276. try {
  277. imei = telephonyMgr.getDeviceId();
  278. } catch (Exception e) {
  279. e.printStackTrace();
  280. }
  281. String serial = Build.SERIAL;
  282. String uuid;
  283. if (TextUtils.isEmpty(imei)) {
  284. imei = "unkown";
  285. } else if (TextUtils.isEmpty(serial)) {
  286. serial = "unkown";
  287. }
  288. uuid = UUID.nameUUIDFromBytes((imei + serial).getBytes()).toString();
  289. return uuid;
  290. }
  291. private long mTime = 0;
  292. public void startTtsListening() {
  293. try {
  294. DDS.getInstance().getAgent().getTTSEngine().setMode(DDSMode.TTS_SILENCE);
  295. DDS.getInstance().getAgent().getTTSEngine().setListener(new TTSEngine.Callback() {
  296. @Override
  297. public void beginning(String ttsId) {
  298. Log.d(TAG, "TTS开始播报 ttsId = " + ttsId);
  299. }
  300. @Override
  301. public void received(byte[] data) {
  302. Log.d(TAG, "收到音频,此方法会回调多次,直至data为0,音频结束 data = " + data.length);
  303. String pcmData = Base64.encodeToString(data, Base64.DEFAULT);
  304. JSONObject jo = new JSONObject();
  305. try {
  306. jo.put("type", "djTts");
  307. jo.put("data", pcmData);
  308. WebSocketManager.getInstance(MainActivity.instance).sendMsg(jo.toString());
  309. } catch (JSONException e) {
  310. throw new RuntimeException(e);
  311. }
  312. // File file = createFile(mTime + ".pcm");
  313. // RandomAccessFile raf = null;
  314. // try {
  315. // raf = new RandomAccessFile(file, "rw");
  316. // raf.seek(file.length());
  317. // raf.write(data);
  318. // raf.close();
  319. // } catch (IOException e) {
  320. // throw new RuntimeException(e);
  321. // }
  322. }
  323. @Override
  324. public void end(String ttsId, int status) {
  325. }
  326. @Override
  327. public void error(String error) {
  328. Log.d(TAG, "出现错误," + error);
  329. }
  330. @Override
  331. public void phoneReturnReceived(String s) {
  332. }
  333. });
  334. } catch (DDSNotInitCompleteException e) {
  335. e.printStackTrace();
  336. }
  337. }
  338. public File createFile(String name) {
  339. String dirPath = Environment.getExternalStorageDirectory().getAbsolutePath()
  340. +"/Android/data/com.aispeech.nativedemo/cache/asrCache/";
  341. File file = new File(dirPath);
  342. if(!file.exists()) {
  343. file.mkdirs();
  344. }
  345. String filePath = dirPath +name;
  346. File objFile = new File(filePath);
  347. if (!objFile.exists()) {
  348. try {
  349. objFile.createNewFile();
  350. } catch (IOException e) {
  351. e.printStackTrace();
  352. }
  353. return objFile;
  354. }
  355. return objFile;
  356. }
  357. }