/** * Copyright 2010 Voxeo Corporation Licensed under the Apache License, Version * 2.0 (the "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law * or agreed to in writing, software distributed under the License is * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ package com.voxeo.moho.sip; import java.util.Map; import javax.media.mscontrol.MsControlException; import javax.media.mscontrol.join.Joinable.Direction; import javax.servlet.sip.SipServletRequest; import javax.servlet.sip.SipServletResponse; import org.apache.log4j.Logger; import com.voxeo.moho.Participant.JoinType; import com.voxeo.moho.event.JoinCompleteEvent; import com.voxeo.moho.sip.SIPCall.State; public class DirectNO2NOJoinDelegate extends JoinDelegate { private static final Logger LOG = Logger.getLogger(DirectNO2NOJoinDelegate.class); protected SipServletResponse _responseCall2; protected SipServletResponse _reliable183RespCall2; protected SipServletResponse _responseCall1; protected Direction _direction; protected boolean _invitedCall1; protected boolean _ackedCall2; protected boolean _ackedCall1; protected Object respSyncLock = new Object(); protected DirectNO2NOJoinDelegate(final SIPOutgoingCall call1, final SIPOutgoingCall call2, final Direction direction, final SIPOutgoingCall peer) { _call1 = call1; _call2 = call2; _direction = direction; _peer = peer; } @Override public void doJoin() throws Exception { super.doJoin(); // TODO try to disable 183 by removing 100rel. should we disable 183 here? // should we use mock SDP (SDP connection address 0.0.0.0 or with sendonly // atrribute) to disable 183 here? SIPHelper.remove100relSupport(_call2.getSipInitnalRequest()); SIPHelper.remove100relSupport(_call1.getSipInitnalRequest()); ((SIPOutgoingCall) _call2).call(null); } @Override protected void doInviteResponse(final SipServletResponse res, final SIPCallImpl call, final Map<String, String> headers) throws Exception { try { synchronized (respSyncLock) { if (_call2.equals(call)) { if (SIPHelper.isProvisionalResponse(res)) { call.setSIPCallState(SIPCall.State.ANSWERING); if (res.getStatus() == SipServletResponse.SC_SESSION_PROGRESS) { if (SIPHelper.getRawContentWOException(res) != null && SIPHelper.needPrack(res)) { _reliable183RespCall2 = res; ((SIPOutgoingCall) _call1).setContinueRouting(_call2); ((SIPOutgoingCall) _call1).call(res.getRawContent(), _call2.getSipSession().getApplicationSession()); _invitedCall1 = true; } else { SIPHelper.trySendPrack(res); } } else { SIPHelper.trySendPrack(res); } } else if (SIPHelper.isSuccessResponse(res)) { _responseCall2 = res; if (!_invitedCall1) { ((SIPOutgoingCall) _call1).setContinueRouting(_call2); ((SIPOutgoingCall) _call1).call(res.getRawContent(), _call2.getSipSession().getApplicationSession()); } else if (_responseCall1 != null) { SipServletRequest ackCall2 = res.createAck(); if (SIPHelper.getRawContentWOException(res) != null) { SIPHelper.copyContent(_responseCall1, ackCall2); } ackCall2.send(); _ackedCall2 = true; _call2.setSIPCallState(State.ANSWERED); if (_ackedCall1) { successJoin(); } } } else if (SIPHelper.isErrorResponse(res)) { Exception ex = getExceptionByResponse(res); done(getJoinCompleteCauseByResponse(res), ex); disconnectCall(_call2, true, getCallCompleteCauseByResponse(res), ex); disconnectCall(_call1, true, getCallCompleteCauseByResponse(res), ex); } } else if (_call1.equals(call)) { if (SIPHelper.isProvisionalResponse(res)) { call.setSIPCallState(SIPCall.State.ANSWERING); if (res.getStatus() == SipServletResponse.SC_SESSION_PROGRESS) { if (SIPHelper.getRawContentWOException(res) != null) { _responseCall1 = res; if (_responseCall2 != null) { SipServletRequest ack2 = _responseCall2.createAck(); if (SIPHelper.getRawContentWOException(_responseCall2) != null) { SIPHelper.copyContent(res, ack2); } ack2.send(); _ackedCall2 = true; _call2.setSIPCallState(State.ANSWERED); } else if (_reliable183RespCall2 != null) { SipServletRequest call2Prack = _reliable183RespCall2.createPrack(); SIPHelper.copyContent(res, call2Prack); call2Prack.send(); } } } SIPHelper.trySendPrack(res); } else if (SIPHelper.isSuccessResponse(res)) { if (_responseCall1 == null) { _responseCall1 = res; } final SipServletRequest ack1 = res.createAck(); ack1.send(); _call1.setSIPCallState(State.ANSWERED); _ackedCall1 = true; if (!_ackedCall2) { if (_responseCall2 != null) { SipServletRequest ack2 = _responseCall2.createAck(); if (SIPHelper.getRawContentWOException(_responseCall2) != null) { SIPHelper.copyContent(res, ack2); } ack2.send(); _call2.setSIPCallState(State.ANSWERED); _ackedCall2 = true; successJoin(); } else if (_reliable183RespCall2 != null) { SipServletRequest call2Prack = _reliable183RespCall2.createPrack(); SIPHelper.copyContent(res, call2Prack); call2Prack.send(); } } else { successJoin(); } } else if (SIPHelper.isErrorResponse(res)) { Exception ex = getExceptionByResponse(res); done(getJoinCompleteCauseByResponse(res), ex); disconnectCall(_call1, true, getCallCompleteCauseByResponse(res), ex); disconnectCall(_call2, true, getCallCompleteCauseByResponse(res), ex); } } } } catch (final Exception e) { done(JoinCompleteEvent.Cause.ERROR, e); failCall(_call1, e); failCall(_call2, e); throw e; } } private void successJoin() throws MsControlException { _call1.linkCall(_call2, JoinType.DIRECT, _direction); done(JoinCompleteEvent.Cause.JOINED, null); } }