/* * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. * * Distributable under LGPL license. * See terms of license at gnu.org. */ package net.java.sip.communicator.impl.media.transform; import java.io.*; import java.net.*; import javax.media.protocol.*; /** * TransformInputStream implements PushSourceStream. It is used by RTPManager to * receive RTP/RTCP packet datas. * * In this implementation, we use UDP sockets to receive RTP/RTCP. We listen on * the address / port specified by local session address. When one packet is * received, it is first reverse transformed through PacketTransformer defined * by user. And then returned as normal RTP/RTCP packets to RTPManager. * * @author Bing SU (nova.su@gmail.com) */ public class TransformInputStream implements PushSourceStream, Runnable { /** * UDP socket used to receive data. */ private DatagramSocket socket; /** * User defined PacketTransformer, which is used to reverse transform * packets. */ private PacketTransformer transformer; /** * SourceTransferHandler object which is used to read packets. */ private SourceTransferHandler transferHandler; /** * Whether this stream is closed. Used to control the termination of worker * thread. */ private boolean closed; /** * Worker thread we use to call transfer handle to received the data */ private Thread recvThread; /** * Packet receive buffer */ private byte[] buffer = new byte[65535]; /** * Caught an IO exception during read from socket */ private boolean ioError = false; private RawPacket pkt = null; /** * Construct a TransformInputStream based on the receiving socket and * PacketTransformer * * @param socket * data receiving socket * @param transformer * packet transformer used */ public TransformInputStream(DatagramSocket socket, PacketTransformer transformer) { this.socket = socket; this.transformer = transformer; this.closed = false; this.recvThread = new Thread(this); this.recvThread.start(); } /** * Close this stream, stops the worker thread. */ public synchronized void close() { this.closed = true; this.socket.close(); } /* * (non-Javadoc) * * @see javax.media.protocol.PushSourceStream#read(byte[], int, int) */ public int read(byte[] inBuffer, int offset, int length) throws IOException { if (ioError) { return -1; } if (length < pkt.getLength()) { throw new IOException("Input buffer not big enough for " + String.valueOf(pkt.getLength())); } System.arraycopy(pkt.getBuffer(), pkt.getOffset(), inBuffer, offset, pkt.getLength()); return pkt.getLength(); } /* * (non-Javadoc) * * @see javax.media.protocol.PushSourceStream#setTransferHandler * (javax.media.protocol.SourceTransferHandler) */ public void setTransferHandler(SourceTransferHandler handler) { if (this.closed) return; this.transferHandler = handler; } /* * (non-Javadoc) * * @see javax.media.protocol.PushSourceStream#getMinimumTransferSize() */ public int getMinimumTransferSize() { return 2 * 1024; // twice the MTU size, just to be safe. } // ----- Not applicable methods ----- /* * (non-Javadoc) * * @see javax.media.protocol.SourceStream#endOfStream() */ public boolean endOfStream() { return false; } /* * (non-Javadoc) * * @see javax.media.protocol.SourceStream#getContentDescriptor() */ public ContentDescriptor getContentDescriptor() { return null; } /* * (non-Javadoc) * * @see javax.media.protocol.SourceStream#getContentLength() */ public long getContentLength() { return LENGTH_UNKNOWN; } /* * (non-Javadoc) * * @see javax.media.Controls#getControl(java.lang.String) */ public Object getControl(String controlType) { return null; } /* * (non-Javadoc) * * @see javax.media.Controls#getControls() */ public Object[] getControls() { return new Object[0]; } /* * (non-Javadoc) * * @see java.lang.Runnable#run() */ public void run() { while (!this.closed) { DatagramPacket p = new DatagramPacket(this.buffer, 0, 65535); try { this.socket.receive(p); } catch (IOException e) { ioError = true; break; } pkt = new RawPacket(this.buffer, 0, p.getLength()); pkt = this.transformer.reverseTransform(pkt); // If the reverse transformed result is not valid, // then we will not deliver this packet. if (pkt == null) { continue; } if (this.transferHandler != null && !this.closed) { this.transferHandler.transferData(TransformInputStream.this); } } } }