Android 6.0 Phone 多方通话流程

写在前面的话

本文主要分析Voice Call多方通话的流程,分析GSM和CDMA在多方通话不同的地方,研究的代码是Android 6.0的,目前只关注framework层。


1. 多方通话的概念

下面引用来自《百度百科》的一段文字:

多方通话的发起流程是:主席方用户A先呼叫参与方用户B,B用户接通呼叫,形成一个典型的两人通话的基本呼叫场景,此后A用户通过终端菜单发起保持B用户呼叫的请求,此时B用户会听到一段背景音乐,并且与A用户的通话暂时断开,主席方A用户紧接着呼叫另一个参与方C用户,在与C用户建立了一个基本通话之后,由A用户发起建立多方通话的业务请求,此时B用户听到的背景音乐将会取消,A、B、C三方加入到一个多方通话中来,他们每个人都可以听到其他两人的话音。其他的四方通话、五方通话的建立过程与此类似。

在明确了多方通话的概念之后,下面我们就来分析多方通话的整个过程吧


本文来自本文来自http://blog.csdn.net/linyongan ,转载请务必注明出处。,转载请务必注明出处。


2. 多方通话的流程(GSM)

如果图片看不清的话,可以右键选择在新标签中打开图片


多方通话主要分成四个部分:

  1. A呼叫B,B接电话,A与B开始通话。
  2. A再呼叫C,A与B的通话变成HOLDING,C接电话。
  3. 点击“合并”按钮,建立多方通话。
  4. 挂断电话。

2.1 A呼叫B,B接通电话

拨打电话的流程,在Android 5.1 Phone MO(去电)流程分析(应用层) 和《 Android 5.1 Phone MO(去电)流程分析(Framework层) 》 里已经详细介绍过了,如果还没有看过这两篇文章的童鞋,建议先看看这两篇文章啦。


2.2 A呼叫C,并且Hold住B

2.2小节又可以细分成三部分:

  1. 用户输入C的号码,点击拨号按钮,流程从应用层一直走到Framework层(即来到GsmCallTracker.java的dial()方法里,步骤2~5)。
  2. 将A与B的通话switch成HOLDING状态。
  3. 调用RIL.java的dial()方法发起RIL_REQUEST_DIAL请求(步骤12~15)。

其中第一部分和第三部分跟上面说的MO(去电)流程是一样的,所以这里重点讲解第二部分(步骤6~11) 
在GsmCallTracker.java的dial()方法里

