mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-12-23 04:57:58 +01:00
[SMACK-221][SMACK-222] - Added Keyframe Support and One-Side-Only Session
git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@8214 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
parent
ff2900653c
commit
925bd389c2
13 changed files with 102 additions and 135 deletions
|
@ -1083,7 +1083,7 @@ public abstract class JingleSession extends JingleNegotiator implements MediaRec
|
|||
rc.removeCandidateEcho();
|
||||
lc.removeCandidateEcho();
|
||||
|
||||
jingleMediaSession = jingleMediaManager.createMediaSession(pt, rc, lc);
|
||||
jingleMediaSession = jingleMediaManager.createMediaSession(pt, rc, lc, this);
|
||||
jingleMediaSession.addMediaReceivedListener(this);
|
||||
if (jingleMediaSession != null) {
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
package org.jivesoftware.smackx.jingle.media;
|
||||
|
||||
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
||||
import org.jivesoftware.smackx.jingle.JingleSession;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -60,6 +61,6 @@ public abstract class JingleMediaManager {
|
|||
* @param local
|
||||
* @return
|
||||
*/
|
||||
public abstract JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local);
|
||||
public abstract JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, JingleSession jingleSession);
|
||||
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
package org.jivesoftware.smackx.jingle.media;
|
||||
|
||||
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
||||
import org.jivesoftware.smackx.jingle.JingleSession;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
@ -48,6 +49,8 @@ public abstract class JingleMediaSession {
|
|||
private String mediaLocator;
|
||||
// Media Received Listener
|
||||
private List<MediaReceivedListener> mediaReceivedListeners = new ArrayList<MediaReceivedListener>();
|
||||
// Jingle Session
|
||||
private JingleSession jingleSession;
|
||||
|
||||
/**
|
||||
* Creates a new JingleMediaSession Instance to handle Media methods.
|
||||
|
@ -58,11 +61,12 @@ public abstract class JingleMediaSession {
|
|||
* @param mediaLocator Media Locator of the capture device
|
||||
*/
|
||||
public JingleMediaSession(PayloadType payloadType, TransportCandidate remote,
|
||||
TransportCandidate local, String mediaLocator) {
|
||||
TransportCandidate local, String mediaLocator, JingleSession jingleSession) {
|
||||
this.local = local;
|
||||
this.remote = remote;
|
||||
this.payloadType = payloadType;
|
||||
this.mediaLocator = mediaLocator;
|
||||
this.jingleSession = jingleSession;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -177,4 +181,11 @@ public abstract class JingleMediaSession {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets associated JingleSession
|
||||
* @return associated JingleSession
|
||||
*/
|
||||
public JingleSession getJingleSession() {
|
||||
return jingleSession;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
|
|||
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
|
||||
import org.jivesoftware.smackx.jingle.media.PayloadType;
|
||||
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
||||
import org.jivesoftware.smackx.jingle.JingleSession;
|
||||
|
||||
import javax.media.MediaLocator;
|
||||
import java.io.IOException;
|
||||
|
@ -51,8 +52,8 @@ public class AudioMediaSession extends JingleMediaSession {
|
|||
* @param locator media locator
|
||||
*/
|
||||
public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote,
|
||||
final TransportCandidate local, String locator) {
|
||||
super(payloadType, remote, local, locator==null?"dsound://":locator);
|
||||
final TransportCandidate local, String locator, JingleSession jingleSession) {
|
||||
super(payloadType, remote, local, locator==null?"dsound://":locator,jingleSession);
|
||||
initialize();
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
|
|||
import org.jivesoftware.smackx.jingle.media.PayloadType;
|
||||
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
||||
import org.jivesoftware.smackx.jingle.mediaimpl.JMFInit;
|
||||
import org.jivesoftware.smackx.jingle.JingleSession;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -68,8 +69,8 @@ public class JmfMediaManager extends JingleMediaManager {
|
|||
* @param local local Candidate
|
||||
* @return JingleMediaSession
|
||||
*/
|
||||
public JingleMediaSession createMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local) {
|
||||
return new AudioMediaSession(payloadType, remote, local,mediaLocator);
|
||||
public JingleMediaSession createMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
|
||||
return new AudioMediaSession(payloadType, remote, local, mediaLocator, jingleSession);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,6 +27,7 @@ import mil.jfcom.cie.media.srtp.packetizer.SpeexFormat;
|
|||
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
|
||||
import org.jivesoftware.smackx.jingle.media.PayloadType;
|
||||
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
||||
import org.jivesoftware.smackx.jingle.JingleSession;
|
||||
|
||||
import javax.media.NoProcessorException;
|
||||
import javax.media.format.UnsupportedFormatException;
|
||||
|
@ -55,15 +56,15 @@ public class AudioMediaSession extends JingleMediaSession implements MediaSessio
|
|||
|
||||
/**
|
||||
* Create a Session using Speex Codec
|
||||
*
|
||||
* @param localhost localHost
|
||||
* @param localPort localPort
|
||||
* @param remoteHost remoteHost
|
||||
* @param remotePort remotePort
|
||||
*
|
||||
* @param localhost localHost
|
||||
* @param localPort localPort
|
||||
* @param remoteHost remoteHost
|
||||
* @param remotePort remotePort
|
||||
* @param eventHandler eventHandler
|
||||
* @param quality quality
|
||||
* @param secure secure
|
||||
* @param micOn micOn
|
||||
* @param quality quality
|
||||
* @param secure secure
|
||||
* @param micOn micOn
|
||||
* @return MediaSession
|
||||
* @throws NoProcessorException
|
||||
* @throws UnsupportedFormatException
|
||||
|
@ -101,8 +102,8 @@ public class AudioMediaSession extends JingleMediaSession implements MediaSessio
|
|||
* @param locator media locator
|
||||
*/
|
||||
public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote,
|
||||
final TransportCandidate local, String locator) {
|
||||
super(payloadType, remote, local, locator==null?"dsound://":locator);
|
||||
final TransportCandidate local, String locator, JingleSession jingleSession) {
|
||||
super(payloadType, remote, local, locator == null ? "dsound://" : locator, jingleSession);
|
||||
initialize();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
|
|||
import org.jivesoftware.smackx.jingle.media.PayloadType;
|
||||
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
||||
import org.jivesoftware.smackx.jingle.mediaimpl.JMFInit;
|
||||
import org.jivesoftware.smackx.jingle.JingleSession;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -54,8 +55,8 @@ public class SpeexMediaManager extends JingleMediaManager {
|
|||
* @param local local Candidate
|
||||
* @return JingleMediaSession
|
||||
*/
|
||||
public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local) {
|
||||
return new AudioMediaSession(payloadType, remote, local, null);
|
||||
public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
|
||||
return new AudioMediaSession(payloadType, remote, local, null,null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
|
|||
import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
|
||||
import org.jivesoftware.smackx.jingle.media.PayloadType;
|
||||
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
||||
import org.jivesoftware.smackx.jingle.JingleSession;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
@ -76,10 +77,10 @@ public class MultiMediaManager extends JingleMediaManager {
|
|||
* @param local local Candidate
|
||||
* @return JingleMediaSession JingleMediaSession
|
||||
*/
|
||||
public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local) {
|
||||
public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
|
||||
for (JingleMediaManager manager : managers) {
|
||||
if (manager.getPayloads().contains(payloadType)) {
|
||||
return manager.createMediaSession(payloadType, remote, local);
|
||||
return manager.createMediaSession(payloadType, remote, local, jingleSession);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.jivesoftware.smackx.jingle.media.PayloadType;
|
|||
import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageEncoder;
|
||||
import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageDecoder;
|
||||
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
||||
import org.jivesoftware.smackx.jingle.JingleSession;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -72,9 +73,9 @@ public class ScreenShareMediaManager extends JingleMediaManager {
|
|||
* @param local local Candidate
|
||||
* @return JingleMediaSession JingleMediaSession
|
||||
*/
|
||||
public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local) {
|
||||
public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
|
||||
ScreenShareSession session = null;
|
||||
session = new ScreenShareSession(payloadType, remote, local, "Screen");
|
||||
session = new ScreenShareSession(payloadType, remote, local, "Screen", jingleSession);
|
||||
if (encoder != null) {
|
||||
session.setEncoder(encoder);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageEncoder;
|
|||
import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageReceiver;
|
||||
import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageTransmitter;
|
||||
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
|
||||
import org.jivesoftware.smackx.jingle.JingleSession;
|
||||
import org.jivesoftware.smackx.jingle.IncomingJingleSession;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
@ -33,6 +35,7 @@ import java.io.IOException;
|
|||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.net.DatagramSocket;
|
||||
|
||||
/**
|
||||
* This Class implements a complete JingleMediaSession.
|
||||
|
@ -47,6 +50,8 @@ public class ScreenShareSession extends JingleMediaSession {
|
|||
|
||||
private ImageTransmitter transmitter = null;
|
||||
private ImageReceiver receiver = null;
|
||||
private int width = 600;
|
||||
private int height = 600;
|
||||
|
||||
/**
|
||||
* Creates a org.jivesoftware.jingleaudio.jmf.AudioMediaSession with defined payload type, remote and local candidates
|
||||
|
@ -57,8 +62,8 @@ public class ScreenShareSession extends JingleMediaSession {
|
|||
* @param locator media locator
|
||||
*/
|
||||
public ScreenShareSession(final PayloadType payloadType, final TransportCandidate remote,
|
||||
final TransportCandidate local, final String locator) {
|
||||
super(payloadType, remote, local, "Screen");
|
||||
final TransportCandidate local, final String locator, JingleSession jingleSession) {
|
||||
super(payloadType, remote, local, "Screen", jingleSession);
|
||||
initialize();
|
||||
}
|
||||
|
||||
|
@ -67,36 +72,39 @@ public class ScreenShareSession extends JingleMediaSession {
|
|||
*/
|
||||
public void initialize() {
|
||||
|
||||
JFrame window = new JFrame();
|
||||
JPanel jp = new JPanel();
|
||||
window.add(jp);
|
||||
if (this.getJingleSession() instanceof IncomingJingleSession) {
|
||||
|
||||
window.setLocation(0, 0);
|
||||
window.setSize(400, 400);
|
||||
JFrame window = new JFrame();
|
||||
JPanel jp = new JPanel();
|
||||
window.add(jp);
|
||||
|
||||
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
window.setLocation(0, 0);
|
||||
window.setSize(600, 600);
|
||||
|
||||
try {
|
||||
receiver = new ImageReceiver(InetAddress.getByName("0.0.0.0"), getRemote().getPort(), getLocal().getPort(), 800, 600);
|
||||
System.out.println("Receiving on:" + receiver.getLocalPort());
|
||||
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
|
||||
try {
|
||||
receiver = new ImageReceiver(InetAddress.getByName("0.0.0.0"), getRemote().getPort(), getLocal().getPort(), width, height);
|
||||
System.out.println("Receiving on:" + receiver.getLocalPort());
|
||||
}
|
||||
catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
jp.add(receiver);
|
||||
receiver.setVisible(true);
|
||||
window.setAlwaysOnTop(true);
|
||||
window.setVisible(true);
|
||||
}
|
||||
catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
else {
|
||||
try {
|
||||
InetAddress remote = InetAddress.getByName(getRemote().getIp());
|
||||
transmitter = new ImageTransmitter(new DatagramSocket(getLocal().getPort()), remote, getRemote().getPort(), new Rectangle(0, 0, width, height));
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
jp.add(receiver);
|
||||
receiver.setVisible(true);
|
||||
window.setAlwaysOnTop(true);
|
||||
window.setVisible(true);
|
||||
|
||||
try {
|
||||
InetAddress remote = InetAddress.getByName(getRemote().getIp());
|
||||
transmitter = new ImageTransmitter(receiver.getDatagramSocket(), remote, getRemote().getPort(), new Rectangle(0, 0, 800, 600));
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -31,9 +31,8 @@ public class ImageTransmitter implements Runnable {
|
|||
private int tiles[][][];
|
||||
private int maxI;
|
||||
private int maxJ;
|
||||
private boolean changed = false;
|
||||
private final Object sync = new Object();
|
||||
private ImageEncoder encoder;
|
||||
public final static int KEYFRAME = 10;
|
||||
|
||||
public ImageTransmitter(DatagramSocket socket, InetAddress remoteHost, int remotePort, Rectangle area) {
|
||||
|
||||
|
@ -66,93 +65,23 @@ public class ImageTransmitter implements Runnable {
|
|||
byte buf[] = new byte[1024];
|
||||
final DatagramPacket p = new DatagramPacket(buf, 1024);
|
||||
|
||||
/*
|
||||
new Thread(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
|
||||
int w = (int) area.getWidth();
|
||||
int h = (int) area.getHeight();
|
||||
|
||||
int tiles[][][] = new int[maxI][maxJ][tileWidth * tileWidth];
|
||||
|
||||
while (on) {
|
||||
if (transmit) {
|
||||
|
||||
boolean differ = false;
|
||||
|
||||
BufferedImage capture = robot.createScreenCapture(area);
|
||||
|
||||
//ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
|
||||
//ColorConvertOp op = new ColorConvertOp(cs, null);
|
||||
//capture = op.filter(capture, null);
|
||||
|
||||
QuantizeFilter filter = new QuantizeFilter();
|
||||
capture = filter.filter(capture, null);
|
||||
|
||||
long trace = System.currentTimeMillis();
|
||||
|
||||
for (int i = 0; i < maxI; i++) {
|
||||
for (int j = 0; j < maxJ; j++) {
|
||||
|
||||
final BufferedImage bufferedImage = capture.getSubimage(i * tileWidth, j * tileWidth, tileWidth, tileWidth);
|
||||
|
||||
int pixels[] = new int[tileWidth * tileWidth];
|
||||
|
||||
PixelGrabber pg = new PixelGrabber(bufferedImage, 0, 0, tileWidth, tileWidth, pixels, 0, tileWidth);
|
||||
|
||||
try {
|
||||
if (pg.grabPixels()) {
|
||||
if (!differ) {
|
||||
if (!Arrays.equals(tiles[i][j], pixels)) {
|
||||
differ = true;
|
||||
}
|
||||
}
|
||||
tiles[i][j] = pixels;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (differ) {
|
||||
synchronized (sync) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
trace = (System.currentTimeMillis() - trace);
|
||||
System.err.println("Loop Time:" + trace);
|
||||
|
||||
if (trace < 250) {
|
||||
try {
|
||||
Thread.sleep(250);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
).start();
|
||||
*/
|
||||
int keyframe = 0;
|
||||
|
||||
while (on) {
|
||||
if (transmit) {
|
||||
|
||||
BufferedImage capture = robot.createScreenCapture(area);
|
||||
|
||||
//ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
|
||||
//ColorConvertOp op = new ColorConvertOp(cs, null);
|
||||
//capture = op.filter(capture, null);
|
||||
|
||||
QuantizeFilter filter = new QuantizeFilter();
|
||||
capture = filter.filter(capture, null);
|
||||
|
||||
long trace = System.currentTimeMillis();
|
||||
|
||||
if (++keyframe > KEYFRAME) {
|
||||
keyframe = 0;
|
||||
}
|
||||
System.out.println("KEYFRAME:" + keyframe);
|
||||
|
||||
for (int i = 0; i < maxI; i++) {
|
||||
for (int j = 0; j < maxJ; j++) {
|
||||
|
||||
|
@ -165,7 +94,7 @@ public class ImageTransmitter implements Runnable {
|
|||
try {
|
||||
if (pg.grabPixels()) {
|
||||
|
||||
if (!Arrays.equals(tiles[i][j], pixels)) {
|
||||
if (keyframe == KEYFRAME || !Arrays.equals(tiles[i][j], pixels)) {
|
||||
|
||||
ByteArrayOutputStream baos = encoder.encode(bufferedImage);
|
||||
|
||||
|
@ -178,7 +107,7 @@ public class ImageTransmitter implements Runnable {
|
|||
|
||||
byte[] bytesOut = baos.toByteArray();
|
||||
|
||||
if (bytesOut.length > 400)
|
||||
if (bytesOut.length > 1000)
|
||||
System.err.println(bytesOut.length);
|
||||
|
||||
p.setData(bytesOut);
|
||||
|
@ -225,14 +154,26 @@ public class ImageTransmitter implements Runnable {
|
|||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Transmit Enabled/Disabled
|
||||
* @param transmit boolean Enabled/Disabled
|
||||
*/
|
||||
public void setTransmit(boolean transmit) {
|
||||
this.transmit = transmit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the encoder used to encode Images Tiles
|
||||
* @return encoder
|
||||
*/
|
||||
public ImageEncoder getEncoder() {
|
||||
return encoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the encoder used to encode Image Tiles
|
||||
* @param encoder encoder
|
||||
*/
|
||||
public void setEncoder(ImageEncoder encoder) {
|
||||
this.encoder = encoder;
|
||||
}
|
||||
|
|
|
@ -835,8 +835,8 @@ public class JingleManagerTest extends SmackTestCase {
|
|||
|
||||
JingleMediaManager jingleMediaManager = new JingleMediaManager() {
|
||||
// Media Session Implementation
|
||||
public JingleMediaSession createMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local) {
|
||||
return new JingleMediaSession(payloadType, remote, local, null) {
|
||||
public JingleMediaSession createMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
|
||||
return new JingleMediaSession(payloadType, remote, local, null,null) {
|
||||
|
||||
public void initialize() {
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
package org.jivesoftware.smackx.jingle;
|
||||
|
||||
/**
|
||||
* $RCSfile$
|
||||
* $Revision: $
|
||||
|
@ -277,8 +279,6 @@ public class JingleMediaTest extends SmackTestCase {
|
|||
|
||||
try {
|
||||
|
||||
//XMPPConnection.DEBUG_ENABLED = true;
|
||||
|
||||
XMPPConnection x0 = getConnection(0);
|
||||
XMPPConnection x1 = getConnection(1);
|
||||
|
||||
|
@ -297,7 +297,7 @@ public class JingleMediaTest extends SmackTestCase {
|
|||
public void sessionRequested(final JingleSessionRequest request) {
|
||||
|
||||
try {
|
||||
|
||||
|
||||
IncomingJingleSession session = request.accept(jm1.getMediaManager().getPayloads());
|
||||
|
||||
session.start(request);
|
||||
|
|
Loading…
Reference in a new issue