SIP服务器采用B2BUA,sip呼叫控制实现流程:
INVITE的请求:
收到INVITE后,克隆INVITE消息。替换Request URI被叫注册的地址。
替换VIA头为服务器地址。通过该INVITE请求得到客户端事务并通过
该事务来发送INVITE请求。
180,200 OK响应的处理:
根据返回的响应码创建新的响应。
替换CONTACT头地址为服务器的地址。
拷贝原响应中的媒体内容至新的响应中。
通过INVITE中保存下来的服务端事务发送响应消息。
ACK的处理:
从ACK请求中得到序列数。
通过被叫对话来创建新的ACK请求。
通过被叫对话发送ACK请求。
BYE的处理流程:
根据被叫端的客户端事务得到发送给被叫的INVITE请求,根据INVITE请求创建BYE消息。
BYE响应消息处理流程:
根据DIALOG得到服务端事务,并由此得到BYE请求。根据BYE请求创建响应。
CANCEL的处理流程:
向主叫响应CANCEL 200 OK。
根据客户端事务得到发送给主叫的INVITE请求中的URI,CALLID,FROM,TO,VIA头域来创建CANCEL请求。
注:非200 OK的ACK响应是由协议栈来实现的,不需要应用层来发送。也就是说,ACK消息不会经过应用层。
package ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import .*; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; public class SipPhone implements SipListener { public void processDialogTerminated(DialogTerminatedEvent arg0) { // TODO Auto-generated method stub ("processDialogTerminated " + ()); } public void processIOException(IOExceptionEvent arg0) { // TODO Auto-generated method stub ("processIOException " + ()); } /** * 保存当前注册的用户 */ private static Hashtable<URI, URI> currUser = new Hashtable(); /** * @author software * 注册定时器 */ class TimerTask extends Timer { /** * default constructor */ public TimerTask() { } /** * 如果定时任务到,则删除该用户的注册信息 */ public void run() { } } /** * 服务器侦听IP地址 */ private String ipAddr = "192.168.0.20"; /** * 服务器侦听端口 */ private int port = 5060; /** * 处理register请求 * @param request 请求消息 */ private void processRegister(Request request, RequestEvent requestEvent) { if (null == request) { ("processInvite request is null."); return; } //("Request " + ()); ServerTransaction serverTransactionId = (); try { Response response = null; ToHeader head = (ToHeader)(); Address toAddress = (); URI toURI = (); ContactHeader contactHeader = (ContactHeader) ("Contact"); Address contactAddr = (); URI contactURI = (); ("processRegister from: " + toURI + " request str: " + contactURI); int expires = ().getExpires(); // 如果expires不等于0,则为注册,否则为注销。 if (expires != 0 || () != 0) { (toURI, contactURI); ("register user " + toURI); } else { (toURI); ("unregister user " + toURI); } response = (200, request); ("send register response : " + ()); if(serverTransactionId == null) { serverTransactionId = (request); (response); //(); ("register serverTransaction: " + serverTransactionId); } else { ("processRequest serverTransactionId is null."); } } catch (ParseException e) { // TODO Auto-generated catch block (); } catch (SipException e) { // TODO Auto-generated catch block (); } catch (InvalidArgumentException e) { // TODO Auto-generated catch block (); } } /** * 处理invite请求 * @param request 请求消息 */ private void processInvite(Request request, RequestEvent requestEvent) { if (null == request) { ("processInvite request is null."); return; } try { // 发送100 Trying serverTransactionId = (); if (serverTransactionId == null) { serverTransactionId = (request); callerDialog = (); Response response = (, request); (response); } //查询目标地址 URI reqUri = (); URI contactURI = (reqUri); ("processInvite rqStr=" + reqUri + " contact=" + contactURI); //根据Request uri来路由,后续的响应消息通过VIA来路由 Request cliReq = (()); (contactURI); Via callerVia = (Via)(); Via via = (Via) (ipAddr, port, "UDP", ()+"sipphone"); // FIXME 需要测试是否能够通过设置VIA头域来修改VIA头域值 (); (via); // 更新contact的地址 ContactHeader contactHeader = (); Address address = ("sip:sipsoft@" + ipAddr +":"+ port); (address); (3600); (contactHeader); clientTransactionId = (cliReq); (); ("processInvite clientTransactionId=" + ()); ("send invite to callee: " + cliReq); } catch (TransactionUnavailableException e1) { // TODO Auto-generated catch block (); } catch (SipException e) { // TODO Auto-generated catch block (); } catch (ParseException e) { (); } catch (Exception e) { (); } } /** * 处理SUBSCRIBE请求 * @param request 请求消息 */ private void processSubscribe(Request request) { if (null == request) { ("processSubscribe request is null."); return; } ServerTransaction serverTransactionId = null; try { serverTransactionId = (request); } catch (TransactionAlreadyExistsException e1) { // TODO Auto-generated catch block (); } catch (TransactionUnavailableException e1) { // TODO Auto-generated catch block (); } try { Response response = null; response = (200, request); if (response != null) { ExpiresHeader expireHeader = (30); (expireHeader); } ("response : " + ()); if(serverTransactionId != null) { (response); (); } else { ("processRequest serverTransactionId is null."); } } catch (ParseException e) { // TODO Auto-generated catch block (); } catch (SipException e) { // TODO Auto-generated catch block (); } catch (InvalidArgumentException e) { // TODO Auto-generated catch block (); } } /** * 处理BYE请求 * @param request 请求消息 */ private void processBye(Request request, RequestEvent requestEvent) { if (null == request || null == requestEvent) { ("processBye request is null."); return; } Request byeReq = null; Dialog dialog = (); ("calleeDialog : " + calleeDialog); ("callerDialog : " + callerDialog); try { if ((calleeDialog)) { byeReq = (()); ClientTransaction clientTran = (byeReq); (clientTran); (()); } else if ((callerDialog)) { byeReq = (()); ClientTransaction clientTran = (byeReq); (clientTran); (()); } else { (""); } ("send bye to peer:" + ()); } catch (SipException e) { // TODO Auto-generated catch block (); } } /** * 处理CANCEL请求 * @param request 请求消息 */ private void processCancel(Request request) { if (null == request) { ("processCancel request is null."); return; } } /** * 处理INFO请求 * @param request 请求消息 */ private void processInfo(Request request) { if (null == request) { ("processInfo request is null."); return; } } /** * 处理ACK请求 * @param request 请求消息 */ private void processAck(Request request, RequestEvent requestEvent) { if (null == request) { ("processAck request is null."); return; } try { Request ackRequest = null; CSeq csReq = (CSeq)(); ackRequest = (()); (ackRequest); ("send ack to callee:" + ()); } catch (SipException e) { // TODO Auto-generated catch block (); } catch (InvalidArgumentException e) { // TODO Auto-generated catch block (); } } /** * 处理CANCEL消息 * @param request * @param requestEvent */ private void processCancel(Request request, RequestEvent requestEvent) { // 判断参数是否有效 if (request == null || requestEvent == null) { ("processCancel input parameter invalid."); return; } try { // 发送CANCEL 200 OK消息 Response response = (, request); ServerTransaction cancelServTran = (); if (cancelServTran == null) { cancelServTran = (request); } (response); // 向对端发送CANCEL消息 Request cancelReq = null; Request inviteReq = (); List list = new ArrayList(); Via viaHeader = (Via)(); (viaHeader); CSeq cseq = (CSeq)(); CSeq cancelCSeq = (CSeq)((), ); cancelReq = ((), (), (CallIdHeader)(), cancelCSeq, (FromHeader)(), (ToHeader)(), list, (MaxForwardsHeader)()); ClientTransaction cancelClientTran = (cancelReq); (); } catch (ParseException e) { // TODO Auto-generated catch block (); } catch (TransactionAlreadyExistsException e) { // TODO Auto-generated catch block (); } catch (TransactionUnavailableException e) { // TODO Auto-generated catch block (); } catch (SipException e) { // TODO Auto-generated catch block (); } catch (InvalidArgumentException e) { // TODO Auto-generated catch block (); } } private ServerTransaction serverTransactionId = null; /* (non-Javadoc) * @see #processRequest() */ public void processRequest(RequestEvent arg0) { Request request = (); if (null == request) { ("processRequest request is null."); return; } ("processRequest:" + ()); if ((())) { processInvite(request, arg0); } else if ((())) { processRegister(request, arg0); } else if ((())) { processSubscribe(request); } else if ((())) { processAck(request, arg0); } else if ((())) { processBye(request, arg0); } else if ((())) { processCancel(request, arg0); } else { ("no support the method!"); } } /** * 主叫对话 */ private Dialog calleeDialog = null; /** * 被叫对话 */ private Dialog callerDialog = null; /** * */ ClientTransaction clientTransactionId = null; /** * 处理BYE响应消息 * @param reponseEvent */ private void doByeResponse(Response response, ResponseEvent responseEvent) { Dialog dialog = (); try { Response byeResp = null; if ((dialog)) { ServerTransaction servTran = (ServerTransaction)(); byeResp = ((), ()); (byeResp); } else if ((dialog)) { ServerTransaction servTran = (ServerTransaction)(); byeResp = ((), ()); (byeResp); } else { } ("send bye response to peer:" + ()); } catch (ParseException e) { // TODO Auto-generated catch block (); } catch (SipException e) { // TODO Auto-generated catch block (); } catch (InvalidArgumentException e) { // TODO Auto-generated catch block (); } } /* (non-Javadoc) * @see #processResponse() * */ public void processResponse(ResponseEvent arg0) { // FIXME 需要判断各个响应对应的是什么请求 Response response = (); ("recv the response :" + ()); ("respone to request : " + ().getRequest()); if (() == ) { ("The response is 100 response."); return; } try { ClientTransaction clientTran = (ClientTransaction) (); if ((().getMethod())) { int statusCode = (); Response callerResp = null; callerResp = (statusCode, ()); // 更新contact头域值,因为后面的消息是根据该URI来路由的 ContactHeader contactHeader = (); Address address = ("sip:sipsoft@"+ipAddr+":"+port); (address); (3600); (contactHeader); // 拷贝to头域 ToHeader toHeader = (ToHeader)(); (toHeader); // 拷贝相应的消息体 ContentLength contentLen = (ContentLength)(); if (contentLen != null && () != 0) { ContentType contentType = (ContentType)(); ("the sdp contenttype is " + contentType); (contentLen); //(contentType); ((), contentType); } else { ("sdp is null."); } if (serverTransactionId != null) { callerDialog = (); calleeDialog = (); (callerResp); ("callerDialog=" + callerDialog); ("=" + ()); } else { ("serverTransactionId is null."); } ("send response to caller : " + ()); } else if ((().getMethod())) { doByeResponse(response, arg0); } else if ((().getMethod())) { //doCancelResponse(response, arg0); } else { } } catch (ParseException e) { // TODO Auto-generated catch block (); } catch (SipException e) { // TODO Auto-generated catch block (); } catch (InvalidArgumentException e) { // TODO Auto-generated catch block (); } catch (Exception ex) { (); } } private void doCancelResponse(Response response, ResponseEvent responseEvent) { //FIXME 需要验证参数的有效性 ServerTransaction servTran = (ServerTransaction)(); Response cancelResp; try { cancelResp = ((), ()); (cancelResp); } catch (ParseException e) { // TODO Auto-generated catch block (); } catch (SipException e) { // TODO Auto-generated catch block (); } catch (InvalidArgumentException e) { // TODO Auto-generated catch block (); } } public void processTimeout(TimeoutEvent arg0) { // TODO Auto-generated method stub (" processTimeout " + ()); } public void processTransactionTerminated(TransactionTerminatedEvent arg0) { // TODO Auto-generated method stub (" processTransactionTerminated " + ().getBranchId() + " " + ().getBranchId()); } private static SipStack sipStack = null; private static AddressFactory addressFactory = null; private static MessageFactory msgFactory = null; private static HeaderFactory headerFactory = null; private static SipProvider sipProvider = null; private void init() { SipFactory sipFactory = null; sipFactory = (); if (null == sipFactory) { ("init sipFactory is null."); return; } (""); Properties properties = new Properties(); (".STACK_NAME", "sipphone"); // You need 16 for logging traces. 32 for debug + traces. // Your code will limp at 32 but it is best for debugging. (".TRACE_LEVEL", "32"); (".DEBUG_LOG", ""); (".SERVER_LOG", ""); try { sipStack = (properties); } catch (PeerUnavailableException e) { // TODO Auto-generated catch block (); return; } try { headerFactory = (); addressFactory = (); msgFactory = (); ListeningPoint lp = ("192.168.0.20", 5060, "udp"); SipPhone listener = this; sipProvider = (lp); ("udp provider " + ()); (listener); } catch (Exception ex) { (); return; } } /** * 程序入口 * @param args */ public static void main(String []args) { new SipPhone().init(); } }