/** * 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.HashMap; import java.util.Map; import javax.media.mscontrol.MsControlException; import javax.sdp.SdpException; import javax.servlet.sip.SipServletRequest; import javax.servlet.sip.SipServletResponse; import org.apache.log4j.Logger; import com.voxeo.moho.sip.SIPCallImpl.HoldState; public class SIPCallDirectDelegate extends SIPCallDelegate { private static final Logger LOG = Logger.getLogger(SIPCallDirectDelegate.class); private static final String REINVITE_PEER_RES = "com.voxeo.moho.reinvite-peer-res"; protected SIPCallDirectDelegate() { super(); } @Override protected void handleAck(final SIPCallImpl call, final SipServletRequest req) throws Exception { final SipServletResponse res = (SipServletResponse) req.getSession().getAttribute(REINVITE_PEER_RES); final SipServletRequest newReq = res.createAck(); SIPHelper.copyContent(req, newReq); newReq.send(); } @Override protected void handleReinvite(final SIPCallImpl call, final SipServletRequest req, final Map<String, String> headers) throws Exception { final SIPCallImpl peer = (SIPCallImpl) call.getLastPeer(); final SipServletRequest newReq = peer.getSipSession().createRequest(req.getMethod()); SIPHelper.addHeaders(newReq, headers); SIPHelper.copyContent(req, newReq); SIPHelper.linkSIPMessage(req, newReq); newReq.send(); } @Override protected void handleUpdate(final SIPCallImpl call, final SipServletRequest req, final Map<String, String> headers) throws Exception { final SIPCallImpl peer = (SIPCallImpl) call.getLastPeer(); final SipServletRequest newReq = peer.getSipSession().createRequest(req.getMethod()); SIPHelper.addHeaders(newReq, headers); SIPHelper.copyContent(req, newReq); SIPHelper.linkSIPMessage(req, newReq); newReq.send(); } @Override protected void handleUpdateResponse(final SIPCallImpl call, final SipServletResponse res, final Map<String, String> headers) throws Exception { try { final SipServletRequest req = res.getRequest(); final SipServletRequest newReq = (SipServletRequest) SIPHelper.getLinkSIPMessage(req); if (newReq != null) { SIPHelper.unlinkSIPMessage(req); final SipServletResponse newRes = newReq.createResponse(res.getStatus(), res.getReasonPhrase()); SIPHelper.addHeaders(newRes, headers); SIPHelper.copyContent(res, newRes); newRes.send(); } else{ LOG.warn("Can't find linked request, discarding this response:"+ res); } } catch (final Exception e) { LOG.warn("", e); return; } } @Override protected void handleReinviteResponse(final SIPCallImpl call, final SipServletResponse res, final Map<String, String> headers) { if (res.getRequest().getAttribute(SIPCallDelegate.SIPCALL_HOLD_REQUEST) != null || res.getRequest().getAttribute(SIPCallDelegate.SIPCALL_UNHOLD_REQUEST) != null || res.getRequest().getAttribute(SIPCallDelegate.SIPCALL_DEAF_REQUEST) != null) { try { res.createAck().send(); if (call.getHoldState() == HoldState.Holding) { call.setHoldState(HoldState.Held); } else if (call.getHoldState() == HoldState.UnHolding) { call.setHoldState(HoldState.None); } else if (call.getDeafState() == HoldState.Deafing) { call.setDeafState(HoldState.Deafed); } else if (call.getDeafState() == HoldState.Undeafing) { call.setDeafState(HoldState.None); } } catch (IOException e) { LOG.error("IOException when sending back ACK.", e); call.setHoldState(HoldState.None); call.setDeafState(HoldState.None); call.fail(e); } finally { call.notify(); } } else if (res.getRequest().getAttribute(SIPCallDelegate.SIPCALL_MUTE_REQUEST) != null || res.getRequest().getAttribute(SIPCallDelegate.SIPCALL_UNMUTE_REQUEST) != null) { // send ACK. try { res.createAck().send(); // send the received SDP to peer. final SIPCallImpl peer = (SIPCallImpl) call.getLastPeer(); synchronized (peer) { if (call.getMuteState() == HoldState.Muting) { peer.setDeafState(HoldState.Deafing); } else { peer.setDeafState(HoldState.Undeafing); } Map<String, String> attributes = new HashMap<String, String>(); attributes.put(SIPCallDelegate.SIPCALL_DEAF_REQUEST, "true"); peer.reInviteRemote(res.getRawContent(), null, attributes); while (peer.getDeafState() != HoldState.Deafed && peer.getDeafState() != HoldState.None) { try { peer.wait(); } catch (InterruptedException e) { LOG.warn("InterruptedException when wait make peer deaf, the peer's DeafState " + peer.getDeafState()); } } // set call deaf state if (call.getMuteState() == HoldState.Muting) { peer.setDeafState(HoldState.Deafed); call.setMuteState(HoldState.Muted); } else if (call.getMuteState() == HoldState.UnMuting) { peer.setDeafState(HoldState.None); call.setMuteState(HoldState.None); } } } catch (Exception e1) { LOG.error("Exception", e1); call.setMuteState(HoldState.None); call.fail(e1); } finally { call.notify(); } } else { try { final SipServletRequest req = res.getRequest(); final SipServletRequest newReq = (SipServletRequest) SIPHelper.getLinkSIPMessage(req); if (newReq != null) { SIPHelper.unlinkSIPMessage(req); final SipServletResponse newRes = newReq.createResponse(res.getStatus(), res.getReasonPhrase()); SIPHelper.addHeaders(newRes, headers); SIPHelper.copyContent(res, newRes); if (SIPHelper.isReinvite(newRes)) { newRes.getSession().setAttribute(REINVITE_PEER_RES, res); } newRes.send(); } } catch (final Exception e) { LOG.warn("", e); return; } } } @Override protected void hold(SIPCallImpl call, boolean send) throws MsControlException, IOException, SdpException { final SIPCallImpl peer = (SIPCallImpl) call.getLastPeer(); Map<String, String> attributes = new HashMap<String, String>(); attributes.put(SIPCallDelegate.SIPCALL_HOLD_REQUEST, "true"); call.reInviteRemote(createSendonlySDP(call, peer.getRemoteSdp()), null, attributes); peer.hold(); } @Override protected void mute(SIPCallImpl call) throws MsControlException, IOException, SdpException { final SIPCallImpl peer = (SIPCallImpl) call.getLastPeer(); Map<String, String> attributes = new HashMap<String, String>(); attributes.put(SIPCallDelegate.SIPCALL_MUTE_REQUEST, "true"); call.reInviteRemote(createSendonlySDP(call, peer.getRemoteSdp()), null, attributes); } @Override protected void unhold(SIPCallImpl call) throws MsControlException, IOException, SdpException { final SIPCallImpl peer = (SIPCallImpl) call.getLastPeer(); Map<String, String> attributes = new HashMap<String, String>(); attributes.put(SIPCallDelegate.SIPCALL_UNHOLD_REQUEST, "true"); call.reInviteRemote(createSendrecvSDP(call, peer.getRemoteSdp()), null, attributes); peer.unhold(); } @Override protected void unmute(SIPCallImpl call) throws MsControlException, IOException, SdpException { final SIPCallImpl peer = (SIPCallImpl) call.getLastPeer(); Map<String, String> attributes = new HashMap<String, String>(); attributes.put(SIPCallDelegate.SIPCALL_UNMUTE_REQUEST, "true"); call.reInviteRemote(createSendrecvSDP(call, peer.getRemoteSdp()), null, attributes); } }