/*
* 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.net.*;
import java.util.*;
import javax.media.rtp.*;
/**
* TransformOutputStream implements OutputDataStream. It is use by RTPManager
* to send RTP/RTCP packet data out.
*
* In this implementation, UDP socket is used to send the data out. When a
* normal RTP/RTCP packet is passed down from RTPManager, we first transform
* the packet using user define PacketTransformer and then send it out through
* network to all the stream targets.
*
* @author Bing SU (nova.su@gmail.com)
*/
public class TransformOutputStream
implements OutputDataStream
{
/**
* UDP socket used to send packet data
*/
private DatagramSocket socket;
/**
* PacketTransformer used to transform RTP/RTCP packets
*/
private PacketTransformer transformer;
/**
* Stream targets' ip addresses
*/
private Vector<InetAddress> remoteAddrs;
/**
* Stream targets' ports, corresponding to their ip addresses.
*/
private Vector<Integer> remotePorts;
/**
* Construct a TransformOutputStream based on the given UDP socket and
* PacketTransformer
*
* @param socket UDP socket used to send packet data out
* @param transformer PacketTransformer used to transform RTP/RTCP packets
*/
public TransformOutputStream(DatagramSocket socket,
PacketTransformer transformer)
{
this.socket = socket;
this.transformer = transformer;
this.remoteAddrs = new Vector<InetAddress>();
this.remotePorts = new Vector<Integer>();
}
/**
* Add a target to stream targets list
*
* @param remoteAddr target ip address
* @param remotePort target port
*/
public void addTarget(InetAddress remoteAddr, int remotePort)
{
this.remoteAddrs.add(remoteAddr);
this.remotePorts.add(new Integer(remotePort));
}
/**
* Remove a target from stream targets list
*
* @param remoteAddr target ip address
* @param remotePort target port
* @return true if the target is in stream target list and can be removed
* false if not
*/
public boolean removeTarget(InetAddress remoteAddr, int remotePort)
{
boolean ok = true;
ok = ok && this.remoteAddrs.remove(remoteAddr);
ok = ok && this.remoteAddrs.remove(new Integer(remotePort));
return ok;
}
/**
* Remove all stream targets from this session.
*/
public void removeTargets()
{
this.remoteAddrs.removeAllElements();
this.remotePorts.removeAllElements();
}
/* (non-Javadoc)
* @see javax.media.rtp.OutputDataStream#write(byte[], int, int)
*/
public int write(byte[] buffer, int offset, int length)
{
// Transformation could be non-inplace, we shall not modify the old
// buffer
RawPacket pkt = this.transformer.transform(new RawPacket(buffer,
offset,
length));
// This is for the case when the ZRTP engine stops the media stream
// allowing only ZRTP packets
/* TODO GoClear
* To uncomment in order to use the GoClear feature
*/
/*
if (pkt == null)
return length;
*/
for (int i = 0; i < this.remoteAddrs.size(); ++i)
{
InetAddress remoteAddr =
(InetAddress) this.remoteAddrs.elementAt(i);
int remotePort =
((Integer) this.remotePorts.elementAt(i)).intValue();
try
{
this.socket.send(new DatagramPacket(pkt.getBuffer(),
pkt.getOffset(),
pkt.getLength(),
remoteAddr,
remotePort));
}
catch (Exception e)
{
// TODO error handling
return -1;
}
}
// yes, we should return the pre-transformed packet length
return length;
}
}