1. 程式人生 > >Android 7.0 IMS框架詳解

Android 7.0 IMS框架詳解

本文主要講解IP Multimedia Subsystem (IMS)在Android 7.0上由谷歌Android實現的部分內容。 
從APP側一直到Telephony Framework,是不區分CS流程還是PS流程的。到了Telephony Framework模組,會依據IMS相關的狀態資訊(Registration Status,Service Status等)和使用者設定資訊(Volte Enable?Wifi Calling Enable?UT Enable?等 )進而判斷出,Call、SMS等是否需要優先走IMS的流程。 
整體來看,IMS框架如下圖: 

通常都是由Phone物件或者ImsPhoneCallTracker物件直接得到ImsManager物件

mImsManager = ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId());
1
接著再通過ImsManager物件間接地得到ImsConfig、ImsUt、ImsCall等重要物件,然後根據請求不同而走不同的通道與Vendor RIL通訊,與Call相關的走ImsCall,與補充業務相關的走ImsUt,與IMS功能的能力、引數相關的走ImsConfig,所以分工是十分明確的。谷歌為了規範高通/MTK等晶片廠商的行為,所以定義了IImsService、IImsConfig、IImsCallSession和IImsUt等介面,再由各晶片廠商來實現這些介面,谷歌只需要處理好上層呼叫介面的邏輯即可。

接下來分別講一下各個類

ImsPhone
ImsPhone是為了與CS Call區分開,用來處理IMS相關事務的Phone例項,以setCallWaiting為例:

    public void setCallWaiting(boolean enable, Message onComplete) {
        if (isPhoneTypeGsm()) {
            Phone imsPhone = mImsPhone;
            //判斷是否符合IMS的條件
            if ((imsPhone != null)
                    && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
                    || imsPhone.isUtEnabled())) {
                //走IMS流程
                imsPhone.setCallWaiting(enable, onComplete);
                return;
            }
            //走CS流程
            mCi.setCallWaiting(enable, CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
        } else {
            loge("method setCallWaiting is NOT supported in CDMA!");
        }
    }
然而僅僅有Phone例項是不夠的,還需要有對應地CallTracker、Call以及Connection物件,所以就有了下面這張圖: 

ImsPhone例項是在IMS Service啟動之後被建立的,接著會初始化ImsPhoneCallTracker物件。

ImsPhoneCallTracker
ImsPhoneCallTracker在初始化的時候會註冊監聽IMS InComing call

intentfilter.addAction(ImsManager.ACTION_IMS_INCOMING_CALL);

同時將Action為“ACTION_IMS_INCOMING_CALL”的PendingIntent傳遞給IMS Service,這樣子就可以監聽到IMS MT Call了。

ImsPhoneCallTracker內部會初始化四個ImsPhoneCall物件,

    public ImsPhoneCall mRingingCall = new ImsPhoneCall(this, ImsPhoneCall.CONTEXT_RINGING);
    public ImsPhoneCall mForegroundCall = new ImsPhoneCall(this,
            ImsPhoneCall.CONTEXT_FOREGROUND);
    public ImsPhoneCall mBackgroundCall = new ImsPhoneCall(this,
            ImsPhoneCall.CONTEXT_BACKGROUND);
    public ImsPhoneCall mHandoverCall = new ImsPhoneCall(this, ImsPhoneCall.CONTEXT_HANDOVER);

比GsmCdmaCallTracker多了一個Handover Call,比如VoWiFi與VoLTE相互切換就是通過Handover來實現的。

還有一點ImsPhoneCallTracker與GsmCdmaCallTracker不一樣的就是

    protected void handlePollCalls(AsyncResult ar) {
    }

ImsPhoneCallTracker的handlePollCalls()方法是空的,是因為IMS Call狀態訊息的上報和獲取modem當前Call List資訊等這些邏輯需要高通/MTK來實現,ImsPhoneCallTracker則通過ImsCall.Listener來監聽Ims Call的狀態變化資訊,然後再根據ImsCall的狀態,更新當前ImsPhoneConnection與四種ImsPhoneCall的繫結關係。 
比如: 
1. A<—>B正在通話,這通電話對應的Connection會與mForegroundCall繫結; 
2. 此時A再呼叫C,那麼A<—>B這通電話的Connection就會先與mBackgroundCall繫結,這種切換是由mBackgroundCall與mForegroundCall互換Connection集合和狀態實現的;

mForegroundCall.switchWith(mBackgroundCall);

3.然後A<—>C接通之後,A<—>C這通電話對應的Connection會與mForegroundCall繫結。 
就是這樣子。每個ImsPhoneCall最多繫結5個ImsPhoneConnection,這個值規定在ImsPhoneCallTracker中:

