首页 > 代码库 > 发送语音+讯飞翻译 项目案例

发送语音+讯飞翻译 项目案例

数据结构

  1. public LongSparseArray<RecordBean> recordList=new LongSparseArray<>();
封装所有相关数据的Bean
  1. public class RecordBean {
  2. public static final String VOICE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "voice";
  3. public static final String XF_VOICE_FILE_PATH = VOICE_PATH + File.separator + "xf_temp_file.wav";
  4. public String pcmPath;
  5. public String aacPath;
  6. public boolean startRecordSuccess = false;//开始录音成功,即调用JJMediaSDK.startRecord的返回值
  7. public boolean endRecordSuccess = false;//结束录音成功,即调用JJMediaSDK.stopRecord的返回值
  8. public long startTime;//开始录音时间
  9. public long endTime;//结束录音时间
  10. public boolean sendVoiceSuccess = false;//上传并发送成功
  11. public boolean translateSuccess = false;//翻译成功
  12. public String qnKey;//上传到七牛的语音地址
  13. public long clientid;//当上传七牛成功后发送一条socket语音消息,此消息需要客户端生成一个clientid。同时这也是集合recordList中的key
  14. public int msgid;//当上传七牛成功后发送一条socket语音消息,服务器响应时会返回一个msgid,以后就需根据msgid发送及获取语音对应的文本
  15. public String content;//讯飞翻译出的内容
  16. public RecordBean(long time) {
  17. clientid = time;
  18. String data = new SimpleDateFormat("yyyy_MM_dd HH_mm_ss SSS", Locale.getDefault()).format(new Date(time));
  19. this.aacPath = VOICE_PATH + File.separator + "aac_" + data + ".aac";
  20. this.pcmPath = VOICE_PATH + File.separator + "pcm_" + data + ".pcm";
  21. L.i("语音文件保存路径:" + pcmPath + "\n" + aacPath);
  22. }
  23. public static class VoiceBean {//发送的语音消息的内容。仅仅包含语音URL路径以及语音时长
  24. String path;
  25. int duration;
  26. public VoiceBean(String path, int duration) {
  27. this.path = path;
  28. this.duration = duration;
  29. }
  30. }
  31. }

