Android调用环信的EaseUI V3.0发送语音不成功的问题。

这两个在集成环信实现IM功能,在开发过程中遇到一个问题,发送文字、表情、图片、位置都是正常的,但是语音就是一直发送不成功,并且只是在第一次安装app登录账号之后发送语音的时候才会出现发送不成功的问题,如果把app杀掉重新打开或者退出账号重新登录再发送语音就能成功发送了。一开始以为是某些初始化的代码没有加,但是仔细查看该加的初始化的东西都加了,没办法,问题要解决啊,于是开始一行一行的看环信的代码,最开始单点到ACTION_UP的时候发现调用recorder.stop()方法的时候会一直报IllegalStateException,显示在这句话这里找原因,一直没找到解决办法。后来开始转换思路,既然recorder.stop()方法会出现问题,肯定是创建的时候哪里出了问题,然后开始在ACTION_DOWN的地方找原因,最后发现是环信给的代码里有一个文件创建的问题,导致文件创建不成功,语音无法发送成功。在说这个问题之前先了解一下环信发送语音功能的实现过程。

环信的聊天页面的底部是一个自定义View,




当点击“按住说话”按钮的时候会出发它的onTouch事件,

//发送语音按钮被点击的时候
    buttonPressToSpeak.setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (listener != null) {
                return listener.onPressToSpeakBtnTouch(v, event);
            }
            return false;
        }
    });
}

然后这个listener会回调到聊天页面,EaseChatFragment,在这个页面处理它的touch事件,

/**
 * 发送语音
 * @param v
 * @param event
 * @return
 */
@Override
public boolean onPressToSpeakBtnTouch(View v, MotionEvent event) {
    return voiceRecorderView.onPressToSpeakBtnTouch(v, event, new EaseVoiceRecorderCallback() {

        @Override
        public void onVoiceRecordComplete(String voiceFilePath, int voiceTimeLength) {
            sendVoiceMessage(voiceFilePath, voiceTimeLength);
        }
    });
}

我们进入onPressSpeakBtnTouch()方法,会看到在这里面对touch的按下、移动、抬起手势进行了处理。

public boolean onPressToSpeakBtnTouch(View v, MotionEvent event, EaseVoiceRecorderCallback recorderCallback) {
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        try {
            if (EaseChatRowVoicePlayClickListener.isPlaying)
                EaseChatRowVoicePlayClickListener.currentPlayListener.stopPlayVoice();
            v.setPressed(true);
            startRecording();
        } catch (Exception e) {
            v.setPressed(false);
        }
        return true;
    case MotionEvent.ACTION_MOVE:
        if (event.getY() < 0) {
            showReleaseToCancelHint();
        } else {
            showMoveUpToCancelHint();
        }
        return true;
    case MotionEvent.ACTION_UP:
        v.setPressed(false);
        if (event.getY() < 0) {
            // discard the recorded audio.
            discardRecording();
        } else {
            // stop recording and send voice file
            try {
                int length = stopRecoding();
                if (length > 0) {
                    if (recorderCallback != null) {
                        recorderCallback.onVoiceRecordComplete(getVoiceFilePath(), length);
                    }
                } else if (length == EMError.FILE_INVALID) {
                    Toast.makeText(context, R.string.Recording_without_permission, Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(context, R.string.The_recording_time_is_too_short, Toast.LENGTH_SHORT).show();
                }
            } catch (Exception e) {
                e.printStackTrace();
                Toast.makeText(context, R.string.send_failure_please, Toast.LENGTH_SHORT).show();
            }
        }
        return true;
    default:
        discardRecording();
        return false;
    }
}

ACTION_DOWN的时候,开始录音,首先是先判断一下当前是否正处于录音状态,如果是,先关闭录音,重新录,然后开始录音,接下来就是录音的代码了:在录音的代码中,带删除线的那一行代码是环信原来自己的代码,红色标记的部分是我自己添加进去的,就是这里出的错,这里要执行的操作是创建对应的录音文件,但是创建一个文件的时候需要先创建这个文件对应的目录,这里没有创建目录的过程就直接创建文件,所以在执行接下来的语句的时候就会报no such file or directory错误。

public String startRecording(Context appContext) {
    file = null;
    try {
        // need to create recorder every time, otherwise, will got exception
        // from setOutputFile when try to reuse
        if (recorder != null) {
            recorder.release();
            recorder = null;
        }
        recorder = new MediaRecorder();
        recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
        recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        recorder.setAudioChannels(1); // MONO
        recorder.setAudioSamplingRate(8000); // 8000Hz
        recorder.setAudioEncodingBitRate(64); // seems if change this to
        voiceFileName = getVoiceFileName(EMClient.getInstance().getCurrentUser());
        voiceFilePath = PathUtil.getInstance().getVoicePath() + "/" + voiceFileName;
        //file = new File(voiceFilePath);
        File file2=PathUtil.getInstance().getVoicePath();
        if(!file2.exists()){
            file2.mkdirs();
        }
        file = new File(voiceFilePath);
        if(!file.exists()){
            file.createNewFile();
        }
        recorder.setOutputFile(file.getAbsolutePath());
        recorder.prepare();
        isRecording = true;
        recorder.start();
    } catch (IOException e) {
        EMLog.e("voice", "prepare() failed");
    }
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                while (isRecording) {
                    android.os.Message msg = new android.os.Message();
                    msg.what = recorder.getMaxAmplitude() * 13 / 0x7FFF;
                    handler.sendMessage(msg);
                    SystemClock.sleep(100);
                }
            } catch (Exception e) {
                EMLog.e("voice", e.toString());
            }
        }
    }).start();
    startTime = new Date().getTime();
    EMLog.d("voice", "start voice recording to file:" + file.getAbsolutePath());
    return file == null ? null : file.getAbsolutePath();
}

ACTION_MOVE的时候,根据手指所在的位置执行不同的结果。

public void showReleaseToCancelHint() {
    recordingHint.setText(context.getString(R.string.release_to_cancel));
    recordingHint.setBackgroundResource(R.drawable.ease_recording_text_hint_bg);
}

public void showMoveUpToCancelHint() {
    recordingHint.setText(context.getString(R.string.move_up_to_cancel));
    recordingHint.setBackgroundColor(Color.TRANSPARENT);
}

ACTION_UP的时候,停止录音,保存语音文件。

public int stopRecoding() {
    if(recorder != null){
        isRecording = false;
        recorder.stop();
        recorder.release();
        recorder = null;

        if(file == null || !file.exists() || !file.isFile()){
            return EMError.FILE_INVALID;
        }
        if (file.length() == 0) {
            file.delete();
            return EMError.FILE_INVALID;
        }
        int seconds = (int) (new Date().getTime() - startTime) / 1000;
        EMLog.d("voice", "voice recording finished. seconds:" + seconds + " file length:" + file.length());
        return seconds;
    }
    return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值