SIP服务器采用B2BUA,sip呼叫控制实现流程
TAG:
SIP服务器采用B2BUA,sip呼叫控制实现流程:
package com.voip.sipphone; import gov.nist.javax.sip.address.SipUri; import gov.nist.javax.sip.header.CSeq; import gov.nist.javax.sip.header.Contact; import gov.nist.javax.sip.header.ContentLength; import gov.nist.javax.sip.header.ContentType; import gov.nist.javax.sip.header.From; import gov.nist.javax.sip.header.Via; import java.text.ParseException; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Properties; import java.util.Timer; import javax.sip.*; import javax.sip.address.Address; import javax.sip.address.AddressFactory; import javax.sip.address.URI; import javax.sip.header.CallIdHeader; import javax.sip.header.ContactHeader; import javax.sip.header.ExpiresHeader; import javax.sip.header.FromHeader; import javax.sip.header.Header; import javax.sip.header.HeaderFactory; import javax.sip.header.MaxForwardsHeader; import javax.sip.header.RecordRouteHeader; import javax.sip.header.ToHeader; import javax.sip.header.ViaHeader; import javax.sip.message.MessageFactory; import javax.sip.message.Request; import javax.sip.message.Response; public class SipPhone implements SipListener { public void processDialogTerminated(DialogTerminatedEvent arg0) { // TODO Auto-generated method stub System.out.println("processDialogTerminated " + arg0.toString()); } public void processIOException(IOExceptionEvent arg0) { // TODO Auto-generated method stub System.out.println("processIOException " + arg0.toString()); } /** * 保存当前注册的用户 */ 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) { System.out.println("processInvite request is null."); return; } //System.out.println("Request " + request.toString()); ServerTransaction serverTransactionId = requestEvent.getServerTransaction(); try { Response response = null; ToHeader head = (ToHeader)request.getHeader(ToHeader.NAME); Address toAddress = head.getAddress(); URI toURI = toAddress.getURI(); ContactHeader contactHeader = (ContactHeader) request.getHeader("Contact"); Address contactAddr = contactHeader.getAddress(); URI contactURI = contactAddr.getURI(); System.out.println("processRegister from: " + toURI + " request str: " + contactURI); int expires = request.getExpires().getExpires(); // 如果expires不等于0,则为注册,否则为注销。 if (expires != 0 || contactHeader.getExpires() != 0) { currUser.put(toURI, contactURI); System.out.println("register user " + toURI); } else { currUser.remove(toURI); System.out.println("unregister user " + toURI); } response = msgFactory.createResponse(200, request); System.out.println("send register response : " + response.toString()); if(serverTransactionId == null) { serverTransactionId = sipProvider.getNewServerTransaction(request); serverTransactionId.sendResponse(response); //serverTransactionId.terminate(); System.out.println("register serverTransaction: " + serverTransactionId); } else { System.out.println("processRequest serverTransactionId is null."); } } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SipException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvalidArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 处理invite请求 * @param request 请求消息 */ private void processInvite(Request request, RequestEvent requestEvent) { if (null == request) { System.out.println("processInvite request is null."); return; } try { // 发送100 Trying serverTransactionId = requestEvent.getServerTransaction(); if (serverTransactionId == null) { serverTransactionId = sipProvider.getNewServerTransaction(request); callerDialog = serverTransactionId.getDialog(); Response response = msgFactory.createResponse(Response.TRYING, request); serverTransactionId.sendResponse(response); } //查询目标地址 URI reqUri = request.getRequestURI(); URI contactURI = currUser.get(reqUri); System.out.println("processInvite rqStr=" + reqUri + " contact=" + contactURI); //根据Request uri来路由,后续的响应消息通过VIA来路由 Request cliReq = msgFactory.createRequest(request.toString()); cliReq.setRequestURI(contactURI); Via callerVia = (Via)request.getHeader(Via.NAME); Via via = (Via) headerFactory.createViaHeader(ipAddr, port, "UDP", callerVia.getBranch()+"sipphone"); // FIXME 需要测试是否能够通过设置VIA头域来修改VIA头域值 cliReq.removeHeader(Via.NAME); cliReq.addHeader(via); // 更新contact的地址 ContactHeader contactHeader = headerFactory.createContactHeader(); Address address = addressFactory.createAddress("sip:sipsoft@" + ipAddr +":"+ port); contactHeader.setAddress(address); contactHeader.setExpires(3600); cliReq.setHeader(contactHeader); clientTransactionId = sipProvider.getNewClientTransaction(cliReq); clientTransactionId.sendRequest(); System.out.println("processInvite clientTransactionId=" + clientTransactionId.toString()); System.out.println("send invite to callee: " + cliReq); } catch (TransactionUnavailableException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (SipException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } /** * 处理SUBSCRIBE请求 * @param request 请求消息 */ private void processSubscribe(Request request) { if (null == request) { System.out.println("processSubscribe request is null."); return; } ServerTransaction serverTransactionId = null; try { serverTransactionId = sipProvider.getNewServerTransaction(request); } catch (TransactionAlreadyExistsException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (TransactionUnavailableException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } try { Response response = null; response = msgFactory.createResponse(200, request); if (response != null) { ExpiresHeader expireHeader = headerFactory.createExpiresHeader(30); response.setExpires(expireHeader); } System.out.println("response : " + response.toString()); if(serverTransactionId != null) { serverTransactionId.sendResponse(response); serverTransactionId.terminate(); } else { System.out.println("processRequest serverTransactionId is null."); } } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SipException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvalidArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 处理BYE请求 * @param request 请求消息 */ private void processBye(Request request, RequestEvent requestEvent) { if (null == request || null == requestEvent) { System.out.println("processBye request is null."); return; } Request byeReq = null; Dialog dialog = requestEvent.getDialog(); System.out.println("calleeDialog : " + calleeDialog); System.out.println("callerDialog : " + callerDialog); try { if (dialog.equals(calleeDialog)) { byeReq = callerDialog.createRequest(request.getMethod()); ClientTransaction clientTran = sipProvider.getNewClientTransaction(byeReq); callerDialog.sendRequest(clientTran); calleeDialog.setApplicationData(requestEvent.getServerTransaction()); } else if (dialog.equals(callerDialog)) { byeReq = calleeDialog.createRequest(request.getMethod()); ClientTransaction clientTran = sipProvider.getNewClientTransaction(byeReq); calleeDialog.sendRequest(clientTran); callerDialog.setApplicationData(requestEvent.getServerTransaction()); } else { System.out.println(""); } System.out.println("send bye to peer:" + byeReq.toString()); } catch (SipException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 处理CANCEL请求 * @param request 请求消息 */ private void processCancel(Request request) { if (null == request) { System.out.println("processCancel request is null."); return; } } /** * 处理INFO请求 * @param request 请求消息 */ private void processInfo(Request request) { if (null == request) { System.out.println("processInfo request is null."); return; } } /** * 处理ACK请求 * @param request 请求消息 */ private void processAck(Request request, RequestEvent requestEvent) { if (null == request) { System.out.println("processAck request is null."); return; } try { Request ackRequest = null; CSeq csReq = (CSeq)request.getHeader(CSeq.NAME); ackRequest = calleeDialog.createAck(csReq.getSeqNumber()); calleeDialog.sendAck(ackRequest); System.out.println("send ack to callee:" + ackRequest.toString()); } catch (SipException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvalidArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 处理CANCEL消息 * @param request * @param requestEvent */ private void processCancel(Request request, RequestEvent requestEvent) { // 判断参数是否有效 if (request == null || requestEvent == null) { System.out.println("processCancel input parameter invalid."); return; } try { // 发送CANCEL 200 OK消息 Response response = msgFactory.createResponse(Response.OK, request); ServerTransaction cancelServTran = requestEvent.getServerTransaction(); if (cancelServTran == null) { cancelServTran = sipProvider.getNewServerTransaction(request); } cancelServTran.sendResponse(response); // 向对端发送CANCEL消息 Request cancelReq = null; Request inviteReq = clientTransactionId.getRequest(); List list = new ArrayList(); Via viaHeader = (Via)inviteReq.getHeader(Via.NAME); list.add(viaHeader); CSeq cseq = (CSeq)inviteReq.getHeader(CSeq.NAME); CSeq cancelCSeq = (CSeq)headerFactory.createCSeqHeader(cseq.getSeqNumber(), Request.CANCEL); cancelReq = msgFactory.createRequest(inviteReq.getRequestURI(), inviteReq.getMethod(), (CallIdHeader)inviteReq.getHeader(CallIdHeader.NAME), cancelCSeq, (FromHeader)inviteReq.getHeader(From.NAME), (ToHeader)inviteReq.getHeader(ToHeader.NAME), list, (MaxForwardsHeader)inviteReq.getHeader(MaxForwardsHeader.NAME)); ClientTransaction cancelClientTran = sipProvider.getNewClientTransaction(cancelReq); cancelClientTran.sendRequest(); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (TransactionAlreadyExistsException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (TransactionUnavailableException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SipException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvalidArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private ServerTransaction serverTransactionId = null; /* (non-Javadoc) * @see javax.sip.SipListener#processRequest(javax.sip.RequestEvent) */ public void processRequest(RequestEvent arg0) { Request request = arg0.getRequest(); if (null == request) { System.out.println("processRequest request is null."); return; } System.out.println("processRequest:" + request.toString()); if (Request.INVITE.equals(request.getMethod())) { processInvite(request, arg0); } else if (Request.REGISTER.equals(request.getMethod())) { processRegister(request, arg0); } else if (Request.SUBSCRIBE.equals(request.getMethod())) { processSubscribe(request); } else if (Request.ACK.equalsIgnoreCase(request.getMethod())) { processAck(request, arg0); } else if (Request.BYE.equalsIgnoreCase(request.getMethod())) { processBye(request, arg0); } else if (Request.CANCEL.equalsIgnoreCase(request.getMethod())) { processCancel(request, arg0); } else { System.out.println("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 = responseEvent.getDialog(); try { Response byeResp = null; if (callerDialog.equals(dialog)) { ServerTransaction servTran = (ServerTransaction)calleeDialog.getApplicationData(); byeResp = msgFactory.createResponse(response.getStatusCode(), servTran.getRequest()); servTran.sendResponse(byeResp); } else if (calleeDialog.equals(dialog)) { ServerTransaction servTran = (ServerTransaction)callerDialog.getApplicationData(); byeResp = msgFactory.createResponse(response.getStatusCode(), servTran.getRequest()); servTran.sendResponse(byeResp); } else { } System.out.println("send bye response to peer:" + byeResp.toString()); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SipException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvalidArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /* (non-Javadoc) * @see javax.sip.SipListener#processResponse(javax.sip.ResponseEvent) * */ public void processResponse(ResponseEvent arg0) { // FIXME 需要判断各个响应对应的是什么请求 Response response = arg0.getResponse(); System.out.println("recv the response :" + response.toString()); System.out.println("respone to request : " + arg0.getClientTransaction().getRequest()); if (response.getStatusCode() == Response.TRYING) { System.out.println("The response is 100 response."); return; } try { ClientTransaction clientTran = (ClientTransaction) arg0.getClientTransaction(); if (Request.INVITE.equalsIgnoreCase(clientTran.getRequest().getMethod())) { int statusCode = response.getStatusCode(); Response callerResp = null; callerResp = msgFactory.createResponse(statusCode, serverTransactionId.getRequest()); // 更新contact头域值,因为后面的消息是根据该URI来路由的 ContactHeader contactHeader = headerFactory.createContactHeader(); Address address = addressFactory.createAddress("sip:sipsoft@"+ipAddr+":"+port); contactHeader.setAddress(address); contactHeader.setExpires(3600); callerResp.addHeader(contactHeader); // 拷贝to头域 ToHeader toHeader = (ToHeader)response.getHeader(ToHeader.NAME); callerResp.setHeader(toHeader); // 拷贝相应的消息体 ContentLength contentLen = (ContentLength)response.getContentLength(); if (contentLen != null && contentLen.getContentLength() != 0) { ContentType contentType = (ContentType)response.getHeader(ContentType.NAME); System.out.println("the sdp contenttype is " + contentType); callerResp.setContentLength(contentLen); //callerResp.addHeader(contentType); callerResp.setContent(response.getContent(), contentType); } else { System.out.println("sdp is null."); } if (serverTransactionId != null) { callerDialog = serverTransactionId.getDialog(); calleeDialog = clientTran.getDialog(); serverTransactionId.sendResponse(callerResp); System.out.println("callerDialog=" + callerDialog); System.out.println("serverTransactionId.branch=" + serverTransactionId.getBranchId()); } else { System.out.println("serverTransactionId is null."); } System.out.println("send response to caller : " + callerResp.toString()); } else if (Request.BYE.equalsIgnoreCase(clientTran.getRequest().getMethod())) { doByeResponse(response, arg0); } else if (Request.CANCEL.equalsIgnoreCase(clientTran.getRequest().getMethod())) { //doCancelResponse(response, arg0); } else { } } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SipException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvalidArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception ex) { ex.printStackTrace(); } } private void doCancelResponse(Response response, ResponseEvent responseEvent) { //FIXME 需要验证参数的有效性 ServerTransaction servTran = (ServerTransaction)callerDialog.getApplicationData(); Response cancelResp; try { cancelResp = msgFactory.createResponse(response.getStatusCode(), servTran.getRequest()); servTran.sendResponse(cancelResp); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SipException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvalidArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void processTimeout(TimeoutEvent arg0) { // TODO Auto-generated method stub System.out.println(" processTimeout " + arg0.toString()); } public void processTransactionTerminated(TransactionTerminatedEvent arg0) { // TODO Auto-generated method stub System.out.println(" processTransactionTerminated " + arg0.getClientTransaction().getBranchId() + " " + arg0.getServerTransaction().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 = SipFactory.getInstance(); if (null == sipFactory) { System.out.println("init sipFactory is null."); return; } sipFactory.setPathName("gov.nist"); Properties properties = new Properties(); properties.setProperty("javax.sip.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. properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "32"); properties.setProperty("gov.nist.javax.sip.DEBUG_LOG", "sipphonedebug.txt"); properties.setProperty("gov.nist.javax.sip.SERVER_LOG", "sipphonelog.txt"); try { sipStack = sipFactory.createSipStack(properties); } catch (PeerUnavailableException e) { // TODO Auto-generated catch block e.printStackTrace(); return; } try { headerFactory = sipFactory.createHeaderFactory(); addressFactory = sipFactory.createAddressFactory(); msgFactory = sipFactory.createMessageFactory(); ListeningPoint lp = sipStack.createListeningPoint("192.168.0.20", 5060, "udp"); SipPhone listener = this; sipProvider = sipStack.createSipProvider(lp); System.out.println("udp provider " + sipProvider.toString()); sipProvider.addSipListener(listener); } catch (Exception ex) { ex.printStackTrace(); return; } } /** * 程序入口 * @param args */ public static void main(String []args) { new SipPhone().init(); } } |