CSipSimple程序之拨打电话

本文详细介绍了从用户界面操作开始,如何通过调用JNI库实现SIP电话功能的具体流程。包括键盘监听事件触发、SIP账号选择、SIP服务调用及最终底层库的调用等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

         与前面的短信发送一样,这里我们不再重复讲解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的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值