mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-26 14:02:06 +01:00
Jingle Extension and Media Merged
git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@7426 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
parent
9feb6ece42
commit
a3b15bce09
37 changed files with 0 additions and 2310 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,94 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module version="4" relativePaths="true" type="JAVA_MODULE">
|
|
||||||
<component name="BuildJarSettings">
|
|
||||||
<containerInfo>
|
|
||||||
<containerElement type="module" name="JingleMedia">
|
|
||||||
<attribute name="method" value="1" />
|
|
||||||
<attribute name="URI" value="/" />
|
|
||||||
</containerElement>
|
|
||||||
</containerInfo>
|
|
||||||
<setting name="jarUrl" value="file://$MODULE_DIR$/../../JingleMedia.jar" />
|
|
||||||
<setting name="buildJar" value="true" />
|
|
||||||
<setting name="mainClass" value="" />
|
|
||||||
</component>
|
|
||||||
<component name="ModuleRootManager" />
|
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="false">
|
|
||||||
<output url="file://$MODULE_DIR$/../../classes" />
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$/../..">
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/../lib" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/../lib/windows" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/../../source" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/../../test" isTestSource="true" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="module" module-name="JingleExtension" />
|
|
||||||
<orderEntry type="module" module-name="Smack" />
|
|
||||||
<orderEntry type="module-library">
|
|
||||||
<library>
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MODULE_DIR$/../lib/jmf.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</orderEntry>
|
|
||||||
<orderEntry type="module-library">
|
|
||||||
<library>
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MODULE_DIR$/../lib/commons-logging-adapters-1.1.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</orderEntry>
|
|
||||||
<orderEntry type="module-library">
|
|
||||||
<library>
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MODULE_DIR$/../lib/jspeex-0.9.7-jfcom.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</orderEntry>
|
|
||||||
<orderEntry type="module-library">
|
|
||||||
<library>
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MODULE_DIR$/../lib/commons-logging-api-1.1.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</orderEntry>
|
|
||||||
<orderEntry type="module-library">
|
|
||||||
<library>
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MODULE_DIR$/../lib/Speex.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</orderEntry>
|
|
||||||
<orderEntry type="module-library">
|
|
||||||
<library>
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MODULE_DIR$/../lib/commons-logging-1.1.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</orderEntry>
|
|
||||||
<orderEntry type="module-library">
|
|
||||||
<library>
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MODULE_DIR$/../../../../build/junit.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</orderEntry>
|
|
||||||
<orderEntryProperties />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
|
|
|
@ -1,157 +0,0 @@
|
||||||
package org.jivesoftware.demo;
|
|
||||||
|
|
||||||
import org.jivesoftware.jingleaudio.jmf.JmfMediaManager;
|
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
|
||||||
import org.jivesoftware.smack.XMPPException;
|
|
||||||
import org.jivesoftware.smackx.jingle.IncomingJingleSession;
|
|
||||||
import org.jivesoftware.smackx.jingle.JingleManager;
|
|
||||||
import org.jivesoftware.smackx.jingle.JingleSessionRequest;
|
|
||||||
import org.jivesoftware.smackx.jingle.OutgoingJingleSession;
|
|
||||||
import org.jivesoftware.smackx.jingle.listeners.JingleSessionRequestListener;
|
|
||||||
import org.jivesoftware.smackx.jingle.nat.BridgedTransportManager;
|
|
||||||
import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
|
|
||||||
import org.jivesoftware.smackx.jingle.nat.RTPBridge;
|
|
||||||
import org.jivesoftware.smackx.jingle.nat.STUNTransportManager;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* $RCSfile$
|
|
||||||
* $Revision: $
|
|
||||||
* $Date: 28/12/2006
|
|
||||||
*
|
|
||||||
* Copyright 2003-2006 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
public class Demo extends JFrame {
|
|
||||||
|
|
||||||
private JingleTransportManager transportManager = null;
|
|
||||||
private XMPPConnection xmppConnection = null;
|
|
||||||
|
|
||||||
private String server = null;
|
|
||||||
private String user = null;
|
|
||||||
private String pass = null;
|
|
||||||
|
|
||||||
private JingleManager jm = null;
|
|
||||||
private IncomingJingleSession incoming = null;
|
|
||||||
private OutgoingJingleSession outgoing = null;
|
|
||||||
|
|
||||||
private JTextField jid = new JTextField(30);
|
|
||||||
|
|
||||||
public Demo(String server, String user, String pass) {
|
|
||||||
|
|
||||||
this.server = server;
|
|
||||||
this.user = user;
|
|
||||||
this.pass = pass;
|
|
||||||
|
|
||||||
xmppConnection = new XMPPConnection(server);
|
|
||||||
try {
|
|
||||||
xmppConnection.connect();
|
|
||||||
xmppConnection.login(user, pass);
|
|
||||||
initialize();
|
|
||||||
} catch (XMPPException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void initialize() {
|
|
||||||
if (RTPBridge.serviceAvailable(xmppConnection))
|
|
||||||
transportManager = new BridgedTransportManager(xmppConnection);
|
|
||||||
else
|
|
||||||
transportManager = new STUNTransportManager();
|
|
||||||
|
|
||||||
jm = new JingleManager(xmppConnection, transportManager, new JmfMediaManager());
|
|
||||||
|
|
||||||
if (transportManager instanceof BridgedTransportManager)
|
|
||||||
jm.addCreationListener((BridgedTransportManager) transportManager);
|
|
||||||
|
|
||||||
jm.addJingleSessionRequestListener(new JingleSessionRequestListener() {
|
|
||||||
public void sessionRequested(JingleSessionRequest request) {
|
|
||||||
|
|
||||||
if (incoming != null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Accept the call
|
|
||||||
incoming = request.accept();
|
|
||||||
|
|
||||||
// Start the call
|
|
||||||
incoming.start();
|
|
||||||
}
|
|
||||||
catch (XMPPException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
createGUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createGUI() {
|
|
||||||
|
|
||||||
JPanel jPanel = new JPanel();
|
|
||||||
|
|
||||||
jPanel.add(jid);
|
|
||||||
|
|
||||||
jPanel.add(new JButton(new AbstractAction("Call") {
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
if (outgoing != null) return;
|
|
||||||
try {
|
|
||||||
outgoing = jm.createOutgoingJingleSession(jid.getText());
|
|
||||||
} catch (XMPPException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
jPanel.add(new JButton(new AbstractAction("Hangup") {
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
if (outgoing != null)
|
|
||||||
try {
|
|
||||||
outgoing.terminate();
|
|
||||||
} catch (XMPPException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
outgoing = null;
|
|
||||||
}
|
|
||||||
if (incoming != null)
|
|
||||||
try {
|
|
||||||
incoming.terminate();
|
|
||||||
} catch (XMPPException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
incoming = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
this.add(jPanel);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String args[]) {
|
|
||||||
|
|
||||||
Demo demo = null;
|
|
||||||
|
|
||||||
if (args.length > 2) {
|
|
||||||
demo = new Demo(args[0], args[1], args[2]);
|
|
||||||
demo.pack();
|
|
||||||
demo.setVisible(true);
|
|
||||||
demo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,272 +0,0 @@
|
||||||
package org.jivesoftware.jingleaudio;
|
|
||||||
|
|
||||||
import com.sun.media.util.Registry;
|
|
||||||
import com.sun.media.ExclusiveUse;
|
|
||||||
|
|
||||||
import javax.media.format.AudioFormat;
|
|
||||||
import javax.media.Renderer;
|
|
||||||
import javax.media.PlugInManager;
|
|
||||||
import javax.media.Format;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
public class JMFInit extends Frame implements Runnable {
|
|
||||||
|
|
||||||
private String tempDir = "/tmp";
|
|
||||||
|
|
||||||
private boolean done = false;
|
|
||||||
|
|
||||||
private String userHome;
|
|
||||||
|
|
||||||
private boolean visible = false;
|
|
||||||
|
|
||||||
public JMFInit(String[] args, boolean visible) {
|
|
||||||
super("Initializing JMF...");
|
|
||||||
|
|
||||||
this.visible = visible;
|
|
||||||
|
|
||||||
Registry.set("secure.allowCaptureFromApplets", new Boolean(true));
|
|
||||||
Registry.set("secure.allowSaveFileFromApplets", new Boolean(true));
|
|
||||||
|
|
||||||
updateTemp(args);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Registry.commit();
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
|
|
||||||
message("Failed to commit to JMFRegistry!");
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread detectThread = new Thread(this);
|
|
||||||
detectThread.run();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* int slept = 0; while (!done && slept < 60 * 1000 * 2) { try {
|
|
||||||
* Thread.currentThread().sleep(500); } catch (InterruptedException ie) { }
|
|
||||||
* slept += 500; }
|
|
||||||
*
|
|
||||||
* if (!done) { console.error("Detection is taking too long!
|
|
||||||
* Aborting!"); message("Detection is taking too long! Aborting!"); }
|
|
||||||
*
|
|
||||||
* try { Thread.currentThread().sleep(2000); } catch
|
|
||||||
* (InterruptedException ie) { }
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
detectDirectAudio();
|
|
||||||
detectS8DirectAudio();
|
|
||||||
detectCaptureDevices();
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateTemp(String[] args) {
|
|
||||||
if (args != null && args.length > 0) {
|
|
||||||
tempDir = args[0];
|
|
||||||
|
|
||||||
message("Setting cache directory to " + tempDir);
|
|
||||||
Registry r = new Registry();
|
|
||||||
try {
|
|
||||||
r.set("secure.cacheDir", tempDir);
|
|
||||||
r.commit();
|
|
||||||
|
|
||||||
message("Updated registry");
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
message("Couldn't update registry!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void detectCaptureDevices() {
|
|
||||||
// check if JavaSound capture is available
|
|
||||||
message("Looking for Audio capturer");
|
|
||||||
Class dsauto = null;
|
|
||||||
try {
|
|
||||||
dsauto = Class.forName("DirectSoundAuto");
|
|
||||||
dsauto.newInstance();
|
|
||||||
message("Finished detecting DirectSound capturer");
|
|
||||||
}
|
|
||||||
catch (ThreadDeath td) {
|
|
||||||
throw td;
|
|
||||||
}
|
|
||||||
catch (Throwable t) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Class jsauto = null;
|
|
||||||
try {
|
|
||||||
jsauto = Class.forName("JavaSoundAuto");
|
|
||||||
jsauto.newInstance();
|
|
||||||
message("Finished detecting javasound capturer");
|
|
||||||
}
|
|
||||||
catch (ThreadDeath td) {
|
|
||||||
throw td;
|
|
||||||
}
|
|
||||||
catch (Throwable t) {
|
|
||||||
message("JavaSound capturer detection failed!");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// Check if VFWAuto or SunVideoAuto is available
|
|
||||||
message("Looking for video capture devices");
|
|
||||||
Class auto = null;
|
|
||||||
Class autoPlus = null;
|
|
||||||
try {
|
|
||||||
auto = Class.forName("VFWAuto");
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
}
|
|
||||||
if (auto == null) {
|
|
||||||
try {
|
|
||||||
auto = Class.forName("SunVideoAuto");
|
|
||||||
}
|
|
||||||
catch (Exception ee) {
|
|
||||||
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
autoPlus = Class.forName("SunVideoPlusAuto");
|
|
||||||
}
|
|
||||||
catch (Exception ee) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (auto == null) {
|
|
||||||
try {
|
|
||||||
auto = Class.forName("V4LAuto");
|
|
||||||
}
|
|
||||||
catch (Exception ee) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Object instance = auto.newInstance();
|
|
||||||
if (autoPlus != null) {
|
|
||||||
Object instancePlus = autoPlus.newInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
message("Finished detecting video capture devices");
|
|
||||||
}
|
|
||||||
catch (ThreadDeath td) {
|
|
||||||
throw td;
|
|
||||||
}
|
|
||||||
catch (Throwable t) {
|
|
||||||
|
|
||||||
message("Capture device detection failed!");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
private void detectDirectAudio() {
|
|
||||||
Class cls;
|
|
||||||
int plType = PlugInManager.RENDERER;
|
|
||||||
String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
|
|
||||||
try {
|
|
||||||
// Check if this is the Windows Performance Pack - hack
|
|
||||||
cls = Class.forName("VFWAuto");
|
|
||||||
// Check if DS capture is supported, otherwise fail DS renderer
|
|
||||||
// since NT doesn't have capture
|
|
||||||
cls = Class.forName("com.sun.media.protocol.dsound.DSound");
|
|
||||||
// Find the renderer class and instantiate it.
|
|
||||||
cls = Class.forName(dar);
|
|
||||||
|
|
||||||
Renderer rend = (Renderer)cls.newInstance();
|
|
||||||
try {
|
|
||||||
// Set the format and open the device
|
|
||||||
AudioFormat af = new AudioFormat(AudioFormat.LINEAR, 44100, 16,
|
|
||||||
2);
|
|
||||||
rend.setInputFormat(af);
|
|
||||||
rend.open();
|
|
||||||
Format[] inputFormats = rend.getSupportedInputFormats();
|
|
||||||
// Register the device
|
|
||||||
PlugInManager.addPlugIn(dar, inputFormats, new Format[0],
|
|
||||||
plType);
|
|
||||||
// Move it to the top of the list
|
|
||||||
Vector rendList = PlugInManager.getPlugInList(null, null,
|
|
||||||
plType);
|
|
||||||
int listSize = rendList.size();
|
|
||||||
if (rendList.elementAt(listSize - 1).equals(dar)) {
|
|
||||||
rendList.removeElementAt(listSize - 1);
|
|
||||||
rendList.insertElementAt(dar, 0);
|
|
||||||
PlugInManager.setPlugInList(rendList, plType);
|
|
||||||
PlugInManager.commit();
|
|
||||||
// Log.debug("registered");
|
|
||||||
}
|
|
||||||
rend.close();
|
|
||||||
}
|
|
||||||
catch (Throwable t) {
|
|
||||||
// Log.debug("Error " + t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Throwable tt) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void detectS8DirectAudio() {
|
|
||||||
Class cls;
|
|
||||||
int plType = PlugInManager.RENDERER;
|
|
||||||
String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
|
|
||||||
try {
|
|
||||||
// Check if this is the solaris Performance Pack - hack
|
|
||||||
cls = Class.forName("SunVideoAuto");
|
|
||||||
|
|
||||||
// Find the renderer class and instantiate it.
|
|
||||||
cls = Class.forName(dar);
|
|
||||||
|
|
||||||
Renderer rend = (Renderer)cls.newInstance();
|
|
||||||
|
|
||||||
if (rend instanceof ExclusiveUse
|
|
||||||
&& !((ExclusiveUse)rend).isExclusive()) {
|
|
||||||
// sol8+, DAR supports mixing
|
|
||||||
Vector rendList = PlugInManager.getPlugInList(null, null,
|
|
||||||
plType);
|
|
||||||
int listSize = rendList.size();
|
|
||||||
boolean found = false;
|
|
||||||
String rname = null;
|
|
||||||
|
|
||||||
for (int i = 0; i < listSize; i++) {
|
|
||||||
rname = (String)(rendList.elementAt(i));
|
|
||||||
if (rname.equals(dar)) { // DAR is in the registry
|
|
||||||
found = true;
|
|
||||||
rendList.removeElementAt(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found) {
|
|
||||||
rendList.insertElementAt(dar, 0);
|
|
||||||
PlugInManager.setPlugInList(rendList, plType);
|
|
||||||
PlugInManager.commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Throwable tt) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void message(String mesg) {
|
|
||||||
System.out.println(mesg);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createGUI() {
|
|
||||||
TextArea textBox = new TextArea(5, 50);
|
|
||||||
add("Center", textBox);
|
|
||||||
textBox.setEditable(false);
|
|
||||||
addNotify();
|
|
||||||
pack();
|
|
||||||
|
|
||||||
int scrWidth = (int)Toolkit.getDefaultToolkit().getScreenSize()
|
|
||||||
.getWidth();
|
|
||||||
int scrHeight = (int)Toolkit.getDefaultToolkit().getScreenSize()
|
|
||||||
.getHeight();
|
|
||||||
|
|
||||||
setLocation((scrWidth - getWidth()) / 2, (scrHeight - getHeight()) / 2);
|
|
||||||
|
|
||||||
setVisible(visible);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void start(boolean visible) {
|
|
||||||
JMFInit init = new JMFInit(null, visible);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,440 +0,0 @@
|
||||||
/**
|
|
||||||
* $RCSfile$
|
|
||||||
* $Revision: $
|
|
||||||
* $Date: 08/11/2006
|
|
||||||
* <p/>
|
|
||||||
* Copyright 2003-2006 Jive Software.
|
|
||||||
* <p/>
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* <p/>
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* <p/>
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jivesoftware.jingleaudio.jmf;
|
|
||||||
|
|
||||||
import javax.media.*;
|
|
||||||
import javax.media.control.TrackControl;
|
|
||||||
import javax.media.format.AudioFormat;
|
|
||||||
import javax.media.protocol.ContentDescriptor;
|
|
||||||
import javax.media.protocol.DataSource;
|
|
||||||
import javax.media.protocol.PushBufferDataSource;
|
|
||||||
import javax.media.protocol.PushBufferStream;
|
|
||||||
import javax.media.rtp.RTPManager;
|
|
||||||
import javax.media.rtp.SendStream;
|
|
||||||
import javax.media.rtp.SessionAddress;
|
|
||||||
import javax.media.rtp.rtcp.SourceDescription;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An Easy to use Audio Channel implemented using JMF.
|
|
||||||
* It sends and receives jmf for and from desired IPs and ports.
|
|
||||||
* Also has a rport Symetric behavior for better NAT Traversal.
|
|
||||||
* It send data from a defined port and receive data in the same port, making NAT binds easier.
|
|
||||||
* <p/>
|
|
||||||
* Send from portA to portB and receive from portB in portA.
|
|
||||||
* <p/>
|
|
||||||
* Sending
|
|
||||||
* portA ---> portB
|
|
||||||
* <p/>
|
|
||||||
* Receiving
|
|
||||||
* portB ---> portA
|
|
||||||
* <p/>
|
|
||||||
* <i>Transmit and Receive are interdependents. To receive you MUST trasmit. </i>
|
|
||||||
*
|
|
||||||
* @author Thiago Camargo
|
|
||||||
*/
|
|
||||||
public class AudioChannel {
|
|
||||||
|
|
||||||
private MediaLocator locator;
|
|
||||||
private String localIpAddress;
|
|
||||||
private String ipAddress;
|
|
||||||
private int localPort;
|
|
||||||
private int portBase;
|
|
||||||
private Format format;
|
|
||||||
|
|
||||||
private Processor processor = null;
|
|
||||||
private RTPManager rtpMgrs[];
|
|
||||||
private DataSource dataOutput = null;
|
|
||||||
private AudioReceiver audioReceiver;
|
|
||||||
|
|
||||||
private List<SendStream> sendStreams = new ArrayList<SendStream>();
|
|
||||||
|
|
||||||
private boolean started = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an Audio Channel for a desired jmf locator. For instance: new MediaLocator("dsound://")
|
|
||||||
*
|
|
||||||
* @param locator
|
|
||||||
* @param ipAddress
|
|
||||||
* @param localPort
|
|
||||||
* @param remotePort
|
|
||||||
* @param format
|
|
||||||
*/
|
|
||||||
public AudioChannel(MediaLocator locator,
|
|
||||||
String localIpAddress,
|
|
||||||
String ipAddress,
|
|
||||||
int localPort,
|
|
||||||
int remotePort,
|
|
||||||
Format format) {
|
|
||||||
|
|
||||||
this.locator = locator;
|
|
||||||
this.localIpAddress = localIpAddress;
|
|
||||||
this.ipAddress = ipAddress;
|
|
||||||
this.localPort = localPort;
|
|
||||||
this.portBase = remotePort;
|
|
||||||
this.format = format;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts the transmission. Returns null if transmission started ok.
|
|
||||||
* Otherwise it returns a string with the reason why the setup failed.
|
|
||||||
* Starts receive also.
|
|
||||||
*/
|
|
||||||
public synchronized String start() {
|
|
||||||
if (started) return null;
|
|
||||||
started = true;
|
|
||||||
String result;
|
|
||||||
|
|
||||||
// Create a processor for the specified jmf locator
|
|
||||||
result = createProcessor();
|
|
||||||
if (result != null) {
|
|
||||||
started = false;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an RTP session to transmit the output of the
|
|
||||||
// processor to the specified IP address and port no.
|
|
||||||
result = createTransmitter();
|
|
||||||
if (result != null) {
|
|
||||||
processor.close();
|
|
||||||
processor = null;
|
|
||||||
started = false;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the transmission
|
|
||||||
processor.start();
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops the transmission if already started.
|
|
||||||
* Stops the receiver also.
|
|
||||||
*/
|
|
||||||
public void stop() {
|
|
||||||
if (!started) return;
|
|
||||||
synchronized (this) {
|
|
||||||
try {
|
|
||||||
started = false;
|
|
||||||
if (processor != null) {
|
|
||||||
processor.stop();
|
|
||||||
processor = null;
|
|
||||||
|
|
||||||
for (int i = 0; i < rtpMgrs.length; i++) {
|
|
||||||
rtpMgrs[i].removeReceiveStreamListener(audioReceiver);
|
|
||||||
rtpMgrs[i].removeSessionListener(audioReceiver);
|
|
||||||
rtpMgrs[i].removeTargets("Session ended.");
|
|
||||||
rtpMgrs[i].dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
sendStreams.clear();
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String createProcessor() {
|
|
||||||
if (locator == null)
|
|
||||||
return "Locator is null";
|
|
||||||
|
|
||||||
DataSource ds;
|
|
||||||
|
|
||||||
try {
|
|
||||||
ds = javax.media.Manager.createDataSource(locator);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return "Couldn't create DataSource";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to create a processor to handle the input jmf locator
|
|
||||||
try {
|
|
||||||
processor = javax.media.Manager.createProcessor(ds);
|
|
||||||
} catch (NoProcessorException npe) {
|
|
||||||
npe.printStackTrace();
|
|
||||||
return "Couldn't create processor";
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
ioe.printStackTrace();
|
|
||||||
return "IOException creating processor";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for it to configure
|
|
||||||
boolean result = waitForState(processor, Processor.Configured);
|
|
||||||
if (result == false)
|
|
||||||
return "Couldn't configure processor";
|
|
||||||
|
|
||||||
// Get the tracks from the processor
|
|
||||||
TrackControl[] tracks = processor.getTrackControls();
|
|
||||||
|
|
||||||
// Do we have atleast one track?
|
|
||||||
if (tracks == null || tracks.length < 1)
|
|
||||||
return "Couldn't find tracks in processor";
|
|
||||||
|
|
||||||
// Set the output content descriptor to RAW_RTP
|
|
||||||
// This will limit the supported formats reported from
|
|
||||||
// Track.getSupportedFormats to only valid RTP formats.
|
|
||||||
ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP);
|
|
||||||
processor.setContentDescriptor(cd);
|
|
||||||
|
|
||||||
Format supported[];
|
|
||||||
Format chosen = null;
|
|
||||||
boolean atLeastOneTrack = false;
|
|
||||||
|
|
||||||
// Program the tracks.
|
|
||||||
for (int i = 0; i < tracks.length; i++) {
|
|
||||||
if (tracks[i].isEnabled()) {
|
|
||||||
|
|
||||||
supported = tracks[i].getSupportedFormats();
|
|
||||||
|
|
||||||
if (supported.length > 0) {
|
|
||||||
for (Format format : supported) {
|
|
||||||
if (format instanceof AudioFormat) {
|
|
||||||
if (this.format.matches(format))
|
|
||||||
chosen = format;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (chosen != null) {
|
|
||||||
tracks[i].setFormat(chosen);
|
|
||||||
System.err.println("Track " + i + " is set to transmit as:");
|
|
||||||
System.err.println(" " + chosen);
|
|
||||||
atLeastOneTrack = true;
|
|
||||||
} else
|
|
||||||
tracks[i].setEnabled(false);
|
|
||||||
} else
|
|
||||||
tracks[i].setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!atLeastOneTrack)
|
|
||||||
return "Couldn't set any of the tracks to a valid RTP format";
|
|
||||||
|
|
||||||
result = waitForState(processor, Controller.Realized);
|
|
||||||
if (result == false)
|
|
||||||
return "Couldn't realize processor";
|
|
||||||
|
|
||||||
// Get the output data source of the processor
|
|
||||||
dataOutput = processor.getDataOutput();
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use the RTPManager API to create sessions for each jmf
|
|
||||||
* track of the processor.
|
|
||||||
*/
|
|
||||||
private String createTransmitter() {
|
|
||||||
|
|
||||||
// Cheated. Should have checked the type.
|
|
||||||
PushBufferDataSource pbds = (PushBufferDataSource) dataOutput;
|
|
||||||
PushBufferStream pbss[] = pbds.getStreams();
|
|
||||||
|
|
||||||
rtpMgrs = new RTPManager[pbss.length];
|
|
||||||
SessionAddress localAddr, destAddr;
|
|
||||||
InetAddress ipAddr;
|
|
||||||
SendStream sendStream;
|
|
||||||
audioReceiver = new AudioReceiver(this);
|
|
||||||
int port;
|
|
||||||
SourceDescription srcDesList[];
|
|
||||||
|
|
||||||
for (int i = 0; i < pbss.length; i++) {
|
|
||||||
try {
|
|
||||||
rtpMgrs[i] = RTPManager.newInstance();
|
|
||||||
|
|
||||||
port = portBase + 2 * i;
|
|
||||||
ipAddr = InetAddress.getByName(ipAddress);
|
|
||||||
|
|
||||||
localAddr = new SessionAddress(InetAddress.getByName(this.localIpAddress),
|
|
||||||
localPort);
|
|
||||||
|
|
||||||
destAddr = new SessionAddress(ipAddr, port);
|
|
||||||
|
|
||||||
rtpMgrs[i].addReceiveStreamListener(audioReceiver);
|
|
||||||
rtpMgrs[i].addSessionListener(audioReceiver);
|
|
||||||
|
|
||||||
rtpMgrs[i].initialize(localAddr);
|
|
||||||
|
|
||||||
rtpMgrs[i].addTarget(destAddr);
|
|
||||||
|
|
||||||
System.err.println("Created RTP session at " + localPort + " to: " + ipAddress + " " + port);
|
|
||||||
|
|
||||||
sendStream = rtpMgrs[i].createSendStream(dataOutput, i);
|
|
||||||
|
|
||||||
sendStreams.add(sendStream);
|
|
||||||
|
|
||||||
sendStream.start();
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return e.getMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set transmit activity. If the active is true, the instance should trasmit.
|
|
||||||
* If it is set to false, the instance should pause transmit.
|
|
||||||
*
|
|
||||||
* @param active
|
|
||||||
*/
|
|
||||||
public void setTrasmit(boolean active) {
|
|
||||||
for (SendStream sendStream : sendStreams) {
|
|
||||||
try {
|
|
||||||
if (active) {
|
|
||||||
sendStream.start();
|
|
||||||
System.out.println("START");
|
|
||||||
} else {
|
|
||||||
sendStream.stop();
|
|
||||||
System.out.println("STOP");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* *************************************************************
|
|
||||||
* Convenience methods to handle processor's state changes.
|
|
||||||
* **************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
private Integer stateLock = new Integer(0);
|
|
||||||
private boolean failed = false;
|
|
||||||
|
|
||||||
Integer getStateLock() {
|
|
||||||
return stateLock;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setFailed() {
|
|
||||||
failed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized boolean waitForState(Processor p, int state) {
|
|
||||||
p.addControllerListener(new StateListener());
|
|
||||||
failed = false;
|
|
||||||
|
|
||||||
// Call the required method on the processor
|
|
||||||
if (state == Processor.Configured) {
|
|
||||||
p.configure();
|
|
||||||
} else if (state == Processor.Realized) {
|
|
||||||
p.realize();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait until we get an event that confirms the
|
|
||||||
// success of the method, or a failure event.
|
|
||||||
// See StateListener inner class
|
|
||||||
while (p.getState() < state && !failed) {
|
|
||||||
synchronized (getStateLock()) {
|
|
||||||
try {
|
|
||||||
getStateLock().wait();
|
|
||||||
} catch (InterruptedException ie) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (failed)
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* *************************************************************
|
|
||||||
* Inner Classes
|
|
||||||
* **************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
class StateListener implements ControllerListener {
|
|
||||||
|
|
||||||
public void controllerUpdate(ControllerEvent ce) {
|
|
||||||
|
|
||||||
// If there was an error during configure or
|
|
||||||
// realize, the processor will be closed
|
|
||||||
if (ce instanceof ControllerClosedEvent)
|
|
||||||
setFailed();
|
|
||||||
|
|
||||||
// All controller events, send a notification
|
|
||||||
// to the waiting thread in waitForState method.
|
|
||||||
if (ce instanceof ControllerEvent) {
|
|
||||||
synchronized (getStateLock()) {
|
|
||||||
getStateLock().notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String args[]) {
|
|
||||||
|
|
||||||
InetAddress localhost;
|
|
||||||
try {
|
|
||||||
localhost = InetAddress.getLocalHost();
|
|
||||||
|
|
||||||
AudioChannel audioChannel0 = new AudioChannel(new MediaLocator("javasound://8000"), localhost.getHostAddress(), localhost.getHostAddress(), 7002, 7020, new AudioFormat(AudioFormat.GSM_RTP));
|
|
||||||
AudioChannel audioChannel1 = new AudioChannel(new MediaLocator("javasound://8000"), localhost.getHostAddress(), localhost.getHostAddress(), 7020, 7002, new AudioFormat(AudioFormat.GSM_RTP));
|
|
||||||
|
|
||||||
audioChannel0.start();
|
|
||||||
audioChannel1.start();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(5000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
audioChannel0.setTrasmit(false);
|
|
||||||
audioChannel1.setTrasmit(false);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(5000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
audioChannel0.setTrasmit(true);
|
|
||||||
audioChannel1.setTrasmit(true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(5000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
audioChannel0.stop();
|
|
||||||
audioChannel1.stop();
|
|
||||||
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
/**
|
|
||||||
* $RCSfile$
|
|
||||||
* $Revision: $
|
|
||||||
* $Date: 08/11/2006
|
|
||||||
* <p/>
|
|
||||||
* Copyright 2003-2006 Jive Software.
|
|
||||||
* <p/>
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* <p/>
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* <p/>
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jivesoftware.jingleaudio.jmf;
|
|
||||||
|
|
||||||
import org.jivesoftware.smackx.jingle.media.PayloadType;
|
|
||||||
|
|
||||||
import javax.media.format.AudioFormat;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Audio Format Utils.
|
|
||||||
*
|
|
||||||
* @author Thiago Camargo
|
|
||||||
*/
|
|
||||||
public class AudioFormatUtils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a JMF AudioFormat for a given Jingle Payload type.
|
|
||||||
* Return null if the payload is not supported by this jmf API.
|
|
||||||
*
|
|
||||||
* @param payloadtype
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static AudioFormat getAudioFormat(PayloadType payloadtype) {
|
|
||||||
|
|
||||||
switch (payloadtype.getId()) {
|
|
||||||
case 0:
|
|
||||||
return new AudioFormat(AudioFormat.ULAW_RTP);
|
|
||||||
case 3:
|
|
||||||
return new AudioFormat(AudioFormat.GSM_RTP);
|
|
||||||
case 4:
|
|
||||||
return new AudioFormat(AudioFormat.G723_RTP);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,175 +0,0 @@
|
||||||
package org.jivesoftware.jingleaudio.jmf; /**
|
|
||||||
* $RCSfile$
|
|
||||||
* $Revision: $
|
|
||||||
* $Date: 08/11/2006
|
|
||||||
* <p/>
|
|
||||||
* Copyright 2003-2006 Jive Software.
|
|
||||||
* <p/>
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* <p/>
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* <p/>
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import org.jivesoftware.jingleaudio.jmf.AudioChannel;
|
|
||||||
import org.jivesoftware.jingleaudio.jmf.AudioFormatUtils;
|
|
||||||
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
|
|
||||||
import org.jivesoftware.smackx.jingle.media.PayloadType;
|
|
||||||
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
|
||||||
|
|
||||||
import javax.media.MediaLocator;
|
|
||||||
import javax.media.format.AudioFormat;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This Class implements a complete JingleMediaSession.
|
|
||||||
* It sould be used to transmit and receive audio captured from the Mic.
|
|
||||||
* This Class should be automaticly controlled by JingleSession.
|
|
||||||
* But you could also use in any VOIP application.
|
|
||||||
* For better NAT Traversal support this implementation don´t support only receive or only transmit.
|
|
||||||
* To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit()
|
|
||||||
*
|
|
||||||
* @author Thiago Camargo
|
|
||||||
*/
|
|
||||||
public class AudioMediaSession extends JingleMediaSession {
|
|
||||||
|
|
||||||
private AudioFormat format;
|
|
||||||
private AudioChannel audioChannel;
|
|
||||||
private String locator = "javasound://";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a org.jivesoftware.jingleaudio.jmf.AudioMediaSession with defined payload type, remote and local candidates
|
|
||||||
*
|
|
||||||
* @param payloadType Payload of the jmf
|
|
||||||
* @param remote The remote information. The candidate that the jmf will be sent to.
|
|
||||||
* @param local The local information. The candidate that will receive the jmf
|
|
||||||
*/
|
|
||||||
public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote,
|
|
||||||
final TransportCandidate local) {
|
|
||||||
this(payloadType, remote, local, "javasound://");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a org.jivesoftware.jingleaudio.jmf.AudioMediaSession with defined payload type, remote and local candidates
|
|
||||||
*
|
|
||||||
* @param payloadType Payload of the jmf
|
|
||||||
* @param remote The remote information. The candidate that the jmf will be sent to.
|
|
||||||
* @param local The local information. The candidate that will receive the jmf
|
|
||||||
*/
|
|
||||||
public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote,
|
|
||||||
final TransportCandidate local, String locator) {
|
|
||||||
super(payloadType, remote, local);
|
|
||||||
if (locator != null && !locator.equals(""))
|
|
||||||
this.locator = locator;
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the Audio Channel to make it able to send and receive audio
|
|
||||||
*/
|
|
||||||
public void initialize() {
|
|
||||||
|
|
||||||
String ip;
|
|
||||||
String localIp;
|
|
||||||
int localPort;
|
|
||||||
int remotePort;
|
|
||||||
|
|
||||||
if (this.getLocal().getSymmetric() != null) {
|
|
||||||
ip = this.getLocal().getIp();
|
|
||||||
localIp = this.getLocal().getLocalIp();
|
|
||||||
localPort = getFreePort();
|
|
||||||
remotePort = this.getLocal().getSymmetric().getPort();
|
|
||||||
|
|
||||||
System.out.println(this.getLocal().getConnection() + " " + ip + ": " + localPort + "->" + remotePort);
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ip = this.getRemote().getIp();
|
|
||||||
localIp = this.getLocal().getLocalIp();
|
|
||||||
localPort = this.getLocal().getPort();
|
|
||||||
remotePort = this.getRemote().getPort();
|
|
||||||
}
|
|
||||||
|
|
||||||
audioChannel = new AudioChannel(new MediaLocator(locator), localIp, ip, localPort, remotePort, AudioFormatUtils.getAudioFormat(this.getPayloadType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts transmission and for NAT Traversal reasons start receiving also.
|
|
||||||
*/
|
|
||||||
public void startTrasmit() {
|
|
||||||
audioChannel.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set transmit activity. If the active is true, the instance should trasmit.
|
|
||||||
* If it is set to false, the instance should pause transmit.
|
|
||||||
*
|
|
||||||
* @param active
|
|
||||||
*/
|
|
||||||
public void setTrasmit(boolean active) {
|
|
||||||
audioChannel.setTrasmit(active);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
|
|
||||||
*/
|
|
||||||
public void startReceive() {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops transmission and for NAT Traversal reasons stop receiving also.
|
|
||||||
*/
|
|
||||||
public void stopTrasmit() {
|
|
||||||
if (audioChannel != null)
|
|
||||||
audioChannel.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
|
|
||||||
*/
|
|
||||||
public void stopReceive() {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a free port we can use.
|
|
||||||
*
|
|
||||||
* @return A free port number.
|
|
||||||
*/
|
|
||||||
protected int getFreePort() {
|
|
||||||
ServerSocket ss;
|
|
||||||
int freePort = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
freePort = (int) (10000 + Math.round(Math.random() * 10000));
|
|
||||||
freePort = freePort % 2 == 0 ? freePort : freePort + 1;
|
|
||||||
try {
|
|
||||||
ss = new ServerSocket(freePort);
|
|
||||||
freePort = ss.getLocalPort();
|
|
||||||
ss.close();
|
|
||||||
return freePort;
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
ss = new ServerSocket(0);
|
|
||||||
freePort = ss.getLocalPort();
|
|
||||||
ss.close();
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return freePort;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,147 +0,0 @@
|
||||||
/**
|
|
||||||
* $RCSfile$
|
|
||||||
* $Revision: $
|
|
||||||
* $Date: 08/11/2006
|
|
||||||
* <p/>
|
|
||||||
* Copyright 2003-2006 Jive Software.
|
|
||||||
* <p/>
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* <p/>
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* <p/>
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jivesoftware.jingleaudio.jmf;
|
|
||||||
|
|
||||||
import javax.media.*;
|
|
||||||
import javax.media.protocol.DataSource;
|
|
||||||
import javax.media.rtp.*;
|
|
||||||
import javax.media.rtp.event.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class implements receive methods and listeners to be used in AudioChannel
|
|
||||||
*
|
|
||||||
* @author Thiago Camargo
|
|
||||||
*/
|
|
||||||
public class AudioReceiver implements ReceiveStreamListener, SessionListener,
|
|
||||||
ControllerListener {
|
|
||||||
|
|
||||||
boolean dataReceived = false;
|
|
||||||
|
|
||||||
Object dataSync;
|
|
||||||
|
|
||||||
public AudioReceiver(Object dataSync) {
|
|
||||||
this.dataSync = dataSync;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JingleSessionListener.
|
|
||||||
*/
|
|
||||||
public synchronized void update(SessionEvent evt) {
|
|
||||||
if (evt instanceof NewParticipantEvent) {
|
|
||||||
Participant p = ((NewParticipantEvent) evt).getParticipant();
|
|
||||||
System.err.println(" - A new participant had just joined: " + p.getCNAME());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ReceiveStreamListener
|
|
||||||
*/
|
|
||||||
public synchronized void update(ReceiveStreamEvent evt) {
|
|
||||||
|
|
||||||
RTPManager mgr = (RTPManager) evt.getSource();
|
|
||||||
Participant participant = evt.getParticipant(); // could be null.
|
|
||||||
ReceiveStream stream = evt.getReceiveStream(); // could be null.
|
|
||||||
|
|
||||||
if (evt instanceof RemotePayloadChangeEvent) {
|
|
||||||
|
|
||||||
System.err.println(" - Received an RTP PayloadChangeEvent.");
|
|
||||||
System.err.println("Sorry, cannot handle payload change.");
|
|
||||||
// System.exit(0);
|
|
||||||
|
|
||||||
} else if (evt instanceof NewReceiveStreamEvent) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
stream = ((NewReceiveStreamEvent) evt).getReceiveStream();
|
|
||||||
DataSource ds = stream.getDataSource();
|
|
||||||
|
|
||||||
// Find out the formats.
|
|
||||||
RTPControl ctl = (RTPControl) ds.getControl("javax.jmf.rtp.RTPControl");
|
|
||||||
if (ctl != null) {
|
|
||||||
System.err.println(" - Recevied new RTP stream: " + ctl.getFormat());
|
|
||||||
} else
|
|
||||||
System.err.println(" - Recevied new RTP stream");
|
|
||||||
|
|
||||||
if (participant == null)
|
|
||||||
System.err.println(" The sender of this stream had yet to be identified.");
|
|
||||||
else {
|
|
||||||
System.err.println(" The stream comes from: " + participant.getCNAME());
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a player by passing datasource to the Media Manager
|
|
||||||
Player p = javax.media.Manager.createPlayer(ds);
|
|
||||||
if (p == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
p.addControllerListener(this);
|
|
||||||
p.realize();
|
|
||||||
|
|
||||||
// Notify intialize() that a new stream had arrived.
|
|
||||||
synchronized (dataSync) {
|
|
||||||
dataReceived = true;
|
|
||||||
dataSync.notifyAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.err.println("NewReceiveStreamEvent exception " + e.getMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (evt instanceof StreamMappedEvent) {
|
|
||||||
|
|
||||||
if (stream != null && stream.getDataSource() != null) {
|
|
||||||
DataSource ds = stream.getDataSource();
|
|
||||||
// Find out the formats.
|
|
||||||
RTPControl ctl = (RTPControl) ds.getControl("javax.jmf.rtp.RTPControl");
|
|
||||||
System.err.println(" - The previously unidentified stream ");
|
|
||||||
if (ctl != null)
|
|
||||||
System.err.println(" " + ctl.getFormat());
|
|
||||||
System.err.println(" had now been identified as sent by: " + participant.getCNAME());
|
|
||||||
}
|
|
||||||
} else if (evt instanceof ByeEvent) {
|
|
||||||
|
|
||||||
System.err.println(" - Got \"bye\" from: " + participant.getCNAME());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ControllerListener for the Players.
|
|
||||||
*/
|
|
||||||
public synchronized void controllerUpdate(ControllerEvent ce) {
|
|
||||||
|
|
||||||
Player p = (Player) ce.getSourceController();
|
|
||||||
|
|
||||||
if (p == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Get this when the internal players are realized.
|
|
||||||
if (ce instanceof RealizeCompleteEvent) {
|
|
||||||
p.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ce instanceof ControllerErrorEvent) {
|
|
||||||
p.removeControllerListener(this);
|
|
||||||
System.err.println("Receiver internal error: " + ce);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,127 +0,0 @@
|
||||||
package org.jivesoftware.jingleaudio.jmf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* $RCSfile$
|
|
||||||
* $Revision: $
|
|
||||||
* $Date: 08/11/2006
|
|
||||||
* <p/>
|
|
||||||
* Copyright 2003-2006 Jive Software.
|
|
||||||
* <p/>
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* <p/>
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* <p/>
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
|
|
||||||
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
|
|
||||||
import org.jivesoftware.smackx.jingle.media.PayloadType;
|
|
||||||
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
|
||||||
import org.jivesoftware.jingleaudio.JMFInit;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements a jingleMediaManager using JMF based API.
|
|
||||||
* It supports GSM and G723 codecs.
|
|
||||||
* <i>This API only currently works on windows and Mac.</i>
|
|
||||||
*
|
|
||||||
* @author Thiago Camargo
|
|
||||||
*/
|
|
||||||
public class JmfMediaManager extends JingleMediaManager {
|
|
||||||
|
|
||||||
private List<PayloadType> payloads = new ArrayList<PayloadType>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a Media Manager instance
|
|
||||||
*/
|
|
||||||
public JmfMediaManager() {
|
|
||||||
setupPayloads();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new jingleMediaSession
|
|
||||||
*
|
|
||||||
* @param payloadType
|
|
||||||
* @param remote
|
|
||||||
* @param local
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public JingleMediaSession createMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local) {
|
|
||||||
return new AudioMediaSession(payloadType, remote, local);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup API supported Payloads
|
|
||||||
*/
|
|
||||||
private void setupPayloads() {
|
|
||||||
payloads.add(new PayloadType.Audio(3, "gsm"));
|
|
||||||
payloads.add(new PayloadType.Audio(4, "g723"));
|
|
||||||
payloads.add(new PayloadType.Audio(0, "PCMU", 16000));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return all supported Payloads for this Manager
|
|
||||||
*
|
|
||||||
* @return The Payload List
|
|
||||||
*/
|
|
||||||
public List<PayloadType> getPayloads() {
|
|
||||||
return payloads;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs JMFInit the first time the application is started so that capture
|
|
||||||
* devices are properly detected and initialized by JMF.
|
|
||||||
*/
|
|
||||||
public static void setupJMF() {
|
|
||||||
// .jmf is the place where we store the jmf.properties file used
|
|
||||||
// by JMF. if the directory does not exist or it does not contain
|
|
||||||
// a jmf.properties file. or if the jmf.properties file has 0 length
|
|
||||||
// then this is the first time we're running and should continue to
|
|
||||||
// with JMFInit
|
|
||||||
String homeDir = System.getProperty("user.home");
|
|
||||||
File jmfDir = new File(homeDir, ".jmf");
|
|
||||||
String classpath = System.getProperty("java.class.path");
|
|
||||||
classpath += System.getProperty("path.separator")
|
|
||||||
+ jmfDir.getAbsolutePath();
|
|
||||||
System.setProperty("java.class.path", classpath);
|
|
||||||
|
|
||||||
if (!jmfDir.exists())
|
|
||||||
jmfDir.mkdir();
|
|
||||||
|
|
||||||
File jmfProperties = new File(jmfDir, "jmf.properties");
|
|
||||||
|
|
||||||
if (!jmfProperties.exists()) {
|
|
||||||
try {
|
|
||||||
jmfProperties.createNewFile();
|
|
||||||
}
|
|
||||||
catch (IOException ex) {
|
|
||||||
System.out.println("Failed to create jmf.properties");
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we're running on linux checkout that libjmutil.so is where it
|
|
||||||
// should be and put it there.
|
|
||||||
runLinuxPreInstall();
|
|
||||||
|
|
||||||
//if (jmfProperties.length() == 0) {
|
|
||||||
new JMFInit(null, false);
|
|
||||||
//}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void runLinuxPreInstall() {
|
|
||||||
// @TODO Implement Linux Pre-Install
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,225 +0,0 @@
|
||||||
/**
|
|
||||||
* $RCSfile$
|
|
||||||
* $Revision: $
|
|
||||||
* $Date: 25/12/2006
|
|
||||||
* <p/>
|
|
||||||
* Copyright 2003-2006 Jive Software.
|
|
||||||
* <p/>
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* <p/>
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* <p/>
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jivesoftware.jingleaudio.jspeex;
|
|
||||||
|
|
||||||
import mil.jfcom.cie.media.session.MediaSession;
|
|
||||||
import mil.jfcom.cie.media.session.MediaSessionListener;
|
|
||||||
import mil.jfcom.cie.media.session.StreamPlayer;
|
|
||||||
import mil.jfcom.cie.media.srtp.packetizer.SpeexFormat;
|
|
||||||
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
|
|
||||||
import org.jivesoftware.smackx.jingle.media.PayloadType;
|
|
||||||
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
|
||||||
|
|
||||||
import javax.media.NoProcessorException;
|
|
||||||
import javax.media.format.UnsupportedFormatException;
|
|
||||||
import javax.media.rtp.rtcp.SenderReport;
|
|
||||||
import javax.media.rtp.rtcp.SourceDescription;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.DatagramSocket;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This Class implements a complete JingleMediaSession.
|
|
||||||
* It sould be used to transmit and receive audio captured from the Mic.
|
|
||||||
* This Class should be automaticly controlled by JingleSession.
|
|
||||||
* But you could also use in any VOIP application.
|
|
||||||
* For better NAT Traversal support this implementation don´t support only receive or only transmit.
|
|
||||||
* To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit()
|
|
||||||
*
|
|
||||||
* @author Thiago Camargo
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class AudioMediaSession extends JingleMediaSession implements MediaSessionListener {
|
|
||||||
|
|
||||||
private MediaSession mediaSession;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create session for test program.
|
|
||||||
*
|
|
||||||
* @param micOn microphone turned on
|
|
||||||
*/
|
|
||||||
public static MediaSession createSession(String localhost, int localPort, String remoteHost, int remotePort, MediaSessionListener eventHandler, int quality, boolean secure, boolean micOn) throws NoProcessorException, UnsupportedFormatException, IOException, GeneralSecurityException {
|
|
||||||
|
|
||||||
SpeexFormat.setFramesPerPacket(1);
|
|
||||||
/**
|
|
||||||
* The master key. Hardcoded for now.
|
|
||||||
*/
|
|
||||||
byte[] masterKey = new byte[]{(byte) 0xE1, (byte) 0xF9, 0x7A, 0x0D, 0x3E, 0x01, (byte) 0x8B, (byte) 0xE0, (byte) 0xD6, 0x4F, (byte) 0xA3, 0x2C, 0x06, (byte) 0xDE, 0x41, 0x39};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The master salt. Hardcoded for now.
|
|
||||||
*/
|
|
||||||
byte[] masterSalt = new byte[]{0x0E, (byte) 0xC6, 0x75, (byte) 0xAD, 0x49, (byte) 0x8A, (byte) 0xFE, (byte) 0xEB, (byte) 0xB6, (byte) 0x96, 0x0B, 0x3A, (byte) 0xAB, (byte) 0xE6};
|
|
||||||
|
|
||||||
DatagramSocket[] localPorts = MediaSession.getLocalPorts(InetAddress.getByName(localhost), localPort);
|
|
||||||
MediaSession session = MediaSession.createInstance(remoteHost, remotePort, localPorts, quality, secure, masterKey, masterSalt);
|
|
||||||
session.setListener(eventHandler);
|
|
||||||
|
|
||||||
session.setSourceDescription(new SourceDescription[]{new SourceDescription(SourceDescription.SOURCE_DESC_NAME, "Superman", 1, false), new SourceDescription(SourceDescription.SOURCE_DESC_EMAIL, "cdcie.tester@je.jfcom.mil", 1, false), new SourceDescription(SourceDescription.SOURCE_DESC_LOC, InetAddress.getByName(localhost) + " Port " + session.getLocalDataPort(), 1, false), new SourceDescription(SourceDescription.SOURCE_DESC_TOOL, "JFCOM CDCIE Audio Chat", 1, false)});
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a org.jivesoftware.jingleaudio.jmf.AudioMediaSession with defined payload type, remote and local candidates
|
|
||||||
*
|
|
||||||
* @param payloadType Payload of the jmf
|
|
||||||
* @param remote The remote information. The candidate that the jmf will be sent to.
|
|
||||||
* @param local The local information. The candidate that will receive the jmf
|
|
||||||
*/
|
|
||||||
public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote,
|
|
||||||
final TransportCandidate local) {
|
|
||||||
super(payloadType, remote, local);
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the Audio Channel to make it able to send and receive audio
|
|
||||||
*/
|
|
||||||
public void initialize() {
|
|
||||||
|
|
||||||
String ip;
|
|
||||||
String localIp;
|
|
||||||
int localPort;
|
|
||||||
int remotePort;
|
|
||||||
|
|
||||||
if (this.getLocal().getSymmetric() != null) {
|
|
||||||
ip = this.getLocal().getIp();
|
|
||||||
localIp = this.getLocal().getLocalIp();
|
|
||||||
localPort = getFreePort();
|
|
||||||
remotePort = this.getLocal().getSymmetric().getPort();
|
|
||||||
|
|
||||||
System.out.println(this.getLocal().getConnection() + " " + ip + ": " + localPort + "->" + remotePort);
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ip = this.getRemote().getIp();
|
|
||||||
localIp = this.getLocal().getLocalIp();
|
|
||||||
localPort = this.getLocal().getPort();
|
|
||||||
remotePort = this.getRemote().getPort();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
mediaSession = createSession(localIp, localPort, ip, remotePort, this, 2, false, true);
|
|
||||||
}
|
|
||||||
catch (NoProcessorException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
catch (UnsupportedFormatException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
catch (GeneralSecurityException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts transmission and for NAT Traversal reasons start receiving also.
|
|
||||||
*/
|
|
||||||
public void startTrasmit() {
|
|
||||||
try {
|
|
||||||
System.out.println("start");
|
|
||||||
mediaSession.start(true);
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set transmit activity. If the active is true, the instance should trasmit.
|
|
||||||
* If it is set to false, the instance should pause transmit.
|
|
||||||
*
|
|
||||||
* @param active
|
|
||||||
*/
|
|
||||||
public void setTrasmit(boolean active) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
|
|
||||||
*/
|
|
||||||
public void startReceive() {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops transmission and for NAT Traversal reasons stop receiving also.
|
|
||||||
*/
|
|
||||||
public void stopTrasmit() {
|
|
||||||
if (mediaSession != null)
|
|
||||||
mediaSession.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
|
|
||||||
*/
|
|
||||||
public void stopReceive() {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
public void newStreamIdentified(StreamPlayer streamPlayer) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void senderReportReceived(SenderReport report) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void streamClosed(StreamPlayer stream, boolean timeout) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a free port we can use.
|
|
||||||
*
|
|
||||||
* @return A free port number.
|
|
||||||
*/
|
|
||||||
protected int getFreePort() {
|
|
||||||
ServerSocket ss;
|
|
||||||
int freePort = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
freePort = (int) (10000 + Math.round(Math.random() * 10000));
|
|
||||||
freePort = freePort % 2 == 0 ? freePort : freePort + 1;
|
|
||||||
try {
|
|
||||||
ss = new ServerSocket(freePort);
|
|
||||||
freePort = ss.getLocalPort();
|
|
||||||
ss.close();
|
|
||||||
return freePort;
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
ss = new ServerSocket(0);
|
|
||||||
freePort = ss.getLocalPort();
|
|
||||||
ss.close();
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return freePort;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,114 +0,0 @@
|
||||||
/**
|
|
||||||
* $RCSfile$
|
|
||||||
* $Revision: $
|
|
||||||
* $Date: 25/12/2006
|
|
||||||
* <p/>
|
|
||||||
* Copyright 2003-2006 Jive Software.
|
|
||||||
* <p/>
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* <p/>
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* <p/>
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jivesoftware.jingleaudio.jspeex;
|
|
||||||
|
|
||||||
import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
|
|
||||||
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
|
|
||||||
import org.jivesoftware.smackx.jingle.media.PayloadType;
|
|
||||||
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
|
||||||
import org.jivesoftware.jingleaudio.JMFInit;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements a jingleMediaManager using JMF based API and JSpeex.
|
|
||||||
* It supports Speex codec.
|
|
||||||
* <i>This API only currently works on windows.</i>
|
|
||||||
*
|
|
||||||
* @author Thiago Camargo
|
|
||||||
*/
|
|
||||||
public class SpeexMediaManager extends JingleMediaManager {
|
|
||||||
|
|
||||||
private List<PayloadType> payloads = new ArrayList<PayloadType>();
|
|
||||||
|
|
||||||
public SpeexMediaManager() {
|
|
||||||
setupPayloads();
|
|
||||||
setupJMF();
|
|
||||||
}
|
|
||||||
|
|
||||||
public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local) {
|
|
||||||
return new AudioMediaSession(payloadType, remote, local);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup API supported Payloads
|
|
||||||
*/
|
|
||||||
private void setupPayloads() {
|
|
||||||
payloads.add(new PayloadType.Audio(15, "speex"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return all supported Payloads for this Manager
|
|
||||||
*
|
|
||||||
* @return The Payload List
|
|
||||||
*/
|
|
||||||
public List<PayloadType> getPayloads() {
|
|
||||||
return payloads;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs JMFInit the first time the application is started so that capture
|
|
||||||
* devices are properly detected and initialized by JMF.
|
|
||||||
*/
|
|
||||||
public static void setupJMF() {
|
|
||||||
// .jmf is the place where we store the jmf.properties file used
|
|
||||||
// by JMF. if the directory does not exist or it does not contain
|
|
||||||
// a jmf.properties file. or if the jmf.properties file has 0 length
|
|
||||||
// then this is the first time we're running and should continue to
|
|
||||||
// with JMFInit
|
|
||||||
String homeDir = System.getProperty("user.home");
|
|
||||||
File jmfDir = new File(homeDir, ".jmf");
|
|
||||||
String classpath = System.getProperty("java.class.path");
|
|
||||||
classpath += System.getProperty("path.separator")
|
|
||||||
+ jmfDir.getAbsolutePath();
|
|
||||||
System.setProperty("java.class.path", classpath);
|
|
||||||
|
|
||||||
if (!jmfDir.exists())
|
|
||||||
jmfDir.mkdir();
|
|
||||||
|
|
||||||
File jmfProperties = new File(jmfDir, "jmf.properties");
|
|
||||||
|
|
||||||
if (!jmfProperties.exists()) {
|
|
||||||
try {
|
|
||||||
jmfProperties.createNewFile();
|
|
||||||
}
|
|
||||||
catch (IOException ex) {
|
|
||||||
System.out.println("Failed to create jmf.properties");
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we're running on linux checkout that libjmutil.so is where it
|
|
||||||
// should be and put it there.
|
|
||||||
runLinuxPreInstall();
|
|
||||||
|
|
||||||
if (jmfProperties.length() == 0) {
|
|
||||||
new JMFInit(null, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void runLinuxPreInstall() {
|
|
||||||
// @TODO Implement Linux Pre-Install
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
package org.jivesoftware.jingleaudio.multi;
|
|
||||||
|
|
||||||
import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
|
|
||||||
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
|
|
||||||
import org.jivesoftware.smackx.jingle.media.PayloadType;
|
|
||||||
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements a MultiMediaManager using other JingleMediaManager implementations.
|
|
||||||
* It supports every Codecs that JingleMediaManagers added has.
|
|
||||||
*
|
|
||||||
* @author Thiago Camargo
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class MultiMediaManager extends JingleMediaManager {
|
|
||||||
|
|
||||||
private List<JingleMediaManager> managers = new ArrayList<JingleMediaManager>();
|
|
||||||
|
|
||||||
public MultiMediaManager() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addMediaManager(JingleMediaManager manager) {
|
|
||||||
managers.add(manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeMediaManager(JingleMediaManager manager) {
|
|
||||||
managers.remove(manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return all supported Payloads for this Manager.
|
|
||||||
*
|
|
||||||
* @return The Payload List
|
|
||||||
*/
|
|
||||||
public List<PayloadType> getPayloads() {
|
|
||||||
List<PayloadType> list = new ArrayList<PayloadType>();
|
|
||||||
for (JingleMediaManager manager : managers) {
|
|
||||||
for (PayloadType payloadType : manager.getPayloads()) {
|
|
||||||
if (!list.contains(payloadType))
|
|
||||||
list.add(payloadType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new JingleMediaSession
|
|
||||||
*
|
|
||||||
* @param payloadType
|
|
||||||
* @param remote
|
|
||||||
* @param local
|
|
||||||
* @return JingleMediaSession
|
|
||||||
*/
|
|
||||||
public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local) {
|
|
||||||
for (JingleMediaManager manager : managers) {
|
|
||||||
if (manager.getPayloads().contains(payloadType)) {
|
|
||||||
return manager.createMediaSession(payloadType, remote, local);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,440 +0,0 @@
|
||||||
import junit.framework.TestCase;
|
|
||||||
import org.jivesoftware.jingleaudio.jmf.AudioChannel;
|
|
||||||
import org.jivesoftware.jingleaudio.jmf.JmfMediaManager;
|
|
||||||
import org.jivesoftware.jingleaudio.jspeex.SpeexMediaManager;
|
|
||||||
import org.jivesoftware.jingleaudio.multi.MultiMediaManager;
|
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
|
||||||
import org.jivesoftware.smack.XMPPException;
|
|
||||||
import org.jivesoftware.smack.test.SmackTestCase;
|
|
||||||
import org.jivesoftware.smackx.jingle.IncomingJingleSession;
|
|
||||||
import org.jivesoftware.smackx.jingle.JingleManager;
|
|
||||||
import org.jivesoftware.smackx.jingle.JingleSessionRequest;
|
|
||||||
import org.jivesoftware.smackx.jingle.OutgoingJingleSession;
|
|
||||||
import org.jivesoftware.smackx.jingle.listeners.JingleSessionRequestListener;
|
|
||||||
import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
|
|
||||||
import org.jivesoftware.smackx.jingle.nat.BridgedTransportManager;
|
|
||||||
import org.jivesoftware.smackx.jingle.nat.ICETransportManager;
|
|
||||||
import org.jivesoftware.smackx.jingle.nat.STUNTransportManager;
|
|
||||||
import org.jivesoftware.smackx.jingle.nat.BasicTransportManager;
|
|
||||||
|
|
||||||
import javax.media.MediaLocator;
|
|
||||||
import javax.media.format.AudioFormat;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* $RCSfile$
|
|
||||||
* $Revision: $
|
|
||||||
* $Date: 09/11/2006
|
|
||||||
* <p/>
|
|
||||||
* Copyright 2003-2006 Jive Software.
|
|
||||||
* <p/>
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* <p/>
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* <p/>
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
public class JingleMediaTest extends SmackTestCase {
|
|
||||||
|
|
||||||
public JingleMediaTest(final String name) {
|
|
||||||
super(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testCompleteJmf() {
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
XMPPConnection x0 = getConnection(0);
|
|
||||||
XMPPConnection x1 = getConnection(1);
|
|
||||||
|
|
||||||
ICETransportManager icetm0 = new ICETransportManager(x0, "jivesoftware.com", 3478);
|
|
||||||
ICETransportManager icetm1 = new ICETransportManager(x1, "jivesoftware.com", 3478);
|
|
||||||
|
|
||||||
final JingleManager jm0 = new JingleManager(
|
|
||||||
x0, icetm0);
|
|
||||||
final JingleManager jm1 = new JingleManager(
|
|
||||||
x1, icetm1);
|
|
||||||
|
|
||||||
jm0.addCreationListener(icetm0);
|
|
||||||
jm1.addCreationListener(icetm1);
|
|
||||||
|
|
||||||
JingleMediaManager jingleMediaManager0 = new JmfMediaManager();
|
|
||||||
JingleMediaManager jingleMediaManager1 = new JmfMediaManager();
|
|
||||||
|
|
||||||
jm0.setMediaManager(jingleMediaManager0);
|
|
||||||
jm1.setMediaManager(jingleMediaManager1);
|
|
||||||
|
|
||||||
jm1.addJingleSessionRequestListener(new JingleSessionRequestListener() {
|
|
||||||
public void sessionRequested(final JingleSessionRequest request) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
IncomingJingleSession session = request.accept(jm1.getMediaManager().getPayloads());
|
|
||||||
session.start(request);
|
|
||||||
}
|
|
||||||
catch (XMPPException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
OutgoingJingleSession js0 = jm0.createOutgoingJingleSession(x1.getUser());
|
|
||||||
|
|
||||||
js0.start();
|
|
||||||
|
|
||||||
Thread.sleep(60000);
|
|
||||||
js0.terminate();
|
|
||||||
|
|
||||||
Thread.sleep(6000);
|
|
||||||
|
|
||||||
x0.disconnect();
|
|
||||||
x1.disconnect();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testCompleteMulti() {
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
XMPPConnection x0 = getConnection(0);
|
|
||||||
XMPPConnection x1 = getConnection(1);
|
|
||||||
|
|
||||||
|
|
||||||
ICETransportManager icetm0 = new ICETransportManager(x0, "jivesoftware.com", 3478);
|
|
||||||
ICETransportManager icetm1 = new ICETransportManager(x1, "jivesoftware.com", 3478);
|
|
||||||
|
|
||||||
final JingleManager jm0 = new JingleManager(
|
|
||||||
x0, icetm0);
|
|
||||||
final JingleManager jm1 = new JingleManager(
|
|
||||||
x1, icetm1);
|
|
||||||
|
|
||||||
jm0.addCreationListener(icetm0);
|
|
||||||
jm1.addCreationListener(icetm1);
|
|
||||||
/*
|
|
||||||
|
|
||||||
final JingleManager jm0 = new JingleManager(
|
|
||||||
x0, new BasicTransportManager());
|
|
||||||
final JingleManager jm1 = new JingleManager(
|
|
||||||
x1, new BasicTransportManager());
|
|
||||||
*/
|
|
||||||
MultiMediaManager jingleMediaManager0 = new MultiMediaManager();
|
|
||||||
jingleMediaManager0.addMediaManager(new SpeexMediaManager());
|
|
||||||
jingleMediaManager0.addMediaManager(new JmfMediaManager());
|
|
||||||
MultiMediaManager jingleMediaManager1 = new MultiMediaManager();
|
|
||||||
jingleMediaManager1.addMediaManager(new JmfMediaManager());
|
|
||||||
jingleMediaManager1.addMediaManager(new SpeexMediaManager());
|
|
||||||
|
|
||||||
jm0.setMediaManager(jingleMediaManager0);
|
|
||||||
jm1.setMediaManager(jingleMediaManager1);
|
|
||||||
|
|
||||||
jm1.addJingleSessionRequestListener(new JingleSessionRequestListener() {
|
|
||||||
public void sessionRequested(final JingleSessionRequest request) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
IncomingJingleSession session = request.accept(jm1.getMediaManager().getPayloads());
|
|
||||||
session.start(request);
|
|
||||||
}
|
|
||||||
catch (XMPPException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
OutgoingJingleSession js0 = jm0.createOutgoingJingleSession(x1.getUser());
|
|
||||||
|
|
||||||
js0.start();
|
|
||||||
|
|
||||||
Thread.sleep(60000);
|
|
||||||
js0.terminate();
|
|
||||||
|
|
||||||
Thread.sleep(6000);
|
|
||||||
|
|
||||||
x0.disconnect();
|
|
||||||
x1.disconnect();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testCompleteSpeex() {
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
//XMPPConnection.DEBUG_ENABLED = true;
|
|
||||||
|
|
||||||
XMPPConnection x0 = getConnection(0);
|
|
||||||
XMPPConnection x1 = getConnection(1);
|
|
||||||
|
|
||||||
final JingleManager jm0 = new JingleManager(
|
|
||||||
x0, new STUNTransportManager());
|
|
||||||
final JingleManager jm1 = new JingleManager(
|
|
||||||
x1, new STUNTransportManager());
|
|
||||||
|
|
||||||
JingleMediaManager jingleMediaManager0 = new SpeexMediaManager();
|
|
||||||
JingleMediaManager jingleMediaManager1 = new SpeexMediaManager();
|
|
||||||
|
|
||||||
jm0.setMediaManager(jingleMediaManager0);
|
|
||||||
jm1.setMediaManager(jingleMediaManager1);
|
|
||||||
|
|
||||||
jm1.addJingleSessionRequestListener(new JingleSessionRequestListener() {
|
|
||||||
public void sessionRequested(final JingleSessionRequest request) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
IncomingJingleSession session = request.accept(jm1.getMediaManager().getPayloads());
|
|
||||||
|
|
||||||
session.start(request);
|
|
||||||
}
|
|
||||||
catch (XMPPException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
OutgoingJingleSession js0 = jm0.createOutgoingJingleSession(x1.getUser());
|
|
||||||
|
|
||||||
js0.start();
|
|
||||||
|
|
||||||
Thread.sleep(150000);
|
|
||||||
js0.terminate();
|
|
||||||
|
|
||||||
Thread.sleep(6000);
|
|
||||||
|
|
||||||
x0.disconnect();
|
|
||||||
x1.disconnect();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testCompleteWithBridge() {
|
|
||||||
|
|
||||||
for (int i = 0; i < 1; i += 2) {
|
|
||||||
final int n = i;
|
|
||||||
Thread t = new Thread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
|
|
||||||
XMPPConnection x0 = getConnection(n);
|
|
||||||
XMPPConnection x1 = getConnection(n + 1);
|
|
||||||
|
|
||||||
BridgedTransportManager btm0 = new BridgedTransportManager(x0);
|
|
||||||
BridgedTransportManager btm1 = new BridgedTransportManager(x1);
|
|
||||||
|
|
||||||
final JingleManager jm0 = new JingleManager(x0, btm0);
|
|
||||||
final JingleManager jm1 = new JingleManager(x1, btm1);
|
|
||||||
|
|
||||||
jm0.addCreationListener(btm0);
|
|
||||||
jm1.addCreationListener(btm1);
|
|
||||||
|
|
||||||
JingleMediaManager jingleMediaManager = new JmfMediaManager();
|
|
||||||
JingleMediaManager jingleMediaManager2 = new JmfMediaManager();
|
|
||||||
|
|
||||||
jm0.setMediaManager(jingleMediaManager);
|
|
||||||
jm1.setMediaManager(jingleMediaManager2);
|
|
||||||
|
|
||||||
jm1.addJingleSessionRequestListener(new JingleSessionRequestListener() {
|
|
||||||
public void sessionRequested(final JingleSessionRequest request) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
IncomingJingleSession session = request.accept(jm1.getMediaManager().getPayloads());
|
|
||||||
|
|
||||||
session.start(request);
|
|
||||||
}
|
|
||||||
catch (XMPPException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
OutgoingJingleSession js0 = jm0.createOutgoingJingleSession(x1.getUser());
|
|
||||||
|
|
||||||
js0.start();
|
|
||||||
|
|
||||||
Thread.sleep(55000);
|
|
||||||
|
|
||||||
js0.terminate();
|
|
||||||
|
|
||||||
Thread.sleep(3000);
|
|
||||||
|
|
||||||
x0.disconnect();
|
|
||||||
x1.disconnect();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
t.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(250000);
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testCompleteWithBridgeB() {
|
|
||||||
try {
|
|
||||||
|
|
||||||
//XMPPConnection.DEBUG_ENABLED = true;
|
|
||||||
|
|
||||||
XMPPConnection x0 = getConnection(0);
|
|
||||||
XMPPConnection x1 = getConnection(1);
|
|
||||||
|
|
||||||
BridgedTransportManager btm0 = new BridgedTransportManager(x0);
|
|
||||||
BridgedTransportManager btm1 = new BridgedTransportManager(x1);
|
|
||||||
|
|
||||||
final JingleManager jm0 = new JingleManager(x0, btm0);
|
|
||||||
final JingleManager jm1 = new JingleManager(x1, btm1);
|
|
||||||
|
|
||||||
jm0.addCreationListener(btm0);
|
|
||||||
jm1.addCreationListener(btm1);
|
|
||||||
|
|
||||||
JingleMediaManager jingleMediaManager = new JmfMediaManager();
|
|
||||||
|
|
||||||
jm0.setMediaManager(jingleMediaManager);
|
|
||||||
jm1.setMediaManager(jingleMediaManager);
|
|
||||||
|
|
||||||
jm1.addJingleSessionRequestListener(new JingleSessionRequestListener() {
|
|
||||||
public void sessionRequested(final JingleSessionRequest request) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
IncomingJingleSession session = request.accept(jm1.getMediaManager().getPayloads());
|
|
||||||
|
|
||||||
session.start(request);
|
|
||||||
}
|
|
||||||
catch (XMPPException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
OutgoingJingleSession js0 = jm0.createOutgoingJingleSession(x1.getUser());
|
|
||||||
|
|
||||||
js0.start();
|
|
||||||
|
|
||||||
Thread.sleep(20000);
|
|
||||||
|
|
||||||
js0.terminate();
|
|
||||||
|
|
||||||
Thread.sleep(3000);
|
|
||||||
|
|
||||||
js0 = jm0.createOutgoingJingleSession(x1.getUser());
|
|
||||||
|
|
||||||
js0.start();
|
|
||||||
|
|
||||||
Thread.sleep(20000);
|
|
||||||
|
|
||||||
js0.terminate();
|
|
||||||
|
|
||||||
Thread.sleep(3000);
|
|
||||||
|
|
||||||
x0.disconnect();
|
|
||||||
x1.disconnect();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testAudioChannelOpenClose
|
|
||||||
() {
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
try {
|
|
||||||
AudioChannel audioChannel0 = new AudioChannel(new MediaLocator("javasound://"), InetAddress.getLocalHost().getHostAddress(), InetAddress.getLocalHost().getHostAddress(), 7002, 7020, new AudioFormat(AudioFormat.GSM_RTP));
|
|
||||||
AudioChannel audioChannel1 = new AudioChannel(new MediaLocator("javasound://"), InetAddress.getLocalHost().getHostAddress(), InetAddress.getLocalHost().getHostAddress(), 7020, 7002, new AudioFormat(AudioFormat.GSM_RTP));
|
|
||||||
|
|
||||||
audioChannel0.start();
|
|
||||||
audioChannel1.start();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(10000);
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
audioChannel0.stop();
|
|
||||||
audioChannel1.stop();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(3000);
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testAudioChannelStartStop
|
|
||||||
() {
|
|
||||||
|
|
||||||
try {
|
|
||||||
AudioChannel audioChannel0 = new AudioChannel(new MediaLocator("javasound://"), InetAddress.getLocalHost().getHostAddress(), InetAddress.getLocalHost().getHostAddress(), 7002, 7020, new AudioFormat(AudioFormat.GSM_RTP));
|
|
||||||
AudioChannel audioChannel1 = new AudioChannel(new MediaLocator("javasound://"), InetAddress.getLocalHost().getHostAddress(), InetAddress.getLocalHost().getHostAddress(), 7020, 7002, new AudioFormat(AudioFormat.GSM_RTP));
|
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
|
|
||||||
audioChannel0.start();
|
|
||||||
audioChannel1.start();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(10000);
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
audioChannel0.stop();
|
|
||||||
audioChannel1.stop();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(3000);
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getMaxConnections() {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue