/* * 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.*; import javax.media.rtp.*; /** * TransformConnector implements the RTPConnector interface. RTPConnector * is originally designed for programmers to abstract the underlying transport * mechanism for RTP control and data from the RTPManager. However, it provides * the possibility to modify / transform the RTP and RTCP packets before * they are sent to network, or after the have been received from the network. * * The RTPConnector interface is very powerful. But just to perform packets * transformation, we do not need all the flexibility. So, we designed this * TransformConnector, which uses UDP to transfer RTP/RTCP packets just like * normal RTP stack, and then provides the TransformInputStream interface for * people to define their own transformation. * * With TransformConnector, people can implement RTP/RTCP packets transformation * and/or manipulation by implementing the TransformEngine interface. * * @see TransformEngine * @see RTPConnector * @see RTPManager * * @author Bing SU (nova.su@gmail.com) */ public class TransformConnector implements RTPConnector { /** * The customized TransformEngine object, which contains the concrete * transform logic. */ protected TransformEngine engine; /** * Local RTP session listen address. */ private SessionAddress localAddr; /** * RTP packet input stream object used by RTPManager. */ private TransformInputStream dataInputStream; /** * RTCP packet input stream object used by RTPManager. */ private TransformInputStream ctrlInputStream; /** * RTP packet output stream used by RTPManager. */ private TransformOutputStream dataOutputStream; /** * RTCP packet output stream used by RTPManager. */ private TransformOutputStream ctrlOutputStream; /** * UDP Socket we used to send and receive RTP packets. */ private DatagramSocket dataSocket; /** * UDP Socket we used to send and receive RTCP packets. */ private DatagramSocket ctrlSocket; /** * Construct a TransformConnector based on the given local RTP session * address and a customized TransformEngine. * * @param localAddr The local listen address of this RTP session * @param engine TransformEngine object which contains your transformation * logic * * @throws InvalidSessionAddressException if session address is invalid, */ public TransformConnector(SessionAddress localAddr, TransformEngine engine) throws InvalidSessionAddressException { this.localAddr = localAddr; this.engine = engine; try { this.dataSocket = new DatagramSocket(this.localAddr.getDataPort(), this.localAddr.getDataAddress()); this.ctrlSocket = new DatagramSocket( this.localAddr.getControlPort(), this.localAddr.getControlAddress()); } catch (SocketException e) { throw new InvalidSessionAddressException(); } } /** * Closes this RTPConnector object * * @see javax.media.rtp.RTPConnector#close() */ public void close() { this.dataOutputStream = null; this.ctrlOutputStream = null; if (this.dataInputStream != null) { this.dataInputStream.close(); this.dataInputStream = null; } if (this.ctrlInputStream != null) { this.ctrlInputStream.close(); this.ctrlInputStream = null; } this.dataSocket.close(); this.dataSocket = null; this.ctrlSocket.close(); this.ctrlSocket = null; } /** * Add a stream target. A stream target is the destination address which * this RTP session will send its data to. For a single session, we can add * multiple SessionAddresses, and for each address, one copy of data will be * sent to. * * @param target Destination target address */ public void addTarget(SessionAddress target) { if (this.ctrlOutputStream == null) { this.ctrlOutputStream = new TransformOutputStream(this.ctrlSocket, this.engine.getRTCPTransformer()); } this.ctrlOutputStream.addTarget(target.getControlAddress(), target.getControlPort()); if (this.dataOutputStream == null) { this.dataOutputStream = new TransformOutputStream(this.dataSocket, this.engine.getRTPTransformer()); } this.dataOutputStream.addTarget(target.getDataAddress(), target.getDataPort()); } /** * Removes a target from our session. If a target is removed, there will be * no data sent to that address. * * @param target Destination target to be removed * @return true if the target address is removed successfully * false if there is something wrong */ public boolean removeTarget(SessionAddress target) { boolean ok = true; if (this.ctrlOutputStream != null) { ok &= this.ctrlOutputStream.removeTarget(target.getControlAddress(), target.getControlPort()); } if (this.dataOutputStream != null) { ok &= this.dataOutputStream.removeTarget(target.getDataAddress(), target.getDataPort()); } return ok; } /** * Remove all stream targets. After this operation is done. There will be * no targets receiving data, so no data will be sent. */ public void removeTargets() { if (this.ctrlOutputStream != null) { this.ctrlOutputStream.removeTargets(); } if (this.dataOutputStream != null) { this.dataOutputStream.removeTargets(); } } /* (non-Javadoc) * @see javax.media.rtp.RTPConnector#getControlInputStream() */ public PushSourceStream getControlInputStream() throws IOException { if (this.ctrlInputStream == null) { this.ctrlInputStream = new TransformInputStream(this.ctrlSocket, this.engine.getRTCPTransformer()); } return this.ctrlInputStream; } /* (non-Javadoc) * @see javax.media.rtp.RTPConnector#getControlOutputStream() */ public OutputDataStream getControlOutputStream() throws IOException { if (this.ctrlOutputStream == null) { this.ctrlOutputStream = new TransformOutputStream(this.ctrlSocket, this.engine.getRTCPTransformer()); } return this.ctrlOutputStream; } /* (non-Javadoc) * @see javax.media.rtp.RTPConnector#getDataInputStream() */ public PushSourceStream getDataInputStream() throws IOException { if (this.dataInputStream == null) { this.dataInputStream = new TransformInputStream(this.dataSocket, this.engine.getRTPTransformer()); } return this.dataInputStream; } /* (non-Javadoc) * @see javax.media.rtp.RTPConnector#getDataOutputStream() */ public OutputDataStream getDataOutputStream() throws IOException { if (this.dataOutputStream == null) { this.dataOutputStream = new TransformOutputStream(this.dataSocket, this.engine.getRTPTransformer()); } return this.dataOutputStream; } /* (non-Javadoc) * @see javax.media.rtp.RTPConnector#getRTCPBandwidthFraction() */ public double getRTCPBandwidthFraction() { // Not applicable return -1; } /* (non-Javadoc) * @see javax.media.rtp.RTPConnector#getRTCPSenderBandwidthFraction() */ public double getRTCPSenderBandwidthFraction() { // Not applicable return -1; } /* (non-Javadoc) * @see javax.media.rtp.RTPConnector#getReceiveBufferSize() */ public int getReceiveBufferSize() { // Not applicable return -1; } /* (non-Javadoc) * @see javax.media.rtp.RTPConnector#setReceiveBufferSize(int) */ public void setReceiveBufferSize(int size) throws IOException { // Nothing should be done here :-) } /* (non-Javadoc) * @see javax.media.rtp.RTPConnector#getSendBufferSize() */ public int getSendBufferSize() { // Not applicable return -1; } /* (non-Javadoc) * @see javax.media.rtp.RTPConnector#setSendBufferSize(int) */ public void setSendBufferSize(int size) throws IOException { // Nothing should be done here :-) } /** * Getter to use in derived classes. * (Could modify the member variable to protected instead for direct access) * * @return the control input stream */ public TransformInputStream getCtrlInputStream() { return ctrlInputStream; } /** * Getter to use in derived classes. * (Could modify the member variable to protected instead for direct access) * * @return the control output stream */ public TransformOutputStream getCtrlOutputStream() { return ctrlOutputStream; } /** * Setter to use in derived classes. * (Could modify the member variable to protected instead for direct access) * * @param ctrlOutputStream the control output stream to be set */ public void setCtrlOutputStream(TransformOutputStream ctrlOutputStream) { this.ctrlOutputStream = ctrlOutputStream; } /** * Setter to use in derived classes. * (Could modify the member variable to protected instead for direct access) * * @param dataInputStream the data input stream to be set */ public void setDataInputStream(TransformInputStream dataInputStream) { this.dataInputStream = dataInputStream; } /** * Setter to use in derived classes. * (Could modify the member variable to protected instead for direct access) * * @param ctrlInputStream the control input stream to be set */ public void setCtrlInputStream(TransformInputStream ctrlInputStream) { this.ctrlInputStream = ctrlInputStream; } /** * Setter to use in derived classes. * (Could modify the member variable to protected instead for direct access) * * @param dataOutputStream the data output stream to be set */ public void setDataOutputStream(TransformOutputStream dataOutputStream) { this.dataOutputStream = dataOutputStream; } /** * Getter to use in derived classes. * (Could modify the member variable to protected instead for direct access) * * @return the data socket */ public DatagramSocket getDataSocket() { return dataSocket; } /** * Getter to use in derived classes. * (Could modify the member variable to protected instead for direct access) * * @return the control socket */ public DatagramSocket getCtrlSocket() { return ctrlSocket; } /** * Getter to use in derived classes. * (Could modify the member variable to protected instead for direct access) * * @return the engine */ public TransformEngine getEngine() { return engine; } }