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