/* The new call must be assigned to the foreground call.That call must be idle, so place anything that'sthere on hold */
if (mForegroundCall.getState() == GsmCall.State.ACTIVE) {/* this will probably be done by the radio anywaybut the dial might fail before this happensand we need to make sure the foreground call is clearfor the newly dialed connection */switchWaitingOrHoldingAndActive();/* This is a hack to delay DIAL so that it is sent out to RIL only afterEVENT_SWITCH_RESULT is received. We've seen failures when adding a new call tomulti-way conference calls due to DIAL being sent out before SWITCH is processed */try {Thread.sleep(500);} catch (InterruptedException e) {// do nothing}/* Fake local state so thata) foregroundCall is empty for the newly dialed connectionb) hasNonHangupStateChanged remains false in thenext poll, so that we don't clear a failed dialing call */fakeHoldForegroundBeforeDial();
}

上面的代码做了两件事: 
1.当发现ForegroundCall正处于ACTIVE状态,用户又要发起DIAL请求,则调用switchWaitingOrHoldingAndActive()方法把当前的ForegroundCall变成Holding状态。 
2.并且让线程休眠500毫秒,目的是延迟DIAL请求的下发,等待RIL上报REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE(但是,即便延迟了500毫秒,但是并不能确保在RIL上报REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE之后才下发DIAL请求)

其实第三部分(步骤12~15)还有些值得注意的地方,就是Call的状态变化。ID为1的Call一直都处于HOLDING状态,而ID为2的Call就从DIALING—->ALERTING—->ACTIVE变化。等待A与C的通话建立,就变成id=1,HOLDING;id=2,ACTIVE状态(步骤15),此时Foreground Call是A与C,Background Call就是A与B,此时B是听不到A与C对话的。


2.3 建立多方通话merge as a conference call

用户点击建立多方通话的按钮之后,流程一直走,从应用层走到PhoneUtils.java的mergeCalls()方法里

    static void mergeCalls(CallManager cm) {int phoneType = cm.getFgPhone().getPhoneType();if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {省略...} else {try {log("mergeCalls(): calling cm.conference()...");cm.conference(cm.getFirstActiveBgCall());} catch (CallStateException ex) {Log.w(LOG_TAG, "mergeCalls: caught " + ex, ex);}}}

在这里会对Phone的类型做判断,这里分析的是GSM多方通话流程,所以走进else语句,依次调CallManager.java—->GSMPhone.java—->GsmCallTracker.java的conference()方法(步骤16~19),最后调用RIL.java的conference()方法向RILC发送RIL_REQUEST_CONFERENCE请求建立多方通话(步骤20)。

2.4 挂断电话

对于GSM的话,多方通话中的电话是可以一通一通地挂断的;而CDMA的话,点击挂断按钮,就把所有电话都挂断。


3. 多方通话的流程(CDMA)

如果图片看不清的话,可以右键选择在新标签中打开图片


3.1 A呼叫B,B接通电话

同2.1节。


3.2 A呼叫C,并且Hold住B

拨号流程从应用层走到framework层, 
在CdmaCallTracker.javaCdmaCallTracker.java的dial 方法里的流程就有点不一样了(步骤5

Connection dial (String dialString, int clirMode) throws CallStateException { ...// The new call must be assigned to the foreground call.// That call must be idle, so place anything that's// there on holdif (mForegroundCall.getState() == CdmaCall.State.ACTIVE) {return dialThreeWay(dialString);}...
}private Connection dialThreeWay (String dialString) {if (!mForegroundCall.isIdle()) {// Check data calldisableDataCallInEmergencyCall(dialString);// Attach the new connection to foregroundCallmPendingMO = new CdmaConnection(mPhone,checkForTestEmergencyNumber(dialString), this, mForegroundCall);// Some network need a empty flash before sending the normal onem3WayCallFlashDelay = mPhone.getContext().getResources().getInteger(com.android.internal.R.integer.config_cdma_3waycall_flash_delay);if (m3WayCallFlashDelay > 0) {mCi.sendCDMAFeatureCode("", obtainMessage(EVENT_THREE_WAY_DIAL_BLANK_FLASH));} else {mCi.sendCDMAFeatureCode(mPendingMO.getAddress(),obtainMessage(EVENT_THREE_WAY_DIAL_L2_RESULT_CDMA));}return null;
}

如果发现当前ForegroundCall的状态是ACTIVE,则进入dialThreeWay()方法里,然后调用RIL.java的sendCDMAFeatureCode()方法发出RIL_REQUEST_CDMA_FLASH请求(注意,这次拨号并没有发出RIL_REQUEST_DIAL请求,也没有switch A与B那通电话的状态)


3.3 merge call

建立多方通话,从PhoneUtils.java的mergeCallsmergeCalls方法开始

static void mergeCalls(CallManager cm) {int phoneType = cm.getFgPhone().getPhoneType();if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {log("mergeCalls(): CDMA...");PhoneGlobals app = PhoneGlobals.getInstance();if (app.cdmaPhoneCallState.getCurrentCallState()== CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {// Set the Phone Call State to conferenceapp.cdmaPhoneCallState.setCurrentCallState(CdmaPhoneCallState.PhoneCallState.CONF_CALL);// Send flash cmd// TODO: Need to change the call from switchHoldingAndActive to// something meaningful as we are not actually trying to swap calls but// instead are merging two calls by sending a Flash command.log("- sending flash...");switchHoldingAndActive(cm.getFirstActiveBgCall());}}else {try {log("mergeCalls(): calling cm.conference()...");cm.conference(cm.getFirstActiveBgCall());} catch (CallStateException ex) {Log.w(LOG_TAG, "mergeCalls: caught " + ex, ex);}}}

依次调PhoneUtils.java—->CallManager.java—->CDMAPhone.java的switchHoldingAndActive()方法(步骤14~16)。 
接着调CdmaCallTracker.java的switchWaitingOrHoldingAndActive()方法(步骤17

void switchWaitingOrHoldingAndActive() throws CallStateException {// Should we bother with this check?if (mRingingCall.getState() == CdmaCall.State.INCOMING) {throw new CallStateException("cannot be in the incoming state");} else if (mForegroundCall.getConnections().size() > 1) {flashAndSetGenericTrue();} else {// Send a flash command to CDMA network for putting the other party on hold.// For CDMA networks which do not support this the user would just hear a beep// from the network. For CDMA networks which do support it will put the other// party on hold.mCi.sendCDMAFeatureCode("", obtainMessage(EVENT_SWITCH_RESULT));}
}

最后还是调用RIL.java的sendCDMAFeatureCode()方法发出RIL_REQUEST_CDMA_FLASH请求(步骤20)。(最后把两通电话合并成一通电话?这个问题还需继续深究。根据挂断电话时一次性把所有通话都挂断,可推测只有一通电话)


3.4 挂断电话

对于CDMA的话,与GSM不同。点击挂断按钮,就把所有电话都挂断。


4 扩展的问题

假如多方通话已建立,那么这时候再拨打紧急电话会怎样?紧急电话能拨通吗? 
PS:GSM网络下,iphone5S是把多方通话挂断,然后再拨紧急电话;安卓如果想实现这样的效果,还需自己修改代码。

智能电话会议系统(11)---Android 6.0 Phone 多方通话流程相关推荐

  1. Android 6.0 Phone 多方通话流程

    写在前面的话 本文主要分析Voice Call多方通话的流程,分析GSM和CDMA在多方通话不同的地方,研究的代码是Android 6.0的,目前只关注framework层. 1. 多方通话的概念 下 ...

  2. 基于感应器的智能求救系统----以android为例实现

    基于感应器的智能求救系统----以android为例实现   基于感应器的智能求救系统是由android实验小组研发的一款基于android手机系统以及汽车硬件的能够通过感应外界温度.压力.初速度就可 ...

  3. Android 9.0 SIM卡初始化流程

    转载:https://blog.csdn.net/linyongan/article/details/51406123 本文主要讲述Android 9.0 SIM卡初始化流程,这个过程也涉及到UICC ...

  4. Android 最新 ios 11,差异性越来越小!iOS 11/Android 8.0最新系统对比

    北京时间9月13日凌晨1点,苹果在他的新飞船总部举办新品发布会.会上除了发布了一系列的智能设备外,更是发布了iOS 11操作系统的正式版本.iOS 11版本在今年6月份的苹果开发者大会正式亮相,但是之 ...

  5. 联想K系引领智能电视潮流,Android 4.0将成行业标配

    现在,随着智能电视的普及,电视机正从平板时代向互联网时代甚至向目前的智能时代跨越,电视正在成为家庭的智能娱乐终端.笔者上周撰写的<联想完成PC+战略布局,K系智能电视打响"家庭争夺战& ...

  6. android 7.0电视,将智能电视升级到Android 7.0有什么经验?为索尼用户祝福

    尽管Android 7.0系统很早以前就已正式发布,但实际上,由于Android设备的严重碎片化,并不是所有的Android设备都可以在第一时间进行升级,因此,实际上现在已经安装了Android 7. ...

  7. android 4.0系统,全新Android 4.0系统_手机Android频道-中关村在线

    与搭载Android 2.3系统的OPPO R807不同,OPPO R817搭载了Android 4.0系统.不过这款手机仍旧舍弃了Android系统的原生界面,因此两款手机在界面上的变化其实并不非常 ...

  8. Android 系统(11)---android 系统权限大全

    收集到的android权限都很实用的(permission)大全 1.android.permission.WRITE_USER_DICTIONARY 允许应用程序向用户词典中写入新词 2.andro ...

  9. android改变系统语言,Android 9.0设置系统语言

    1.系统权限 android:sharedUserId="android.uid.system" 2.签名 通过手动签名的方式,用系统的签名文件为程序签名解决签名的问题,将程序加入 ...

最新文章

  1. SqlSessionFactoryBean的构建流程
  2. 什麽样的资料集不适合用深度学习?
  3. 《FusionCharts学习及使用笔记》之 第一篇
  4. “拼图”化解智慧城市“碎片化”难题
  5. kdj指标主要看哪个值_终于有人把KDJ指标总结全了,值得收藏
  6. 激光雷达的KPI与技术方案
  7. 计算机基础与C语言程序设计书籍,C语言程序设计(21世纪高等学校计算机基础实用规划教材)...
  8. Selenium TestNG Java环境搭建过程中所遇问题汇总
  9. 基于C#的学生选课管理系统
  10. 为啥外包喜欢php,为什么要面向对象?
  11. 13.SpringBoot学习(十三)——JDBC之 Spring Boot Jpa多数据源
  12. EtherCAT从站协议栈代码笔记之ecat_def.h
  13. 一叶知秋:“安全“的野指针、 static函数、成员函数、this 指针、gcc编译器、name mangling...
  14. 数字健康-共建共享 火绒安全将亮相2021中华医院信息网络大会(CHINC)
  15. 【JHOK-ZBZ201型智能型剩余电流继电器】
  16. 【2016年第4期】基于仿真大数据的效能评估指标体系构建方法
  17. Unity-URP 实现遮挡高亮
  18. 批量删除 txt 记事本文本文件中的某一行或一些行
  19. 无人驾驶1——自动驾驶硬件、软件概述
  20. WPS中设置参考文献自动插入和更新

热门文章

  1. 概念理解:外包、众包
  2. python扫雷游戏代码_python实现扫雷游戏的示例
  3. 微信公众号正文如何插入附件
  4. 动态图片怎么压缩?如何在线压缩gif动图大小?
  5. “好奇号”顺利完成”火星第一勺“
  6. 怎样屏蔽微信朋友圈视频?局域网如何禁止员工看朋友圈视频?
  7. 分开搭建DNS和AD的方法(一)
  8. C++中char和int的相互转换
  9. dymola学习笔记第二天——求解非线性方程
  10. 小孩刚烫伤之后留下的疤痕一般多久开始增生