您的位置:首页 > 移动开发 > Android开发

CSipSimple程序之拨打电话

2013-09-15 20:13 369 查看
         与前面的短信发送一样,这里我们不再重复讲解ViewPage和Fragments以及进程间通信的内容,具体可参考前面的短信发送部分的内容。

         在这一部分,主要说明程序是如何从上层到调用本地的JNI库,实现SIP打电话功能的。这里我们主要以用户输入被打用户的SPI URI,即如图点击右下角的txt按钮,然后输入被打用户的URI(如wxm@10.7.106.74),然后点击键盘按钮去往即进入打电话功能。如图26所示:



图26 被打用户的SPI URI
         接下来从点击键盘的“去往”按钮开始,分析程序是如何一步步调用底层JNI库的。首先如图27,有个键盘监听器,当键盘监听器监听到按下的action为EditorInfo.IME_ACTION_GO,即为去往按钮时,调用placeCall函数。

private OnEditorActionListener keyboardActionListener = new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView tv, int action, KeyEvent arg2) {
if (action == EditorInfo.IME_ACTION_GO) {
//IME_ACTION_GO即键盘上的Go按钮,
System.out.println("IME_ACTION_GO");
placeCall();
return true;
}
return false;
}
};


图27 键盘监听事件触发
         进入placeCall函数之后,如判断为SIP用户,则进行SipService方法调用,否则直接进行基本用户拨打。如图28程序所示:

private void placeCallWithOption(Bundle b) {
if (service == null) {
return;
}
String toCall = "";
Long accountToUse = SipProfile.INVALID_ID;
// Find account to use
SipProfile acc = accountChooserButton.getSelectedAccount();
if (acc != null) {
accountToUse = acc.id;
}
// Find number to dial
if(isDigit) {
toCall = PhoneNumberUtils.stripSeparators(digits.getText().toString());
}else {
toCall = digits.getText().toString();
}

if (TextUtils.isEmpty(toCall)) {
return;
}

// Well we have now the fields, clear theses fields
digits.getText().clear();

// -- MAKE THE CALL --//
if (accountToUse >= 0) {
// It is a SIP account, try to call service for that
System.out.println("to check that if it's a SIP account");
try {
//用的是SIP用户,所以调用该函数
service.makeCallWithOptions(toCall, accountToUse.intValue(), b);
} catch (RemoteException e) {
Log.e(THIS_FILE, "Service can't be called to make the call");
}
} else if (accountToUse != SipProfile.INVALID_ID) {
// It's an external account, find correct external account
//即用的是SIP电话还是基本电话
System.out.println("to check that if it's a external account");
CallHandlerPlugin ch = new CallHandlerPlugin(getActivity());
ch.loadFrom(accountToUse, toCall, new OnLoadListener() {
@Override
public void onLoad(CallHandlerPlugin ch) {
placePluginCall(ch);
}
});
}
}


图28 DialFragment程序
         上面的语句是进入if语句还是else if与下图29的选择有关。当点击红色矩形的按钮之后会弹出蓝色矩形内的图标,选择第一个表示用SIP账号拨打电话,选择第二个则表示用基本电话拨打。



图29 选择SIP账号还是基本电话账号
                  这里只说明使用SIP电话拨打情况。从图28可看出,程序调用了SipService的makeCallWithOptions方法。进而进入SipService的makeCallWithOptions方法。如图30所示:

@Override
public void makeCallWithOptions(final String callee, final int accountId, final Bundle options)
throws RemoteException {
SipService.this.enforceCallingOrSelfPermission(SipManager.PERMISSION_USE_SIP, null);
//We have to ensure service is properly started and not just binded
SipService.this.startService(new Intent(SipService.this, SipService.class));

if(pjService == null) {
System.out.println("In makeCallWithOptions(),the PjSipService is not started");
Log.e(THIS_FILE, "Can't place call if service not started");
// TODO - we should return a failing status here
return;
}

if(!supportMultipleCalls) {
// Check if there is no ongoing calls if so drop this request by alerting user
SipCallSession activeCall = pjService.getActiveCallInProgress();
if(activeCall != null) {
if(!CustomDistribution.forceNoMultipleCalls()) {
notifyUserOfMessage(R.string.not_configured_multiple_calls);
}
return;
}
}
getExecutor().execute(new SipRunnable() {
@Override
protected void doRun() throws SameThreadException {
//打电话
pjService.makeCall(callee, accountId, options);
}
});
}


图30 SipService的打电话方法
         这样,最终调用PJsipService的makeCall。如图31,红色字体即为最终调用了底层的JNI库函数。

/**
* Make a call
*
* @param callee remote contact ot call If not well formated we try to add
*            domain name of the default account
*/
public int makeCall(String callee, int accountId, Bundle b) throws SameThreadException {
if (!created) {
return -1;
}
//Transform a string callee into a valid sip uri in the context of an account
final ToCall toCall = sanitizeSipUri(callee, accountId);
if (toCall != null) {
pj_str_t uri = pjsua.pj_str_copy(toCall.getCallee());

// Nothing to do with this values
byte[] userData = new byte[1];
int[] callId = new int[1];
pjsua_call_setting cs = new pjsua_call_setting();
pjsua_msg_data msgData = new pjsua_msg_data();
int pjsuaAccId = toCall.getPjsipAccountId();

// Call settings to add video
pjsua.call_setting_default(cs);
cs.setAud_cnt(1);
cs.setVid_cnt(0);
if(b != null && b.getBoolean(SipCallSession.OPT_CALL_VIDEO, false)) {
cs.setVid_cnt(1);
}
cs.setFlag(0);
// Msg data to add headers
pjsua.msg_data_init(msgData);
pjsua.csipsimple_init_acc_msg_data(pjsuaAccId, msgData);

//判断是否打通
int status = pjsua.call_make_call(pjsuaAccId, uri, cs, userData, msgData, callId);
System.out.println("Get the call status -->" + status);
if(status == pjsuaConstants.PJ_SUCCESS) {
dtmfToAutoSend.put(callId[0], toCall.getDtmf());
Log.d(THIS_FILE, "DTMF - Store for " + callId[0] + " - "+toCall.getDtmf());
}
return status;
} else {
System.out.println("to call is null");
service.notifyUserOfMessage(service.getString(R.string.invalid_sip_uri) + " : "
+ callee);
}
return -1;
}


图31 PjSip的makeCall方法
         若使用电话视频也一样,从图31可看出,不管是否开启电话视频,只要使用PjSua设置的相关参数就可以了。如上面的解释语句:call settings to add video。其下面的那些语句就是设置加入vedio的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息