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

数据结构

  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 onError(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)#onVolumeChanged【onVolumeChanged。当前正在说话,音量大小:0。返回音频数据长度:33280】
  5. I/VoiceUtils$1: 包青天bqt(VoiceUtils.java:81)#onEndOfSpeech【onEndOfSpeech】
  6. I/VoiceUtils$1: 包青天bqt(VoiceUtils.java:106)#onEvent【onEvent:20001 session_id =[email protected]】
  7. I/VoiceUtils$1: 包青天bqt(VoiceUtils.java:86)#onResult【onResult:{"sn":1,"ls":false,"bg":0,"ed":0,"ws":[{"bg":0,"cw":[{"sc":0.00,"w":"你好"}]}]}。格式化内容:你好。isLast:false】
  8. I/VoiceUtils$1: 包青天bqt(VoiceUtils.java:106)#onEvent【onEvent:20001 session_id =[email protected]】
  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)#onResult【onResult:{"sn":2,"ls":true,"bg":0,"ed":0,"ws":[{"bg":0,"cw":[{"sc":0.00,"w":"。"}]}]}。格式化内容:。。isLast:true】
  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【成功移除recordBean:1499159123100】

查询语音对应文字

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

2017-7-4

时间: 2024-10-18 00:10:43

发送语音+讯飞翻译 项目案例的相关文章

Android讯飞语音云语音听写学习

讯飞语音云语音听写学习         这几天两个舍友都买了iPhone 6S,玩起了"Hey, Siri",我依旧对我的Nexus 5喊着"OK,Google".但种种原因,国内的"OK,Google"并不能展示出他的全部威力,于是上网搜索国内Android平台的语音助手,个人觉得评价最好的是讯飞的--灵犀语音助手.其实讯飞语音云平台早就注册过了,并下载了相应的SDK,只是没仔细研究.今天突然想好好学习一下,以方便以后集成到自己开发的APP中,

cocos2dx实现android的对讯飞语音的合成(语言朗读的实现)

事实上非常easy,只是有些细节须要注意. 关于讯飞语音在android上的应用,大家须要自己去下载SDK,然后依照讯飞语音提供的api在自己的android的Demo上执行成功,那东西也相当的简单. 然后,大家也须要把自己的cocos2dx项目在android 上部署起来,这些网上资料非常多,也不一一解释,兴许我也会做出相应的总结.这里不多说. OK,废话不多说,直接上代码 思路就是,通过cocos2dx的JNIhelper类实现C++对Java的调用,然后实现语音功能 废话不多说: 直接上代

聚焦语音交互,引爆智能硬件——暨讯飞语音云沙龙杭州站成功举办

5月16日,"让世界聆听我们的声音"--2014年语音云开发者沙龙暨"聚焦语音交互引爆智能硬件"在杭州贝塔咖啡成功举办. 自2013年8月以来,由讯飞语音云举办的开发者沙龙已走过北京.上海.深圳.成都.合肥.厦门等地,与1000多名开发者亲密接触,爆棚的场面.忘我的分享和激烈的讨论,让我们更加坚信:移动互联网时代,语音交互将无处不在. 2014年被称为智能硬件元年,在2014全球移动互联网大会上,智能硬件成为主角, "下一个50亿"预示着智能硬件

讯飞语音 使用步骤(针对androidStudio):语音转文字:

前言:最近做项目用到了讯飞语音,遂搞了一个简单的教程,供大家使用. 讯飞语音  使用步骤:语音转文字:   1,首先去讯飞开放平台( http://www.xfyun.cn/)注册,账号:   2,注册后登录: 3,点击选择我的语音云:   4,点击左侧边栏,创建新的应用: 5,创建好应用后:如图:复制appid: 6,下载sdk:  点击边栏左侧sdk下载中心: 选择我们所需要的功能和平台: 7,点击下载sdk,保存文件,并打开. //-----------------------------

讯飞语音——唤醒

讯飞语音唤醒 唤醒功能,顾名思义,通过语音,唤醒服务,做我们想做的事情. 效果图(开启应用后说讯飞语音或者讯飞语点唤醒) 源码下载 地址:http://download.csdn.net/detail/q4878802/9023213 步骤 1. 创建应用,开通服务 地址:http://blog.csdn.net/q4878802/article/details/47762169 2. 下载SDK 我们要使用的是讯飞的付费功能,选择唤醒服务,点击下载以后,会提示没有购买.点击"购买服务"

(原创)用讯飞语音实现人机交互的功能

目前在做一款车载的项目,其中有一个需求是在开车的时候实现人与手机的对话,全过程不需要用手,只用语音操控. 这个就类似于人与机器人的对话,机器人在后台一直待命,用户说话 机器人做出对应的反映. 但由于用户手机电源的宝贵性,又不能让用户一直开着录音监听,这样很耗费资源.因此使用了讯飞语音提供的唤醒功能. 具体怎么做呢? 看一张流程图吧:这张流程图使用了讯飞的大部分技术(语音唤醒.语音唤醒+命令词识别.语义识别.语音合成),不废话,看图 流程图已经写的很清晰了,简单介绍下 在程序启动的时候先启动唤醒,

基于讯飞语音API应用开发之——离线词典构建

最近实习在做一个跟语音相关的项目,就在度娘上搜索了很多关于语音的API,顺藤摸瓜找到了科大讯飞,虽然度娘自家也有语音识别.语义理解这块,但感觉应该不是很好用,毕竟之前用过百度地图的API,有问题也找不到人帮忙解决(地图开发者群里都是潜水的)...不得不说,科大讯飞在语音这块尤其是中文识别方面做的真心不错,而且Android还支持离线识别. 讯飞官方给的文档内容很详细,在这我就不赘述了.在开发中,由于一些原因需要用到离线识别这块,就学习了一下.讯飞离线识别只支持Android系统,使用时需要安装讯

讯飞阅读与声音复刻:让语音黑科技留住你的声音

提要:在人工智能和移动互联网飞速发展的今天,产品语音同质化越来越严重,如何凸显出产品中的语音特色.让产品的语音有温度变得尤为重要.为此,科大讯飞旗下产品讯飞阅读推出了声音复刻功能,此项功能可基于深度学习的人工智能合成技术为个人定制个性化音库. 在人工智能和移动互联网飞速发展的今天,产品语音同质化越来越严重,如何凸显出产品中的语音特色.让产品的语音有温度变得尤为重要.为此,科大讯飞旗下产品讯飞阅读推出了声音复刻功能,此项功能可基于深度学习的人工智能合成技术为个人定制个性化音库. 讯飞阅读的声音复刻

讯飞语音接口使用

讯飞语音我就不介绍了,说实话,昨晚之前我还不知道这个东西.因为自己现在只用到了语音合成,即将一段文字转化为语音,所以在此先将语音合成的方法列出来. 首先添加框架 iflyMSC.framework, libz.dylib/libz.tbd(Xcode7.x) AVFoundation.framework SystemConfiguration.framework Foundation.framework CoreTelephoney.framework AudioToolbox.framewor