static final int MAX_CONNECTIONS_PER_CALL = 5;
ImsPhoneCallTracker還負責監聽IMS service的狀態變化

private ImsConnectionStateListener mImsConnectionStateListener =
        new ImsConnectionStateListener() {
        //IMS已註冊上
        public void onImsConnected() {}
        //IMS已斷開,有時候會上報斷開的原因
        public void onImsDisconnected(ImsReasonInfo imsReasonInfo) {}
        //IMS處於正在註冊狀態
        public void onImsProgressing() {}
        //"VoLTE", "ViLTE", "VoWiFi", "ViWiFi",
        //"UTLTE", "UTWiFi"等功能的能力變化
        public void onFeatureCapabilityChanged() {}
        ......
}

如果遇到IMS註冊不上的問題,應該去看IMS註冊時的SIP信令流程。 

ImsManager
ImsManager作為IMS框架的核心,是任意IMS action的出發點。ImsManager的職責主要有以下3點: 
1. 向上提供ImsConfig、ImsUt、ImsCall等重要物件,得到這些物件就可以跟Vendor RIL通訊了。

 public ImsUtInterface getSupplementaryServiceConfiguration(){}
 public ImsConfig getConfigInterface(){}
 public ImsCall makeCall(){}
2 .向APP提供設定IMS相關功能的介面

//設定VoLTE開啟或者關閉
public static void setVtSetting(Context context, boolean enabled) {}
//設定WiFi Calling開啟或者關閉
public static void setWfcSetting(Context context, boolean enabled) {}
//設定WiFi Calling的模式,如WiFi Only、WiFi優先...
public static void setWfcMode(Context context, int wfcMode) {}
//設定4G LTE增強模式開啟或者關閉
public static void setEnhanced4gLteModeSetting(Context context, boolean enabled) {}

3.向上傳遞IMS註冊狀態變化的訊息,是由ImsManager來通知ImsPhoneCallTracker的。

ImsService
谷歌定義好了ImsServiceBase抽象類和IImsService介面,接著由晶片廠商實現ImsService。 
ImsConfig、ImsUt、ImsCall等物件最終是依靠ImsService來建立的, 
由此可見,其他三種通訊方式都是依賴著ImsService的。

ImsManager—>ImsService—>Vendor RIL 
這種通訊方式主要用來通知modem turn on/off Ims。 
使用場景就是在VoLTE、WFC和Advanced4GMode等功能被使用者手動enable/disable時,就要響應地通知modem turn on/off Ims了。

ImsConfig
ImsManager—>ImsConfig—>Vendor RIL 
ImsConfig主要就是提供介面給上層動態地去控制IMS功能的能力、引數等。 
ImsConfig類中雖然只有7個方法,但是功能強大,特別是下面幾個方法

public int getProvisionedValue();
public int setProvisionedValue();
public String getProvisionedStringValue();
public int setProvisionedStringValue();

這些方法為開發者打開了一扇大門!通向底層NV的大門!(不同晶片廠商可能有差異)比如,在UI介面上點選了開啟WFC的按鈕,就可以間接地修改到NV的某一項。 
目前Android 7.0中支援的NV只有幾十個,但是這並不能滿足OEM所有的需求,所以有時候還需擴充套件這個介面。

還有就是,如果要開發IMS介面的話,建議也是加在這裡,其他通道都不太合適。

ImsCall
ImsManager—>ImsCall—>ImsCallSession—>Vendor RIL 
這個就很明顯了,這條通道是專門處理IMS Call相關事務的,建立ImsCall的方式有兩種: 
1. IMS MO Call時,通過ImsManager.makeCall()來建立; 
2. IMS MT Call時,通過ImsManager.takeCall()來建立。 
在ImsCall中,每個對Call操作的方法(accept/reject/hold/resume/merge等等)都會有對應的回撥方法:

    /**
     * @see Listener#onCallResumed, Listener#onCallResumeFailed
     */
    public void resume(){
        ......
    }
如果resume成功則通過onCallResumed()方法通知上層,如果resume失敗則通過onCallResumeFailed()方法通知上層,一般的流程如下:

ImsUt
ImsManager—>ImsUt—>Vendor RIL 
這條通道是專門提供向上提供設定補充業務介面的,如來電轉駁、呼叫限制、呼叫等待、outgoing Caller Id display等等。

最後,更多關於IMS的內容,請查閱如下協議文件: 
- GSMA IR.92 : features for voice and sms profile 
- GSMA IR.94 : video calling feature 
- 3GPP TS 24.229 : IMS call control (SIP and SDP) 
- 3GPP TS 26.114 : IMS media handling and interaction 
- 3GPP TS 26.111 : Codec for CS multimedia telephony service (H.324) 
- 3GPP TS 24.623 : XCAP over the Ut interface for manipulating supplementary services