linphone录音分析1
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()方法。
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()方法。
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()方法的可用性,方法调用的位置还需要进一步研究。
- 增加按钮,点击后可开始或者取消录音
- 录音加密和解密播放。