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()方法的可用性,方法調用的位置還需要進一步研究。
- 增加按鈕,點擊後可開始或者取消錄音
- 錄音加密和解密播放。