admin管理员组文章数量:1664358
Conference Call在项目中的场景不是很多,在日常生活应用也不是很多,基本上项目上的需求原生的代码已经足够。我所接触的只是之前在一个STK 运营商项目上时,对Conference call 有很多UI & 功能的要求,所以趁此也做一个总结,本篇主要是对于IMS的情况做个总结。
1.Conference call 基本介绍
Conference call 就是常说的电话会议,简单的说就是多台设备同时参与某一路通话(假设为A,B,C三台设备),不是常见的两方对话。详细的解释可以查看:https://en.wikipedia/wiki/Conference_call. 在多方的参与者中,有一方作为host(A),它是这通呼叫的发起方,可以manager这路conference call(与运营商相关). 其他的参与者(B,C)则叫peercall,这两个参与者没有操作这路conference call的能力。
Conference call 业务是依赖与运营商的,有些运营商是不支持conference call的,在国内暂时只有CMCC支持conference call。发起Conference call有两种方式:1.将两通call merge成conference。这种方式是最为常见的,A拨打一通电话给B,等B接通后,A再拨打一通电话给C,C再接通后,A就可以将这两通电话merge成一通。2.直接拨打conference。这种方式比较少见,应该是只有在ims的情况下才支持(此处不是很确定,在非IMS的情况下我没有见过能够直接拨打conference。A直接输入B&C的号码直接发起conference call.
在非IMS Conference call 最多包含6个参与者(包括host),当增加到6方通话后,则不允许继续添加参与者了,但是IMS conference 就没有限制。在GSM情况下,几个参与者组成了一通conference call,host 可以管理这路电话,可以将某个参与者踢出(split)这通conference call. 但是在CDMA情况下,host就没有这个能力了。在注册了IMS的情况下,拨打了一个conference call后(A,B,C),会创建一个conference room,然后A,B,C会依次加入这个conferece room中。在A,B,C均加入这个conference room后,及时非host主动挂断电话(C挂断,AB仍然在通过中),此时AB的通话仍然是conference call.
Conference call成功后,peer call端(B,C)会在InCallUI上显示host(A)的号码,但是在A端只会显示"Conference call"而不会显示B&C的号码。如果有些运营商有特殊要求(SKT),则可以通过解析sip消息来获取B&C的号码。
2.Conference call 命令下发
对于conference call,常见的发起方式就是第一种:将两通call merge成conference。下面主要也是解释该流程。Conference call 发起主要可以看作两步:发起两通call & merge两通call.
发起两通call
发起两通call的流程,没有特殊的流程,不管是MO或是MT都是可以的。只要A有两通电话就可以了。我本地的做的测试时发起的两通MOcall。这步没有什么特殊的地方,主要的log逻辑如下:
对于A来说现在已经有了两通MO call了,其中一通call为holding,另外一通为active.
merge两通call
如果A手机的simcard开通了conference call的业务,那么在InCallUI上就会有merge的button.点击这个merge button,就可以将这两通单独的call merge成conference。
点击mergebutton,CallButtonPresenter.java# mergeClicked会相应该click事件。
packages/apps/Dialer/java/com/android/incallui/CallButtonPresenter.java
@Override
public void mergeClicked() {
Logger.get(context)
.logCallImpression(
DialerImpression.Type.IN_CALL_MERGE_BUTTON_PRESSED,
call.getUniqueCallId(),
call.getTimeAddedMs());
TelecomAdapter.getInstance().merge(call.getId());
}
*************************************************************************************
packages/apps/Dialer/java/com/android/incallui/call/TelecomAdapter.java
public void merge(String callId) {
android.telecom.Call call = getTelecomCallById(callId);
if (call != null) {
List<android.telecom.Call> conferenceable = call.getConferenceableCalls();
/**
* Returns the list of {@code Call}s with which this {@code Call} is allowed to
* conference.
* @ conferenceable.isEmpty The list of conferenceable {@code Call}s.
*/
if (!conferenceable.isEmpty()) {
// conferenceable.get(0) --> 被merge的那通call
call.conference(conferenceable.get(0));
// It's safe to clear restrict count for merge action.
DialerCall.clearRestrictedCount();
} else {
if (call.getDetails().can(android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE)) {
call.mergeConference();
// It's safe to clear restrict count for merge action.
DialerCall.clearRestrictedCount();
}
}
} else {
LogUtil.e("TelecomAdapter.merge", "call not in call list " + callId);
}
此处要注意的是在执行mergeClicked时,往外传递了一个参数call.getId(),这个Call是当前active 的DialerCall对象。然后在TelecomAdapter通过这个CallId来获取android.telecom.Call对象,并进行merge操作。后续的操作比较简单,没有特别的地方与dial方法类似类似,通过IInCallAdapter来操作Call对象.大概的传递如下:
Call.java # conference --> InCallAdapter.java # conference
--> InCallAdapter.java # conference --> CallsManager.java # conference --> Call.java # conferenceWith
从代码可以到,当执行到这里时,两通需要merge的call已经确定下来。
http://androidxref/9.0.0_r3/xref/packages/services/Telecomm/src/com/android/server/telecom/Call.java
void conferenceWith(Call otherCall) {
if (mConnectionService == null) {
Log.w(this, "conference requested on a call without a connection service.");
} else {
Log.addEvent(this, LogUtils.Events.CONFERENCE_WITH, otherCall);
mConnectionService.conference(this, otherCall);
}
}
后续的调用逻辑没有太复杂也没有写特别需要注意的地方,与MO call类似,大概的调用逻辑如下:
ConnectionServiceWrapper.java # conference --> ConnectionServiceWrapper.java # conference
--> ConnectionService.java # conference # MSG_CONFERENCE # conference # onConference
--> TelephonyConnectionService.java # onConference # performConference
--> TelephonyConnection.java # performConference
--> IMSphone.java # conference()
--> ImsPhoneCallTracker.java # conference
--> ImsCall.java # merge
--> ImsCallSession.java # merge()
--> ImsCallSessionImpl.java # merge
--> ImsServiceClassTracker.java # sendConferenceRequest
--> ImsServiceSub.java # sendConferenceRequest
--> ImsSenderRxr.java # processSolicited
由于我是用的product产品打的log,所以这块log不是很多,主要的log逻辑如下:
在此处需要重点注意的是,当ImsSenderRxr下发了CONFERENCE后,Modem后面会上报三通Call.从log中也可以看出,前两通就是之前分别A打给B,A打给C的电话,属于normalcall,但是第三通call是重新创建的一通Conference call.
3.Conference call 过程
在第二步中,Tele已经成功的将conference 命令发给Modem,在等待Modem返回前,上层需要做一些准备,从而来为接下来modem的返回做准备。这块代码没有很复杂,基本都是在vendor/qcom下面实现的,主要通过UNSOL_RESPONSE_CALL_STATE_CHANGED 和 UNSOL_REFRESH_CONF_INFO 来推动的。下面通过log来分步解释下业务逻辑:
1.modem告知当前两通call 状态发生变化,然后让上层开始处理这些变化,基本没有太多的逻辑变化,与正常的通话相同,有需 注意一点的是此时两通call的状态都是holding状态。
2.modem再次告知call 状态发生变化。此处需要注意的是,此时多了一通call,而且是一通conference call.然后为这通conference call创建对于的callSession.
3.当为第三通call创建了对应的callsession等完毕后,除了第三通call是一通conf外,与其他两通call暂时没有区别。需要注意的是,虽然此时modem上报了三通call,但第三通call并没有传递到上层,即在UI上并没有暂时还没有显示这通call.
4.如开头所说,ims conference call会创建一个conference room.然后会将多方通话依次加到conference room.从下面的log中可以看到,这次已经将第一个和第二个参与者加入到conference room 中。而且merge的信息中可以看到参与者的号码(我在log避免号码泄露,将自己的号码改成了xxxx).
5.当一通电话的参与者已经进入了conference room,那么就没有必要再去维护第一通电话了。所以第一通电话就会被end。
6.第二通电话参与者加入到conference room,加入成功后会将第二通电话end掉。至此,所有参与者都已经成功的加入了conference room中了,所以modem已经处理完毕了,返回response.
4.处理Modem response
当modem告知conference 成功后,modem返回个conference 的response.此处处理与正常流程相同。其最终的处理逻辑在
vendor/qcom/proprietary/telephony-apps/ims/src/org/codeaurora/ims/ImsServiceClassTracker.java
/**
* We have detected that a initial conference call has been fully configured. The internal
* state of both {@code ImsCall} objects need to be cleaned up to reflect the new state.
* This function should only be called in the context of the merge host to simplify logic
*
*/
private void processMergeComplete() {
synchronized(ImsCall.this) {
if (isMultiparty()) {
...
} else {
...
if (isSessionAlive(mSession) && !isSessionAlive(mMergePeer.getCallSession())) {
...
} else if (!isSessionAlive(mSession) &&
isSessionAlive(mMergePeer.getCallSession())) {
...
} else {
// Handles case 1 explained in callSessionMergeComplete
// The transient session stays with us and the disconnect sound should not be
// played when we ripple up the disconnect for the merge peer because it was
// only disconnected to be added to the conference.
finalHostCall = this;
finalPeerCall = mMergePeer;
mMergePeer.markCallAsMerged(false);
swapRequired = false;
setIsMerged(false);
mMergePeer.setIsMerged(true);
if (CONF_DBG) {
logi("processMergeComplete :: transient will stay with us (I'm the host).");
}
}
if (CONF_DBG) {
logi("processMergeComplete :: call=" + finalHostCall + " is the final host");
}
// Add the transient session to the ImsCall that ended up being the host for the
// conference.
finalHostCall.setTransientSessionAsPrimary(transientConferenceSession);
}
...
}
if (listener != null) {
try {
// finalPeerCall will have the participant that was not merged and
// it will be held state
// if peer was merged successfully, finalPeerCall will be null
listener.onCallMerged(finalHostCall, finalPeerCall, swapRequired);
} catch (Throwable t) {
loge("processMergeComplete :: ", t);
}
if (mConferenceParticipants != null && !mConferenceParticipants.isEmpty()) {
try {
listener.onConferenceParticipantsStateChanged(finalHostCall,
mConferenceParticipants);
} catch (Throwable t) {
loge("processMergeComplete :: ", t);
}
}
}
return;
}
1.高通的IMS模块将这些conference 的信息传递给Tele-FW,IMSCall处理上报的信息,确认Host,更改multiparty状态等,主要log如下:
2依次为参与者创建conference的connection,并以此connection创建对应的call对象。
3后面两个参与者创建方式与第一次相同。
4将新创建的三个call设置成conference call的child.
5创建对应的DialerCall,并且end掉之前的两通(A-B,A-C)Dialer。
至此,conference 的整个过程就全部完成了。
5.总结--各种Call对象的转换
此篇分析完全是根据log & 代码来看的,肯定有些错误的地方,后期发现会来更改。我对conference call的理解,比较混乱就是各个call对象,而且各种转换,以至于到最后在Dialer里面有4个call对象。所以单独把这快拎出来总结下:
在A拨号给B时,属于正常的拨号,所以都是正常的一个;
在A拨号给C时,也是正常的拨号,所以都是正常的两个;
在3.2时,由于已经发起了conference,modem会上报一个conference call.这通conferencall 暂时是一通不带任何信息的call. * 其实可以把这通conference call想象成一通可接入的room,后期merge的过程,是各个参与者(A,B,C)分别接入这个room中,可以想象成A,B,C分别拨给conference room;
在3.5 & 3.5时,A ,B,C分别merge了,所以ims需要维护的就越来越少,最终只需要维护一通conferen 就够了。
在4.2时,分别通过participant 的connection 创建了对应的三通Telecom call ,而且此时还未end 之前A->B & A->C的call.
在4.5时,整体merge完成,ims 就一通conference call,其他都是4通call.这4通call可以理解成:conference call 1通,A 拨给conference room 的1通,B拨给conference room 的1通,C拨给conference room 的1通。
本文标签: 以及其他流程CallandroidConference
版权声明:本文标题:Android call 流程以及其他case整理--Conference Call 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dongtai/1730019533a1219293.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论