voice call relevant
来源:互联网 发布:nginx发布多个网站 编辑:程序博客网 时间:2024/05/21 17:46
每次收到底层上报的呼叫状态变化时(UNSOL_RESPONSE_CALL_STATE_CHANGED ),都会去查询变化了的具体内容
给modem发的信息是RIL_REQUEST_GET_CALL_LIST.handlePollCalls是用来处理查询之后的结果,分析如下:
handlePollCalls(AsyncResult ar) List polledCalls;log("****handlepollcalls....."); if (ar.exception == null) { polledCalls = (List)ar.result; } else if (isCommandExceptionRadioNotAvailable(ar.exception)) { // just a dummy empty ArrayList to cause the loop // to hang up all the calls polledCalls = new ArrayList(); } else { // Radio probably wasn't ready--try again in a bit // But don't keep polling if the channel is closed pollCallsAfterDelay(bIsVoice); return; } Connection newRinging = null; //or waiting boolean hasNonHangupStateChanged = false; // Any change besides // a dropped connection boolean needsPollDelay = false; boolean unknownConnectionAppeared = false;boolean isSeparateCallConnection = false; for (int i = 0, curDC = 0, dcSize = polledCalls.size() ; i < connections.length; i++) { GsmConnection conn = connections[i];//一个个查询gsmcalltracker里面的连接 DriverCall dc = null; // polledCall list is sparse if (curDC < dcSize) { dc = (DriverCall) polledCalls.get(curDC); if (dc.index == i+1) { curDC++; } else if(isSeparateCallConnection) { curDC++; isSeparateCallConnection = false;} else { dc = null; } } if (DBG_POLL) log("poll: conn[i=" + i + "]=" + conn+", dc=" + dc); log("****poll: conn[i=" + i + "]=" + conn+", dc=" + dc); if (conn == null && dc != null) {//进来一个新的呼叫 // Connection appeared in CLCC response that we don't know about if (pendingMO != null && pendingMO.compareTo(dc)) { if (DBG_POLL) log("poll: pendingMO=" + pendingMO); // It's our pending mobile originating call connections[i] = pendingMO; pendingMO.index = i; pendingMO.update(dc); pendingMO = null; // Someone has already asked to hangup this call if (hangupPendingMO) { hangupPendingMO = false; try { if (Phone.DEBUG_PHONE) log( "poll: hangupPendingMO, hangup conn " + i); hangup(connections[i]); } catch (CallStateException ex) { Log.e(LOG_TAG, "unexpected error on hangup"); } // Do not continue processing this poll // Wait for hangup and repoll return; } } else { connections[i] = new GsmConnection(phone.getContext(), dc, this, i); log("****setting connection"); // it's a ringing call if (connections[i].getCall() == ringingCall) {log("****new ringing connection"); newRinging = connections[i]; } else { // Something strange happened: a call appeared // which is neither a ringing call or one we created. // Either we've crashed and re-attached to an existing // call, or something else (eg, SIM) initiated the call. Log.i(LOG_TAG,"Phantom call appeared " + dc); // If it's a connected call, set the connect time so that // it's non-zero. It may not be accurate, but at least // it won't appear as a Missed Call. if (dc.state != DriverCall.State.ALERTING && dc.state != DriverCall.State.DIALING) { connections[i].connectTime = System.currentTimeMillis(); } unknownConnectionAppeared = true; } } <span style="color:#000099;"><strong>hasNonHangupStateChanged = true;</strong></span> } else if (conn != null && dc == null) {//modem呼叫断开时走这 // Connection missing in CLCC response that we were // tracking.log("****no connection let's drop");if(conn.isVoice != bIsVoice) { log("Different call came 1"); continue;} droppedDuringPoll.add(conn); // Dropped connections are removed from the CallTracker // list but kept in the GsmCall list connections[i] = null; } else if (conn != null && dc != null && !conn.compareTo(dc)) { // Connection in CLCC response does not match what // we were tracking. Assume dropped call and new calllog("****connection not matching let's drop");if(conn.isVoice != dc.isVoice) { log("Different call came 2"); curDC--; isSeparateCallConnection = true; continue;} droppedDuringPoll.add(conn); connections[i] = new GsmConnection (phone.getContext(), dc, this, i); if (connections[i].getCall() == ringingCall) { newRinging = connections[i]; } // else something strange happened hasNonHangupStateChanged = true; } else if (conn != null && dc != null) { /* implicit conn.compareTo(dc)有连接且查询到的call也存在,正常外呼走这 */ boolean changed;log("****conn dc both has value"); changed = conn.update(dc); //尝试更新连接,如果返回的值位changed,则表明查询前后call的状态有变化 hasNonHangupStateChanged = hasNonHangupStateChanged || changed;log("****hasNonHangupStateChanged = "+hasNonHangupStateChanged); } if (REPEAT_POLLING) { if (dc != null) { // FIXME with RIL, we should not need this anymore if ((dc.state == DriverCall.State.DIALING /*&& cm.getOption(cm.OPTION_POLL_DIALING)*/) || (dc.state == DriverCall.State.ALERTING /*&& cm.getOption(cm.OPTION_POLL_ALERTING)*/) || (dc.state == DriverCall.State.INCOMING /*&& cm.getOption(cm.OPTION_POLL_INCOMING)*/) || (dc.state == DriverCall.State.WAITING /*&& cm.getOption(cm.OPTION_POLL_WAITING)*/) ) { // Sometimes there's no unsolicited notification // for state transitions bIsVoice = dc.isVoice; needsPollDelay = true; } } } } // This is the first poll after an ATD. // We expect the pending call to appear in the list // If it does not, we land here if (pendingMO != null) { Log.d(LOG_TAG,"Pending MO dropped before poll fg state:" + foregroundCall.getState()); droppedDuringPoll.add(pendingMO); pendingMO = null; hangupPendingMO = false; } if (newRinging != null) {//如果是新进来的呼叫 phone.notifyNewRingingConnection(newRinging); } /* clear the "local hangup" and "missed/rejected call" cases from the "dropped during poll" list These cases need no "last call fail" reason .清除掉一些因本地挂机,以及网络拒绝的原因相关的连接 */ for (int i = droppedDuringPoll.size() - 1; i >= 0 ; i--) { //本地原因引起的挂断</span> GsmConnection conn = droppedDuringPoll.get(i); log("****welcome to drop call"); if (conn.isIncoming() && conn.getConnectTime() == 0) { // Missed or rejected call Connection.DisconnectCause cause; if (conn.cause == Connection.DisconnectCause.LOCAL) {//进来的call不接听 cause = Connection.DisconnectCause.INCOMING_REJECTED; } else { cause = Connection.DisconnectCause.INCOMING_MISSED; } if (Phone.DEBUG_PHONE) { log("missed/rejected call, conn.cause=" + conn.cause); log("setting cause to " + cause); } droppedDuringPoll.remove(i); conn.onDisconnect(cause); } else if (conn.cause == Connection.DisconnectCause.LOCAL) {//主动挂断 // Local hanguplog("****local hangup"); droppedDuringPoll.remove(i); conn.onDisconnect(Connection.DisconnectCause.LOCAL); } else if (conn.cause == Connection.DisconnectCause.INVALID_NUMBER) {//拨出的号码无效log("****invalid hangup"); droppedDuringPoll.remove(i); conn.onDisconnect(Connection.DisconnectCause.INVALID_NUMBER); } } // Any non-local disconnects: determine cause如果有非本地原因要清除的连接 if (droppedDuringPoll.size() > 0) { //bIsVoice = droppedDuringPoll.get(0).isVoice(); log("****dropping call bIsVoice = "+bIsVoice); if(bIsVoice) { cm.getLastCallFailCause(//先查找上次失败的原因 obtainNoPollCompleteMessage(EVENT_GET_LAST_CALL_FAIL_CAUSE)); } else { cm.getLastVTCallFailCause( obtainNoPollCompleteMessage(EVENT_GET_LAST_CALL_FAIL_CAUSE)); } } if (needsPollDelay) { log("****needspolldelay"); pollCallsAfterDelay(bIsVoice); } // Cases when we can no longer keep disconnected Connection's新进来的呼叫 // with their previous calls // 1) the phone has started to ring // 2) A Call/Connection object has changed state... // we may have switched or held or answered (but not hung up) if (newRinging != null || hasNonHangupStateChanged) { log("****newringing and hasnonhangupstatechanged"); internalClearDisconnected(); } updatePhoneState();//跟新gsmphone的状态 if (unknownConnectionAppeared) { log("****unknown connection appeared"); phone.notifyUnknownConnection(); } if (hasNonHangupStateChanged || newRinging != null) { log("****hasnonhangupstatechanged and newringing"); phone.notifyPreciseCallStateChanged(); } //dumpState(); }
GsmCallTracker.java里面维护了三个call对象
GsmCall ringingCall = new GsmCall(this);
// A call that is ringing or (call) waiting
GsmCall foregroundCall = new GsmCall(this);
GsmCall backgroundCall = new GsmCall(this);
call可以有如下几种状态:
IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING
的但是不是每一个call都可以拥有上面所有的状态.具体一个call对象可以拥有哪些状态可以查看parentFromDcstate函数
private
GsmCall
663
parentFromDCState (DriverCall.State state) {
664
switch
(state) {
665
case
ACTIVE:
666
case
DIALING:
667
case
ALERTING:
668
return
owner.foregroundCall;
foreground call can have ACTIVE/DIALING/ALERTING three states669
//break;
670
671
case
HOLDING:
672
return
owner.backgroundCall;
673
//break;
674
675
case
INCOMING:
676
case
WAITING:
677
return
owner.ringingCall;
678
//break;
679
680
default
:
681
throw
new
RuntimeException(
"illegal call state: "
+ state);
682
}
683
}
684
三个call对象的介绍如下:
ringingCall(用来管理处于INCOMING和WAITING状态的通话)//刚进来的电话且初始化gsmconnection 时,call的状态会变成INCOMING
foregroundCall(用来管理处于DAILING、ALERTING、ACTIVE状态的通话)
backgroundCall(用来管理HOLD的通话)。
往外打的电话可以有DAILING,ALERTING,ACTIVE 三种状态
打进来的电话可以有INCOMING,WAITING,ACTIVE 三种状态
往modem发了挂断命令时call的状态变为DISCONNECTING(正在断开)。
而手机的状态只有下面三种:IDLE, RINGING, OFFHOOK; 每一种状态的解释Android代码里直接有介绍如下:
/**
* The phone state. One of the following:<p>
* <ul>
* <li>IDLE = no phone activity</li>
* <li>RINGING = a phone call is ringing or call waiting.
* In the later case, another call is active as well 有电话在在打进来或者等待接听</li>
* <li>OFFHOOK = The phone is off hook. At least one call
* exists that is dialing, active or holding and no calls are
* ringing or waiting. 有正在打出去的电话 or 已经接通了的call or 处于hold状态的call</li>
* </ul>
*/
一个call对象里面有一个连接数组
public ArrayList<Connection> connections = new ArrayList<Connection>();
GsmCallTracker里面也有一个connections数组,to record the call list .and in GsmConnection ,it have a member type GsmCall parent.
every time poll current call, the connections arry will updata it's state .主要包括把parent在三种类型的call之间切换(根据返回的DriverCall.state来选择parent应该是ringing or foreground or background call),如果call的类型没切换,可以是变化了call 的状态.或者DriverCall.state和查询前一样,返回false
所以一个backgroundCall里面其实可以保存多个通话连接,只是暂时挂起。再比如,在开始呼叫时,gsmcalltracker会初始化一个gsmconnection
isIncoming = false; isVoice = ct.isMOVoice; createTime = System.currentTimeMillis(); this.parent = parent;//这里的parent就是call。且是foregroundCall。相反呼进来的电话是ringincall parent.attachFake(this, GsmCall.State.DIALING);//将这个connection加入到call的connection数组成员中,且将parent的状态设置为DIALING
gsmcalltracker的构造函数里有
cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
所以当ril.java每次接到底层上报的UNSOL_RESPONSE_CALL_STATE_CHANGED 时,就会给gsmcalltracker 发EVENT_CALL_STATE_CHANGE事件
这个事件的处理就是初始化查询当前的call的状态
protected void pollCallsWhenSafe() { needsPoll = true; if (checkNoOperationsPending()) { lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);//当查询完call list的状态后返回到calltracker的事件 cm.getCurrentCalls(lastRelevantPoll);//调用ril实例查询call的状态 } }
查询完后给gsmcalltracker发的事件EVENT_POLL_CALLS_RESULT,其处理就是 handlePollCalls函数。
挂断电话时分不同的call对象,如果电话已经接通了则RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND
如果是挂断正在打进来的电话则用RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND
对于MT voice call
在PhoneBase.java文件里有
mCM.setOnCallRing(this, EVENT_CALL_RING, null);
当ril接到UNSOL_CALL_RING 时,就会报告EVENT_CALL_RING这个事件给GsmPhone 。其处理为notifyIncomingRing
private void notifyIncomingRing() { if (!mIsVoiceCapable) return; AsyncResult ar = new AsyncResult(null, this, null); mIncomingRingRegistrants.notifyRegistrants(ar);//通知注册过次事件的模块 }
在CallManager.java里有
phone.registerForIncomingRing(mHandler, EVENT_INCOMING_RING, null);
在callmanager里的处理也是通知注册次事件的模块
case EVENT_INCOMING_RING: if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_INCOMING_RING)"); // The event may come from RIL who's not aware of an ongoing fg call if (!hasActiveFgCall()) { mIncomingRingRegistrants.notifyRegistrants((AsyncResult) msg.obj); }
InCallScreen.java里有
mCM.registerForIncomingRing(mHandler, PHONE_INCOMING_RING, null);mCM是CallManager的实例
上层如果接听了,则会调用gsmphone里的acceptCall-->gamcalltracker.acceptCall函数来发RIL_REQUEST_ANSWER给modem
- voice call relevant
- qcril voice call flow
- Basic Call Processing (Voice) - GSM
- Single Radio Voice Call Continuity (SRVCC)
- Voice Over IP - Per Call Bandwidth Consumption
- [FAQ14410][SIM]Data/voice call/SMS默认卡设定客制化
- [RK3288][Android6.0] 调试笔记 --- Audio的Voice Call无法静音问题
- SharpNl relevant
- 【LTE基础】SRVCC(Single Radio Voice Call Continuity 双模单待无线语音呼叫连续性)技术研究背景
- Mobile Voice
- google voice
- Voice VLAN
- ios voice
- Voice study
- Voice mail
- Google Voice、Voice Search 安装
- Google Voice、Voice Search 安装
- ctags for lua relevant
- iOS—— NSFileManager ——管理文件和目录
- 银行版余额宝进退两难
- Java List Map 初始 赋值例子
- 使用ViewSwitcher模拟手机屏幕应用分屏和切换
- WINCE--编译环境一二三(转摘)
- voice call relevant
- Python 之ConfigParser
- C语言总结第1篇:堆和栈的区别
- makefile 和shell文件相互调用
- static全局变量与普通的全局变量的区别/static局部变量和普通局部变量的区别/static函数与普通函数的区别
- VS创建非模态窗口
- lua 部分结构
- mysql字段修改
- 趣文:假如编程语言在一起聚餐