Experience sharing: video for SIP clients using cloneable DataSource
Hi,
Im developing a SIP client. My objective was to implement a client that can have multiple simultaneous video calls. I ran into all kinds of problems with JMF. So here's the story.
The first problem was with creating symmetric RTP transmitter/receiver (that one is useful for NAT/Firewall transition). The only good possiblity to create a symmetric RTP receiver/transmitter tuple is to use RTPSocketAdapter to initialize your RTPManager. That RTPSocketAdapter comes together with AVReceive3/AVTransmit3 examples. However, that is not all. I had to modify RTPSocketAdapter code, so that its constructor would take 5 arguments (added local address and local port) instead of original 3. So:
1. Original RTPSockerAdapter constructor:
public RTPSocketAdapter3(InetAddress addr,
int port, int ttl)
throws IOException {
try {
if (addr.isMulticastAddress()) {
dataSock = new MulticastSocket(port);
ctrlSock = new MulticastSocket(port+1);
((MulticastSocket)dataSock).joinGroup(addr);
((MulticastSocket)dataSock).setTimeToLive(ttl);
((MulticastSocket)ctrlSock).joinGroup(addr);
((MulticastSocket)ctrlSock).setTimeToLive(ttl);
}
else {
dataSock = new DatagramSocket(port, InetAddress.getLocalHost());
ctrlSock = new DatagramSocket(port+1, InetAddress.getLocalHost());
}
}
catch (SocketException e) {
throw new IOException(e.getMessage());
}
this.addr = addr;
this.port = port;
}
2. Modified RTPSocketAdapter constructor to ensure symmetric RTP:
public RTPSocketAdapter(InetAddress localAddress, int localPort,
InetAddress remoteAddress, int remotePort,
int ttl) throws IOException {
try {
if (remoteAddress.isMulticastAddress()) {
dataSock = new MulticastSocket(localPort);
ctrlSock = new MulticastSocket(localPort+1);
((MulticastSocket)dataSock).joinGroup(remoteAddress);
((MulticastSocket)dataSock).setTimeToLive(ttl);
((MulticastSocket)ctrlSock).joinGroup(remoteAddress);
((MulticastSocket)ctrlSock).setTimeToLive(ttl);
}
else {
dataSock = new DatagramSocket(localPort, localAddress);
ctrlSock = new DatagramSocket(localPort+1, localAddress);
}
}
catch (SocketException e) {
throw new IOException(e.getMessage());
}
this.localAddress = localAddress;
this.localPort = localPort;
this.remoteAddress = remoteAddress;
this.remotePort = remotePort;
}
Continued in the next post
[2601 byte] By [
andreyvka] at [2007-10-3 9:38:54]

When symmetric RTP was behind and everything seemed to be working, suddenly I find out that when 1st call is established, 1st remote party can see me fine. But when 2nd remote party connects, the 1st one loses my video feed. Simply put, the party that connects last will get my video stream, while all others will lose the picture (i.e. client stops transmitting previous video feed). After some time I realized that it was something to do with my DataSource. A little while longer I found out that I need to use cloneable/cloned data sources. But job was far from being complete.
The sample code for DataSource clones can be found in JMF 2.1.1e guidelines under RTPSending.html file. However, there's a big problem with their code there. But firstly let's do through simple steps on creating clones for DataSources. In short:
1. origDataSource = processor.getDataOutput();
2. cloneableDataSource = Manager.createCloneableDataSource(origDataSource);
3.clonedDataSource = ((SourceCloneable)
cloneableDataSource).createClone();
That's what the document says. After that they just use *clonedDataSource* to send same audio stream to multiple destinations. This is a lie! JMF has one peculiarity: *cloneableDataSource* MUST be used together with its clones. If *cloneable* stops, then all the *clones* stop as well. What a pity! :( There's one thread, which describes a workaround for this problem: http://forum.java.sun.com/thread.jspa?threadID=667817&messageID=3907064. In short, you have to reuse *cloneable*, while at least one clone is running.
My solution was much simpler and it works like a charm :). When the first remote party connects, just before I create symmetric RTP tuple (transmitter/receiver) for that party, I create another tuple, a dummy tuple that has remote and local addresses set to "0.0.0.0" and remote and local ports set to 0. Simply, this tuple transmits nowhere and receives nothing. But (!) this dummy tuple uses *cloneable*, while the rest will just use *clones* of that cloneable! :))) Once there're no more connections, I close dummy and release *cloneable*. And again, if someone connects back and he/she the first one, then i create dummy once more!
Whew! I think that's about it. I really hope this thread helps to someone. :)
Good luck,
Andrey.
Dear andreyvk ,
I've read your post about how to use a single RTP session for both media reception and trasmission (I'm referring to you RTPSocketAdapter modified version), but, at the moment, I'receive a BIND error.
I think that your post is an EXCELLENT solution. I'modified AVReceive3 and AVTransmit3 in order to accept all parameters (Local IP & Port, Remote IP & Port).
Can you please give me a simple scenario so I can understand what the mistake?
I'use AVTransmit3 and AVReceive3 from different prompts and if I run these 2 classes contemporarely both in 2 different PC (172.17.32.27 and 172.17.32.30) I can transmit the media (vfw://0 for example) using AVTransmit3 but I'can't receive nothing if I run also AVReceive3 in the same PC?
What's the problem? Furthermore, If I run first AVReceive3 from a MSDOS Prompt and subsequently I run AVTransmit3 from another prompt I see a BIND error (port already in use).
How can I use your modified RTPSocketAdapter in order to send and receive a single media from the same port (e.g. 7500).
I've used this scenario PC1: IP 172.17.32.30 Local Port 5000 and PC2:IP 172.17.32.27 LocalPort 10000
So in the PC1 I run:
AVTransmit3 vfw://0 <Local IP 172.17.32.30> <5000> <Remote IP 172.17.32.27> <10000>
AVReceive3 <Local IP 172.17.32.30/5000> <Remote IP 172.17.32.27/10000>
and in PC2:
AVTransmit3 vfw://0 <Local IP 172.17.32.27> <10000> <Remote IP 172.17.32.30> <5000>
AVReceive3 <Local IP 172.17.32.27/10000> <Remote IP 172.17.32.30/5000>
I'd like to use the same port 5000 (in PC1) and 10000 (in PC2) in order to transmit and receive rtp packets. How can i do that without receive a Bind Error? How can I receive packets (and playing these media if audio &/or video) from the same port used to send stream over the network?
How can I obtain a RTP Symmetric Transmission/Reception solution?
Please give me an hint. If you can't post this is my email: Siracg99@libero.it
Message was edited by:
TheSirac