package com.voxeo.tropo.core; import javax.servlet.sip.SipApplicationSession; import javax.servlet.sip.SipFactory; import javax.servlet.sip.SipServletRequest; import org.apache.log4j.Logger; import com.voxeo.tropo.ErrorException; import com.voxeo.tropo.app.Application; import com.voxeo.tropo.app.ApplicationInstance; import com.voxeo.tropo.util.MrcpRTCCallback; import com.voxeo.tropo.util.MrcpRTCListener; import com.voxeo.tropo.util.Utils; public class SimpleCallFactory implements CallFactory { private static final Logger LOG = Logger.getLogger(SimpleCallFactory.class); protected SipApplicationSession _session; protected ApplicationInstance _inst; protected Application _app; protected SipFactory _sipFactory; public SimpleCallFactory(final ApplicationInstance inst) { _inst = inst; _app = inst.getApp(); _session = inst.getApplicationSession(); _sipFactory = _app.getManager().getSipFactory(); } public SimpleCallFactory(final Application app, final SipApplicationSession session) { _session = session; _sipFactory = app.getManager().getSipFactory(); _app = app; } public SimpleOutgoingCall call(final String from, final String to, final boolean answerOnMedia, final int timeout, final String callRecordUri, final String callRecordFormat) { return call(null, from, to, answerOnMedia, timeout, null, callRecordUri, callRecordFormat); } public SimpleOutgoingCall call(final SipServletRequest origReq, final String from, final String to, final boolean answerOnMedia, final int timeout, final MrcpRTCListener listener, final String callRecordUri, final String callRecordFormat) { final SimpleOutgoingCall call; String caller = Utils.processFrom(from, origReq == null ? null : origReq.getLocalAddr()); if ((caller == null || caller.length() == 0) && origReq != null) { caller = origReq.getFrom().toString(); } final String callee = Utils.processTo(to); LOG.info("Creating outgoing call : " + caller + "-->" + callee + "," + answerOnMedia + "," + timeout); try { final SipServletRequest req = _sipFactory.createRequest(_session, "INVITE", caller, callee); if (_inst != null) { call = new SimpleOutgoingCall(this, origReq == null ? null : origReq, req, answerOnMedia, _inst); } else { call = new SimpleOutgoingCall(this, origReq == null ? null : origReq, req, answerOnMedia, _app); } if (listener != null) { if (!listener.isStarted()) { throw new ErrorException("Outbound call cancelled."); } listener.setCallback(new MrcpRTCCallback() { public void invoke() { call.hangup(); } }); } req.send(); LOG.info(call + " is calling."); if (LOG.isDebugEnabled()) { LOG.debug(call + "->sending outgoing INVITE [timeout:" + timeout + ",answerOnMedia:" + answerOnMedia + "]:\r\n" + req); } final long start = System.currentTimeMillis(); long time = timeout; call.lock(); try { while ((call.getState() == Call.State.RINGING || call.getState() == Call.State.ANSWERING) && time > 0) { time = timeout - (System.currentTimeMillis() - start); call.await(time); } if (time <= 0 && (call.getState() == Call.State.RINGING || call.getState() == Call.State.ANSWERING)) { call.hangup(); throw new ErrorException("Outbound call is timeout."); } if (call.getState() != Call.State.ANSWERED) { LOG.error(call + " can not be completed at this time."); if (listener != null && !listener.isStarted()) { throw new ErrorException("Outbound call cancelled."); } throw new ErrorException("Outbound call can not complete."); } LOG.info(call + " is answered."); if (callRecordUri != null && callRecordUri.length() > 0) { call.startCallRecording(callRecordUri, callRecordFormat, null, null); } } finally { call.unlock(); } return call; } catch (final ErrorException e) { throw e; } catch (final Throwable e) { LOG.error("Error creating outgoing call to " + to + " : " + e.getMessage(), e); throw new ErrorException(e); } } }