- implement http tunnel sender

git-svn-id: http://bigbluebutton.googlecode.com/svn/trunk@1840 af16638f-c34d-0410-8cfa-b39d5352b314
This commit is contained in:
Richard Alam 2009-07-06 21:16:24 +00:00
parent 23b08916ba
commit 11bab7fa9e
5 changed files with 328 additions and 2 deletions

View File

@ -45,7 +45,7 @@ public class DeskShareApplet extends JApplet implements IScreenCaptureListener {
} else {
captureSender = new SocketScreenCaptureSender();
((SocketScreenCaptureSender) captureSender).connect(host, room, capture.getVideoWidth(),
captureSender.connect(host, room, capture.getVideoWidth(),
capture.getVideoHeight(), capture.getProperFrameRate());
}
@ -63,6 +63,9 @@ public class DeskShareApplet extends JApplet implements IScreenCaptureListener {
*/
public void destroy(){
captureTaker.setCapture(false);
if (!httpTunnel) {
captureSender.disconnect();
}
}
public void setScreenCoordinates(int x, int y){

View File

@ -1,12 +1,75 @@
package org.bigbluebutton.deskshare.client;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import javax.imageio.ImageIO;
public class HttpScreenCaptureSender implements IScreenCaptureSender {
private String host = "localhost";
private String room;
private int videoWidth;
private int videoHeight;
private int frameRate;
private String servletName = "deskshare";
private URL url;
private String videoInfo;
private MultiPartFormOutputStream mpfOutStream;
private URLConnection conn;
public void send(BufferedImage screenCapture) {
// TODO Auto-generated method stub
ByteArrayOutputStream byteConvert = new ByteArrayOutputStream();
try {
ImageIO.write(screenCapture, "jpeg", byteConvert);
byte[] imageData = byteConvert.toByteArray();
mpfOutStream.writeField("room", room);
mpfOutStream.writeField("video", videoInfo);
mpfOutStream.writeFile("screen", "image/jpeg", "screen.jpg", imageData);
} catch (IOException e) {
System.out.println("IOException while converting screen capture.");
}
}
public void connect(String host, String room, int videoWidth,
int videoHeight, int frameRate) {
this.host = host;
this.room = room;
this.videoWidth = videoWidth;
this.videoHeight = videoHeight;
this.frameRate = frameRate;
videoInfo = Integer.toString(videoWidth)
+ "x" + Integer.toString(videoHeight)
+ "x" + Integer.toString(frameRate);
String urlString = "";
try {
urlString = "http://" + host + "/" + servletName;
url = new URL(urlString);
conn = MultiPartFormOutputStream.createConnection(url);
conn.setRequestProperty("Connection", "Keep-Alive");
mpfOutStream = new MultiPartFormOutputStream(conn.getOutputStream(), MultiPartFormOutputStream.createBoundary());
} catch (MalformedURLException e) {
System.out.println("MalformedURLException for " + urlString);
} catch (IOException e) {
System.out.println("IOException while creating URL connection.");
}
}
public void disconnect() {
try {
mpfOutStream.close();
} catch (IOException e) {
System.out.println("IOException while closing output stream");
}
}
}

View File

@ -4,5 +4,8 @@ import java.awt.image.BufferedImage;
public interface IScreenCaptureSender {
public void connect(String host, String room, int videoWidth, int videoHeight, int frameRate);
public void send(BufferedImage screenCapture);
public void disconnect();
}

View File

@ -0,0 +1,249 @@
package org.bigbluebutton.deskshare.client;
import java.io.*;
import java.net.*;
/**
* <code>MultiPartFormOutputStream</code> is used to write
* "multipart/form-data" to a <code>java.net.URLConnection</code> for
* POSTing. This is primarily for file uploading to HTTP servers.
*
* @since JDK1.3
*
* Taken from http://forums.sun.com/thread.jspa?threadID=451245&forumID=31 (July 5, 2009)
*/
public class MultiPartFormOutputStream {
/**
* The line end characters.
*/
private static final String NEWLINE = "\r\n";
/**
* The boundary prefix.
*/
private static final String PREFIX = "--";
/**
* The output stream to write to.
*/
private DataOutputStream out = null;
/**
* The multipart boundary string.
*/
private String boundary = null;
/**
* Creates a new <code>MultiPartFormOutputStream</code> object using
* the specified output stream and boundary. The boundary is required
* to be created before using this method, as described in the
* description for the <code>getContentType(String)</code> method.
* The boundary is only checked for <code>null</code> or empty string,
* but it is recommended to be at least 6 characters. (Or use the
* static createBoundary() method to create one.)
*
* @param os the output stream
* @param boundary the boundary
* @see #createBoundary()
* @see #getContentType(String)
*/
public MultiPartFormOutputStream(OutputStream os, String boundary) {
if(os == null) {
throw new IllegalArgumentException("Output stream is required.");
}
if(boundary == null || boundary.length() == 0) {
throw new IllegalArgumentException("Boundary stream is required.");
}
this.out = new DataOutputStream(os);
this.boundary = boundary;
}
/**
* Writes an int field value.
*
* @param name the field name (required)
* @param value the field value
* @throws java.io.IOException on input/output errors
*/
public void writeField(String name, int value)
throws java.io.IOException {
writeField(name, Integer.toString(value));
}
/**
* Writes an string field value. If the value is null, an empty string
* is sent ("").
*
* @param name the field name (required)
* @param value the field value
* @throws java.io.IOException on input/output errors
*/
public void writeField(String name, String value)
throws java.io.IOException {
if(name == null) {
throw new IllegalArgumentException("Name cannot be null or empty.");
}
if(value == null) {
value = "";
}
/*
--boundary\r\n
Content-Disposition: form-data; name="<fieldName>"\r\n
\r\n
<value>\r\n
*/
// write boundary
out.writeBytes(PREFIX);
out.writeBytes(boundary);
out.writeBytes(NEWLINE);
// write content header
out.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"");
out.writeBytes(NEWLINE);
out.writeBytes(NEWLINE);
// write content
out.writeBytes(value);
out.writeBytes(NEWLINE);
out.flush();
}
/**
* Writes the given bytes. The bytes are assumed to be the contents
* of a file, and will be sent as such. If the data is null, a
* <code>java.lang.IllegalArgumentException</code> will be thrown.
*
* @param name the field name
* @param mimeType the file content type (optional, recommended)
* @param fileName the file name (required)
* @param data the file data
* @throws java.io.IOException on input/output errors
*/
public void writeFile(String name, String mimeType,
String fileName, byte[] data)
throws java.io.IOException {
if(data == null) {
throw new IllegalArgumentException("Data cannot be null.");
}
if(fileName == null || fileName.length() == 0) {
throw new IllegalArgumentException("File name cannot be null or empty.");
}
/*
--boundary\r\n
Content-Disposition: form-data; name="<fieldName>"; filename="<filename>"\r\n
Content-Type: <mime-type>\r\n
\r\n
<file-data>\r\n
*/
// write boundary
out.writeBytes(PREFIX);
out.writeBytes(boundary);
out.writeBytes(NEWLINE);
// write content header
out.writeBytes("Content-Disposition: form-data; name=\"" + name +
"\"; filename=\"" + fileName + "\"");
out.writeBytes(NEWLINE);
if(mimeType != null) {
out.writeBytes("Content-Type: " + mimeType);
out.writeBytes(NEWLINE);
}
out.writeBytes(NEWLINE);
// write content
out.write(data, 0, data.length);
out.writeBytes(NEWLINE);
out.flush();
}
/**
* Flushes the stream. Actually, this method does nothing, as the only
* write methods are highly specialized and automatically flush.
*
* @throws java.io.IOException on input/output errors
*/
public void flush() throws java.io.IOException {
// out.flush();
}
/**
* Closes the stream. <br />
* <br />
* <b>NOTE:</b> This method <b>MUST</b> be called to finalize the
* multipart stream.
*
* @throws java.io.IOException on input/output errors
*/
public void close() throws java.io.IOException {
// write final boundary
out.writeBytes(PREFIX);
out.writeBytes(boundary);
out.writeBytes(PREFIX);
out.writeBytes(NEWLINE);
out.flush();
out.close();
}
/**
* Gets the multipart boundary string being used by this stream.
*
* @return the boundary
*/
public String getBoundary() {
return this.boundary;
}
/**
* Creates a new <code>java.net.URLConnection</code> object from the
* specified <code>java.net.URL</code>. This is a convenience method
* which will set the <code>doInput</code>, <code>doOutput</code>,
* <code>useCaches</code> and <code>defaultUseCaches</code> fields to
* the appropriate settings in the correct order.
*
* @return a <code>java.net.URLConnection</code> object for the URL
* @throws java.io.IOException on input/output errors
*/
public static URLConnection createConnection(URL url)
throws java.io.IOException {
URLConnection urlConn = url.openConnection();
if(urlConn instanceof HttpURLConnection) {
HttpURLConnection httpConn = (HttpURLConnection)urlConn;
httpConn.setRequestMethod("POST");
}
urlConn.setDoInput(true);
urlConn.setDoOutput(true);
urlConn.setUseCaches(false);
urlConn.setDefaultUseCaches(false);
return urlConn;
}
/**
* Creates a multipart boundary string by concatenating 20 hyphens (-)
* and the hexadecimal (base-16) representation of the current time in
* milliseconds.
*
* @return a multipart boundary string
* @see #getContentType(String)
*/
public static String createBoundary() {
return "--------------------" +
Long.toString(System.currentTimeMillis(), 16);
}
/**
* Gets the content type string suitable for the
* <code>java.net.URLConnection</code> which includes the multipart
* boundary string. <br />
* <br />
* This method is static because, due to the nature of the
* <code>java.net.URLConnection</code> class, once the output stream
* for the connection is acquired, it's too late to set the content
* type (or any other request parameter). So one has to create a
* multipart boundary string first before using this class, such as
* with the <code>createBoundary()</code> method.
*
* @param boundary the boundary string
* @return the content type string
* @see #createBoundary()
*/
public static String getContentType(String boundary) {
return "multipart/form-data; boundary=" + boundary;
}
}

View File

@ -57,4 +57,12 @@ public class SocketScreenCaptureSender implements IScreenCaptureSender {
}
}
public void disconnect(){
System.out.println("Closing connection.");
try{
socket.close();
} catch(IOException e){
e.printStackTrace(System.out);
}
}
}