长按录制语音相关逻辑

  1. //长按说话
  2. mChatInputWidget.setPressListener(new PressListener() {
  3. private long key;//集合recordList中的key,同时也是RecordBean中的clientid,同时也是语音消息的clientid
  4. @Override
  5. public void pressing() {
  6. if (micOnoff == 1) {//是否正在上麦(占用录音设备):0,未指定;1,开;2,关
  7. ToastHelper.showToastInThread("亲,发送语音功能需要下麦哦...");
  8. } else { //注意,以下代码要在具有录音权限时访问
  9. AudioManager audioManager = (AudioManager) ChatActivity.this.getSystemService(Context.AUDIO_SERVICE);
  10. audioManager.setMicrophoneMute(false);//关闭麦克风静音
  11. //键为当前时间,以保证唯一性
  12. key = System.currentTimeMillis();
  13. RecordBean recordBean = new RecordBean(key);
  14. recordList.put(key, recordBean);
  15. //调用JNI代码启动录音,录音成功后会生成两个文件,这两个文件的存放位置封装在了recordBean中
  16. JJMediaSDK.captureStop();//停止录音
  17. recordBean.startRecordSuccess = JJMediaSDK.startRecord(recordBean.pcmPath, recordBean.aacPath);
  18. recordBean.startTime = System.currentTimeMillis();//记录开始和结束录音时间,以获取录音时长
  19. if (!recordBean.startRecordSuccess) Toast.makeText(ChatActivity.this, "录音失败", Toast.LENGTH_SHORT).show();
  20. else pressSpeeking("正在说话...");//一个自定义的UI,当按住的时候一直显示,当松开的时候消失
  21. }
  22. }
  23. @Override
  24. public void pressStop() {
  25. RecordBean recordBean = recordList.get(key);//获取当前key对应的RecordBean
  26. if (recordBean == null || !recordBean.startRecordSuccess) {//肯定是录音失败了
  27. Toast.makeText(ChatActivity.this, "录音失败", Toast.LENGTH_SHORT).show();
  28. return;
  29. }
  30. AudioManager audioManager = (AudioManager) ChatActivity.this.getSystemService(Context.AUDIO_SERVICE);
  31. audioManager.setMicrophoneMute(true);//开启麦克风静音
  32. //调用JNI代码结束录音。JNI同事说这里不会失败的。谁信啊,万一存储空间不足或手机突然爆掉了呢?
  33. recordBean.endRecordSuccess = JJMediaSDK.stopRecord();
  34. recordBean.endTime = System.currentTimeMillis();
  35. pressSpeekingdimiss();
  36. if (!recordBean.endRecordSuccess) {
  37. Toast.makeText(ChatActivity.this, "录音失败", Toast.LENGTH_SHORT).show();
  38. return;
  39. }
  40. //****************************************【第一个异步:异步上传语音】*****************************************
  41. //异步上传语音到七牛,当上传成功后发送一条socket消息通知语音的URL路径,此时其他用户就可以播放此语音了
  42. //同时,服务器收到此消息后会做出响应,主要是返回一个msgid,以后就可以根据msgid通知及获取语音对应的文本了
  43. VoiceUtils.uploadVoiceAndSendMsg(ChatActivity.this, recordBean);
  44. //****************************************【第二个异步:异步讯飞翻译】*****************************************
  45. if (mIat == null) mIat = VoiceUtils.getSpeechRecognizerInstance(ChatActivity.this);//讯飞SDK初始化
  46. if (mIat == null) return;//讯飞SDK初始化失败
  47. //讯飞SDK翻译过程及状态监听
  48. RecognizerListener recognizerListener = VoiceUtils.getRecognizerListener(content -> {//翻译成功回调
  49. recordBean.content = content;
  50. recordBean.translateSuccess = true;
  51. Toast.makeText(ChatActivity.this, recordBean.content, Toast.LENGTH_SHORT).show();
  52. //**************************【将上传到七牛的语音和讯飞翻译的内容关联起来】******************************
  53. //如果第一个异步已经完成,则直接发一条socket消息,将两者内容联系在一起;否则等第一个异步完成以后再做处理
  54. if (recordBean.sendVoiceSuccess) SendMsgUtils.sendVoiceContentMsg(ChatActivity.this, recordBean);
  55. });
  56. // 函数调用返回值
  57. int ret = mIat.startListening(recognizerListener);
  58. if (ret != ErrorCode.SUCCESS) {
  59. Toast.makeText(ChatActivity.this, "翻译失败", Toast.LENGTH_SHORT).show();
  60. L.i("讯飞SDK翻译失败,错误码:" + ret);
  61. } else {
  62. byte[] audioData = VoiceUtils.readSDFile(recordBean.pcmPath);//读取SDK返回的pcm文件流
  63. if (null != audioData) {
  64. L.i("讯飞SDK开始音频流识别");
  65. mIat.writeAudio(audioData, 0, audioData.length);
  66. mIat.stopListening();
  67. } else {
  68. mIat.cancel();
  69. Toast.makeText(ChatActivity.this, "讯飞SDK读取音频流失败", Toast.LENGTH_SHORT).show();
  70. }
  71. }
  72. }
  73. });

