package com.voxeo.tropo.core;
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.SipServletResponse;
import org.apache.log4j.Logger;
import com.voxeo.tropo.ErrorException;
import com.voxeo.tropo.FatalException;
import com.voxeo.tropo.ServletContextConstants;
import com.voxeo.tropo.app.Application;
import com.voxeo.tropo.app.ApplicationInstance;
import com.voxeo.tropo.util.Utils;
import com.voxeo.sipmethod.mrcp.client.Endpoint;
public class SimpleIncomingCall extends SimpleCall implements IncomingCall {
private static final Logger LOG = Logger.getLogger(SimpleIncomingCall.class);
public SimpleIncomingCall(final SimpleCallFactory callFactory, final SipServletRequest invite, final ApplicationInstance inst) {
super(callFactory, invite, inst);
init();
}
public SimpleIncomingCall(final SimpleCallFactory callFactory, final SipServletRequest invite, final Application app) {
super(callFactory, invite, app);
init();
}
void init() {
setState(State.RINGING);
if (LOG.isDebugEnabled()) {
LOG.debug(this + "->got INVITE:\r\n" + _invite);
}
LOG.info(this + " is received.");
}
public void answer(final int timeout) {
LOG.info(this + "->answer(" + timeout + ")");
try {
initMrcpClient(new Endpoint(_invite.getRemoteAddr(), _invite.getRemotePort(), _invite.getContent().toString()),
_sipSession.getApplicationSession());
final long start = System.currentTimeMillis();
long time = timeout;
lock();
try {
if (_state == State.RINGING || _state == State.ANSWERING) {
setState(Call.State.ANSWERING);
}
else {
throw new FatalException("Expected Ringing or Answering state: " + _state);
}
final String content = getASR().getMrcpEndpoint().getSdp();
final SipServletResponse response = _invite.createResponse(SipServletResponse.SC_OK);
response.setContent(content, ServletContextConstants.CONTENT_TYPE_SDP);
response.send();
LOG.info(this + " is answering.");
while ((_state == State.RINGING || _state == State.ANSWERING) && time > 0) {
time = timeout - (System.currentTimeMillis() - start);
await(time);
}
if (time <= 0 && _state != State.ANSWERED) {
throw new ErrorException("Can not answer within " + timeout + "ms.");
}
assertReady("answer", Call.State.ANSWERED);
LOG.info(this + " is answered.");
}
finally {
unlock();
}
}
catch (final Throwable t) {
lock();
try {
if (_state == State.RINGING || _state == State.ANSWERING) {
try {
_invite.createResponse(SipServletResponse.SC_SERVER_INTERNAL_ERROR).send();
}
catch (final Throwable t1) {
;
}
setState(State.FAILED);
}
}
finally {
unlock();
}
handleException(t, "answer");
}
}
public void reject() {
LOG.info(this + "->reject()");
lock();
try {
if (_state == State.RINGING || _state == State.ANSWERING) {
setState(Call.State.REJECTING);
_invite.createResponse(SipServletResponse.SC_DECLINE).send();
LOG.info(this + " has been rejected.");
}
else if (_state == State.REJECTING || _state == State.REJECTED) {
;
}
else {
LOG.error(this + " can not be rejected in " + _state + " state.");
throw new ErrorException(this + " can not be rejected in " + _state + " state.");
}
}
catch (final Throwable t) {
handleException(t, "reject");
}
finally {
unlock();
}
}
public void redirect(String number) {
LOG.info(this + "->redirect(" + number + ")");
number = Utils.processTo(number);
lock();
try {
if (_state == State.RINGING || _state == State.ANSWERING) {
setState(Call.State.REDIRECTING);
final SipServletResponse response = _invite.createResponse(SipServletResponse.SC_MOVED_TEMPORARILY);
response.addHeader("Contact", number);
response.send();
LOG.info(this + " has been redirected to " + number);
}
else if (_state == State.REDIRECTING || _state == State.REDIRECTED) {
;
}
else {
LOG.error(this + " can not be redirected in " + _state + " state.");
throw new ErrorException("Expected Ringing or Answering state: " + _state);
}
}
catch (final Throwable t) {
handleException(t, "redirect");
}
finally {
unlock();
}
}
@Override
protected void stateChanged(final State oldState, final State newState) {
if (!_stateLock.isHeldByCurrentThread()) {
throw new IllegalStateException("The caller must hold the lock first.");
}
if (LOG.isDebugEnabled()) {
LOG.debug(this.toString() + " state is changed: " + oldState + "->" + newState);
}
if (oldState == Call.State.ANSWERING
&& (newState == Call.State.ANSWERED || newState == Call.State.FAILED || newState == Call.State.DISCONNECTED)) {
signal(null);
}
super.stateChanged(oldState, newState);
}
}