发送语音+讯飞翻译 项目案例
数据结构
public LongSparseArray<RecordBean> recordList=new LongSparseArray<>();
封装所有相关数据的Bean
public class RecordBean {
public static final String VOICE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "voice";
public static final String XF_VOICE_FILE_PATH = VOICE_PATH + File.separator + "xf_temp_file.wav";
public String pcmPath;
public String aacPath;
public boolean startRecordSuccess = false;//开始录音成功,即调用JJMediaSDK.startRecord的返回值
public boolean endRecordSuccess = false;//结束录音成功,即调用JJMediaSDK.stopRecord的返回值
public long startTime;//开始录音时间
public long endTime;//结束录音时间
public boolean sendVoiceSuccess = false;//上传并发送成功
public boolean translateSuccess = false;//翻译成功
public String qnKey;//上传到七牛的语音地址
public long clientid;//当上传七牛成功后发送一条socket语音消息,此消息需要客户端生成一个clientid。同时这也是集合recordList中的key
public int msgid;//当上传七牛成功后发送一条socket语音消息,服务器响应时会返回一个msgid,以后就需根据msgid发送及获取语音对应的文本
public String content;//讯飞翻译出的内容
public RecordBean(long time) {
clientid = time;
String data = new SimpleDateFormat("yyyy_MM_dd HH_mm_ss SSS", Locale.getDefault()).format(new Date(time));
this.aacPath = VOICE_PATH + File.separator + "aac_" + data + ".aac";
this.pcmPath = VOICE_PATH + File.separator + "pcm_" + data + ".pcm";
L.i("语音文件保存路径:" + pcmPath + "\n" + aacPath);
}
public static class VoiceBean {
//发送的语音消息的内容。仅仅包含语音URL路径以及语音时长String path;
int duration;
public VoiceBean(String path, int duration) {
this.path = path;
this.duration = duration;
}
}
}
长按录制语音相关逻辑
//长按说话
mChatInputWidget.setPressListener(new PressListener() {
private long key;//集合recordList中的key,同时也是RecordBean中的clientid,同时也是语音消息的clientid
@Override
public void pressing() {
if (micOnoff == 1) {//是否正在上麦(占用录音设备):0,未指定;1,开;2,关
ToastHelper.showToastInThread("亲,发送语音功能需要下麦哦...");
} else { //注意,以下代码要在具有录音权限时访问
AudioManager audioManager = (AudioManager) ChatActivity.this.getSystemService(Context.AUDIO_SERVICE);
audioManager.setMicrophoneMute(false);//关闭麦克风静音
//键为当前时间,以保证唯一性
key = System.currentTimeMillis();
RecordBean recordBean = new RecordBean(key);
recordList.put(key, recordBean);
//调用JNI代码启动录音,录音成功后会生成两个文件,这两个文件的存放位置封装在了recordBean中
JJMediaSDK.captureStop();//停止录音
recordBean.startRecordSuccess = JJMediaSDK.startRecord(recordBean.pcmPath, recordBean.aacPath);
recordBean.startTime = System.currentTimeMillis();//记录开始和结束录音时间,以获取录音时长
if (!recordBean.startRecordSuccess) Toast.makeText(ChatActivity.this, "录音失败", Toast.LENGTH_SHORT).show();
else pressSpeeking("正在说话...");//一个自定义的UI,当按住的时候一直显示,当松开的时候消失
}
}
@Override
public void pressStop() {
RecordBean recordBean = recordList.get(key);//获取当前key对应的RecordBean
if (recordBean == null || !recordBean.startRecordSuccess) {//肯定是录音失败了
Toast.makeText(ChatActivity.this, "录音失败", Toast.LENGTH_SHORT).show();
return;
}
AudioManager audioManager = (AudioManager) ChatActivity.this.getSystemService(Context.AUDIO_SERVICE);
audioManager.setMicrophoneMute(true);//开启麦克风静音
//调用JNI代码结束录音。JNI同事说这里不会失败的。谁信啊,万一存储空间不足或手机突然爆掉了呢?
recordBean.endRecordSuccess = JJMediaSDK.stopRecord();
recordBean.endTime = System.currentTimeMillis();
pressSpeekingdimiss();
if (!recordBean.endRecordSuccess) {
Toast.makeText(ChatActivity.this, "录音失败", Toast.LENGTH_SHORT).show();
return;
}
//****************************************【第一个异步:异步上传语音】*****************************************
//异步上传语音到七牛,当上传成功后发送一条socket消息通知语音的URL路径,此时其他用户就可以播放此语音了
//同时,服务器收到此消息后会做出响应,主要是返回一个msgid,以后就可以根据msgid通知及获取语音对应的文本了
VoiceUtils.uploadVoiceAndSendMsg(ChatActivity.this, recordBean);
//****************************************【第二个异步:异步讯飞翻译】*****************************************
if (mIat == null) mIat = VoiceUtils.getSpeechRecognizerInstance(ChatActivity.this);//讯飞SDK初始化
if (mIat == null) return;//讯飞SDK初始化失败
//讯飞SDK翻译过程及状态监听
RecognizerListener recognizerListener = VoiceUtils.getRecognizerListener(content -> {//翻译成功回调
recordBean.content = content;
recordBean.translateSuccess = true;
Toast.makeText(ChatActivity.this, recordBean.content, Toast.LENGTH_SHORT).show();
//**************************【将上传到七牛的语音和讯飞翻译的内容关联起来】******************************
//如果第一个异步已经完成,则直接发一条socket消息,将两者内容联系在一起;否则等第一个异步完成以后再做处理
if (recordBean.sendVoiceSuccess) SendMsgUtils.sendVoiceContentMsg(ChatActivity.this, recordBean);
});
// 函数调用返回值
int ret = mIat.startListening(recognizerListener);
if (ret != ErrorCode.SUCCESS) {
Toast.makeText(ChatActivity.this, "翻译失败", Toast.LENGTH_SHORT).show();
L.i("讯飞SDK翻译失败,错误码:" + ret);
} else {
byte[] audioData = VoiceUtils.readSDFile(recordBean.pcmPath);//读取SDK返回的pcm文件流
if (null != audioData) {
L.i("讯飞SDK开始音频流识别");
mIat.writeAudio(audioData, 0, audioData.length);
mIat.stopListening();
} else {
mIat.cancel();
Toast.makeText(ChatActivity.this, "讯飞SDK读取音频流失败", Toast.LENGTH_SHORT).show();
}
}
}
});
发送三条消息
public class SendMsgUtils {
/**
* 发送语音、Gif图等通用聊天消息
*
* @param activity 必须是ChatActivity或ChatActivityPrivate
* @param msgType 例如Common.e_MsgType.MSGTYPE_GIF_VALUE
* @param content 消息内容,一般都是json格式
*/
public static void sendNormalMsg(Activity activity, int msgType, String content, long clientid) {
if (activity instanceof ChatActivity) {
if (msgType == Common.e_MsgType.MSGTYPE_VOICE_VALUE || msgType == Common.e_MsgType.MSGTYPE_GIF_VALUE) {
int roleType = ((ChatActivity) activity).getRoleType();
if (roleType <= 0) {//游客
Toast.makeText(activity, "您没有权限发送此类型消息", Toast.LENGTH_SHORT).show();
return;
}
}
}
int groupId = 0;
boolean isGroup = false;
int dstId = 0;
if (activity instanceof ChatActivity) {
groupId = ((ChatActivity) activity).getGroupId();
isGroup = ((ChatActivity) activity).isGroup();
dstId = ((ChatActivity) activity).getDstId();
} else if (activity instanceof ChatActivityPrivate) {
groupId = ((ChatActivityPrivate) activity).getGroupId();
isGroup = ((ChatActivityPrivate) activity).isGroup();
dstId = ((ChatActivityPrivate) activity).getDstId();
}
ChatReqHelper.sendNormalMsg(content, groupId, isGroup, dstId, clientid);
ChatModel model = new ChatModel(content, ChatModel.RIGHT, msgType);
model.clientid = clientid;
model.setMsgTime((int) (System.currentTimeMillis() / 1000));
model.setGroupId(groupId);
model.setSrcUser(ChatReqHelper.getUserInfo());
if (activity instanceof ChatActivity) {
((ChatActivity) activity).getmGroupChats().add(0, model);
((ChatActivity) activity).getmRvSquareChat().getAdapter().notifyItemInserted(0);
((ChatActivity) activity).getmRvSquareChat().scrollToPosition(0);
} else if (activity instanceof ChatActivityPrivate) {
Common.UserInfo_t dstUserInfo = Common.UserInfo_t.getDefaultInstance().newBuilderForType().setUserId(dstId).build();
model.setDstUser(dstUserInfo);
((ChatActivityPrivate) activity).getmGroupChats().add(0, model);
((ChatActivityPrivate) activity).getmRvSquareChat().getAdapter().notifyItemInserted(0);
((ChatActivityPrivate) activity).getmRvSquareChat().scrollToPosition(0);
}
}
/**
* 发送语音消息(里面只有语音的URL路径及时长),里面用的完全就是sendNormalMsg的逻辑
*
* @param activity 必须是ChatActivity或ChatActivityPrivate
* @param recordBean 封装所有信息的bean
*/
public static void sendNormalVoiceMsg(Activity activity, RecordBean recordBean) {
//当上传七牛成功后发送一条socket消息,当收到响应时(会返回一个msgid)说明此socket消息发送成功了
int duration = (int) ((recordBean.endTime - recordBean.startTime) / 1000);
RecordBean.VoiceBean voiceBean = new RecordBean.VoiceBean(recordBean.qnKey, duration);
String content = new Gson().toJson(voiceBean);//{"path:":"", duration:100}
sendNormalMsg(activity, Common.e_MsgType.MSGTYPE_VOICE_VALUE, content, recordBean.clientid);
L.i("发送语音消息。content=" + content + "。clientid=" + recordBean.clientid);
}
/**
* 发送语音所对应的文本消息,目的是将上传到七牛的【语音】和讯飞翻译的【内容】关联起来
*/
public static void sendVoiceContentMsg(Activity activity, RecordBean recordBean) {
if (recordBean == null) return;
if (recordBean.sendVoiceSuccess && recordBean.translateSuccess && recordBean.msgid != 0) {
int groupId = 0, dstId = 0;
if (activity instanceof ChatActivity) {
groupId = ((ChatActivity) activity).getGroupId();
dstId = ((ChatActivity) activity).getDstId();
} else if (activity instanceof ChatActivityPrivate) {
groupId = ((ChatActivityPrivate) activity).getGroupId();
dstId = ((ChatActivityPrivate) activity).getDstId();
}
ChatSvr.CMDVoiceContentSubmit message = ChatSvr.CMDVoiceContentSubmit.newBuilder()
.setGroupid(groupId)//群id
.setSrcuid(AccountManager.getInstance().getServiceUserId())//消息发起者id
.setDstuid(dstId)//消息接收者id(群聊传0)
.setMsgid(recordBean.msgid)//msgid,此msgid是由服务器返回的
.setContent(recordBean.content)//语音消息翻译成文本的内容
.build();
LoginConnection.voiceContentSubmit(message.toByteArray(), null);
L.i("发送语音文本消息。content=" + recordBean.content + "。msgid=" + recordBean.msgid);
if (recordBean.pcmPath != null && new File(recordBean.pcmPath).delete()) L.i("成功删除pcm临时文件");
if (recordBean.aacPath != null && new File(recordBean.aacPath).delete()) L.i("成功删除aac临时文件");
//移除集合中的此RecordBean
LongSparseArray<RecordBean> recordList = null;
if (activity instanceof ChatActivity) recordList = ((ChatActivity) activity).recordList;
else if (activity instanceof ChatActivityPrivate) recordList = ((ChatActivityPrivate) activity).recordList;
if (recordList != null) {
recordList.remove(recordBean.clientid);
L.i("成功移除recordBean:" + recordBean.clientid);
}
} else L.i("RecordBean状态错误" + recordBean.toString());
}
/**
* 查询语音文本消息。这时已经与RecordBeanme没有任何关系了,这里的msgid是后台返回的
*/
public static void qryVoiceContentMsg(Activity activity, int msgid) {
int groupId = 0, dstId = 0;
if (activity instanceof ChatActivity) {
groupId = ((ChatActivity) activity).getGroupId();
dstId = ((ChatActivity) activity).getDstId();
} else if (activity instanceof ChatActivityPrivate) {
groupId = ((ChatActivityPrivate) activity).getGroupId();
dstId = ((ChatActivityPrivate) activity).getDstId();
}
ChatSvr.CMDQryChatMsgReq req = ChatSvr.CMDQryChatMsgReq.newBuilder()
.setGroupid(groupId)//群id
.setSrcuid(AccountManager.getInstance().getServiceUserId())//消息发起者id
.setDstuid(dstId)//消息接收者id(群聊传0)
.setMsgid(msgid)//msgid
.build();
LoginConnection.qryChatMsgReq(req.toByteArray(), null);
L.i("查询语音文本消息。msgid=" + msgid + "。groupId=" + groupId);
}
}
服务器的两个响应
public void onEventMainThread(BaseEvent event) {
if (event.getEvent() == EventHelper.EVENT_GROUPMSGRECV) {
if (event.getData() instanceof ChatSvr.CMDGroupMsgRecv) {
//异步上传语音到七牛成功后,客户端发送一条socket消息通知语音的URL路径
//这是当服务器收到此消息后做出的响应,我们主要是拿到回一个msgid,以后就可以根据msgid通知语音对应的文本了
ChatSvr.CMDGroupMsgRecv msgRecv = (ChatSvr.CMDGroupMsgRecv) event.getData();
for (int i = 0; i < recordList.size(); i++) {
Long key = recordList.keyAt(i);
if (msgRecv.getClientMSgId() == key) {//RecordBean的clientid和recordList的key时同一个数
RecordBean recordBean = recordList.get(key);
recordBean.sendVoiceSuccess = true;
recordBean.msgid = msgRecv.getMsgId();
L.i("发送语音响应:msgid=" + recordBean.msgid + " clientid=" + recordBean.clientid);
//**************************【将上传到七牛的语音和讯飞翻译的内容关联起来】******************************
//如果第二个异步已经完成,则直接发一条socket消息,将两者内容联系在一起;否则等第二个异步完成以后再做处理
if (recordBean.translateSuccess) SendMsgUtils.sendVoiceContentMsg(this, recordBean);
break;
}
}
}
return;
}
if (event.getEvent() == EventHelper.EVENT_QRY_CHAT_MSG) {
//**********************************************【响应查询语音消息】************************************************
if (event.getData() instanceof ChatSvr.CMDQryChatMsgResp) {
ChatSvr.CMDQryChatMsgResp resp = (ChatSvr.CMDQryChatMsgResp) event.getData();
if (resp.getMsg() != null) {
int msgID = resp.getMsg().getMsgId();
String voiceContent;
if (resp.getMsg().getVoiceContent() != null) voiceContent = resp.getMsg().getVoiceContent().getData();
else voiceContent = "翻译失败";
Toast.makeText(this, "msgID:" + msgID + " 内容:" + voiceContent, Toast.LENGTH_SHORT).show();
L.i("查询语音文本响应。" + "msgID:" + msgID + " 内容:" + voiceContent);
}
}
return;
}
}
讯飞监听、上传语音等
public class VoiceUtils {
public interface OnRecognizerResultListener {
void onResult(String content);
}
public static RecognizerListener getRecognizerListener(OnRecognizerResultListener listener) {
return new RecognizerListener() {
StringBuilder sb = new StringBuilder();
@Override
public void onBeginOfSpeech() {// 此回调表示:sdk内部录音机已经准备好了,用户可以开始语音输入
L.i("onBeginOfSpeech");
}
@Override
public void onError(SpeechError error) {
L.i("onError:" + error.getErrorCode() + " " + error.getErrorDescription());
//http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=13056&fromuid=44990
// 错误码:10118(您没有说话),可能是录音机权限被禁,需要提示用户打开应用的录音权限。
// 如果使用本地功能(语记)需要提示用户开启语记的录音权限。
//没有数据,vad_bos设置问题
}
@Override
public void onEndOfSpeech() {// 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入
L.i("onEndOfSpeech");
}
@Override
public void onResult(RecognizerResult results, boolean isLast) {
L.i("onResult:" + results.getResultString() + "。格式化内容:" + getFormatResult(results) + "。isLast:" + isLast);
sb.append(getFormatResult(results));
if (isLast) {
L.i("完整结果为:" + sb.toString());
listener.onResult(sb.toString());
}
}
@Override
public void onVolumeChanged(int volume, byte[] data) {
L.i("onVolumeChanged。当前正在说话,音量大小:" + volume + "。返回音频数据长度:" + data.length);
}
@Override
public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
// 以下代码用于获取与云端的会话id,当业务出错时将会话id提供给技术支持人员,可用于查询会话日志,定位出错原因
// 若使用本地能力,会话id为null
if (SpeechEvent.EVENT_SESSION_ID == eventType) {
String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID);
L.i("onEvent:" + eventType + " session_id =" + sid);
}
}
};
}
public static SpeechRecognizer getSpeechRecognizerInstance(Context context) {
//*****************************************************初始化监听器************************************************
InitListener mInitListener = code -> {
if (code != ErrorCode.SUCCESS) L.i("初始化失败,错误码:" + code);
};
SpeechRecognizer mIat = SpeechRecognizer.createRecognizer(context, mInitListener);
if (null == mIat) {
// 创建单例失败,与 21001 错误为同样原因,参考 http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=9688
L.i("创建对象失败,请确认 libmsc.so 放置正确,且有调用 createUtility 进行初始化");
Toast.makeText(context, "语音引擎初始化失败", Toast.LENGTH_SHORT).show();
return null;
}
//******************************************************参数设置**************************************************
// 清空参数
mIat.setParameter(SpeechConstant.PARAMS, null);
mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);// 设置听写引擎
mIat.setParameter(SpeechConstant.RESULT_TYPE, "json");// 设置返回结果格式
mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");// 设置语言
mIat.setParameter(SpeechConstant.ACCENT, "mandarin");// 设置语言区域,mandarin为普通话;
// 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理
mIat.setParameter(SpeechConstant.VAD_BOS, "4000");//4000
// 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音
mIat.setParameter(SpeechConstant.VAD_EOS, "4000");//1000
// 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点
mIat.setParameter(SpeechConstant.ASR_PTT, "1");
// 设置音频【保存】路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");// 注:AUDIO_FORMAT参数语记需要更新版本才能生效
mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, RecordBean.XF_VOICE_FILE_PATH);
// 设置音频来源为外部文件
mIat.setParameter(SpeechConstant.AUDIO_SOURCE, "-1");
// 也可以像以下这样直接设置音频文件路径识别(要求设置文件在sdcard上的全路径):
//mIat.setParameter(SpeechConstant.AUDIO_SOURCE, "-2");
//mIat.setParameter(SpeechConstant.ASR_SOURCE_PATH, "sdcard/XXX/XXX.pcm");
return mIat;
}
/**
* 获取解析出的字符串内容
*/
private static String getFormatResult(RecognizerResult results) {
String text = parseIatResult(results.getResultString());
String sn = null;
// 读取json结果中的sn字段
try {
JSONObject resultJson = new JSONObject(results.getResultString());
sn = resultJson.optString("sn");
} catch (JSONException e) {
e.printStackTrace();
}
// 用HashMap存储听写结果
HashMap<String, String> mIatResults = new LinkedHashMap<>();
mIatResults.put(sn, text);
StringBuilder resultBuffer = new StringBuilder();
for (String key : mIatResults.keySet()) {
resultBuffer.append(mIatResults.get(key));
}
return resultBuffer.toString();
}
private static String parseIatResult(String json) {
StringBuilder ret = new StringBuilder();
try {
JSONArray words = new JSONObject(new JSONTokener(json)).getJSONArray("ws");
for (int i = 0; i < words.length(); i++) {
// 转写结果词,默认使用第一个结果
JSONArray items = words.getJSONObject(i).getJSONArray("cw");
JSONObject obj = items.getJSONObject(0);
ret.append(obj.getString("w"));
}
} catch (Exception e) {
e.printStackTrace();
}
return ret.toString();
}
/**
* 上传语音消息,然后发送语音消息
*/
public static void uploadVoiceAndSendMsg(BaseActivity activity, RecordBean recordBean) {
if (recordBean == null || recordBean.aacPath == null) return;
final File file = new File(recordBean.aacPath);
if (!file.exists()) {
ToastHelper.showErrorToast("录音文件不存在");
return;
}
if (AccountManager.getInstance().getServiceInfo() == null) {
ToastHelper.showToastInThread("您尚未登录");
return;
}
activity.showLoadingDialog();
//**************************************************上传语音消息****************************************
String keyQN = LoginConnection.getUploadKey(recordBean.aacPath);
HBApplication.getInstance().getUploadManager()
.put(recordBean.aacPath,
keyQN,
LoginConnection.getUploadToken(),
(key, info, res) -> {
L.i("上传语音骑牛key:" + key);
//*************************************发送语音消息*****************************************
//当上传七牛成功后发送一条socket消息,当收到响应时(会返回一个msgid)说明此socket消息发送成功了
recordBean.qnKey = key;
SendMsgUtils.sendNormalVoiceMsg(activity, recordBean);
},
new UploadOptions(null, null, false, (key, percent) -> {
//if (activity.dialog != null) activity.dialog.update((int) percent * 100);
}, null));
}
/**
* 【读】SD卡也即/mnt/sdcard/目录下的文件
*/
public static byte[] readSDFile(String fileName) {
if (TextUtils.isEmpty(fileName)) return null;
File file = new File(fileName);
if (!file.exists()) return null;
try {
InputStream ins = new FileInputStream(file);
byte[] data = new byte[ins.available()];
ins.read(data);
ins.close();
return data;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
日志
发送语音
I/RecordBean: 包青天bqt(RecordBean.java:39)#<init>【语音文件保存路径:/storage/emulated/0/voice/pcm_2017_07_04 17_05_23 100.pcm
/storage/emulated/0/voice/aac_2017_07_04 17_05_23 100.aac】
I/ChatActivity$5: 包青天bqt(ChatActivity.java:908)#pressStop【讯飞SDK开始音频流识别】
I/VoiceUtils$1: 包青天bqt(VoiceUtils.java:97)#onVolumeChanged【onVolumeChanged。当前正在说话,音量大小:0。返回音频数据长度:33280】
I/VoiceUtils$1: 包青天bqt(VoiceUtils.java:81)#onEndOfSpeech【onEndOfSpeech】
I/VoiceUtils$1: 包青天bqt(VoiceUtils.java:106)#onEvent【onEvent:20001 session_id =iatad118bff@gz02600cb6a6553cf300】
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】
I/VoiceUtils$1: 包青天bqt(VoiceUtils.java:106)#onEvent【onEvent:20001 session_id =iatad118bff@gz02600cb6a6553cf300】
I/VoiceUtils: 包青天bqt(VoiceUtils.java:222)#lambda$uploadVoiceAndSendMsg$1【上传语音骑牛key:_F-UBAN-YeQIB.aac】
I/SendMsgUtils: 包青天bqt(SendMsgUtils.java:87)#sendNormalVoiceMsg【发送语音消息。content={"duration":1,"path":"_F-UBAN-YeQIB.aac"}。clientid=1499159123100】
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】
I/VoiceUtils$1: 包青天bqt(VoiceUtils.java:89)#onResult【完整结果为:你好。】
I/ChatActivity: 包青天bqt(ChatActivity.java:1703)#onEventMainThread【发送语音响应:msgid=13878 clientid=1499159123100】
I/SendMsgUtils: 包青天bqt(SendMsgUtils.java:113)#sendVoiceContentMsg【发送语音文本消息。content=你好。。msgid=13878】
I/SendMsgUtils: 包青天bqt(SendMsgUtils.java:115)#sendVoiceContentMsg【成功删除pcm临时文件】
I/SendMsgUtils: 包青天bqt(SendMsgUtils.java:116)#sendVoiceContentMsg【成功删除aac临时文件】
I/SendMsgUtils: 包青天bqt(SendMsgUtils.java:124)#sendVoiceContentMsg【成功移除recordBean:1499159123100】
查询语音对应文字
I/SendMsgUtils: 包青天bqt(SendMsgUtils.java:148)#qryVoiceContentMsg【查询语音文本消息。msgid=13879。groupId=36】
I/ChatActivity: 包青天bqt(ChatActivity.java:1723)#onEventMainThread【查询语音文本响应。msgID:13879 内容:需要。】
2017-7-4
本文来自博客园,作者:白乾涛,转载请注明原文链接:https://www.cnblogs.com/baiqiantao/p/7117835.html