/*
* Copyright 2007 Sun Microsystems, Inc.
*
* This file is part of jVoiceBridge.
*
* jVoiceBridge is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation and distributed hereunder
* to you.
*
* jVoiceBridge is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Sun designates this particular file as subject to the "Classpath"
* exception as provided by Sun in the License file that accompanied this
* code.
*/
package com.sun.voip.server;
import java.text.ParseException;
import javax.sip.*;
import javax.sip.header.*;
import javax.sip.message.*;
import javax.sip.address.*;
import com.sun.voip.CallParticipant;
import com.sun.voip.Logger;
/**
* @author jerry
*/
public class DirectOutgoingCallHandler implements SipListener {
public static final int INVITE_SENT = 1;
public static final int INVITE_OK = 2;
public static final int INVITE_ACK = 3;
public static final int TERMINATED = 4;
CallParticipant callParticipant;
int state;
ClientTransaction ct;
String sdp;
Object stateLock = new Object();
SipUtil sipUtil;
DirectOutgoingCallHandler otherCall;
String sipCallId;
/** Creates a new instance of DirectOutgoingCallHandler */
public DirectOutgoingCallHandler(CallParticipant cp) {
callParticipant = cp;
sipUtil = new SipUtil();
}
/**
* Sends an Invite with the given SDP
* If the sdp is null, then sends an Invite with no sdp
* @param sdp String the SDP to send with the INVITE
*/
public void sendInvite(String sdp){
try {
ct = sipUtil.sendInvite(callParticipant, sdp);
CallIdHeader callIdHeader = (CallIdHeader) ct.getRequest().getHeader(CallIdHeader.NAME);
sipCallId = callIdHeader.getCallId();
SipServer.getSipServerCallback().addSipListener(sipCallId, this);
setState(INVITE_SENT);
} catch (InvalidArgumentException ex) {
ex.printStackTrace();
} catch (ParseException ex) {
ex.printStackTrace();
} catch (SipException ex) {
ex.printStackTrace();
}
}
public String waitForOK() throws Exception{
synchronized(stateLock){
while(getState() == INVITE_SENT){
try {
stateLock.wait();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
if(getState() == INVITE_OK){
return sdp;
}
else{
throw new Exception("Could not establish call");
}
}
}
/**
* Sends an ACK with the given sdp
* @param sdp String the SDP to use in the ACK
*/
public void sendAck(String sdp){
try {
SipUtil.sendAckWithSDP(ct, sdp);
setState(INVITE_ACK);
} catch (SipException ex) {
ex.printStackTrace();
} catch (ParseException ex) {
ex.printStackTrace();
}
}
public void processResponse(ResponseEvent responseEvent) {
Response resp = responseEvent.getResponse();
int status = resp.getStatusCode();
// We only handle the OK response for now
if(status == Response.OK && getState() == INVITE_SENT){
sdp = new String(resp.getRawContent());
synchronized(stateLock){
setState(INVITE_OK);
stateLock.notify();
}
}
if(status > 400){ // All status codes > 400 are errors
synchronized(stateLock){
setState(TERMINATED);
stateLock.notifyAll();
}
}
}
public void processTimeout(TimeoutEvent timeoutEvent) {
// Any timeout is considered a failure. We terminate the call
sendBye();
setState(TERMINATED);
if(otherCall != null){
otherCall.sendBye();
}
}
public void processRequest(RequestEvent requestEvent) {
Request req = requestEvent.getRequest();
if(req.getMethod().equals(Request.BYE) && getState() == INVITE_ACK){
setState(TERMINATED);
if(otherCall != null){
otherCall.sendBye();
}
SipServer.getSipServerCallback().removeSipListener(sipCallId);
}
try {
sipUtil.sendOK(req, requestEvent.getServerTransaction());
} catch (TransactionDoesNotExistException ex) {
ex.printStackTrace();
} catch (ParseException ex) {
ex.printStackTrace();
} catch (SipException ex) {
ex.printStackTrace();
}
}
public void setOtherCall(DirectOutgoingCallHandler ot){
otherCall = ot;
}
public DirectOutgoingCallHandler getOtherCall(){
return otherCall;
}
public void sendBye(){
try {
sipUtil.sendBye(ct);
setState(TERMINATED);
SipServer.getSipServerCallback().removeSipListener(sipCallId);
} catch (TransactionDoesNotExistException ex) {
ex.printStackTrace();
} catch (InvalidArgumentException ex) {
ex.printStackTrace();
} catch (ParseException ex) {
ex.printStackTrace();
} catch (SipException ex) {
ex.printStackTrace();
}
}
public void waitForTerminate() {
while(true){
if(getState() == TERMINATED){
return;
}
synchronized(stateLock){
try {
stateLock.wait();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
public void setState(int st){
synchronized(stateLock){
state = st;
stateLock.notifyAll();
}
}
public int getState(){
return state;
}
public void processDialogTerminated(DialogTerminatedEvent dte) {
if (Logger.logLevel >= Logger.LOG_SIP) {
Logger.println("processDialogTerminated called");
}
}
public void processTransactionTerminated(TransactionTerminatedEvent tte) {
if (Logger.logLevel >= Logger.LOG_SIP) {
Logger.println("processTransactionTerminated called");
}
}
public void processIOException(IOExceptionEvent ioee) {
if (Logger.logLevel >= Logger.LOG_SIP) {
Logger.println("processTransactionTerminated called");
}
}
}