Android应用开发Android Sipdroid 对外通话建立过程分析,以及监听通话接通时刻
白羽 2019-01-14 来源 :网络 阅读 535 评论 0

摘要:本文将带你了解Android应用开发Android Sipdroid 对外通话建立过程分析,以及监听通话接通时刻,希望本文对大家学Android有所帮助。

    本文将带你了解Android应用开发Android Sipdroid 对外通话建立过程分析,以及监听通话接通时刻,希望本文对大家学Android有所帮助。


Android   Sipdroid 对外通话建立过程分析,以及监听通话接通时刻。
   
    CallCard中有两类注意一下,一个是更新通话界面的方法
   
    ?
    1
    2
    //对外暴露的方法:更新如通话时间,通话状态
    public void displayMainCallStatus(Phone phone, Call call){}
    第二个私有
   
    ?
    1
    2
    3
    4
    5
    6
    /**
    * Updates the "upper" and "lower" titles based on   the
    * current state of this call.
    */
     
    private void updateCardTitleWidgets(Phone phone, Call call){}
    在私有方法里面你可以看到Call.State state =   call.getState();通话状态的判断,当Call.State.ACTIVE时,计时器mElapsedTime开始计时,从某种状态来说,这个已经算正式接通的状态。所以,更进一步是要对Call状态的实时监听。
   
    调用处:
    这里写图片描述
   
    CallCard的displayMainCallStatus:
    CallCard的displayMainCallStatus
   
    CallCard的updateCardTitleWidgets:
    CallCard的updateCardTitleWidgets
   
    Call通话状态枚举
   
    IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED
   
    我们只注意ACTIVE(通话中)这个。
   
      在管理器Receiver中,你可以查看到这里有对Call状态的设置ccCall.setState(...),在我们向外拨打电话同时会发送OFFHOLD广播(摘机)过程,你也可以通过这个广播同时判断Call状态即可获取对外通话正式接通的时刻。
    注:OFFHOLD广播会发送两个,一次是开始拨打电话(按了拨号键)状态为Call.State.DIALING,第二次是接通(建立通话),状态为Call.State.ACTIVE
   
    再进一步分析
   
    在Receiver中,你可以看到call状态的改变是在public static void onState(int state,String   caller),而这个方法的调用时是依赖UserAgent中的protected synchronized void changeStatus(int   state,String caller)
   
    Receiver的onState(int state,String caller)部分代码:
   
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    <code><code><code><code><code><code><code><code><code><code><code>public   static void onState(int state,String caller) {
                ...
     
                if (call_state != state)   {
                    if (state !=   UserAgent.UA_STATE_IDLE)
                        call_end_reason =   -1;
                    call_state =   state;
                      switch(call_state)
                    {
                    ...
                    case   UserAgent.UA_STATE_OUTGOING_CALL:
                          broadcastCallStateChanged("OFFHOOK", caller);
                          ccCall.setState(Call.State.DIALING);
                          ccConn.setUserData(null);
                          ccConn.setAddress(caller,caller);
                          ccConn.setIncoming(false);
                        ccConn.date =   System.currentTimeMillis();
                        ccCall.base =   0;
                        moveTop();
                          Checkin.checkin(true);
                        break;
                    case   UserAgent.UA_STATE_INCALL:
                          broadcastCallStateChanged("OFFHOOK", null);
                        if (ccCall.base   == 0) {
                            ccCall.base =   SystemClock.elapsedRealtime();
                        }
                        progress();
                          ccCall.setState(Call.State.ACTIVE);
                          stopRingtone();
                        if (wl != null   && wl.isHeld())
                              wl.release();
                          mContext.startActivity(createIntent(InCallScreen.class));
                        break;
                    ...
                    }
                    pos(true);
                    RtpStreamReceiver.ringback(false);
                }
              }</code></code></code></code></code></code></code></code></code></code></code>
      在UserAgent中,通话状态由变量call_state保持,而值UserAgent.UA_STATE_INCALL即值3代表通话中,具体见代码,这里不详说,其中建立会话成功是接收到报文”2xx”后被调用onCallReInviteAccepted()(实现CallListener接口)通话建立,这里就开始一系列的变化,改变UserAgent的通话状态call_state,调用Receiver.onState,改变Call.state,发送广播,更新通话界面。
   
    那么,CallListener接口是什么时候创建实现的呢?
      在对外呼出,UserAgent会创建一个ExtendedCall对象持有,UserAgent可以理解为通话的一个配置,而ExtendedCall是一个具体是通话实现,他处理报文,将接收的信息继续下发,让其它类解析。
   
    所以让我们回到起点,当我们对外拨打电话时,调用Receiver.engine(mContext).call(xxx,true);,构建一个UserAgent,又构造了ExtendedCall,又创建了InviteDialog,调用invite,最后启动
   
    ?
    1
    2
    3
    4
      <code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code>Message   invite = MessageFactory.createInviteRequest(sip_provider,
                    request_uri, to_url,   from_url,
                    contact_url,   session_descriptor, icsi);
      invite(invite);</code></code></code></code></code></code></code></code></code></code></code></code></code></code></code></code></code></code></code></code>
    向服务器请求建立通话连接,接下来就是等服务器数据的返回,报文解析,这里不详述(因为很久前抓的报文文件删了,找不到)。
   
    从上面分析,一次通话的拨出就已经很清晰了,那么我们想获取到通话正式接通那个时间点,该怎么处理?
   
    用广播,最简单,原始代码都不用改动,上面已经说了“OFFHOLD” 自定义监听器
      很明显,在你拨出界面的做监听,简单点,就是在你调用Receiver.engine(mContext).call(xxx,true);时做监听,这里没有监听方法,你可以在SipdroidEngine增加构造方法,将监听器下传到UserAgent,在UserAgent的onCallReInviteAccepted实现你的回调,如yourListener.onCallReInviteAccepted,假如你要继续下传到ExtendedCall甚至InviteDialog再回调出来也没有关系,你开心就好。
    好了,写到这也就够了,下面放构造的代码块,我没有在github上放这个库,反正有开源代码,自己clone后爱怎么改怎么改,it all on   you.
   
    SipdroidEngine 代码块:
   
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
      <code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code>public   boolean call(String target_url,boolean force,InviteListener listener) {
            int p = pref;
            boolean found = false;
     
            if (isRegistered(p)   && Receiver.isFast(p))
                found = true;
            else {
                for (p = 0; p < LINES;   p++)
                    if (isRegistered(p)   && Receiver.isFast(p)) {
                        found =   true;
                        break;
                    }
                if (!found &&   force) {
                    p = pref;
                    if   (Receiver.isFast(p))
                        found =   true;
                    else for (p = 0; p   < LINES; p++)
                        if   (Receiver.isFast(p)) {
                            found =   true;
                            break;
                        }
                }
            }
     
            if (!found || (ua = uas[p])   == null) {
                if   (PreferenceManager.getDefaultSharedPreferences(getUIContext()).getBoolean(Settings.PREF_CALLBACK,   Settings.DEFAULT_CALLBACK) &&
                          PreferenceManager.getDefaultSharedPreferences(getUIContext()).getString(Settings.PREF_POSURL,   Settings.DEFAULT_POSURL).length() > 0) {
                      Receiver.url("n="+Uri.encode(target_url));
                    return true;
                }    

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!

本文由 @白羽 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程