linphone录音分析


linphone自feature/record_audio_and_send_it_through_chat版本后对代码结构做了比较大的更改,在AndroidStudio上无法编译,因此尝试将新版linphone的acceptCall功能移植到旧版上,以实现通话录音的功能。

旧版linphone被叫通话过程

当有通话呼入时,在界面上滑动接收通话按钮(accept),即接通电话。按钮accept的触摸监听中主要调用了*answer()*方法。首先实例化一个CallParams对象,设置一些属性,然后主要调用了LinphoneManager.getInstance().acceptCallWithParams(mCall, params)方法接受通话。

private void answer() {
    if (alreadyAcceptedOrDeniedCall) {
        return;
    }
    alreadyAcceptedOrDeniedCall = true;
    //CallParams是一个包含不同的通话相关参数的接口
    CallParams params = LinphoneManager.getLc().createCallParams(mCall);

    boolean isLowBandwidthConnection = !LinphoneUtils.isHighBandwidthConnection(LinphoneService.instance().getApplicationContext());

    if (params != null) {
        params.enableLowBandwidth(isLowBandwidthConnection);
    } else {
        Log.e("Could not create call params for call");
    }

    if (params == null || !LinphoneManager.getInstance().acceptCallWithParams(mCall, params)) {
        // the above method takes care of Samsung Galaxy S
        Toast.makeText(this, R.string.couldnt_accept_call, Toast.LENGTH_LONG).show();
    } else {
        if (!LinphoneActivity.isInstanciated()) {
            return;
        }
        LinphoneManager.getInstance().routeAudioToReceiver();
        LinphoneActivity.instance().startIncallActivity(mCall);
    }
}

新版linphone被叫通话过程

在accept方法中调用的是LinphoneManager.getCallManager().acceptCall(mCall)方法,在该方法中实例化了CallParams参数,并调用了setRecordFile方法设置录音文件的路径。这在老版的linphone中并没有看到。

public boolean acceptCall(Call call) {
    if (call == null) return false;

    Core core = LinphoneManager.getCore();
    CallParams params = core.createCallParams(call);

    boolean isLowBandwidthConnection =
            !LinphoneUtils.isHighBandwidthConnection(
                    LinphoneContext.instance().getApplicationContext());

    if (params != null) {
        params.enableLowBandwidth(isLowBandwidthConnection);
        params.setRecordFile(
                FileUtils.getCallRecordingFilename(mContext, call.getRemoteAddress()));
    } else {
        Log.e("[Call Manager] Could not create call params for call");
        return false;
    }

    call.acceptWithParams(params);
    return true;
}

在被叫通话时实现录音

下载旧版的linphone,如release/4.0.1。在Android Studio中打开,等待gradle加载工程。对方有电话呼入时,滑动接受呼叫按钮后,双方建立通话连接。我想要在建立通话后即开始录音,并在点击通话结束按钮后停止录音。录音文件保存在手机某目录下,可以直接播放。

开始录音

首先要找到代码调用的位置。可以通过布局文件查找对应的活动(Activity)或者碎片(Fragment),这个布局文件对应的是活动call/CallIncomingActivity.java.ImageView accept对象通过findViewById(R.id.accept)方法绑定到接受通话按钮上,通过重写setOnTouchListener方法处理ImageView上的移动事件,当事件为**ACTION_MOVE**,并满足一定条件时,将执行answer()方法。
电话呼入,R.layout.call_incoming

answerRecord()

为了实现录音功能,在这里我用一个answerRecord()方法替代answer()方法。

/**
 * wlf 1127
 */
private void answerRecord() {
    if (alreadyAcceptedOrDeniedCall) {
        return;
    }
    Log.i("wlf","CallIncomingActivity#answerRecord!");
    alreadyAcceptedOrDeniedCall = true;
    if (!CallManager.getInstance().acceptCall(mCall)) {
        // the above method takes care of Samsung Galaxy S
        Toast.makeText(this, R.string.couldnt_accept_call, Toast.LENGTH_LONG).show();
    }
}

代码很简单,从新版linphone中扒过来,主要就是调用了CallManager.getInstance().acceptCall(mCall)方法,但是现在CallManager类中并没有这个方法,需要去实现它。

acceptCall(Call call)

/**
 * wlf 1127
 * @param call
 * @return
 */
public boolean acceptCall(Call call) {
    if (call == null) return false;
    Log.i("wlf","CallManager#acceptCall!");
    CallParams params = LinphoneManager.getLc().createCallParams(call);
    //TODO :params.setMediaEncryption();
    boolean isLowBandwidthConnection =
            !LinphoneUtils.isHighBandwidthConnection(LinphoneService.instance().getApplicationContext());

    if (params != null) {
        params.enableLowBandwidth(isLowBandwidthConnection);
        String filePath = FileUtils.getCallRecordingFilename(LinphoneService.instance().getApplicationContext(), call.getRemoteAddress());
        Log.i("wlf","filePath = " + filePath);
        params.setRecordFile(filePath);
    } else {
        Log.e("[Call Manager] Could not create call params for call");
        return false;
    }
    call.acceptWithParams(params);
    LinphoneManager.getInstance().routeAudioToReceiver();
    LinphoneActivity.instance().startIncallActivity(call);
    call.startRecording();
    Log.i("wlf","after startIncallActivity!");
    return true;
}

首先还是实例化对象CallParams,并设置一些参数。
其中setRecordFile()需要的参数是一个String类型的文件保存路径,我们通过FileUtils中的getCallRecordingFilename获取,该工具类只在新版中有,所以直接把整个文件拷贝到org/linphone路径下。AS会提示一些缺库错误,可以直接把它们注释掉,保证getCallRecordingFilename方法没问题就可以。另外,因为我们只需要录音,而不需要录视频,所以这里把getCallRecordingFilename方法内的fileName += format.format(new Date()) + ".mkv"改为fileName += format.format(new Date()) + ".wav"
call对象接受了参数params,就可以启动通话界面,然后调用call.startRecording()开始录音了。

结束录音

通话开始后,将进入活动CallActivity.java
在onClick(View v)中监听按钮的点击事件,结束通话的按钮是R.id.hang_up。当点击该按钮时,将调用hangUp()方法。
通话界面R.id.call

hangUp()

private void hangUp() {
    Core lc = LinphoneManager.getLc();
    Call currentCall = lc.getCurrentCall();
    Call.stopRecording();//wlf 1127
    Log.i("wlf"," CallActivity#hangUp.stopRecording!");
 
    if(crrentCall != null) {
   	 lc.terminateCall(currentCall)
    } else if (lc.isInConference()) {
        lc.terminateConference();
    } else {
        lc.terminateAllCalls();
    }
}

这里调用LinphoneManager.getLc().getCurrentCall()方法获取到当前的Call对象,并中断通话。我们在中断通话前加入代码Call.stopRecording()以停止录音

这样整个录音过程就结束了,可以在手机目录/storage/emulated/0/Linphone/recordings/目录下找到录音文件,测试是否录音成功

TODO

目前只是在被叫通话时测试了录音方法Call.startRecord()和Call.stopRecord()方法的可用性,方法调用的位置还需要进一步研究。

  1. 增加按钮,点击后可开始或者取消录音
  2. 录音加密和解密播放。
发布了30 篇原创文章 · 获赞 4 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章