发送三条消息

  1. public class SendMsgUtils {
  2. /**
  3. * 发送语音、Gif图等通用聊天消息
  4. *
  5. * @param activity 必须是ChatActivity或ChatActivityPrivate
  6. * @param msgType 例如Common.e_MsgType.MSGTYPE_GIF_VALUE
  7. * @param content 消息内容,一般都是json格式
  8. */
  9. public static void sendNormalMsg(Activity activity, int msgType, String content, long clientid) {
  10. if (activity instanceof ChatActivity) {
  11. if (msgType == Common.e_MsgType.MSGTYPE_VOICE_VALUE || msgType == Common.e_MsgType.MSGTYPE_GIF_VALUE) {
  12. int roleType = ((ChatActivity) activity).getRoleType();
  13. if (roleType <= 0) {//游客
  14. Toast.makeText(activity, "您没有权限发送此类型消息", Toast.LENGTH_SHORT).show();
  15. return;
  16. }
  17. }
  18. }
  19. int groupId = 0;
  20. boolean isGroup = false;
  21. int dstId = 0;
  22. if (activity instanceof ChatActivity) {
  23. groupId = ((ChatActivity) activity).getGroupId();
  24. isGroup = ((ChatActivity) activity).isGroup();
  25. dstId = ((ChatActivity) activity).getDstId();
  26. } else if (activity instanceof ChatActivityPrivate) {
  27. groupId = ((ChatActivityPrivate) activity).getGroupId();
  28. isGroup = ((ChatActivityPrivate) activity).isGroup();
  29. dstId = ((ChatActivityPrivate) activity).getDstId();
  30. }
  31. ChatReqHelper.sendNormalMsg(content, groupId, isGroup, dstId, clientid);
  32. ChatModel model = new ChatModel(content, ChatModel.RIGHT, msgType);
  33. model.clientid = clientid;
  34. model.setMsgTime((int) (System.currentTimeMillis() / 1000));
  35. model.setGroupId(groupId);
  36. model.setSrcUser(ChatReqHelper.getUserInfo());
  37. if (activity instanceof ChatActivity) {
  38. ((ChatActivity) activity).getmGroupChats().add(0, model);
  39. ((ChatActivity) activity).getmRvSquareChat().getAdapter().notifyItemInserted(0);
  40. ((ChatActivity) activity).getmRvSquareChat().scrollToPosition(0);
  41. } else if (activity instanceof ChatActivityPrivate) {
  42. Common.UserInfo_t dstUserInfo = Common.UserInfo_t.getDefaultInstance().newBuilderForType().setUserId(dstId).build();
  43. model.setDstUser(dstUserInfo);
  44. ((ChatActivityPrivate) activity).getmGroupChats().add(0, model);
  45. ((ChatActivityPrivate) activity).getmRvSquareChat().getAdapter().notifyItemInserted(0);
  46. ((ChatActivityPrivate) activity).getmRvSquareChat().scrollToPosition(0);
  47. }
  48. }
  49. /**
  50. * 发送语音消息(里面只有语音的URL路径及时长),里面用的完全就是sendNormalMsg的逻辑
  51. *
  52. * @param activity 必须是ChatActivity或ChatActivityPrivate
  53. * @param recordBean 封装所有信息的bean
  54. */
  55. public static void sendNormalVoiceMsg(Activity activity, RecordBean recordBean) {
  56. //当上传七牛成功后发送一条socket消息,当收到响应时(会返回一个msgid)说明此socket消息发送成功了
  57. int duration = (int) ((recordBean.endTime - recordBean.startTime) / 1000);
  58. RecordBean.VoiceBean voiceBean = new RecordBean.VoiceBean(recordBean.qnKey, duration);
  59. String content = new Gson().toJson(voiceBean);//{"path:":"", duration:100}
  60. sendNormalMsg(activity, Common.e_MsgType.MSGTYPE_VOICE_VALUE, content, recordBean.clientid);
  61. L.i("发送语音消息。content=" + content + "。clientid=" + recordBean.clientid);
  62. }
  63. /**
  64. * 发送语音所对应的文本消息,目的是将上传到七牛的【语音】和讯飞翻译的【内容】关联起来
  65. */
  66. public static void sendVoiceContentMsg(Activity activity, RecordBean recordBean) {
  67. if (recordBean == null) return;
  68. if (recordBean.sendVoiceSuccess && recordBean.translateSuccess && recordBean.msgid != 0) {
  69. int groupId = 0, dstId = 0;
  70. if (activity instanceof ChatActivity) {
  71. groupId = ((ChatActivity) activity).getGroupId();
  72. dstId = ((ChatActivity) activity).getDstId();
  73. } else if (activity instanceof ChatActivityPrivate) {
  74. groupId = ((ChatActivityPrivate) activity).getGroupId();
  75. dstId = ((ChatActivityPrivate) activity).getDstId();
  76. }
  77. ChatSvr.CMDVoiceContentSubmit message = ChatSvr.CMDVoiceContentSubmit.newBuilder()
  78. .setGroupid(groupId)//群id
  79. .setSrcuid(AccountManager.getInstance().getServiceUserId())//消息发起者id
  80. .setDstuid(dstId)//消息接收者id(群聊传0)
  81. .setMsgid(recordBean.msgid)//msgid,此msgid是由服务器返回的
  82. .setContent(recordBean.content)//语音消息翻译成文本的内容
  83. .build();
  84. LoginConnection.voiceContentSubmit(message.toByteArray(), null);
  85. L.i("发送语音文本消息。content=" + recordBean.content + "。msgid=" + recordBean.msgid);
  86. if (recordBean.pcmPath != null && new File(recordBean.pcmPath).delete()) L.i("成功删除pcm临时文件");
  87. if (recordBean.aacPath != null && new File(recordBean.aacPath).delete()) L.i("成功删除aac临时文件");
  88. //移除集合中的此RecordBean
  89. LongSparseArray<RecordBean> recordList = null;
  90. if (activity instanceof ChatActivity) recordList = ((ChatActivity) activity).recordList;
  91. else if (activity instanceof ChatActivityPrivate) recordList = ((ChatActivityPrivate) activity).recordList;
  92. if (recordList != null) {
  93. recordList.remove(recordBean.clientid);
  94. L.i("成功移除recordBean:" + recordBean.clientid);
  95. }
  96. } else L.i("RecordBean状态错误" + recordBean.toString());
  97. }
  98. /**
  99. * 查询语音文本消息。这时已经与RecordBeanme没有任何关系了,这里的msgid是后台返回的
  100. */
  101. public static void qryVoiceContentMsg(Activity activity, int msgid) {
  102. int groupId = 0, dstId = 0;
  103. if (activity instanceof ChatActivity) {
  104. groupId = ((ChatActivity) activity).getGroupId();
  105. dstId = ((ChatActivity) activity).getDstId();
  106. } else if (activity instanceof ChatActivityPrivate) {
  107. groupId = ((ChatActivityPrivate) activity).getGroupId();
  108. dstId = ((ChatActivityPrivate) activity).getDstId();
  109. }
  110. ChatSvr.CMDQryChatMsgReq req = ChatSvr.CMDQryChatMsgReq.newBuilder()
  111. .setGroupid(groupId)//群id
  112. .setSrcuid(AccountManager.getInstance().getServiceUserId())//消息发起者id
  113. .setDstuid(dstId)//消息接收者id(群聊传0)
  114. .setMsgid(msgid)//msgid
  115. .build();
  116. LoginConnection.qryChatMsgReq(req.toByteArray(), null);
  117. L.i("查询语音文本消息。msgid=" + msgid + "。groupId=" + groupId);
  118. }
  119. }

