dcsimg
Testing RTPManager for an Audio Chat
0 posts in topic
Flat View  Flat View
TOPIC ACTIONS:
 

Posted By:   Jose_Botella
Posted On:   Thursday, August 14, 2003 11:53 AM

I am trying to write a voice chat using JMF. In JMF there is an implementation of the Real-Time Transport Protocol and RTCP (for control). They allow the streaming of audio and video over the Internet. If you are using just UDP, should'nt write yourself what RTP-RTCP already provide? for instance reordering the packets out of sequence. Below is a test code that should work in theory. I have been able to make two participants in different computers to talk to each other in a LAN. But the third one has problems. The difficulty I have found is that RTPManager seems not being issuing all the events. When a stream is received from a remote participant I list   More>>

I am trying to write a voice chat using JMF. In JMF there
is an implementation of the Real-Time Transport Protocol and RTCP (for control). They allow the streaming of audio
and video over the Internet. If you are using just UDP,
should'nt write yourself what RTP-RTCP already provide? for instance reordering the packets out of
sequence.


Below is a test code that should work in theory.


I have been able to make two participants in different
computers to talk to each other in a LAN. But the third
one has problems. The difficulty I have found is
that RTPManager seems not being issuing all the events.
When a stream is received from a remote
participant I listen for any of three events from which
I could extract the stream to play. Sometimes none
of these events occurr.



Another problem I have -initially- avoided is that if
Participant A has started the program first, he will
receive the stream from Participant B; but B will not
receive the one from A unless both programs has been
started within the same minute. In fact that lapse is
even fewer, maybe 45 seconds.

I have found that closing and starting the sending stream
from A makes B to receive it.


Here is the code you can test it and feedback please.





			
package josebotella.jconference.test;
import java.net.InetAddress;
import javax.media.*;
import javax.media.Format;
import javax.media.format.AudioFormat;
import javax.media.protocol.*;
import javax.media.control.FormatControl;
import javax.media.rtp.*;
import javax.media.rtp.event.*;
import java.util.*;
import java.io.IOException;
import javax.swing.*;
import java.awt.event.*;
import java.awt.BorderLayout;

public class TestRTPManager implements ControllerListener,
ReceiveStreamListener, SessionListener {
static TestRTPManager test = new TestRTPManager();
static RTPManager mng;
static Processor proc; //converts captured audio to a format to transmit
static SendStream ss;
static DataSource dataSo;
//static List players = new ArrayList() ;//to play each remote host
static Map streams = new IdentityHashMap();
/*usage: java -ea josebotella.jconference.test.TestRTPManager ip1 ip2... port
*
*/
public static void main(String[] args) throws Exception {
final InetAddress[] ia = new InetAddress[args.length-1];
final InetAddress localIP = InetAddress.getLocalHost();
int port = Integer.parseInt(args[args.length-1]);
for(int i =0; i < args.length-1 ; i++)
ia[i] = InetAddress.getByName(args[i]);
List capturers = CaptureDeviceManager.getDeviceList(
new AudioFormat(AudioFormat.LINEAR));
CaptureDeviceInfo cdi = (CaptureDeviceInfo) capturers.get(0);
dataSo = Manager.createDataSource( cdi.getLocator() );
//setting the first audio format to capture
setFormat( ((CaptureDevice) dataSo).getFormatControls() ,
(AudioFormat) cdi.getFormats()[0] );
mng = RTPManager.newInstance();
mng.initialize( new SessionAddress(localIP, port) );
assert TestRTPManager.sop("localhost: " + localIP + " local port: " + port);
for(int i=0; i < ia.length; i++)
mng.addTarget( new SessionAddress( ia[i] , port ) );
mng.addReceiveStreamListener(test);
mng.addSessionListener(test);
proc = Manager.createProcessor(dataSo);
proc.addControllerListener(test);
proc.configure();
////////////////////////////////////////////////////////////
//a minimal GUI
JFrame frame = new JFrame("TestRTPManager");
JButton button = new JButton("Stop");
JButton reset = new JButton("Reset Stream");
button.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent ae) {
stopConference();
System.exit(0);
}
}
);
reset.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent ae) {
try {
ss.close();//spawn a NewReceiveStreamEvent in the remote hosts
ss.start();//that had not yet received one
} catch(Exception e) {
System.out.println(e);
}
}
}
);
frame.getContentPane().add(button, BorderLayout.NORTH);
frame.getContentPane().add(reset, BorderLayout.SOUTH);
frame.pack();
frame.show();
}

