摘要:本文将带你了解Android应用开发Android Sipdroid 对外通话建立过程分析,以及监听通话接通时刻,希望本文对大家学Android有所帮助。
本文将带你了解Android应用开发Android Sipdroid 对外通话建立过程分析,以及监听通话接通时刻,希望本文对大家学Android有所帮助。
Android Sipdroid 对外通话建立过程分析,以及监听通话接通时刻。
CallCard中有两类注意一下,一个是更新通话界面的方法
?
1
2
//对外暴露的方法:更新如通话时间,通话状态
public void displayMainCallStatus(Phone phone, Call call){}
第二个私有
?
1
2
3
4
5
6
/**
* Updates the "upper" and "lower" titles based on the
* current state of this call.
*/
private void updateCardTitleWidgets(Phone phone, Call call){}
在私有方法里面你可以看到Call.State state = call.getState();通话状态的判断,当Call.State.ACTIVE时,计时器mElapsedTime开始计时,从某种状态来说,这个已经算正式接通的状态。所以,更进一步是要对Call状态的实时监听。
调用处:
这里写图片描述
CallCard的displayMainCallStatus:
CallCard的displayMainCallStatus
CallCard的updateCardTitleWidgets:
CallCard的updateCardTitleWidgets
Call通话状态枚举
IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED
我们只注意ACTIVE(通话中)这个。
在管理器Receiver中,你可以查看到这里有对Call状态的设置ccCall.setState(...),在我们向外拨打电话同时会发送OFFHOLD广播(摘机)过程,你也可以通过这个广播同时判断Call状态即可获取对外通话正式接通的时刻。
注:OFFHOLD广播会发送两个,一次是开始拨打电话(按了拨号键)状态为Call.State.DIALING,第二次是接通(建立通话),状态为Call.State.ACTIVE
再进一步分析
在Receiver中,你可以看到call状态的改变是在public static void onState(int state,String caller),而这个方法的调用时是依赖UserAgent中的protected synchronized void changeStatus(int state,String caller)
Receiver的onState(int state,String caller)部分代码:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<code><code><code><code><code><code><code><code><code><code><code>public static void onState(int state,String caller) {
...
if (call_state != state) {
if (state != UserAgent.UA_STATE_IDLE)
call_end_reason = -1;
call_state = state;
switch(call_state)
{
...
case UserAgent.UA_STATE_OUTGOING_CALL:
broadcastCallStateChanged("OFFHOOK", caller);
ccCall.setState(Call.State.DIALING);
ccConn.setUserData(null);
ccConn.setAddress(caller,caller);
ccConn.setIncoming(false);
ccConn.date = System.currentTimeMillis();
ccCall.base = 0;
moveTop();
Checkin.checkin(true);
break;
case UserAgent.UA_STATE_INCALL:
broadcastCallStateChanged("OFFHOOK", null);
if (ccCall.base == 0) {
ccCall.base = SystemClock.elapsedRealtime();
}
progress();
ccCall.setState(Call.State.ACTIVE);
stopRingtone();
if (wl != null && wl.isHeld())
wl.release();
mContext.startActivity(createIntent(InCallScreen.class));
break;
...
}
pos(true);
RtpStreamReceiver.ringback(false);
}
}</code></code></code></code></code></code></code></code></code></code></code>
在UserAgent中,通话状态由变量call_state保持,而值UserAgent.UA_STATE_INCALL即值3代表通话中,具体见代码,这里不详说,其中建立会话成功是接收到报文”2xx”后被调用onCallReInviteAccepted()(实现CallListener接口)通话建立,这里就开始一系列的变化,改变UserAgent的通话状态call_state,调用Receiver.onState,改变Call.state,发送广播,更新通话界面。
那么,CallListener接口是什么时候创建实现的呢?
在对外呼出,UserAgent会创建一个ExtendedCall对象持有,UserAgent可以理解为通话的一个配置,而ExtendedCall是一个具体是通话实现,他处理报文,将接收的信息继续下发,让其它类解析。
所以让我们回到起点,当我们对外拨打电话时,调用Receiver.engine(mContext).call(xxx,true);,构建一个UserAgent,又构造了ExtendedCall,又创建了InviteDialog,调用invite,最后启动
?
1
2
3
4
<code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code>Message invite = MessageFactory.createInviteRequest(sip_provider,
request_uri, to_url, from_url,
contact_url, session_descriptor, icsi);
invite(invite);</code></code></code></code></code></code></code></code></code></code></code></code></code></code></code></code></code></code></code></code>
向服务器请求建立通话连接,接下来就是等服务器数据的返回,报文解析,这里不详述(因为很久前抓的报文文件删了,找不到)。
从上面分析,一次通话的拨出就已经很清晰了,那么我们想获取到通话正式接通那个时间点,该怎么处理?
用广播,最简单,原始代码都不用改动,上面已经说了“OFFHOLD” 自定义监听器
很明显,在你拨出界面的做监听,简单点,就是在你调用Receiver.engine(mContext).call(xxx,true);时做监听,这里没有监听方法,你可以在SipdroidEngine增加构造方法,将监听器下传到UserAgent,在UserAgent的onCallReInviteAccepted实现你的回调,如yourListener.onCallReInviteAccepted,假如你要继续下传到ExtendedCall甚至InviteDialog再回调出来也没有关系,你开心就好。
好了,写到这也就够了,下面放构造的代码块,我没有在github上放这个库,反正有开源代码,自己clone后爱怎么改怎么改,it all on you.
SipdroidEngine 代码块:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code>public boolean call(String target_url,boolean force,InviteListener listener) {
int p = pref;
boolean found = false;
if (isRegistered(p) && Receiver.isFast(p))
found = true;
else {
for (p = 0; p < LINES; p++)
if (isRegistered(p) && Receiver.isFast(p)) {
found = true;
break;
}
if (!found && force) {
p = pref;
if (Receiver.isFast(p))
found = true;
else for (p = 0; p < LINES; p++)
if (Receiver.isFast(p)) {
found = true;
break;
}
}
}
if (!found || (ua = uas[p]) == null) {
if (PreferenceManager.getDefaultSharedPreferences(getUIContext()).getBoolean(Settings.PREF_CALLBACK, Settings.DEFAULT_CALLBACK) &&
PreferenceManager.getDefaultSharedPreferences(getUIContext()).getString(Settings.PREF_POSURL, Settings.DEFAULT_POSURL).length() > 0) {
Receiver.url("n="+Uri.encode(target_url));
return true;
}
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号