1 Index: 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 -} |
|
98 Index: 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 -} |
|
196 Index: 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 -} |
|
483 Index: 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 -} |
|
662 Index: 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 -} |
|
873 Index: 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 -} |
|
1082 Index: 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 -} |
|
1100 Index: 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 -} |
|
1328 Index: 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 -} |
|
1386 Index: 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 -} |
|
1415 Index: 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 -} |
|
1598 Index: 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 -} |
|
1753 Index: 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 - |
|
1844 Index: 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 -} |
|
1947 Index: 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 -} |
|
1967 Index: 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 - |
|
2259 Index: 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 -} |
|
2280 Index: 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 -} |
|
2400 Index: 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 -} |
|
2511 Index: 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 -} |
|
2681 Index: 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 -} |
|
2857 Index: 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 -} |
|
3032 Index: 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 |
|
3591 Index: 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 -} |
|
3651 Index: 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 -} |
|
3790 Index: 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 -} |
|