本文主要讲解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