static void stopConference() {
if(dataSo != null) {
try {
dataSo.stop();
} catch(IOException e) { }
dataSo.disconnect();
dataSo = null;
}
if(proc != null) {
proc.close();
proc = null;
}
if(ss != null) {
ss.close();
ss = null;
}
if(mng != null) {
mng.removeTargets(null);
mng.dispose();
mng = null;
}
synchronized(streams) {
for(Iterator it = streams.values().iterator(); it.hasNext(); ) {
Player pla = (Player) it.next();
if(pla != null) pla.close();
}
}
}

public void controllerUpdate(ControllerEvent ce) {
if(ce instanceof ConfigureCompleteEvent) {
assert TestRTPManager.sop("The processor has been configured");
proc.setContentDescriptor(
new ContentDescriptor(ContentDescriptor.RAW_RTP) );
//setting the codec for the processor
setFormat( proc.getTrackControls() ,
new AudioFormat(AudioFormat.G723_RTP) );
proc.realize();
} else if(ce instanceof RealizeCompleteEvent ) {
if(ce.getSourceController() == proc) {
//proc, for the local host to transmit, has been realized
assert TestRTPManager.sop("The processor has been realized");
try { //according to API it should be 1...
ss = mng.createSendStream(proc.getDataOutput(), 0);
ss.start();//...but ArrayIndexOutBoundsException 1
proc.start();
} catch(Exception ex) {
System.out.println(ex);
}
} else {//any of the players for listening to remote hosts was realized
assert TestRTPManager.sop("A player has been realized");
((Player) ce.getSourceController()).start();
}
} else if (ce instanceof ControllerErrorEvent) assert TestRTPManager.sop(ce);
}

public void update(ReceiveStreamEvent rse) {
if(rse instanceof NewReceiveStreamEvent) {
ReceiveStream stream = rse.getReceiveStream();
String name = null;
Participant parti = stream.getParticipant();
if(parti != null) name = parti.getCNAME();
assert TestRTPManager.sop("The stream: " + stream + " from :" +
name + " has arrived: " );
createPlayer(stream);
} else if(rse instanceof ByeEvent) {
assert TestRTPManager.sop("BYE from " + rse.getParticipant().getCNAME() +
" ssrc=" + rse.getReceiveStream().getSSRC() +
" reason=" + ((ByeEvent) rse).getReason() );
} else if(rse instanceof StreamMappedEvent) {
ReceiveStream stream = rse.getReceiveStream();
String name = null;
Participant parti = stream.getParticipant();
if(parti != null) name = parti.getCNAME();
assert TestRTPManager.sop("The stream: " + stream +
"has been mapped to " + name);
createPlayer(stream);
}
}

public void update(SessionEvent se) {
if(se instanceof NewParticipantEvent) {
Participant parti = ((NewParticipantEvent) se).getParticipant();
assert TestRTPManager.sop("The participant: " + parti.getCNAME() +
" with the following streams has connected. " + parti.getStreams());
createPlayer( parti.getStreams().firstElement() );
}
}

void createPlayer(Object o) {
if(o == null) return;
ReceiveStream rStream = null;
if( !(o instanceof ReceiveStream) ) return;
else rStream = (ReceiveStream) o;
synchronized(streams) {
if( streams.containsKey(rStream) ) return;//already created for this stream
try {
DataSource ds = rStream.getDataSource();
Player pla = Manager.createPlayer(ds);
streams.put(rStream, pla);
pla.addControllerListener(test);
assert TestRTPManager.sop("Player created");
pla.realize();
} catch(Exception e) {
System.out.println(e);
}
}
}


private static void setFormat(FormatControl[] fca, AudioFormat format) {
//one FormatControl per stream in DataSource,
//maybe only one for an audio card CaptureDevice
loop:
for (int i=0; i
Format[] supported = fca[i].getSupportedFormats();
for (int j=0; j
if (format.matches(supported[j])) {
fca[i].setFormat(supported[j]);//setting the desired format
break loop;
}
}
fca[i].setEnabled(false);
}
}

static boolean sop(Object o) {
System.out.println(o);
return true;
}

static boolean sop(int i) {
System.out.println(i);
return true;
}

}
   <<Less
About | Sitemap | Contact