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

最新文章

  1. SQL server 语句新建用户、对用户授权、删除用户实例
  2. 匈牙利 算法&amp;模板
  3. JavaScript编码规范[百度]
  4. 菜鸟-手把手教你把Acegi应用到实际项目中(8)-扩展UserDetailsService接口
  5. Stretch a row if data overflows in jasper reports
  6. HNOI2008 and ZJOI2006 排名系统
  7. HDOJ/HDU 1087 Super Jumping! Jumping! Jumping!(经典DP~)
  8. Scala减少代码重复
  9. 如何给网站添加CNZZ站长统计功能代码的常用办法
  10. Oracle database
  11. java程序的内存分配(一)
  12. [Swift]LeetCode257. 二叉树的所有路径 | Binary Tree Paths
  13. ubuntu16.04连接wifi
  14. django rest framework(4)
  15. mass create DN
  16. 使用YII框架的migrate迁移数据库
  17. ubuntu 里切换 gcc,g++ 的版本
  18. Java中List与数组互相转化
  19. 微软BI 之SSAS 系列 - 多维数据集中度量值设计时的聚合函数 (累加性_半累加性和非累加性)
  20. solr开发,提交索引数据的几种方式

热门文章

  1. AcWing 138. 兔子与兔子 hash打卡
  2. go语言中使用正则表达式
  3. HTML标签类总结
  4. js设计模式——1.代理模式
  5. sublime text3配置c++环境和一些插件
  6. php开发面试题---Mysql常用命令行大全
  7. MySql在建立索引优化时需要注意的问题
  8. 1251 client does not support
  9. npm cnpm node yarn
  10. Linux内核代码布局