JAIN SIP #10 (Create Invite ตอนจบ)
ความเดิมตอนที่แล้ว ผมทิ้งคำถามไว้ว่า ผู้ส่ง ข้อมูล RTP ไปหา SIP Server ก่อนถึงผู้รับ ทำให้ส่งช้าลงโดยไม่จำเป็น ในตอนนี้ ผมจะอธิบายการส่งข้อมูลจากผู้ส่งไปหาผู้รับโดยตรง
หลังจากที่จัดตั้ง session ขึ้นเรียบร้อยแล้ว SIP Server ก็จะส่ง Invite Request (ReInvite) มาหาผู้ส่งใหม่อีกรอบ (คล้าย ๆ กับเป็น B2BUA เลยแฮะ) เมื่อเราได้รับ Invite (อีกรอบ) คราวนี้เราเป็นผู้รับ (เมื่อก่อนเราเป็นผู้ส่ง Invite) มันก็จะไปเรียกฟังก์ชัน processRequest() ดังนี้
| public void processRequest(RequestEvent requestReceivedEvent) { Request request = requestReceivedEvent.getRequest(); ServerTransaction serverTransactionId = requestReceivedEvent .getServerTransaction(); System.out.println("\n\nRequest " + request.getMethod() + " received at " + sipStack.getStackName() + " with server transaction id " + serverTransactionId); if (request.getMethod().equals(Request.INVITE)) processInvite(request, serverTransactionId); } |
ความนี้ข้อมูลใน SDP จะระบุ IP และ port ของผู้รับโดยตรง มาให้ เราจัดการ shutdown RTP Session เก่าทิ้งซะ แล้วก็เอาข้อมูลจาก SDP นี้แหละ ไปสร้างเป็น RTP Session ใหม่ โดยกำหนดใน ฟังก์ชัน processInvite() ดังนี้ครับ
| public void processInvite(Request request, ServerTransaction serverTransactionId) { try { System.out.println(" I got INVITE Request!!! " + request.toString() ); //---------- Start SDP Split --------------------- //------ I don't know how to get SDP data, --- // then I split it by from response object String respString = (String) request.toString(); String addrRecv = ""; String portRecv = ""; String newCallId = ""; StringTokenizer Tok = new StringTokenizer(respString); while (Tok.hasMoreElements()) { String tmp = Tok.nextElement().toString(); if ( tmp.equals("IP4") ) addrRecv = Tok.nextElement().toString(); else if ( tmp.equals("Call-ID:") ) newCallId = Tok.nextElement().toString(); else if ( tmp.equals("m=audio") ) portRecv = Tok.nextElement().toString(); } //---------- End SDP Split --------------------- // have to call create ResponseACK (See ACK Invited) Response response = messageFactory.createResponse( Response.OK, request); ((ToHeader) response.getHeader(ToHeader.NAME)) .setTag(((ToHeader) request.getHeader(ToHeader.NAME)) .getTag()); response.addHeader(this.contactHeader); serverTransactionId.sendResponse(response); // ------ Stop Sending ------- transRTP.shutDown(); recRTP.shutDown(); // Check addRecv == sipServerIP because Asterisk always sends Invite // before send BYE message to the sender. if ( !addrRecv.equals(sipServer) ) { // ----------- Start Receiver ----------------- System.out.println("Before receive data"); recRTP = new Receive(audioPort); System.out.println("after receive data"); // ----------- Start Receiver ----------------- System.out.println("Start sending stream"); transRTP = new Transmit(addrRecv,Integer.parseInt(portRecv) ); //System.out.println("Start sending stream"); } } catch (Exception ex) { System.out.println("Error from processInvite"); ex.printStackTrace(); } } |
ก็คล้าย ๆ ของเดิมครับ เอา SDP มา split หา IP กับ port ใหม่ แล้วก็สร้าง RTP Session กับผู้รับโดยตรง
ในฟังก์ชันนี้มีสิ่งที่น่าสนใจตรงที่ เงื่อนไข if ( !addrRecv.equals(sipServer) ) ครับ ตรงนี้ผมกำหนดไว้เพราะว่า เวลาผู้รับ ยกเลิก session (วางสาย) โดยการส่ง Bye ผู้รับจะส่ง Bye หา SIP Server และ SIP Server ก็จะส่ง 200 OK หาผู้รับโดยตรง ในขณะที่ผู้ส่งนั้น SIP Server จะส่ง Invite มาให้อีกรอบ ถ้าผมไม่ใส่เงื่อนไขนี้ไว้ เวลาที่ได้รับ Invite ใหม่อีกรอบ ก็จะจัดตั้ง Session ใหม่อีก ทั้ง ๆ ที่จะ Bye กันแล้ว ก็คือ ถ้าผู้ที่ส่ง Invite เป็น SIP Server (อีกครั้ง) ก็คือไม่ต้องสนใจ และรอเตรียมรับ Bye เท่านั้นเองครับ