服务器的两个响应

  1. public void onEventMainThread(BaseEvent event) {
  2. if (event.getEvent() == EventHelper.EVENT_GROUPMSGRECV) {
  3. if (event.getData() instanceof ChatSvr.CMDGroupMsgRecv) {
  4. //异步上传语音到七牛成功后,客户端发送一条socket消息通知语音的URL路径
  5. //这是当服务器收到此消息后做出的响应,我们主要是拿到回一个msgid,以后就可以根据msgid通知语音对应的文本了
  6. ChatSvr.CMDGroupMsgRecv msgRecv = (ChatSvr.CMDGroupMsgRecv) event.getData();
  7. for (int i = 0; i < recordList.size(); i++) {
  8. Long key = recordList.keyAt(i);
  9. if (msgRecv.getClientMSgId() == key) {//RecordBean的clientid和recordList的key时同一个数
  10. RecordBean recordBean = recordList.get(key);
  11. recordBean.sendVoiceSuccess = true;
  12. recordBean.msgid = msgRecv.getMsgId();
  13. L.i("发送语音响应:msgid=" + recordBean.msgid + " clientid=" + recordBean.clientid);
  14. //**************************【将上传到七牛的语音和讯飞翻译的内容关联起来】******************************
  15. //如果第二个异步已经完成,则直接发一条socket消息,将两者内容联系在一起;否则等第二个异步完成以后再做处理
  16. if (recordBean.translateSuccess) SendMsgUtils.sendVoiceContentMsg(this, recordBean);
  17. break;
  18. }
  19. }
  20. }
  21. return;
  22. }
  23. if (event.getEvent() == EventHelper.EVENT_QRY_CHAT_MSG) {
  24. //**********************************************【响应查询语音消息】************************************************
  25. if (event.getData() instanceof ChatSvr.CMDQryChatMsgResp) {
  26. ChatSvr.CMDQryChatMsgResp resp = (ChatSvr.CMDQryChatMsgResp) event.getData();
  27. if (resp.getMsg() != null) {
  28. int msgID = resp.getMsg().getMsgId();
  29. String voiceContent;
  30. if (resp.getMsg().getVoiceContent() != null) voiceContent = resp.getMsg().getVoiceContent().getData();
  31. else voiceContent = "翻译失败";
  32. Toast.makeText(this, "msgID:" + msgID + " 内容:" + voiceContent, Toast.LENGTH_SHORT).show();
  33. L.i("查询语音文本响应。" + "msgID:" + msgID + " 内容:" + voiceContent);
  34. }
  35. }
  36. return;
  37. }
  38. }

