/* / Copyright (C) 2009 Risto Känsäkoski - Sesca ISW Ltd / / This file is part of SIP-Applet (www.sesca.com, www.purplescout.com) / This file is modified from MjSip (http://www.mjsip.org) / / This program is free software; you can redistribute it and/or / modify it under the terms of the GNU General Public License / as published by the Free Software Foundation; either version 2 / of the License, or (at your option) any later version. / / This program 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, write to the Free Software / Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package com.sesca.voip.media; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.DatagramSocket; import java.nio.channels.SocketChannel; import java.util.Enumeration; import java.util.Hashtable; import local.media.AudioOutput; import local.net.RtpPacket; import org.zoolu.net.IpAddress; import org.zoolu.sip.message.Message; import org.zoolu.sip.provider.ConnectionIdentifier; import org.zoolu.sip.provider.SipStack; import org.zoolu.sip.provider.Transport; import org.zoolu.sip.provider.TransportListener; import com.sesca.misc.Logger; import com.sesca.voip.transport.HttpTunnelTransport; import com.sesca.voip.ua.UserAgent; import com.sesca.misc.Logger; public class RtpHttpBridge implements TransportListener { // public Socket audiosocket; boolean running = false; UserAgent ua = null; Hashtable connections = null; String outbound_addr = null; int outbound_port = 0; int nmax_connections = 0; private InputStream input_stream = null; private int p_type; private long frame_rate; private int frame_size; private boolean do_sync; public SocketChannel audiochannel; private OutputStream output_stream = null; private AudioOutput ao; RtpPacket[] buffer = null; int bufferSize = 10; int bpointer = 0; int blockSize = 5; private boolean audioPaused = false; public void startTransport() { Logger.info("RtpHttpBridge.startTransport: http tunnel"); ConnectionIdentifier conn_id = new ConnectionIdentifier("tcp", new IpAddress(ua.user_profile.tunnelServer), ua.user_profile.tunnelPort); if(!connections.containsKey(conn_id)) { // printLog("no active connection found matching // "+conn_id,LogLevel.MEDIUM); // printLog("open "+proto+" connection to // "+dest_ipaddr+":"+dest_port,LogLevel.MEDIUM); HttpTunnelTransport conn = null; try { Logger.info("Luo HttpTunnelTransport:" + System.currentTimeMillis()); conn = new HttpTunnelTransport(new IpAddress(ua.user_profile.tunnelServer), ua.user_profile.tunnelPort, this); Logger.info("HttpTunnelTransport luotu:" + System.currentTimeMillis()); Logger.debug("conn=" + conn); } catch (Exception e) { Logger.warning("connection setup FAILED"); e.printStackTrace(); } Logger.info("connection " + conn + " opened"); Logger.info("Adding connection: " + conn); Logger.info("Lisää pooliin:" + System.currentTimeMillis()); addConnection(conn); Logger.info("Lisätty pooliin:" + System.currentTimeMillis()); Logger.debug(connections); } else { } Logger.info("Hae poolista:" + System.currentTimeMillis()); HttpTunnelTransport conn = (HttpTunnelTransport) connections.get(conn_id); Logger.info("Haettu poolista:" + System.currentTimeMillis()); if(conn != null) { try { Logger.info("Trying to open tunnel..."); Logger.info("Luo Http-viesti:" + System.currentTimeMillis()); Message msg = new Message("GET / HTTP/1.1\r\nUdpHost: " + IpAddress.getByName(outbound_addr) + ":" + outbound_port + "\r\n\r\n"); // conn.sendMessage(msg); Logger.info("Lähetä viesti:" + System.currentTimeMillis()); conn.sendMessage(msg.toString().getBytes(), true); Logger.info("Viesti lähetetty:" + System.currentTimeMillis()); Logger.info("Tunnel opened succesfully"); } catch (IOException e) { Logger.warning("Tunnel failed"); } } else { // this point has not to be reached Logger.warning("ERROR: conn " + conn_id + " not found: abort."); } Logger.info("RtpHttpBridge.startTransport exit"); } private void addConnection(HttpTunnelTransport conn) { Logger.info("addConnection: conn=" + conn); ConnectionIdentifier conn_id = new ConnectionIdentifier(conn); Logger.info("addConnection: conn_id=" + conn_id); if(connections.containsKey(conn_id)) { // remove the previous connection HttpTunnelTransport old_conn = (HttpTunnelTransport) connections.get(conn_id); old_conn.halt(); connections.remove(conn_id); } else if(connections.size() >= nmax_connections) { // remove the older unused connection long older_time = System.currentTimeMillis(); ConnectionIdentifier older_id = null; for (Enumeration e = connections.elements(); e.hasMoreElements();) { HttpTunnelTransport co = (HttpTunnelTransport) e.nextElement(); if(co.getLastTimeMillis() < older_time) older_id = new ConnectionIdentifier(co); } if(older_id != null) removeConnection(older_id); } connections.put(conn_id, conn); conn_id = new ConnectionIdentifier(conn); conn = (HttpTunnelTransport) connections.get(conn_id); // DEBUG log: Logger.debug("active connenctions:"); for (Enumeration e = connections.keys(); e.hasMoreElements();) { ConnectionIdentifier id = (ConnectionIdentifier) e.nextElement(); } } public void onReceivedMessage(Transport transport, Message msg) { Logger.warning("Tänne ei pitäisi koskaan tulla"); } public void onTransportTerminated(Transport transport, Exception error) { Logger.warning("Terminoitu"); if(ua != null) ua.onTunnelTerminated(); } private void removeConnection(ConnectionIdentifier conn_id) { Logger.info("removeConnection: " + conn_id); if(connections.containsKey(conn_id)) { HttpTunnelTransport conn = (HttpTunnelTransport) connections.get(conn_id); conn.halt(); connections.remove(conn_id); // DEBUG log: Logger.debug("active connenctions:"); for (Enumeration e = connections.elements(); e.hasMoreElements();) { HttpTunnelTransport co = (HttpTunnelTransport) e.nextElement(); Logger.debug("conn " + co.toString()); } } } private void init(InputStream input_stream, boolean do_sync, int payload_type, long frame_rate, int frame_size, DatagramSocket src_socket, /* * int * src_port, */String dest_addr, int dest_port) { // testing // skip = 0; // skipIndex=0; if(nmax_connections <= 0) nmax_connections = SipStack.default_nmax_connections; connections = new Hashtable(); this.outbound_addr = dest_addr; this.outbound_port = dest_port; this.input_stream = input_stream; this.p_type = payload_type; this.frame_rate = frame_rate; this.frame_size = frame_size; this.do_sync = do_sync; buffer = new RtpPacket[bufferSize]; startTransport(); /* * try * { if (src_socket==null) { //if (src_port>0) src_socket=new * DatagramSocket(src_port); else src_socket=new DatagramSocket(); * socket_is_local=true; } rtp_socket=new * RtpSocket(src_socket,InetAddress.getByName(dest_addr),dest_port); } * catch (Exception e) { e.printStackTrace(); } */ } public RtpHttpBridge(InputStream input_stream, boolean do_sync, int payload_type, long frame_rate, int frame_size, DatagramSocket src_socket, String dest_addr, int dest_port, SocketChannel audiochannel, UserAgent agent) { this.ua = agent; this.audiochannel = audiochannel; init(input_stream, do_sync, payload_type, frame_rate, frame_size, src_socket, dest_addr, dest_port); } public RtpHttpBridge(InputStream input_stream, boolean do_sync, int payload_type, long frame_rate, int frame_size, String dest_addr, int dest_port) { init(input_stream, do_sync, payload_type, frame_rate, frame_size, null, dest_addr, dest_port); } public void setOutputStream(OutputStream os) { this.output_stream = os; } public void setAudioOutput(AudioOutput ao) { this.ao = ao; } public boolean send(RtpPacket packet) { send2(packet.getPacket()); return true; } public boolean send(RtpPacket packet, RtpPacket packet2) { send2(packet.getPacket(), packet2.getPacket()); return true; } public void run() { if(bpointer >= blockSize) { int size = 0; for (int i = 0; i <= bpointer - 1; i++) { size += buffer[i].getLength(); } byte[] block = new byte[size + 4 * (bpointer + 1)]; int index = 0; for (int i = 0; i <= bpointer - 1; i++) { byte[] temp = buffer[i].getPacket(); int length = temp.length; block[index] = (byte) ((length >>> 0) & 0xFF); block[index + 1] = (byte) ((length >>> 8) & 0xFF); block[index + 2] = (byte) ((length >>> 16) & 0xFF); block[index + 3] = (byte) ((length >>> 24) & 0xFF); index += 4; for (int j = 0; j < temp.length; j++) { block[index] = temp[j]; index++; } } long a = System.currentTimeMillis(); send2(block); long b = System.currentTimeMillis(); Logger.debug(b - a + ""); bpointer = 0; } } public boolean send2(byte[] packet) { ConnectionIdentifier conn_id = new ConnectionIdentifier("tcp", new IpAddress(ua.user_profile.tunnelServer), ua.user_profile.tunnelPort); if(!connections.containsKey(conn_id)) { HttpTunnelTransport conn = null; try { conn = new HttpTunnelTransport(new IpAddress(ua.user_profile.tunnelServer), ua.user_profile.tunnelPort, this); } catch (Exception e) { Logger.warning("connection setup FAILED"); e.printStackTrace(); return false; } addConnection(conn); } else {} HttpTunnelTransport conn = (HttpTunnelTransport) connections.get(conn_id); if(conn != null) { try { // socket flush conn.sendMessage(packet, true); conn_id = new ConnectionIdentifier(conn); } catch (IOException e) { return false; } } else { // this point has not to be reached Logger.warning("ERROR: conn " + conn_id + " not found: abort."); return false; } return true; } public boolean send2(byte[] packet, byte[] packet2) { ConnectionIdentifier conn_id = new ConnectionIdentifier("tcp", new IpAddress(ua.user_profile.tunnelServer), ua.user_profile.tunnelPort); if(!connections.containsKey(conn_id)) { HttpTunnelTransport conn = null; try { conn = new HttpTunnelTransport(new IpAddress(ua.user_profile.tunnelServer), ua.user_profile.tunnelPort, this); } catch (Exception e) { Logger.warning("connection setup FAILED"); e.printStackTrace(); return false; } addConnection(conn); } else {} HttpTunnelTransport conn = (HttpTunnelTransport) connections.get(conn_id); if(conn != null) { try { // socket flush conn.sendMessage(packet, packet2, true); conn_id = new ConnectionIdentifier(conn); } catch (IOException e) { return false; } } else { // this point has not to be reached Logger.warning("ERROR: conn " + conn_id + " not found: abort."); return false; } return true; } public void onReceivedMessage(RtpPacket packet) { byte[] b = packet.getPacket(); if(packet.getPayloadType() == 0) { if(audioPaused) resumeAudio(); try { output_stream.write(packet.getPacket(), packet.getHeaderLength(), packet.getPayloadLength()); } catch (IOException e) { e.printStackTrace(); } } else if(packet.getPayloadType() == 19) { if(!audioPaused) pauseAudio(); // stoppaa } } private void pauseAudio() { audioPaused = true; ao.stop(); } private void resumeAudio() { audioPaused = false; ao.play(); } }