/** * 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.io.IOException; import java.util.Map; import javax.media.mscontrol.join.Joinable; import javax.media.mscontrol.join.Joinable.Direction; import javax.media.mscontrol.networkconnection.SdpPortManagerEvent; import javax.servlet.sip.Rel100Exception; import javax.servlet.sip.SipServletMessage; import javax.servlet.sip.SipServletRequest; import javax.servlet.sip.SipServletResponse; import org.apache.log4j.Logger; import com.voxeo.moho.Constants; import com.voxeo.moho.NegotiateException; import com.voxeo.moho.SignalException; import com.voxeo.moho.event.JoinCompleteEvent; import com.voxeo.moho.event.JoinCompleteEvent.Cause; import com.voxeo.moho.util.SDPUtils; public class Media2NOJoinDelegate extends JoinDelegate { private static final Logger LOG = Logger.getLogger(Media2NOJoinDelegate.class); protected boolean processedAnswer = false; protected SipServletResponse _response; protected SipServletResponse _earlyMediaResponse; protected SipServletRequest _updateRequest; protected Media2NOJoinDelegate(final SIPOutgoingCall call) { _call1 = call; } @Override protected void doUpdate(SipServletRequest req, SIPCallImpl call, Map<String, String> headers) throws Exception { if (call.equals(_call1) && req.getRawContent() != null) { _updateRequest = req; call.processSDPOffer(req); } else if (req.getRawContent() == null) { req.createResponse(SipServletResponse.SC_OK).send(); } else { LOG.error("call received UPDATE request in wrong state." + call + " " + req); req.createResponse(SipServletResponse.SC_SERVER_INTERNAL_ERROR).send(); } } @Override public void doJoin() throws Exception { super.doJoin(); _call1.processSDPOffer((SipServletMessage) null); } @Override protected void doSdpEvent(final SdpPortManagerEvent event) { if (event.getEventType().equals(SdpPortManagerEvent.OFFER_GENERATED) || event.getEventType().equals(SdpPortManagerEvent.ANSWER_GENERATED)) { if (event.isSuccessful()) { try { if (_updateRequest != null) { SipServletResponse updateResponse = _updateRequest.createResponse(200); _updateRequest = null; updateResponse.setContent(SDPUtils.formulateSDP(_call1, event.getMediaServerSdp()), "application/sdp"); updateResponse.send(); return; } else { final byte[] sdp = event.getMediaServerSdp(); _call1.setLocalSDP(sdp); ((SIPOutgoingCall) _call1).call(sdp); return; } } catch (final Exception e) { done(Cause.ERROR, e); _call1.fail(e); } } else { if (_updateRequest != null) { LOG.error("call received fail SdpPortManagerEvent when processing UPDATE." + _call1 + " " + event); try { _updateRequest.createResponse(SipServletResponse.SC_SERVER_INTERNAL_ERROR).send(); _updateRequest = null; } catch (Exception ex) { LOG.error("Exception when sending response", ex); } } } Exception ex = new NegotiateException(event); done(Cause.ERROR, ex); _call1.fail(ex); } else if (event.getEventType().equals(SdpPortManagerEvent.ANSWER_PROCESSED)) { if (event.isSuccessful()) { if (processedAnswer && _call1.getSIPCallState() == SIPCall.State.ANSWERED) { try { _response.createAck().send(); done(JoinCompleteEvent.Cause.JOINED, null); } catch (IOException e) { LOG.error("IOException when sending back ACK", e); Exception ex = new NegotiateException(e); done(Cause.ERROR, ex); _call1.fail(ex); } } else if (processedAnswer && _call1.getSIPCallState() == SIPCall.State.PROGRESSING) { // accept early media if (_earlyMediaResponse.getAttribute(Constants.Attribute_AcceptEarlyMedia) != null && _call1.getJoiningPeer() != null) { try { // bridge join peer is not null if (_call1.getJoiningPeer().getParticipant().getMediaObject() == null) { if (_call1.getJoiningPeer().getParticipant() instanceof SIPIncomingCall) { SIPIncomingCall incomingCall = (SIPIncomingCall) _call1.getJoiningPeer().getParticipant(); if (incomingCall.getSIPCallState() == SIPCall.State.INVITING || incomingCall.getSIPCallState() == SIPCall.State.RINGING) { ((SIPIncomingCall) _call1.getJoiningPeer().getParticipant()).answer(); } } else { ((SIPOutgoingCall) _call1.getJoiningPeer().getParticipant()).join().get(); } } if (_call1.getMediaObject() instanceof Joinable && _call1.getJoiningPeer().getParticipant().getMediaObject() instanceof Joinable) { JoinDelegate.bridgeJoin(_call1, _call1.getJoiningPeer().getParticipant(), Direction.DUPLEX); } // direct join peer is not null and peer is a not-answerd incoming // call, accept with early media. and join two networkconnection } catch (final Exception e) { throw new SignalException(e); } } _call1.setSIPCallState(SIPCall.State.PROGRESSED); _call1.notify(); if (_earlyMediaResponse != null) { SipServletResponse resp = _earlyMediaResponse; _earlyMediaResponse = null; try { SIPHelper.trySendPrack(resp); } catch (IOException e) { LOG.error("Exception when sending back PRACK", e); Exception ex = new NegotiateException(event); done(Cause.ERROR, ex); _call1.fail(ex); } } } return; } Exception ex = new NegotiateException(event); done(Cause.ERROR, ex); _call1.fail(ex); } Exception ex = new NegotiateException(event); done(Cause.ERROR, ex); _call1.fail(ex); } @Override protected void doInviteResponse(final SipServletResponse res, final SIPCallImpl call, final Map<String, String> headers) throws Exception { try { if (SIPHelper.isProvisionalResponse(res)) { _call1.setSIPCallState(SIPCall.State.ANSWERING); if (SIPHelper.getRawContentWOException(res) != null && SIPHelper.needPrack(res)) { if (_earlyMediaResponse != null) { return; } _earlyMediaResponse = res; _call1.setSIPCallState(SIPCall.State.PROGRESSING); if (!processedAnswer) { processedAnswer = true; _call1.processSDPAnswer(res); } else { SIPHelper.trySendPrack(res); } } else { SIPHelper.trySendPrack(res); } } else if (SIPHelper.isSuccessResponse(res)) { _call1.setSIPCallState(SIPCall.State.ANSWERED); _response = res; if (!processedAnswer) { processedAnswer = true; _call1.processSDPAnswer(res); } else { res.createAck().send(); done(JoinCompleteEvent.Cause.JOINED, null); } } else if (SIPHelper.isErrorResponse(res)) { Exception e = getExceptionByResponse(res); done(this.getJoinCompleteCauseByResponse(res), e); call.disconnect(true, getCallCompleteCauseByResponse(res), e, null); } } catch (final Exception e) { done(Cause.ERROR, e); _call1.fail(e); throw e; } } }