/* * Created on Aug 10, 2005 * *Copyright Reliable Response, 2005 */ package net.reliableresponse.notification.sip; import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.io.IOException; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.UnknownHostException; import java.text.ParseException; import java.util.Vector; import javax.media.NoDataSinkException; import javax.media.NoDataSourceException; import javax.media.NoProcessorException; import javax.media.NotConfiguredError; import javax.media.NotRealizedError; import javax.media.rtp.InvalidSessionAddressException; import javax.media.rtp.SessionAddress; import javax.sdp.Media; import javax.sdp.MediaDescription; import javax.sdp.SdpConstants; import javax.sdp.SdpException; import javax.sdp.SdpFactory; import javax.sdp.SdpParseException; import javax.sdp.SessionDescription; import javax.sip.ClientTransaction; import javax.sip.InvalidArgumentException; import javax.sip.PeerUnavailableException; import javax.sip.RequestEvent; import javax.sip.ResponseEvent; import javax.sip.SipException; import javax.sip.SipFactory; import javax.sip.SipStack; import javax.sip.Transaction; import javax.sip.TransactionUnavailableException; import javax.sip.header.CSeqHeader; import javax.sip.header.ContentTypeHeader; import javax.sip.message.Message; import javax.sip.message.Request; import javax.sip.message.Response; import net.reliableresponse.notification.broker.BrokerFactory; import net.reliableresponse.notification.tts.FreeTTS; /** * @author drig * * Copyright 2004 - David Rudder */ public class SipOutboundCall extends SipCall implements RequestListener, ResponseListener, DTMFListener, SilenceListener { int remotePort; String remoteHost; int localMediaPort; SipStack sipStack; SipFactory sipFactory; FreeTTS tts; boolean initialized; SilenceDelayThread silenceThread; public SipOutboundCall(String host, int port) { remoteHost = host; remotePort = port; tts = new FreeTTS(); sipHandler = SipHandler.getInstance(host, port); sipHandler.setRemoteHost(host); sipHandler.setRemotePort(port); localMediaPort = -1; try { DatagramSocket socket = new DatagramSocket(); localMediaPort = socket.getLocalPort(); socket.disconnect(); socket.close(); initRTP(localMediaPort); } catch (Exception e1) { BrokerFactory.getLoggingBroker().logError(e1); } //sipHandler.addRequestListener(this); //sipHandler.addResponseListener(this); sipHandler.addDTMFListener(this); addSilenceListener(this); sipFactory = SipFactory.getInstance(); initialized = false; } /** * @throws ParseException * @throws PeerUnavailableException * @throws InvalidArgumentException * @throws TransactionUnavailableException * @throws SipException */ void makeCall(String recipient) throws ParseException, PeerUnavailableException, InvalidArgumentException, TransactionUnavailableException, SipException { if (!initialized) { sipHandler.init(); initialized = true; } sipHandler.setCallID(System.currentTimeMillis()+ "@" + sipHandler.getLocalHost()); this.recipient = recipient; sendInitialInvite(recipient); } /** * @param localMediaPort * @throws ParseException * @throws PeerUnavailableException * @throws InvalidArgumentException * @throws TransactionUnavailableException * @throws SipException */ private void sendInitialInvite(String recipient) throws ParseException, PeerUnavailableException, InvalidArgumentException, TransactionUnavailableException, SipException { BrokerFactory.getLoggingBroker().logDebug("Calling " + recipient+" at "+remoteHost); ContentTypeHeader contentTypeHeader = null; //content type should be application/sdp (not applications) //reported by Oleg Shevchenko (Miratech) contentTypeHeader = sipFactory.createHeaderFactory() .createContentTypeHeader("application", "sdp"); String sdpContent = "v=0\n" + "o="+sipHandler.getUsername()+" 0 0 IN IP4 " + SipHandler.getInstance().getLocalHost() + "\n" + "s=-\n" + "c=IN IP4 " + SipHandler.getInstance().getLocalHost() + "\n" + "t=0 0\n" + "m=audio " + localMediaPort + " RTP/AVP 4 3 0 5 6 8 15 18\n" + "a=sendrecv\n" + "a=rtpmap:101 telephone-event/8000 \n" + "a=fmtp:101 64\n" + "a=rtpmap:0 PCMU/8000\n"; BrokerFactory.getLoggingBroker().logDebug("sdpContent ="+sdpContent); sipHandler.sendRequest(recipient, Request.INVITE, sdpContent, contentTypeHeader); } public void handleRequest(RequestEvent requestEvent) { Request request =requestEvent.getRequest(); BrokerFactory.getLoggingBroker().logDebug("Got request in SipOutboundCall "+request); String method = ((CSeqHeader) request.getHeader(CSeqHeader.NAME)).getMethod(); if (method.equals (Request.BYE)) { hangup(); } } public void handleResponse(ResponseEvent responseEvent) { Response response = responseEvent.getResponse(); BrokerFactory.getLoggingBroker().logDebug("Got response in SipOutboundCall "+response); String method = ((CSeqHeader) response.getHeader(CSeqHeader.NAME)) .getMethod(); ClientTransaction clientTransaction = responseEvent .getClientTransaction(); try { if (response.getStatusCode() == Response.OK) { if (method.equals(Request.INVITE)) { if (clientTransaction != null) { Request ack = (Request) clientTransaction.getDialog() .createRequest(Request.ACK); clientTransaction.getDialog().sendAck(ack); startConversation(response, clientTransaction); } } else if (method.equals(Request.ACK)) { System.out.println("Got ack"); } } else if ((response.getStatusCode() == Response.BUSY_HERE) || (response.getStatusCode() == Response.BUSY_EVERYWHERE)) { hangup(); } } catch (Exception e) { BrokerFactory.getLoggingBroker().logError(e); } } /** * @param response * @param clientTransaction * @throws SipException * @throws SdpParseException * @throws SdpException * @throws IOException * @throws NoDataSourceException * @throws NoProcessorException * @throws InterruptedException * @throws NotConfiguredError * @throws NotRealizedError * @throws NoDataSinkException * @throws InvalidSessionAddressException * @throws UnknownHostException */ void startConversation(Message response, Transaction clientTransaction) throws SipException, SdpParseException, SdpException, IOException, NoDataSourceException, NoProcessorException, InterruptedException, NotConfiguredError, NotRealizedError, NoDataSinkException, InvalidSessionAddressException, UnknownHostException { System.out.println("Starting conversation"); String sdpData = new String(response.getRawContent()); SdpFactory sdpFactory = new SdpFactory(); SessionDescription sessionDescription = sdpFactory .createSessionDescription(sdpData); Vector mediaDescriptions = sessionDescription .getMediaDescriptions(true); BrokerFactory.getLoggingBroker().logDebug("We have "+mediaDescriptions.size()+" media descriptions"); for (int mdNum = 0; mdNum < mediaDescriptions.size(); mdNum++) { MediaDescription mediaDescription = (MediaDescription) mediaDescriptions .elementAt(mdNum); Media media = mediaDescription.getMedia(); String proto = media.getProtocol(); String type = media.getMediaType(); int port = media.getMediaPort(); Vector formats = media.getMediaFormats(true); if (formats.size() < 1) { BrokerFactory.getLoggingBroker().logWarn( "In SIP outbound call: No audio formats"); } int sdpFormat = SdpConstants.PCMU; try { sdpFormat = Integer.parseInt((String) formats.elementAt(0)); } catch (NumberFormatException nfExc) { nfExc.printStackTrace(); } transmitter = new RtpTransmitter(remoteHost, port, sdpFormat); startReceiver(remoteHost, port); BrokerFactory.getLoggingBroker().logDebug("Starting transmitter"); transmitter = new RtpTransmitter(remoteHost, port, sdpFormat); BrokerFactory.getLoggingBroker().logDebug("transmitter="+transmitter); } } private void startReceiver(String remoteHost, int localPort) throws InvalidSessionAddressException, IOException, UnknownHostException { BrokerFactory.getLoggingBroker().logDebug( "Starting conversation on " + localMediaPort+" to "+remoteHost+":"+localPort); SessionAddress remoteAddress = new SessionAddress(InetAddress .getByName(remoteHost), localPort); rtpManager.addTarget(remoteAddress); } public void handleDTMF(String digit) { transmitter.playFromInputStream(new ByteArrayInputStream(tts.getWav("You pressed "+digit)), "audio.x_wav"); } public void handleSilenceStart() { // TODO Auto-generated method stub silenceThread = new SilenceDelayThread(this); silenceThread.start(); } public void handleSilenceEnd() { // TODO Auto-generated method stub if (silenceThread != null) { silenceThread.stopDelay(); } } public static void main(String[] args) throws Exception { BrokerFactory.getConfigurationBroker().setConfiguration( new FileInputStream("conf/reliable.properties")); SipOutboundCall out; if (args.length >= 1) { out = new SipOutboundCall("sys1a.TelecomMatters.net", 5060); out.setRegistrarHost("sys1a.TelecomMatters.net"); out.setRegistrarPort(5060); out.setRegistrarDomain("asterisk"); out.setUsername("daverudder"); out.setPassword("3035421990"); BrokerFactory.getLoggingBroker().logDebug("Making call"); out.makeCall("sip:93035689253@sys1a.TelecomMatters.net:5060"); } else { out = new SipOutboundCall("10.10.10.5", 5060); out.setUsername("daverudder"); //out.makeCall("sip:reliableresponse@10.10.10.5:5060"); // Thread.sleep(4000); // char[] phoneNumber = "97025308877".toCharArray(); // for (int p = 0; p < phoneNumber.length; p++) { // out.sendDTMF(Integer.parseInt(phoneNumber[p]+"")); // } out.makeCall("sip:1990@10.10.10.5:5060"); //out.makeCall("tel:+97205308877"); } // new BufferedReader(new InputStreamReader(System.in)).readLine(); // out.hangup(); } } class SilenceDelayThread extends Thread { SipOutboundCall call; boolean stopped; public SilenceDelayThread (SipOutboundCall call) { this.call = call; stopped = false; } public void run() { int seconds = 0; BrokerFactory.getLoggingBroker().logDebug("Starting silence checker"); while ((seconds < 15) && (!stopped)) { try { Thread.sleep(1000); seconds++; } catch (InterruptedException e) { BrokerFactory.getLoggingBroker().logError(e); } } if (!stopped) { call.hangup(); } } public void stopDelay() { BrokerFactory.getLoggingBroker().logDebug("Stopping silence checker"); stopped = true; } }