讯飞监听、上传语音等

  1. public class VoiceUtils {
  2. public interface OnRecognizerResultListener {
  3. void onResult(String content);
  4. }
  5. public static RecognizerListener getRecognizerListener(OnRecognizerResultListener listener) {
  6. return new RecognizerListener() {
  7. StringBuilder sb = new StringBuilder();
  8. @Override
  9. public void onBeginOfSpeech() {// 此回调表示:sdk内部录音机已经准备好了,用户可以开始语音输入
  10. L.i("onBeginOfSpeech");
  11. }
  12. @Override
  13. public void one rror(SpeechError error) {
  14. L.i("onError:" + error.getErrorCode() + " " + error.getErrorDescription());
  15. //http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=13056&fromuid=44990
  16. // 错误码:10118(您没有说话),可能是录音机权限被禁,需要提示用户打开应用的录音权限。
  17. // 如果使用本地功能(语记)需要提示用户开启语记的录音权限。
  18. //没有数据,vad_bos设置问题
  19. }
  20. @Override
  21. public void onEndOfSpeech() {// 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入
  22. L.i("onEndOfSpeech");
  23. }
  24. @Override
  25. public void onResult(RecognizerResult results, boolean isLast) {
  26. L.i("onResult:" + results.getResultString() + "。格式化内容:" + getFormatResult(results) + "。isLast:" + isLast);
  27. sb.append(getFormatResult(results));
  28. if (isLast) {
  29. L.i("完整结果为:" + sb.toString());
  30. listener.onResult(sb.toString());
  31. }
  32. }
  33. @Override
  34. public void onVolumeChanged(int volume, byte[] data) {
  35. L.i("onVolumeChanged。当前正在说话,音量大小:" + volume + "。返回音频数据长度:" + data.length);
  36. }
  37. @Override
  38. public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
  39. // 以下代码用于获取与云端的会话id,当业务出错时将会话id提供给技术支持人员,可用于查询会话日志,定位出错原因
  40. // 若使用本地能力,会话id为null
  41. if (SpeechEvent.EVENT_SESSION_ID == eventType) {
  42. String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID);
  43. L.i("onEvent:" + eventType + " session_id =" + sid);
  44. }
  45. }
  46. };
  47. }
  48. public static SpeechRecognizer getSpeechRecognizerInstance(Context context) {
  49. //*****************************************************初始化监听器************************************************
  50. InitListener mInitListener = code -> {
  51. if (code != ErrorCode.SUCCESS) L.i("初始化失败,错误码:" + code);
  52. };
  53. SpeechRecognizer mIat = SpeechRecognizer.createRecognizer(context, mInitListener);
  54. if (null == mIat) {
  55. // 创建单例失败,与 21001 错误为同样原因,参考 http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=9688
  56. L.i("创建对象失败,请确认 libmsc.so 放置正确,且有调用 createUtility 进行初始化");
  57. Toast.makeText(context, "语音引擎初始化失败", Toast.LENGTH_SHORT).show();
  58. return null;
  59. }
  60. //******************************************************参数设置**************************************************
  61. // 清空参数
  62. mIat.setParameter(SpeechConstant.PARAMS, null);
  63. mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);// 设置听写引擎
  64. mIat.setParameter(SpeechConstant.RESULT_TYPE, "json");// 设置返回结果格式
  65. mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");// 设置语言
  66. mIat.setParameter(SpeechConstant.ACCENT, "mandarin");// 设置语言区域,mandarin为普通话;
  67. // 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理
  68. mIat.setParameter(SpeechConstant.VAD_BOS, "4000");//4000
  69. // 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音
  70. mIat.setParameter(SpeechConstant.VAD_EOS, "4000");//1000
  71. // 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点
  72. mIat.setParameter(SpeechConstant.ASR_PTT, "1");
  73. // 设置音频【保存】路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
  74. mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");// 注:AUDIO_FORMAT参数语记需要更新版本才能生效
  75. mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, RecordBean.XF_VOICE_FILE_PATH);
  76. // 设置音频来源为外部文件
  77. mIat.setParameter(SpeechConstant.AUDIO_SOURCE, "-1");
  78. // 也可以像以下这样直接设置音频文件路径识别(要求设置文件在sdcard上的全路径):
  79. //mIat.setParameter(SpeechConstant.AUDIO_SOURCE, "-2");
  80. //mIat.setParameter(SpeechConstant.ASR_SOURCE_PATH, "sdcard/XXX/XXX.pcm");
  81. return mIat;
  82. }
  83. /**
  84. * 获取解析出的字符串内容
  85. */
  86. private static String getFormatResult(RecognizerResult results) {
  87. String text = parseIatResult(results.getResultString());
  88. String sn = null;
  89. // 读取json结果中的sn字段
  90. try {
  91. JSONObject resultJson = new JSONObject(results.getResultString());
  92. sn = resultJson.optString("sn");
  93. } catch (JSONException e) {
  94. e.printStackTrace();
  95. }
  96. // 用HashMap存储听写结果
  97. HashMap<String, String> mIatResults = new LinkedHashMap<>();
  98. mIatResults.put(sn, text);
  99. StringBuilder resultBuffer = new StringBuilder();
  100. for (String key : mIatResults.keySet()) {
  101. resultBuffer.append(mIatResults.get(key));
  102. }
  103. return resultBuffer.toString();
  104. }
  105. private static String parseIatResult(String json) {
  106. StringBuilder ret = new StringBuilder();
  107. try {
  108. JSONArray words = new JSONObject(new JSONTokener(json)).getJSONArray("ws");
  109. for (int i = 0; i < words.length(); i++) {
  110. // 转写结果词,默认使用第一个结果
  111. JSONArray items = words.getJSONObject(i).getJSONArray("cw");
  112. JSONObject obj = items.getJSONObject(0);
  113. ret.append(obj.getString("w"));
  114. }
  115. } catch (Exception e) {
  116. e.printStackTrace();
  117. }
  118. return ret.toString();
  119. }
  120. /**
  121. * 上传语音消息,然后发送语音消息
  122. */
  123. public static void uploadVoiceAndSendMsg(BaseActivity activity, RecordBean recordBean) {
  124. if (recordBean == null || recordBean.aacPath == null) return;
  125. final File file = new File(recordBean.aacPath);
  126. if (!file.exists()) {
  127. ToastHelper.showErrorToast("录音文件不存在");
  128. return;
  129. }
  130. if (AccountManager.getInstance().getServiceInfo() == null) {
  131. ToastHelper.showToastInThread("您尚未登录");
  132. return;
  133. }
  134. activity.showLoadingDialog();
  135. //**************************************************上传语音消息****************************************
  136. String keyQN = LoginConnection.getUploadKey(recordBean.aacPath);
  137. HBApplication.getInstance().getUploadManager()
  138. .put(recordBean.aacPath,
  139. keyQN,
  140. LoginConnection.getUploadToken(),
  141. (key, info, res) -> {
  142. L.i("上传语音骑牛key:" + key);
  143. //*************************************发送语音消息*****************************************
  144. //当上传七牛成功后发送一条socket消息,当收到响应时(会返回一个msgid)说明此socket消息发送成功了
  145. recordBean.qnKey = key;
  146. SendMsgUtils.sendNormalVoiceMsg(activity, recordBean);
  147. },
  148. new UploadOptions(null, null, false, (key, percent) -> {
  149. //if (activity.dialog != null) activity.dialog.update((int) percent * 100);
  150. }, null));
  151. }
  152. /**
  153. * 【读】SD卡也即/mnt/sdcard/目录下的文件
  154. */
  155. public static byte[] readSDFile(String fileName) {
  156. if (TextUtils.isEmpty(fileName)) return null;
  157. File file = new File(fileName);
  158. if (!file.exists()) return null;
  159. try {
  160. InputStream ins = new FileInputStream(file);
  161. byte[] data = new byte[ins.available()];
  162. ins.read(data);
  163. ins.close();
  164. return data;
  165. } catch (Exception e) {
  166. e.printStackTrace();
  167. }
  168. return null;
  169. }
  170. }

