+ */
+public abstract class JingleTransportProvider implements PacketExtensionProvider {
+
+ /**
+ * Creates a new provider. ProviderManager requires that every
+ * PacketExtensionProvider has a public, no-argument constructor
+ */
+ public JingleTransportProvider() {
+ super();
+ }
+
+ /**
+ * Obtain the corresponding TransportNegotiator instance.
+ *
+ * @return a new TransportNegotiator instance
+ */
+ protected JingleTransport getInstance() {
+ return new JingleTransport();
+ }
+
+ /**
+ * Parse a iq/jingle/transport element.
+ *
+ * @param parser the structure to parse
+ * @return a transport element.
+ * @throws Exception
+ */
+ public PacketExtension parseExtension(final XmlPullParser parser) throws Exception {
+ boolean done = false;
+ JingleTransport trans = getInstance();
+
+ while (!done) {
+ int eventType = parser.next();
+ String name = parser.getName();
+
+ if (eventType == XmlPullParser.START_TAG) {
+ if (name.equals(JingleTransportCandidate.NODENAME)) {
+ JingleTransportCandidate jtc = parseCandidate(parser);
+ if (jtc != null) trans.addCandidate(jtc);
+ } else {
+ throw new Exception("Unknown tag \"" + name + "\" in transport element.");
+ }
+ } else if (eventType == XmlPullParser.END_TAG) {
+ if (name.equals(JingleTransport.NODENAME)) {
+ done = true;
+ }
+ }
+ }
+
+ return trans;
+ }
+
+ protected abstract JingleTransportCandidate parseCandidate(final XmlPullParser parser)
+ throws Exception;
+
+ /**
+ * RTP-ICE profile
+ */
+ public static class Ice extends JingleTransportProvider {
+
+ /**
+ * Defauls constructor.
+ */
+ public Ice() {
+ super();
+ }
+
+ /**
+ * Obtain the corresponding TransportNegotiator.Ice instance.
+ *
+ * @return a new TransportNegotiator.Ice instance
+ */
+ protected JingleTransport getInstance() {
+ return new JingleTransport.Ice();
+ }
+
+ /**
+ * Parse a iq/jingle/transport/candidate element.
+ *
+ * @param parser the structure to parse
+ * @return a candidate element
+ * @throws Exception
+ */
+ protected JingleTransportCandidate parseCandidate(XmlPullParser parser) throws Exception {
+ TransportCandidate.Ice mt = new TransportCandidate.Ice();
+
+ String channel = parser.getAttributeValue("", "channel");
+ String generation = parser.getAttributeValue("", "generation");
+ String ip = parser.getAttributeValue("", "ip");
+ String name = parser.getAttributeValue("", "name");
+ String network = parser.getAttributeValue("", "network");
+ String username = parser.getAttributeValue("", "username");
+ String password = parser.getAttributeValue("", "password");
+ String port = parser.getAttributeValue("", "port");
+ String preference = parser.getAttributeValue("", "preference");
+ String proto = parser.getAttributeValue("", "proto");
+
+ if (channel != null) {
+ mt.setChannel(new TransportCandidate.Channel(channel));
+ }
+
+ if (generation != null) {
+ try {
+ mt.setGeneration(Integer.parseInt(generation));
+ } catch (Exception e) {
+ }
+ }
+
+ if (ip != null) {
+ mt.setIp(ip);
+ } else {
+ return null;
+ }
+
+ if (name != null) {
+ mt.setName(name);
+ }
+
+ if (network != null) {
+ try {
+ mt.setNetwork(Integer.parseInt(network));
+ } catch (Exception e) {
+ }
+ }
+
+ if (username != null) {
+ mt.setUsername(username);
+ }
+
+ if (password != null) {
+ mt.setPassword(password);
+ }
+
+ if (port != null) {
+ try {
+ mt.setPort(Integer.parseInt(port));
+ } catch (Exception e) {
+ }
+ }
+
+ if (preference != null) {
+ try {
+ mt.setPreference(Integer.parseInt(preference));
+ } catch (Exception e) {
+ }
+ }
+
+ if (proto != null) {
+ mt.setProto(new TransportCandidate.Protocol(proto));
+ }
+
+ return new JingleTransport.Ice.Candidate(mt);
+ }
+ }
+
+ /**
+ * Raw UDP profile
+ */
+ public static class RawUdp extends JingleTransportProvider {
+
+ /**
+ * Defauls constructor.
+ */
+ public RawUdp() {
+ super();
+ }
+
+ /**
+ * Obtain the corresponding TransportNegotiator.RawUdp instance.
+ *
+ * @return a new TransportNegotiator.RawUdp instance
+ */
+ protected JingleTransport getInstance() {
+ return new JingleTransport.RawUdp();
+ }
+
+ /**
+ * Parse a iq/jingle/transport/candidate element.
+ *
+ * @param parser the structure to parse
+ * @return a candidate element
+ * @throws Exception
+ */
+ protected JingleTransportCandidate parseCandidate(XmlPullParser parser) throws Exception {
+ TransportCandidate.Fixed mt = new TransportCandidate.Fixed();
+
+ String generation = parser.getAttributeValue("", "generation");
+ String ip = parser.getAttributeValue("", "ip");
+ String name = parser.getAttributeValue("", "name");
+ String port = parser.getAttributeValue("", "port");
+
+ //System.out.println();
+
+ if (generation != null) {
+ try {
+ mt.setGeneration(Integer.parseInt(generation));
+ } catch (Exception e) {
+ }
+ }
+
+ if (ip != null) {
+ mt.setIp(ip);
+ }
+
+ if (name != null) {
+ mt.setName(name);
+ }
+
+ if (port != null) {
+ try {
+ mt.setPort(Integer.parseInt(port));
+ } catch (Exception e) {
+ }
+ }
+ return new JingleTransport.RawUdp.Candidate(mt);
+ }
+ }
+}
diff --git a/jingle/extension/source/org/jivesoftware/smackx/provider/package.html b/jingle/extension/source/org/jivesoftware/smackx/provider/package.html
new file mode 100644
index 000000000..962ba6372
--- /dev/null
+++ b/jingle/extension/source/org/jivesoftware/smackx/provider/package.html
@@ -0,0 +1 @@
+Provides pluggable parsing logic for Smack extensions.
\ No newline at end of file
diff --git a/jingle/extension/source/overview.html b/jingle/extension/source/overview.html
new file mode 100644
index 000000000..8ec5b8ff7
--- /dev/null
+++ b/jingle/extension/source/overview.html
@@ -0,0 +1,4 @@
+API specification for Smack, an Open Source XMPP client library.
+
+ The {@link org.jivesoftware.smack.XMPPConnection} class is the main entry point for the API.
+
diff --git a/jingle/extension/test/config/test-case.xml b/jingle/extension/test/config/test-case.xml
new file mode 100644
index 000000000..d477c269e
--- /dev/null
+++ b/jingle/extension/test/config/test-case.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+ localhost
+ 5222
+
+
+ chat
+ conference
+
+
\ No newline at end of file
diff --git a/jingle/extension/test/org/jivesoftware/smack/test/SmackTestCase.java b/jingle/extension/test/org/jivesoftware/smack/test/SmackTestCase.java
new file mode 100644
index 000000000..2784cf9e5
--- /dev/null
+++ b/jingle/extension/test/org/jivesoftware/smack/test/SmackTestCase.java
@@ -0,0 +1,368 @@
+/**
+ * $RCSfile$
+ * $Revision: 5367 $
+ * $Date: 2006-09-14 16:16:40 -0300 (qui, 14 set 2006) $
+ *
+ * Copyright 2003-2005 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.
+ */
+package org.jivesoftware.smack.test;
+
+import junit.framework.TestCase;
+import org.jivesoftware.smack.ConnectionConfiguration;
+import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.XMPPException;
+import org.xmlpull.mxp1.MXParser;
+import org.xmlpull.v1.XmlPullParser;
+
+import javax.net.SocketFactory;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+
+/**
+ * Base class for all the test cases which provides a pre-configured execution context. This
+ * means that any test case that subclassifies this base class will have access to a pool of
+ * connections and to the user of each connection. The maximum number of connections in the pool
+ * can be controlled by the message {@link #getMaxConnections()} which every subclass must
+ * implement.
+ *
+ * This base class defines a default execution context (i.e. host, port, chat domain and muc
+ * domain) which can be found in the file "config/test-case.xml". However, each subclass could
+ * redefine the default configuration by providing its own configuration file (if desired). The
+ * name of the configuration file must be of the form .xml (e.g. RosterTest.xml).
+ * The file must be placed in the folder "config". This folder is where the default configuration
+ * file is being held.
+ *
+ * @author Gaston Dombiak
+ */
+public abstract class SmackTestCase extends TestCase {
+
+ private String host = "localhost";
+ private String serviceName = "localhost";
+ private int port = 5222;
+
+ private String chatDomain = "chat";
+ private String mucDomain = "conference";
+
+ private XMPPConnection[] connections = null;
+
+ /**
+ * Constructor for SmackTestCase.
+ * @param arg0
+ */
+ public SmackTestCase(String arg0) {
+ super(arg0);
+ }
+
+ /**
+ * Returns the maximum number of connections to initialize for this test case. All the
+ * initialized connections will be connected to the server using a new test account for
+ * each conection.
+ *
+ * @return the maximum number of connections to initialize for this test case.
+ */
+ protected abstract int getMaxConnections();
+
+ /**
+ * Returns a SocketFactory that will be used to create the socket to the XMPP server. By
+ * default no SocketFactory is used but subclasses my want to redefine this method.
+ *
+ * A custom SocketFactory allows fine-grained control of the actual connection to the XMPP
+ * server. A typical use for a custom SocketFactory is when connecting through a SOCKS proxy.
+ *
+ * @return a SocketFactory that will be used to create the socket to the XMPP server.
+ */
+ protected SocketFactory getSocketFactory() {
+ return null;
+ }
+
+ /**
+ * Returns the XMPPConnection located at the requested position. Each test case holds a
+ * pool of connections which is initialized while setting up the test case. The maximum
+ * number of connections is controlled by the message {@link #getMaxConnections()} which
+ * every subclass must implement.
+ *
+ * If the requested position is greater than the connections size then an
+ * IllegalArgumentException will be thrown.
+ *
+ * @param index the position in the pool of the connection to look for.
+ * @return the XMPPConnection located at the requested position.
+ */
+ protected XMPPConnection getConnection(int index) {
+ if (index > getMaxConnections()) {
+ throw new IllegalArgumentException("Index out of bounds");
+ }
+ return connections[index];
+ }
+
+ /**
+ * Returns the name of the user (e.g. johndoe) that is using the connection
+ * located at the requested position.
+ *
+ * @param index the position in the pool of the connection to look for.
+ * @return the user of the user (e.g. johndoe).
+ */
+ protected String getUsername(int index) {
+ if (index > getMaxConnections()) {
+ throw new IllegalArgumentException("Index out of bounds");
+ }
+ return "user" + index;
+ }
+
+ /**
+ * Returns the bare XMPP address of the user (e.g. johndoe@jabber.org) that is
+ * using the connection located at the requested position.
+ *
+ * @param index the position in the pool of the connection to look for.
+ * @return the bare XMPP address of the user (e.g. johndoe@jabber.org).
+ */
+ protected String getBareJID(int index) {
+ return getUsername(index) + "@" + getConnection(index).getServiceName();
+ }
+
+ /**
+ * Returns the full XMPP address of the user (e.g. johndoe@jabber.org/Smack) that is
+ * using the connection located at the requested position.
+ *
+ * @param index the position in the pool of the connection to look for.
+ * @return the full XMPP address of the user (e.g. johndoe@jabber.org/Smack).
+ */
+ protected String getFullJID(int index) {
+ return getBareJID(index) + "/Smack";
+ }
+
+ protected String getHost() {
+ return host;
+ }
+
+ protected int getPort() {
+ return port;
+ }
+
+ protected String getServiceName() {
+ return serviceName;
+ }
+
+ /**
+ * Returns the default groupchat service domain.
+ *
+ * @return the default groupchat service domain.
+ */
+ protected String getChatDomain() {
+ return chatDomain;
+ }
+
+ /**
+ * Returns the default MUC service domain.
+ *
+ * @return the default MUC service domain.
+ */
+ protected String getMUCDomain() {
+ return mucDomain + "." + serviceName;
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ init();
+ if (getMaxConnections() < 1) {
+ return;
+ }
+ connections = new XMPPConnection[getMaxConnections()];
+ try {
+ // Connect to the server
+ for (int i = 0; i < getMaxConnections(); i++) {
+ // Create the configuration for this new connection
+ ConnectionConfiguration config = new ConnectionConfiguration(host, port);
+ config.setTLSEnabled(true);
+ config.setCompressionEnabled(Boolean.getBoolean("test.compressionEnabled"));
+ config.setSASLAuthenticationEnabled(true);
+ if (getSocketFactory() == null) {
+ connections[i] = new XMPPConnection(config);
+ }
+ else {
+ connections[i] = new XMPPConnection(config, getSocketFactory());
+ }
+ connections[i].connect();
+ }
+ // Use the host name that the server reports. This is a good idea in most
+ // cases, but could fail if the user set a hostname in their XMPP server
+ // that will not resolve as a network connection.
+ host = connections[0].getHost();
+ serviceName = connections[0].getServiceName();
+ // Create the test accounts
+ if (!getConnection(0).getAccountManager().supportsAccountCreation())
+ fail("Server does not support account creation");
+
+ for (int i = 0; i < getMaxConnections(); i++) {
+ // Create the test account
+ try {
+ getConnection(i).getAccountManager().createAccount("user" + i, "user" + i);
+ } catch (XMPPException e) {
+ // Do nothing if the accout already exists
+ if (e.getXMPPError() == null || e.getXMPPError().getCode() != 409) {
+ throw e;
+ }
+ }
+ // Login with the new test account
+ getConnection(i).login("user" + i, "user" + i);
+ }
+ // Let the server process the available presences
+ Thread.sleep(150);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ for (int i = 0; i < getMaxConnections(); i++) {
+ if (getConnection(i).isConnected()) {
+ // Delete the created account for the test
+ getConnection(i).getAccountManager().deleteAccount();
+ // Close the connection
+ getConnection(i).disconnect();
+ }
+ }
+ }
+
+ /**
+ * Initializes the context of the test case. We will first try to load the configuration from
+ * a file whose name is conformed by the test case class name plus an .xml extension
+ * (e.g RosterTest.xml). If no file was found under that name then we will try to load the
+ * default configuration for all the test cases from the file "config/test-case.xml".
+ *
+ */
+ private void init() {
+ try {
+ boolean found = false;
+ // Try to load the configutation from an XML file specific for this test case
+ Enumeration resources =
+ ClassLoader.getSystemClassLoader().getResources(getConfigurationFilename());
+ while (resources.hasMoreElements()) {
+ found = parseURL((URL) resources.nextElement());
+ }
+ // If none was found then try to load the configuration from the default configuration
+ // file (i.e. "config/test-case.xml")
+ if (!found) {
+ resources = ClassLoader.getSystemClassLoader().getResources("config/test-case.xml");
+ while (resources.hasMoreElements()) {
+ found = parseURL((URL) resources.nextElement());
+ }
+ }
+ if (!found) {
+ System.err.println("File config/test-case.xml not found. Using default config.");
+ }
+ }
+ catch (Exception e) {
+ }
+ }
+
+ /**
+ * Returns true if the given URL was found and parsed without problems. The file provided
+ * by the URL must contain information useful for the test case configuration, such us,
+ * host and port of the server.
+ *
+ * @param url the url of the file to parse.
+ * @return true if the given URL was found and parsed without problems.
+ */
+ private boolean parseURL(URL url) {
+ boolean parsedOK = false;
+ InputStream systemStream = null;
+ try {
+ systemStream = url.openStream();
+ XmlPullParser parser = new MXParser();
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+ parser.setInput(systemStream, "UTF-8");
+ int eventType = parser.getEventType();
+ do {
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("host")) {
+ host = parser.nextText();
+ }
+ else if (parser.getName().equals("port")) {
+ port = parseIntProperty(parser, port);
+ }
+ else if (parser.getName().equals("serviceName")) {
+ serviceName = parser.nextText();
+ }
+ else if (parser.getName().equals("chat")) {
+ chatDomain = parser.nextText();
+ }
+ else if (parser.getName().equals("muc")) {
+ mucDomain = parser.nextText();
+ }
+ }
+ eventType = parser.next();
+ }
+ while (eventType != XmlPullParser.END_DOCUMENT);
+ parsedOK = true;
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ finally {
+ try {
+ systemStream.close();
+ }
+ catch (Exception e) {
+ }
+ }
+ return parsedOK;
+ }
+
+ private static int parseIntProperty(XmlPullParser parser, int defaultValue) throws Exception {
+ try {
+ return Integer.parseInt(parser.nextText());
+ }
+ catch (NumberFormatException nfe) {
+ nfe.printStackTrace();
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Returns the name of the configuration file related to this test case. By default all
+ * the test cases will use the same configuration file. However, it's possible to override the
+ * default configuration by providing a file of the form .xml
+ * (e.g. RosterTest.xml).
+ *
+ * @return the name of the configuration file related to this test case.
+ */
+ private String getConfigurationFilename() {
+ String fullClassName = this.getClass().getName();
+ int firstChar = fullClassName.lastIndexOf('.') + 1;
+ return "config/" + fullClassName.substring(firstChar) + ".xml";
+ }
+
+ /**
+ * Compares two contents of two byte arrays to make sure that they are equal
+ *
+ * @param message The message to show in the case of failure
+ * @param byteArray1 The first byte array.
+ * @param byteArray2 The second byte array.
+ */
+ public static void assertEquals(String message, byte [] byteArray1, byte [] byteArray2) {
+ if(byteArray1.length != byteArray2.length) {
+ fail(message);
+ }
+ for(int i = 0; i < byteArray1.length; i++) {
+ assertEquals(message, byteArray1[i], byteArray2[i]);
+ }
+ }
+
+}
diff --git a/jingle/extension/test/org/jivesoftware/smackx/jingle/JingleManagerTest.java b/jingle/extension/test/org/jivesoftware/smackx/jingle/JingleManagerTest.java
new file mode 100644
index 000000000..5d252ff9f
--- /dev/null
+++ b/jingle/extension/test/org/jivesoftware/smackx/jingle/JingleManagerTest.java
@@ -0,0 +1,1016 @@
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright (C) 2002-2006 Jive Software. All rights reserved.
+ * ====================================================================
+ * The Jive Software License (based on Apache Software License, Version 1.1)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by
+ * Jive Software (http://www.jivesoftware.com)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Smack" and "Jive Software" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please
+ * contact webmaster@jivesoftware.com.
+ *
+ * 5. Products derived from this software may not be called "Smack",
+ * nor may "Smack" appear in their name, without prior written
+ * permission of Jive Software.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ */
+
+package org.jivesoftware.smackx.jingle;
+
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.provider.ProviderManager;
+import org.jivesoftware.smack.test.SmackTestCase;
+import org.jivesoftware.smackx.jingle.listeners.JingleSessionListener;
+import org.jivesoftware.smackx.jingle.listeners.JingleSessionRequestListener;
+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.*;
+import org.jivesoftware.smackx.packet.Jingle;
+import org.jivesoftware.smackx.provider.JingleProvider;
+
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.util.ArrayList;
+
+/**
+ * Test the Jingle extension using the high level API
+ *
+ *
+ * @author Alvaro Saurin
+ */
+public class JingleManagerTest extends SmackTestCase {
+
+ private int counter;
+
+ private final Object mutex = new Object();
+
+ /**
+ * Constructor for JingleManagerTest.
+ *
+ * @param name
+ */
+ public JingleManagerTest(final String name) {
+ super(name);
+
+ resetCounter();
+ }
+
+ // Counter management
+
+ private void resetCounter() {
+ synchronized (mutex) {
+ counter = 0;
+ }
+ }
+
+ public void incCounter() {
+ synchronized (mutex) {
+ counter++;
+ }
+ }
+
+ private int valCounter() {
+ int val;
+ synchronized (mutex) {
+ val = counter;
+ }
+ return val;
+ }
+
+ /**
+ * Generate a list of payload types
+ *
+ * @return A testing list
+ */
+ private ArrayList getTestPayloads1() {
+ ArrayList result = new ArrayList();
+
+ result.add(new PayloadType.Audio(34, "supercodec-1", 2, 14000));
+ result.add(new PayloadType.Audio(56, "supercodec-2", 1, 44000));
+ result.add(new PayloadType.Audio(36, "supercodec-3", 2, 28000));
+ result.add(new PayloadType.Audio(45, "supercodec-4", 1, 98000));
+
+ return result;
+ }
+
+ private ArrayList getTestPayloads2() {
+ ArrayList result = new ArrayList();
+
+ result.add(new PayloadType.Audio(27, "supercodec-3", 2, 28000));
+ result.add(new PayloadType.Audio(56, "supercodec-2", 1, 44000));
+ result.add(new PayloadType.Audio(32, "supercodec-4", 1, 98000));
+ result.add(new PayloadType.Audio(34, "supercodec-1", 2, 14000));
+
+ return result;
+ }
+
+ private ArrayList getTestPayloads3() {
+ ArrayList result = new ArrayList();
+
+ result.add(new PayloadType.Audio(91, "badcodec-1", 2, 28000));
+ result.add(new PayloadType.Audio(92, "badcodec-2", 1, 44000));
+ result.add(new PayloadType.Audio(93, "badcodec-3", 1, 98000));
+ result.add(new PayloadType.Audio(94, "badcodec-4", 2, 14000));
+
+ return result;
+ }
+
+ /**
+ * Test for the session request detection. Here, we use the same filter we
+ * use in the JingleManager...
+ */
+ public void testInitJingleSessionRequestListeners() {
+
+ resetCounter();
+
+ ProviderManager.getInstance().addIQProvider("jingle",
+ "http://jabber.org/protocol/jingle",
+ new JingleProvider());
+
+ PacketFilter initRequestFilter = new PacketFilter() {
+ // Return true if we accept this packet
+ public boolean accept(Packet pin) {
+ if (pin instanceof IQ) {
+ System.out.println("packet: " + pin.toXML());
+ IQ iq = (IQ) pin;
+ if (iq.getType().equals(IQ.Type.SET)) {
+ System.out.println("packet");
+ if (iq instanceof Jingle) {
+ Jingle jin = (Jingle) pin;
+ if (jin.getAction().equals(Jingle.Action.SESSIONINITIATE)) {
+ System.out
+ .println("Session initiation packet accepted... ");
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+ };
+
+ // Start a packet listener for session initiation requests
+ getConnection(0).addPacketListener(new PacketListener() {
+ public void processPacket(final Packet packet) {
+ System.out.println("Packet detected... ");
+ incCounter();
+ }
+ }, initRequestFilter);
+
+ // Create a dummy packet for testing...
+ IQfake iqSent = new IQfake(
+ " "
+ + "");
+
+ iqSent.setTo(getFullJID(0));
+ iqSent.setFrom(getFullJID(0));
+ iqSent.setType(IQ.Type.SET);
+
+ System.out.println("Sending packet and waiting... ");
+ getConnection(1).sendPacket(iqSent);
+ try {
+ Thread.sleep(10000);
+ }
+ catch (InterruptedException e) {
+ }
+
+ System.out.println("Awake... " + valCounter());
+ assertTrue(valCounter() > 0);
+ }
+
+ /**
+ * High level API test. This is a simple test to use with a XMPP client and
+ * check if the client receives the message 1. User_1 will send an
+ * invitation to user_2.
+ */
+ public void testSendSimpleMessage() {
+
+ resetCounter();
+
+ try {
+ TransportResolver tr1 = new FixedResolver("127.0.0.1", 54222);
+ TransportResolver tr2 = new FixedResolver("127.0.0.1", 54567);
+
+ JingleManager man0 = new JingleManager(getConnection(0), tr1);
+ JingleManager man1 = new JingleManager(getConnection(1), tr2);
+
+ // Session 1 waits for connections
+ man1.addJingleSessionRequestListener(new JingleSessionRequestListener() {
+ /**
+ * Called when a new session request is detected
+ */
+ public void sessionRequested(final JingleSessionRequest request) {
+ incCounter();
+ System.out.println("Session request detected, from "
+ + request.getFrom());
+ }
+ });
+
+ // Session 0 starts a request
+ System.out.println("Starting session request, to " + getFullJID(1) + "...");
+ OutgoingJingleSession session0 = man0.createOutgoingJingleSession(
+ getFullJID(1), getTestPayloads1());
+ session0.start(null);
+
+ Thread.sleep(5000);
+
+ assertTrue(valCounter() > 0);
+
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ fail("An error occured with Jingle");
+ }
+ }
+
+ /**
+ * High level API test. This is a simple test to use with a XMPP client and
+ * check if the client receives the message 1. User_1 will send an
+ * invitation to user_2.
+ */
+ public void testAcceptJingleSession() {
+
+ resetCounter();
+
+ try {
+ TransportResolver tr1 = new FixedResolver("127.0.0.1", 54222);
+ TransportResolver tr2 = new FixedResolver("127.0.0.1", 54567);
+
+ final JingleManager man0 = new JingleManager(getConnection(0), tr1);
+ final JingleManager man1 = new JingleManager(getConnection(1), tr2);
+
+ man1.addJingleSessionRequestListener(new JingleSessionRequestListener() {
+ /**
+ * Called when a new session request is detected
+ */
+ public void sessionRequested(final JingleSessionRequest request) {
+ incCounter();
+ System.out.println("Session request detected, from "
+ + request.getFrom() + ": accepting.");
+
+ // We accept the request
+ try {
+ IncomingJingleSession session1 = request.accept(getTestPayloads2());
+ session1.start(request);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ // Session 0 starts a request
+ System.out.println("Starting session request, to " + getFullJID(1) + "...");
+ OutgoingJingleSession session0 = man0.createOutgoingJingleSession(
+ getFullJID(1), getTestPayloads1());
+ session0.start(null);
+
+ Thread.sleep(20000);
+
+ assertTrue(valCounter() > 0);
+
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ fail("An error occured with Jingle");
+ }
+ }
+
+ /**
+ * This is a simple test where both endpoints have exactly the same payloads
+ * and the session is accepted.
+ */
+ public void testEqualPayloadsSetSession() {
+
+ resetCounter();
+
+ try {
+ TransportResolver tr1 = new FixedResolver("127.0.0.1", 54213);
+ TransportResolver tr2 = new FixedResolver("127.0.0.1", 54531);
+
+ final JingleManager man0 = new JingleManager(getConnection(0), tr1);
+ final JingleManager man1 = new JingleManager(getConnection(1), tr2);
+
+ man1.addJingleSessionRequestListener(new JingleSessionRequestListener() {
+ /**
+ * Called when a new session request is detected
+ */
+ public void sessionRequested(final JingleSessionRequest request) {
+ System.out.println("Session request detected, from "
+ + request.getFrom() + ": accepting.");
+ try {
+ // We accept the request
+ IncomingJingleSession session1 = request.accept(getTestPayloads1());
+
+ session1.addListener(new JingleSessionListener() {
+ public void sessionClosed(String reason, JingleSession jingleSession) {
+ System.out.println("sessionClosed().");
+ }
+
+ public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
+ System.out.println("sessionClosedOnError().");
+ }
+
+ public void sessionDeclined(String reason, JingleSession jingleSession) {
+ System.out.println("sessionDeclined().");
+ }
+
+ public void sessionEstablished(PayloadType pt,
+ TransportCandidate rc, TransportCandidate lc, JingleSession jingleSession) {
+ incCounter();
+ System.out
+ .println("Responder: the session is fully established.");
+ System.out.println("+ Payload Type: " + pt.getId());
+ System.out.println("+ Local IP/port: " + lc.getIp() + ":"
+ + lc.getPort());
+ System.out.println("+ Remote IP/port: " + rc.getIp() + ":"
+ + rc.getPort());
+ }
+
+ public void sessionRedirected(String redirection, JingleSession jingleSession) {
+ }
+ });
+
+ session1.start(request);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ // Session 0 starts a request
+ System.out.println("Starting session request with equal payloads, to "
+ + getFullJID(1) + "...");
+ OutgoingJingleSession session0 = man0.createOutgoingJingleSession(
+ getFullJID(1), getTestPayloads1());
+ session0.start(null);
+
+ Thread.sleep(20000);
+
+ assertTrue(valCounter() == 1);
+
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ fail("An error occured with Jingle");
+ }
+ }
+
+ /**
+ * This is a simple test where the user_2 rejects the Jingle session.
+ */
+ public void testStagesSession() {
+
+ resetCounter();
+
+ try {
+ TransportResolver tr1 = new FixedResolver("127.0.0.1", 54222);
+ TransportResolver tr2 = new FixedResolver("127.0.0.1", 54567);
+
+ final JingleManager man0 = new JingleManager(getConnection(0), tr1);
+ final JingleManager man1 = new JingleManager(getConnection(1), tr2);
+
+ man1.addJingleSessionRequestListener(new JingleSessionRequestListener() {
+ /**
+ * Called when a new session request is detected
+ */
+ public void sessionRequested(final JingleSessionRequest request) {
+ System.out.println("Session request detected, from "
+ + request.getFrom() + ": accepting.");
+ try {
+ // We accept the request
+ IncomingJingleSession session1 = request.accept(getTestPayloads2());
+
+ session1.addListener(new JingleSessionListener() {
+ public void sessionClosed(String reason, JingleSession jingleSession) {
+ System.out.println("sessionClosed().");
+ }
+
+ public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
+ System.out.println("sessionClosedOnError().");
+ }
+
+ public void sessionDeclined(String reason, JingleSession jingleSession) {
+ System.out.println("sessionDeclined().");
+ }
+
+ public void sessionEstablished(PayloadType pt,
+ TransportCandidate rc, final TransportCandidate lc, JingleSession jingleSession) {
+ incCounter();
+ System.out
+ .println("Responder: the session is fully established.");
+ System.out.println("+ Payload Type: " + pt.getId());
+ System.out.println("+ Local IP/port: " + lc.getIp() + ":"
+ + lc.getPort());
+ System.out.println("+ Remote IP/port: " + rc.getIp() + ":"
+ + rc.getPort());
+ }
+
+ public void sessionRedirected(String redirection, JingleSession jingleSession) {
+ }
+ });
+
+
+ session1.start(request);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ // Session 0 starts a request
+ System.out.println("Starting session request, to " + getFullJID(1) + "...");
+ OutgoingJingleSession session0 = man0.createOutgoingJingleSession(
+ getFullJID(1), getTestPayloads1());
+
+ session0.addListener(new JingleSessionListener() {
+ public void sessionClosed(String reason, JingleSession jingleSession) {
+ }
+
+ public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
+ }
+
+ public void sessionDeclined(String reason, JingleSession jingleSession) {
+ }
+
+ public void sessionEstablished(PayloadType pt,
+ TransportCandidate rc, TransportCandidate lc, JingleSession jingleSession) {
+ incCounter();
+ System.out.println("Initiator: the session is fully established.");
+ System.out.println("+ Payload Type: " + pt.getId());
+ System.out.println("+ Local IP/port: " + lc.getIp() + ":"
+ + lc.getPort());
+ System.out.println("+ Remote IP/port: " + rc.getIp() + ":"
+ + rc.getPort());
+ }
+
+ public void sessionRedirected(String redirection, JingleSession jingleSession) {
+ }
+ });
+ session0.start(null);
+
+ Thread.sleep(20000);
+
+ assertTrue(valCounter() == 2);
+
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ fail("An error occured with Jingle");
+ }
+ }
+
+ /**
+ * This is a simple test where the user_2 rejects the Jingle session.
+ */
+ public void testRejectSession() {
+
+ resetCounter();
+
+ try {
+ TransportResolver tr1 = new FixedResolver("127.0.0.1", 54222);
+ TransportResolver tr2 = new FixedResolver("127.0.0.1", 54567);
+
+ final JingleManager man0 = new JingleManager(getConnection(0), tr1);
+ final JingleManager man1 = new JingleManager(getConnection(1), tr2);
+
+ man1.addJingleSessionRequestListener(new JingleSessionRequestListener() {
+ /**
+ * Called when a new session request is detected
+ */
+ public void sessionRequested(final JingleSessionRequest request) {
+ System.out.println("Session request detected, from "
+ + request.getFrom() + ": rejecting.");
+
+ // We reject the request
+ request.reject();
+ }
+ });
+
+ // Session 0 starts a request
+ System.out.println("Starting session request, to " + getFullJID(1) + "...");
+ OutgoingJingleSession session0 = man0.createOutgoingJingleSession(
+ getFullJID(1), getTestPayloads1());
+
+ session0.addListener(new JingleSessionListener() {
+ public void sessionClosed(String reason, JingleSession jingleSession) {
+ }
+
+ public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
+ }
+
+ public void sessionDeclined(String reason, JingleSession jingleSession) {
+ incCounter();
+ System.out
+ .println("The session has been detected as rejected with reason: "
+ + reason);
+ }
+
+ public void sessionEstablished(PayloadType pt,
+ TransportCandidate rc, TransportCandidate lc, JingleSession jingleSession) {
+ }
+
+ public void sessionRedirected(String redirection, JingleSession jingleSession) {
+ }
+ });
+
+ session0.start(null);
+
+ Thread.sleep(20000);
+
+ assertTrue(valCounter() > 0);
+
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ fail("An error occured with Jingle");
+ }
+ }
+
+ /**
+ * RTP Bridge Test
+ */
+ public void testRTPBridge() {
+
+ resetCounter();
+
+ try {
+
+ ProviderManager.getInstance().addIQProvider(RTPBridge.NAME,
+ RTPBridge.NAMESPACE, new RTPBridge.Provider());
+
+ XMPPConnection x2 = new XMPPConnection("thiago");
+ x2.connect();
+ x2.login("barata6", "barata6");
+
+ RTPBridge response = RTPBridge.getRTPBridge(x2, "102");
+
+ class Listener implements Runnable {
+ private byte[] buf = new byte[5000];
+ private DatagramSocket dataSocket;
+ private DatagramPacket packet;
+
+ public Listener(DatagramSocket dataSocket) {
+ this.dataSocket = dataSocket;
+ }
+
+ public void run() {
+ try {
+ while (true) {
+ // Block until a datagram appears:
+ packet = new DatagramPacket(buf, buf.length);
+ dataSocket.receive(packet);
+ incCounter();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ try {
+ byte packet[] = {0, 0, 1, 1, 1, 1, 1};
+ DatagramSocket ds0 = new DatagramSocket(14004, InetAddress.getByName("0.0.0.0"));
+ DatagramSocket ds1 = new DatagramSocket(14050, InetAddress.getByName("0.0.0.0"));
+ DatagramPacket echo0 = new DatagramPacket(packet, packet.length,
+ InetAddress.getLocalHost(), response.getPortA());
+ DatagramPacket echo1 = new DatagramPacket(packet, packet.length,
+ InetAddress.getLocalHost(), response.getPortB());
+
+ ds1.send(echo1);
+ ds0.send(echo0);
+
+ Thread.sleep(500);
+
+ Thread t0 = new Thread(new Listener(ds0));
+ Thread t1 = new Thread(new Listener(ds1));
+
+ t0.start();
+ t1.start();
+
+ int repeat = 300;
+
+ for (int i = 0; i < repeat; i++) {
+ ds0.send(echo0);
+ ds1.send(echo1);
+ Thread.sleep(200);
+ }
+
+ System.out.println(valCounter());
+ assertTrue(valCounter() == repeat * 2 + 1);
+
+ t0.stop();
+ t1.stop();
+
+ ds0.close();
+ ds1.close();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ }
+
+ }
+
+ /**
+ * This is a full test in the Jingle API.
+ */
+ public void testFullTest() {
+
+ resetCounter();
+
+ try {
+
+ XMPPConnection.DEBUG_ENABLED = true;
+
+ XMPPConnection x0 = new XMPPConnection("thiago");
+ XMPPConnection x1 = new XMPPConnection("thiago");
+
+ x0.connect();
+ x0.login("barata7", "barata7");
+ x1.connect();
+ x1.login("barata6", "barata6");
+
+ final JingleManager jm0 = new JingleManager(
+ x0, new STUNResolver() {
+ });
+ final JingleManager jm1 = new JingleManager(
+ x1, new FixedResolver("127.0.0.1", 20040));
+
+// JingleManager jm0 = new JingleSessionManager(
+// x0, new ICEResolver());
+// JingleManager jm1 = new JingleSessionManager(
+// x1, new ICEResolver());
+
+ JingleMediaManager jingleMediaManager = new JingleMediaManager() {
+ // Media Session Implementation
+ public JingleMediaSession createMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local) {
+ return new JingleMediaSession(payloadType, remote, local) {
+
+ public void initialize() {
+ }
+
+ public void startTrasmit() {
+ }
+
+ public void startReceive() {
+ }
+
+ public void setTrasmit(boolean active) {
+ }
+
+ public void stopTrasmit() {
+ }
+
+ public void stopReceive() {
+ }
+ };
+ }
+ };
+
+ jingleMediaManager.addPayloadType(new PayloadType.Audio(3, "GSM", 1, 16000));
+
+ 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.addListener(new JingleSessionListener() {
+
+ public void sessionEstablished(PayloadType pt, TransportCandidate rc, TransportCandidate lc, JingleSession jingleSession) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ incCounter();
+ System.out.println("Establish In");
+ }
+
+ public void sessionDeclined(String reason, JingleSession jingleSession) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void sessionRedirected(String redirection, JingleSession jingleSession) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void sessionClosed(String reason, JingleSession jingleSession) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+ });
+
+ session.start();
+ } catch (XMPPException e) {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+
+ }
+ });
+
+ OutgoingJingleSession js0 = jm0.createOutgoingJingleSession("barata6@thiago/Smack");
+
+ js0.addListener(new JingleSessionListener() {
+
+ public void sessionEstablished(PayloadType pt, TransportCandidate rc, TransportCandidate lc, JingleSession jingleSession) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ incCounter();
+ System.out.println("Establish Out");
+ }
+
+ public void sessionDeclined(String reason, JingleSession jingleSession) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void sessionRedirected(String redirection, JingleSession jingleSession) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void sessionClosed(String reason, JingleSession jingleSession) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+ });
+
+ js0.start();
+
+ Thread.sleep(12000);
+ js0.terminate();
+
+ assertTrue(valCounter() == 2);
+ //Thread.sleep(15000);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ /**
+ * This is a full test in the Jingle API.
+ */
+ public void testMediaManager() {
+
+ resetCounter();
+
+ try {
+
+ //XMPPConnection.DEBUG_ENABLED = true;
+
+ XMPPConnection x0 = new XMPPConnection("thiago");
+ XMPPConnection x1 = new XMPPConnection("thiago");
+
+ x0.connect();
+ x0.login("barata7", "barata7");
+ x1.connect();
+ x1.login("barata6", "barata6");
+
+ final JingleManager jm0 = new JingleManager(
+ x0, new FixedResolver("127.0.0.1", 20004));
+ final JingleManager jm1 = new JingleManager(
+ x1, new FixedResolver("127.0.0.1", 20040));
+
+// JingleManager jm0 = new JingleSessionManager(
+// x0, new ICEResolver());
+// JingleManager jm1 = new JingleSessionManager(
+// x1, new ICEResolver());
+
+ JingleMediaManager jingleMediaManager = new JingleMediaManager() {
+ // Media Session Implementation
+ public JingleMediaSession createMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local) {
+ return new JingleMediaSession(payloadType, remote, local) {
+
+ public void initialize() {
+
+ }
+
+ public void startTrasmit() {
+ incCounter();
+ System.out.println("Transmit");
+ }
+
+ public void startReceive() {
+ incCounter();
+ System.out.println("Receive");
+ }
+
+ public void setTrasmit(boolean active) {
+ }
+
+ public void stopTrasmit() {
+ incCounter();
+ System.out.println("Stop Transmit");
+ }
+
+ public void stopReceive() {
+ incCounter();
+ System.out.println("Stop Receive");
+ }
+ };
+ }
+ };
+
+ jingleMediaManager.addPayloadType(new PayloadType.Audio(3, "GSM", 1, 16000));
+
+ 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(); //To change body of catch statement use File | Settings | File Templates.
+ }
+
+ }
+ });
+
+ OutgoingJingleSession js0 = jm0.createOutgoingJingleSession("barata6@thiago/Smack");
+
+ js0.start();
+
+ Thread.sleep(10000);
+ js0.terminate();
+
+ Thread.sleep(3000);
+
+ System.out.println(valCounter());
+
+ assertTrue(valCounter() == 8);
+ //Thread.sleep(15000);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ /**
+ * This is a simple test where the user_2 rejects the Jingle session.
+ */
+ public void testIncompatibleCodecs() {
+
+ resetCounter();
+
+ try {
+ TransportResolver tr1 = new FixedResolver("127.0.0.1", 54222);
+ TransportResolver tr2 = new FixedResolver("127.0.0.1", 54567);
+
+ final JingleManager man0 = new JingleManager(getConnection(0), tr1);
+ final JingleManager man1 = new JingleManager(getConnection(1), tr2);
+
+ man1.addJingleSessionRequestListener(new JingleSessionRequestListener() {
+ /**
+ * Called when a new session request is detected
+ */
+ public void sessionRequested
+ (
+ final JingleSessionRequest request) {
+ System.out.println("Session request detected, from "
+ + request.getFrom() + ": accepting.");
+
+ try {
+ // We reject the request
+ IncomingJingleSession ses = request.accept(getTestPayloads3());
+
+ ses.start(request);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ // Session 0 starts a request
+ System.out.println("Starting session request, to " + getFullJID(1) + "...");
+ OutgoingJingleSession session0 = man0.createOutgoingJingleSession(
+ getFullJID(1), getTestPayloads1());
+
+ session0.addListener(new JingleSessionListener() {
+ public void sessionClosed(String reason, JingleSession jingleSession) {
+ }
+
+ public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
+ incCounter();
+ System.out
+ .println("The session has been close on error with reason: "
+ + e.getMessage());
+ }
+
+ public void sessionDeclined(String reason, JingleSession jingleSession) {
+ incCounter();
+ System.out
+ .println("The session has been detected as rejected with reason: "
+ + reason);
+ }
+
+ public void sessionEstablished(PayloadType pt,
+ TransportCandidate rc, TransportCandidate lc, JingleSession jingleSession) {
+ }
+
+ public void sessionRedirected(String redirection, JingleSession jingleSession) {
+ }
+ });
+
+ session0.start(null);
+
+ Thread.sleep(20000);
+
+ assertTrue(valCounter() > 0);
+
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ fail("An error occured with Jingle");
+ }
+ }
+
+ protected int getMaxConnections() {
+ return 2;
+ }
+
+ /**
+ * Simple class for testing an IQ...
+ *
+ * @author Alvaro Saurin
+ */
+ private class IQfake extends IQ {
+
+ private String s;
+
+ public IQfake(final String s) {
+ super();
+ this.s = s;
+ }
+
+ public String getChildElementXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(s);
+ return buf.toString();
+ }
+ }
+}
diff --git a/jingle/extension/test/org/jivesoftware/smackx/jingle/JingleSessionTest.java b/jingle/extension/test/org/jivesoftware/smackx/jingle/JingleSessionTest.java
new file mode 100644
index 000000000..5292844a1
--- /dev/null
+++ b/jingle/extension/test/org/jivesoftware/smackx/jingle/JingleSessionTest.java
@@ -0,0 +1,51 @@
+package org.jivesoftware.smackx.jingle;
+
+import org.jivesoftware.smack.test.SmackTestCase;
+import org.jivesoftware.smackx.jingle.nat.BasicResolver;
+
+public class JingleSessionTest extends SmackTestCase {
+
+ public JingleSessionTest(final String name) {
+ super(name);
+ }
+
+ public void testEqualsObject() {
+ JingleSession js1 = new OutgoingJingleSession(getConnection(0), "res1", null, new BasicResolver());
+ JingleSession js2 = new OutgoingJingleSession(getConnection(1), "res1", null, new BasicResolver());
+ JingleSession js3 = new OutgoingJingleSession(getConnection(2), "res2", null, new BasicResolver());
+
+ System.out.println(js1.getSid());
+ System.out.println(js2.getSid());
+
+ js1.setInitiator("js1");
+ js2.setInitiator("js1");
+ js1.setSid("10");
+ js2.setSid("10");
+
+ assertEquals(js1, js2);
+ assertEquals(js2, js1);
+
+ assertFalse(js1.equals(js3));
+ }
+
+ public void testGetInstanceFor() {
+ String ini1 = "initiator1";
+ String sid1 = "sid1";
+ String ini2 = "initiator2";
+ String sid2 = "sid2";
+
+ JingleSession js1 = new OutgoingJingleSession(getConnection(0), sid1, null, new BasicResolver());
+ JingleSession js2 = new OutgoingJingleSession(getConnection(1), sid2, null, new BasicResolver());
+
+ // For a packet, we should be able to get a session that handles that...
+ assertNotNull(JingleSession.getInstanceFor(getConnection(0)));
+ assertNotNull(JingleSession.getInstanceFor(getConnection(1)));
+
+ assertEquals(JingleSession.getInstanceFor(getConnection(0)), js1);
+ assertEquals(JingleSession.getInstanceFor(getConnection(1)), js2);
+ }
+
+ protected int getMaxConnections() {
+ return 3;
+ }
+}
diff --git a/jingle/extension/test/org/jivesoftware/smackx/jingle/JingleSupportTests.java b/jingle/extension/test/org/jivesoftware/smackx/jingle/JingleSupportTests.java
new file mode 100644
index 000000000..03f8e68af
--- /dev/null
+++ b/jingle/extension/test/org/jivesoftware/smackx/jingle/JingleSupportTests.java
@@ -0,0 +1,74 @@
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright (C) 2002-2006 Jive Software. All rights reserved.
+ * ====================================================================
+ * The Jive Software License (based on Apache Software License, Version 1.1)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by
+ * Jive Software (http://www.jivesoftware.com)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Smack" and "Jive Software" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please
+ * contact webmaster@jivesoftware.com.
+ *
+ * 5. Products derived from this software may not be called "Smack",
+ * nor may "Smack" appear in their name, without prior written
+ * permission of Jive Software.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ */
+
+package org.jivesoftware.smackx.jingle;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Test suite that runs all the Jingle support tests
+ *
+ * @author Alvaro Saurin
+ */
+public class JingleSupportTests {
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite("High and low level API tests for Jingle support");
+
+ // $JUnit-BEGIN$
+ suite.addTest(new TestSuite(JingleManagerTest.class));
+ // $JUnit-END$
+
+ return suite;
+ }
+}
diff --git a/jingle/extension/test/org/jivesoftware/smackx/jingle/PayloadTypeTest.java b/jingle/extension/test/org/jivesoftware/smackx/jingle/PayloadTypeTest.java
new file mode 100644
index 000000000..647e37bb8
--- /dev/null
+++ b/jingle/extension/test/org/jivesoftware/smackx/jingle/PayloadTypeTest.java
@@ -0,0 +1,89 @@
+package org.jivesoftware.smackx.jingle;
+
+import java.util.ArrayList;
+
+import org.jivesoftware.smack.test.SmackTestCase;
+import org.jivesoftware.smackx.jingle.media.PayloadType;
+
+public class PayloadTypeTest extends SmackTestCase {
+
+ public PayloadTypeTest(final String arg0) {
+ super(arg0);
+ }
+
+ public void testEqualsObject() {
+ PayloadType p1 = new PayloadType(0, "pt1", 2);
+ PayloadType p2 = new PayloadType(0, "pt1", 2);
+ assertTrue(p1.equals(p2));
+ }
+
+ /**
+ * Test for the difference of payloads.
+ */
+ public void testDifference() {
+ ArrayList set1 = new ArrayList();
+ ArrayList set2 = new ArrayList();
+
+ PayloadType.Audio common1 = new PayloadType.Audio(34, "supercodec-1", 2, 14000);
+ PayloadType.Audio common2 = new PayloadType.Audio(56, "supercodec-2", 1, 44000);
+
+ set1.add(common1);
+ set1.add(common2);
+ set1.add(new PayloadType.Audio(36, "supercodec-3", 2, 28000));
+ set1.add(new PayloadType.Audio(45, "supercodec-4", 1, 98000));
+
+ set2.add(new PayloadType.Audio(27, "supercodec-3", 2, 28000));
+ set2.add(common2);
+ set2.add(new PayloadType.Audio(32, "supercodec-4", 1, 98000));
+ set2.add(common1);
+
+ // Get the difference
+ ArrayList commonSet = new ArrayList();
+ commonSet.addAll(set1);
+ commonSet.retainAll(set2);
+
+ assertTrue(commonSet.size() == 2);
+ System.out.println("Codec " + ((PayloadType.Audio)commonSet.get(0)).getId());
+ System.out.println("Codec " + ((PayloadType.Audio)commonSet.get(1)).getId());
+
+ assertTrue(commonSet.contains(common1));
+ assertTrue(commonSet.contains(common2));
+ }
+
+ /**
+ * Test for the difference of payloads when we are handling the same sets.
+ */
+ public void testDifferenceSameSet() {
+ ArrayList set1 = new ArrayList();
+ ArrayList set2 = new ArrayList();
+
+ PayloadType.Audio common1 = new PayloadType.Audio(34, "supercodec-1", 2, 14000);
+ PayloadType.Audio common2 = new PayloadType.Audio(56, "supercodec-2", 1, 44000);
+ PayloadType.Audio common3 = new PayloadType.Audio(0, "supercodec-3", 1, 44000);
+ PayloadType.Audio common4 = new PayloadType.Audio(120, "supercodec-4", 2, 66060);
+
+ set1.add(common1);
+ set1.add(common2);
+ set1.add(common3);
+ set1.add(common4);
+
+ set2.add(common1);
+ set2.add(common2);
+ set2.add(common3);
+ set2.add(common4);
+
+ // Get the difference
+ ArrayList commonSet = new ArrayList();
+ commonSet.addAll(set1);
+ commonSet.retainAll(set2);
+
+ assertTrue(commonSet.size() == 4);
+ assertTrue(commonSet.contains(common1));
+ assertTrue(commonSet.contains(common2));
+ }
+
+ protected int getMaxConnections() {
+ return 0;
+ }
+
+}
diff --git a/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/BasicResolverTest.java b/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/BasicResolverTest.java
new file mode 100644
index 000000000..16fc889db
--- /dev/null
+++ b/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/BasicResolverTest.java
@@ -0,0 +1,101 @@
+package org.jivesoftware.smackx.jingle.nat;
+
+import org.jivesoftware.smack.test.SmackTestCase;
+
+public class BasicResolverTest extends SmackTestCase {
+
+ private int counter;
+
+ private final Object mutex = new Object();
+
+ public BasicResolverTest(String arg) {
+ super(arg);
+ }
+
+ // Counter management
+
+ private void resetCounter() {
+ synchronized (mutex) {
+ counter = 0;
+ }
+ }
+
+ private void incCounter() {
+ synchronized (mutex) {
+ counter++;
+ }
+ }
+
+ private int valCounter() {
+ int val;
+ synchronized (mutex) {
+ val = counter;
+ }
+ return val;
+ }
+
+ public void testCheckValidHostname() {
+ String validHostname = new String("slashdot.org");
+ BasicResolver br = new BasicResolver();
+ TransportCandidate tc = new TransportCandidate.Fixed(validHostname, 0);
+
+ resetCounter();
+
+ tc.addListener(new TransportResolverListener.Checker() {
+ public void candidateChecked(TransportCandidate cand, boolean result) {
+ if(result == true) {
+ System.out.println(cand.getIp() + " is reachable (as expected)");
+ incCounter();
+ }
+ }
+
+ public void candidateChecking(TransportCandidate cand) {
+
+ }
+ });
+
+ tc.check();
+
+ try {
+ Thread.sleep(TransportResolver.CHECK_TIMEOUT);
+ } catch (Exception e) {
+ }
+
+ assertTrue(valCounter() > 0);
+ }
+
+ public void testCheckInvalidHostname() {
+ String invalidHostname = new String("camupilosupino.org");
+ BasicResolver br = new BasicResolver();
+ TransportCandidate tc = new TransportCandidate.Fixed(invalidHostname, 0);
+
+ resetCounter();
+
+ tc.addListener(new TransportResolverListener.Checker() {
+ public void candidateChecked(TransportCandidate cand, boolean result) {
+ if(result == false) {
+ System.out.println(cand.getIp() + " is _not_ reachable (as expected)");
+ incCounter();
+ }
+ }
+
+ public void candidateChecking(TransportCandidate cand) {
+ }
+ });
+
+ tc.check();
+
+ try {
+ Thread.sleep(TransportResolver.CHECK_TIMEOUT);
+ } catch (Exception e) {
+ }
+
+ assertTrue(valCounter() > 0);
+ }
+
+
+ protected int getMaxConnections() {
+ return 0;
+ }
+
+}
diff --git a/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/BridgedResolverTest.java b/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/BridgedResolverTest.java
new file mode 100644
index 000000000..577fc5d09
--- /dev/null
+++ b/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/BridgedResolverTest.java
@@ -0,0 +1,172 @@
+package org.jivesoftware.smackx.jingle.nat;
+
+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.media.JingleMediaSession;
+import org.jivesoftware.smackx.jingle.media.PayloadType;
+
+public class BridgedResolverTest extends SmackTestCase {
+
+ private int counter;
+
+ private final Object mutex = new Object();
+
+ public BridgedResolverTest(String arg) {
+ super(arg);
+ }
+
+ // Counter management
+
+ private void resetCounter() {
+ synchronized (mutex) {
+ counter = 0;
+ }
+ }
+
+ private void incCounter() {
+ synchronized (mutex) {
+ counter++;
+ }
+ }
+
+ private int valCounter() {
+ int val;
+ synchronized (mutex) {
+ val = counter;
+ }
+ return val;
+ }
+
+ public void testCheckService() {
+ assertTrue(RTPBridge.serviceAvailable(getConnection(0)));
+ }
+
+ public void testGetBridge() {
+
+ resetCounter();
+
+ RTPBridge rtpBridge = RTPBridge.getRTPBridge(getConnection(0), "001");
+
+ System.out.println(rtpBridge.getIp() + " portA:" + rtpBridge.getPortA() + " portB:" + rtpBridge.getPortB());
+
+ if (rtpBridge != null) {
+ if (rtpBridge.getIp() != null) incCounter();
+ if (rtpBridge.getPortA() != -1) incCounter();
+ if (rtpBridge.getPortB() != -1) incCounter();
+ }
+
+ assertTrue(valCounter() == 3);
+ }
+
+ public void testFullBridge() {
+ resetCounter();
+
+ try {
+
+ //XMPPConnection.DEBUG_ENABLED = true;
+
+ XMPPConnection x0 = new XMPPConnection("thiago");
+ XMPPConnection x1 = new XMPPConnection("thiago");
+
+ x0.connect();
+ x0.login("barata7", "barata7");
+ x1.connect();
+ x1.login("barata6", "barata6");
+
+ final JingleManager jm0 = new JingleManager(
+ x0, new BridgedResolver(x0));
+ final JingleManager jm1 = new JingleManager(
+ x1, new BridgedResolver(x1));
+
+ JingleMediaManager jingleMediaManager = new JingleMediaManager() {
+ // Media Session Implementation
+ public JingleMediaSession createMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local) {
+ return new JingleMediaSession(payloadType, remote, local) {
+
+ public void initialize() {
+
+ }
+
+ public void startTrasmit() {
+ incCounter();
+
+ System.out.print("IPs:");
+ System.out.println(local.getSymmetric().getIp());
+ System.out.println(local.getIp());
+
+ System.out.println("Transmit");
+ }
+
+ public void startReceive() {
+ incCounter();
+ System.out.println("Receive");
+ }
+
+ public void setTrasmit(boolean active) {
+ }
+
+ public void stopTrasmit() {
+ incCounter();
+ System.out.println("Stop Transmit");
+ }
+
+ public void stopReceive() {
+ incCounter();
+ System.out.println("Stop Receive");
+ }
+ };
+ }
+ };
+
+ jingleMediaManager.addPayloadType(new PayloadType.Audio(3, "GSM", 1, 16000));
+
+ 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(); //To change body of catch statement use File | Settings | File Templates.
+ }
+
+ }
+ });
+
+ OutgoingJingleSession js0 = jm0.createOutgoingJingleSession("barata6@thiago/Smack");
+
+ js0.start();
+
+ Thread.sleep(10000);
+ js0.terminate();
+
+ Thread.sleep(3000);
+
+ System.out.println(valCounter());
+
+ assertTrue(valCounter() == 8);
+ //Thread.sleep(15000);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ protected int getMaxConnections() {
+ return 1;
+ }
+
+}
diff --git a/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/STUNResolverTest.java b/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/STUNResolverTest.java
new file mode 100644
index 000000000..ec75f5419
--- /dev/null
+++ b/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/STUNResolverTest.java
@@ -0,0 +1,342 @@
+package org.jivesoftware.smackx.jingle.nat;
+
+import de.javawi.jstun.test.demo.ice.Candidate;
+import de.javawi.jstun.test.demo.ice.ICENegociator;
+import de.javawi.jstun.util.UtilityException;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.test.SmackTestCase;
+import org.jivesoftware.smackx.jingle.*;
+import org.jivesoftware.smackx.jingle.listeners.JingleSessionListener;
+import org.jivesoftware.smackx.jingle.listeners.JingleSessionRequestListener;
+import org.jivesoftware.smackx.jingle.media.PayloadType;
+
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+
+/**
+ * Test the STUN IP resolver.
+ *
+ * @author alvaro
+ */
+public class STUNResolverTest extends SmackTestCase {
+
+ // Counter management
+
+ public STUNResolverTest(final String arg) {
+ super(arg);
+ }
+
+ private int counter;
+
+ private final Object mutex = new Object();
+
+ private void resetCounter() {
+ synchronized (mutex) {
+ counter = 0;
+ }
+ }
+
+ private void incCounter() {
+ synchronized (mutex) {
+ counter++;
+ }
+ }
+
+ private int valCounter() {
+ int val;
+ synchronized (mutex) {
+ val = counter;
+ }
+ return val;
+ }
+
+ /**
+ * Test for getPreferredCandidate()
+ *
+ * @throws Exception
+ */
+ public void testGetPreferredCandidate() throws Exception {
+ int highestPref = 100;
+
+ TransportCandidate cand1 = new TransportCandidate.Ice("192.168.2.1", 3, 2,
+ "password", 3468, "username1", 1);
+ TransportCandidate cand2 = new TransportCandidate.Ice("192.168.5.1", 2, 10,
+ "password", 3469, "username2", 15);
+ TransportCandidate candH = new TransportCandidate.Ice("192.168.2.11", 1, 2,
+ "password", 3468, "usernameH", highestPref);
+ TransportCandidate cand3 = new TransportCandidate.Ice("192.168.2.10", 2, 10,
+ "password", 3469, "username3", 2);
+ TransportCandidate cand4 = new TransportCandidate.Ice("192.168.4.1", 3, 2,
+ "password", 3468, "username4", 78);
+
+ STUNResolver stunResolver = new STUNResolver() {
+ };
+ stunResolver.addCandidate(cand1);
+ stunResolver.addCandidate(cand2);
+ stunResolver.addCandidate(candH);
+ stunResolver.addCandidate(cand3);
+ stunResolver.addCandidate(cand4);
+
+ assertEquals(stunResolver.getPreferredCandidate(), candH);
+ }
+
+ /**
+ * Test for getPreferredCandidate()
+ *
+ * @throws Exception
+ */
+ public void testGetPreferredCandidateICE() throws Exception {
+ int highestPref = 100;
+
+ TransportCandidate cand1 = new TransportCandidate.Ice("192.168.2.1", 3, 2,
+ "password", 3468, "username1", 1);
+ TransportCandidate cand2 = new TransportCandidate.Ice("192.168.5.1", 2, 10,
+ "password", 3469, "username2", 15);
+ TransportCandidate candH = new TransportCandidate.Ice("192.168.2.11", 1, 2,
+ "password", 3468, "usernameH", highestPref);
+ TransportCandidate cand3 = new TransportCandidate.Ice("192.168.2.10", 2, 10,
+ "password", 3469, "username3", 2);
+ TransportCandidate cand4 = new TransportCandidate.Ice("192.168.4.1", 3, 2,
+ "password", 3468, "username4", 78);
+
+ ICEResolver iceResolver = new ICEResolver() {
+ };
+ iceResolver.addCandidate(cand1);
+ iceResolver.addCandidate(cand2);
+ iceResolver.addCandidate(candH);
+ iceResolver.addCandidate(cand3);
+ iceResolver.addCandidate(cand4);
+
+ assertEquals(iceResolver.getPreferredCandidate(), candH);
+ }
+
+ /**
+ * Test priority generated by STUN lib
+ *
+ * @throws Exception
+ */
+ public void testICEPriority() throws Exception {
+
+ String first = "";
+
+ for (int i = 0; i < 100; i++) {
+
+ ICENegociator cc = new ICENegociator((short) 1);
+ // gather candidates
+ cc.gatherCandidateAddresses();
+ // priorize candidates
+ cc.prioritizeCandidates();
+ // get SortedCandidates
+ //List sortedCandidates = cc.getSortedCandidates();
+
+ for (Candidate candidate : cc.getSortedCandidates())
+ try {
+ TransportCandidate transportCandidate = new TransportCandidate.Ice(candidate.getAddress().getInetAddress().getHostAddress(), 1, candidate.getNetwork(), "1", candidate.getPort(), "1", candidate.getPriority());
+ transportCandidate.setLocalIp(candidate.getBase().getAddress().getInetAddress().getHostAddress());
+ System.out.println("C: " + candidate.getAddress().getInetAddress() + "|" + candidate.getBase().getAddress().getInetAddress() + " p:" + candidate.getPriority());
+ } catch (UtilityException e) {
+ e.printStackTrace();
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ }
+ Candidate candidate = cc.getSortedCandidates().get(0);
+ String temp = "C: " + candidate.getAddress().getInetAddress() + "|" + candidate.getBase().getAddress().getInetAddress() + " p:" + candidate.getPriority();
+ if (first.equals(""))
+ first = temp;
+ assertEquals(first, temp);
+ first = temp;
+ }
+ }
+
+ /**
+ * Test for loadSTUNServers()
+ *
+ * @throws Exception
+ */
+ public void testLoadSTUNServers() throws Exception {
+ STUNResolver stunResolver = new STUNResolver() {
+ };
+ ArrayList stunServers = stunResolver.loadSTUNServers();
+
+ assertTrue(stunServers.size() > 0);
+ System.out.println(stunServers.size() + " servers loaded");
+ }
+
+ /**
+ * Test for resolve()
+ *
+ * @throws Exception
+ */
+ public void testResolve() throws Exception {
+
+ final STUNResolver stunResolver = new STUNResolver() {
+ };
+
+ stunResolver.addListener(new TransportResolverListener.Resolver() {
+
+ public void candidateAdded(final TransportCandidate cand) {
+ incCounter();
+
+ String addr = cand.getIp();
+ int port = cand.getPort();
+
+ System.out.println("Addr: " + addr + " port:" + port);
+
+ }
+
+ public void init() {
+ System.out.println("Resolution started");
+ }
+
+ public void end() {
+ System.out.println("Resolution finished");
+ }
+ });
+
+ try {
+ stunResolver.initialize();
+ Thread.sleep(55000);
+ assertTrue(valCounter() > 0);
+ stunResolver.resolve();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ /**
+ * Generate a list of payload types
+ *
+ * @return A testing list
+ */
+ private ArrayList getTestPayloads1() {
+ ArrayList result = new ArrayList();
+
+ result.add(new PayloadType.Audio(34, "supercodec-1", 2, 14000));
+ result.add(new PayloadType.Audio(56, "supercodec-2", 1, 44000));
+ result.add(new PayloadType.Audio(36, "supercodec-3", 2, 28000));
+ result.add(new PayloadType.Audio(45, "supercodec-4", 1, 98000));
+
+ return result;
+ }
+
+ private ArrayList getTestPayloads2() {
+ ArrayList result = new ArrayList();
+
+ result.add(new PayloadType.Audio(27, "supercodec-3", 2, 28000));
+ result.add(new PayloadType.Audio(56, "supercodec-2", 1, 44000));
+ result.add(new PayloadType.Audio(32, "supercodec-4", 1, 98000));
+ result.add(new PayloadType.Audio(34, "supercodec-1", 2, 14000));
+
+ return result;
+ }
+
+ /**
+ * This is a simple test where the user_2 rejects the Jingle session.
+ */
+ public void testSTUNJingleSession() {
+
+ resetCounter();
+
+ try {
+ TransportResolver tr1 = new STUNResolver() {
+ };
+ TransportResolver tr2 = new STUNResolver() {
+ };
+
+ // Explicit resolution
+ tr1.resolve();
+ tr2.resolve();
+
+ final JingleManager man0 = new JingleManager(getConnection(0), tr1);
+ final JingleManager man1 = new JingleManager(getConnection(1), tr2);
+
+ man1.addJingleSessionRequestListener(new JingleSessionRequestListener() {
+ /**
+ * Called when a new session request is detected
+ */
+ public void sessionRequested(final JingleSessionRequest request) {
+ System.out.println("Session request detected, from "
+ + request.getFrom() + ": accepting.");
+
+ // We accept the request
+ IncomingJingleSession session1;
+ try {
+ session1 = request.accept(getTestPayloads2());
+ session1.addListener(new JingleSessionListener() {
+ public void sessionClosed(String reason, JingleSession jingleSession) {
+ }
+
+ public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
+ }
+
+ public void sessionDeclined(String reason, JingleSession jingleSession) {
+ }
+
+ public void sessionEstablished(PayloadType pt,
+ TransportCandidate rc, TransportCandidate lc, JingleSession jingleSession) {
+ incCounter();
+ System.out
+ .println("Responder: the session is fully established.");
+ System.out.println("+ Payload Type: " + pt.getId());
+ System.out.println("+ Local IP/port: " + lc.getIp() + ":"
+ + lc.getPort());
+ System.out.println("+ Remote IP/port: " + rc.getIp() + ":"
+ + rc.getPort());
+ }
+
+ public void sessionRedirected(String redirection, JingleSession jingleSession) {
+ }
+ });
+ session1.start(request);
+ } catch (XMPPException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ // Session 0 starts a request
+ System.out.println("Starting session request, to " + getFullJID(1) + "...");
+ OutgoingJingleSession session0 = man0.createOutgoingJingleSession(
+ getFullJID(1), getTestPayloads1());
+
+ session0.addListener(new JingleSessionListener() {
+ public void sessionClosed(String reason, JingleSession jingleSession) {
+ }
+
+ public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
+ }
+
+ public void sessionDeclined(String reason, JingleSession jingleSession) {
+ }
+
+ public void sessionEstablished(PayloadType pt,
+ TransportCandidate rc, TransportCandidate lc, JingleSession jingleSession) {
+ incCounter();
+ System.out.println("Initiator: the session is fully established.");
+ System.out.println("+ Payload Type: " + pt.getId());
+ System.out.println("+ Local IP/port: " + lc.getIp() + ":"
+ + lc.getPort());
+ System.out.println("+ Remote IP/port: " + rc.getIp() + ":"
+ + rc.getPort());
+ }
+
+ public void sessionRedirected(String redirection, JingleSession jingleSession) {
+ }
+ });
+ session0.start(null);
+
+ Thread.sleep(60000);
+
+ assertTrue(valCounter() == 2);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("An error occured with Jingle");
+ }
+ }
+
+ protected int getMaxConnections() {
+ return 2;
+ }
+}
diff --git a/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/TransportCandidateTest.java b/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/TransportCandidateTest.java
new file mode 100644
index 000000000..2aee30e70
--- /dev/null
+++ b/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/TransportCandidateTest.java
@@ -0,0 +1,59 @@
+package org.jivesoftware.smackx.jingle.nat;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import org.jivesoftware.smack.test.SmackTestCase;
+
+public class TransportCandidateTest extends SmackTestCase {
+
+ public TransportCandidateTest(final String arg0) {
+ super(arg0);
+ }
+
+ /**
+ * Test for equals()
+ */
+ public void testEqualsObject() {
+ TransportCandidate cand1 = new TransportCandidate.Ice("192.168.2.1", 1, 2,
+ "password", 3468, "username", 25);
+ TransportCandidate cand2 = new TransportCandidate.Ice("192.168.2.1", 1, 2,
+ "password", 3468, "username", 25);
+ TransportCandidate cand3 = new TransportCandidate.Ice("192.168.2.1", 1, 2,
+ "password", 3469, "username", 25);
+
+ assertEquals(cand1, cand2);
+ assertFalse(cand1.equals(cand3));
+ }
+
+ /**
+ * Test for compareTo()
+ */
+ public void testCompareTo() {
+ int highestPref = 100;
+
+ TransportCandidate cand1 = new TransportCandidate.Ice("192.168.2.1", 3, 2,
+ "password", 3468, "username", 1);
+ TransportCandidate cand2 = new TransportCandidate.Ice("192.168.5.1", 2, 10,
+ "password", 3469, "username", 15);
+ TransportCandidate candH = new TransportCandidate.Ice("192.168.2.1", 1, 2,
+ "password", 3468, "username", highestPref);
+ TransportCandidate cand3 = new TransportCandidate.Ice("192.168.2.10", 2, 10,
+ "password", 3469, "username", 2);
+ TransportCandidate cand4 = new TransportCandidate.Ice("192.168.4.1", 3, 2,
+ "password", 3468, "username", 78);
+
+ ArrayList candList = new ArrayList();
+ candList.add(cand1);
+ candList.add(cand2);
+ candList.add(candH);
+ candList.add(cand3);
+ candList.add(cand4);
+
+ Collections.sort(candList);
+ assertEquals(candList.get(candList.size() - 1), candH);
+ }
+
+ protected int getMaxConnections() {
+ return 0;
+ }
+}
diff --git a/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/TransportResolverTest.java b/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/TransportResolverTest.java
new file mode 100644
index 000000000..a7fc45cb4
--- /dev/null
+++ b/jingle/extension/test/org/jivesoftware/smackx/jingle/nat/TransportResolverTest.java
@@ -0,0 +1,50 @@
+package org.jivesoftware.smackx.jingle.nat;
+
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.test.SmackTestCase;
+
+public class TransportResolverTest extends SmackTestCase {
+
+ public TransportResolverTest(final String arg) {
+ super(arg);
+ }
+
+ public void testIsResolving() {
+ final TransportResolver tr = new BasicResolver();
+
+ tr.addListener(
+ new TransportResolverListener.Resolver() {
+ public void candidateAdded(final TransportCandidate cand) {
+ System.out.println("candidateAdded() called.");
+ assertTrue(tr.isResolving() || (!tr.isResolving() && tr.isResolved()));
+ }
+
+ public void end() {
+ System.out.println("end() called.");
+ assertFalse(tr.isResolving());
+ assertTrue(tr.isResolved());
+ }
+
+ public void init() {
+ System.out.println("init() called.");
+ assertTrue(tr.isResolving());
+ assertFalse(tr.isResolved());
+ }
+ });
+
+ assertFalse(tr.isResolving());
+ assertFalse(tr.isResolved());
+
+ try {
+ tr.resolve();
+ } catch (XMPPException e) {
+ e.printStackTrace();
+ fail("Error resolving");
+ }
+ }
+
+ protected int getMaxConnections() {
+ return 0;
+ }
+
+}
diff --git a/jingle/extension/test/org/jivesoftware/smackx/provider/JingleProviderTest.java b/jingle/extension/test/org/jivesoftware/smackx/provider/JingleProviderTest.java
new file mode 100644
index 000000000..a54732410
--- /dev/null
+++ b/jingle/extension/test/org/jivesoftware/smackx/provider/JingleProviderTest.java
@@ -0,0 +1,112 @@
+package org.jivesoftware.smackx.provider;
+
+import org.jivesoftware.smack.PacketCollector;
+import org.jivesoftware.smack.SmackConfiguration;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.jivesoftware.smack.provider.ProviderManager;
+import org.jivesoftware.smack.test.SmackTestCase;
+import org.jivesoftware.smackx.packet.Jingle;
+
+public class JingleProviderTest extends SmackTestCase {
+
+ public JingleProviderTest(final String name) {
+ super(name);
+ }
+
+ public void testProviderManager() {
+ IQProvider iqProv;
+ String elementNamee = Jingle.getElementName();
+ String nameSpace = Jingle.getNamespace();
+
+ System.out.println("Testing if the Jingle IQ provider is registered...");
+
+ // Verify that the Jingle IQProvider is registered.
+ iqProv = (IQProvider)ProviderManager.getInstance().getIQProvider(elementNamee, nameSpace);
+
+ assertNotNull(iqProv);
+ }
+
+ /**
+ * Test for parsing a Jingle
+ */
+ public void testParseIQSimple() {
+
+ // Create a dummy packet for testing...
+ IQfake iqSent = new IQfake (
+ " " +
+ " " +
+ " " +
+ " " +
+ "");
+
+ iqSent.setTo(getFullJID(0));
+ iqSent.setFrom(getFullJID(0));
+ iqSent.setType(IQ.Type.GET);
+
+ // Create a filter and a collector...
+ PacketFilter filter = new PacketTypeFilter(IQ.class);
+ PacketCollector collector = getConnection(0).createPacketCollector(filter);
+
+ System.out.println("Testing if a Jingle IQ can be sent and received...");
+
+ // Send the iq packet with an invalid namespace
+ getConnection(0).sendPacket(iqSent);
+
+ // Receive the packet
+ IQ iqReceived = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Stop queuing results
+ collector.cancel();
+
+ if (iqReceived == null) {
+ fail("No response from server");
+ }
+ else if (iqReceived.getType() == IQ.Type.ERROR) {
+ fail("The server did reply with an error packet: " + iqReceived.getError().getCode());
+ }
+ else {
+ assertTrue(iqReceived instanceof Jingle);
+
+ Jingle jin = (Jingle) iqReceived;
+
+ System.out.println("Sent: " + iqSent.toXML());
+ System.out.println("Received: " + jin.toXML());
+ }
+ }
+
+ /**
+ * Simple class for testing an IQ...
+ * @author Alvaro Saurin
+ */
+ private class IQfake extends IQ {
+ private String s;
+
+ public IQfake(final String s) {
+ super();
+ this.s = s;
+ }
+
+ public String getChildElementXML() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(s);
+ return buf.toString();
+ }
+ }
+
+
+ protected int getMaxConnections() {
+ return 2;
+ }
+
+}
diff --git a/jingle/media/build/lib/Speex.jar b/jingle/media/build/lib/Speex.jar
new file mode 100644
index 000000000..f8abcbb0b
Binary files /dev/null and b/jingle/media/build/lib/Speex.jar differ
diff --git a/jingle/media/build/lib/commons-logging-1.1.jar b/jingle/media/build/lib/commons-logging-1.1.jar
new file mode 100644
index 000000000..2ff9bbd90
Binary files /dev/null and b/jingle/media/build/lib/commons-logging-1.1.jar differ
diff --git a/jingle/media/build/lib/commons-logging-adapters-1.1.jar b/jingle/media/build/lib/commons-logging-adapters-1.1.jar
new file mode 100644
index 000000000..6eec9a525
Binary files /dev/null and b/jingle/media/build/lib/commons-logging-adapters-1.1.jar differ
diff --git a/jingle/media/build/lib/commons-logging-api-1.1.jar b/jingle/media/build/lib/commons-logging-api-1.1.jar
new file mode 100644
index 000000000..d1abcbb47
Binary files /dev/null and b/jingle/media/build/lib/commons-logging-api-1.1.jar differ
diff --git a/jingle/media/build/lib/jmf.jar b/jingle/media/build/lib/jmf.jar
new file mode 100644
index 000000000..556b508ef
Binary files /dev/null and b/jingle/media/build/lib/jmf.jar differ
diff --git a/jingle/media/build/lib/jspeex-0.9.7-jfcom.jar b/jingle/media/build/lib/jspeex-0.9.7-jfcom.jar
new file mode 100644
index 000000000..f2631b1f4
Binary files /dev/null and b/jingle/media/build/lib/jspeex-0.9.7-jfcom.jar differ
diff --git a/jingle/media/build/lib/windows/jmacm.dll b/jingle/media/build/lib/windows/jmacm.dll
new file mode 100644
index 000000000..3edd7ebf2
Binary files /dev/null and b/jingle/media/build/lib/windows/jmacm.dll differ
diff --git a/jingle/media/build/lib/windows/jmam.dll b/jingle/media/build/lib/windows/jmam.dll
new file mode 100644
index 000000000..46c0ddc2a
Binary files /dev/null and b/jingle/media/build/lib/windows/jmam.dll differ
diff --git a/jingle/media/build/lib/windows/jmcvid.dll b/jingle/media/build/lib/windows/jmcvid.dll
new file mode 100644
index 000000000..fad506adf
Binary files /dev/null and b/jingle/media/build/lib/windows/jmcvid.dll differ
diff --git a/jingle/media/build/lib/windows/jmdaud.dll b/jingle/media/build/lib/windows/jmdaud.dll
new file mode 100644
index 000000000..61a18d633
Binary files /dev/null and b/jingle/media/build/lib/windows/jmdaud.dll differ
diff --git a/jingle/media/build/lib/windows/jmdaudc.dll b/jingle/media/build/lib/windows/jmdaudc.dll
new file mode 100644
index 000000000..5847317cd
Binary files /dev/null and b/jingle/media/build/lib/windows/jmdaudc.dll differ
diff --git a/jingle/media/build/lib/windows/jmddraw.dll b/jingle/media/build/lib/windows/jmddraw.dll
new file mode 100644
index 000000000..4001890dc
Binary files /dev/null and b/jingle/media/build/lib/windows/jmddraw.dll differ
diff --git a/jingle/media/build/lib/windows/jmfjawt.dll b/jingle/media/build/lib/windows/jmfjawt.dll
new file mode 100644
index 000000000..b44df82af
Binary files /dev/null and b/jingle/media/build/lib/windows/jmfjawt.dll differ
diff --git a/jingle/media/build/lib/windows/jmg723.dll b/jingle/media/build/lib/windows/jmg723.dll
new file mode 100644
index 000000000..d1172fd21
Binary files /dev/null and b/jingle/media/build/lib/windows/jmg723.dll differ
diff --git a/jingle/media/build/lib/windows/jmgdi.dll b/jingle/media/build/lib/windows/jmgdi.dll
new file mode 100644
index 000000000..a68e16cf9
Binary files /dev/null and b/jingle/media/build/lib/windows/jmgdi.dll differ
diff --git a/jingle/media/build/lib/windows/jmgsm.dll b/jingle/media/build/lib/windows/jmgsm.dll
new file mode 100644
index 000000000..4317ffb55
Binary files /dev/null and b/jingle/media/build/lib/windows/jmgsm.dll differ
diff --git a/jingle/media/build/lib/windows/jmh263enc.dll b/jingle/media/build/lib/windows/jmh263enc.dll
new file mode 100644
index 000000000..8c25686bf
Binary files /dev/null and b/jingle/media/build/lib/windows/jmh263enc.dll differ
diff --git a/jingle/media/build/lib/windows/jmjpeg.dll b/jingle/media/build/lib/windows/jmjpeg.dll
new file mode 100644
index 000000000..3a42e9261
Binary files /dev/null and b/jingle/media/build/lib/windows/jmjpeg.dll differ
diff --git a/jingle/media/build/lib/windows/jmmci.dll b/jingle/media/build/lib/windows/jmmci.dll
new file mode 100644
index 000000000..e17df4082
Binary files /dev/null and b/jingle/media/build/lib/windows/jmmci.dll differ
diff --git a/jingle/media/build/lib/windows/jmmpa.dll b/jingle/media/build/lib/windows/jmmpa.dll
new file mode 100644
index 000000000..5356ba37a
Binary files /dev/null and b/jingle/media/build/lib/windows/jmmpa.dll differ
diff --git a/jingle/media/build/lib/windows/jmmpegv.dll b/jingle/media/build/lib/windows/jmmpegv.dll
new file mode 100644
index 000000000..d44f1889b
Binary files /dev/null and b/jingle/media/build/lib/windows/jmmpegv.dll differ
diff --git a/jingle/media/build/lib/windows/jmutil.dll b/jingle/media/build/lib/windows/jmutil.dll
new file mode 100644
index 000000000..c22b26f9b
Binary files /dev/null and b/jingle/media/build/lib/windows/jmutil.dll differ
diff --git a/jingle/media/build/lib/windows/jmvcm.dll b/jingle/media/build/lib/windows/jmvcm.dll
new file mode 100644
index 000000000..45711f019
Binary files /dev/null and b/jingle/media/build/lib/windows/jmvcm.dll differ
diff --git a/jingle/media/build/lib/windows/jmvfw.dll b/jingle/media/build/lib/windows/jmvfw.dll
new file mode 100644
index 000000000..d77e7cde7
Binary files /dev/null and b/jingle/media/build/lib/windows/jmvfw.dll differ
diff --git a/jingle/media/build/lib/windows/jmvh263.dll b/jingle/media/build/lib/windows/jmvh263.dll
new file mode 100644
index 000000000..e554d0c19
Binary files /dev/null and b/jingle/media/build/lib/windows/jmvh263.dll differ
diff --git a/jingle/media/build/projects/JingleMedia.iml b/jingle/media/build/projects/JingleMedia.iml
new file mode 100644
index 000000000..a51db05cc
--- /dev/null
+++ b/jingle/media/build/projects/JingleMedia.iml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jingle/media/source/org/jivesoftware/demo/Demo.java b/jingle/media/source/org/jivesoftware/demo/Demo.java
new file mode 100644
index 000000000..c170cf101
--- /dev/null
+++ b/jingle/media/source/org/jivesoftware/demo/Demo.java
@@ -0,0 +1,157 @@
+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);
+ }
+
+ }
+
+}
diff --git a/jingle/media/source/org/jivesoftware/jingleaudio/jmf/AudioChannel.java b/jingle/media/source/org/jivesoftware/jingleaudio/jmf/AudioChannel.java
new file mode 100644
index 000000000..8a3074590
--- /dev/null
+++ b/jingle/media/source/org/jivesoftware/jingleaudio/jmf/AudioChannel.java
@@ -0,0 +1,439 @@
+/**
+ * $RCSfile$
+ * $Revision: $
+ * $Date: 08/11/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.
+ */
+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.
+ *
+ * Send from portA to portB and receive from portB in portA.
+ *
+ * Sending
+ * portA ---> portB
+ *
+ * Receiving
+ * portB ---> portA
+ *
+ * Transmit and Receive are interdependents. To receive you MUST trasmit.
+ */
+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 sendStreams = new ArrayList();
+
+ 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();
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/jingle/media/source/org/jivesoftware/jingleaudio/jmf/AudioFormatUtils.java b/jingle/media/source/org/jivesoftware/jingleaudio/jmf/AudioFormatUtils.java
new file mode 100644
index 000000000..70eb5db89
--- /dev/null
+++ b/jingle/media/source/org/jivesoftware/jingleaudio/jmf/AudioFormatUtils.java
@@ -0,0 +1,51 @@
+/**
+ * $RCSfile$
+ * $Revision: $
+ * $Date: 08/11/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.
+ */
+package org.jivesoftware.jingleaudio.jmf;
+
+import org.jivesoftware.smackx.jingle.media.PayloadType;
+
+import javax.media.format.AudioFormat;
+
+/**
+ * Audio Format Ttils.
+ */
+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 3:
+ return new AudioFormat(AudioFormat.GSM_RTP);
+ case 4:
+ return new AudioFormat(AudioFormat.G723_RTP);
+ default:
+ return null;
+ }
+
+ }
+
+}
diff --git a/jingle/media/source/org/jivesoftware/jingleaudio/jmf/AudioMediaSession.java b/jingle/media/source/org/jivesoftware/jingleaudio/jmf/AudioMediaSession.java
new file mode 100644
index 000000000..d85a21168
--- /dev/null
+++ b/jingle/media/source/org/jivesoftware/jingleaudio/jmf/AudioMediaSession.java
@@ -0,0 +1,155 @@
+package org.jivesoftware.jingleaudio.jmf; /**
+ * $RCSfile$
+ * $Revision: $
+ * $Date: 08/11/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.
+ */
+
+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()
+ */
+public class AudioMediaSession extends JingleMediaSession {
+
+ private AudioFormat format;
+ private AudioChannel audioChannel;
+
+ /**
+ * 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 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("dsound://"), 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() {
+ 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;
+ }
+}
diff --git a/jingle/media/source/org/jivesoftware/jingleaudio/jmf/AudioReceiver.java b/jingle/media/source/org/jivesoftware/jingleaudio/jmf/AudioReceiver.java
new file mode 100644
index 000000000..f7645bd8d
--- /dev/null
+++ b/jingle/media/source/org/jivesoftware/jingleaudio/jmf/AudioReceiver.java
@@ -0,0 +1,143 @@
+package org.jivesoftware.jingleaudio.jmf; /**
+ * $RCSfile$
+ * $Revision: $
+ * $Date: 08/11/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.
+ */
+
+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
+ */
+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);
+ }
+
+ }
+}
diff --git a/jingle/media/source/org/jivesoftware/jingleaudio/jmf/JmfMediaManager.java b/jingle/media/source/org/jivesoftware/jingleaudio/jmf/JmfMediaManager.java
new file mode 100644
index 000000000..a6f0e3dd1
--- /dev/null
+++ b/jingle/media/source/org/jivesoftware/jingleaudio/jmf/JmfMediaManager.java
@@ -0,0 +1,119 @@
+package org.jivesoftware.jingleaudio.jmf;
+
+/**
+ * $RCSfile$
+ * $Revision: $
+ * $Date: 08/11/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.
+ */
+
+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.io.File;
+import java.io.IOException;
+
+/**
+ * Implements a jingleMediaManager using JMF based API.
+ * It supports GSM and G723 codecs.
+ * This API only currently works on windows.
+ */
+public class JmfMediaManager extends JingleMediaManager {
+
+ /**
+ * Creates a Media Manager instance
+ */
+ public JmfMediaManager() {
+ setupPayloads();
+ setupJMF();
+ }
+
+ /**
+ * 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() {
+ this.addPayloadType(new PayloadType.Audio(3, "gsm"));
+ this.addPayloadType(new PayloadType.Audio(4, "g723"));
+ }
+
+ /**
+ * Runs JMFInit the first time the application is started so that capture
+ * devices are properly detected and initialized by JMF.
+ */
+ public static void setupJMF() {
+ try {
+
+ // .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) {
+ //JMFInit init = new JMFInit(null);
+ //init.setVisible(false);
+ }
+
+ }
+ finally {
+
+ }
+
+ }
+
+ private static void runLinuxPreInstall() {
+ // @TODO Implement Linux Pre-Install
+ }
+}
diff --git a/jingle/media/source/org/jivesoftware/jingleaudio/jspeex/AudioMediaSession.java b/jingle/media/source/org/jivesoftware/jingleaudio/jspeex/AudioMediaSession.java
new file mode 100644
index 000000000..897beb65c
--- /dev/null
+++ b/jingle/media/source/org/jivesoftware/jingleaudio/jspeex/AudioMediaSession.java
@@ -0,0 +1,209 @@
+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;
+
+/**
+ * $RCSfile$
+ * $Revision: $
+ * $Date: 25/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 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 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() {
+ // Do nothing
+ }
+
+ /**
+ * 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) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void senderReportReceived(SenderReport report) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void streamClosed(StreamPlayer stream, boolean timeout) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ /**
+ * 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;
+ }
+}
diff --git a/jingle/media/source/org/jivesoftware/jingleaudio/jspeex/SpeexMediaManager.java b/jingle/media/source/org/jivesoftware/jingleaudio/jspeex/SpeexMediaManager.java
new file mode 100644
index 000000000..6b8a61ecd
--- /dev/null
+++ b/jingle/media/source/org/jivesoftware/jingleaudio/jspeex/SpeexMediaManager.java
@@ -0,0 +1,101 @@
+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 java.io.File;
+import java.io.IOException;
+
+/**
+ * $RCSfile$
+ * $Revision: $
+ * $Date: 25/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 SpeexMediaManager extends JingleMediaManager {
+
+ 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() {
+ this.addPayloadType(new PayloadType.Audio(15, "speex"));
+ }
+
+ /**
+ * Runs JMFInit the first time the application is started so that capture
+ * devices are properly detected and initialized by JMF.
+ */
+ public static void setupJMF() {
+ try {
+
+ // .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) {
+ //JMFInit init = new JMFInit(null);
+ //init.setVisible(false);
+ }
+
+ }
+ finally {
+
+ }
+
+ }
+
+ private static void runLinuxPreInstall() {
+ // @TODO Implement Linux Pre-Install
+ }
+}
diff --git a/jingle/media/test/JingleMediaTest.java b/jingle/media/test/JingleMediaTest.java
new file mode 100644
index 000000000..ea3ccaec6
--- /dev/null
+++ b/jingle/media/test/JingleMediaTest.java
@@ -0,0 +1,362 @@
+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.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.media.JingleMediaManager;
+import org.jivesoftware.smackx.jingle.nat.BridgedTransportManager;
+import org.jivesoftware.smackx.jingle.nat.ICETransportManager;
+import org.jivesoftware.smackx.jingle.nat.STUNTransportManager;
+
+import javax.media.MediaLocator;
+import javax.media.format.AudioFormat;
+import java.net.InetAddress;
+
+/**
+ * $RCSfile$
+ * $Revision: $
+ * $Date: 09/11/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 JingleMediaTest extends TestCase {
+
+ public void testCompleteJmf() {
+
+ try {
+
+ //XMPPConnection.DEBUG_ENABLED = true;
+
+ XMPPConnection x0 = new XMPPConnection("thiago");
+ XMPPConnection x1 = new XMPPConnection("thiago");
+
+ x0.connect();
+ x0.login("barata7", "barata7");
+ x1.connect();
+ x1.login("barata6", "barata6");
+
+ final JingleManager jm0 = new JingleManager(
+ x0, new ICETransportManager());
+ final JingleManager jm1 = new JingleManager(
+ x1, new ICETransportManager());
+
+ 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("barata6@thiago/Smack");
+
+ js0.start();
+
+ Thread.sleep(50000);
+ js0.terminate();
+
+ Thread.sleep(6000);
+
+ x0.disconnect();
+ x1.disconnect();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ public void testCompleteSpeex() {
+
+ try {
+
+ //XMPPConnection.DEBUG_ENABLED = true;
+
+ XMPPConnection x0 = new XMPPConnection("thiago");
+ XMPPConnection x1 = new XMPPConnection("thiago");
+
+ x0.connect();
+ x0.login("barata7", "barata7");
+ x1.connect();
+ x1.login("barata6", "barata6");
+
+ 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("barata6@thiago/Smack");
+
+ 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 = new XMPPConnection("thiago");
+ XMPPConnection x1 = new XMPPConnection("thiago");
+
+ x0.connect();
+ x0.login("user" + String.valueOf(n), "user" + String.valueOf(n));
+ x1.connect();
+ x1.login("user" + String.valueOf(n + 1), "user" + String.valueOf(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 SpeexMediaManager();
+ JingleMediaManager jingleMediaManager2 = new SpeexMediaManager();
+
+ 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("user" + String.valueOf(n + 1) + "@thiago/Smack");
+
+ 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(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ }
+
+ public void testCompleteWithBridgeB() {
+ try {
+
+ //XMPPConnection.DEBUG_ENABLED = true;
+
+ XMPPConnection x0 = new XMPPConnection("thiago");
+ XMPPConnection x1 = new XMPPConnection("thiago");
+
+ x0.connect();
+ x0.login("barata5", "barata5");
+ x1.connect();
+ x1.login("barata4", "barata4");
+
+ 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("barata4@thiago/Smack");
+
+ js0.start();
+
+ Thread.sleep(20000);
+
+ js0.terminate();
+
+ Thread.sleep(3000);
+
+ js0 = jm0.createOutgoingJingleSession("barata4@thiago/Smack");
+
+ 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();
+ }
+ }
+}
\ No newline at end of file