/* * Copyright 2007 Sun Microsystems, Inc. * * This file is part of jVoiceBridge. * * jVoiceBridge is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation and distributed hereunder * to you. * * jVoiceBridge is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Sun designates this particular file as subject to the "Classpath" * exception as provided by Sun in the License file that accompanied this * code. */ package com.sun.voip.server; import com.sun.voip.CallParticipant; import com.sun.voip.CallState; import com.sun.voip.Logger; import com.sun.voip.MediaInfo; import com.sun.voip.RtpPacket; import com.sun.voip.SdpInfo; import com.sun.voip.TreatmentManager; import java.io.IOException; import java.net.InetSocketAddress; import java.text.ParseException; /** * Non-Signaling handles calls setup by an external source. */ public class NSOutgoingCallAgent extends CallSetupAgent { private SipUtil sipUtil; private CallParticipant cp; private boolean callAnswered = false; private MediaInfo mixerMediaPreference; public NSOutgoingCallAgent(CallHandler callHandler) { super(callHandler); cp = callHandler.getCallParticipant(); mixerMediaPreference = callHandler.getConferenceManager().getMediaInfo(); sipUtil = new SipUtil(mixerMediaPreference); } public void initiateCall() throws IOException { InetSocketAddress isa = callHandler.getReceiveAddress(); if (isa == null) { throw new IOException("can't get receiver socket!"); } setState(CallState.INVITED); TreatmentManager treatmentManager = null; if (cp.getInputTreatment() != null) { if (cp.getInputTreatment().length() > 0) { try { /* * Just make sure we can open the file */ treatmentManager = new TreatmentManager(cp.getInputTreatment(), RtpPacket.PCM_ENCODING, mixerMediaPreference.getSampleRate(), mixerMediaPreference.getChannels()); treatmentManager.stopTreatment(false); } catch (IOException e) { Logger.println("Invalid input treatment: " + cp.getInputTreatment()); throw new IOException( "Invalid input treatment: " + cp.getInputTreatment()); } } /* * This is a special call which is used to play * an input treatment as its input. * There is no remote endpoint. */ try { setRemoteMediaInfo(treatmentManager); } catch (ParseException e) { throw new IOException(e.getMessage()); } } } public String getSdp() { InetSocketAddress isa; if (cp.getInputTreatment() != null) { isa = new InetSocketAddress(Bridge.getPrivateHost(), 0); } else { isa = callHandler.getReceiveAddress(); } return sipUtil.generateSdp(cp, isa); } public void setRemoteMediaInfo(String sdp) throws ParseException { if (getState() != CallState.INVITED) { Logger.println("Call " + cp + ": NSOutgoingCallAgent: bad state " + getState()); return; } sdp = sdp.replaceAll("\\+", "\r\n"); Logger.println("Call " + cp + ": NSOutgoingCallAgent: remote SDP: " + sdp); SdpInfo sdpInfo = sipUtil.getSdpInfo(sdp, false); MediaInfo mediaInfo = sdpInfo.getMediaInfo(); InetSocketAddress isa = new InetSocketAddress( sdpInfo.getRemoteHost(), sdpInfo.getRemotePort()); Logger.println("Call " + cp + ": NSOutgoingCallAgent: " + mediaInfo + " remote " + isa); setEndpointAddress(isa, mediaInfo.getPayload(), sdpInfo.getTransmitMediaInfo().getPayload(), sdpInfo.getTelephoneEventPayload()); if (callAnswered) { Logger.writeFile("Call " + cp + ": NSOutgoingCallAgent: done remote SDP"); return; } /* * The CallParticipant has answered. * If join confirmation is required, we remain in the * INVITED state. */ callAnswered = true; if (cp.getJoinConfirmationTimeout() == 0) { setState(CallState.ANSWERED); } /* * Start treatment if any and wait for it to finish. * When the treatment finishes, notification will * be delivered to our parent which will indicate * we're ready for the conference. * * If there's no treatment to be played, we're ready now * unless we're waiting for join confirmation.. */ initializeCallAnsweredTreatment(); if (callAnsweredTreatment != null) { startCallAnsweredTreatment(); } else { if (cp.getJoinConfirmationTimeout() == 0) { setState(CallState.ESTABLISHED); } } } /* * This is called for calls with an input treatment. * There is really no endpoint * and no data is ever sent to the call. * The looks like any other call but is used only as a source of sound. */ public void setRemoteMediaInfo(TreatmentManager treatmentManager) throws ParseException { if (getState() != CallState.INVITED) { Logger.println("Call " + cp + ": NSOutgoingCallAgent: bad state " + getState()); return; } MediaInfo mediaInfo = mixerMediaPreference; if (treatmentManager != null) { int sampleRate = treatmentManager.getSampleRate(); int channels = treatmentManager.getChannels(); try { mediaInfo = MediaInfo.findMediaInfo(RtpPacket.PCM_ENCODING, sampleRate, channels); } catch (IOException e) { Logger.println("Using conference media preference " + mediaInfo + ": " + e.getMessage()); } } InetSocketAddress isa = callHandler.getMember().getMemberReceiver().getReceiveAddress(); Logger.println("Call " + cp + ": NSOutgoingCallAgent: " + mediaInfo + " remote " + isa); setEndpointAddress(isa, mediaInfo.getPayload(), mediaInfo.getPayload(), (byte) 0); if (callAnswered) { Logger.writeFile("Call " + cp + ": NSOutgoingCallAgent: done remote SDP"); return; } /* * The CallParticipant has answered. * If join confirmation is required, we remain in the * INVITED state. */ callAnswered = true; if (cp.getJoinConfirmationTimeout() == 0) { setState(CallState.ANSWERED); } /* * Start treatment if any and wait for it to finish. * When the treatment finishes, notification will * be delivered to our parent which will indicate * we're ready for the conference. * * If there's no treatment to be played, we're ready now * unless we're waiting for join confirmation.. */ initializeCallAnsweredTreatment(); if (callAnsweredTreatment != null) { startCallAnsweredTreatment(); } else { if (cp.getJoinConfirmationTimeout() == 0) { setState(CallState.ESTABLISHED); } } } public void terminateCall() { } }