写在前面的话

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


1. 多方通话的概念

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

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

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


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


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.java \color{red}{CdmaCallTracker.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的 mergeCalls \color{red}{mergeCalls}方法开始

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是把多方通话挂断,然后再拨紧急电话;安卓如果想实现这样的效果,还需自己修改代码。

Android 6.0 Phone 多方通话流程相关推荐

  1. 智能电话会议系统(11)---Android 6.0 Phone 多方通话流程

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

  2. Phone 多方通话流程(GSM CDMA)

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

  3. Android 9.0 SIM卡初始化流程

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

  4. Android 9.0 开关机动画流程分析

    Android开机动画流程的启动主要是在Surfaseflinger里面完成的,具体代码如下: /frameworks/native/services/surfaceflinger/StartProp ...

  5. Android 11.0 ActivityManagerService的启动流程

    首先推荐一篇文章,ActivityManagerService-AMS启动流程-[Android取经之路].这篇文章是以Android 10.0源码为基础分析的,写的很详细也很棒,我学习AMS的启动就 ...

  6. 深入分析Android 9.0源代码——Activity启动流程

    引言 点击此处查看<深入分析Android 9.0源代码>系列的组织结构和相关说明. 1 应用进程发起启动请求 本章的调用流程如下图所示: (Context) Activity Instr ...

  7. 深入分析Android 9.0源代码——Service启动流程(startService方式)

    引言 点击此处查看<深入分析Android 9.0源代码>系列的组织结构和相关说明. 1 应用进程发起启动请求 本章的调用流程如下图所示: (Context)ContextWrapperC ...

  8. Android 7.0 挂断电话流程分析

    1.图形显示 挂断电话分为本地挂断和远程对方挂断 2.本地挂断 1).点击按钮 先看按键的监听事件 CallCardFragment.java 中有对按钮的监听事件 @Overridepublic v ...

  9. Android 7.0 APN 拨号上网流程分析

    1.前言 在前段时间的项目中遇到客户的设备出现APN断开的情况没有自动连接,后来折腾了一段时间解决了这个问题.现在用这篇博客记录一下APN的选择和连接流程. 2.名词解析 APN:APN指一种网络接入 ...

最新文章

  1. c语言文本按行分配数组元素,【转】C语言中动态分配数组
  2. 洛谷P4630 [APIO2018] Duathlon 铁人两项 【圆方树】
  3. 【算法竞赛学习】资金流入流出预测-挑战Baseline_特征工程
  4. React开发(209):react错误边界
  5. Django学习目录
  6. MATLAB工具箱下载地址
  7. java集合类中的迭代器
  8. 2021永州高中高考成绩查询入口,邵阳高考成绩查询入口2021
  9. Ros简单程序编写及使用类Hello World
  10. 利用WPS功能破解及本地恢复密码
  11. LeetCode的使用方法
  12. Kmeans参数n_clusters_labels_centers_
  13. 2021-11-27 2021年施工员-装饰方向-岗位技能(施工员)考试题及施工员-装饰方向-岗位技能(施工员)考试题库
  14. 小说作者推荐:忘却的悠合集
  15. 【推荐】《Java 并发编程的艺术》迷你书
  16. 支付宝五福java_2021年集支付宝五福攻略 一个账号一天最少扫到10张+ 扫一轮下来 基本要啥福有啥福!...
  17. 趋肤效应实验报告_无线电能传输(课程设计)实验报告
  18. 甘书计算机,甘文生,暨南大学
  19. fishnet:论文阅读与代码理解
  20. java.net.malf,得到java异常:java.net.MalformedURLException:没有协议

热门文章

  1. 2021-06-08STC15F2K602S串口2驱动代码
  2. MySQL中删除数据库的基本语法格式为_《MySQL数据库》SQL简介、语法格式
  3. 800套绝美PPT模板免费下载
  4. 通过PS制作一个苹果样式的“牛仔裤”
  5. 《麦肯锡方法》读书笔记1
  6. 水面反光如何拍摄_拍摄水景的技巧方法
  7. 骁龙778gplus什么水平 骁龙778gplus什么级别 骁龙778gplus相当于什么档次
  8. 【NOIP】【codevs】【DP】1169传纸条
  9. 跟小静读CLR via C#(18)——Enum
  10. 谷歌浏览器如何查看及设置网页编码格式(亲测可用)