日志

发送语音
  1. I/RecordBean: 包青天bqt(RecordBean.java:39)#<init>【语音文件保存路径:/storage/emulated/0/voice/pcm_2017_07_04 17_05_23 100.pcm
  2. /storage/emulated/0/voice/aac_2017_07_04 17_05_23 100.aac
  3. I/ChatActivity$5: 包青天bqt(ChatActivity.java:908)#pressStop【讯飞SDK开始音频流识别】
  4. I/VoiceUtils$1: 包青天bqt(VoiceUtils.java:97)#onVolumeChangedonVolumeChanged。当前正在说话,音量大小:0。返回音频数据长度:33280
  5. I/VoiceUtils$1: 包青天bqt(VoiceUtils.java:81)#onEndOfSpeechonEndOfSpeech
  6. I/VoiceUtils$1: 包青天bqt(VoiceUtils.java:106)#onEventonEvent:20001 session_id =iatad118bff@gz02600cb6a6553cf300
  7. I/VoiceUtils$1: 包青天bqt(VoiceUtils.java:86)#onResultonResult:{"sn":1,"ls":false,"bg":0,"ed":0,"ws":[{"bg":0,"cw":[{"sc":0.00,"w":"你好"}]}]}。格式化内容:你好。isLastfalse
  8. I/VoiceUtils$1: 包青天bqt(VoiceUtils.java:106)#onEventonEvent:20001 session_id =iatad118bff@gz02600cb6a6553cf300
  9. I/VoiceUtils: 包青天bqt(VoiceUtils.java:222)#lambda$uploadVoiceAndSendMsg$1上传语音骑牛key_F-UBAN-YeQIB.aac
  10. I/SendMsgUtils: 包青天bqt(SendMsgUtils.java:87)#sendNormalVoiceMsg发送语音消息content={"duration":1,"path":"_F-UBAN-YeQIB.aac"}。clientid=1499159123100
  11. I/VoiceUtils$1: 包青天bqt(VoiceUtils.java:86)#onResultonResult:{"sn":2,"ls":true,"bg":0,"ed":0,"ws":[{"bg":0,"cw":[{"sc":0.00,"w":"。"}]}]}。格式化内容:。。isLasttrue
  12. I/VoiceUtils$1: 包青天bqt(VoiceUtils.java:89)#onResult完整结果为:你好。
  13. I/ChatActivity: 包青天bqt(ChatActivity.java:1703)#onEventMainThread发送语音响应msgid=13878 clientid=1499159123100
  14. I/SendMsgUtils: 包青天bqt(SendMsgUtils.java:113)#sendVoiceContentMsg发送语音文本消息content=你好。。msgid=13878
  15. I/SendMsgUtils: 包青天bqt(SendMsgUtils.java:115)#sendVoiceContentMsg【成功删除pcm临时文件】
  16. I/SendMsgUtils: 包青天bqt(SendMsgUtils.java:116)#sendVoiceContentMsg【成功删除aac临时文件】
  17. I/SendMsgUtils: 包青天bqt(SendMsgUtils.java:124)#sendVoiceContentMsg【成功移除recordBean1499159123100

查询语音对应文字
  1. I/SendMsgUtils: 包青天bqt(SendMsgUtils.java:148)#qryVoiceContentMsg查询语音文本消息msgid=13879groupId=36
  2. I/ChatActivity: 包青天bqt(ChatActivity.java:1723)#onEventMainThread查询语音文本响应msgID13879 内容:需要。】
2017-7-4

发送语音+讯飞翻译 项目案例