本文主要講解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());
接着再通過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
————————————————
版權聲明:本文為CSDN博主「linyongan」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/linyongan/article/details/53350493
