SIP协议是一个Client/Sever协议,因此SIP消息分两种:请求消息和响应消息。请求消息是SIP客户端为了激活特定操作而发给服务器端的消息。常用的SIP请求消息如下:
INVITE:表示主叫用户发起会话请求,邀请其他用户加入一个会话。也可以用在呼叫建立后用于更新会话(此时该INVITE又称为Re-invite)。
ACK:客户端向服务器端证实它已经收到了对INVITE请求的最终响应。
PRACK:表示对1xx响应消息的确认请求消息。
BYE:表示终止一个已经建立的呼叫。
CANCEL:表示在收到对请求的最终响应之前取消该请求,对于已完成的请求则无影响。
REGISTER:表示客户端向SIP服务器端注册列在To字段中的地址信息。
OPTIONS:表示查询被叫的相关信息和功能。SIP协议中的响应消息用于对请求消息进行响应,指示呼叫的成功或失败状态。
常用的一些响应消息:100试呼叫(Trying)
180振铃(Ringing)
181呼叫正在前转(Call is Being Forwarded)
200成功响应(OK)
302临时迁移(Moved Temporarily)
400错误请求(Bad Request)
401未授权(Unauthorized)
403禁止(Forbidden)
404用户不存在(Not Found)
408请求超时(Request Timeout)
480暂时无人接听(Temporarily Unavailable)
486线路忙(Busy Here)
504服务器超时(Server Time-out)
600全忙(Busy Everywhere)
以上背景知识在下面的代码分析中会用到。
为了了解如何监听来电,我们从Sipdroid.StartEngine()开始,一步一步写出函数的调用过程。过程如下:
Sipdroid.StartEngine() -> Sipdroid.listen() -> UserAgent.listen() ->ExtendedCall.listen() -> ExtendedInviteDialog.listen() -> InviteTransactionServer.listen()
好戏从InviteTransactionServer.listen()开始,下面是代码:
public void listen() {
printLog("start", LogLevel.LOW);
if (statusIs(STATE_IDLE)) {
changeStatus(STATE_WAITING);
sip_provider.addSipProviderListener(new TransactionIdentifier(
SipMethods.INVITE), this);
sip_provider.addSipProviderListener(new TransactionIdentifier(
SipMethods.OPTIONS), this);
}
}
大概得看上去,这里是给sip_provider添加了几个Listener,参数中寻找回调接口时发现了this,那就是在本类中了。寻找后发现回调方法就是这个了:
public void onReceivedMessage(SipProvider provider, Message msg) {
if (msg.isRequest()) {
String req_method = msg.getRequestLine().getMethod();
// invite 消息收到
if (req_method.equals(SipMethods.INVITE)) {
if (statusIs(STATE_WAITING)) {
request = new Message(msg);
connection_id = request.getConnectionId();
transaction_id = request.getTransactionId();
sip_provider.addSipProviderListener(transaction_id, this);
sip_provider
.removeSipProviderListener(new TransactionIdentifier(
SipMethods.INVITE));
changeStatus(STATE_TRYING);
// automatically send "100 Tryng" response and go to
// STATE_PROCEEDING
//自动回复"100 Tryng"消息
if (auto_trying) {
Message trying100 = MessageFactory.createResponse(
request, 100, SipResponses.reasonOf(100), null);
respondWith(trying100); // this method makes it going
// automatically to
// STATE_PROCEEDING
}
if (transaction_listener != null)
transaction_listener.onTransRequest(this, msg);
return;
}
if (statusIs(STATE_PROCEEDING) || statusIs(STATE_COMPLETED)) { // retransmission
// of
// the
// last
// response
sip_provider.sendMessage(response, connection_id);
return;
}
}
//如果收到的是 OPTIONS 消息
if (req_method.equals(SipMethods.OPTIONS)) {
Message ok200 = MessageFactory.createResponse(msg, 200, SipResponses.reasonOf(200), null);
ok200.removeServerHeader();
ok200.addContactHeader(new ContactHeader(ok200.getToHeader().getNameAddress()), false);
sip_provider.sendMessage(ok200, connection_id);
return;
}
// ack received
//如果收到的是 ack 消息
if (req_method.equals(SipMethods.ACK) && statusIs(STATE_COMPLETED)) {
retransmission_to.halt();
end_to.halt();
changeStatus(STATE_CONFIRMED);
if (transaction_listener != null)
transaction_listener.onTransFailureAck(this, msg);
clearing_to.start();
return;
}
}
}
初看此方法,可以发现这里面的处理分为三种情况,收到 invite 消息时,收到options 消息时,收到 ack 消息时。本类的名字是InviteTransactionServer,意思是invite消息服务器,就是说这个类是专门用来处理invite消息的,对于其他的消息的处理就在其他的专门的类中了。
结合本文开篇的背景知识,我们就能知道这里实际上就是在对sip协议中的其中三种请求进行处理。根据sip协议,当一个用户想要拨打另一用户,代理服务器会首先将invite消息发给另一用户。在此方法中,我们只看见了对于invite消息进行回复100,根据sip协议,通话的建立是需要两个客户端进行几次握手的,这里仅仅是回复了一次消息,距离通话建立还有几步,不过这里好像就没有看到后续的操作了。
sipdroid的源码分层十分明显,从底层的网络数据接受发送到上层的呼叫的各种状态的建立(来电,接通,取消,挂断等等),每一层都用了单独的类。这里简单记录一下个类的分层情况(这里是仅考虑等待来电到接通电话,其他的代码还没看),从上往下是:
UserAgent(直接处理来电)
ExtendedCall (extends Call)
ExtendedInviteDialog (extends InviteDialog)
InviteTransactionServer
每一层通过回调接口相互联系。具体的流程十分的繁杂,文字叙述还真是很不方便。