| Index: org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaSession.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaSession.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaSession.java (working copy) |
| @@ -1,92 +0,0 @@ |
| -/** |
| - * $RCSfile: TestMediaSession.java,v $ |
| - * $Revision: 1.1 $ |
| - * $Date: 08/11/2006 |
| - * <p/> |
| - * Copyright 2003-2006 Jive Software. |
| - * <p/> |
| - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); |
| - * you may not use this file except in compliance with the License. |
| - * You may obtain a copy of the License at |
| - * <p/> |
| - * http://www.apache.org/licenses/LICENSE-2.0 |
| - * <p/> |
| - * Unless required by applicable law or agreed to in writing, software |
| - * distributed under the License is distributed on an "AS IS" BASIS, |
| - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| - * See the License for the specific language governing permissions and |
| - * limitations under the License. |
| - */ |
| -package org.jivesoftware.smackx.jingle.mediaimpl.test; |
| - |
| -import org.jivesoftware.smackx.jingle.JingleSession; |
| -import org.jivesoftware.smackx.jingle.media.JingleMediaSession; |
| -import org.jivesoftware.smackx.jingle.media.PayloadType; |
| -import org.jivesoftware.smackx.jingle.nat.TransportCandidate; |
| - |
| -/** |
| - * This Class implements a complete JingleMediaSession for unit testing. |
| - * |
| - * @author Thiago Camargo |
| - */ |
| -public class TestMediaSession extends JingleMediaSession { |
| - |
| - /** |
| - * Creates a TestMediaSession 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 |
| - * @param locator media locator |
| - */ |
| - public TestMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, |
| - final String locator, JingleSession jingleSession) { |
| - super(payloadType, remote, local, "Test", jingleSession); |
| - initialize(); |
| - } |
| - |
| - /** |
| - * Initialize the screen share channels. |
| - */ |
| - public void initialize() { |
| - |
| - } |
| - |
| - /** |
| - * Starts transmission and for NAT Traversal reasons start receiving also. |
| - */ |
| - public void startTrasmit() { |
| - |
| - } |
| - |
| - /** |
| - * 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 active state |
| - */ |
| - public void setTrasmit(boolean 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() { |
| - |
| - } |
| - |
| - /** |
| - * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf |
| - */ |
| - public void stopReceive() { |
| - |
| - } |
| -} |
| Index: org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaManager.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaManager.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaManager.java (working copy) |
| @@ -1,93 +0,0 @@ |
| -/** |
| - * $RCSfile: TestMediaManager.java,v $ |
| - * $Revision: 1.3 $ |
| - * $Date: 25/12/2006 |
| - * <p/> |
| - * Copyright 2003-2006 Jive Software. |
| - * <p/> |
| - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); |
| - * you may not use this file except in compliance with the License. |
| - * You may obtain a copy of the License at |
| - * <p/> |
| - * http://www.apache.org/licenses/LICENSE-2.0 |
| - * <p/> |
| - * Unless required by applicable law or agreed to in writing, software |
| - * distributed under the License is distributed on an "AS IS" BASIS, |
| - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| - * See the License for the specific language governing permissions and |
| - * limitations under the License. |
| - */ |
| - |
| -package org.jivesoftware.smackx.jingle.mediaimpl.test; |
| - |
| -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.JingleTransportManager; |
| -import org.jivesoftware.smackx.jingle.nat.TransportCandidate; |
| -import org.jivesoftware.smackx.jingle.JingleSession; |
| - |
| -import java.util.*; |
| - |
| -/** |
| - * Implements a MediaManager for test purposes. |
| - * |
| - * @author Thiago Camargo |
| - */ |
| - |
| -public class TestMediaManager extends JingleMediaManager { |
| - |
| - public static final String MEDIA_NAME = "TestMedia"; |
| - |
| - private List<PayloadType> payloads = new ArrayList<PayloadType>(); |
| - |
| - private PayloadType preferredPayloadType = null; |
| - |
| - public TestMediaManager(JingleTransportManager transportManager) { |
| - super(transportManager); |
| - } |
| - |
| - /** |
| - * Return all supported Payloads for this Manager. |
| - * |
| - * @return The Payload List |
| - */ |
| - public List<PayloadType> getPayloads() { |
| - return payloads; |
| - } |
| - |
| - public void setPayloads(List<PayloadType> payloads) { |
| - this.payloads.addAll(payloads); |
| - } |
| - |
| - /** |
| - * Returns a new JingleMediaSession |
| - * |
| - * @param payloadType payloadType |
| - * @param remote remote Candidate |
| - * @param local local Candidate |
| - * @return JingleMediaSession JingleMediaSession |
| - */ |
| - public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, |
| - final TransportCandidate local, final JingleSession jingleSession) { |
| - TestMediaSession session = null; |
| - |
| - session = new TestMediaSession(payloadType, remote, local, "", jingleSession); |
| - |
| - return session; |
| - } |
| - |
| - public PayloadType getPreferredPayloadType() { |
| - if (preferredPayloadType != null) |
| - return preferredPayloadType; |
| - return super.getPreferredPayloadType(); |
| - } |
| - |
| - public void setPreferredPayloadType(PayloadType preferredPayloadType) { |
| - this.preferredPayloadType = preferredPayloadType; |
| - } |
| - |
| - public String getName() { |
| - return MEDIA_NAME; |
| - } |
| -} |
| Index: org/jivesoftware/smackx/jingle/mediaimpl/JMFInit.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/JMFInit.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/JMFInit.java (working copy) |
| @@ -1,282 +0,0 @@ |
| -package org.jivesoftware.smackx.jingle.mediaimpl;
|
| -
|
| -import java.awt.Frame;
|
| -import java.awt.TextArea;
|
| -import java.awt.Toolkit;
|
| -import java.util.Vector;
|
| -
|
| -import javax.media.Format;
|
| -import javax.media.PlugInManager;
|
| -import javax.media.Renderer;
|
| -import javax.media.format.AudioFormat;
|
| -
|
| -import org.jivesoftware.smackx.jingle.SmackLogger;
|
| -
|
| -import com.sun.media.ExclusiveUse;
|
| -import com.sun.media.util.Registry;
|
| -
|
| -public class JMFInit extends Frame implements Runnable {
|
| -
|
| - private static final SmackLogger LOGGER = SmackLogger.getLogger(JMFInit.class);
|
| -
|
| - private String tempDir = "/tmp";
|
| -
|
| - private boolean done = false;
|
| -
|
| - private String userHome;
|
| -
|
| - private boolean visible = false;
|
| -
|
| - public JMFInit(String[] args, boolean visible) {
|
| - super("Initializing JMF...");
|
| -
|
| - this.visible = visible;
|
| -
|
| - Registry.set("secure.allowCaptureFromApplets", true);
|
| - Registry.set("secure.allowSaveFileFromApplets", true);
|
| -
|
| - updateTemp(args);
|
| -
|
| - try {
|
| - Registry.commit();
|
| - }
|
| - catch (Exception e) {
|
| -
|
| - message("Failed to commit to JMFRegistry!");
|
| - }
|
| -
|
| - Thread detectThread = new Thread(this);
|
| - detectThread.run();
|
| -
|
| - /*
|
| - * int slept = 0; while (!done && slept < 60 * 1000 * 2) { try {
|
| - * Thread.currentThread().sleep(500); } catch (InterruptedException ie) { }
|
| - * slept += 500; }
|
| - *
|
| - * if (!done) { console.error("Detection is taking too long!
|
| - * Aborting!"); message("Detection is taking too long! Aborting!"); }
|
| - *
|
| - * try { Thread.currentThread().sleep(2000); } catch
|
| - * (InterruptedException ie) { }
|
| - */
|
| - }
|
| -
|
| - public void run() {
|
| - detectDirectAudio();
|
| - detectS8DirectAudio();
|
| - detectCaptureDevices();
|
| - done = true;
|
| - }
|
| -
|
| - private void updateTemp(String[] args) {
|
| - if (args != null && args.length > 0) {
|
| - tempDir = args[0];
|
| -
|
| - message("Setting cache directory to " + tempDir);
|
| - Registry r = new Registry();
|
| - try {
|
| - r.set("secure.cacheDir", tempDir);
|
| - r.commit();
|
| -
|
| - message("Updated registry");
|
| - }
|
| - catch (Exception e) {
|
| - message("Couldn't update registry!");
|
| - }
|
| - }
|
| - }
|
| -
|
| - private void detectCaptureDevices() {
|
| - // check if JavaSound capture is available
|
| - message("Looking for Audio capturer");
|
| - Class dsauto;
|
| - try {
|
| - dsauto = Class.forName("DirectSoundAuto");
|
| - dsauto.newInstance();
|
| - message("Finished detecting DirectSound capturer");
|
| - }
|
| - catch (ThreadDeath td) {
|
| - throw td;
|
| - }
|
| - catch (Throwable t) {
|
| - //Do nothing
|
| - }
|
| -
|
| - Class jsauto;
|
| - try {
|
| - jsauto = Class.forName("JavaSoundAuto");
|
| - jsauto.newInstance();
|
| - message("Finished detecting javasound capturer");
|
| - }
|
| - catch (ThreadDeath td) {
|
| - throw td;
|
| - }
|
| - catch (Throwable t) {
|
| - message("JavaSound capturer detection failed!");
|
| - }
|
| -
|
| - /*
|
| - // Check if VFWAuto or SunVideoAuto is available
|
| - message("Looking for video capture devices");
|
| - Class auto = null;
|
| - Class autoPlus = null;
|
| - try {
|
| - auto = Class.forName("VFWAuto");
|
| - }
|
| - catch (Exception e) {
|
| - }
|
| - if (auto == null) {
|
| - try {
|
| - auto = Class.forName("SunVideoAuto");
|
| - }
|
| - catch (Exception ee) {
|
| -
|
| - }
|
| - try {
|
| - autoPlus = Class.forName("SunVideoPlusAuto");
|
| - }
|
| - catch (Exception ee) {
|
| -
|
| - }
|
| - }
|
| - if (auto == null) {
|
| - try {
|
| - auto = Class.forName("V4LAuto");
|
| - }
|
| - catch (Exception ee) {
|
| -
|
| - }
|
| - }
|
| - try {
|
| - Object instance = auto.newInstance();
|
| - if (autoPlus != null) {
|
| - Object instancePlus = autoPlus.newInstance();
|
| - }
|
| -
|
| - message("Finished detecting video capture devices");
|
| - }
|
| - catch (ThreadDeath td) {
|
| - throw td;
|
| - }
|
| - catch (Throwable t) {
|
| -
|
| - message("Capture device detection failed!");
|
| - }
|
| - */
|
| - }
|
| -
|
| - private void detectDirectAudio() {
|
| - Class cls;
|
| - int plType = PlugInManager.RENDERER;
|
| - String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
|
| - try {
|
| - // Check if this is the Windows Performance Pack - hack
|
| - cls = Class.forName("VFWAuto");
|
| - // Check if DS capture is supported, otherwise fail DS renderer
|
| - // since NT doesn't have capture
|
| - cls = Class.forName("com.sun.media.protocol.dsound.DSound");
|
| - // Find the renderer class and instantiate it.
|
| - cls = Class.forName(dar);
|
| -
|
| - Renderer rend = (Renderer) cls.newInstance();
|
| - try {
|
| - // Set the format and open the device
|
| - AudioFormat af = new AudioFormat(AudioFormat.LINEAR, 44100, 16,
|
| - 2);
|
| - rend.setInputFormat(af);
|
| - rend.open();
|
| - Format[] inputFormats = rend.getSupportedInputFormats();
|
| - // Register the device
|
| - PlugInManager.addPlugIn(dar, inputFormats, new Format[0],
|
| - plType);
|
| - // Move it to the top of the list
|
| - Vector rendList = PlugInManager.getPlugInList(null, null,
|
| - plType);
|
| - int listSize = rendList.size();
|
| - if (rendList.elementAt(listSize - 1).equals(dar)) {
|
| - rendList.removeElementAt(listSize - 1);
|
| - rendList.insertElementAt(dar, 0);
|
| - PlugInManager.setPlugInList(rendList, plType);
|
| - PlugInManager.commit();
|
| - // Log.debug("registered");
|
| - }
|
| - rend.close();
|
| - }
|
| - catch (Throwable t) {
|
| - // Log.debug("Error " + t);
|
| - }
|
| - }
|
| - catch (Throwable tt) {
|
| - //Do nothing
|
| - }
|
| - }
|
| -
|
| - private void detectS8DirectAudio() {
|
| - Class cls;
|
| - int plType = PlugInManager.RENDERER;
|
| - String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
|
| - try {
|
| - // Check if this is the solaris Performance Pack - hack
|
| - cls = Class.forName("SunVideoAuto");
|
| -
|
| - // Find the renderer class and instantiate it.
|
| - cls = Class.forName(dar);
|
| -
|
| - Renderer rend = (Renderer) cls.newInstance();
|
| -
|
| - if (rend instanceof ExclusiveUse
|
| - && !((ExclusiveUse) rend).isExclusive()) {
|
| - // sol8+, DAR supports mixing
|
| - Vector rendList = PlugInManager.getPlugInList(null, null,
|
| - plType);
|
| - int listSize = rendList.size();
|
| - boolean found = false;
|
| - String rname = null;
|
| -
|
| - for (int i = 0; i < listSize; i++) {
|
| - rname = (String) (rendList.elementAt(i));
|
| - if (rname.equals(dar)) { // DAR is in the registry
|
| - found = true;
|
| - rendList.removeElementAt(i);
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (found) {
|
| - rendList.insertElementAt(dar, 0);
|
| - PlugInManager.setPlugInList(rendList, plType);
|
| - PlugInManager.commit();
|
| - }
|
| - }
|
| - }
|
| - catch (Throwable tt) {
|
| - //Do nothing
|
| - }
|
| - }
|
| -
|
| - private void message(String mesg) {
|
| - LOGGER.debug(mesg);
|
| - }
|
| -
|
| - private void createGUI() {
|
| - TextArea textBox = new TextArea(5, 50);
|
| - add("Center", textBox);
|
| - textBox.setEditable(false);
|
| - addNotify();
|
| - pack();
|
| -
|
| - int scrWidth = (int) Toolkit.getDefaultToolkit().getScreenSize()
|
| - .getWidth();
|
| - int scrHeight = (int) Toolkit.getDefaultToolkit().getScreenSize()
|
| - .getHeight();
|
| -
|
| - setLocation((scrWidth - getWidth()) / 2, (scrHeight - getHeight()) / 2);
|
| -
|
| - setVisible(visible);
|
| -
|
| - }
|
| -
|
| - public static void start(boolean visible) {
|
| - new JMFInit(null, visible);
|
| - }
|
| -}
|
| Index: org/jivesoftware/smackx/jingle/mediaimpl/demo/Demo.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/demo/Demo.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/demo/Demo.java (working copy) |
| @@ -1,174 +0,0 @@ |
| -/**
|
| - * $RCSfile: Demo.java,v $
|
| - * $Revision: 1.3 $
|
| - * $Date: 28/12/2006
|
| - * <p/>
|
| - * Copyright 2003-2006 Jive Software.
|
| - * <p/>
|
| - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
| - * you may not use this file except in compliance with the License.
|
| - * You may obtain a copy of the License at
|
| - * <p/>
|
| - * http://www.apache.org/licenses/LICENSE-2.0
|
| - * <p/>
|
| - * Unless required by applicable law or agreed to in writing, software
|
| - * distributed under the License is distributed on an "AS IS" BASIS,
|
| - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| - * See the License for the specific language governing permissions and
|
| - * limitations under the License.
|
| - */
|
| -package org.jivesoftware.smackx.jingle.mediaimpl.demo;
|
| -
|
| -import org.jivesoftware.smack.Connection;
|
| -import org.jivesoftware.smack.XMPPConnection;
|
| -import org.jivesoftware.smack.XMPPException;
|
| -import org.jivesoftware.smackx.jingle.JingleManager;
|
| -import org.jivesoftware.smackx.jingle.JingleSession;
|
| -import org.jivesoftware.smackx.jingle.JingleSessionRequest;
|
| -import org.jivesoftware.smackx.jingle.listeners.JingleSessionRequestListener;
|
| -import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
|
| -import org.jivesoftware.smackx.jingle.mediaimpl.jspeex.SpeexMediaManager;
|
| -import org.jivesoftware.smackx.jingle.mediaimpl.sshare.ScreenShareMediaManager;
|
| -import org.jivesoftware.smackx.jingle.nat.ICETransportManager;
|
| -import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
|
| -
|
| -import javax.swing.*;
|
| -import java.awt.event.ActionEvent;
|
| -import java.util.ArrayList;
|
| -import java.util.List;
|
| -
|
| -/**
|
| - * Jingle Demo Application. It register in a XMPP Server and let users place calls using a full JID and auto-receive calls.
|
| - * Parameters: Server User Pass.
|
| - */
|
| -public class Demo extends JFrame {
|
| -
|
| - private JingleTransportManager transportManager = null;
|
| - private Connection xmppConnection = null;
|
| -
|
| - private String server = null;
|
| - private String user = null;
|
| - private String pass = null;
|
| -
|
| - private JingleManager jm = null;
|
| - private JingleSession incoming = null;
|
| - private JingleSession outgoing = null;
|
| -
|
| - private JTextField jid;
|
| -
|
| - public Demo(String server, String user, String pass) {
|
| -
|
| - this.server = server;
|
| - this.user = user;
|
| - this.pass = pass;
|
| -
|
| - if (user.equals("jeffw")) {
|
| - jid = new JTextField("eowyn" + "@" + server + "/Smack");
|
| - } else {
|
| - jid = new JTextField("jeffw" + "@" + server + "/Smack");
|
| - }
|
| -
|
| - xmppConnection = new XMPPConnection(server);
|
| - try {
|
| - xmppConnection.connect();
|
| - xmppConnection.login(user, pass);
|
| - initialize();
|
| - }
|
| - catch (XMPPException e) {
|
| - e.printStackTrace();
|
| - }
|
| - }
|
| -
|
| - public void initialize() {
|
| - ICETransportManager icetm0 = new ICETransportManager(xmppConnection, "10.47.47.53", 3478);
|
| - List<JingleMediaManager> mediaManagers = new ArrayList<JingleMediaManager>();
|
| - //mediaManagers.add(new JmfMediaManager(icetm0));
|
| - mediaManagers.add(new SpeexMediaManager(icetm0));
|
| - mediaManagers.add(new ScreenShareMediaManager(icetm0));
|
| - jm = new JingleManager(xmppConnection, mediaManagers);
|
| - jm.addCreationListener(icetm0);
|
| -
|
| - jm.addJingleSessionRequestListener(new JingleSessionRequestListener() {
|
| - public void sessionRequested(JingleSessionRequest request) {
|
| -
|
| -// if (incoming != null)
|
| -// return;
|
| -
|
| - try {
|
| - // Accept the call
|
| - incoming = request.accept();
|
| -
|
| - // Start the call
|
| - incoming.startIncoming();
|
| - }
|
| - 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());
|
| - outgoing.startOutgoing();
|
| - }
|
| - 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);
|
| - }
|
| -
|
| - }
|
| -
|
| -}
|
| Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareSession.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareSession.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareSession.java (working copy) |
| @@ -1,206 +0,0 @@ |
| -/** |
| - * $RCSfile: ScreenShareSession.java,v $ |
| - * $Revision: 1.2 $ |
| - * $Date: 08/11/2006 |
| - * <p/> |
| - * Copyright 2003-2006 Jive Software. |
| - * <p/> |
| - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); |
| - * you may not use this file except in compliance with the License. |
| - * You may obtain a copy of the License at |
| - * <p/> |
| - * http://www.apache.org/licenses/LICENSE-2.0 |
| - * <p/> |
| - * Unless required by applicable law or agreed to in writing, software |
| - * distributed under the License is distributed on an "AS IS" BASIS, |
| - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| - * See the License for the specific language governing permissions and |
| - * limitations under the License. |
| - */ |
| -package org.jivesoftware.smackx.jingle.mediaimpl.sshare; |
| - |
| -import java.awt.Rectangle; |
| -import java.awt.event.WindowAdapter; |
| -import java.awt.event.WindowEvent; |
| -import java.io.IOException; |
| -import java.net.DatagramSocket; |
| -import java.net.InetAddress; |
| -import java.net.ServerSocket; |
| -import java.net.UnknownHostException; |
| - |
| -import javax.swing.JFrame; |
| -import javax.swing.JPanel; |
| - |
| -import org.jivesoftware.smackx.jingle.JingleSession; |
| -import org.jivesoftware.smackx.jingle.SmackLogger; |
| -import org.jivesoftware.smackx.jingle.media.JingleMediaSession; |
| -import org.jivesoftware.smackx.jingle.media.PayloadType; |
| -import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageDecoder; |
| -import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageEncoder; |
| -import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageReceiver; |
| -import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageTransmitter; |
| -import org.jivesoftware.smackx.jingle.nat.TransportCandidate; |
| - |
| -/** |
| - * This Class implements a complete JingleMediaSession. |
| - * It sould be used to transmit and receive captured images from the Display. |
| - * This Class should be automaticly controlled by JingleSession. |
| - * For better NAT Traversal support this implementation don't support only receive or only transmit. |
| - * To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit() |
| - * |
| - * @author Thiago Camargo |
| - */ |
| -public class ScreenShareSession extends JingleMediaSession { |
| - |
| - private static final SmackLogger LOGGER = SmackLogger.getLogger(ScreenShareSession.class); |
| - |
| - private ImageTransmitter transmitter = null; |
| - private ImageReceiver receiver = null; |
| - private int width = 600; |
| - private int height = 600; |
| - |
| - /** |
| - * 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 |
| - * @param locator media locator |
| - */ |
| - public ScreenShareSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, |
| - final String locator, JingleSession jingleSession) { |
| - super(payloadType, remote, local, "Screen", jingleSession); |
| - initialize(); |
| - } |
| - |
| - /** |
| - * Initialize the screen share channels. |
| - */ |
| - public void initialize() { |
| - |
| - JingleSession session = getJingleSession(); |
| - if ((session != null) && (session.getInitiator().equals(session.getConnection().getUser()))) { |
| - // If the initiator of the jingle session is us then we transmit a screen share. |
| - try { |
| - InetAddress remote = InetAddress.getByName(getRemote().getIp()); |
| - transmitter = new ImageTransmitter(new DatagramSocket(getLocal().getPort()), remote, getRemote().getPort(), |
| - new Rectangle(0, 0, width, height)); |
| - } catch (Exception e) { |
| - e.printStackTrace(); |
| - } |
| - |
| - } else { |
| - // Otherwise we receive a screen share. |
| - JFrame window = new JFrame(); |
| - JPanel jp = new JPanel(); |
| - window.add(jp); |
| - |
| - window.setLocation(0, 0); |
| - window.setSize(600, 600); |
| - |
| - window.addWindowListener(new WindowAdapter() { |
| - public void windowClosed(WindowEvent e) { |
| - receiver.stop(); |
| - } |
| - }); |
| - |
| - try { |
| - receiver = new ImageReceiver(InetAddress.getByName("0.0.0.0"), getRemote().getPort(), getLocal().getPort(), width, |
| - height); |
| - LOGGER.debug("Receiving on:" + receiver.getLocalPort()); |
| - } catch (UnknownHostException e) { |
| - e.printStackTrace(); |
| - } |
| - |
| - jp.add(receiver); |
| - receiver.setVisible(true); |
| - window.setAlwaysOnTop(true); |
| - window.setVisible(true); |
| - } |
| - } |
| - |
| - /** |
| - * Starts transmission and for NAT Traversal reasons start receiving also. |
| - */ |
| - public void startTrasmit() { |
| - new Thread(transmitter).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 active state |
| - */ |
| - public void setTrasmit(boolean active) { |
| - transmitter.setTransmit(true); |
| - } |
| - |
| - /** |
| - * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf |
| - */ |
| - public void startReceive() { |
| - // Do nothing |
| - } |
| - |
| - /** |
| - * Stops transmission and for NAT Traversal reasons stop receiving also. |
| - */ |
| - public void stopTrasmit() { |
| - if (transmitter != null) { |
| - transmitter.stop(); |
| - } |
| - } |
| - |
| - /** |
| - * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf |
| - */ |
| - public void stopReceive() { |
| - if (receiver != null) { |
| - receiver.stop(); |
| - } |
| - } |
| - |
| - /** |
| - * 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; |
| - } |
| - |
| - public void setEncoder(ImageEncoder encoder) { |
| - if (encoder != null) { |
| - this.transmitter.setEncoder(encoder); |
| - } |
| - } |
| - |
| - public void setDecoder(ImageDecoder decoder) { |
| - if (decoder != null) { |
| - this.receiver.setDecoder(decoder); |
| - } |
| - } |
| -} |
| Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageTransmitter.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageTransmitter.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageTransmitter.java (working copy) |
| @@ -1,204 +0,0 @@ |
| -package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
|
| -
|
| -import java.awt.AWTException;
|
| -import java.awt.Rectangle;
|
| -import java.awt.Robot;
|
| -import java.awt.image.BufferedImage;
|
| -import java.awt.image.PixelGrabber;
|
| -import java.io.ByteArrayOutputStream;
|
| -import java.io.IOException;
|
| -import java.net.DatagramPacket;
|
| -import java.net.DatagramSocket;
|
| -import java.net.InetAddress;
|
| -import java.util.Arrays;
|
| -
|
| -import org.jivesoftware.smackx.jingle.SmackLogger;
|
| -
|
| -/**
|
| - * UDP Image Receiver.
|
| - * It uses PNG Tiles into UDP packets.
|
| - *
|
| - * @author Thiago Rocha Camargo
|
| - */
|
| -public class ImageTransmitter implements Runnable {
|
| -
|
| - private static final SmackLogger LOGGER = SmackLogger.getLogger(ImageTransmitter.class);
|
| -
|
| - private Robot robot;
|
| - private InetAddress localHost;
|
| - private InetAddress remoteHost;
|
| - private int localPort;
|
| - private int remotePort;
|
| - public static final int tileWidth = 25;
|
| - private boolean on = true;
|
| - private boolean transmit = false;
|
| - private DatagramSocket socket;
|
| - private Rectangle area;
|
| - private int tiles[][][];
|
| - private int maxI;
|
| - private int maxJ;
|
| - private ImageEncoder encoder;
|
| - public final static int KEYFRAME = 10;
|
| -
|
| - public ImageTransmitter(DatagramSocket socket, InetAddress remoteHost, int remotePort, Rectangle area) {
|
| -
|
| - try {
|
| - robot = new Robot();
|
| -
|
| - maxI = (int) Math.ceil(area.getWidth() / tileWidth);
|
| - maxJ = (int) Math.ceil(area.getHeight() / tileWidth);
|
| -
|
| - tiles = new int[maxI][maxJ][tileWidth * tileWidth];
|
| -
|
| - this.area = area;
|
| - this.socket = socket;
|
| - localHost = socket.getLocalAddress();
|
| - localPort = socket.getLocalPort();
|
| - this.remoteHost = remoteHost;
|
| - this.remotePort = remotePort;
|
| - this.encoder = new DefaultEncoder();
|
| -
|
| - transmit = true;
|
| -
|
| - }
|
| - catch (AWTException e) {
|
| - e.printStackTrace();
|
| - }
|
| -
|
| - }
|
| -
|
| - public void start() {
|
| - byte buf[] = new byte[1024];
|
| - final DatagramPacket p = new DatagramPacket(buf, 1024);
|
| -
|
| - int keyframe = 0;
|
| -
|
| - while (on) {
|
| - if (transmit) {
|
| -
|
| - BufferedImage capture = robot.createScreenCapture(area);
|
| -
|
| - QuantizeFilter filter = new QuantizeFilter();
|
| - capture = filter.filter(capture, null);
|
| -
|
| - long trace = System.currentTimeMillis();
|
| -
|
| - if (++keyframe > KEYFRAME) {
|
| - keyframe = 0;
|
| - }
|
| - LOGGER.debug("KEYFRAME:" + keyframe);
|
| -
|
| - for (int i = 0; i < maxI; i++) {
|
| - for (int j = 0; j < maxJ; j++) {
|
| -
|
| - final BufferedImage bufferedImage = capture.getSubimage(i * tileWidth, j * tileWidth, tileWidth, tileWidth);
|
| -
|
| - int pixels[] = new int[tileWidth * tileWidth];
|
| -
|
| - PixelGrabber pg = new PixelGrabber(bufferedImage, 0, 0, tileWidth, tileWidth, pixels, 0, tileWidth);
|
| -
|
| - try {
|
| - if (pg.grabPixels()) {
|
| -
|
| - if (keyframe == KEYFRAME || !Arrays.equals(tiles[i][j], pixels)) {
|
| -
|
| - ByteArrayOutputStream baos = encoder.encode(bufferedImage);
|
| -
|
| - if (baos != null) {
|
| -
|
| - try {
|
| -
|
| - Thread.sleep(1);
|
| -
|
| - baos.write(i);
|
| - baos.write(j);
|
| -
|
| - byte[] bytesOut = baos.toByteArray();
|
| -
|
| - if (bytesOut.length > 1000)
|
| - LOGGER.error("Bytes out > 1000. Equals " + bytesOut.length);
|
| -
|
| - p.setData(bytesOut);
|
| - p.setAddress(remoteHost);
|
| - p.setPort(remotePort);
|
| -
|
| - try {
|
| - socket.send(p);
|
| - }
|
| - catch (IOException e) {
|
| - e.printStackTrace();
|
| - }
|
| -
|
| - tiles[i][j] = pixels;
|
| -
|
| - }
|
| - catch (Exception e) {
|
| - }
|
| -
|
| - }
|
| -
|
| - }
|
| -
|
| - }
|
| - }
|
| - catch (InterruptedException e) {
|
| - e.printStackTrace();
|
| - }
|
| - }
|
| - }
|
| -
|
| - trace = (System.currentTimeMillis() - trace);
|
| - LOGGER.debug("Loop Time:" + trace);
|
| -
|
| - if (trace < 500) {
|
| - try {
|
| - Thread.sleep(500 - trace);
|
| - }
|
| - catch (InterruptedException e) {
|
| - e.printStackTrace();
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - public void run() {
|
| - start();
|
| - }
|
| -
|
| - /**
|
| - * Set Transmit Enabled/Disabled
|
| - *
|
| - * @param transmit boolean Enabled/Disabled
|
| - */
|
| - public void setTransmit(boolean transmit) {
|
| - this.transmit = transmit;
|
| - }
|
| -
|
| - /**
|
| - * Get the encoder used to encode Images Tiles
|
| - *
|
| - * @return encoder
|
| - */
|
| - public ImageEncoder getEncoder() {
|
| - return encoder;
|
| - }
|
| -
|
| - /**
|
| - * Set the encoder used to encode Image Tiles
|
| - *
|
| - * @param encoder encoder
|
| - */
|
| - public void setEncoder(ImageEncoder encoder) {
|
| - this.encoder = encoder;
|
| - }
|
| -
|
| - /**
|
| - * Stops Transmitter
|
| - */
|
| - public void stop() {
|
| - this.transmit = false;
|
| - this.on = false;
|
| - socket.close();
|
| - }
|
| -}
|
| Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageEncoder.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageEncoder.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageEncoder.java (working copy) |
| @@ -1,13 +0,0 @@ |
| -package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api; |
| - |
| -import java.awt.image.BufferedImage; |
| -import java.io.ByteArrayOutputStream; |
| - |
| -/** |
| - * Image Encoder Interface use this interface if you want to change the default encoder |
| - * |
| - * @author Thiago Rocha Camargo |
| - */ |
| -public interface ImageEncoder { |
| - public ByteArrayOutputStream encode(BufferedImage bufferedImage); |
| -} |
| Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/PixelUtils.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/PixelUtils.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/PixelUtils.java (working copy) |
| @@ -1,223 +0,0 @@ |
| -/* |
| -Copyright 2006 Jerry Huxtable |
| - |
| -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.smackx.jingle.mediaimpl.sshare.api; |
| - |
| -import java.awt.*; |
| -import java.util.Random; |
| - |
| -/** |
| - * Some more useful math functions for image processing. |
| - * These are becoming obsolete as we move to Java2D. Use MiscComposite instead. |
| - */ |
| -public class PixelUtils { |
| - |
| - public final static int REPLACE = 0; |
| - public final static int NORMAL = 1; |
| - public final static int MIN = 2; |
| - public final static int MAX = 3; |
| - public final static int ADD = 4; |
| - public final static int SUBTRACT = 5; |
| - public final static int DIFFERENCE = 6; |
| - public final static int MULTIPLY = 7; |
| - public final static int HUE = 8; |
| - public final static int SATURATION = 9; |
| - public final static int VALUE = 10; |
| - public final static int COLOR = 11; |
| - public final static int SCREEN = 12; |
| - public final static int AVERAGE = 13; |
| - public final static int OVERLAY = 14; |
| - public final static int CLEAR = 15; |
| - public final static int EXCHANGE = 16; |
| - public final static int DISSOLVE = 17; |
| - public final static int DST_IN = 18; |
| - public final static int ALPHA = 19; |
| - public final static int ALPHA_TO_GRAY = 20; |
| - |
| - private static Random randomGenerator = new Random(); |
| - |
| - /** |
| - * Clamp a value to the range 0..255 |
| - */ |
| - public static int clamp(int c) { |
| - if (c < 0) |
| - return 0; |
| - if (c > 255) |
| - return 255; |
| - return c; |
| - } |
| - |
| - public static int interpolate(int v1, int v2, float f) { |
| - return clamp((int)(v1+f*(v2-v1))); |
| - } |
| - |
| - public static int brightness(int rgb) { |
| - int r = (rgb >> 16) & 0xff; |
| - int g = (rgb >> 8) & 0xff; |
| - int b = rgb & 0xff; |
| - return (r+g+b)/3; |
| - } |
| - |
| - public static boolean nearColors(int rgb1, int rgb2, int tolerance) { |
| - int r1 = (rgb1 >> 16) & 0xff; |
| - int g1 = (rgb1 >> 8) & 0xff; |
| - int b1 = rgb1 & 0xff; |
| - int r2 = (rgb2 >> 16) & 0xff; |
| - int g2 = (rgb2 >> 8) & 0xff; |
| - int b2 = rgb2 & 0xff; |
| - return Math.abs(r1-r2) <= tolerance && Math.abs(g1-g2) <= tolerance && Math.abs(b1-b2) <= tolerance; |
| - } |
| - |
| - private final static float hsb1[] = new float[3];//FIXME-not thread safe |
| - private final static float hsb2[] = new float[3];//FIXME-not thread safe |
| - |
| - // Return rgb1 painted onto rgb2 |
| - public static int combinePixels(int rgb1, int rgb2, int op) { |
| - return combinePixels(rgb1, rgb2, op, 0xff); |
| - } |
| - |
| - public static int combinePixels(int rgb1, int rgb2, int op, int extraAlpha, int channelMask) { |
| - return (rgb2 & ~channelMask) | combinePixels(rgb1 & channelMask, rgb2, op, extraAlpha); |
| - } |
| - |
| - public static int combinePixels(int rgb1, int rgb2, int op, int extraAlpha) { |
| - if (op == REPLACE) |
| - return rgb1; |
| - int a1 = (rgb1 >> 24) & 0xff; |
| - int r1 = (rgb1 >> 16) & 0xff; |
| - int g1 = (rgb1 >> 8) & 0xff; |
| - int b1 = rgb1 & 0xff; |
| - int a2 = (rgb2 >> 24) & 0xff; |
| - int r2 = (rgb2 >> 16) & 0xff; |
| - int g2 = (rgb2 >> 8) & 0xff; |
| - int b2 = rgb2 & 0xff; |
| - |
| - switch (op) { |
| - case NORMAL: |
| - break; |
| - case MIN: |
| - r1 = Math.min(r1, r2); |
| - g1 = Math.min(g1, g2); |
| - b1 = Math.min(b1, b2); |
| - break; |
| - case MAX: |
| - r1 = Math.max(r1, r2); |
| - g1 = Math.max(g1, g2); |
| - b1 = Math.max(b1, b2); |
| - break; |
| - case ADD: |
| - r1 = clamp(r1+r2); |
| - g1 = clamp(g1+g2); |
| - b1 = clamp(b1+b2); |
| - break; |
| - case SUBTRACT: |
| - r1 = clamp(r2-r1); |
| - g1 = clamp(g2-g1); |
| - b1 = clamp(b2-b1); |
| - break; |
| - case DIFFERENCE: |
| - r1 = clamp(Math.abs(r1-r2)); |
| - g1 = clamp(Math.abs(g1-g2)); |
| - b1 = clamp(Math.abs(b1-b2)); |
| - break; |
| - case MULTIPLY: |
| - r1 = clamp(r1*r2/255); |
| - g1 = clamp(g1*g2/255); |
| - b1 = clamp(b1*b2/255); |
| - break; |
| - case DISSOLVE: |
| - if ((randomGenerator.nextInt() & 0xff) <= a1) { |
| - r1 = r2; |
| - g1 = g2; |
| - b1 = b2; |
| - } |
| - break; |
| - case AVERAGE: |
| - r1 = (r1+r2)/2; |
| - g1 = (g1+g2)/2; |
| - b1 = (b1+b2)/2; |
| - break; |
| - case HUE: |
| - case SATURATION: |
| - case VALUE: |
| - case COLOR: |
| - Color.RGBtoHSB(r1, g1, b1, hsb1); |
| - Color.RGBtoHSB(r2, g2, b2, hsb2); |
| - switch (op) { |
| - case HUE: |
| - hsb2[0] = hsb1[0]; |
| - break; |
| - case SATURATION: |
| - hsb2[1] = hsb1[1]; |
| - break; |
| - case VALUE: |
| - hsb2[2] = hsb1[2]; |
| - break; |
| - case COLOR: |
| - hsb2[0] = hsb1[0]; |
| - hsb2[1] = hsb1[1]; |
| - break; |
| - } |
| - rgb1 = Color.HSBtoRGB(hsb2[0], hsb2[1], hsb2[2]); |
| - r1 = (rgb1 >> 16) & 0xff; |
| - g1 = (rgb1 >> 8) & 0xff; |
| - b1 = rgb1 & 0xff; |
| - break; |
| - case SCREEN: |
| - r1 = 255 - ((255 - r1) * (255 - r2)) / 255; |
| - g1 = 255 - ((255 - g1) * (255 - g2)) / 255; |
| - b1 = 255 - ((255 - b1) * (255 - b2)) / 255; |
| - break; |
| - case OVERLAY: |
| - int m, s; |
| - s = 255 - ((255 - r1) * (255 - r2)) / 255; |
| - m = r1 * r2 / 255; |
| - r1 = (s * r1 + m * (255 - r1)) / 255; |
| - s = 255 - ((255 - g1) * (255 - g2)) / 255; |
| - m = g1 * g2 / 255; |
| - g1 = (s * g1 + m * (255 - g1)) / 255; |
| - s = 255 - ((255 - b1) * (255 - b2)) / 255; |
| - m = b1 * b2 / 255; |
| - b1 = (s * b1 + m * (255 - b1)) / 255; |
| - break; |
| - case CLEAR: |
| - r1 = g1 = b1 = 0xff; |
| - break; |
| - case DST_IN: |
| - r1 = clamp((r2*a1)/255); |
| - g1 = clamp((g2*a1)/255); |
| - b1 = clamp((b2*a1)/255); |
| - a1 = clamp((a2*a1)/255); |
| - return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1; |
| - case ALPHA: |
| - a1 = a1*a2/255; |
| - return (a1 << 24) | (r2 << 16) | (g2 << 8) | b2; |
| - case ALPHA_TO_GRAY: |
| - int na = 255-a1; |
| - return (a1 << 24) | (na << 16) | (na << 8) | na; |
| - } |
| - if (extraAlpha != 0xff || a1 != 0xff) { |
| - a1 = a1*extraAlpha/255; |
| - int a3 = (255-a1)*a2/255; |
| - r1 = clamp((r1*a1+r2*a3)/255); |
| - g1 = clamp((g1*a1+g2*a3)/255); |
| - b1 = clamp((b1*a1+b2*a3)/255); |
| - a1 = clamp(a1+a3); |
| - } |
| - return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1; |
| - } |
| - |
| -} |
| Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/Quantizer.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/Quantizer.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/Quantizer.java (working copy) |
| @@ -1,53 +0,0 @@ |
| -/* |
| -Copyright 2006 Jerry Huxtable |
| - |
| -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.smackx.jingle.mediaimpl.sshare.api; |
| - |
| -/** |
| - * The interface for an image quantizer. The addColor method is called (repeatedly |
| - * if necessary) with all the image pixels. A color table can then be returned by |
| - * calling the buildColorTable method. |
| - */ |
| -public interface Quantizer { |
| - /** |
| - * Initialize the quantizer. This should be called before adding any pixels. |
| - * @param numColors the number of colors we're quantizing to. |
| - */ |
| - public void setup(int numColors); |
| - |
| - /** |
| - * Add pixels to the quantizer. |
| - * @param pixels the array of ARGB pixels |
| - * @param offset the offset into the array |
| - * @param count the count of pixels |
| - */ |
| - public void addPixels(int[] pixels, int offset, int count); |
| - |
| - /** |
| - * Build a color table from the added pixels. |
| - * @return an array of ARGB pixels representing a color table |
| - */ |
| - public int[] buildColorTable(); |
| - |
| - /** |
| - * Using the previously-built color table, return the index into that table for a pixel. |
| - * This is guaranteed to return a valid index - returning the index of a color closer |
| - * to that requested if necessary. |
| - * @param rgb the pixel to find |
| - * @return the pixel's index in the color table |
| - */ |
| - public int getIndexForColor(int rgb); |
| -} |
| Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultEncoder.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultEncoder.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultEncoder.java (working copy) |
| @@ -1,24 +0,0 @@ |
| -package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api; |
| - |
| -import javax.imageio.ImageIO; |
| -import java.awt.image.BufferedImage; |
| -import java.io.ByteArrayOutputStream; |
| -import java.io.IOException; |
| - |
| -/** |
| - * Implements a default PNG Encoder |
| - */ |
| -public class DefaultEncoder implements ImageEncoder{ |
| - |
| - public ByteArrayOutputStream encode(BufferedImage bufferedImage) { |
| - ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| - try { |
| - ImageIO.write(bufferedImage, "png", baos); |
| - } |
| - catch (IOException e) { |
| - e.printStackTrace(); |
| - baos = null; |
| - } |
| - return baos; |
| - } |
| -} |
| Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/QuantizeFilter.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/QuantizeFilter.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/QuantizeFilter.java (working copy) |
| @@ -1,178 +0,0 @@ |
| -/* |
| -Copyright 2006 Jerry Huxtable |
| - |
| -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.smackx.jingle.mediaimpl.sshare.api; |
| - |
| -import java.awt.*; |
| - |
| -/** |
| - * A filter which quantizes an image to a set number of colors - useful for producing |
| - * images which are to be encoded using an index color model. The filter can perform |
| - * Floyd-Steinberg error-diffusion dithering if required. At present, the quantization |
| - * is done using an octtree algorithm but I eventually hope to add more quantization |
| - * methods such as median cut. Note: at present, the filter produces an image which |
| - * uses the RGB color model (because the application it was written for required it). |
| - * I hope to extend it to produce an IndexColorModel by request. |
| - */ |
| -public class QuantizeFilter extends WholeImageFilter { |
| - |
| - /** |
| - * Floyd-Steinberg dithering matrix. |
| - */ |
| - protected final static int[] matrix = { |
| - 0, 0, 0, |
| - 0, 0, 7, |
| - 3, 5, 1, |
| - }; |
| - private int sum = 3+5+7+1; |
| - |
| - private boolean dither; |
| - private int numColors = 256; |
| - private boolean serpentine = true; |
| - |
| - /** |
| - * Set the number of colors to quantize to. |
| - * @param numColors the number of colors. The default is 256. |
| - */ |
| - public void setNumColors(int numColors) { |
| - this.numColors = Math.min(Math.max(numColors, 8), 256); |
| - } |
| - |
| - /** |
| - * Get the number of colors to quantize to. |
| - * @return the number of colors. |
| - */ |
| - public int getNumColors() { |
| - return numColors; |
| - } |
| - |
| - /** |
| - * Set whether to use dithering or not. If not, the image is posterized. |
| - * @param dither true to use dithering |
| - */ |
| - public void setDither(boolean dither) { |
| - this.dither = dither; |
| - } |
| - |
| - /** |
| - * Return the dithering setting |
| - * @return the current setting |
| - */ |
| - public boolean getDither() { |
| - return dither; |
| - } |
| - |
| - /** |
| - * Set whether to use a serpentine pattern for return or not. This can reduce 'avalanche' artifacts in the output. |
| - * @param serpentine true to use serpentine pattern |
| - */ |
| - public void setSerpentine(boolean serpentine) { |
| - this.serpentine = serpentine; |
| - } |
| - |
| - /** |
| - * Return the serpentine setting |
| - * @return the current setting |
| - */ |
| - public boolean getSerpentine() { |
| - return serpentine; |
| - } |
| - |
| - public void quantize(int[] inPixels, int[] outPixels, int width, int height, int numColors, boolean dither, boolean serpentine) { |
| - int count = width*height; |
| - Quantizer quantizer = new OctTreeQuantizer(); |
| - quantizer.setup(numColors); |
| - quantizer.addPixels(inPixels, 0, count); |
| - int[] table = quantizer.buildColorTable(); |
| - |
| - if (!dither) { |
| - for (int i = 0; i < count; i++) |
| - outPixels[i] = table[quantizer.getIndexForColor(inPixels[i])]; |
| - } else { |
| - int index = 0; |
| - for (int y = 0; y < height; y++) { |
| - boolean reverse = serpentine && (y & 1) == 1; |
| - int direction; |
| - if (reverse) { |
| - index = y*width+width-1; |
| - direction = -1; |
| - } else { |
| - index = y*width; |
| - direction = 1; |
| - } |
| - for (int x = 0; x < width; x++) { |
| - int rgb1 = inPixels[index]; |
| - int rgb2 = table[quantizer.getIndexForColor(rgb1)]; |
| - |
| - outPixels[index] = rgb2; |
| - |
| - int r1 = (rgb1 >> 16) & 0xff; |
| - int g1 = (rgb1 >> 8) & 0xff; |
| - int b1 = rgb1 & 0xff; |
| - |
| - int r2 = (rgb2 >> 16) & 0xff; |
| - int g2 = (rgb2 >> 8) & 0xff; |
| - int b2 = rgb2 & 0xff; |
| - |
| - int er = r1-r2; |
| - int eg = g1-g2; |
| - int eb = b1-b2; |
| - |
| - for (int i = -1; i <= 1; i++) { |
| - int iy = i+y; |
| - if (0 <= iy && iy < height) { |
| - for (int j = -1; j <= 1; j++) { |
| - int jx = j+x; |
| - if (0 <= jx && jx < width) { |
| - int w; |
| - if (reverse) |
| - w = matrix[(i+1)*3-j+1]; |
| - else |
| - w = matrix[(i+1)*3+j+1]; |
| - if (w != 0) { |
| - int k = reverse ? index - j : index + j; |
| - rgb1 = inPixels[k]; |
| - r1 = (rgb1 >> 16) & 0xff; |
| - g1 = (rgb1 >> 8) & 0xff; |
| - b1 = rgb1 & 0xff; |
| - r1 += er * w/sum; |
| - g1 += eg * w/sum; |
| - b1 += eb * w/sum; |
| - inPixels[k] = (PixelUtils.clamp(r1) << 16) | (PixelUtils.clamp(g1) << 8) | PixelUtils.clamp(b1); |
| - } |
| - } |
| - } |
| - } |
| - } |
| - index += direction; |
| - } |
| - } |
| - } |
| - } |
| - |
| - protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) { |
| - int[] outPixels = new int[width*height]; |
| - |
| - quantize(inPixels, outPixels, width, height, numColors, dither, serpentine); |
| - |
| - return outPixels; |
| - } |
| - |
| - public String toString() { |
| - return "Colors/Quantize..."; |
| - } |
| - |
| -} |
| Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageReceiver.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageReceiver.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageReceiver.java (working copy) |
| @@ -1,150 +0,0 @@ |
| -package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
|
| -
|
| -import java.awt.*;
|
| -import java.awt.image.BufferedImage;
|
| -import java.io.ByteArrayInputStream;
|
| -import java.io.IOException;
|
| -import java.net.DatagramPacket;
|
| -import java.net.DatagramSocket;
|
| -import java.net.InetAddress;
|
| -import java.net.SocketException;
|
| -
|
| -/**
|
| - * UDP Image Receiver.
|
| - * It uses PNG Tiles into UDP packets.
|
| - *
|
| - * @author Thiago Rocha Camargo
|
| - */
|
| -public class ImageReceiver extends Canvas {
|
| -
|
| - private boolean on = true;
|
| - private DatagramSocket socket;
|
| - private BufferedImage tiles[][];
|
| - private static final int tileWidth = ImageTransmitter.tileWidth;
|
| - private InetAddress localHost;
|
| - private InetAddress remoteHost;
|
| - private int localPort;
|
| - private int remotePort;
|
| - private ImageDecoder decoder;
|
| -
|
| - public ImageReceiver(final InetAddress remoteHost, final int remotePort, final int localPort, int width, int height) {
|
| - tiles = new BufferedImage[width][height];
|
| -
|
| - try {
|
| -
|
| - socket = new DatagramSocket(localPort);
|
| - localHost = socket.getLocalAddress();
|
| - this.remoteHost = remoteHost;
|
| - this.remotePort = remotePort;
|
| - this.localPort = localPort;
|
| - this.decoder = new DefaultDecoder();
|
| -
|
| - new Thread(new Runnable() {
|
| - public void run() {
|
| - byte buf[] = new byte[1024];
|
| - DatagramPacket p = new DatagramPacket(buf, 1024);
|
| - try {
|
| - while (on) {
|
| - socket.receive(p);
|
| -
|
| - int length = p.getLength();
|
| -
|
| - BufferedImage bufferedImage = decoder.decode(new ByteArrayInputStream(p.getData(), 0, length - 2));
|
| -
|
| - if (bufferedImage != null) {
|
| -
|
| - int x = p.getData()[length - 2];
|
| - int y = p.getData()[length - 1];
|
| -
|
| - drawTile(x, y, bufferedImage);
|
| -
|
| - }
|
| -
|
| - }
|
| - }
|
| - catch (IOException e) {
|
| - e.printStackTrace();
|
| - }
|
| - }
|
| - }).start();
|
| -
|
| - new Thread(new Runnable() {
|
| - public void run() {
|
| - byte buf[] = new byte[1024];
|
| - DatagramPacket p = new DatagramPacket(buf, 1024);
|
| - try {
|
| - while (on) {
|
| -
|
| - p.setAddress(remoteHost);
|
| - p.setPort(remotePort);
|
| - socket.send(p);
|
| -
|
| - try {
|
| - Thread.sleep(1000);
|
| - }
|
| - catch (InterruptedException e) {
|
| - e.printStackTrace();
|
| - }
|
| -
|
| - }
|
| - }
|
| - catch (IOException e) {
|
| - e.printStackTrace();
|
| - }
|
| - }
|
| - }).start();
|
| -
|
| - }
|
| - catch (SocketException e) {
|
| - e.printStackTrace();
|
| - }
|
| - this.setSize(width, height);
|
| - }
|
| -
|
| - public InetAddress getLocalHost() {
|
| - return localHost;
|
| - }
|
| -
|
| - public InetAddress getRemoteHost() {
|
| - return remoteHost;
|
| - }
|
| -
|
| - public int getLocalPort() {
|
| - return localPort;
|
| - }
|
| -
|
| - public int getRemotePort() {
|
| - return remotePort;
|
| - }
|
| -
|
| - public DatagramSocket getDatagramSocket() {
|
| - return socket;
|
| - }
|
| -
|
| - public void drawTile(int x, int y, BufferedImage bufferedImage) {
|
| - tiles[x][y] = bufferedImage;
|
| - //repaint(x * tileWidth, y * tileWidth, tileWidth, tileWidth);
|
| - this.getGraphics().drawImage(bufferedImage, tileWidth * x, tileWidth * y, this);
|
| - }
|
| -
|
| - public void paint(Graphics g) {
|
| - for (int i = 0; i < tiles.length; i++) {
|
| - for (int j = 0; j < tiles[0].length; j++) {
|
| - g.drawImage(tiles[i][j], tileWidth * i, tileWidth * j, this);
|
| - }
|
| - }
|
| - }
|
| -
|
| - public ImageDecoder getDecoder() {
|
| - return decoder;
|
| - }
|
| -
|
| - public void setDecoder(ImageDecoder decoder) {
|
| - this.decoder = decoder;
|
| - }
|
| -
|
| - public void stop(){
|
| - this.on=false;
|
| - socket.close();
|
| - }
|
| -}
|
| Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/WholeImageFilter.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/WholeImageFilter.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/WholeImageFilter.java (working copy) |
| @@ -1,86 +0,0 @@ |
| -/* |
| -Copyright 2006 Jerry Huxtable |
| - |
| -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.smackx.jingle.mediaimpl.sshare.api; |
| - |
| -import java.awt.*; |
| -import java.awt.image.BufferedImage; |
| -import java.awt.image.ColorModel; |
| -import java.awt.image.WritableRaster; |
| - |
| -/** |
| - * A filter which acts as a superclass for filters which need to have the whole image in memory |
| - * to do their stuff. |
| - */ |
| -public abstract class WholeImageFilter extends AbstractBufferedImageOp { |
| - |
| - /** |
| - * The output image bounds. |
| - */ |
| - protected Rectangle transformedSpace; |
| - |
| - /** |
| - * The input image bounds. |
| - */ |
| - protected Rectangle originalSpace; |
| - |
| - /** |
| - * Construct a WholeImageFilter. |
| - */ |
| - public WholeImageFilter() { |
| - } |
| - |
| - public BufferedImage filter( BufferedImage src, BufferedImage dst ) { |
| - int width = src.getWidth(); |
| - int height = src.getHeight(); |
| - int type = src.getType(); |
| - WritableRaster srcRaster = src.getRaster(); |
| - |
| - originalSpace = new Rectangle(0, 0, width, height); |
| - transformedSpace = new Rectangle(0, 0, width, height); |
| - transformSpace(transformedSpace); |
| - |
| - if ( dst == null ) { |
| - ColorModel dstCM = src.getColorModel(); |
| - dst = new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(transformedSpace.width, transformedSpace.height), dstCM.isAlphaPremultiplied(), null); |
| - } |
| - WritableRaster dstRaster = dst.getRaster(); |
| - |
| - int[] inPixels = getRGB( src, 0, 0, width, height, null ); |
| - inPixels = filterPixels( width, height, inPixels, transformedSpace ); |
| - setRGB( dst, 0, 0, transformedSpace.width, transformedSpace.height, inPixels ); |
| - |
| - return dst; |
| - } |
| - |
| - /** |
| - * Calculate output bounds for given input bounds. |
| - * @param rect input and output rectangle |
| - */ |
| - protected void transformSpace(Rectangle rect) { |
| - } |
| - |
| - /** |
| - * Actually filter the pixels. |
| - * @param width the image width |
| - * @param height the image height |
| - * @param inPixels the image pixels |
| - * @param transformedSpace the output bounds |
| - * @return the output pixels |
| - */ |
| - protected abstract int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ); |
| -} |
| - |
| Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/AbstractBufferedImageOp.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/AbstractBufferedImageOp.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/AbstractBufferedImageOp.java (working copy) |
| @@ -1,98 +0,0 @@ |
| -/* |
| -Copyright 2006 Jerry Huxtable |
| - |
| -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.smackx.jingle.mediaimpl.sshare.api; |
| - |
| -import java.awt.*; |
| -import java.awt.geom.Point2D; |
| -import java.awt.geom.Rectangle2D; |
| -import java.awt.image.BufferedImage; |
| -import java.awt.image.BufferedImageOp; |
| -import java.awt.image.ColorModel; |
| - |
| -/** |
| - * A convenience class which implements those methods of BufferedImageOp which are rarely changed. |
| - */ |
| -public abstract class AbstractBufferedImageOp implements BufferedImageOp, Cloneable { |
| - |
| - public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) { |
| - if ( dstCM == null ) |
| - dstCM = src.getColorModel(); |
| - return new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()), dstCM.isAlphaPremultiplied(), null); |
| - } |
| - |
| - public Rectangle2D getBounds2D( BufferedImage src ) { |
| - return new Rectangle(0, 0, src.getWidth(), src.getHeight()); |
| - } |
| - |
| - public Point2D getPoint2D( Point2D srcPt, Point2D dstPt ) { |
| - if ( dstPt == null ) |
| - dstPt = new Point2D.Double(); |
| - dstPt.setLocation( srcPt.getX(), srcPt.getY() ); |
| - return dstPt; |
| - } |
| - |
| - public RenderingHints getRenderingHints() { |
| - return null; |
| - } |
| - |
| - /** |
| - * A convenience method for getting ARGB pixels from an image. This tries to avoid the performance |
| - * penalty of BufferedImage.getRGB unmanaging the image. |
| - * @param image a BufferedImage object |
| - * @param x the left edge of the pixel block |
| - * @param y the right edge of the pixel block |
| - * @param width the width of the pixel arry |
| - * @param height the height of the pixel arry |
| - * @param pixels the array to hold the returned pixels. May be null. |
| - * @return the pixels |
| - * @see #setRGB |
| - */ |
| - public int[] getRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) { |
| - int type = image.getType(); |
| - if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB ) |
| - return (int [])image.getRaster().getDataElements( x, y, width, height, pixels ); |
| - return image.getRGB( x, y, width, height, pixels, 0, width ); |
| - } |
| - |
| - /** |
| - * A convenience method for setting ARGB pixels in an image. This tries to avoid the performance |
| - * penalty of BufferedImage.setRGB unmanaging the image. |
| - * @param image a BufferedImage object |
| - * @param x the left edge of the pixel block |
| - * @param y the right edge of the pixel block |
| - * @param width the width of the pixel arry |
| - * @param height the height of the pixel arry |
| - * @param pixels the array of pixels to set |
| - * @see #getRGB |
| - */ |
| - public void setRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) { |
| - int type = image.getType(); |
| - if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB ) |
| - image.getRaster().setDataElements( x, y, width, height, pixels ); |
| - else |
| - image.setRGB( x, y, width, height, pixels, 0, width ); |
| - } |
| - |
| - public Object clone() { |
| - try { |
| - return super.clone(); |
| - } |
| - catch ( CloneNotSupportedException e ) { |
| - return null; |
| - } |
| - } |
| -} |
| Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageDecoder.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageDecoder.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageDecoder.java (working copy) |
| @@ -1,15 +0,0 @@ |
| -package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api; |
| - |
| -import java.awt.image.BufferedImage; |
| -import java.io.ByteArrayInputStream; |
| -import java.io.IOException; |
| - |
| -/** |
| - * Image Decoder Interface use this interface if you want to change the default decoder |
| - * |
| - * @author Thiago Rocha Camargo |
| - */ |
| -public interface ImageDecoder { |
| - |
| - public BufferedImage decode(ByteArrayInputStream stream) throws IOException; |
| -} |
| Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/OctTreeQuantizer.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/OctTreeQuantizer.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/OctTreeQuantizer.java (working copy) |
| @@ -1,287 +0,0 @@ |
| -/* |
| -Copyright 2006 Jerry Huxtable |
| - |
| -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.smackx.jingle.mediaimpl.sshare.api; |
| - |
| -import java.io.PrintStream; |
| -import java.util.Vector; |
| - |
| -import org.jivesoftware.smackx.jingle.SmackLogger; |
| - |
| -/** |
| - * An image Quantizer based on the Octree algorithm. This is a very basic implementation |
| - * at present and could be much improved by picking the nodes to reduce more carefully |
| - * (i.e. not completely at random) when I get the time. |
| - */ |
| -public class OctTreeQuantizer implements Quantizer { |
| - |
| - private static final SmackLogger LOGGER = SmackLogger.getLogger(OctTreeQuantizer.class); |
| - |
| - /** |
| - * The greatest depth the tree is allowed to reach |
| - */ |
| - final static int MAX_LEVEL = 5; |
| - |
| - /** |
| - * An Octtree node. |
| - */ |
| - class OctTreeNode { |
| - int children; |
| - int level; |
| - OctTreeNode parent; |
| - OctTreeNode leaf[] = new OctTreeNode[8]; |
| - boolean isLeaf; |
| - int count; |
| - int totalRed; |
| - int totalGreen; |
| - int totalBlue; |
| - int index; |
| - |
| - /** |
| - * A debugging method which prints the tree out. |
| - */ |
| - public void list(PrintStream s, int level) { |
| - String indentStr = ""; |
| - for (int i = 0; i < level; i++) |
| - indentStr += " "; |
| - if (count == 0) |
| - LOGGER.debug(indentStr + index + ": count=" + count); |
| - else |
| - LOGGER.debug(indentStr + index + ": count=" + count + " red=" + (totalRed/count) + " green=" + (totalGreen / count) + " blue=" + (totalBlue / count)); |
| - for (int i = 0; i < 8; i++) |
| - if (leaf[i] != null) |
| - leaf[i].list(s, level+2); |
| - } |
| - } |
| - |
| - private int nodes = 0; |
| - private OctTreeNode root; |
| - private int reduceColors; |
| - private int maximumColors; |
| - private int colors = 0; |
| - private Vector[] colorList; |
| - |
| - public OctTreeQuantizer() { |
| - setup(256); |
| - colorList = new Vector[MAX_LEVEL+1]; |
| - for (int i = 0; i < MAX_LEVEL+1; i++) |
| - colorList[i] = new Vector(); |
| - root = new OctTreeNode(); |
| - } |
| - |
| - /** |
| - * Initialize the quantizer. This should be called before adding any pixels. |
| - * @param numColors the number of colors we're quantizing to. |
| - */ |
| - public void setup(int numColors) { |
| - maximumColors = numColors; |
| - reduceColors = Math.max(512, numColors * 2); |
| - } |
| - |
| - /** |
| - * Add pixels to the quantizer. |
| - * @param pixels the array of ARGB pixels |
| - * @param offset the offset into the array |
| - * @param count the count of pixels |
| - */ |
| - public void addPixels(int[] pixels, int offset, int count) { |
| - for (int i = 0; i < count; i++) { |
| - insertColor(pixels[i+offset]); |
| - if (colors > reduceColors) |
| - reduceTree(reduceColors); |
| - } |
| - } |
| - |
| - /** |
| - * Get the color table index for a color. |
| - * @param rgb the color |
| - * @return the index |
| - */ |
| - public int getIndexForColor(int rgb) { |
| - int red = (rgb >> 16) & 0xff; |
| - int green = (rgb >> 8) & 0xff; |
| - int blue = rgb & 0xff; |
| - |
| - OctTreeNode node = root; |
| - |
| - for (int level = 0; level <= MAX_LEVEL; level++) { |
| - OctTreeNode child; |
| - int bit = 0x80 >> level; |
| - |
| - int index = 0; |
| - if ((red & bit) != 0) |
| - index += 4; |
| - if ((green & bit) != 0) |
| - index += 2; |
| - if ((blue & bit) != 0) |
| - index += 1; |
| - |
| - child = node.leaf[index]; |
| - |
| - if (child == null) |
| - return node.index; |
| - else if (child.isLeaf) |
| - return child.index; |
| - else |
| - node = child; |
| - } |
| - LOGGER.debug("getIndexForColor failed"); |
| - return 0; |
| - } |
| - |
| - private void insertColor(int rgb) { |
| - int red = (rgb >> 16) & 0xff; |
| - int green = (rgb >> 8) & 0xff; |
| - int blue = rgb & 0xff; |
| - |
| - OctTreeNode node = root; |
| - |
| -// LOGGER.debug("insertColor="+Integer.toHexString(rgb)); |
| - for (int level = 0; level <= MAX_LEVEL; level++) { |
| - OctTreeNode child; |
| - int bit = 0x80 >> level; |
| - |
| - int index = 0; |
| - if ((red & bit) != 0) |
| - index += 4; |
| - if ((green & bit) != 0) |
| - index += 2; |
| - if ((blue & bit) != 0) |
| - index += 1; |
| - |
| - child = node.leaf[index]; |
| - |
| - if (child == null) { |
| - node.children++; |
| - |
| - child = new OctTreeNode(); |
| - child.parent = node; |
| - node.leaf[index] = child; |
| - node.isLeaf = false; |
| - nodes++; |
| - colorList[level].addElement(child); |
| - |
| - if (level == MAX_LEVEL) { |
| - child.isLeaf = true; |
| - child.count = 1; |
| - child.totalRed = red; |
| - child.totalGreen = green; |
| - child.totalBlue = blue; |
| - child.level = level; |
| - colors++; |
| - return; |
| - } |
| - |
| - node = child; |
| - } else if (child.isLeaf) { |
| - child.count++; |
| - child.totalRed += red; |
| - child.totalGreen += green; |
| - child.totalBlue += blue; |
| - return; |
| - } else |
| - node = child; |
| - } |
| - LOGGER.debug("insertColor failed"); |
| - } |
| - |
| - private void reduceTree(int numColors) { |
| - for (int level = MAX_LEVEL-1; level >= 0; level--) { |
| - Vector v = colorList[level]; |
| - if (v != null && v.size() > 0) { |
| - for (int j = 0; j < v.size(); j++) { |
| - OctTreeNode node = (OctTreeNode)v.elementAt(j); |
| - if (node.children > 0) { |
| - for (int i = 0; i < 8; i++) { |
| - OctTreeNode child = node.leaf[i]; |
| - if (child != null) { |
| - if (!child.isLeaf) |
| - LOGGER.debug("not a leaf!"); |
| - node.count += child.count; |
| - node.totalRed += child.totalRed; |
| - node.totalGreen += child.totalGreen; |
| - node.totalBlue += child.totalBlue; |
| - node.leaf[i] = null; |
| - node.children--; |
| - colors--; |
| - nodes--; |
| - colorList[level+1].removeElement(child); |
| - } |
| - } |
| - node.isLeaf = true; |
| - colors++; |
| - if (colors <= numColors) |
| - return; |
| - } |
| - } |
| - } |
| - } |
| - |
| - LOGGER.debug("Unable to reduce the OctTree"); |
| - } |
| - |
| - /** |
| - * Build the color table. |
| - * @return the color table |
| - */ |
| - public int[] buildColorTable() { |
| - int[] table = new int[colors]; |
| - buildColorTable(root, table, 0); |
| - return table; |
| - } |
| - |
| - /** |
| - * A quick way to use the quantizer. Just create a table the right size and pass in the pixels. |
| - * @param inPixels the input colors |
| - * @param table the output color table |
| - */ |
| - public void buildColorTable(int[] inPixels, int[] table) { |
| - int count = inPixels.length; |
| - maximumColors = table.length; |
| - for (int i = 0; i < count; i++) { |
| - insertColor(inPixels[i]); |
| - if (colors > reduceColors) |
| - reduceTree(reduceColors); |
| - } |
| - if (colors > maximumColors) |
| - reduceTree(maximumColors); |
| - buildColorTable(root, table, 0); |
| - } |
| - |
| - private int buildColorTable(OctTreeNode node, int[] table, int index) { |
| - if (colors > maximumColors) |
| - reduceTree(maximumColors); |
| - |
| - if (node.isLeaf) { |
| - int count = node.count; |
| - table[index] = 0xff000000 | |
| - ((node.totalRed/count) << 16) | |
| - ((node.totalGreen/count) << 8) | |
| - node.totalBlue/count; |
| - node.index = index++; |
| - } else { |
| - for (int i = 0; i < 8; i++) { |
| - if (node.leaf[i] != null) { |
| - node.index = index; |
| - index = buildColorTable(node.leaf[i], table, index); |
| - } |
| - } |
| - } |
| - return index; |
| - } |
| - |
| -} |
| - |
| Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultDecoder.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultDecoder.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultDecoder.java (working copy) |
| @@ -1,16 +0,0 @@ |
| -package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api; |
| - |
| -import javax.imageio.ImageIO; |
| -import java.awt.image.BufferedImage; |
| -import java.io.ByteArrayInputStream; |
| -import java.io.IOException; |
| - |
| -/** |
| - * Implements a default PNG decoder. |
| - */ |
| -public class DefaultDecoder implements ImageDecoder { |
| - |
| - public BufferedImage decode(ByteArrayInputStream stream) throws IOException { |
| - return ImageIO.read(stream); |
| - } |
| -} |
| Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareMediaManager.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareMediaManager.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareMediaManager.java (working copy) |
| @@ -1,115 +0,0 @@ |
| -/** |
| - * $RCSfile: ScreenShareMediaManager.java,v $ |
| - * $Revision: 1.3 $ |
| - * $Date: 25/12/2006 |
| - * <p/> |
| - * Copyright 2003-2006 Jive Software. |
| - * <p/> |
| - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); |
| - * you may not use this file except in compliance with the License. |
| - * You may obtain a copy of the License at |
| - * <p/> |
| - * http://www.apache.org/licenses/LICENSE-2.0 |
| - * <p/> |
| - * Unless required by applicable law or agreed to in writing, software |
| - * distributed under the License is distributed on an "AS IS" BASIS, |
| - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| - * See the License for the specific language governing permissions and |
| - * limitations under the License. |
| - */ |
| - |
| -package org.jivesoftware.smackx.jingle.mediaimpl.sshare; |
| - |
| -import org.jivesoftware.smackx.jingle.JingleSession; |
| -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.mediaimpl.sshare.api.ImageDecoder; |
| -import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageEncoder; |
| -import org.jivesoftware.smackx.jingle.nat.JingleTransportManager; |
| -import org.jivesoftware.smackx.jingle.nat.TransportCandidate; |
| - |
| -import java.util.ArrayList; |
| -import java.util.List; |
| - |
| -/** |
| - * Implements a JingleMediaManager for ScreenSharing. |
| - * It currently uses an Audio payload Type. Which needs to be fixed in the next version. |
| - * |
| - * @author Thiago Camargo |
| - */ |
| - |
| -public class ScreenShareMediaManager extends JingleMediaManager { |
| - |
| - public static final String MEDIA_NAME = "ScreenShare"; |
| - |
| - private List<PayloadType> payloads = new ArrayList<PayloadType>(); |
| - |
| - private ImageDecoder decoder = null; |
| - private ImageEncoder encoder = null; |
| - |
| - public ScreenShareMediaManager(JingleTransportManager transportManager) { |
| - super(transportManager); |
| - setupPayloads(); |
| - } |
| - |
| - /** |
| - * Setup API supported Payloads |
| - */ |
| - private void setupPayloads() { |
| - payloads.add(new PayloadType.Audio(30, "sshare")); |
| - } |
| - |
| - /** |
| - * Return all supported Payloads for this Manager. |
| - * |
| - * @return The Payload List |
| - */ |
| - public List<PayloadType> getPayloads() { |
| - return payloads; |
| - } |
| - |
| - /** |
| - * Returns a new JingleMediaSession |
| - * |
| - * @param payloadType payloadType |
| - * @param remote remote Candidate |
| - * @param local local Candidate |
| - * @return JingleMediaSession JingleMediaSession |
| - */ |
| - public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) { |
| - ScreenShareSession session = null; |
| - session = new ScreenShareSession(payloadType, remote, local, "Screen", jingleSession); |
| - if (encoder != null) { |
| - session.setEncoder(encoder); |
| - } |
| - if (decoder != null) { |
| - session.setDecoder(decoder); |
| - } |
| - return session; |
| - } |
| - |
| - public PayloadType getPreferredPayloadType() { |
| - return super.getPreferredPayloadType(); |
| - } |
| - |
| - public ImageDecoder getDecoder() { |
| - return decoder; |
| - } |
| - |
| - public void setDecoder(ImageDecoder decoder) { |
| - this.decoder = decoder; |
| - } |
| - |
| - public ImageEncoder getEncoder() { |
| - return encoder; |
| - } |
| - |
| - public void setEncoder(ImageEncoder encoder) { |
| - this.encoder = encoder; |
| - } |
| - |
| - public String getName() { |
| - return MEDIA_NAME; |
| - } |
| -} |
| Index: org/jivesoftware/smackx/jingle/mediaimpl/multi/MultiMediaManager.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/multi/MultiMediaManager.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/multi/MultiMediaManager.java (working copy) |
| @@ -1,106 +0,0 @@ |
| -/** |
| - * $RCSfile: MultiMediaManager.java,v $ |
| - * $Revision: 1.3 $ |
| - * $Date: 25/12/2006 |
| - * <p/> |
| - * Copyright 2003-2006 Jive Software. |
| - * <p/> |
| - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); |
| - * you may not use this file except in compliance with the License. |
| - * You may obtain a copy of the License at |
| - * <p/> |
| - * http://www.apache.org/licenses/LICENSE-2.0 |
| - * <p/> |
| - * Unless required by applicable law or agreed to in writing, software |
| - * distributed under the License is distributed on an "AS IS" BASIS, |
| - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| - * See the License for the specific language governing permissions and |
| - * limitations under the License. |
| - */ |
| - |
| -package org.jivesoftware.smackx.jingle.mediaimpl.multi; |
| - |
| -import org.jivesoftware.smackx.jingle.JingleSession; |
| -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.JingleTransportManager; |
| -import org.jivesoftware.smackx.jingle.nat.TransportCandidate; |
| - |
| -import java.util.ArrayList; |
| -import java.util.List; |
| - |
| -/** |
| - * Implements a MultiMediaManager using other JingleMediaManager implementations. |
| - * It supports every Codecs that JingleMediaManagers added has. |
| - * |
| - * @author Thiago Camargo |
| - */ |
| - |
| -public class MultiMediaManager extends JingleMediaManager { |
| - |
| - public static final String MEDIA_NAME = "Multi"; |
| - |
| - private List<JingleMediaManager> managers = new ArrayList<JingleMediaManager>(); |
| - |
| - private PayloadType preferredPayloadType = null; |
| - |
| - public MultiMediaManager(JingleTransportManager transportManager) { |
| - super(transportManager); |
| - } |
| - |
| - public void addMediaManager(JingleMediaManager manager) { |
| - managers.add(manager); |
| - } |
| - |
| - public void removeMediaManager(JingleMediaManager manager) { |
| - managers.remove(manager); |
| - } |
| - |
| - /** |
| - * Return all supported Payloads for this Manager. |
| - * |
| - * @return The Payload List |
| - */ |
| - public List<PayloadType> getPayloads() { |
| - List<PayloadType> list = new ArrayList<PayloadType>(); |
| - if (preferredPayloadType != null) list.add(preferredPayloadType); |
| - for (JingleMediaManager manager : managers) { |
| - for (PayloadType payloadType : manager.getPayloads()) { |
| - if (!list.contains(payloadType) && !payloadType.equals(preferredPayloadType)) |
| - list.add(payloadType); |
| - } |
| - } |
| - return list; |
| - } |
| - |
| - /** |
| - * Returns a new JingleMediaSession |
| - * |
| - * @param payloadType payloadType |
| - * @param remote remote Candidate |
| - * @param local local Candidate |
| - * @return JingleMediaSession JingleMediaSession |
| - */ |
| - public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) { |
| - for (JingleMediaManager manager : managers) { |
| - if (manager.getPayloads().contains(payloadType)) { |
| - return manager.createMediaSession(payloadType, remote, local, jingleSession); |
| - } |
| - } |
| - return null; |
| - } |
| - |
| - public PayloadType getPreferredPayloadType() { |
| - if (preferredPayloadType != null) return preferredPayloadType; |
| - return super.getPreferredPayloadType(); |
| - } |
| - |
| - public void setPreferredPayloadType(PayloadType preferredPayloadType) { |
| - this.preferredPayloadType = preferredPayloadType; |
| - } |
| - |
| - public String getName() { |
| - return MEDIA_NAME; |
| - } |
| -} |
| Index: org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioMediaSession.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioMediaSession.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioMediaSession.java (working copy) |
| @@ -1,165 +0,0 @@ |
| -/**
|
| - * $RCSfile: AudioMediaSession.java,v $
|
| - * $Revision: 1.1 $
|
| - * $Date: 08/11/2006
|
| - * <p/>
|
| - * Copyright 2003-2006 Jive Software.
|
| - * <p/>
|
| - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
| - * you may not use this file except in compliance with the License.
|
| - * You may obtain a copy of the License at
|
| - * <p/>
|
| - * http://www.apache.org/licenses/LICENSE-2.0
|
| - * <p/>
|
| - * Unless required by applicable law or agreed to in writing, software
|
| - * distributed under the License is distributed on an "AS IS" BASIS,
|
| - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| - * See the License for the specific language governing permissions and
|
| - * limitations under the License.
|
| - */
|
| -
|
| -package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
|
| -
|
| -import java.io.IOException;
|
| -import java.net.ServerSocket;
|
| -
|
| -import javax.media.MediaLocator;
|
| -
|
| -import org.jivesoftware.smackx.jingle.JingleSession;
|
| -import org.jivesoftware.smackx.jingle.SmackLogger;
|
| -import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
|
| -import org.jivesoftware.smackx.jingle.media.PayloadType;
|
| -import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
| -
|
| -/**
|
| - * This Class implements a complete JingleMediaSession.
|
| - * It sould be used to transmit and receive audio captured from the Mic.
|
| - * This Class should be automaticly controlled by JingleSession.
|
| - * But you could also use in any VOIP application.
|
| - * For better NAT Traversal support this implementation don't support only receive or only transmit.
|
| - * To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit()
|
| - *
|
| - * @author Thiago Camargo
|
| - */
|
| -public class AudioMediaSession extends JingleMediaSession {
|
| -
|
| - private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioMediaSession.class);
|
| -
|
| - 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
|
| - * @param locator media locator
|
| - */
|
| - public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote,
|
| - final TransportCandidate local, String locator, JingleSession jingleSession) {
|
| - super(payloadType, remote, local, locator==null?"dsound://":locator,jingleSession);
|
| - initialize();
|
| - }
|
| -
|
| - /**
|
| - * Initialize the Audio Channel to make it able to send and receive audio
|
| - */
|
| - public void initialize() {
|
| -
|
| - String ip;
|
| - String localIp;
|
| - int localPort;
|
| - int remotePort;
|
| -
|
| - if (this.getLocal().getSymmetric() != null) {
|
| - ip = this.getLocal().getIp();
|
| - localIp = this.getLocal().getLocalIp();
|
| - localPort = getFreePort();
|
| - remotePort = this.getLocal().getSymmetric().getPort();
|
| -
|
| - LOGGER.debug(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(this.getMediaLocator()), localIp, ip, localPort, remotePort, AudioFormatUtils.getAudioFormat(this.getPayloadType()),this);
|
| - }
|
| -
|
| - /**
|
| - * 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 active state
|
| - */
|
| - public void setTrasmit(boolean active) {
|
| - audioChannel.setTrasmit(active);
|
| - }
|
| -
|
| - /**
|
| - * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
|
| - */
|
| - public void startReceive() {
|
| - // Do nothing
|
| - }
|
| -
|
| - /**
|
| - * Stops transmission and for NAT Traversal reasons stop receiving also.
|
| - */
|
| - public void stopTrasmit() {
|
| - if (audioChannel != null)
|
| - audioChannel.stop();
|
| - }
|
| -
|
| - /**
|
| - * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
|
| - */
|
| - public void stopReceive() {
|
| - // Do nothing
|
| - }
|
| -
|
| - /**
|
| - * Obtain a free port we can use.
|
| - *
|
| - * @return A free port number.
|
| - */
|
| - protected int getFreePort() {
|
| - ServerSocket ss;
|
| - int freePort = 0;
|
| -
|
| - for (int i = 0; i < 10; i++) {
|
| - freePort = (int) (10000 + Math.round(Math.random() * 10000));
|
| - freePort = freePort % 2 == 0 ? freePort : freePort + 1;
|
| - try {
|
| - ss = new ServerSocket(freePort);
|
| - freePort = ss.getLocalPort();
|
| - ss.close();
|
| - return freePort;
|
| - }
|
| - catch (IOException e) {
|
| - e.printStackTrace();
|
| - }
|
| - }
|
| - try {
|
| - ss = new ServerSocket(0);
|
| - freePort = ss.getLocalPort();
|
| - ss.close();
|
| - }
|
| - catch (IOException e) {
|
| - e.printStackTrace();
|
| - }
|
| - return freePort;
|
| - }
|
| -
|
| -}
|
| Index: org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioReceiver.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioReceiver.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioReceiver.java (working copy) |
| @@ -1,171 +0,0 @@ |
| -/**
|
| - * $RCSfile: AudioReceiver.java,v $
|
| - * $Revision: 1.1 $
|
| - * $Date: 08/11/2006
|
| - * <p/>
|
| - * Copyright 2003-2006 Jive Software.
|
| - * <p/>
|
| - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
| - * you may not use this file except in compliance with the License.
|
| - * You may obtain a copy of the License at
|
| - * <p/>
|
| - * http://www.apache.org/licenses/LICENSE-2.0
|
| - * <p/>
|
| - * Unless required by applicable law or agreed to in writing, software
|
| - * distributed under the License is distributed on an "AS IS" BASIS,
|
| - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| - * See the License for the specific language governing permissions and
|
| - * limitations under the License.
|
| - */
|
| -
|
| -package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
|
| -
|
| -import javax.media.ControllerErrorEvent;
|
| -import javax.media.ControllerEvent;
|
| -import javax.media.ControllerListener;
|
| -import javax.media.Player;
|
| -import javax.media.RealizeCompleteEvent;
|
| -import javax.media.protocol.DataSource;
|
| -import javax.media.rtp.Participant;
|
| -import javax.media.rtp.RTPControl;
|
| -import javax.media.rtp.ReceiveStream;
|
| -import javax.media.rtp.ReceiveStreamListener;
|
| -import javax.media.rtp.SessionListener;
|
| -import javax.media.rtp.event.ByeEvent;
|
| -import javax.media.rtp.event.NewParticipantEvent;
|
| -import javax.media.rtp.event.NewReceiveStreamEvent;
|
| -import javax.media.rtp.event.ReceiveStreamEvent;
|
| -import javax.media.rtp.event.RemotePayloadChangeEvent;
|
| -import javax.media.rtp.event.SessionEvent;
|
| -import javax.media.rtp.event.StreamMappedEvent;
|
| -
|
| -import org.jivesoftware.smackx.jingle.SmackLogger;
|
| -import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
|
| -
|
| -/**
|
| - * This class implements receive methods and listeners to be used in AudioChannel
|
| - *
|
| - * @author Thiago Camargo
|
| - */
|
| -public class AudioReceiver implements ReceiveStreamListener, SessionListener,
|
| - ControllerListener {
|
| -
|
| - private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioReceiver.class);
|
| -
|
| - boolean dataReceived = false;
|
| -
|
| - Object dataSync;
|
| - JingleMediaSession jingleMediaSession;
|
| -
|
| - public AudioReceiver(final Object dataSync, final JingleMediaSession jingleMediaSession) {
|
| - this.dataSync = dataSync;
|
| - this.jingleMediaSession = jingleMediaSession;
|
| - }
|
| -
|
| - /**
|
| - * JingleSessionListener.
|
| - */
|
| - public synchronized void update(SessionEvent evt) {
|
| - if (evt instanceof NewParticipantEvent) {
|
| - Participant p = ((NewParticipantEvent) evt).getParticipant();
|
| - LOGGER.error(" - A new participant had just joined: " + p.getCNAME());
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * ReceiveStreamListener
|
| - */
|
| - public synchronized void update(ReceiveStreamEvent evt) {
|
| -
|
| - Participant participant = evt.getParticipant(); // could be null.
|
| - ReceiveStream stream = evt.getReceiveStream(); // could be null.
|
| -
|
| - if (evt instanceof RemotePayloadChangeEvent) {
|
| - LOGGER.error(" - Received an RTP PayloadChangeEvent.");
|
| - LOGGER.error("Sorry, cannot handle payload change.");
|
| -
|
| - }
|
| - else if (evt instanceof NewReceiveStreamEvent) {
|
| -
|
| - try {
|
| - stream = evt.getReceiveStream();
|
| - DataSource ds = stream.getDataSource();
|
| -
|
| - // Find out the formats.
|
| - RTPControl ctl = (RTPControl) ds.getControl("javax.jmf.rtp.RTPControl");
|
| - if (ctl != null) {
|
| - LOGGER.error(" - Recevied new RTP stream: " + ctl.getFormat());
|
| - }
|
| - else
|
| - LOGGER.error(" - Recevied new RTP stream");
|
| -
|
| - if (participant == null)
|
| - LOGGER.error(" The sender of this stream had yet to be identified.");
|
| - else {
|
| - LOGGER.error(" 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();
|
| - jingleMediaSession.mediaReceived(participant != null ? participant.getCNAME() : "");
|
| -
|
| - // Notify intialize() that a new stream had arrived.
|
| - synchronized (dataSync) {
|
| - dataReceived = true;
|
| - dataSync.notifyAll();
|
| - }
|
| -
|
| - }
|
| - catch (Exception e) {
|
| - LOGGER.error("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");
|
| - LOGGER.error(" - The previously unidentified stream ");
|
| - if (ctl != null)
|
| - LOGGER.error(" " + ctl.getFormat());
|
| - LOGGER.error(" had now been identified as sent by: " + participant.getCNAME());
|
| - }
|
| - }
|
| - else if (evt instanceof ByeEvent) {
|
| -
|
| - LOGGER.error(" - 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);
|
| - LOGGER.error("Receiver internal error: " + ce);
|
| - }
|
| -
|
| - }
|
| -}
|
| Index: org/jivesoftware/smackx/jingle/mediaimpl/jmf/JmfMediaManager.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/jmf/JmfMediaManager.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/jmf/JmfMediaManager.java (working copy) |
| @@ -1,170 +0,0 @@ |
| -/**
|
| - * $RCSfile: JmfMediaManager.java,v $
|
| - * $Revision: 1.3 $
|
| - * $Date: 08/11/2006
|
| - * <p/>
|
| - * Copyright 2003-2006 Jive Software.
|
| - * <p/>
|
| - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
| - * you may not use this file except in compliance with the License.
|
| - * You may obtain a copy of the License at
|
| - * <p/>
|
| - * http://www.apache.org/licenses/LICENSE-2.0
|
| - * <p/>
|
| - * Unless required by applicable law or agreed to in writing, software
|
| - * distributed under the License is distributed on an "AS IS" BASIS,
|
| - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| - * See the License for the specific language governing permissions and
|
| - * limitations under the License.
|
| - */
|
| -
|
| -package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
|
| -
|
| -import java.io.File;
|
| -import java.io.IOException;
|
| -import java.util.ArrayList;
|
| -import java.util.List;
|
| -
|
| -import org.jivesoftware.smackx.jingle.JingleSession;
|
| -import org.jivesoftware.smackx.jingle.SmackLogger;
|
| -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.mediaimpl.JMFInit;
|
| -import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
|
| -import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
| -
|
| -/**
|
| - * Implements a jingleMediaManager using JMF based API.
|
| - * It supports GSM and G723 codecs.
|
| - * <i>This API only currently works on windows and Mac.</i>
|
| - *
|
| - * @author Thiago Camargo
|
| - */
|
| -public class JmfMediaManager extends JingleMediaManager {
|
| -
|
| - private static final SmackLogger LOGGER = SmackLogger.getLogger(JmfMediaManager.class);
|
| -
|
| - public static final String MEDIA_NAME = "JMF";
|
| -
|
| -
|
| - private List<PayloadType> payloads = new ArrayList<PayloadType>();
|
| - private String mediaLocator = null;
|
| -
|
| - /**
|
| - * Creates a Media Manager instance
|
| - */
|
| - public JmfMediaManager(JingleTransportManager transportManager) {
|
| - super(transportManager);
|
| - setupPayloads();
|
| - }
|
| -
|
| - /**
|
| - * Creates a Media Manager instance
|
| - *
|
| - * @param mediaLocator Media Locator
|
| - */
|
| - public JmfMediaManager(String mediaLocator, JingleTransportManager transportManager) {
|
| - super(transportManager);
|
| - this.mediaLocator = mediaLocator;
|
| - setupPayloads();
|
| - }
|
| -
|
| - /**
|
| - * Returns a new jingleMediaSession
|
| - *
|
| - * @param payloadType payloadType
|
| - * @param remote remote Candidate
|
| - * @param local local Candidate
|
| - * @return JingleMediaSession
|
| - */
|
| - public JingleMediaSession createMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
|
| - return new AudioMediaSession(payloadType, remote, local, mediaLocator, jingleSession);
|
| - }
|
| -
|
| - /**
|
| - * Setup API supported Payloads
|
| - */
|
| - private void setupPayloads() {
|
| - payloads.add(new PayloadType.Audio(3, "gsm"));
|
| - payloads.add(new PayloadType.Audio(4, "g723"));
|
| - payloads.add(new PayloadType.Audio(0, "PCMU", 16000));
|
| - }
|
| -
|
| - /**
|
| - * Return all supported Payloads for this Manager
|
| - *
|
| - * @return The Payload List
|
| - */
|
| - public List<PayloadType> getPayloads() {
|
| - return payloads;
|
| - }
|
| -
|
| - /**
|
| - * Return the media locator or null if not defined
|
| - *
|
| - * @return media locator
|
| - */
|
| - public String getMediaLocator() {
|
| - return mediaLocator;
|
| - }
|
| -
|
| - /**
|
| - * Set the media locator
|
| - *
|
| - * @param mediaLocator media locator or null to use default
|
| - */
|
| - public void setMediaLocator(String mediaLocator) {
|
| - this.mediaLocator = mediaLocator;
|
| - }
|
| -
|
| - /**
|
| - * Runs JMFInit the first time the application is started so that capture
|
| - * devices are properly detected and initialized by JMF.
|
| - */
|
| - public static void setupJMF() {
|
| - // .jmf is the place where we store the jmf.properties file used
|
| - // by JMF. if the directory does not exist or it does not contain
|
| - // a jmf.properties file. or if the jmf.properties file has 0 length
|
| - // then this is the first time we're running and should continue to
|
| - // with JMFInit
|
| - String homeDir = System.getProperty("user.home");
|
| - File jmfDir = new File(homeDir, ".jmf");
|
| - String classpath = System.getProperty("java.class.path");
|
| - classpath += System.getProperty("path.separator")
|
| - + jmfDir.getAbsolutePath();
|
| - System.setProperty("java.class.path", classpath);
|
| -
|
| - if (!jmfDir.exists())
|
| - jmfDir.mkdir();
|
| -
|
| - File jmfProperties = new File(jmfDir, "jmf.properties");
|
| -
|
| - if (!jmfProperties.exists()) {
|
| - try {
|
| - jmfProperties.createNewFile();
|
| - }
|
| - catch (IOException ex) {
|
| - LOGGER.debug("Failed to create jmf.properties");
|
| - ex.printStackTrace();
|
| - }
|
| - }
|
| -
|
| - // if we're running on linux checkout that libjmutil.so is where it
|
| - // should be and put it there.
|
| - runLinuxPreInstall();
|
| -
|
| - //if (jmfProperties.length() == 0) {
|
| - new JMFInit(null, false);
|
| - //}
|
| -
|
| - }
|
| -
|
| - private static void runLinuxPreInstall() {
|
| - // @TODO Implement Linux Pre-Install
|
| - }
|
| -
|
| - public String getName() {
|
| - return MEDIA_NAME;
|
| - }
|
| -}
|
| Index: org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioChannel.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioChannel.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioChannel.java (working copy) |
| @@ -1,553 +0,0 @@ |
| -/**
|
| - * $RCSfile: AudioChannel.java,v $
|
| - * $Revision: 1.1 $
|
| - * $Date: 08/11/2006
|
| - * <p/>
|
| - * Copyright 2003-2006 Jive Software.
|
| - * <p/>
|
| - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
| - * you may not use this file except in compliance with the License.
|
| - * You may obtain a copy of the License at
|
| - * <p/>
|
| - * http://www.apache.org/licenses/LICENSE-2.0
|
| - * <p/>
|
| - * Unless required by applicable law or agreed to in writing, software
|
| - * distributed under the License is distributed on an "AS IS" BASIS,
|
| - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| - * See the License for the specific language governing permissions and
|
| - * limitations under the License.
|
| - */
|
| -package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
|
| -
|
| -import java.io.IOException;
|
| -import java.net.InetAddress;
|
| -import java.net.UnknownHostException;
|
| -import java.util.ArrayList;
|
| -import java.util.List;
|
| -
|
| -import javax.media.Codec;
|
| -import javax.media.Controller;
|
| -import javax.media.ControllerClosedEvent;
|
| -import javax.media.ControllerEvent;
|
| -import javax.media.ControllerListener;
|
| -import javax.media.Format;
|
| -import javax.media.MediaLocator;
|
| -import javax.media.NoProcessorException;
|
| -import javax.media.Processor;
|
| -import javax.media.UnsupportedPlugInException;
|
| -import javax.media.control.BufferControl;
|
| -import javax.media.control.PacketSizeControl;
|
| -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.InvalidSessionAddressException;
|
| -import javax.media.rtp.RTPManager;
|
| -import javax.media.rtp.SendStream;
|
| -import javax.media.rtp.SessionAddress;
|
| -
|
| -import org.jivesoftware.smackx.jingle.SmackLogger;
|
| -import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
|
| -
|
| -/**
|
| - * An Easy to use Audio Channel implemented using JMF.
|
| - * It sends and receives jmf for and from desired IPs and ports.
|
| - * Also has a rport Symetric behavior for better NAT Traversal.
|
| - * It send data from a defined port and receive data in the same port, making NAT binds easier.
|
| - * <p/>
|
| - * Send from portA to portB and receive from portB in portA.
|
| - * <p/>
|
| - * Sending
|
| - * portA ---> portB
|
| - * <p/>
|
| - * Receiving
|
| - * portB ---> portA
|
| - * <p/>
|
| - * <i>Transmit and Receive are interdependents. To receive you MUST trasmit. </i>
|
| - *
|
| - * @author Thiago Camargo
|
| - */
|
| -public class AudioChannel {
|
| -
|
| - private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioChannel.class);
|
| -
|
| - private MediaLocator locator;
|
| - private String localIpAddress;
|
| - private String remoteIpAddress;
|
| - private int localPort;
|
| - private int portBase;
|
| - private Format format;
|
| -
|
| - private Processor processor = null;
|
| - private RTPManager rtpMgrs[];
|
| - private DataSource dataOutput = null;
|
| - private AudioReceiver audioReceiver;
|
| -
|
| - private List<SendStream> sendStreams = new ArrayList<SendStream>();
|
| -
|
| - private JingleMediaSession jingleMediaSession;
|
| -
|
| - private boolean started = false;
|
| -
|
| - /**
|
| - * Creates an Audio Channel for a desired jmf locator. For instance: new MediaLocator("dsound://")
|
| - *
|
| - * @param locator media locator
|
| - * @param localIpAddress local IP address
|
| - * @param remoteIpAddress remote IP address
|
| - * @param localPort local port number
|
| - * @param remotePort remote port number
|
| - * @param format audio format
|
| - */
|
| - public AudioChannel(MediaLocator locator,
|
| - String localIpAddress,
|
| - String remoteIpAddress,
|
| - int localPort,
|
| - int remotePort,
|
| - Format format, JingleMediaSession jingleMediaSession) {
|
| -
|
| - this.locator = locator;
|
| - this.localIpAddress = localIpAddress;
|
| - this.remoteIpAddress = remoteIpAddress;
|
| - this.localPort = localPort;
|
| - this.portBase = remotePort;
|
| - this.format = format;
|
| - this.jingleMediaSession = jingleMediaSession;
|
| - }
|
| -
|
| - /**
|
| - * Starts the transmission. Returns null if transmission started ok.
|
| - * Otherwise it returns a string with the reason why the setup failed.
|
| - * Starts receive also.
|
| - *
|
| - * @return result description
|
| - */
|
| - public synchronized String start() {
|
| - if (started) return null;
|
| -
|
| - // Create a processor for the specified jmf locator
|
| - String result = createProcessor();
|
| - if (result != null) {
|
| - started = false;
|
| - }
|
| -
|
| - // 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;
|
| - }
|
| - else {
|
| - started = true;
|
| - }
|
| -
|
| - // 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 (RTPManager rtpMgr : rtpMgrs) {
|
| - rtpMgr.removeReceiveStreamListener(audioReceiver);
|
| - rtpMgr.removeSessionListener(audioReceiver);
|
| - rtpMgr.removeTargets("Session ended.");
|
| - rtpMgr.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) {
|
| - // Try JavaSound Locator as a last resort
|
| - try {
|
| - ds = javax.media.Manager.createDataSource(new MediaLocator("javasound://"));
|
| - }
|
| - catch (Exception ee) {
|
| - 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){
|
| - 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);
|
| - LOGGER.error("Track " + i + " is set to transmit as:");
|
| - LOGGER.error(" " + chosen);
|
| -
|
| - if (tracks[i].getFormat() instanceof AudioFormat) {
|
| - int packetRate = 20;
|
| - PacketSizeControl pktCtrl = (PacketSizeControl) processor.getControl(PacketSizeControl.class.getName());
|
| - if (pktCtrl != null) {
|
| - try {
|
| - pktCtrl.setPacketSize(getPacketSize(tracks[i].getFormat(), packetRate));
|
| - }
|
| - catch (IllegalArgumentException e) {
|
| - pktCtrl.setPacketSize(80);
|
| - // Do nothing
|
| - }
|
| - }
|
| -
|
| - if (tracks[i].getFormat().getEncoding().equals(AudioFormat.ULAW_RTP)) {
|
| - Codec codec[] = new Codec[3];
|
| -
|
| - codec[0] = new com.ibm.media.codec.audio.rc.RCModule();
|
| - codec[1] = new com.ibm.media.codec.audio.ulaw.JavaEncoder();
|
| - codec[2] = new com.sun.media.codec.audio.ulaw.Packetizer();
|
| - ((com.sun.media.codec.audio.ulaw.Packetizer) codec
|
| - [2]).setPacketSize(160);
|
| -
|
| - try {
|
| - tracks[i].setCodecChain(codec);
|
| - }
|
| - catch (UnsupportedPlugInException e) {
|
| - e.printStackTrace();
|
| - }
|
| - }
|
| -
|
| - }
|
| -
|
| - 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)
|
| - return "Couldn't realize processor";
|
| -
|
| - // Get the output data source of the processor
|
| - dataOutput = processor.getDataOutput();
|
| -
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * Get the best packet size for a given codec and a codec rate
|
| - *
|
| - * @param codecFormat
|
| - * @param milliseconds
|
| - * @return
|
| - * @throws IllegalArgumentException
|
| - */
|
| - private int getPacketSize(Format codecFormat, int milliseconds) throws IllegalArgumentException {
|
| - String encoding = codecFormat.getEncoding();
|
| - if (encoding.equalsIgnoreCase(AudioFormat.GSM) ||
|
| - encoding.equalsIgnoreCase(AudioFormat.GSM_RTP)) {
|
| - return milliseconds * 4; // 1 byte per millisec
|
| - }
|
| - else if (encoding.equalsIgnoreCase(AudioFormat.ULAW) ||
|
| - encoding.equalsIgnoreCase(AudioFormat.ULAW_RTP)) {
|
| - return milliseconds * 8;
|
| - }
|
| - else {
|
| - throw new IllegalArgumentException("Unknown codec type");
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Use the RTPManager API to create sessions for each jmf
|
| - * track of the processor.
|
| - *
|
| - * @return description
|
| - */
|
| - 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, jingleMediaSession);
|
| - int port;
|
| -
|
| - for (int i = 0; i < pbss.length; i++) {
|
| - try {
|
| - rtpMgrs[i] = RTPManager.newInstance();
|
| -
|
| - port = portBase + 2 * i;
|
| - ipAddr = InetAddress.getByName(remoteIpAddress);
|
| -
|
| - localAddr = new SessionAddress(InetAddress.getByName(this.localIpAddress),
|
| - localPort);
|
| -
|
| - destAddr = new SessionAddress(ipAddr, port);
|
| -
|
| - rtpMgrs[i].addReceiveStreamListener(audioReceiver);
|
| - rtpMgrs[i].addSessionListener(audioReceiver);
|
| -
|
| - BufferControl bc = (BufferControl) rtpMgrs[i].getControl("javax.media.control.BufferControl");
|
| - if (bc != null) {
|
| - int bl = 160;
|
| - bc.setBufferLength(bl);
|
| - }
|
| -
|
| - try {
|
| -
|
| - rtpMgrs[i].initialize(localAddr);
|
| -
|
| - }
|
| - catch (InvalidSessionAddressException e) {
|
| - // In case the local address is not allowed to read, we user another local address
|
| - SessionAddress sessAddr = new SessionAddress();
|
| - localAddr = new SessionAddress(sessAddr.getDataAddress(),
|
| - localPort);
|
| - rtpMgrs[i].initialize(localAddr);
|
| - }
|
| -
|
| - rtpMgrs[i].addTarget(destAddr);
|
| -
|
| - LOGGER.error("Created RTP session at " + localPort + " to: " + remoteIpAddress + " " + 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 active state
|
| - */
|
| - public void setTrasmit(boolean active) {
|
| - for (SendStream sendStream : sendStreams) {
|
| - try {
|
| - if (active) {
|
| - sendStream.start();
|
| - LOGGER.debug("START");
|
| - }
|
| - else {
|
| - sendStream.stop();
|
| - LOGGER.debug("STOP");
|
| - }
|
| - }
|
| - catch (IOException e) {
|
| - e.printStackTrace();
|
| - }
|
| -
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * *************************************************************
|
| - * Convenience methods to handle processor's state changes.
|
| - * **************************************************************
|
| - */
|
| -
|
| - private Integer stateLock = 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;
|
| - }
|
| - }
|
| - }
|
| -
|
| - return !failed;
|
| - }
|
| -
|
| - /**
|
| - * *************************************************************
|
| - * 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 != null) {
|
| - 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), null);
|
| - AudioChannel audioChannel1 = new AudioChannel(new MediaLocator("javasound://8000"), localhost.getHostAddress(), localhost.getHostAddress(), 7020, 7002, new AudioFormat(AudioFormat.GSM_RTP), null);
|
| -
|
| - 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 |
| Index: org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioFormatUtils.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioFormatUtils.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioFormatUtils.java (working copy) |
| @@ -1,55 +0,0 @@ |
| -/**
|
| - * $RCSfile: AudioFormatUtils.java,v $
|
| - * $Revision: 1.1 $
|
| - * $Date: 08/11/2006
|
| - * <p/>
|
| - * Copyright 2003-2006 Jive Software.
|
| - * <p/>
|
| - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
| - * you may not use this file except in compliance with the License.
|
| - * You may obtain a copy of the License at
|
| - * <p/>
|
| - * http://www.apache.org/licenses/LICENSE-2.0
|
| - * <p/>
|
| - * Unless required by applicable law or agreed to in writing, software
|
| - * distributed under the License is distributed on an "AS IS" BASIS,
|
| - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| - * See the License for the specific language governing permissions and
|
| - * limitations under the License.
|
| - */
|
| -package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
|
| -
|
| -import org.jivesoftware.smackx.jingle.media.PayloadType;
|
| -
|
| -import javax.media.format.AudioFormat;
|
| -
|
| -/**
|
| - * Audio Format Utils.
|
| - *
|
| - * @author Thiago Camargo
|
| - */
|
| -public class AudioFormatUtils {
|
| -
|
| - /**
|
| - * Return a JMF AudioFormat for a given Jingle Payload type.
|
| - * Return null if the payload is not supported by this jmf API.
|
| - *
|
| - * @param payloadtype payloadtype
|
| - * @return correspondent audioType
|
| - */
|
| - public static AudioFormat getAudioFormat(PayloadType payloadtype) {
|
| -
|
| - switch (payloadtype.getId()) {
|
| - case 0:
|
| - return new AudioFormat(AudioFormat.ULAW_RTP);
|
| - case 3:
|
| - return new AudioFormat(AudioFormat.GSM_RTP);
|
| - case 4:
|
| - return new AudioFormat(AudioFormat.G723_RTP);
|
| - default:
|
| - return null;
|
| - }
|
| -
|
| - }
|
| -
|
| -}
|
| Index: org/jivesoftware/smackx/jingle/mediaimpl/jspeex/SpeexMediaManager.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/jspeex/SpeexMediaManager.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/jspeex/SpeexMediaManager.java (working copy) |
| @@ -1,134 +0,0 @@ |
| -/**
|
| - * $RCSfile: SpeexMediaManager.java,v $
|
| - * $Revision: 1.3 $
|
| - * $Date: 25/12/2006
|
| - * <p/>
|
| - * Copyright 2003-2006 Jive Software.
|
| - * <p/>
|
| - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
| - * you may not use this file except in compliance with the License.
|
| - * You may obtain a copy of the License at
|
| - * <p/>
|
| - * http://www.apache.org/licenses/LICENSE-2.0
|
| - * <p/>
|
| - * Unless required by applicable law or agreed to in writing, software
|
| - * distributed under the License is distributed on an "AS IS" BASIS,
|
| - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| - * See the License for the specific language governing permissions and
|
| - * limitations under the License.
|
| - */
|
| -package org.jivesoftware.smackx.jingle.mediaimpl.jspeex;
|
| -
|
| -import java.io.File;
|
| -import java.io.IOException;
|
| -import java.util.ArrayList;
|
| -import java.util.List;
|
| -
|
| -import org.jivesoftware.smackx.jingle.JingleSession;
|
| -import org.jivesoftware.smackx.jingle.SmackLogger;
|
| -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.mediaimpl.JMFInit;
|
| -import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
|
| -import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
| -
|
| -/**
|
| - * Implements a jingleMediaManager using JMF based API and JSpeex.
|
| - * It supports Speex codec.
|
| - * <i>This API only currently works on windows.</i>
|
| - *
|
| - * @author Thiago Camargo
|
| - */
|
| -public class SpeexMediaManager extends JingleMediaManager {
|
| -
|
| - private static final SmackLogger LOGGER = SmackLogger.getLogger(SpeexMediaManager.class);
|
| -
|
| - public static final String MEDIA_NAME = "Speex";
|
| -
|
| - private List<PayloadType> payloads = new ArrayList<PayloadType>();
|
| -
|
| - public SpeexMediaManager(JingleTransportManager transportManager) {
|
| - super(transportManager);
|
| - setupPayloads();
|
| - setupJMF();
|
| - }
|
| -
|
| - /**
|
| - * Returns a new jingleMediaSession
|
| - *
|
| - * @param payloadType payloadType
|
| - * @param remote remote Candidate
|
| - * @param local local Candidate
|
| - * @return JingleMediaSession
|
| - */
|
| - public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
|
| - return new AudioMediaSession(payloadType, remote, local, null,null);
|
| - }
|
| -
|
| - /**
|
| - * Setup API supported Payloads
|
| - */
|
| - private void setupPayloads() {
|
| - payloads.add(new PayloadType.Audio(15, "speex"));
|
| - }
|
| -
|
| - /**
|
| - * Return all supported Payloads for this Manager
|
| - *
|
| - * @return The Payload List
|
| - */
|
| - public List<PayloadType> getPayloads() {
|
| - return payloads;
|
| - }
|
| -
|
| - /**
|
| - * Runs JMFInit the first time the application is started so that capture
|
| - * devices are properly detected and initialized by JMF.
|
| - */
|
| - public static void setupJMF() {
|
| - // .jmf is the place where we store the jmf.properties file used
|
| - // by JMF. if the directory does not exist or it does not contain
|
| - // a jmf.properties file. or if the jmf.properties file has 0 length
|
| - // then this is the first time we're running and should continue to
|
| - // with JMFInit
|
| - String homeDir = System.getProperty("user.home");
|
| - File jmfDir = new File(homeDir, ".jmf");
|
| - String classpath = System.getProperty("java.class.path");
|
| - classpath += System.getProperty("path.separator")
|
| - + jmfDir.getAbsolutePath();
|
| - System.setProperty("java.class.path", classpath);
|
| -
|
| - if (!jmfDir.exists())
|
| - jmfDir.mkdir();
|
| -
|
| - File jmfProperties = new File(jmfDir, "jmf.properties");
|
| -
|
| - if (!jmfProperties.exists()) {
|
| - try {
|
| - jmfProperties.createNewFile();
|
| - }
|
| - catch (IOException ex) {
|
| - LOGGER.debug("Failed to create jmf.properties");
|
| - ex.printStackTrace();
|
| - }
|
| - }
|
| -
|
| - // if we're running on linux checkout that libjmutil.so is where it
|
| - // should be and put it there.
|
| - runLinuxPreInstall();
|
| -
|
| - if (jmfProperties.length() == 0) {
|
| - new JMFInit(null, false);
|
| - }
|
| -
|
| - }
|
| -
|
| - private static void runLinuxPreInstall() {
|
| - // @TODO Implement Linux Pre-Install
|
| - }
|
| -
|
| - public String getName() {
|
| - return MEDIA_NAME;
|
| - }
|
| -}
|
| Index: org/jivesoftware/smackx/jingle/mediaimpl/jspeex/AudioMediaSession.java |
| =================================================================== |
| --- org/jivesoftware/smackx/jingle/mediaimpl/jspeex/AudioMediaSession.java (revision 11644) |
| +++ org/jivesoftware/smackx/jingle/mediaimpl/jspeex/AudioMediaSession.java (working copy) |
| @@ -1,245 +0,0 @@ |
| -/**
|
| - * $RCSfile: AudioMediaSession.java,v $
|
| - * $Revision: 1.1 $
|
| - * $Date: 25/12/2006
|
| - * <p/>
|
| - * Copyright 2003-2006 Jive Software.
|
| - * <p/>
|
| - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
| - * you may not use this file except in compliance with the License.
|
| - * You may obtain a copy of the License at
|
| - * <p/>
|
| - * http://www.apache.org/licenses/LICENSE-2.0
|
| - * <p/>
|
| - * Unless required by applicable law or agreed to in writing, software
|
| - * distributed under the License is distributed on an "AS IS" BASIS,
|
| - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| - * See the License for the specific language governing permissions and
|
| - * limitations under the License.
|
| - */
|
| -
|
| -package org.jivesoftware.smackx.jingle.mediaimpl.jspeex;
|
| -
|
| -import java.io.IOException;
|
| -import java.net.DatagramSocket;
|
| -import java.net.InetAddress;
|
| -import java.net.ServerSocket;
|
| -import java.security.GeneralSecurityException;
|
| -
|
| -import javax.media.NoProcessorException;
|
| -import javax.media.format.UnsupportedFormatException;
|
| -import javax.media.rtp.rtcp.SenderReport;
|
| -import javax.media.rtp.rtcp.SourceDescription;
|
| -
|
| -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.JingleSession;
|
| -import org.jivesoftware.smackx.jingle.SmackLogger;
|
| -import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
|
| -import org.jivesoftware.smackx.jingle.media.PayloadType;
|
| -import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
| -
|
| -/**
|
| - * This Class implements a complete JingleMediaSession.
|
| - * It sould be used to transmit and receive audio captured from the Mic.
|
| - * This Class should be automaticly controlled by JingleSession.
|
| - * But you could also use in any VOIP application.
|
| - * For better NAT Traversal support this implementation don't support only receive or only transmit.
|
| - * To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit()
|
| - *
|
| - * @author Thiago Camargo
|
| - */
|
| -
|
| -public class AudioMediaSession extends JingleMediaSession implements MediaSessionListener {
|
| -
|
| - private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioMediaSession.class);
|
| -
|
| - private MediaSession mediaSession;
|
| -
|
| - /**
|
| - * Create a Session using Speex Codec
|
| - *
|
| - * @param localhost localHost
|
| - * @param localPort localPort
|
| - * @param remoteHost remoteHost
|
| - * @param remotePort remotePort
|
| - * @param eventHandler eventHandler
|
| - * @param quality quality
|
| - * @param secure secure
|
| - * @param micOn micOn
|
| - * @return MediaSession
|
| - * @throws NoProcessorException
|
| - * @throws UnsupportedFormatException
|
| - * @throws IOException
|
| - * @throws GeneralSecurityException
|
| - */
|
| - 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.jspeex.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
|
| - * @param locator media locator
|
| - */
|
| - public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote,
|
| - final TransportCandidate local, String locator, JingleSession jingleSession) {
|
| - super(payloadType, remote, local, locator == null ? "dsound://" : locator, jingleSession);
|
| - initialize();
|
| - }
|
| -
|
| - /**
|
| - * Initialize the Audio Channel to make it able to send and receive audio
|
| - */
|
| - public void initialize() {
|
| -
|
| - String ip;
|
| - String localIp;
|
| - int localPort;
|
| - int remotePort;
|
| -
|
| - if (this.getLocal().getSymmetric() != null) {
|
| - ip = this.getLocal().getIp();
|
| - localIp = this.getLocal().getLocalIp();
|
| - localPort = getFreePort();
|
| - remotePort = this.getLocal().getSymmetric().getPort();
|
| -
|
| - LOGGER.debug(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 {
|
| - LOGGER.debug("start");
|
| - mediaSession.start(true);
|
| - this.mediaReceived("");
|
| - }
|
| - 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 active state
|
| - */
|
| - public void setTrasmit(boolean active) {
|
| - // Do nothing
|
| - }
|
| -
|
| - /**
|
| - * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
|
| - */
|
| - public void startReceive() {
|
| - // Do nothing
|
| - }
|
| -
|
| - /**
|
| - * Stops transmission and for NAT Traversal reasons stop receiving also.
|
| - */
|
| - public void stopTrasmit() {
|
| - if (mediaSession != null)
|
| - mediaSession.close();
|
| - }
|
| -
|
| - /**
|
| - * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
|
| - */
|
| - public void stopReceive() {
|
| - // Do nothing
|
| - }
|
| -
|
| - public void newStreamIdentified(StreamPlayer streamPlayer) {
|
| - }
|
| -
|
| - public void senderReportReceived(SenderReport report) {
|
| - }
|
| -
|
| - public void streamClosed(StreamPlayer stream, boolean timeout) {
|
| - }
|
| -
|
| - /**
|
| - * Obtain a free port we can use.
|
| - *
|
| - * @return A free port number.
|
| - */
|
| - protected int getFreePort() {
|
| - ServerSocket ss;
|
| - int freePort = 0;
|
| -
|
| - for (int i = 0; i < 10; i++) {
|
| - freePort = (int) (10000 + Math.round(Math.random() * 10000));
|
| - freePort = freePort % 2 == 0 ? freePort : freePort + 1;
|
| - try {
|
| - ss = new ServerSocket(freePort);
|
| - freePort = ss.getLocalPort();
|
| - ss.close();
|
| - return freePort;
|
| - }
|
| - catch (IOException e) {
|
| - e.printStackTrace();
|
| - }
|
| - }
|
| - try {
|
| - ss = new ServerSocket(0);
|
| - freePort = ss.getLocalPort();
|
| - ss.close();
|
| - }
|
| - catch (IOException e) {
|
| - e.printStackTrace();
|
| - }
|
| - return freePort;
|
| - }
|
| -}
|