• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1Index: org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaSession.java
2===================================================================
3--- org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaSession.java	(revision 11644)
4+++ org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaSession.java	(working copy)
5@@ -1,92 +0,0 @@
6-/**
7- * $RCSfile: TestMediaSession.java,v $
8- * $Revision: 1.1 $
9- * $Date: 08/11/2006
10- * <p/>
11- * Copyright 2003-2006 Jive Software.
12- * <p/>
13- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
14- * you may not use this file except in compliance with the License.
15- * You may obtain a copy of the License at
16- * <p/>
17- * http://www.apache.org/licenses/LICENSE-2.0
18- * <p/>
19- * Unless required by applicable law or agreed to in writing, software
20- * distributed under the License is distributed on an "AS IS" BASIS,
21- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22- * See the License for the specific language governing permissions and
23- * limitations under the License.
24- */
25-package org.jivesoftware.smackx.jingle.mediaimpl.test;
26-
27-import org.jivesoftware.smackx.jingle.JingleSession;
28-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
29-import org.jivesoftware.smackx.jingle.media.PayloadType;
30-import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
31-
32-/**
33- * This Class implements a complete JingleMediaSession for unit testing.
34- *
35- * @author Thiago Camargo
36- */
37-public class TestMediaSession extends JingleMediaSession {
38-
39-     /**
40-     * Creates a TestMediaSession with defined payload type, remote and local candidates
41-     *
42-     * @param payloadType Payload of the jmf
43-     * @param remote      the remote information. The candidate that the jmf will be sent to.
44-     * @param local       the local information. The candidate that will receive the jmf
45-     * @param locator     media locator
46-     */
47-    public TestMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local,
48-            final String locator, JingleSession jingleSession) {
49-        super(payloadType, remote, local, "Test", jingleSession);
50-        initialize();
51-    }
52-
53-    /**
54-     * Initialize the screen share channels.
55-     */
56-    public void initialize() {
57-
58-    }
59-
60-    /**
61-     * Starts transmission and for NAT Traversal reasons start receiving also.
62-     */
63-    public void startTrasmit() {
64-
65-    }
66-
67-    /**
68-     * Set transmit activity. If the active is true, the instance should trasmit.
69-     * If it is set to false, the instance should pause transmit.
70-     *
71-     * @param active active state
72-     */
73-    public void setTrasmit(boolean active) {
74-
75-    }
76-
77-    /**
78-     * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
79-     */
80-    public void startReceive() {
81-        // Do nothing
82-    }
83-
84-    /**
85-     * Stops transmission and for NAT Traversal reasons stop receiving also.
86-     */
87-    public void stopTrasmit() {
88-
89-    }
90-
91-    /**
92-     * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
93-     */
94-    public void stopReceive() {
95-
96-    }
97-}
98Index: org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaManager.java
99===================================================================
100--- org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaManager.java	(revision 11644)
101+++ org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaManager.java	(working copy)
102@@ -1,93 +0,0 @@
103-/**
104- * $RCSfile: TestMediaManager.java,v $
105- * $Revision: 1.3 $
106- * $Date: 25/12/2006
107- * <p/>
108- * Copyright 2003-2006 Jive Software.
109- * <p/>
110- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
111- * you may not use this file except in compliance with the License.
112- * You may obtain a copy of the License at
113- * <p/>
114- * http://www.apache.org/licenses/LICENSE-2.0
115- * <p/>
116- * Unless required by applicable law or agreed to in writing, software
117- * distributed under the License is distributed on an "AS IS" BASIS,
118- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
119- * See the License for the specific language governing permissions and
120- * limitations under the License.
121- */
122-
123-package org.jivesoftware.smackx.jingle.mediaimpl.test;
124-
125-import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
126-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
127-import org.jivesoftware.smackx.jingle.media.PayloadType;
128-import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
129-import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
130-import org.jivesoftware.smackx.jingle.JingleSession;
131-
132-import java.util.*;
133-
134-/**
135- * Implements a MediaManager for test purposes.
136- *
137- * @author Thiago Camargo
138- */
139-
140-public class TestMediaManager extends JingleMediaManager {
141-
142-    public static final String MEDIA_NAME = "TestMedia";
143-
144-    private List<PayloadType> payloads = new ArrayList<PayloadType>();
145-
146-    private PayloadType preferredPayloadType = null;
147-
148-    public TestMediaManager(JingleTransportManager transportManager) {
149-        super(transportManager);
150-    }
151-
152-    /**
153-    * Return all supported Payloads for this Manager.
154-    *
155-    * @return The Payload List
156-    */
157-    public List<PayloadType> getPayloads() {
158-        return payloads;
159-    }
160-
161-    public void setPayloads(List<PayloadType> payloads) {
162-        this.payloads.addAll(payloads);
163-    }
164-
165-    /**
166-     * Returns a new JingleMediaSession
167-     *
168-     * @param payloadType payloadType
169-     * @param remote      remote Candidate
170-     * @param local       local Candidate
171-     * @return JingleMediaSession JingleMediaSession
172-     */
173-    public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote,
174-            final TransportCandidate local, final JingleSession jingleSession) {
175-        TestMediaSession session = null;
176-
177-        session = new TestMediaSession(payloadType, remote, local, "", jingleSession);
178-
179-        return session;
180-    }
181-
182-    public PayloadType getPreferredPayloadType() {
183-        if (preferredPayloadType != null)
184-            return preferredPayloadType;
185-        return super.getPreferredPayloadType();
186-    }
187-
188-    public void setPreferredPayloadType(PayloadType preferredPayloadType) {
189-        this.preferredPayloadType = preferredPayloadType;
190-    }
191-
192-    public String getName() {
193-        return MEDIA_NAME;
194-    }
195-}
196Index: org/jivesoftware/smackx/jingle/mediaimpl/JMFInit.java
197===================================================================
198--- org/jivesoftware/smackx/jingle/mediaimpl/JMFInit.java	(revision 11644)
199+++ org/jivesoftware/smackx/jingle/mediaimpl/JMFInit.java	(working copy)
200@@ -1,282 +0,0 @@
201-package org.jivesoftware.smackx.jingle.mediaimpl;
202-
203-import java.awt.Frame;
204-import java.awt.TextArea;
205-import java.awt.Toolkit;
206-import java.util.Vector;
207-
208-import javax.media.Format;
209-import javax.media.PlugInManager;
210-import javax.media.Renderer;
211-import javax.media.format.AudioFormat;
212-
213-import org.jivesoftware.smackx.jingle.SmackLogger;
214-
215-import com.sun.media.ExclusiveUse;
216-import com.sun.media.util.Registry;
217-
218-public class JMFInit extends Frame implements Runnable {
219-
220-	private static final SmackLogger LOGGER = SmackLogger.getLogger(JMFInit.class);
221-
222-	private String tempDir = "/tmp";
223-
224-    private boolean done = false;
225-
226-    private String userHome;
227-
228-    private boolean visible = false;
229-
230-    public JMFInit(String[] args, boolean visible) {
231-        super("Initializing JMF...");
232-
233-        this.visible = visible;
234-
235-        Registry.set("secure.allowCaptureFromApplets", true);
236-        Registry.set("secure.allowSaveFileFromApplets", true);
237-
238-        updateTemp(args);
239-
240-        try {
241-            Registry.commit();
242-        }
243-        catch (Exception e) {
244-
245-            message("Failed to commit to JMFRegistry!");
246-        }
247-
248-        Thread detectThread = new Thread(this);
249-        detectThread.run();
250-
251-        /*
252-           * int slept = 0; while (!done && slept < 60 * 1000 * 2) { try {
253-           * Thread.currentThread().sleep(500); } catch (InterruptedException ie) { }
254-           * slept += 500; }
255-           *
256-           * if (!done) { console.error("Detection is taking too long!
257-           * Aborting!"); message("Detection is taking too long! Aborting!"); }
258-           *
259-           * try { Thread.currentThread().sleep(2000); } catch
260-           * (InterruptedException ie) { }
261-           */
262-    }
263-
264-    public void run() {
265-        detectDirectAudio();
266-        detectS8DirectAudio();
267-        detectCaptureDevices();
268-        done = true;
269-    }
270-
271-    private void updateTemp(String[] args) {
272-        if (args != null && args.length > 0) {
273-            tempDir = args[0];
274-
275-            message("Setting cache directory to " + tempDir);
276-            Registry r = new Registry();
277-            try {
278-                r.set("secure.cacheDir", tempDir);
279-                r.commit();
280-
281-                message("Updated registry");
282-            }
283-            catch (Exception e) {
284-                message("Couldn't update registry!");
285-            }
286-        }
287-    }
288-
289-    private void detectCaptureDevices() {
290-        // check if JavaSound capture is available
291-        message("Looking for Audio capturer");
292-        Class dsauto;
293-        try {
294-            dsauto = Class.forName("DirectSoundAuto");
295-            dsauto.newInstance();
296-            message("Finished detecting DirectSound capturer");
297-        }
298-        catch (ThreadDeath td) {
299-            throw td;
300-        }
301-        catch (Throwable t) {
302-            //Do nothing
303-        }
304-
305-        Class jsauto;
306-        try {
307-            jsauto = Class.forName("JavaSoundAuto");
308-            jsauto.newInstance();
309-            message("Finished detecting javasound capturer");
310-        }
311-        catch (ThreadDeath td) {
312-            throw td;
313-        }
314-        catch (Throwable t) {
315-            message("JavaSound capturer detection failed!");
316-        }
317-
318-        /*
319-        // Check if VFWAuto or SunVideoAuto is available
320-        message("Looking for video capture devices");
321-        Class auto = null;
322-        Class autoPlus = null;
323-        try {
324-            auto = Class.forName("VFWAuto");
325-        }
326-        catch (Exception e) {
327-        }
328-        if (auto == null) {
329-            try {
330-                auto = Class.forName("SunVideoAuto");
331-            }
332-            catch (Exception ee) {
333-
334-            }
335-            try {
336-                autoPlus = Class.forName("SunVideoPlusAuto");
337-            }
338-            catch (Exception ee) {
339-
340-            }
341-        }
342-        if (auto == null) {
343-            try {
344-                auto = Class.forName("V4LAuto");
345-            }
346-            catch (Exception ee) {
347-
348-            }
349-        }
350-        try {
351-            Object instance = auto.newInstance();
352-            if (autoPlus != null) {
353-                Object instancePlus = autoPlus.newInstance();
354-            }
355-
356-            message("Finished detecting video capture devices");
357-        }
358-        catch (ThreadDeath td) {
359-            throw td;
360-        }
361-        catch (Throwable t) {
362-
363-            message("Capture device detection failed!");
364-        }
365-        */
366-    }
367-
368-    private void detectDirectAudio() {
369-        Class cls;
370-        int plType = PlugInManager.RENDERER;
371-        String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
372-        try {
373-            // Check if this is the Windows Performance Pack - hack
374-            cls = Class.forName("VFWAuto");
375-            // Check if DS capture is supported, otherwise fail DS renderer
376-            // since NT doesn't have capture
377-            cls = Class.forName("com.sun.media.protocol.dsound.DSound");
378-            // Find the renderer class and instantiate it.
379-            cls = Class.forName(dar);
380-
381-            Renderer rend = (Renderer) cls.newInstance();
382-            try {
383-                // Set the format and open the device
384-                AudioFormat af = new AudioFormat(AudioFormat.LINEAR, 44100, 16,
385-                        2);
386-                rend.setInputFormat(af);
387-                rend.open();
388-                Format[] inputFormats = rend.getSupportedInputFormats();
389-                // Register the device
390-                PlugInManager.addPlugIn(dar, inputFormats, new Format[0],
391-                        plType);
392-                // Move it to the top of the list
393-                Vector rendList = PlugInManager.getPlugInList(null, null,
394-                        plType);
395-                int listSize = rendList.size();
396-                if (rendList.elementAt(listSize - 1).equals(dar)) {
397-                    rendList.removeElementAt(listSize - 1);
398-                    rendList.insertElementAt(dar, 0);
399-                    PlugInManager.setPlugInList(rendList, plType);
400-                    PlugInManager.commit();
401-                    // Log.debug("registered");
402-                }
403-                rend.close();
404-            }
405-            catch (Throwable t) {
406-                // Log.debug("Error " + t);
407-            }
408-        }
409-        catch (Throwable tt) {
410-            //Do nothing
411-        }
412-    }
413-
414-    private void detectS8DirectAudio() {
415-        Class cls;
416-        int plType = PlugInManager.RENDERER;
417-        String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
418-        try {
419-            // Check if this is the solaris Performance Pack - hack
420-            cls = Class.forName("SunVideoAuto");
421-
422-            // Find the renderer class and instantiate it.
423-            cls = Class.forName(dar);
424-
425-            Renderer rend = (Renderer) cls.newInstance();
426-
427-            if (rend instanceof ExclusiveUse
428-                    && !((ExclusiveUse) rend).isExclusive()) {
429-                // sol8+, DAR supports mixing
430-                Vector rendList = PlugInManager.getPlugInList(null, null,
431-                        plType);
432-                int listSize = rendList.size();
433-                boolean found = false;
434-                String rname = null;
435-
436-                for (int i = 0; i < listSize; i++) {
437-                    rname = (String) (rendList.elementAt(i));
438-                    if (rname.equals(dar)) { // DAR is in the registry
439-                        found = true;
440-                        rendList.removeElementAt(i);
441-                        break;
442-                    }
443-                }
444-
445-                if (found) {
446-                    rendList.insertElementAt(dar, 0);
447-                    PlugInManager.setPlugInList(rendList, plType);
448-                    PlugInManager.commit();
449-                }
450-            }
451-        }
452-        catch (Throwable tt) {
453-            //Do nothing
454-        }
455-    }
456-
457-    private void message(String mesg) {
458-        LOGGER.debug(mesg);
459-    }
460-
461-    private void createGUI() {
462-        TextArea textBox = new TextArea(5, 50);
463-        add("Center", textBox);
464-        textBox.setEditable(false);
465-        addNotify();
466-        pack();
467-
468-        int scrWidth = (int) Toolkit.getDefaultToolkit().getScreenSize()
469-                .getWidth();
470-        int scrHeight = (int) Toolkit.getDefaultToolkit().getScreenSize()
471-                .getHeight();
472-
473-        setLocation((scrWidth - getWidth()) / 2, (scrHeight - getHeight()) / 2);
474-
475-        setVisible(visible);
476-
477-    }
478-
479-    public static void start(boolean visible) {
480-        new JMFInit(null, visible);
481-    }
482-}
483Index: org/jivesoftware/smackx/jingle/mediaimpl/demo/Demo.java
484===================================================================
485--- org/jivesoftware/smackx/jingle/mediaimpl/demo/Demo.java	(revision 11644)
486+++ org/jivesoftware/smackx/jingle/mediaimpl/demo/Demo.java	(working copy)
487@@ -1,174 +0,0 @@
488-/**
489- * $RCSfile: Demo.java,v $
490- * $Revision: 1.3 $
491- * $Date: 28/12/2006
492- * <p/>
493- * Copyright 2003-2006 Jive Software.
494- * <p/>
495- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
496- * you may not use this file except in compliance with the License.
497- * You may obtain a copy of the License at
498- * <p/>
499- * http://www.apache.org/licenses/LICENSE-2.0
500- * <p/>
501- * Unless required by applicable law or agreed to in writing, software
502- * distributed under the License is distributed on an "AS IS" BASIS,
503- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
504- * See the License for the specific language governing permissions and
505- * limitations under the License.
506- */
507-package org.jivesoftware.smackx.jingle.mediaimpl.demo;
508-
509-import org.jivesoftware.smack.Connection;
510-import org.jivesoftware.smack.XMPPConnection;
511-import org.jivesoftware.smack.XMPPException;
512-import org.jivesoftware.smackx.jingle.JingleManager;
513-import org.jivesoftware.smackx.jingle.JingleSession;
514-import org.jivesoftware.smackx.jingle.JingleSessionRequest;
515-import org.jivesoftware.smackx.jingle.listeners.JingleSessionRequestListener;
516-import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
517-import org.jivesoftware.smackx.jingle.mediaimpl.jspeex.SpeexMediaManager;
518-import org.jivesoftware.smackx.jingle.mediaimpl.sshare.ScreenShareMediaManager;
519-import org.jivesoftware.smackx.jingle.nat.ICETransportManager;
520-import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
521-
522-import javax.swing.*;
523-import java.awt.event.ActionEvent;
524-import java.util.ArrayList;
525-import java.util.List;
526-
527-/**
528- * Jingle Demo Application. It register in a XMPP Server and let users place calls using a full JID and auto-receive calls.
529- * Parameters: Server User Pass.
530- */
531-public class Demo extends JFrame {
532-
533-    private JingleTransportManager transportManager = null;
534-    private Connection xmppConnection = null;
535-
536-    private String server = null;
537-    private String user = null;
538-    private String pass = null;
539-
540-    private JingleManager jm = null;
541-    private JingleSession incoming = null;
542-    private JingleSession outgoing = null;
543-
544-    private JTextField jid;
545-
546-    public Demo(String server, String user, String pass) {
547-
548-        this.server = server;
549-        this.user = user;
550-        this.pass = pass;
551-
552-        if (user.equals("jeffw")) {
553-            jid = new JTextField("eowyn" + "@" + server + "/Smack");
554-        } else {
555-            jid = new JTextField("jeffw" + "@" + server + "/Smack");
556-        }
557-
558-        xmppConnection = new XMPPConnection(server);
559-        try {
560-            xmppConnection.connect();
561-            xmppConnection.login(user, pass);
562-            initialize();
563-        }
564-        catch (XMPPException e) {
565-            e.printStackTrace();
566-        }
567-    }
568-
569-    public void initialize() {
570-        ICETransportManager icetm0 = new ICETransportManager(xmppConnection, "10.47.47.53", 3478);
571-        List<JingleMediaManager> mediaManagers = new ArrayList<JingleMediaManager>();
572-        //mediaManagers.add(new JmfMediaManager(icetm0));
573-        mediaManagers.add(new SpeexMediaManager(icetm0));
574-        mediaManagers.add(new ScreenShareMediaManager(icetm0));
575-        jm = new JingleManager(xmppConnection, mediaManagers);
576-        jm.addCreationListener(icetm0);
577-
578-        jm.addJingleSessionRequestListener(new JingleSessionRequestListener() {
579-            public void sessionRequested(JingleSessionRequest request) {
580-
581-//                if (incoming != null)
582-//                    return;
583-
584-                try {
585-                    // Accept the call
586-                    incoming = request.accept();
587-
588-                    // Start the call
589-                    incoming.startIncoming();
590-                }
591-                catch (XMPPException e) {
592-                    e.printStackTrace();
593-                }
594-
595-            }
596-        });
597-        createGUI();
598-    }
599-
600-    public void createGUI() {
601-
602-        JPanel jPanel = new JPanel();
603-
604-        jPanel.add(jid);
605-
606-        jPanel.add(new JButton(new AbstractAction("Call") {
607-            public void actionPerformed(ActionEvent e) {
608-                if (outgoing != null) return;
609-                try {
610-                    outgoing = jm.createOutgoingJingleSession(jid.getText());
611-                    outgoing.startOutgoing();
612-                }
613-                catch (XMPPException e1) {
614-                    e1.printStackTrace();
615-                }
616-            }
617-        }));
618-
619-        jPanel.add(new JButton(new AbstractAction("Hangup") {
620-            public void actionPerformed(ActionEvent e) {
621-                if (outgoing != null)
622-                    try {
623-                        outgoing.terminate();
624-                    }
625-                    catch (XMPPException e1) {
626-                        e1.printStackTrace();
627-                    }
628-                    finally {
629-                        outgoing = null;
630-                    }
631-                if (incoming != null)
632-                    try {
633-                        incoming.terminate();
634-                    }
635-                    catch (XMPPException e1) {
636-                        e1.printStackTrace();
637-                    }
638-                    finally {
639-                        incoming = null;
640-                    }
641-            }
642-        }));
643-
644-        this.add(jPanel);
645-
646-    }
647-
648-    public static void main(String args[]) {
649-
650-        Demo demo = null;
651-
652-        if (args.length > 2) {
653-            demo = new Demo(args[0], args[1], args[2]);
654-            demo.pack();
655-            demo.setVisible(true);
656-            demo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
657-        }
658-
659-    }
660-
661-}
662Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareSession.java
663===================================================================
664--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareSession.java	(revision 11644)
665+++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareSession.java	(working copy)
666@@ -1,206 +0,0 @@
667-/**
668- * $RCSfile: ScreenShareSession.java,v $
669- * $Revision: 1.2 $
670- * $Date: 08/11/2006
671- * <p/>
672- * Copyright 2003-2006 Jive Software.
673- * <p/>
674- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
675- * you may not use this file except in compliance with the License.
676- * You may obtain a copy of the License at
677- * <p/>
678- * http://www.apache.org/licenses/LICENSE-2.0
679- * <p/>
680- * Unless required by applicable law or agreed to in writing, software
681- * distributed under the License is distributed on an "AS IS" BASIS,
682- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
683- * See the License for the specific language governing permissions and
684- * limitations under the License.
685- */
686-package org.jivesoftware.smackx.jingle.mediaimpl.sshare;
687-
688-import java.awt.Rectangle;
689-import java.awt.event.WindowAdapter;
690-import java.awt.event.WindowEvent;
691-import java.io.IOException;
692-import java.net.DatagramSocket;
693-import java.net.InetAddress;
694-import java.net.ServerSocket;
695-import java.net.UnknownHostException;
696-
697-import javax.swing.JFrame;
698-import javax.swing.JPanel;
699-
700-import org.jivesoftware.smackx.jingle.JingleSession;
701-import org.jivesoftware.smackx.jingle.SmackLogger;
702-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
703-import org.jivesoftware.smackx.jingle.media.PayloadType;
704-import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageDecoder;
705-import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageEncoder;
706-import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageReceiver;
707-import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageTransmitter;
708-import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
709-
710-/**
711- * This Class implements a complete JingleMediaSession.
712- * It sould be used to transmit and receive captured images from the Display.
713- * This Class should be automaticly controlled by JingleSession.
714- * For better NAT Traversal support this implementation don't support only receive or only transmit.
715- * To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit()
716- *
717- * @author Thiago Camargo
718- */
719-public class ScreenShareSession extends JingleMediaSession {
720-
721-	private static final SmackLogger LOGGER = SmackLogger.getLogger(ScreenShareSession.class);
722-
723-	private ImageTransmitter transmitter = null;
724-    private ImageReceiver receiver = null;
725-    private int width = 600;
726-    private int height = 600;
727-
728-    /**
729-     * Creates a org.jivesoftware.jingleaudio.jmf.AudioMediaSession with defined payload type, remote and local candidates
730-     *
731-     * @param payloadType Payload of the jmf
732-     * @param remote      the remote information. The candidate that the jmf will be sent to.
733-     * @param local       the local information. The candidate that will receive the jmf
734-     * @param locator     media locator
735-     */
736-    public ScreenShareSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local,
737-            final String locator, JingleSession jingleSession) {
738-        super(payloadType, remote, local, "Screen", jingleSession);
739-        initialize();
740-    }
741-
742-    /**
743-     * Initialize the screen share channels.
744-     */
745-    public void initialize() {
746-
747-        JingleSession session = getJingleSession();
748-        if ((session != null) && (session.getInitiator().equals(session.getConnection().getUser()))) {
749-            // If the initiator of the jingle session is us then we transmit a screen share.
750-            try {
751-                InetAddress remote = InetAddress.getByName(getRemote().getIp());
752-                transmitter = new ImageTransmitter(new DatagramSocket(getLocal().getPort()), remote, getRemote().getPort(),
753-                        new Rectangle(0, 0, width, height));
754-            } catch (Exception e) {
755-                e.printStackTrace();
756-            }
757-
758-        } else {
759-            // Otherwise we receive a screen share.
760-            JFrame window = new JFrame();
761-            JPanel jp = new JPanel();
762-            window.add(jp);
763-
764-            window.setLocation(0, 0);
765-            window.setSize(600, 600);
766-
767-            window.addWindowListener(new WindowAdapter() {
768-                public void windowClosed(WindowEvent e) {
769-                    receiver.stop();
770-                }
771-            });
772-
773-            try {
774-                receiver = new ImageReceiver(InetAddress.getByName("0.0.0.0"), getRemote().getPort(), getLocal().getPort(), width,
775-                        height);
776-                LOGGER.debug("Receiving on:" + receiver.getLocalPort());
777-            } catch (UnknownHostException e) {
778-                e.printStackTrace();
779-            }
780-
781-            jp.add(receiver);
782-            receiver.setVisible(true);
783-            window.setAlwaysOnTop(true);
784-            window.setVisible(true);
785-        }
786-    }
787-
788-    /**
789-     * Starts transmission and for NAT Traversal reasons start receiving also.
790-     */
791-    public void startTrasmit() {
792-        new Thread(transmitter).start();
793-    }
794-
795-    /**
796-     * Set transmit activity. If the active is true, the instance should trasmit.
797-     * If it is set to false, the instance should pause transmit.
798-     *
799-     * @param active active state
800-     */
801-    public void setTrasmit(boolean active) {
802-        transmitter.setTransmit(true);
803-    }
804-
805-    /**
806-     * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
807-     */
808-    public void startReceive() {
809-        // Do nothing
810-    }
811-
812-    /**
813-     * Stops transmission and for NAT Traversal reasons stop receiving also.
814-     */
815-    public void stopTrasmit() {
816-        if (transmitter != null) {
817-            transmitter.stop();
818-        }
819-    }
820-
821-    /**
822-     * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
823-     */
824-    public void stopReceive() {
825-        if (receiver != null) {
826-            receiver.stop();
827-        }
828-    }
829-
830-    /**
831-     * Obtain a free port we can use.
832-     *
833-     * @return A free port number.
834-     */
835-    protected int getFreePort() {
836-        ServerSocket ss;
837-        int freePort = 0;
838-
839-        for (int i = 0; i < 10; i++) {
840-            freePort = (int) (10000 + Math.round(Math.random() * 10000));
841-            freePort = freePort % 2 == 0 ? freePort : freePort + 1;
842-            try {
843-                ss = new ServerSocket(freePort);
844-                freePort = ss.getLocalPort();
845-                ss.close();
846-                return freePort;
847-            } catch (IOException e) {
848-                e.printStackTrace();
849-            }
850-        }
851-        try {
852-            ss = new ServerSocket(0);
853-            freePort = ss.getLocalPort();
854-            ss.close();
855-        } catch (IOException e) {
856-            e.printStackTrace();
857-        }
858-        return freePort;
859-    }
860-
861-    public void setEncoder(ImageEncoder encoder) {
862-        if (encoder != null) {
863-            this.transmitter.setEncoder(encoder);
864-        }
865-    }
866-
867-    public void setDecoder(ImageDecoder decoder) {
868-        if (decoder != null) {
869-            this.receiver.setDecoder(decoder);
870-        }
871-    }
872-}
873Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageTransmitter.java
874===================================================================
875--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageTransmitter.java	(revision 11644)
876+++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageTransmitter.java	(working copy)
877@@ -1,204 +0,0 @@
878-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
879-
880-import java.awt.AWTException;
881-import java.awt.Rectangle;
882-import java.awt.Robot;
883-import java.awt.image.BufferedImage;
884-import java.awt.image.PixelGrabber;
885-import java.io.ByteArrayOutputStream;
886-import java.io.IOException;
887-import java.net.DatagramPacket;
888-import java.net.DatagramSocket;
889-import java.net.InetAddress;
890-import java.util.Arrays;
891-
892-import org.jivesoftware.smackx.jingle.SmackLogger;
893-
894-/**
895- * UDP Image Receiver.
896- * It uses PNG Tiles into UDP packets.
897- *
898- * @author Thiago Rocha Camargo
899- */
900-public class ImageTransmitter implements Runnable {
901-
902-	private static final SmackLogger LOGGER = SmackLogger.getLogger(ImageTransmitter.class);
903-
904-	private Robot robot;
905-    private InetAddress localHost;
906-    private InetAddress remoteHost;
907-    private int localPort;
908-    private int remotePort;
909-    public static final int tileWidth = 25;
910-    private boolean on = true;
911-    private boolean transmit = false;
912-    private DatagramSocket socket;
913-    private Rectangle area;
914-    private int tiles[][][];
915-    private int maxI;
916-    private int maxJ;
917-    private ImageEncoder encoder;
918-    public final static int KEYFRAME = 10;
919-
920-    public ImageTransmitter(DatagramSocket socket, InetAddress remoteHost, int remotePort, Rectangle area) {
921-
922-        try {
923-            robot = new Robot();
924-
925-            maxI = (int) Math.ceil(area.getWidth() / tileWidth);
926-            maxJ = (int) Math.ceil(area.getHeight() / tileWidth);
927-
928-            tiles = new int[maxI][maxJ][tileWidth * tileWidth];
929-
930-            this.area = area;
931-            this.socket = socket;
932-            localHost = socket.getLocalAddress();
933-            localPort = socket.getLocalPort();
934-            this.remoteHost = remoteHost;
935-            this.remotePort = remotePort;
936-            this.encoder = new DefaultEncoder();
937-
938-            transmit = true;
939-
940-        }
941-        catch (AWTException e) {
942-            e.printStackTrace();
943-        }
944-
945-    }
946-
947-    public void start() {
948-        byte buf[] = new byte[1024];
949-        final DatagramPacket p = new DatagramPacket(buf, 1024);
950-
951-        int keyframe = 0;
952-
953-        while (on) {
954-            if (transmit) {
955-
956-                BufferedImage capture = robot.createScreenCapture(area);
957-
958-                QuantizeFilter filter = new QuantizeFilter();
959-                capture = filter.filter(capture, null);
960-
961-                long trace = System.currentTimeMillis();
962-
963-                if (++keyframe > KEYFRAME) {
964-                    keyframe = 0;
965-                }
966-                LOGGER.debug("KEYFRAME:" + keyframe);
967-
968-                for (int i = 0; i < maxI; i++) {
969-                    for (int j = 0; j < maxJ; j++) {
970-
971-                        final BufferedImage bufferedImage = capture.getSubimage(i * tileWidth, j * tileWidth, tileWidth, tileWidth);
972-
973-                        int pixels[] = new int[tileWidth * tileWidth];
974-
975-                        PixelGrabber pg = new PixelGrabber(bufferedImage, 0, 0, tileWidth, tileWidth, pixels, 0, tileWidth);
976-
977-                        try {
978-                            if (pg.grabPixels()) {
979-
980-                                if (keyframe == KEYFRAME || !Arrays.equals(tiles[i][j], pixels)) {
981-
982-                                    ByteArrayOutputStream baos = encoder.encode(bufferedImage);
983-
984-                                    if (baos != null) {
985-
986-                                        try {
987-
988-                                            Thread.sleep(1);
989-
990-                                            baos.write(i);
991-                                            baos.write(j);
992-
993-                                            byte[] bytesOut = baos.toByteArray();
994-
995-                                            if (bytesOut.length > 1000)
996-                                                LOGGER.error("Bytes out > 1000. Equals " + bytesOut.length);
997-
998-                                            p.setData(bytesOut);
999-                                            p.setAddress(remoteHost);
1000-                                            p.setPort(remotePort);
1001-
1002-                                            try {
1003-                                                socket.send(p);
1004-                                            }
1005-                                            catch (IOException e) {
1006-                                                e.printStackTrace();
1007-                                            }
1008-
1009-                                            tiles[i][j] = pixels;
1010-
1011-                                        }
1012-                                        catch (Exception e) {
1013-                                        }
1014-
1015-                                    }
1016-
1017-                                }
1018-
1019-                            }
1020-                        }
1021-                        catch (InterruptedException e) {
1022-                            e.printStackTrace();
1023-                        }
1024-                    }
1025-                }
1026-
1027-                trace = (System.currentTimeMillis() - trace);
1028-                LOGGER.debug("Loop Time:" + trace);
1029-
1030-                if (trace < 500) {
1031-                    try {
1032-                        Thread.sleep(500 - trace);
1033-                    }
1034-                    catch (InterruptedException e) {
1035-                        e.printStackTrace();
1036-                    }
1037-                }
1038-            }
1039-        }
1040-    }
1041-
1042-    public void run() {
1043-        start();
1044-    }
1045-
1046-    /**
1047-     * Set Transmit Enabled/Disabled
1048-     *
1049-     * @param transmit boolean Enabled/Disabled
1050-     */
1051-    public void setTransmit(boolean transmit) {
1052-        this.transmit = transmit;
1053-    }
1054-
1055-    /**
1056-     * Get the encoder used to encode Images Tiles
1057-     *
1058-     * @return encoder
1059-     */
1060-    public ImageEncoder getEncoder() {
1061-        return encoder;
1062-    }
1063-
1064-    /**
1065-     * Set the encoder used to encode Image Tiles
1066-     *
1067-     * @param encoder encoder
1068-     */
1069-    public void setEncoder(ImageEncoder encoder) {
1070-        this.encoder = encoder;
1071-    }
1072-
1073-    /**
1074-     * Stops Transmitter
1075-     */
1076-    public void stop() {
1077-        this.transmit = false;
1078-        this.on = false;
1079-        socket.close();
1080-    }
1081-}
1082Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageEncoder.java
1083===================================================================
1084--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageEncoder.java	(revision 11644)
1085+++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageEncoder.java	(working copy)
1086@@ -1,13 +0,0 @@
1087-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
1088-
1089-import java.awt.image.BufferedImage;
1090-import java.io.ByteArrayOutputStream;
1091-
1092-/**
1093- * Image Encoder Interface use this interface if you want to change the default encoder
1094-  *
1095- * @author Thiago Rocha Camargo
1096- */
1097-public interface ImageEncoder {
1098-    public ByteArrayOutputStream encode(BufferedImage bufferedImage);
1099-}
1100Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/PixelUtils.java
1101===================================================================
1102--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/PixelUtils.java	(revision 11644)
1103+++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/PixelUtils.java	(working copy)
1104@@ -1,223 +0,0 @@
1105-/*
1106-Copyright 2006 Jerry Huxtable
1107-
1108-Licensed under the Apache License, Version 2.0 (the "License");
1109-you may not use this file except in compliance with the License.
1110-You may obtain a copy of the License at
1111-
1112-   http://www.apache.org/licenses/LICENSE-2.0
1113-
1114-Unless required by applicable law or agreed to in writing, software
1115-distributed under the License is distributed on an "AS IS" BASIS,
1116-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1117-See the License for the specific language governing permissions and
1118-limitations under the License.
1119-*/
1120-
1121-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
1122-
1123-import java.awt.*;
1124-import java.util.Random;
1125-
1126-/**
1127- * Some more useful math functions for image processing.
1128- * These are becoming obsolete as we move to Java2D. Use MiscComposite instead.
1129- */
1130-public class PixelUtils {
1131-
1132-	public final static int REPLACE = 0;
1133-	public final static int NORMAL = 1;
1134-	public final static int MIN = 2;
1135-	public final static int MAX = 3;
1136-	public final static int ADD = 4;
1137-	public final static int SUBTRACT = 5;
1138-	public final static int DIFFERENCE = 6;
1139-	public final static int MULTIPLY = 7;
1140-	public final static int HUE = 8;
1141-	public final static int SATURATION = 9;
1142-	public final static int VALUE = 10;
1143-	public final static int COLOR = 11;
1144-	public final static int SCREEN = 12;
1145-	public final static int AVERAGE = 13;
1146-	public final static int OVERLAY = 14;
1147-	public final static int CLEAR = 15;
1148-	public final static int EXCHANGE = 16;
1149-	public final static int DISSOLVE = 17;
1150-	public final static int DST_IN = 18;
1151-	public final static int ALPHA = 19;
1152-	public final static int ALPHA_TO_GRAY = 20;
1153-
1154-	private static Random randomGenerator = new Random();
1155-
1156-	/**
1157-	 * Clamp a value to the range 0..255
1158-	 */
1159-	public static int clamp(int c) {
1160-		if (c < 0)
1161-			return 0;
1162-		if (c > 255)
1163-			return 255;
1164-		return c;
1165-	}
1166-
1167-	public static int interpolate(int v1, int v2, float f) {
1168-		return clamp((int)(v1+f*(v2-v1)));
1169-	}
1170-
1171-	public static int brightness(int rgb) {
1172-		int r = (rgb >> 16) & 0xff;
1173-		int g = (rgb >> 8) & 0xff;
1174-		int b = rgb & 0xff;
1175-		return (r+g+b)/3;
1176-	}
1177-
1178-	public static boolean nearColors(int rgb1, int rgb2, int tolerance) {
1179-		int r1 = (rgb1 >> 16) & 0xff;
1180-		int g1 = (rgb1 >> 8) & 0xff;
1181-		int b1 = rgb1 & 0xff;
1182-		int r2 = (rgb2 >> 16) & 0xff;
1183-		int g2 = (rgb2 >> 8) & 0xff;
1184-		int b2 = rgb2 & 0xff;
1185-		return Math.abs(r1-r2) <= tolerance && Math.abs(g1-g2) <= tolerance && Math.abs(b1-b2) <= tolerance;
1186-	}
1187-
1188-	private final static float hsb1[] = new float[3];//FIXME-not thread safe
1189-	private final static float hsb2[] = new float[3];//FIXME-not thread safe
1190-
1191-	// Return rgb1 painted onto rgb2
1192-	public static int combinePixels(int rgb1, int rgb2, int op) {
1193-		return combinePixels(rgb1, rgb2, op, 0xff);
1194-	}
1195-
1196-	public static int combinePixels(int rgb1, int rgb2, int op, int extraAlpha, int channelMask) {
1197-		return (rgb2 & ~channelMask) | combinePixels(rgb1 & channelMask, rgb2, op, extraAlpha);
1198-	}
1199-
1200-	public static int combinePixels(int rgb1, int rgb2, int op, int extraAlpha) {
1201-		if (op == REPLACE)
1202-			return rgb1;
1203-		int a1 = (rgb1 >> 24) & 0xff;
1204-		int r1 = (rgb1 >> 16) & 0xff;
1205-		int g1 = (rgb1 >> 8) & 0xff;
1206-		int b1 = rgb1 & 0xff;
1207-		int a2 = (rgb2 >> 24) & 0xff;
1208-		int r2 = (rgb2 >> 16) & 0xff;
1209-		int g2 = (rgb2 >> 8) & 0xff;
1210-		int b2 = rgb2 & 0xff;
1211-
1212-		switch (op) {
1213-		case NORMAL:
1214-			break;
1215-		case MIN:
1216-			r1 = Math.min(r1, r2);
1217-			g1 = Math.min(g1, g2);
1218-			b1 = Math.min(b1, b2);
1219-			break;
1220-		case MAX:
1221-			r1 = Math.max(r1, r2);
1222-			g1 = Math.max(g1, g2);
1223-			b1 = Math.max(b1, b2);
1224-			break;
1225-		case ADD:
1226-			r1 = clamp(r1+r2);
1227-			g1 = clamp(g1+g2);
1228-			b1 = clamp(b1+b2);
1229-			break;
1230-		case SUBTRACT:
1231-			r1 = clamp(r2-r1);
1232-			g1 = clamp(g2-g1);
1233-			b1 = clamp(b2-b1);
1234-			break;
1235-		case DIFFERENCE:
1236-			r1 = clamp(Math.abs(r1-r2));
1237-			g1 = clamp(Math.abs(g1-g2));
1238-			b1 = clamp(Math.abs(b1-b2));
1239-			break;
1240-		case MULTIPLY:
1241-			r1 = clamp(r1*r2/255);
1242-			g1 = clamp(g1*g2/255);
1243-			b1 = clamp(b1*b2/255);
1244-			break;
1245-		case DISSOLVE:
1246-			if ((randomGenerator.nextInt() & 0xff) <= a1) {
1247-				r1 = r2;
1248-				g1 = g2;
1249-				b1 = b2;
1250-			}
1251-			break;
1252-		case AVERAGE:
1253-			r1 = (r1+r2)/2;
1254-			g1 = (g1+g2)/2;
1255-			b1 = (b1+b2)/2;
1256-			break;
1257-		case HUE:
1258-		case SATURATION:
1259-		case VALUE:
1260-		case COLOR:
1261-			Color.RGBtoHSB(r1, g1, b1, hsb1);
1262-			Color.RGBtoHSB(r2, g2, b2, hsb2);
1263-			switch (op) {
1264-			case HUE:
1265-				hsb2[0] = hsb1[0];
1266-				break;
1267-			case SATURATION:
1268-				hsb2[1] = hsb1[1];
1269-				break;
1270-			case VALUE:
1271-				hsb2[2] = hsb1[2];
1272-				break;
1273-			case COLOR:
1274-				hsb2[0] = hsb1[0];
1275-				hsb2[1] = hsb1[1];
1276-				break;
1277-			}
1278-			rgb1 = Color.HSBtoRGB(hsb2[0], hsb2[1], hsb2[2]);
1279-			r1 = (rgb1 >> 16) & 0xff;
1280-			g1 = (rgb1 >> 8) & 0xff;
1281-			b1 = rgb1 & 0xff;
1282-			break;
1283-		case SCREEN:
1284-			r1 = 255 - ((255 - r1) * (255 - r2)) / 255;
1285-			g1 = 255 - ((255 - g1) * (255 - g2)) / 255;
1286-			b1 = 255 - ((255 - b1) * (255 - b2)) / 255;
1287-			break;
1288-		case OVERLAY:
1289-			int m, s;
1290-			s = 255 - ((255 - r1) * (255 - r2)) / 255;
1291-			m = r1 * r2 / 255;
1292-			r1 = (s * r1 + m * (255 - r1)) / 255;
1293-			s = 255 - ((255 - g1) * (255 - g2)) / 255;
1294-			m = g1 * g2 / 255;
1295-			g1 = (s * g1 + m * (255 - g1)) / 255;
1296-			s = 255 - ((255 - b1) * (255 - b2)) / 255;
1297-			m = b1 * b2 / 255;
1298-			b1 = (s * b1 + m * (255 - b1)) / 255;
1299-			break;
1300-		case CLEAR:
1301-			r1 = g1 = b1 = 0xff;
1302-			break;
1303-		case DST_IN:
1304-			r1 = clamp((r2*a1)/255);
1305-			g1 = clamp((g2*a1)/255);
1306-			b1 = clamp((b2*a1)/255);
1307-			a1 = clamp((a2*a1)/255);
1308-			return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
1309-		case ALPHA:
1310-			a1 = a1*a2/255;
1311-			return (a1 << 24) | (r2 << 16) | (g2 << 8) | b2;
1312-		case ALPHA_TO_GRAY:
1313-			int na = 255-a1;
1314-			return (a1 << 24) | (na << 16) | (na << 8) | na;
1315-		}
1316-		if (extraAlpha != 0xff || a1 != 0xff) {
1317-			a1 = a1*extraAlpha/255;
1318-			int a3 = (255-a1)*a2/255;
1319-			r1 = clamp((r1*a1+r2*a3)/255);
1320-			g1 = clamp((g1*a1+g2*a3)/255);
1321-			b1 = clamp((b1*a1+b2*a3)/255);
1322-			a1 = clamp(a1+a3);
1323-		}
1324-		return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
1325-	}
1326-
1327-}
1328Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/Quantizer.java
1329===================================================================
1330--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/Quantizer.java	(revision 11644)
1331+++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/Quantizer.java	(working copy)
1332@@ -1,53 +0,0 @@
1333-/*
1334-Copyright 2006 Jerry Huxtable
1335-
1336-Licensed under the Apache License, Version 2.0 (the "License");
1337-you may not use this file except in compliance with the License.
1338-You may obtain a copy of the License at
1339-
1340-   http://www.apache.org/licenses/LICENSE-2.0
1341-
1342-Unless required by applicable law or agreed to in writing, software
1343-distributed under the License is distributed on an "AS IS" BASIS,
1344-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1345-See the License for the specific language governing permissions and
1346-limitations under the License.
1347-*/
1348-
1349-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
1350-
1351-/**
1352- * The interface for an image quantizer. The addColor method is called (repeatedly
1353- * if necessary) with all the image pixels. A color table can then be returned by
1354- * calling the buildColorTable method.
1355- */
1356-public interface Quantizer {
1357-	/**
1358-	 * Initialize the quantizer. This should be called before adding any pixels.
1359-	 * @param numColors the number of colors we're quantizing to.
1360-	 */
1361-	public void setup(int numColors);
1362-
1363-	/**
1364-	 * Add pixels to the quantizer.
1365-	 * @param pixels the array of ARGB pixels
1366-	 * @param offset the offset into the array
1367-	 * @param count the count of pixels
1368-	 */
1369-	public void addPixels(int[] pixels, int offset, int count);
1370-
1371-	/**
1372-	 * Build a color table from the added pixels.
1373-	 * @return an array of ARGB pixels representing a color table
1374-	 */
1375-	public int[] buildColorTable();
1376-
1377-	/**
1378-	 * Using the previously-built color table, return the index into that table for a pixel.
1379-	 * This is guaranteed to return a valid index - returning the index of a color closer
1380-	 * to that requested if necessary.
1381-	 * @param rgb the pixel to find
1382-	 * @return the pixel's index in the color table
1383-	 */
1384-	public int getIndexForColor(int rgb);
1385-}
1386Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultEncoder.java
1387===================================================================
1388--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultEncoder.java	(revision 11644)
1389+++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultEncoder.java	(working copy)
1390@@ -1,24 +0,0 @@
1391-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
1392-
1393-import javax.imageio.ImageIO;
1394-import java.awt.image.BufferedImage;
1395-import java.io.ByteArrayOutputStream;
1396-import java.io.IOException;
1397-
1398-/**
1399- * Implements a default PNG Encoder
1400- */
1401-public class DefaultEncoder implements ImageEncoder{
1402-
1403-    public ByteArrayOutputStream encode(BufferedImage bufferedImage) {
1404-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
1405-        try {
1406-            ImageIO.write(bufferedImage, "png", baos);
1407-        }
1408-        catch (IOException e) {
1409-            e.printStackTrace();
1410-            baos = null;
1411-        }
1412-        return baos;
1413-    }
1414-}
1415Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/QuantizeFilter.java
1416===================================================================
1417--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/QuantizeFilter.java	(revision 11644)
1418+++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/QuantizeFilter.java	(working copy)
1419@@ -1,178 +0,0 @@
1420-/*
1421-Copyright 2006 Jerry Huxtable
1422-
1423-Licensed under the Apache License, Version 2.0 (the "License");
1424-you may not use this file except in compliance with the License.
1425-You may obtain a copy of the License at
1426-
1427-   http://www.apache.org/licenses/LICENSE-2.0
1428-
1429-Unless required by applicable law or agreed to in writing, software
1430-distributed under the License is distributed on an "AS IS" BASIS,
1431-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1432-See the License for the specific language governing permissions and
1433-limitations under the License.
1434-*/
1435-
1436-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
1437-
1438-import java.awt.*;
1439-
1440-/**
1441- * A filter which quantizes an image to a set number of colors - useful for producing
1442- * images which are to be encoded using an index color model. The filter can perform
1443- * Floyd-Steinberg error-diffusion dithering if required. At present, the quantization
1444- * is done using an octtree algorithm but I eventually hope to add more quantization
1445- * methods such as median cut. Note: at present, the filter produces an image which
1446- * uses the RGB color model (because the application it was written for required it).
1447- * I hope to extend it to produce an IndexColorModel by request.
1448- */
1449-public class QuantizeFilter extends WholeImageFilter {
1450-
1451-	/**
1452-	 * Floyd-Steinberg dithering matrix.
1453-	 */
1454-	protected final static int[] matrix = {
1455-	 	 0, 0, 0,
1456-	 	 0, 0, 7,
1457-	 	 3, 5, 1,
1458-	};
1459-	private int sum = 3+5+7+1;
1460-
1461-	private boolean dither;
1462-	private int numColors = 256;
1463-	private boolean serpentine = true;
1464-
1465-	/**
1466-	 * Set the number of colors to quantize to.
1467-	 * @param numColors the number of colors. The default is 256.
1468-	 */
1469-	public void setNumColors(int numColors) {
1470-		this.numColors = Math.min(Math.max(numColors, 8), 256);
1471-	}
1472-
1473-	/**
1474-	 * Get the number of colors to quantize to.
1475-	 * @return the number of colors.
1476-	 */
1477-	public int getNumColors() {
1478-		return numColors;
1479-	}
1480-
1481-	/**
1482-	 * Set whether to use dithering or not. If not, the image is posterized.
1483-	 * @param dither true to use dithering
1484-	 */
1485-	public void setDither(boolean dither) {
1486-		this.dither = dither;
1487-	}
1488-
1489-	/**
1490-	 * Return the dithering setting
1491-	 * @return the current setting
1492-	 */
1493-	public boolean getDither() {
1494-		return dither;
1495-	}
1496-
1497-	/**
1498-	 * Set whether to use a serpentine pattern for return or not. This can reduce 'avalanche' artifacts in the output.
1499-	 * @param serpentine true to use serpentine pattern
1500-	 */
1501-	public void setSerpentine(boolean serpentine) {
1502-		this.serpentine = serpentine;
1503-	}
1504-
1505-	/**
1506-	 * Return the serpentine setting
1507-	 * @return the current setting
1508-	 */
1509-	public boolean getSerpentine() {
1510-		return serpentine;
1511-	}
1512-
1513-	public void quantize(int[] inPixels, int[] outPixels, int width, int height, int numColors, boolean dither, boolean serpentine) {
1514-		int count = width*height;
1515-		Quantizer quantizer = new OctTreeQuantizer();
1516-		quantizer.setup(numColors);
1517-		quantizer.addPixels(inPixels, 0, count);
1518-		int[] table =  quantizer.buildColorTable();
1519-
1520-		if (!dither) {
1521-			for (int i = 0; i < count; i++)
1522-				outPixels[i] = table[quantizer.getIndexForColor(inPixels[i])];
1523-		} else {
1524-			int index = 0;
1525-			for (int y = 0; y < height; y++) {
1526-				boolean reverse = serpentine && (y & 1) == 1;
1527-				int direction;
1528-				if (reverse) {
1529-					index = y*width+width-1;
1530-					direction = -1;
1531-				} else {
1532-					index = y*width;
1533-					direction = 1;
1534-				}
1535-				for (int x = 0; x < width; x++) {
1536-					int rgb1 = inPixels[index];
1537-					int rgb2 = table[quantizer.getIndexForColor(rgb1)];
1538-
1539-					outPixels[index] = rgb2;
1540-
1541-					int r1 = (rgb1 >> 16) & 0xff;
1542-					int g1 = (rgb1 >> 8) & 0xff;
1543-					int b1 = rgb1 & 0xff;
1544-
1545-					int r2 = (rgb2 >> 16) & 0xff;
1546-					int g2 = (rgb2 >> 8) & 0xff;
1547-					int b2 = rgb2 & 0xff;
1548-
1549-					int er = r1-r2;
1550-					int eg = g1-g2;
1551-					int eb = b1-b2;
1552-
1553-					for (int i = -1; i <= 1; i++) {
1554-						int iy = i+y;
1555-						if (0 <= iy && iy < height) {
1556-							for (int j = -1; j <= 1; j++) {
1557-								int jx = j+x;
1558-								if (0 <= jx && jx < width) {
1559-									int w;
1560-									if (reverse)
1561-										w = matrix[(i+1)*3-j+1];
1562-									else
1563-										w = matrix[(i+1)*3+j+1];
1564-									if (w != 0) {
1565-										int k = reverse ? index - j : index + j;
1566-										rgb1 = inPixels[k];
1567-										r1 = (rgb1 >> 16) & 0xff;
1568-										g1 = (rgb1 >> 8) & 0xff;
1569-										b1 = rgb1 & 0xff;
1570-										r1 += er * w/sum;
1571-										g1 += eg * w/sum;
1572-										b1 += eb * w/sum;
1573-										inPixels[k] = (PixelUtils.clamp(r1) << 16) | (PixelUtils.clamp(g1) << 8) | PixelUtils.clamp(b1);
1574-									}
1575-								}
1576-							}
1577-						}
1578-					}
1579-					index += direction;
1580-				}
1581-			}
1582-		}
1583-	}
1584-
1585-	protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) {
1586-		int[] outPixels = new int[width*height];
1587-
1588-		quantize(inPixels, outPixels, width, height, numColors, dither, serpentine);
1589-
1590-		return outPixels;
1591-	}
1592-
1593-	public String toString() {
1594-		return "Colors/Quantize...";
1595-	}
1596-
1597-}
1598Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageReceiver.java
1599===================================================================
1600--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageReceiver.java	(revision 11644)
1601+++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageReceiver.java	(working copy)
1602@@ -1,150 +0,0 @@
1603-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
1604-
1605-import java.awt.*;
1606-import java.awt.image.BufferedImage;
1607-import java.io.ByteArrayInputStream;
1608-import java.io.IOException;
1609-import java.net.DatagramPacket;
1610-import java.net.DatagramSocket;
1611-import java.net.InetAddress;
1612-import java.net.SocketException;
1613-
1614-/**
1615- * UDP Image Receiver.
1616- * It uses PNG Tiles into UDP packets.
1617- *
1618- * @author Thiago Rocha Camargo
1619- */
1620-public class ImageReceiver extends Canvas {
1621-
1622-    private boolean on = true;
1623-    private DatagramSocket socket;
1624-    private BufferedImage tiles[][];
1625-    private static final int tileWidth = ImageTransmitter.tileWidth;
1626-    private InetAddress localHost;
1627-    private InetAddress remoteHost;
1628-    private int localPort;
1629-    private int remotePort;
1630-    private ImageDecoder decoder;
1631-
1632-    public ImageReceiver(final InetAddress remoteHost, final int remotePort, final int localPort, int width, int height) {
1633-        tiles = new BufferedImage[width][height];
1634-
1635-        try {
1636-
1637-            socket = new DatagramSocket(localPort);
1638-            localHost = socket.getLocalAddress();
1639-            this.remoteHost = remoteHost;
1640-            this.remotePort = remotePort;
1641-            this.localPort = localPort;
1642-            this.decoder = new DefaultDecoder();
1643-
1644-            new Thread(new Runnable() {
1645-                public void run() {
1646-                    byte buf[] = new byte[1024];
1647-                    DatagramPacket p = new DatagramPacket(buf, 1024);
1648-                    try {
1649-                        while (on) {
1650-                            socket.receive(p);
1651-
1652-                            int length = p.getLength();
1653-
1654-                            BufferedImage bufferedImage = decoder.decode(new ByteArrayInputStream(p.getData(), 0, length - 2));
1655-
1656-                            if (bufferedImage != null) {
1657-
1658-                                int x = p.getData()[length - 2];
1659-                                int y = p.getData()[length - 1];
1660-
1661-                                drawTile(x, y, bufferedImage);
1662-
1663-                            }
1664-
1665-                        }
1666-                    }
1667-                    catch (IOException e) {
1668-                        e.printStackTrace();
1669-                    }
1670-                }
1671-            }).start();
1672-
1673-            new Thread(new Runnable() {
1674-                public void run() {
1675-                    byte buf[] = new byte[1024];
1676-                    DatagramPacket p = new DatagramPacket(buf, 1024);
1677-                    try {
1678-                        while (on) {
1679-
1680-                            p.setAddress(remoteHost);
1681-                            p.setPort(remotePort);
1682-                            socket.send(p);
1683-
1684-                            try {
1685-                                Thread.sleep(1000);
1686-                            }
1687-                            catch (InterruptedException e) {
1688-                                e.printStackTrace();
1689-                            }
1690-
1691-                        }
1692-                    }
1693-                    catch (IOException e) {
1694-                        e.printStackTrace();
1695-                    }
1696-                }
1697-            }).start();
1698-
1699-        }
1700-        catch (SocketException e) {
1701-            e.printStackTrace();
1702-        }
1703-        this.setSize(width, height);
1704-    }
1705-
1706-    public InetAddress getLocalHost() {
1707-        return localHost;
1708-    }
1709-
1710-    public InetAddress getRemoteHost() {
1711-        return remoteHost;
1712-    }
1713-
1714-    public int getLocalPort() {
1715-        return localPort;
1716-    }
1717-
1718-    public int getRemotePort() {
1719-        return remotePort;
1720-    }
1721-
1722-    public DatagramSocket getDatagramSocket() {
1723-        return socket;
1724-    }
1725-
1726-    public void drawTile(int x, int y, BufferedImage bufferedImage) {
1727-        tiles[x][y] = bufferedImage;
1728-        //repaint(x * tileWidth, y * tileWidth, tileWidth, tileWidth);
1729-        this.getGraphics().drawImage(bufferedImage, tileWidth * x, tileWidth * y, this);
1730-    }
1731-
1732-    public void paint(Graphics g) {
1733-        for (int i = 0; i < tiles.length; i++) {
1734-            for (int j = 0; j < tiles[0].length; j++) {
1735-                g.drawImage(tiles[i][j], tileWidth * i, tileWidth * j, this);
1736-            }
1737-        }
1738-    }
1739-
1740-    public ImageDecoder getDecoder() {
1741-        return decoder;
1742-    }
1743-
1744-    public void setDecoder(ImageDecoder decoder) {
1745-        this.decoder = decoder;
1746-    }
1747-
1748-    public void stop(){
1749-        this.on=false;
1750-        socket.close();
1751-    }
1752-}
1753Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/WholeImageFilter.java
1754===================================================================
1755--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/WholeImageFilter.java	(revision 11644)
1756+++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/WholeImageFilter.java	(working copy)
1757@@ -1,86 +0,0 @@
1758-/*
1759-Copyright 2006 Jerry Huxtable
1760-
1761-Licensed under the Apache License, Version 2.0 (the "License");
1762-you may not use this file except in compliance with the License.
1763-You may obtain a copy of the License at
1764-
1765-   http://www.apache.org/licenses/LICENSE-2.0
1766-
1767-Unless required by applicable law or agreed to in writing, software
1768-distributed under the License is distributed on an "AS IS" BASIS,
1769-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1770-See the License for the specific language governing permissions and
1771-limitations under the License.
1772-*/
1773-
1774-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
1775-
1776-import java.awt.*;
1777-import java.awt.image.BufferedImage;
1778-import java.awt.image.ColorModel;
1779-import java.awt.image.WritableRaster;
1780-
1781-/**
1782- * A filter which acts as a superclass for filters which need to have the whole image in memory
1783- * to do their stuff.
1784- */
1785-public abstract class WholeImageFilter extends AbstractBufferedImageOp {
1786-
1787-	/**
1788-     * The output image bounds.
1789-     */
1790-    protected Rectangle transformedSpace;
1791-
1792-	/**
1793-     * The input image bounds.
1794-     */
1795-	protected Rectangle originalSpace;
1796-
1797-	/**
1798-	 * Construct a WholeImageFilter.
1799-	 */
1800-	public WholeImageFilter() {
1801-	}
1802-
1803-    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
1804-        int width = src.getWidth();
1805-        int height = src.getHeight();
1806-		int type = src.getType();
1807-		WritableRaster srcRaster = src.getRaster();
1808-
1809-		originalSpace = new Rectangle(0, 0, width, height);
1810-		transformedSpace = new Rectangle(0, 0, width, height);
1811-		transformSpace(transformedSpace);
1812-
1813-        if ( dst == null ) {
1814-            ColorModel dstCM = src.getColorModel();
1815-			dst = new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(transformedSpace.width, transformedSpace.height), dstCM.isAlphaPremultiplied(), null);
1816-		}
1817-		WritableRaster dstRaster = dst.getRaster();
1818-
1819-		int[] inPixels = getRGB( src, 0, 0, width, height, null );
1820-		inPixels = filterPixels( width, height, inPixels, transformedSpace );
1821-		setRGB( dst, 0, 0, transformedSpace.width, transformedSpace.height, inPixels );
1822-
1823-        return dst;
1824-    }
1825-
1826-	/**
1827-     * Calculate output bounds for given input bounds.
1828-     * @param rect input and output rectangle
1829-     */
1830-	protected void transformSpace(Rectangle rect) {
1831-	}
1832-
1833-	/**
1834-     * Actually filter the pixels.
1835-     * @param width the image width
1836-     * @param height the image height
1837-     * @param inPixels the image pixels
1838-     * @param transformedSpace the output bounds
1839-     * @return the output pixels
1840-     */
1841-	protected abstract int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace );
1842-}
1843-
1844Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/AbstractBufferedImageOp.java
1845===================================================================
1846--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/AbstractBufferedImageOp.java	(revision 11644)
1847+++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/AbstractBufferedImageOp.java	(working copy)
1848@@ -1,98 +0,0 @@
1849-/*
1850-Copyright 2006 Jerry Huxtable
1851-
1852-Licensed under the Apache License, Version 2.0 (the "License");
1853-you may not use this file except in compliance with the License.
1854-You may obtain a copy of the License at
1855-
1856-   http://www.apache.org/licenses/LICENSE-2.0
1857-
1858-Unless required by applicable law or agreed to in writing, software
1859-distributed under the License is distributed on an "AS IS" BASIS,
1860-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1861-See the License for the specific language governing permissions and
1862-limitations under the License.
1863-*/
1864-
1865-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
1866-
1867-import java.awt.*;
1868-import java.awt.geom.Point2D;
1869-import java.awt.geom.Rectangle2D;
1870-import java.awt.image.BufferedImage;
1871-import java.awt.image.BufferedImageOp;
1872-import java.awt.image.ColorModel;
1873-
1874-/**
1875- * A convenience class which implements those methods of BufferedImageOp which are rarely changed.
1876- */
1877-public abstract class AbstractBufferedImageOp implements BufferedImageOp, Cloneable {
1878-
1879-    public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) {
1880-        if ( dstCM == null )
1881-            dstCM = src.getColorModel();
1882-        return new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()), dstCM.isAlphaPremultiplied(), null);
1883-    }
1884-
1885-    public Rectangle2D getBounds2D( BufferedImage src ) {
1886-        return new Rectangle(0, 0, src.getWidth(), src.getHeight());
1887-    }
1888-
1889-    public Point2D getPoint2D( Point2D srcPt, Point2D dstPt ) {
1890-        if ( dstPt == null )
1891-            dstPt = new Point2D.Double();
1892-        dstPt.setLocation( srcPt.getX(), srcPt.getY() );
1893-        return dstPt;
1894-    }
1895-
1896-    public RenderingHints getRenderingHints() {
1897-        return null;
1898-    }
1899-
1900-	/**
1901-	 * A convenience method for getting ARGB pixels from an image. This tries to avoid the performance
1902-	 * penalty of BufferedImage.getRGB unmanaging the image.
1903-     * @param image   a BufferedImage object
1904-     * @param x       the left edge of the pixel block
1905-     * @param y       the right edge of the pixel block
1906-     * @param width   the width of the pixel arry
1907-     * @param height  the height of the pixel arry
1908-     * @param pixels  the array to hold the returned pixels. May be null.
1909-     * @return the pixels
1910-     * @see #setRGB
1911-     */
1912-	public int[] getRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) {
1913-		int type = image.getType();
1914-		if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB )
1915-			return (int [])image.getRaster().getDataElements( x, y, width, height, pixels );
1916-		return image.getRGB( x, y, width, height, pixels, 0, width );
1917-    }
1918-
1919-	/**
1920-	 * A convenience method for setting ARGB pixels in an image. This tries to avoid the performance
1921-	 * penalty of BufferedImage.setRGB unmanaging the image.
1922-     * @param image   a BufferedImage object
1923-     * @param x       the left edge of the pixel block
1924-     * @param y       the right edge of the pixel block
1925-     * @param width   the width of the pixel arry
1926-     * @param height  the height of the pixel arry
1927-     * @param pixels  the array of pixels to set
1928-     * @see #getRGB
1929-	 */
1930-	public void setRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) {
1931-		int type = image.getType();
1932-		if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB )
1933-			image.getRaster().setDataElements( x, y, width, height, pixels );
1934-		else
1935-			image.setRGB( x, y, width, height, pixels, 0, width );
1936-    }
1937-
1938-	public Object clone() {
1939-		try {
1940-			return super.clone();
1941-		}
1942-		catch ( CloneNotSupportedException e ) {
1943-			return null;
1944-		}
1945-	}
1946-}
1947Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageDecoder.java
1948===================================================================
1949--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageDecoder.java	(revision 11644)
1950+++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageDecoder.java	(working copy)
1951@@ -1,15 +0,0 @@
1952-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
1953-
1954-import java.awt.image.BufferedImage;
1955-import java.io.ByteArrayInputStream;
1956-import java.io.IOException;
1957-
1958-/**
1959- * Image Decoder Interface use this interface if you want to change the default decoder
1960- *
1961- * @author Thiago Rocha Camargo
1962- */
1963-public interface ImageDecoder {
1964-
1965-    public BufferedImage decode(ByteArrayInputStream stream) throws IOException;
1966-}
1967Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/OctTreeQuantizer.java
1968===================================================================
1969--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/OctTreeQuantizer.java	(revision 11644)
1970+++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/OctTreeQuantizer.java	(working copy)
1971@@ -1,287 +0,0 @@
1972-/*
1973-Copyright 2006 Jerry Huxtable
1974-
1975-Licensed under the Apache License, Version 2.0 (the "License");
1976-you may not use this file except in compliance with the License.
1977-You may obtain a copy of the License at
1978-
1979-   http://www.apache.org/licenses/LICENSE-2.0
1980-
1981-Unless required by applicable law or agreed to in writing, software
1982-distributed under the License is distributed on an "AS IS" BASIS,
1983-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1984-See the License for the specific language governing permissions and
1985-limitations under the License.
1986-*/
1987-
1988-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
1989-
1990-import java.io.PrintStream;
1991-import java.util.Vector;
1992-
1993-import org.jivesoftware.smackx.jingle.SmackLogger;
1994-
1995-/**
1996- * An image Quantizer based on the Octree algorithm. This is a very basic implementation
1997- * at present and could be much improved by picking the nodes to reduce more carefully
1998- * (i.e. not completely at random) when I get the time.
1999- */
2000-public class OctTreeQuantizer implements Quantizer {
2001-
2002-	private static final SmackLogger LOGGER = SmackLogger.getLogger(OctTreeQuantizer.class);
2003-
2004-	/**
2005-	 * The greatest depth the tree is allowed to reach
2006-	 */
2007-	final static int MAX_LEVEL = 5;
2008-
2009-	/**
2010-	 * An Octtree node.
2011-	 */
2012-	class OctTreeNode {
2013-		int children;
2014-		int level;
2015-		OctTreeNode parent;
2016-		OctTreeNode leaf[] = new OctTreeNode[8];
2017-		boolean isLeaf;
2018-		int count;
2019-		int	totalRed;
2020-		int	totalGreen;
2021-		int	totalBlue;
2022-		int index;
2023-
2024-		/**
2025-		 * A debugging method which prints the tree out.
2026-		 */
2027-		public void list(PrintStream s, int level) {
2028-			String indentStr = "";
2029-			for (int i = 0; i < level; i++)
2030-				indentStr += " ";
2031-			if (count == 0)
2032-				LOGGER.debug(indentStr + index + ": count=" + count);
2033-			else
2034-				LOGGER.debug(indentStr + index + ": count=" + count + " red=" + (totalRed/count) + " green=" + (totalGreen / count) + " blue=" + (totalBlue / count));
2035-			for (int i = 0; i < 8; i++)
2036-				if (leaf[i] != null)
2037-					leaf[i].list(s, level+2);
2038-		}
2039-	}
2040-
2041-	private int nodes = 0;
2042-	private OctTreeNode root;
2043-	private int reduceColors;
2044-	private int maximumColors;
2045-	private int colors = 0;
2046-	private Vector[] colorList;
2047-
2048-	public OctTreeQuantizer() {
2049-		setup(256);
2050-		colorList = new Vector[MAX_LEVEL+1];
2051-		for (int i = 0; i < MAX_LEVEL+1; i++)
2052-			colorList[i] = new Vector();
2053-		root = new OctTreeNode();
2054-	}
2055-
2056-	/**
2057-	 * Initialize the quantizer. This should be called before adding any pixels.
2058-	 * @param numColors the number of colors we're quantizing to.
2059-	 */
2060-	public void setup(int numColors) {
2061-		maximumColors = numColors;
2062-		reduceColors = Math.max(512, numColors * 2);
2063-	}
2064-
2065-	/**
2066-	 * Add pixels to the quantizer.
2067-	 * @param pixels the array of ARGB pixels
2068-	 * @param offset the offset into the array
2069-	 * @param count the count of pixels
2070-	 */
2071-	public void addPixels(int[] pixels, int offset, int count) {
2072-		for (int i = 0; i < count; i++) {
2073-			insertColor(pixels[i+offset]);
2074-			if (colors > reduceColors)
2075-				reduceTree(reduceColors);
2076-		}
2077-	}
2078-
2079-    /**
2080-     * Get the color table index for a color.
2081-     * @param rgb the color
2082-     * @return the index
2083-     */
2084-	public int getIndexForColor(int rgb) {
2085-		int red = (rgb >> 16) & 0xff;
2086-		int green = (rgb >> 8) & 0xff;
2087-		int blue = rgb & 0xff;
2088-
2089-		OctTreeNode node = root;
2090-
2091-		for (int level = 0; level <= MAX_LEVEL; level++) {
2092-			OctTreeNode child;
2093-			int bit = 0x80 >> level;
2094-
2095-			int index = 0;
2096-			if ((red & bit) != 0)
2097-				index += 4;
2098-			if ((green & bit) != 0)
2099-				index += 2;
2100-			if ((blue & bit) != 0)
2101-				index += 1;
2102-
2103-			child = node.leaf[index];
2104-
2105-			if (child == null)
2106-				return node.index;
2107-			else if (child.isLeaf)
2108-				return child.index;
2109-			else
2110-				node = child;
2111-		}
2112-		LOGGER.debug("getIndexForColor failed");
2113-		return 0;
2114-	}
2115-
2116-	private void insertColor(int rgb) {
2117-		int red = (rgb >> 16) & 0xff;
2118-		int green = (rgb >> 8) & 0xff;
2119-		int blue = rgb & 0xff;
2120-
2121-		OctTreeNode node = root;
2122-
2123-//		LOGGER.debug("insertColor="+Integer.toHexString(rgb));
2124-		for (int level = 0; level <= MAX_LEVEL; level++) {
2125-			OctTreeNode child;
2126-			int bit = 0x80 >> level;
2127-
2128-			int index = 0;
2129-			if ((red & bit) != 0)
2130-				index += 4;
2131-			if ((green & bit) != 0)
2132-				index += 2;
2133-			if ((blue & bit) != 0)
2134-				index += 1;
2135-
2136-			child = node.leaf[index];
2137-
2138-			if (child == null) {
2139-				node.children++;
2140-
2141-				child = new OctTreeNode();
2142-				child.parent = node;
2143-				node.leaf[index] = child;
2144-				node.isLeaf = false;
2145-				nodes++;
2146-				colorList[level].addElement(child);
2147-
2148-				if (level == MAX_LEVEL) {
2149-					child.isLeaf = true;
2150-					child.count = 1;
2151-					child.totalRed = red;
2152-					child.totalGreen = green;
2153-					child.totalBlue = blue;
2154-					child.level = level;
2155-					colors++;
2156-					return;
2157-				}
2158-
2159-				node = child;
2160-			} else if (child.isLeaf) {
2161-				child.count++;
2162-				child.totalRed += red;
2163-				child.totalGreen += green;
2164-				child.totalBlue += blue;
2165-				return;
2166-			} else
2167-				node = child;
2168-		}
2169-		LOGGER.debug("insertColor failed");
2170-	}
2171-
2172-	private void reduceTree(int numColors) {
2173-		for (int level = MAX_LEVEL-1; level >= 0; level--) {
2174-			Vector v = colorList[level];
2175-			if (v != null && v.size() > 0) {
2176-				for (int j = 0; j < v.size(); j++) {
2177-					OctTreeNode node = (OctTreeNode)v.elementAt(j);
2178-					if (node.children > 0) {
2179-						for (int i = 0; i < 8; i++) {
2180-							OctTreeNode child = node.leaf[i];
2181-							if (child != null) {
2182-								if (!child.isLeaf)
2183-									LOGGER.debug("not a leaf!");
2184-								node.count += child.count;
2185-								node.totalRed += child.totalRed;
2186-								node.totalGreen += child.totalGreen;
2187-								node.totalBlue += child.totalBlue;
2188-								node.leaf[i] = null;
2189-								node.children--;
2190-								colors--;
2191-								nodes--;
2192-								colorList[level+1].removeElement(child);
2193-							}
2194-						}
2195-						node.isLeaf = true;
2196-						colors++;
2197-						if (colors <= numColors)
2198-							return;
2199-					}
2200-				}
2201-			}
2202-		}
2203-
2204-		LOGGER.debug("Unable to reduce the OctTree");
2205-	}
2206-
2207-    /**
2208-     * Build the color table.
2209-     * @return the color table
2210-     */
2211-	public int[] buildColorTable() {
2212-		int[] table = new int[colors];
2213-		buildColorTable(root, table, 0);
2214-		return table;
2215-	}
2216-
2217-	/**
2218-	 * A quick way to use the quantizer. Just create a table the right size and pass in the pixels.
2219-     * @param inPixels the input colors
2220-     * @param table the output color table
2221-     */
2222-	public void buildColorTable(int[] inPixels, int[] table) {
2223-		int count = inPixels.length;
2224-		maximumColors = table.length;
2225-		for (int i = 0; i < count; i++) {
2226-			insertColor(inPixels[i]);
2227-			if (colors > reduceColors)
2228-				reduceTree(reduceColors);
2229-		}
2230-		if (colors > maximumColors)
2231-			reduceTree(maximumColors);
2232-		buildColorTable(root, table, 0);
2233-	}
2234-
2235-	private int buildColorTable(OctTreeNode node, int[] table, int index) {
2236-		if (colors > maximumColors)
2237-			reduceTree(maximumColors);
2238-
2239-		if (node.isLeaf) {
2240-			int count = node.count;
2241-			table[index] = 0xff000000 |
2242-				((node.totalRed/count) << 16) |
2243-				((node.totalGreen/count) << 8) |
2244-				node.totalBlue/count;
2245-			node.index = index++;
2246-		} else {
2247-			for (int i = 0; i < 8; i++) {
2248-				if (node.leaf[i] != null) {
2249-					node.index = index;
2250-					index = buildColorTable(node.leaf[i], table, index);
2251-				}
2252-			}
2253-		}
2254-		return index;
2255-	}
2256-
2257-}
2258-
2259Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultDecoder.java
2260===================================================================
2261--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultDecoder.java	(revision 11644)
2262+++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultDecoder.java	(working copy)
2263@@ -1,16 +0,0 @@
2264-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
2265-
2266-import javax.imageio.ImageIO;
2267-import java.awt.image.BufferedImage;
2268-import java.io.ByteArrayInputStream;
2269-import java.io.IOException;
2270-
2271-/**
2272- * Implements a default PNG decoder.
2273- */
2274-public class DefaultDecoder implements ImageDecoder {
2275-
2276-    public BufferedImage decode(ByteArrayInputStream stream) throws IOException {
2277-        return ImageIO.read(stream);
2278-    }
2279-}
2280Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareMediaManager.java
2281===================================================================
2282--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareMediaManager.java	(revision 11644)
2283+++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareMediaManager.java	(working copy)
2284@@ -1,115 +0,0 @@
2285-/**
2286- * $RCSfile: ScreenShareMediaManager.java,v $
2287- * $Revision: 1.3 $
2288- * $Date: 25/12/2006
2289- * <p/>
2290- * Copyright 2003-2006 Jive Software.
2291- * <p/>
2292- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
2293- * you may not use this file except in compliance with the License.
2294- * You may obtain a copy of the License at
2295- * <p/>
2296- * http://www.apache.org/licenses/LICENSE-2.0
2297- * <p/>
2298- * Unless required by applicable law or agreed to in writing, software
2299- * distributed under the License is distributed on an "AS IS" BASIS,
2300- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2301- * See the License for the specific language governing permissions and
2302- * limitations under the License.
2303- */
2304-
2305-package org.jivesoftware.smackx.jingle.mediaimpl.sshare;
2306-
2307-import org.jivesoftware.smackx.jingle.JingleSession;
2308-import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
2309-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
2310-import org.jivesoftware.smackx.jingle.media.PayloadType;
2311-import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageDecoder;
2312-import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageEncoder;
2313-import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
2314-import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
2315-
2316-import java.util.ArrayList;
2317-import java.util.List;
2318-
2319-/**
2320- * Implements a JingleMediaManager for ScreenSharing.
2321- * It currently uses an Audio payload Type. Which needs to be fixed in the next version.
2322- *
2323- * @author Thiago Camargo
2324- */
2325-
2326-public class ScreenShareMediaManager extends JingleMediaManager {
2327-
2328-    public static final String MEDIA_NAME = "ScreenShare";
2329-
2330-    private List<PayloadType> payloads = new ArrayList<PayloadType>();
2331-
2332-    private ImageDecoder decoder = null;
2333-    private ImageEncoder encoder = null;
2334-
2335-    public ScreenShareMediaManager(JingleTransportManager transportManager) {
2336-        super(transportManager);
2337-        setupPayloads();
2338-    }
2339-
2340-    /**
2341-     * Setup API supported Payloads
2342-     */
2343-    private void setupPayloads() {
2344-        payloads.add(new PayloadType.Audio(30, "sshare"));
2345-    }
2346-
2347-    /**
2348-     * Return all supported Payloads for this Manager.
2349-     *
2350-     * @return The Payload List
2351-     */
2352-    public List<PayloadType> getPayloads() {
2353-        return payloads;
2354-    }
2355-
2356-    /**
2357-     * Returns a new JingleMediaSession
2358-     *
2359-     * @param payloadType payloadType
2360-     * @param remote      remote Candidate
2361-     * @param local       local Candidate
2362-     * @return JingleMediaSession JingleMediaSession
2363-     */
2364-    public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
2365-        ScreenShareSession session = null;
2366-        session = new ScreenShareSession(payloadType, remote, local, "Screen", jingleSession);
2367-        if (encoder != null) {
2368-            session.setEncoder(encoder);
2369-        }
2370-        if (decoder != null) {
2371-            session.setDecoder(decoder);
2372-        }
2373-        return session;
2374-    }
2375-
2376-    public PayloadType getPreferredPayloadType() {
2377-        return super.getPreferredPayloadType();
2378-    }
2379-
2380-    public ImageDecoder getDecoder() {
2381-        return decoder;
2382-    }
2383-
2384-    public void setDecoder(ImageDecoder decoder) {
2385-        this.decoder = decoder;
2386-    }
2387-
2388-    public ImageEncoder getEncoder() {
2389-        return encoder;
2390-    }
2391-
2392-    public void setEncoder(ImageEncoder encoder) {
2393-        this.encoder = encoder;
2394-    }
2395-
2396-    public  String getName() {
2397-        return MEDIA_NAME;
2398-    }
2399-}
2400Index: org/jivesoftware/smackx/jingle/mediaimpl/multi/MultiMediaManager.java
2401===================================================================
2402--- org/jivesoftware/smackx/jingle/mediaimpl/multi/MultiMediaManager.java	(revision 11644)
2403+++ org/jivesoftware/smackx/jingle/mediaimpl/multi/MultiMediaManager.java	(working copy)
2404@@ -1,106 +0,0 @@
2405-/**
2406- * $RCSfile: MultiMediaManager.java,v $
2407- * $Revision: 1.3 $
2408- * $Date: 25/12/2006
2409- * <p/>
2410- * Copyright 2003-2006 Jive Software.
2411- * <p/>
2412- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
2413- * you may not use this file except in compliance with the License.
2414- * You may obtain a copy of the License at
2415- * <p/>
2416- * http://www.apache.org/licenses/LICENSE-2.0
2417- * <p/>
2418- * Unless required by applicable law or agreed to in writing, software
2419- * distributed under the License is distributed on an "AS IS" BASIS,
2420- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2421- * See the License for the specific language governing permissions and
2422- * limitations under the License.
2423- */
2424-
2425-package org.jivesoftware.smackx.jingle.mediaimpl.multi;
2426-
2427-import org.jivesoftware.smackx.jingle.JingleSession;
2428-import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
2429-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
2430-import org.jivesoftware.smackx.jingle.media.PayloadType;
2431-import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
2432-import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
2433-
2434-import java.util.ArrayList;
2435-import java.util.List;
2436-
2437-/**
2438- * Implements a MultiMediaManager using other JingleMediaManager implementations.
2439- * It supports every Codecs that JingleMediaManagers added has.
2440- *
2441- * @author Thiago Camargo
2442- */
2443-
2444-public class MultiMediaManager extends JingleMediaManager {
2445-
2446-    public static final String MEDIA_NAME = "Multi";
2447-
2448-    private List<JingleMediaManager> managers = new ArrayList<JingleMediaManager>();
2449-
2450-    private PayloadType preferredPayloadType = null;
2451-
2452-    public MultiMediaManager(JingleTransportManager transportManager) {
2453-        super(transportManager);
2454-    }
2455-
2456-    public void addMediaManager(JingleMediaManager manager) {
2457-        managers.add(manager);
2458-    }
2459-
2460-    public void removeMediaManager(JingleMediaManager manager) {
2461-        managers.remove(manager);
2462-    }
2463-
2464-    /**
2465-     * Return all supported Payloads for this Manager.
2466-     *
2467-     * @return The Payload List
2468-     */
2469-    public List<PayloadType> getPayloads() {
2470-        List<PayloadType> list = new ArrayList<PayloadType>();
2471-        if (preferredPayloadType != null) list.add(preferredPayloadType);
2472-        for (JingleMediaManager manager : managers) {
2473-            for (PayloadType payloadType : manager.getPayloads()) {
2474-                if (!list.contains(payloadType) && !payloadType.equals(preferredPayloadType))
2475-                    list.add(payloadType);
2476-            }
2477-        }
2478-        return list;
2479-    }
2480-
2481-    /**
2482-     * Returns a new JingleMediaSession
2483-     *
2484-     * @param payloadType payloadType
2485-     * @param remote      remote Candidate
2486-     * @param local       local Candidate
2487-     * @return JingleMediaSession JingleMediaSession
2488-     */
2489-    public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
2490-        for (JingleMediaManager manager : managers) {
2491-            if (manager.getPayloads().contains(payloadType)) {
2492-                return manager.createMediaSession(payloadType, remote, local, jingleSession);
2493-            }
2494-        }
2495-        return null;
2496-    }
2497-
2498-    public PayloadType getPreferredPayloadType() {
2499-        if (preferredPayloadType != null) return preferredPayloadType;
2500-        return super.getPreferredPayloadType();
2501-    }
2502-
2503-    public void setPreferredPayloadType(PayloadType preferredPayloadType) {
2504-        this.preferredPayloadType = preferredPayloadType;
2505-    }
2506-
2507-    public  String getName() {
2508-        return MEDIA_NAME;
2509-    }
2510-}
2511Index: org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioMediaSession.java
2512===================================================================
2513--- org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioMediaSession.java	(revision 11644)
2514+++ org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioMediaSession.java	(working copy)
2515@@ -1,165 +0,0 @@
2516-/**
2517- * $RCSfile: AudioMediaSession.java,v $
2518- * $Revision: 1.1 $
2519- * $Date: 08/11/2006
2520- * <p/>
2521- * Copyright 2003-2006 Jive Software.
2522- * <p/>
2523- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
2524- * you may not use this file except in compliance with the License.
2525- * You may obtain a copy of the License at
2526- * <p/>
2527- * http://www.apache.org/licenses/LICENSE-2.0
2528- * <p/>
2529- * Unless required by applicable law or agreed to in writing, software
2530- * distributed under the License is distributed on an "AS IS" BASIS,
2531- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2532- * See the License for the specific language governing permissions and
2533- * limitations under the License.
2534- */
2535-
2536-package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
2537-
2538-import java.io.IOException;
2539-import java.net.ServerSocket;
2540-
2541-import javax.media.MediaLocator;
2542-
2543-import org.jivesoftware.smackx.jingle.JingleSession;
2544-import org.jivesoftware.smackx.jingle.SmackLogger;
2545-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
2546-import org.jivesoftware.smackx.jingle.media.PayloadType;
2547-import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
2548-
2549-/**
2550- * This Class implements a complete JingleMediaSession.
2551- * It sould be used to transmit and receive audio captured from the Mic.
2552- * This Class should be automaticly controlled by JingleSession.
2553- * But you could also use in any VOIP application.
2554- * For better NAT Traversal support this implementation don't support only receive or only transmit.
2555- * To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit()
2556- *
2557- * @author Thiago Camargo
2558- */
2559-public class AudioMediaSession extends JingleMediaSession {
2560-
2561-	private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioMediaSession.class);
2562-
2563-	private AudioChannel audioChannel;
2564-
2565-    /**
2566-     * Creates a org.jivesoftware.jingleaudio.jmf.AudioMediaSession with defined payload type, remote and local candidates
2567-     *
2568-     * @param payloadType Payload of the jmf
2569-     * @param remote      the remote information. The candidate that the jmf will be sent to.
2570-     * @param local       the local information. The candidate that will receive the jmf
2571-     * @param locator     media locator
2572-     */
2573-    public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote,
2574-            final TransportCandidate local, String locator, JingleSession jingleSession) {
2575-        super(payloadType, remote, local, locator==null?"dsound://":locator,jingleSession);
2576-        initialize();
2577-    }
2578-
2579-    /**
2580-     * Initialize the Audio Channel to make it able to send and receive audio
2581-     */
2582-    public void initialize() {
2583-
2584-        String ip;
2585-        String localIp;
2586-        int localPort;
2587-        int remotePort;
2588-
2589-        if (this.getLocal().getSymmetric() != null) {
2590-            ip = this.getLocal().getIp();
2591-            localIp = this.getLocal().getLocalIp();
2592-            localPort = getFreePort();
2593-            remotePort = this.getLocal().getSymmetric().getPort();
2594-
2595-            LOGGER.debug(this.getLocal().getConnection() + " " + ip + ": " + localPort + "->" + remotePort);
2596-
2597-        }
2598-        else {
2599-            ip = this.getRemote().getIp();
2600-            localIp = this.getLocal().getLocalIp();
2601-            localPort = this.getLocal().getPort();
2602-            remotePort = this.getRemote().getPort();
2603-        }
2604-
2605-        audioChannel = new AudioChannel(new MediaLocator(this.getMediaLocator()), localIp, ip, localPort, remotePort, AudioFormatUtils.getAudioFormat(this.getPayloadType()),this);
2606-    }
2607-
2608-    /**
2609-     * Starts transmission and for NAT Traversal reasons start receiving also.
2610-     */
2611-    public void startTrasmit() {
2612-        audioChannel.start();
2613-    }
2614-
2615-    /**
2616-     * Set transmit activity. If the active is true, the instance should trasmit.
2617-     * If it is set to false, the instance should pause transmit.
2618-     *
2619-     * @param active active state
2620-     */
2621-    public void setTrasmit(boolean active) {
2622-        audioChannel.setTrasmit(active);
2623-    }
2624-
2625-    /**
2626-     * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
2627-     */
2628-    public void startReceive() {
2629-        // Do nothing
2630-    }
2631-
2632-    /**
2633-     * Stops transmission and for NAT Traversal reasons stop receiving also.
2634-     */
2635-    public void stopTrasmit() {
2636-        if (audioChannel != null)
2637-            audioChannel.stop();
2638-    }
2639-
2640-    /**
2641-     * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
2642-     */
2643-    public void stopReceive() {
2644-        // Do nothing
2645-    }
2646-
2647-    /**
2648-     * Obtain a free port we can use.
2649-     *
2650-     * @return A free port number.
2651-     */
2652-    protected int getFreePort() {
2653-        ServerSocket ss;
2654-        int freePort = 0;
2655-
2656-        for (int i = 0; i < 10; i++) {
2657-            freePort = (int) (10000 + Math.round(Math.random() * 10000));
2658-            freePort = freePort % 2 == 0 ? freePort : freePort + 1;
2659-            try {
2660-                ss = new ServerSocket(freePort);
2661-                freePort = ss.getLocalPort();
2662-                ss.close();
2663-                return freePort;
2664-            }
2665-            catch (IOException e) {
2666-                e.printStackTrace();
2667-            }
2668-        }
2669-        try {
2670-            ss = new ServerSocket(0);
2671-            freePort = ss.getLocalPort();
2672-            ss.close();
2673-        }
2674-        catch (IOException e) {
2675-            e.printStackTrace();
2676-        }
2677-        return freePort;
2678-    }
2679-
2680-}
2681Index: org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioReceiver.java
2682===================================================================
2683--- org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioReceiver.java	(revision 11644)
2684+++ org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioReceiver.java	(working copy)
2685@@ -1,171 +0,0 @@
2686-/**
2687- * $RCSfile: AudioReceiver.java,v $
2688- * $Revision: 1.1 $
2689- * $Date: 08/11/2006
2690- * <p/>
2691- * Copyright 2003-2006 Jive Software.
2692- * <p/>
2693- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
2694- * you may not use this file except in compliance with the License.
2695- * You may obtain a copy of the License at
2696- * <p/>
2697- * http://www.apache.org/licenses/LICENSE-2.0
2698- * <p/>
2699- * Unless required by applicable law or agreed to in writing, software
2700- * distributed under the License is distributed on an "AS IS" BASIS,
2701- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2702- * See the License for the specific language governing permissions and
2703- * limitations under the License.
2704- */
2705-
2706-package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
2707-
2708-import javax.media.ControllerErrorEvent;
2709-import javax.media.ControllerEvent;
2710-import javax.media.ControllerListener;
2711-import javax.media.Player;
2712-import javax.media.RealizeCompleteEvent;
2713-import javax.media.protocol.DataSource;
2714-import javax.media.rtp.Participant;
2715-import javax.media.rtp.RTPControl;
2716-import javax.media.rtp.ReceiveStream;
2717-import javax.media.rtp.ReceiveStreamListener;
2718-import javax.media.rtp.SessionListener;
2719-import javax.media.rtp.event.ByeEvent;
2720-import javax.media.rtp.event.NewParticipantEvent;
2721-import javax.media.rtp.event.NewReceiveStreamEvent;
2722-import javax.media.rtp.event.ReceiveStreamEvent;
2723-import javax.media.rtp.event.RemotePayloadChangeEvent;
2724-import javax.media.rtp.event.SessionEvent;
2725-import javax.media.rtp.event.StreamMappedEvent;
2726-
2727-import org.jivesoftware.smackx.jingle.SmackLogger;
2728-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
2729-
2730-/**
2731- * This class implements receive methods and listeners to be used in AudioChannel
2732- *
2733- * @author Thiago Camargo
2734- */
2735-public class AudioReceiver implements ReceiveStreamListener, SessionListener,
2736-        ControllerListener {
2737-
2738-	private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioReceiver.class);
2739-
2740-	boolean dataReceived = false;
2741-
2742-    Object dataSync;
2743-    JingleMediaSession jingleMediaSession;
2744-
2745-    public AudioReceiver(final Object dataSync, final JingleMediaSession jingleMediaSession) {
2746-        this.dataSync = dataSync;
2747-        this.jingleMediaSession = jingleMediaSession;
2748-    }
2749-
2750-    /**
2751-     * JingleSessionListener.
2752-     */
2753-    public synchronized void update(SessionEvent evt) {
2754-        if (evt instanceof NewParticipantEvent) {
2755-            Participant p = ((NewParticipantEvent) evt).getParticipant();
2756-            LOGGER.error("  - A new participant had just joined: " + p.getCNAME());
2757-        }
2758-    }
2759-
2760-    /**
2761-     * ReceiveStreamListener
2762-     */
2763-    public synchronized void update(ReceiveStreamEvent evt) {
2764-
2765-        Participant participant = evt.getParticipant();    // could be null.
2766-        ReceiveStream stream = evt.getReceiveStream();  // could be null.
2767-
2768-        if (evt instanceof RemotePayloadChangeEvent) {
2769-            LOGGER.error("  - Received an RTP PayloadChangeEvent.");
2770-            LOGGER.error("Sorry, cannot handle payload change.");
2771-
2772-        }
2773-        else if (evt instanceof NewReceiveStreamEvent) {
2774-
2775-            try {
2776-                stream = evt.getReceiveStream();
2777-                DataSource ds = stream.getDataSource();
2778-
2779-                // Find out the formats.
2780-                RTPControl ctl = (RTPControl) ds.getControl("javax.jmf.rtp.RTPControl");
2781-                if (ctl != null) {
2782-                    LOGGER.error("  - Recevied new RTP stream: " + ctl.getFormat());
2783-                }
2784-                else
2785-                    LOGGER.error("  - Recevied new RTP stream");
2786-
2787-                if (participant == null)
2788-                    LOGGER.error("      The sender of this stream had yet to be identified.");
2789-                else {
2790-                    LOGGER.error("      The stream comes from: " + participant.getCNAME());
2791-                }
2792-
2793-                // create a player by passing datasource to the Media Manager
2794-                Player p = javax.media.Manager.createPlayer(ds);
2795-                if (p == null)
2796-                    return;
2797-
2798-                p.addControllerListener(this);
2799-                p.realize();
2800-                jingleMediaSession.mediaReceived(participant != null ? participant.getCNAME() : "");
2801-
2802-                // Notify intialize() that a new stream had arrived.
2803-                synchronized (dataSync) {
2804-                    dataReceived = true;
2805-                    dataSync.notifyAll();
2806-                }
2807-
2808-            }
2809-            catch (Exception e) {
2810-                LOGGER.error("NewReceiveStreamEvent exception " + e.getMessage());
2811-                return;
2812-            }
2813-
2814-        }
2815-        else if (evt instanceof StreamMappedEvent) {
2816-
2817-            if (stream != null && stream.getDataSource() != null) {
2818-                DataSource ds = stream.getDataSource();
2819-                // Find out the formats.
2820-                RTPControl ctl = (RTPControl) ds.getControl("javax.jmf.rtp.RTPControl");
2821-                LOGGER.error("  - The previously unidentified stream ");
2822-                if (ctl != null)
2823-                    LOGGER.error("      " + ctl.getFormat());
2824-                LOGGER.error("      had now been identified as sent by: " + participant.getCNAME());
2825-            }
2826-        }
2827-        else if (evt instanceof ByeEvent) {
2828-
2829-            LOGGER.error("  - Got \"bye\" from: " + participant.getCNAME());
2830-
2831-        }
2832-
2833-    }
2834-
2835-    /**
2836-     * ControllerListener for the Players.
2837-     */
2838-    public synchronized void controllerUpdate(ControllerEvent ce) {
2839-
2840-        Player p = (Player) ce.getSourceController();
2841-
2842-        if (p == null)
2843-            return;
2844-
2845-        // Get this when the internal players are realized.
2846-        if (ce instanceof RealizeCompleteEvent) {
2847-            p.start();
2848-        }
2849-
2850-        if (ce instanceof ControllerErrorEvent) {
2851-            p.removeControllerListener(this);
2852-            LOGGER.error("Receiver internal error: " + ce);
2853-        }
2854-
2855-    }
2856-}
2857Index: org/jivesoftware/smackx/jingle/mediaimpl/jmf/JmfMediaManager.java
2858===================================================================
2859--- org/jivesoftware/smackx/jingle/mediaimpl/jmf/JmfMediaManager.java	(revision 11644)
2860+++ org/jivesoftware/smackx/jingle/mediaimpl/jmf/JmfMediaManager.java	(working copy)
2861@@ -1,170 +0,0 @@
2862-/**
2863- * $RCSfile: JmfMediaManager.java,v $
2864- * $Revision: 1.3 $
2865- * $Date: 08/11/2006
2866- * <p/>
2867- * Copyright 2003-2006 Jive Software.
2868- * <p/>
2869- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
2870- * you may not use this file except in compliance with the License.
2871- * You may obtain a copy of the License at
2872- * <p/>
2873- * http://www.apache.org/licenses/LICENSE-2.0
2874- * <p/>
2875- * Unless required by applicable law or agreed to in writing, software
2876- * distributed under the License is distributed on an "AS IS" BASIS,
2877- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2878- * See the License for the specific language governing permissions and
2879- * limitations under the License.
2880- */
2881-
2882-package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
2883-
2884-import java.io.File;
2885-import java.io.IOException;
2886-import java.util.ArrayList;
2887-import java.util.List;
2888-
2889-import org.jivesoftware.smackx.jingle.JingleSession;
2890-import org.jivesoftware.smackx.jingle.SmackLogger;
2891-import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
2892-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
2893-import org.jivesoftware.smackx.jingle.media.PayloadType;
2894-import org.jivesoftware.smackx.jingle.mediaimpl.JMFInit;
2895-import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
2896-import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
2897-
2898-/**
2899- * Implements a jingleMediaManager using JMF based API.
2900- * It supports GSM and G723 codecs.
2901- * <i>This API only currently works on windows and Mac.</i>
2902- *
2903- * @author Thiago Camargo
2904- */
2905-public class JmfMediaManager extends JingleMediaManager {
2906-
2907-	private static final SmackLogger LOGGER = SmackLogger.getLogger(JmfMediaManager.class);
2908-
2909-	public static final String MEDIA_NAME = "JMF";
2910-
2911-
2912-    private List<PayloadType> payloads = new ArrayList<PayloadType>();
2913-    private String mediaLocator = null;
2914-
2915-    /**
2916-     * Creates a Media Manager instance
2917-     */
2918-    public JmfMediaManager(JingleTransportManager transportManager) {
2919-        super(transportManager);
2920-        setupPayloads();
2921-    }
2922-
2923-    /**
2924-     * Creates a Media Manager instance
2925-     *
2926-     * @param mediaLocator Media Locator
2927-     */
2928-    public JmfMediaManager(String mediaLocator, JingleTransportManager transportManager) {
2929-        super(transportManager);
2930-        this.mediaLocator = mediaLocator;
2931-        setupPayloads();
2932-    }
2933-
2934-    /**
2935-     * Returns a new jingleMediaSession
2936-     *
2937-     * @param payloadType payloadType
2938-     * @param remote      remote Candidate
2939-     * @param local       local Candidate
2940-     * @return JingleMediaSession
2941-     */
2942-    public JingleMediaSession createMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
2943-        return new AudioMediaSession(payloadType, remote, local, mediaLocator, jingleSession);
2944-    }
2945-
2946-    /**
2947-     * Setup API supported Payloads
2948-     */
2949-    private void setupPayloads() {
2950-        payloads.add(new PayloadType.Audio(3, "gsm"));
2951-        payloads.add(new PayloadType.Audio(4, "g723"));
2952-        payloads.add(new PayloadType.Audio(0, "PCMU", 16000));
2953-    }
2954-
2955-    /**
2956-     * Return all supported Payloads for this Manager
2957-     *
2958-     * @return The Payload List
2959-     */
2960-    public List<PayloadType> getPayloads() {
2961-        return payloads;
2962-    }
2963-
2964-    /**
2965-     * Return the media locator or null if not defined
2966-     *
2967-     * @return media locator
2968-     */
2969-    public String getMediaLocator() {
2970-        return mediaLocator;
2971-    }
2972-
2973-    /**
2974-     * Set the media locator
2975-     *
2976-     * @param mediaLocator media locator or null to use default
2977-     */
2978-    public void setMediaLocator(String mediaLocator) {
2979-        this.mediaLocator = mediaLocator;
2980-    }
2981-
2982-    /**
2983-     * Runs JMFInit the first time the application is started so that capture
2984-     * devices are properly detected and initialized by JMF.
2985-     */
2986-    public static void setupJMF() {
2987-        // .jmf is the place where we store the jmf.properties file used
2988-        // by JMF. if the directory does not exist or it does not contain
2989-        // a jmf.properties file. or if the jmf.properties file has 0 length
2990-        // then this is the first time we're running and should continue to
2991-        // with JMFInit
2992-        String homeDir = System.getProperty("user.home");
2993-        File jmfDir = new File(homeDir, ".jmf");
2994-        String classpath = System.getProperty("java.class.path");
2995-        classpath += System.getProperty("path.separator")
2996-                + jmfDir.getAbsolutePath();
2997-        System.setProperty("java.class.path", classpath);
2998-
2999-        if (!jmfDir.exists())
3000-            jmfDir.mkdir();
3001-
3002-        File jmfProperties = new File(jmfDir, "jmf.properties");
3003-
3004-        if (!jmfProperties.exists()) {
3005-            try {
3006-                jmfProperties.createNewFile();
3007-            }
3008-            catch (IOException ex) {
3009-                LOGGER.debug("Failed to create jmf.properties");
3010-                ex.printStackTrace();
3011-            }
3012-        }
3013-
3014-        // if we're running on linux checkout that libjmutil.so is where it
3015-        // should be and put it there.
3016-        runLinuxPreInstall();
3017-
3018-        //if (jmfProperties.length() == 0) {
3019-        new JMFInit(null, false);
3020-        //}
3021-
3022-    }
3023-
3024-    private static void runLinuxPreInstall() {
3025-        // @TODO Implement Linux Pre-Install
3026-    }
3027-
3028-    public  String getName() {
3029-        return MEDIA_NAME;
3030-    }
3031-}
3032Index: org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioChannel.java
3033===================================================================
3034--- org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioChannel.java	(revision 11644)
3035+++ org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioChannel.java	(working copy)
3036@@ -1,553 +0,0 @@
3037-/**
3038- * $RCSfile: AudioChannel.java,v $
3039- * $Revision: 1.1 $
3040- * $Date: 08/11/2006
3041- * <p/>
3042- * Copyright 2003-2006 Jive Software.
3043- * <p/>
3044- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
3045- * you may not use this file except in compliance with the License.
3046- * You may obtain a copy of the License at
3047- * <p/>
3048- * http://www.apache.org/licenses/LICENSE-2.0
3049- * <p/>
3050- * Unless required by applicable law or agreed to in writing, software
3051- * distributed under the License is distributed on an "AS IS" BASIS,
3052- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3053- * See the License for the specific language governing permissions and
3054- * limitations under the License.
3055- */
3056-package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
3057-
3058-import java.io.IOException;
3059-import java.net.InetAddress;
3060-import java.net.UnknownHostException;
3061-import java.util.ArrayList;
3062-import java.util.List;
3063-
3064-import javax.media.Codec;
3065-import javax.media.Controller;
3066-import javax.media.ControllerClosedEvent;
3067-import javax.media.ControllerEvent;
3068-import javax.media.ControllerListener;
3069-import javax.media.Format;
3070-import javax.media.MediaLocator;
3071-import javax.media.NoProcessorException;
3072-import javax.media.Processor;
3073-import javax.media.UnsupportedPlugInException;
3074-import javax.media.control.BufferControl;
3075-import javax.media.control.PacketSizeControl;
3076-import javax.media.control.TrackControl;
3077-import javax.media.format.AudioFormat;
3078-import javax.media.protocol.ContentDescriptor;
3079-import javax.media.protocol.DataSource;
3080-import javax.media.protocol.PushBufferDataSource;
3081-import javax.media.protocol.PushBufferStream;
3082-import javax.media.rtp.InvalidSessionAddressException;
3083-import javax.media.rtp.RTPManager;
3084-import javax.media.rtp.SendStream;
3085-import javax.media.rtp.SessionAddress;
3086-
3087-import org.jivesoftware.smackx.jingle.SmackLogger;
3088-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
3089-
3090-/**
3091- * An Easy to use Audio Channel implemented using JMF.
3092- * It sends and receives jmf for and from desired IPs and ports.
3093- * Also has a rport Symetric behavior for better NAT Traversal.
3094- * It send data from a defined port and receive data in the same port, making NAT binds easier.
3095- * <p/>
3096- * Send from portA to portB and receive from portB in portA.
3097- * <p/>
3098- * Sending
3099- * portA ---> portB
3100- * <p/>
3101- * Receiving
3102- * portB ---> portA
3103- * <p/>
3104- * <i>Transmit and Receive are interdependents. To receive you MUST trasmit. </i>
3105- *
3106- * @author Thiago Camargo
3107- */
3108-public class AudioChannel {
3109-
3110-	private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioChannel.class);
3111-
3112-	private MediaLocator locator;
3113-    private String localIpAddress;
3114-    private String remoteIpAddress;
3115-    private int localPort;
3116-    private int portBase;
3117-    private Format format;
3118-
3119-    private Processor processor = null;
3120-    private RTPManager rtpMgrs[];
3121-    private DataSource dataOutput = null;
3122-    private AudioReceiver audioReceiver;
3123-
3124-    private List<SendStream> sendStreams = new ArrayList<SendStream>();
3125-
3126-    private JingleMediaSession jingleMediaSession;
3127-
3128-    private boolean started = false;
3129-
3130-    /**
3131-     * Creates an Audio Channel for a desired jmf locator. For instance: new MediaLocator("dsound://")
3132-     *
3133-     * @param locator         media locator
3134-     * @param localIpAddress  local IP address
3135-     * @param remoteIpAddress remote IP address
3136-     * @param localPort       local port number
3137-     * @param remotePort      remote port number
3138-     * @param format          audio format
3139-     */
3140-    public AudioChannel(MediaLocator locator,
3141-            String localIpAddress,
3142-            String remoteIpAddress,
3143-            int localPort,
3144-            int remotePort,
3145-            Format format, JingleMediaSession jingleMediaSession) {
3146-
3147-        this.locator = locator;
3148-        this.localIpAddress = localIpAddress;
3149-        this.remoteIpAddress = remoteIpAddress;
3150-        this.localPort = localPort;
3151-        this.portBase = remotePort;
3152-        this.format = format;
3153-        this.jingleMediaSession = jingleMediaSession;
3154-    }
3155-
3156-    /**
3157-     * Starts the transmission. Returns null if transmission started ok.
3158-     * Otherwise it returns a string with the reason why the setup failed.
3159-     * Starts receive also.
3160-     *
3161-     * @return result description
3162-     */
3163-    public synchronized String start() {
3164-        if (started) return null;
3165-
3166-        // Create a processor for the specified jmf locator
3167-        String result = createProcessor();
3168-        if (result != null) {
3169-            started = false;
3170-        }
3171-
3172-        // Create an RTP session to transmit the output of the
3173-        // processor to the specified IP address and port no.
3174-        result = createTransmitter();
3175-        if (result != null) {
3176-            processor.close();
3177-            processor = null;
3178-            started = false;
3179-        }
3180-        else {
3181-            started = true;
3182-        }
3183-
3184-        // Start the transmission
3185-        processor.start();
3186-
3187-        return null;
3188-    }
3189-
3190-    /**
3191-     * Stops the transmission if already started.
3192-     * Stops the receiver also.
3193-     */
3194-    public void stop() {
3195-        if (!started) return;
3196-        synchronized (this) {
3197-            try {
3198-                started = false;
3199-                if (processor != null) {
3200-                    processor.stop();
3201-                    processor = null;
3202-
3203-                    for (RTPManager rtpMgr : rtpMgrs) {
3204-                        rtpMgr.removeReceiveStreamListener(audioReceiver);
3205-                        rtpMgr.removeSessionListener(audioReceiver);
3206-                        rtpMgr.removeTargets("Session ended.");
3207-                        rtpMgr.dispose();
3208-                    }
3209-
3210-                    sendStreams.clear();
3211-
3212-                }
3213-            }
3214-            catch (Exception e) {
3215-                e.printStackTrace();
3216-            }
3217-        }
3218-    }
3219-
3220-    private String createProcessor() {
3221-        if (locator == null)
3222-            return "Locator is null";
3223-
3224-        DataSource ds;
3225-
3226-        try {
3227-            ds = javax.media.Manager.createDataSource(locator);
3228-        }
3229-        catch (Exception e) {
3230-            // Try JavaSound Locator as a last resort
3231-            try {
3232-                ds = javax.media.Manager.createDataSource(new MediaLocator("javasound://"));
3233-            }
3234-            catch (Exception ee) {
3235-                return "Couldn't create DataSource";
3236-            }
3237-        }
3238-
3239-        // Try to create a processor to handle the input jmf locator
3240-        try {
3241-            processor = javax.media.Manager.createProcessor(ds);
3242-        }
3243-        catch (NoProcessorException npe) {
3244-            npe.printStackTrace();
3245-            return "Couldn't create processor";
3246-        }
3247-        catch (IOException ioe) {
3248-            ioe.printStackTrace();
3249-            return "IOException creating processor";
3250-        }
3251-
3252-        // Wait for it to configure
3253-        boolean result = waitForState(processor, Processor.Configured);
3254-        if (!result){
3255-            return "Couldn't configure processor";
3256-        }
3257-
3258-        // Get the tracks from the processor
3259-        TrackControl[] tracks = processor.getTrackControls();
3260-
3261-        // Do we have atleast one track?
3262-        if (tracks == null || tracks.length < 1){
3263-            return "Couldn't find tracks in processor";
3264-        }
3265-
3266-        // Set the output content descriptor to RAW_RTP
3267-        // This will limit the supported formats reported from
3268-        // Track.getSupportedFormats to only valid RTP formats.
3269-        ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP);
3270-        processor.setContentDescriptor(cd);
3271-
3272-        Format supported[];
3273-        Format chosen = null;
3274-        boolean atLeastOneTrack = false;
3275-
3276-        // Program the tracks.
3277-        for (int i = 0; i < tracks.length; i++) {
3278-            if (tracks[i].isEnabled()) {
3279-
3280-                supported = tracks[i].getSupportedFormats();
3281-
3282-                if (supported.length > 0) {
3283-                    for (Format format : supported) {
3284-                        if (format instanceof AudioFormat) {
3285-                            if (this.format.matches(format))
3286-                                chosen = format;
3287-                        }
3288-                    }
3289-                    if (chosen != null) {
3290-                        tracks[i].setFormat(chosen);
3291-                        LOGGER.error("Track " + i + " is set to transmit as:");
3292-                        LOGGER.error("  " + chosen);
3293-
3294-                        if (tracks[i].getFormat() instanceof AudioFormat) {
3295-                            int packetRate = 20;
3296-                            PacketSizeControl pktCtrl = (PacketSizeControl) processor.getControl(PacketSizeControl.class.getName());
3297-                            if (pktCtrl != null) {
3298-                                try {
3299-                                    pktCtrl.setPacketSize(getPacketSize(tracks[i].getFormat(), packetRate));
3300-                                }
3301-                                catch (IllegalArgumentException e) {
3302-                                    pktCtrl.setPacketSize(80);
3303-                                    // Do nothing
3304-                                }
3305-                            }
3306-
3307-                            if (tracks[i].getFormat().getEncoding().equals(AudioFormat.ULAW_RTP)) {
3308-                                Codec codec[] = new Codec[3];
3309-
3310-                                codec[0] = new com.ibm.media.codec.audio.rc.RCModule();
3311-                                codec[1] = new com.ibm.media.codec.audio.ulaw.JavaEncoder();
3312-                                codec[2] = new com.sun.media.codec.audio.ulaw.Packetizer();
3313-                                ((com.sun.media.codec.audio.ulaw.Packetizer) codec
3314-                                        [2]).setPacketSize(160);
3315-
3316-                                try {
3317-                                    tracks[i].setCodecChain(codec);
3318-                                }
3319-                                catch (UnsupportedPlugInException e) {
3320-                                    e.printStackTrace();
3321-                                }
3322-                            }
3323-
3324-                        }
3325-
3326-                        atLeastOneTrack = true;
3327-                    }
3328-                    else
3329-                        tracks[i].setEnabled(false);
3330-                }
3331-                else
3332-                    tracks[i].setEnabled(false);
3333-            }
3334-        }
3335-
3336-        if (!atLeastOneTrack)
3337-            return "Couldn't set any of the tracks to a valid RTP format";
3338-
3339-        result = waitForState(processor, Controller.Realized);
3340-        if (!result)
3341-            return "Couldn't realize processor";
3342-
3343-        // Get the output data source of the processor
3344-        dataOutput = processor.getDataOutput();
3345-
3346-        return null;
3347-    }
3348-
3349-    /**
3350-     * Get the best packet size for a given codec and a codec rate
3351-     *
3352-     * @param codecFormat
3353-     * @param milliseconds
3354-     * @return
3355-     * @throws IllegalArgumentException
3356-     */
3357-    private int getPacketSize(Format codecFormat, int milliseconds) throws IllegalArgumentException {
3358-        String encoding = codecFormat.getEncoding();
3359-        if (encoding.equalsIgnoreCase(AudioFormat.GSM) ||
3360-                encoding.equalsIgnoreCase(AudioFormat.GSM_RTP)) {
3361-            return milliseconds * 4; // 1 byte per millisec
3362-        }
3363-        else if (encoding.equalsIgnoreCase(AudioFormat.ULAW) ||
3364-                encoding.equalsIgnoreCase(AudioFormat.ULAW_RTP)) {
3365-            return milliseconds * 8;
3366-        }
3367-        else {
3368-            throw new IllegalArgumentException("Unknown codec type");
3369-        }
3370-    }
3371-
3372-    /**
3373-     * Use the RTPManager API to create sessions for each jmf
3374-     * track of the processor.
3375-     *
3376-     * @return description
3377-     */
3378-    private String createTransmitter() {
3379-
3380-        // Cheated.  Should have checked the type.
3381-        PushBufferDataSource pbds = (PushBufferDataSource) dataOutput;
3382-        PushBufferStream pbss[] = pbds.getStreams();
3383-
3384-        rtpMgrs = new RTPManager[pbss.length];
3385-        SessionAddress localAddr, destAddr;
3386-        InetAddress ipAddr;
3387-        SendStream sendStream;
3388-        audioReceiver = new AudioReceiver(this, jingleMediaSession);
3389-        int port;
3390-
3391-        for (int i = 0; i < pbss.length; i++) {
3392-            try {
3393-                rtpMgrs[i] = RTPManager.newInstance();
3394-
3395-                port = portBase + 2 * i;
3396-                ipAddr = InetAddress.getByName(remoteIpAddress);
3397-
3398-                localAddr = new SessionAddress(InetAddress.getByName(this.localIpAddress),
3399-                        localPort);
3400-
3401-                destAddr = new SessionAddress(ipAddr, port);
3402-
3403-                rtpMgrs[i].addReceiveStreamListener(audioReceiver);
3404-                rtpMgrs[i].addSessionListener(audioReceiver);
3405-
3406-                BufferControl bc = (BufferControl) rtpMgrs[i].getControl("javax.media.control.BufferControl");
3407-                if (bc != null) {
3408-                    int bl = 160;
3409-                    bc.setBufferLength(bl);
3410-                }
3411-
3412-                try {
3413-
3414-                    rtpMgrs[i].initialize(localAddr);
3415-
3416-                }
3417-                catch (InvalidSessionAddressException e) {
3418-                    // In case the local address is not allowed to read, we user another local address
3419-                    SessionAddress sessAddr = new SessionAddress();
3420-                    localAddr = new SessionAddress(sessAddr.getDataAddress(),
3421-                            localPort);
3422-                    rtpMgrs[i].initialize(localAddr);
3423-                }
3424-
3425-                rtpMgrs[i].addTarget(destAddr);
3426-
3427-                LOGGER.error("Created RTP session at " + localPort + " to: " + remoteIpAddress + " " + port);
3428-
3429-                sendStream = rtpMgrs[i].createSendStream(dataOutput, i);
3430-
3431-                sendStreams.add(sendStream);
3432-
3433-                sendStream.start();
3434-
3435-            }
3436-            catch (Exception e) {
3437-                e.printStackTrace();
3438-                return e.getMessage();
3439-            }
3440-        }
3441-
3442-        return null;
3443-    }
3444-
3445-    /**
3446-     * Set transmit activity. If the active is true, the instance should trasmit.
3447-     * If it is set to false, the instance should pause transmit.
3448-     *
3449-     * @param active active state
3450-     */
3451-    public void setTrasmit(boolean active) {
3452-        for (SendStream sendStream : sendStreams) {
3453-            try {
3454-                if (active) {
3455-                    sendStream.start();
3456-                    LOGGER.debug("START");
3457-                }
3458-                else {
3459-                    sendStream.stop();
3460-                    LOGGER.debug("STOP");
3461-                }
3462-            }
3463-            catch (IOException e) {
3464-                e.printStackTrace();
3465-            }
3466-
3467-        }
3468-    }
3469-
3470-    /**
3471-     * *************************************************************
3472-     * Convenience methods to handle processor's state changes.
3473-     * **************************************************************
3474-     */
3475-
3476-    private Integer stateLock = 0;
3477-    private boolean failed = false;
3478-
3479-    Integer getStateLock() {
3480-        return stateLock;
3481-    }
3482-
3483-    void setFailed() {
3484-        failed = true;
3485-    }
3486-
3487-    private synchronized boolean waitForState(Processor p, int state) {
3488-        p.addControllerListener(new StateListener());
3489-        failed = false;
3490-
3491-        // Call the required method on the processor
3492-        if (state == Processor.Configured) {
3493-            p.configure();
3494-        }
3495-        else if (state == Processor.Realized) {
3496-            p.realize();
3497-        }
3498-
3499-        // Wait until we get an event that confirms the
3500-        // success of the method, or a failure event.
3501-        // See StateListener inner class
3502-        while (p.getState() < state && !failed) {
3503-            synchronized (getStateLock()) {
3504-                try {
3505-                    getStateLock().wait();
3506-                }
3507-                catch (InterruptedException ie) {
3508-                    return false;
3509-                }
3510-            }
3511-        }
3512-
3513-        return !failed;
3514-    }
3515-
3516-    /**
3517-     * *************************************************************
3518-     * Inner Classes
3519-     * **************************************************************
3520-     */
3521-
3522-    class StateListener implements ControllerListener {
3523-
3524-        public void controllerUpdate(ControllerEvent ce) {
3525-
3526-            // If there was an error during configure or
3527-            // realize, the processor will be closed
3528-            if (ce instanceof ControllerClosedEvent)
3529-                setFailed();
3530-
3531-            // All controller events, send a notification
3532-            // to the waiting thread in waitForState method.
3533-            if (ce != null) {
3534-                synchronized (getStateLock()) {
3535-                    getStateLock().notifyAll();
3536-                }
3537-            }
3538-        }
3539-    }
3540-
3541-    public static void main(String args[]) {
3542-
3543-        InetAddress localhost;
3544-        try {
3545-            localhost = InetAddress.getLocalHost();
3546-
3547-            AudioChannel audioChannel0 = new AudioChannel(new MediaLocator("javasound://8000"), localhost.getHostAddress(), localhost.getHostAddress(), 7002, 7020, new AudioFormat(AudioFormat.GSM_RTP), null);
3548-            AudioChannel audioChannel1 = new AudioChannel(new MediaLocator("javasound://8000"), localhost.getHostAddress(), localhost.getHostAddress(), 7020, 7002, new AudioFormat(AudioFormat.GSM_RTP), null);
3549-
3550-            audioChannel0.start();
3551-            audioChannel1.start();
3552-
3553-            try {
3554-                Thread.sleep(5000);
3555-            }
3556-            catch (InterruptedException e) {
3557-                e.printStackTrace();
3558-            }
3559-
3560-            audioChannel0.setTrasmit(false);
3561-            audioChannel1.setTrasmit(false);
3562-
3563-            try {
3564-                Thread.sleep(5000);
3565-            }
3566-            catch (InterruptedException e) {
3567-                e.printStackTrace();
3568-            }
3569-
3570-            audioChannel0.setTrasmit(true);
3571-            audioChannel1.setTrasmit(true);
3572-
3573-            try {
3574-                Thread.sleep(5000);
3575-            }
3576-            catch (InterruptedException e) {
3577-                e.printStackTrace();
3578-            }
3579-
3580-            audioChannel0.stop();
3581-            audioChannel1.stop();
3582-
3583-        }
3584-        catch (UnknownHostException e) {
3585-            e.printStackTrace();
3586-        }
3587-
3588-    }
3589-}
3590\ No newline at end of file
3591Index: org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioFormatUtils.java
3592===================================================================
3593--- org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioFormatUtils.java	(revision 11644)
3594+++ org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioFormatUtils.java	(working copy)
3595@@ -1,55 +0,0 @@
3596-/**
3597- * $RCSfile: AudioFormatUtils.java,v $
3598- * $Revision: 1.1 $
3599- * $Date: 08/11/2006
3600- * <p/>
3601- * Copyright 2003-2006 Jive Software.
3602- * <p/>
3603- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
3604- * you may not use this file except in compliance with the License.
3605- * You may obtain a copy of the License at
3606- * <p/>
3607- * http://www.apache.org/licenses/LICENSE-2.0
3608- * <p/>
3609- * Unless required by applicable law or agreed to in writing, software
3610- * distributed under the License is distributed on an "AS IS" BASIS,
3611- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3612- * See the License for the specific language governing permissions and
3613- * limitations under the License.
3614- */
3615-package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
3616-
3617-import org.jivesoftware.smackx.jingle.media.PayloadType;
3618-
3619-import javax.media.format.AudioFormat;
3620-
3621-/**
3622- * Audio Format Utils.
3623- *
3624- * @author Thiago Camargo
3625- */
3626-public class AudioFormatUtils {
3627-
3628-    /**
3629-     * Return a JMF AudioFormat for a given Jingle Payload type.
3630-     * Return null if the payload is not supported by this jmf API.
3631-     *
3632-     * @param payloadtype payloadtype
3633-     * @return correspondent audioType
3634-     */
3635-    public static AudioFormat getAudioFormat(PayloadType payloadtype) {
3636-
3637-        switch (payloadtype.getId()) {
3638-            case 0:
3639-                return new AudioFormat(AudioFormat.ULAW_RTP);
3640-            case 3:
3641-                return new AudioFormat(AudioFormat.GSM_RTP);
3642-            case 4:
3643-                return new AudioFormat(AudioFormat.G723_RTP);
3644-            default:
3645-                return null;
3646-        }
3647-
3648-    }
3649-
3650-}
3651Index: org/jivesoftware/smackx/jingle/mediaimpl/jspeex/SpeexMediaManager.java
3652===================================================================
3653--- org/jivesoftware/smackx/jingle/mediaimpl/jspeex/SpeexMediaManager.java	(revision 11644)
3654+++ org/jivesoftware/smackx/jingle/mediaimpl/jspeex/SpeexMediaManager.java	(working copy)
3655@@ -1,134 +0,0 @@
3656-/**
3657- * $RCSfile: SpeexMediaManager.java,v $
3658- * $Revision: 1.3 $
3659- * $Date: 25/12/2006
3660- * <p/>
3661- * Copyright 2003-2006 Jive Software.
3662- * <p/>
3663- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
3664- * you may not use this file except in compliance with the License.
3665- * You may obtain a copy of the License at
3666- * <p/>
3667- * http://www.apache.org/licenses/LICENSE-2.0
3668- * <p/>
3669- * Unless required by applicable law or agreed to in writing, software
3670- * distributed under the License is distributed on an "AS IS" BASIS,
3671- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3672- * See the License for the specific language governing permissions and
3673- * limitations under the License.
3674- */
3675-package org.jivesoftware.smackx.jingle.mediaimpl.jspeex;
3676-
3677-import java.io.File;
3678-import java.io.IOException;
3679-import java.util.ArrayList;
3680-import java.util.List;
3681-
3682-import org.jivesoftware.smackx.jingle.JingleSession;
3683-import org.jivesoftware.smackx.jingle.SmackLogger;
3684-import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
3685-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
3686-import org.jivesoftware.smackx.jingle.media.PayloadType;
3687-import org.jivesoftware.smackx.jingle.mediaimpl.JMFInit;
3688-import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
3689-import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
3690-
3691-/**
3692- * Implements a jingleMediaManager using JMF based API and JSpeex.
3693- * It supports Speex codec.
3694- * <i>This API only currently works on windows.</i>
3695- *
3696- * @author Thiago Camargo
3697- */
3698-public class SpeexMediaManager extends JingleMediaManager {
3699-
3700-	private static final SmackLogger LOGGER = SmackLogger.getLogger(SpeexMediaManager.class);
3701-
3702-	public static final String MEDIA_NAME = "Speex";
3703-
3704-    private List<PayloadType> payloads = new ArrayList<PayloadType>();
3705-
3706-    public SpeexMediaManager(JingleTransportManager transportManager) {
3707-        super(transportManager);
3708-        setupPayloads();
3709-        setupJMF();
3710-    }
3711-
3712-    /**
3713-     * Returns a new jingleMediaSession
3714-     *
3715-     * @param payloadType payloadType
3716-     * @param remote      remote Candidate
3717-     * @param local       local Candidate
3718-     * @return JingleMediaSession
3719-     */
3720-    public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
3721-        return new AudioMediaSession(payloadType, remote, local, null,null);
3722-    }
3723-
3724-    /**
3725-     * Setup API supported Payloads
3726-     */
3727-    private void setupPayloads() {
3728-        payloads.add(new PayloadType.Audio(15, "speex"));
3729-    }
3730-
3731-    /**
3732-     * Return all supported Payloads for this Manager
3733-     *
3734-     * @return The Payload List
3735-     */
3736-    public List<PayloadType> getPayloads() {
3737-        return payloads;
3738-    }
3739-
3740-    /**
3741-     * Runs JMFInit the first time the application is started so that capture
3742-     * devices are properly detected and initialized by JMF.
3743-     */
3744-    public static void setupJMF() {
3745-        // .jmf is the place where we store the jmf.properties file used
3746-        // by JMF. if the directory does not exist or it does not contain
3747-        // a jmf.properties file. or if the jmf.properties file has 0 length
3748-        // then this is the first time we're running and should continue to
3749-        // with JMFInit
3750-        String homeDir = System.getProperty("user.home");
3751-        File jmfDir = new File(homeDir, ".jmf");
3752-        String classpath = System.getProperty("java.class.path");
3753-        classpath += System.getProperty("path.separator")
3754-                + jmfDir.getAbsolutePath();
3755-        System.setProperty("java.class.path", classpath);
3756-
3757-        if (!jmfDir.exists())
3758-            jmfDir.mkdir();
3759-
3760-        File jmfProperties = new File(jmfDir, "jmf.properties");
3761-
3762-        if (!jmfProperties.exists()) {
3763-            try {
3764-                jmfProperties.createNewFile();
3765-            }
3766-            catch (IOException ex) {
3767-                LOGGER.debug("Failed to create jmf.properties");
3768-                ex.printStackTrace();
3769-            }
3770-        }
3771-
3772-        // if we're running on linux checkout that libjmutil.so is where it
3773-        // should be and put it there.
3774-        runLinuxPreInstall();
3775-
3776-        if (jmfProperties.length() == 0) {
3777-            new JMFInit(null, false);
3778-        }
3779-
3780-    }
3781-
3782-    private static void runLinuxPreInstall() {
3783-        // @TODO Implement Linux Pre-Install
3784-    }
3785-
3786-    public String getName() {
3787-        return MEDIA_NAME;
3788-    }
3789-}
3790Index: org/jivesoftware/smackx/jingle/mediaimpl/jspeex/AudioMediaSession.java
3791===================================================================
3792--- org/jivesoftware/smackx/jingle/mediaimpl/jspeex/AudioMediaSession.java	(revision 11644)
3793+++ org/jivesoftware/smackx/jingle/mediaimpl/jspeex/AudioMediaSession.java	(working copy)
3794@@ -1,245 +0,0 @@
3795-/**
3796- * $RCSfile: AudioMediaSession.java,v $
3797- * $Revision: 1.1 $
3798- * $Date: 25/12/2006
3799- * <p/>
3800- * Copyright 2003-2006 Jive Software.
3801- * <p/>
3802- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
3803- * you may not use this file except in compliance with the License.
3804- * You may obtain a copy of the License at
3805- * <p/>
3806- * http://www.apache.org/licenses/LICENSE-2.0
3807- * <p/>
3808- * Unless required by applicable law or agreed to in writing, software
3809- * distributed under the License is distributed on an "AS IS" BASIS,
3810- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3811- * See the License for the specific language governing permissions and
3812- * limitations under the License.
3813- */
3814-
3815-package org.jivesoftware.smackx.jingle.mediaimpl.jspeex;
3816-
3817-import java.io.IOException;
3818-import java.net.DatagramSocket;
3819-import java.net.InetAddress;
3820-import java.net.ServerSocket;
3821-import java.security.GeneralSecurityException;
3822-
3823-import javax.media.NoProcessorException;
3824-import javax.media.format.UnsupportedFormatException;
3825-import javax.media.rtp.rtcp.SenderReport;
3826-import javax.media.rtp.rtcp.SourceDescription;
3827-
3828-import mil.jfcom.cie.media.session.MediaSession;
3829-import mil.jfcom.cie.media.session.MediaSessionListener;
3830-import mil.jfcom.cie.media.session.StreamPlayer;
3831-import mil.jfcom.cie.media.srtp.packetizer.SpeexFormat;
3832-
3833-import org.jivesoftware.smackx.jingle.JingleSession;
3834-import org.jivesoftware.smackx.jingle.SmackLogger;
3835-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
3836-import org.jivesoftware.smackx.jingle.media.PayloadType;
3837-import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
3838-
3839-/**
3840- * This Class implements a complete JingleMediaSession.
3841- * It sould be used to transmit and receive audio captured from the Mic.
3842- * This Class should be automaticly controlled by JingleSession.
3843- * But you could also use in any VOIP application.
3844- * For better NAT Traversal support this implementation don't support only receive or only transmit.
3845- * To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit()
3846- *
3847- * @author Thiago Camargo
3848- */
3849-
3850-public class AudioMediaSession extends JingleMediaSession implements MediaSessionListener {
3851-
3852-	private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioMediaSession.class);
3853-
3854-	private MediaSession mediaSession;
3855-
3856-    /**
3857-     * Create a Session using Speex Codec
3858-     *
3859-     * @param localhost    localHost
3860-     * @param localPort    localPort
3861-     * @param remoteHost   remoteHost
3862-     * @param remotePort   remotePort
3863-     * @param eventHandler eventHandler
3864-     * @param quality      quality
3865-     * @param secure       secure
3866-     * @param micOn        micOn
3867-     * @return MediaSession
3868-     * @throws NoProcessorException
3869-     * @throws UnsupportedFormatException
3870-     * @throws IOException
3871-     * @throws GeneralSecurityException
3872-     */
3873-    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 {
3874-
3875-        SpeexFormat.setFramesPerPacket(1);
3876-        /**
3877-         * The master key. Hardcoded for now.
3878-         */
3879-        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};
3880-
3881-        /**
3882-         * The master salt. Hardcoded for now.
3883-         */
3884-        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};
3885-
3886-        DatagramSocket[] localPorts = MediaSession.getLocalPorts(InetAddress.getByName(localhost), localPort);
3887-        MediaSession session = MediaSession.createInstance(remoteHost, remotePort, localPorts, quality, secure, masterKey, masterSalt);
3888-        session.setListener(eventHandler);
3889-
3890-        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)});
3891-        return session;
3892-    }
3893-
3894-
3895-    /**
3896-     * Creates a org.jivesoftware.jingleaudio.jspeex.AudioMediaSession with defined payload type, remote and local candidates
3897-     *
3898-     * @param payloadType Payload of the jmf
3899-     * @param remote      the remote information. The candidate that the jmf will be sent to.
3900-     * @param local       the local information. The candidate that will receive the jmf
3901-     * @param locator     media locator
3902-     */
3903-    public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote,
3904-            final TransportCandidate local, String locator, JingleSession jingleSession) {
3905-        super(payloadType, remote, local, locator == null ? "dsound://" : locator, jingleSession);
3906-        initialize();
3907-    }
3908-
3909-    /**
3910-     * Initialize the Audio Channel to make it able to send and receive audio
3911-     */
3912-    public void initialize() {
3913-
3914-        String ip;
3915-        String localIp;
3916-        int localPort;
3917-        int remotePort;
3918-
3919-        if (this.getLocal().getSymmetric() != null) {
3920-            ip = this.getLocal().getIp();
3921-            localIp = this.getLocal().getLocalIp();
3922-            localPort = getFreePort();
3923-            remotePort = this.getLocal().getSymmetric().getPort();
3924-
3925-            LOGGER.debug(this.getLocal().getConnection() + " " + ip + ": " + localPort + "->" + remotePort);
3926-
3927-        }
3928-        else {
3929-            ip = this.getRemote().getIp();
3930-            localIp = this.getLocal().getLocalIp();
3931-            localPort = this.getLocal().getPort();
3932-            remotePort = this.getRemote().getPort();
3933-        }
3934-
3935-        try {
3936-            mediaSession = createSession(localIp, localPort, ip, remotePort, this, 2, false, true);
3937-        }
3938-        catch (NoProcessorException e) {
3939-            e.printStackTrace();
3940-        }
3941-        catch (UnsupportedFormatException e) {
3942-            e.printStackTrace();
3943-        }
3944-        catch (IOException e) {
3945-            e.printStackTrace();
3946-        }
3947-        catch (GeneralSecurityException e) {
3948-            e.printStackTrace();
3949-        }
3950-    }
3951-
3952-    /**
3953-     * Starts transmission and for NAT Traversal reasons start receiving also.
3954-     */
3955-    public void startTrasmit() {
3956-        try {
3957-            LOGGER.debug("start");
3958-            mediaSession.start(true);
3959-            this.mediaReceived("");
3960-        }
3961-        catch (IOException e) {
3962-            e.printStackTrace();
3963-        }
3964-    }
3965-
3966-    /**
3967-     * Set transmit activity. If the active is true, the instance should trasmit.
3968-     * If it is set to false, the instance should pause transmit.
3969-     *
3970-     * @param active active state
3971-     */
3972-    public void setTrasmit(boolean active) {
3973-        // Do nothing
3974-    }
3975-
3976-    /**
3977-     * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
3978-     */
3979-    public void startReceive() {
3980-        // Do nothing
3981-    }
3982-
3983-    /**
3984-     * Stops transmission and for NAT Traversal reasons stop receiving also.
3985-     */
3986-    public void stopTrasmit() {
3987-        if (mediaSession != null)
3988-            mediaSession.close();
3989-    }
3990-
3991-    /**
3992-     * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
3993-     */
3994-    public void stopReceive() {
3995-        // Do nothing
3996-    }
3997-
3998-    public void newStreamIdentified(StreamPlayer streamPlayer) {
3999-    }
4000-
4001-    public void senderReportReceived(SenderReport report) {
4002-    }
4003-
4004-    public void streamClosed(StreamPlayer stream, boolean timeout) {
4005-    }
4006-
4007-    /**
4008-     * Obtain a free port we can use.
4009-     *
4010-     * @return A free port number.
4011-     */
4012-    protected int getFreePort() {
4013-        ServerSocket ss;
4014-        int freePort = 0;
4015-
4016-        for (int i = 0; i < 10; i++) {
4017-            freePort = (int) (10000 + Math.round(Math.random() * 10000));
4018-            freePort = freePort % 2 == 0 ? freePort : freePort + 1;
4019-            try {
4020-                ss = new ServerSocket(freePort);
4021-                freePort = ss.getLocalPort();
4022-                ss.close();
4023-                return freePort;
4024-            }
4025-            catch (IOException e) {
4026-                e.printStackTrace();
4027-            }
4028-        }
4029-        try {
4030-            ss = new ServerSocket(0);
4031-            freePort = ss.getLocalPort();
4032-            ss.close();
4033-        }
4034-        catch (IOException e) {
4035-            e.printStackTrace();
4036-        }
4037-        return freePort;
4038-    }
4039-}
4040