/** * Responds with <i>resp</i>. This method can be called when the InviteDialog is in D_INVITED or * D_BYED states. * * <p>If the CSeq method is INVITE and the response is 2xx, it moves to state D_ACCEPTED, adds a * new listener to the SipProviderListener, and creates new AckTransactionServer * * <p>If the CSeq method is INVITE and the response is not 2xx, it moves to state D_REFUSED, and * sends the response. */ public void respond(Message resp) // private void respond(Message resp) { printLog("inside respond(resp)", LogLevel.MEDIUM); String method = resp.getCSeqHeader().getMethod(); if (method.equals(SipMethods.INVITE)) { if (!verifyStatus(statusIs(D_INVITED) || statusIs(D_ReINVITED))) { printLog( "respond(): InviteDialog not in (re)invited state: No response now", LogLevel.HIGH); return; } int code = resp.getStatusLine().getCode(); // 1xx provisional responses if (code >= 100 && code < 200) { invite_ts.respondWith(resp); return; } // For all final responses establish the dialog if (code >= 200) { // changeStatus(D_ACCEPTED); update(Dialog.UAS, resp); } // 2xx success responses if (code >= 200 && code < 300) { if (statusIs(D_INVITED)) changeStatus(D_ACCEPTED); else changeStatus(D_ReACCEPTED); // terminates the INVITE Transaction server and activates an ACK // Transaction server invite_ts.terminate(); ConnectionIdentifier conn_id = invite_ts.getConnectionId(); ack_ts = new AckTransactionServer(sip_provider, conn_id, resp, this); ack_ts.respond(); // if (statusIs(D_ReACCEPTED)) // listener.onDlgReInviteAccepted(this); // else listener.onDlgAccepted(this); return; } else // 300-699 failure responses // if (code>=300) { if (statusIs(D_INVITED)) changeStatus(D_REFUSED); else changeStatus(D_ReREFUSED); invite_ts.respondWith(resp); // if (statusIs(D_ReREFUSED)) // listener.onDlgReInviteRefused(this); // else listener.onDlgRefused(this); return; } } if (method.equals(SipMethods.BYE)) { if (!verifyStatus(statusIs(D_BYED))) return; bye_ts.respondWith(resp); } }
/** * When the AckTransactionServer goes into the "Terminated" state, caused by transaction timeout */ public void onTransAckTimeout(AckTransactionServer ts) { printLog("inside onAckSrvTimeout(ts)", LogLevel.LOW); if (!verifyStatus( statusIs(D_ACCEPTED) || statusIs(D_ReACCEPTED) || statusIs(D_REFUSED) || statusIs(D_ReREFUSED))) return; printLog("No ACK received..", LogLevel.HIGH); changeStatus(D_CLOSE); listener.onDlgClose(this); }
/** * Starts a new InviteTransactionClient and initializes the dialog state information. * * @param callee the callee url (and display name) * @param caller the caller url (and display name) * @param contact the contact url OR the contact username * @param session_descriptor SDP body * @param icsi the ICSI for this session */ public void invite( String callee, String caller, String contact, String session_descriptor, String icsi) { // modified by mandrajg printLog("inside invite(callee,caller,contact,sdp)", LogLevel.MEDIUM); if (!statusIs(D_INIT)) return; // else NameAddress to_url = new NameAddress(callee); NameAddress from_url = new NameAddress(caller); SipURL request_uri = to_url.getAddress(); NameAddress contact_url = null; if (contact != null) { if (contact.indexOf("sip:") >= 0) contact_url = new NameAddress(contact); else contact_url = new NameAddress( new SipURL(contact, sip_provider.getViaAddress(), sip_provider.getPort())); } else contact_url = from_url; Message invite = MessageFactory.createInviteRequest( sip_provider, request_uri, to_url, from_url, contact_url, session_descriptor, icsi); // modified by mandrajg // do invite invite(invite); }
/** * Inherited from TransactionClientListener. When the TransactionClientListener goes into the * "Completed" state, receiving a failure response * * <p>If called for a INVITE transaction, it moves to D_CLOSE state, removes the listener from * SipProvider. * * <p>If called for a BYE transaction, it moves to D_CLOSE state, removes the listener from * SipProvider, and fires <i>onClose(this,msg)</i>. */ public void onTransFailureResponse(TransactionClient tc, Message msg) { printLog("inside onTransFailureResponse(" + tc.getTransactionId() + ",msg)", LogLevel.LOW); if (tc.getTransactionMethod().equals(SipMethods.INVITE)) { if (!verifyStatus(statusIs(D_INVITING) || statusIs(D_ReINVITING))) return; StatusLine statusline = msg.getStatusLine(); int code = statusline.getCode(); verifyThat(code >= 300 && code < 700, "error code was expected"); if (statusIs(D_ReINVITING)) { changeStatus(D_CALL); listener.onDlgReInviteFailureResponse(this, code, statusline.getReason(), msg); } else { changeStatus(D_CLOSE); if (code >= 300 && code < 400) listener.onDlgInviteRedirectResponse( this, code, statusline.getReason(), msg.getContacts(), msg); else listener.onDlgInviteFailureResponse(this, code, statusline.getReason(), msg); listener.onDlgClose(this); } } else if (tc.getTransactionMethod().equals(SipMethods.BYE)) { if (!verifyStatus(statusIs(D_BYEING))) return; StatusLine statusline = msg.getStatusLine(); int code = statusline.getCode(); verifyThat(code >= 300 && code < 700, "error code was expected"); changeStatus(InviteDialog.D_CALL); listener.onDlgByeFailureResponse(this, code, statusline.getReason(), msg); } }
/** * Termiante the call. This method should be called when the InviteDialog is in D_CALL state * * <p>Increments the Cseq, moves to state D_BYEING, and creates new BYE TransactionClient */ public void bye() { printLog("inside bye()", LogLevel.MEDIUM); if (statusIs(D_CALL)) { Message bye = MessageFactory.createByeRequest(this); bye(bye); } }
/** * Inherited from TransactionClientListener. When an TransactionClientListener goes into the * "Terminated" state, receiving a 2xx response * * <p>If called for a INVITE transaction, it updates the dialog information, moves to D_CALL * state, add a listener to the SipProvider, creates a new AckTransactionClient(ack,this), and * fires <i>onSuccessResponse(this,code,body,msg)</i>. * * <p>If called for a BYE transaction, it moves to D_CLOSE state, removes the listener from * SipProvider, and fires <i>onClose(this,msg)</i>. */ public void onTransSuccessResponse(TransactionClient tc, Message msg) { printLog("inside onTransSuccessResponse(tc,msg)", LogLevel.LOW); if (tc.getTransactionMethod().equals(SipMethods.INVITE)) { if (!verifyStatus(statusIs(D_INVITING) || statusIs(D_ReINVITING))) return; StatusLine statusline = msg.getStatusLine(); int code = statusline.getCode(); if (!verifyThat( code >= 200 && code < 300 && msg.getTransactionMethod().equals(SipMethods.INVITE), "2xx for invite was expected")) return; boolean re_inviting = statusIs(D_ReINVITING); changeStatus(D_CALL); update(Dialog.UAC, msg); if (invite_offer) { // invite_req=MessageFactory.createRequest(SipMethods.ACK,dialog_state,sdp.toString()); // ack=MessageFactory.createRequest(this,SipMethods.ACK,null); ack_req = MessageFactory.create2xxAckRequest(this, null); AckTransactionClient ack_tc = new AckTransactionClient(sip_provider, ack_req, null); ack_tc.request(); } if (!re_inviting) { listener.onDlgInviteSuccessResponse(this, code, statusline.getReason(), msg.getBody(), msg); listener.onDlgCall(this); } else listener.onDlgReInviteSuccessResponse( this, code, statusline.getReason(), msg.getBody(), msg); } else if (tc.getTransactionMethod().equals(SipMethods.BYE)) { if (!verifyStatus(statusIs(D_BYEING))) return; StatusLine statusline = msg.getStatusLine(); int code = statusline.getCode(); verifyThat(code >= 200 && code < 300, "2xx for bye was expected"); changeStatus(D_CLOSE); listener.onDlgByeSuccessResponse(this, code, statusline.getReason(), msg); listener.onDlgClose(this); } }
/** * Inherited from TransactionClientListener. When the TransactionClientListener is in "Proceeding" * state and receives a new 1xx response * * <p>For INVITE transaction it fires <i>onFailureResponse(this,code,reason,body,msg)</i>. */ public void onTransProvisionalResponse(TransactionClient tc, Message msg) { printLog("inside onTransProvisionalResponse(tc,mdg)", LogLevel.LOW); if (tc.getTransactionMethod().equals(SipMethods.INVITE)) { StatusLine statusline = msg.getStatusLine(); listener.onDlgInviteProvisionalResponse( this, statusline.getCode(), statusline.getReason(), msg.getBody(), msg); } }
/** * Cancel the ongoing call request or a call listening. This method should be called when the * InviteDialog is in D_INVITING or D_ReINVITING state or in the D_WAITING state */ public void cancel(Message cancel) { printLog("inside cancel(cancel)", LogLevel.MEDIUM); if (statusIs(D_INVITING) || statusIs(D_ReINVITING)) { // changeStatus(D_CANCELING); TransactionClient tc = new TransactionClient(sip_provider, cancel, null); tc.request(); } else if (statusIs(D_WAITING) || statusIs(D_ReWAITING)) { invite_ts.terminate(); } }
/** * Cancel the ongoing call request or a call listening. This method should be called when the * InviteDialog is in D_INVITING or D_ReINVITING state or in the D_WAITING state */ public void cancel() { printLog("inside cancel()", LogLevel.MEDIUM); if (statusIs(D_INVITING) || statusIs(D_ReINVITING)) { Message cancel = MessageFactory.createCancelRequest(invite_req, this); // modified cancel(cancel); } else if (statusIs(D_WAITING) || statusIs(D_ReWAITING)) { invite_ts.terminate(); } }
/** * Inherited from InviteTransactionServerListener. When an InviteTransactionServer goes into the * "Confirmed" state receining an ACK for NON-2xx response * * <p>It moves to D_CLOSE state and removes the listener from SipProvider. */ public void onTransFailureAck(InviteTransactionServer ts, Message msg) { printLog("inside onTransFailureAck(ts,msg)", LogLevel.LOW); if (!verifyStatus(statusIs(D_REFUSED) || statusIs(D_ReREFUSED))) return; if (statusIs(D_ReREFUSED)) { changeStatus(D_CALL); } else { changeStatus(D_CLOSE); listener.onDlgClose(this); } }
/** * Re-invites the remote user. * * <p>Starts a new InviteTransactionClient and changes the dialog state information */ public void reInvite(Message invite) { printLog("inside reInvite(invite)", LogLevel.MEDIUM); if (!statusIs(D_CALL)) return; // else changeStatus(D_ReINVITING); invite_req = invite; update(Dialog.UAC, invite_req); InviteTransactionClient invite_tc = new InviteTransactionClient(sip_provider, invite_req, this); invite_tc.request(); }
/** * Termiante the call. This method should be called when the InviteDialog is in D_CALL state * * <p>Increments the Cseq, moves to state D_BYEING, and creates new BYE TransactionClient */ public void bye(Message bye) { printLog("inside bye(bye)", LogLevel.MEDIUM); if (statusIs(D_CALL)) { changeStatus(D_BYEING); // dialog_state.incLocalCSeq(); // done by // MessageFactory.createRequest() TransactionClient tc = new TransactionClient(sip_provider, bye, this); tc.request(); // listener.onDlgByeing(this); } }
/** * Inherited from TransactionClientListener. When the TransactionClient goes into the "Terminated" * state, caused by transaction timeout */ public void onTransTimeout(TransactionClient tc) { printLog("inside onTransTimeout(tc,msg)", LogLevel.LOW); if (tc.getTransactionMethod().equals(SipMethods.INVITE)) { if (!verifyStatus(statusIs(D_INVITING) || statusIs(D_ReINVITING))) return; cancel(); // modified changeStatus(D_CLOSE); listener.onDlgTimeout(this); listener.onDlgClose(this); } else if (tc.getTransactionMethod().equals(SipMethods.BYE)) { if (!verifyStatus(statusIs(D_BYEING))) return; changeStatus(D_CLOSE); listener.onDlgClose(this); } }
/** * Inherited from TransactionServerListener. When the TransactionServer goes into the "Trying" * state receiving a request * * <p>If called for a INVITE transaction, it initializes the dialog information, <br> * moves to D_INVITED state, and add a listener to the SipProvider, <br> * and fires <i>onInvite(caller,body,msg)</i>. */ public void onTransRequest(TransactionServer ts, Message req) { printLog("inside onTransRequest(ts,msg)", LogLevel.LOW); if (ts.getTransactionMethod().equals(SipMethods.INVITE)) { if (!verifyStatus(statusIs(D_WAITING))) return; changeStatus(D_INVITED); invite_req = req; update(Dialog.UAS, invite_req); listener.onDlgInvite( this, invite_req.getToHeader().getNameAddress(), invite_req.getFromHeader().getNameAddress(), invite_req.getBody(), invite_req); } }
/** * Re-invites the remote user. * * <p>Starts a new InviteTransactionClient and changes the dialog state information * * <p>Parameters: <br> * - contact : the contact url OR the contact username; if null, the previous contact is used <br> * - session_descriptor : the message body */ public void reInvite(String contact, String session_descriptor) { printLog("inside reInvite(contact,sdp)", LogLevel.MEDIUM); if (!statusIs(D_CALL)) return; // else Message invite = MessageFactory.createInviteRequest(this, session_descriptor); if (contact != null) { NameAddress contact_url; if (contact.indexOf("sip:") >= 0) contact_url = new NameAddress(contact); else contact_url = new NameAddress( new SipURL(contact, sip_provider.getViaAddress(), sip_provider.getPort())); invite.setContactHeader(new ContactHeader(contact_url)); } reInvite(invite); }
/** * Responds with <i>code</i> and <i>reason</i>. This method can be called when the InviteDialog is * in D_INVITED, D_ReINVITED states */ public void respond(int code, String reason, String contact, String sdp) { printLog("inside respond(" + code + "," + reason + ")", LogLevel.MEDIUM); if (statusIs(D_INVITED) || statusIs(D_ReINVITED)) { NameAddress contact_address = null; if (contact != null) contact_address = new NameAddress(contact); Message resp = MessageFactory.createResponse(invite_req, code, reason, contact_address); resp.setBody(sdp); respond(resp); } else printWarning( "Dialog isn't in \"invited\" state: cannot respond (" + code + "/" + getStatus() + "/" + getDialogID() + ")", LogLevel.MEDIUM); }
/** * Signals that the phone is ringing. This method should be called when the InviteDialog is in * D_INVITED or D_ReINVITED state */ public void ring(String sdp) { // modified printLog("inside ring()", LogLevel.MEDIUM); respond(180, SipResponses.reasonOf(180), null, sdp); }
/** * Accepts the incoming call. This method should be called when the InviteDialog is in D_INVITED * or D_ReINVITED state */ public void accept(String contact, String sdp) { printLog("inside accept(sdp)", LogLevel.MEDIUM); respond(200, SipResponses.reasonOf(200), contact, sdp); }
/** * Refuses the incoming call. This method should be called when the InviteDialog is in D_INVITED * or D_ReINVITED state */ public void refuse(int code, String reason) { printLog("inside refuse(" + code + "," + reason + ")", LogLevel.MEDIUM); respond(code, reason, null, null); }
/** * Inherited from class SipProviderListener. Called when a new message is received (out of any * ongoing transaction) for the current InviteDialog. Always checks for out-of-date methods (CSeq * header sequence number). * * <p>If the message is ACK(2xx/INVITE) request, it moves to D_CALL state, and fires * <i>onDlgAck(this,body,msg)</i>. * * <p>If the message is 2xx(INVITE) response, it create a new AckTransactionClient * * <p>If the message is BYE, it moves to D_BYED state, removes the listener from SipProvider, * fires onDlgBye(this,msg) then it responds with 200 OK, moves to D_CLOSE state and fires * onDlgClose(this) */ public void onReceivedMessage(SipProvider sip_provider, Message msg) { printLog("inside onReceivedMessage(sip_provider,message)", LogLevel.MEDIUM); if (msg.isRequest() && !(msg.isAck() || msg.isCancel()) && msg.getCSeqHeader().getSequenceNumber() <= getRemoteCSeq()) { printLog("Request message is too late (CSeq too small): Message discarded", LogLevel.HIGH); return; } // invite received if (msg.isRequest() && msg.isInvite()) { verifyStatus(statusIs(D_INIT) || statusIs(D_CALL)); // NOTE: if the invite_ts.listen() is used, you should not arrive // here with the D_INIT state.. // however state D_INIT has been included for robustness against // further changes. if (statusIs(D_INIT)) changeStatus(D_INVITED); else changeStatus(D_ReINVITED); invite_req = msg; invite_ts = new InviteTransactionServer(sip_provider, invite_req, this); // ((TransactionServer)transaction).listen(); update(Dialog.UAS, invite_req); if (statusIs(D_INVITED)) listener.onDlgInvite( this, invite_req.getToHeader().getNameAddress(), invite_req.getFromHeader().getNameAddress(), invite_req.getBody(), invite_req); else listener.onDlgReInvite(this, invite_req.getBody(), invite_req); } else // ack (of 2xx of INVITE) if (msg.isRequest() && msg.isAck()) { if (!verifyStatus(statusIs(D_ACCEPTED) || statusIs(D_ReACCEPTED))) return; changeStatus(D_CALL); // terminates the AckTransactionServer ack_ts.terminate(); listener.onDlgAck(this, msg.getBody(), msg); listener.onDlgCall(this); } else // keep sending ACK (if already sent) for any "200 OK" received if (msg.isResponse()) { if (!verifyStatus(statusIs(D_CALL))) return; int code = msg.getStatusLine().getCode(); verifyThat(code >= 200 && code < 300, "code 2xx was expected"); if (ack_req != null) { AckTransactionClient ack_tc = new AckTransactionClient(sip_provider, ack_req, null); ack_tc.request(); } } else // bye received if (msg.isRequest() && msg.isBye()) { if (!verifyStatus(statusIs(D_CALL) || statusIs(D_BYEING))) return; changeStatus(D_BYED); bye_ts = new TransactionServer(sip_provider, msg, this); // automatically sends a 200 OK Message resp = MessageFactory.createResponse(msg, 200, SipResponses.reasonOf(200), null); respond(resp); listener.onDlgBye(this, msg); changeStatus(D_CLOSE); listener.onDlgClose(this); } else // cancel received if (msg.isRequest() && msg.isCancel()) { if (!verifyStatus(statusIs(D_INVITED) || statusIs(D_ReINVITED))) return; // create a CANCEL TransactionServer and send a 200 OK (CANCEL) TransactionServer ts = new TransactionServer(sip_provider, msg, null); // ts.listen(); ts.respondWith(MessageFactory.createResponse(msg, 200, SipResponses.reasonOf(200), null)); // automatically sends a 487 Cancelled Message resp = MessageFactory.createResponse(invite_req, 487, SipResponses.reasonOf(487), null); respond(resp); listener.onDlgCancel(this, msg); } else // any other request received if (msg.isRequest()) { TransactionServer ts = new TransactionServer(sip_provider, msg, null); // ts.listen(); ts.respondWith(MessageFactory.createResponse(msg, 405, SipResponses.reasonOf(405), null)); } }
/** * Redirects the incoming call , specifing the <i>code</i> and <i>reason</i>. This method can be * called when the InviteDialog is in D_INVITED or D_ReINVITED state */ public void redirect(int code, String reason, String contact) { printLog("inside redirect(" + code + "," + reason + "," + contact + ")", LogLevel.MEDIUM); respond(code, reason, contact, null); }
/** * Refuses the incoming call. This method should be called when the InviteDialog is in D_INVITED * or D_ReINVITED state */ public void refuse() { printLog("inside refuse()", LogLevel.MEDIUM); // refuse(480,"Temporarily Unavailable"); // refuse(603,"Decline"); refuse(403, SipResponses.reasonOf(403)); }