Merge pull request #3538 from ritzalam/support-svc2-in-screen-share

Support svc2 in screen share
This commit is contained in:
Richard Alam 2017-01-03 12:37:56 -05:00 committed by GitHub
commit 02f22beff0
73 changed files with 583 additions and 130 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -12,23 +12,23 @@
<resources>
<j2se version="1.7+" href="http://java.sun.com/products/autodl/j2se"/>
<jar href="javacv-screenshare-0.0.1.jar" main="true" />
<jar href="ffmpeg.jar" />
<jar href="ffmpeg-svc2.jar" />
</resources>
<resources os="Windows" arch="amd64">
<nativelib href="ffmpeg-windows-x86_64.jar"/>
<nativelib href="ffmpeg-win-x86_64-native-svc2.jar"/>
</resources>
<resources os="Windows" arch="x86">
<nativelib href="$$jnlpUrl/lib/ffmpeg-windows-x86.jar"/>
<nativelib href="ffmpeg-win-x86-native-svc2.jar"/>
</resources>
<resources os="Linux" arch="x86_64 amd64">
<nativelib href="ffmpeg-linux-x86_64.jar"/>
<nativelib href="ffmpeg-linux-x86_64-svc2.jar"/>
</resources>
<resources os="Linux" arch="x86 i386 i486 i586 i686">
<nativelib href="ffmpeg-linux-x86.jar"/>
<nativelib href="ffmpeg-linux-x86-svc2.jar"/>
</resources>
<resources os="Mac OS X">
@ -45,6 +45,7 @@
<argument>$$fullScreen</argument>
<argument>$$codecOptions</argument>
<argument>$$session</argument>
<argument>$$useH264</argument>
<argument>$$errorMessage</argument>
</application-desc>
<security><all-permissions/></security>

View File

@ -1,52 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.0+" codebase="$$jnlpUrl/lib" href="">
<!--
Keep href empty. Otherwise this jnlp file will always be cached.
http://www.coderanch.com/t/284889/JSP/java/Caching-JNLP
-->
<information>
<title>BigBlueButton Screen Share</title>
<vendor>BigBlueButton</vendor>
</information>
<resources>
<j2se version="1.7+" href="http://java.sun.com/products/autodl/j2se"/>
<jar href="javacv-screenshare-0.0.1.jar" main="true" />
<jar href="ffmpeg.jar" />
</resources>
<resources os="Windows" arch="amd64">
<nativelib href="ffmpeg-windows-x86_64.jar"/>
</resources>
<resources os="Windows" arch="x86">
<nativelib href="$$jnlpUrl/lib/ffmpeg-windows-x86.jar"/>
</resources>
<resources os="Linux" arch="x86_64 amd64">
<nativelib href="ffmpeg-linux-x86_64.jar"/>
</resources>
<resources os="Linux" arch="x86 i386 i486 i586 i686">
<nativelib href="ffmpeg-linux-x86.jar"/>
</resources>
<resources os="Mac OS X">
<nativelib href="ffmpeg-macosx-x86_64.jar"/>
</resources>
<application-desc
name="Desktop Sharing Demo Application"
main-class="org.bigbluebutton.screenshare.client.DeskshareMain">
<argument>$$publishUrl</argument>
<argument>$$serverUrl</argument>
<argument>$$meetingId</argument>
<argument>$$streamId</argument>
<argument>$$fullScreen</argument>
<argument>$$codecOptions</argument>
<argument>$$session</argument>
<argument>$$errorMessage</argument>
</application-desc>
<security><all-permissions/></security>
<update check="always" policy="always"/>
</jnlp>

View File

@ -41,6 +41,8 @@ import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.xml.parsers.*;
import com.sun.org.apache.xpath.internal.operations.Bool;
import org.xml.sax.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
@ -314,12 +316,23 @@ public class JnlpFileHandler {
if (sInfo == null) {
errorMessage = "ERROR_GETTING_INFO_USING_TOKEN";
} else {
publishUrl = sInfo.publishUrl;
System.out.println("********* URL=" + sInfo.publishUrl);
if (sInfo.tunnel) {
publishUrl = sInfo.publishUrl.replaceFirst("rtmp","rtmpt");
} else {
publishUrl = sInfo.publishUrl;
}
streamId = sInfo.streamId;
session = sInfo.session;
}
System.out.println("********* URL=" + publishUrl);
String jnlpUrl = configurator.getJnlpUrl();
Boolean useH264 = configurator.isUseH264();
String codecOptions = configurator.getCodecOptions();
log.debug("Codec Options = [" + codecOptions + "]");
@ -337,6 +350,7 @@ public class JnlpFileHandler {
jnlpTemplate = substitute(jnlpTemplate, "$$session", session);
jnlpTemplate = substitute(jnlpTemplate, "$$streamId", streamId);
jnlpTemplate = substitute(jnlpTemplate, "$$codecOptions", codecOptions);
jnlpTemplate = substitute(jnlpTemplate, "$$useH264", useH264.toString());
jnlpTemplate = substitute(jnlpTemplate, "$$errorMessage", errorMessage);
// fix for 5039951: Add $$hostname macro
jnlpTemplate = substitute(jnlpTemplate, "$$hostname", request.getServerName());

View File

@ -11,7 +11,7 @@ public interface IScreenShareApplication {
Boolean recordStream(String meetingId, String streamId);
void isScreenSharing(String meetingId, String userId);
void requestShareToken(String meetingId, String userId, Boolean record);
void requestShareToken(String meetingId, String userId, Boolean record, Boolean tunnel);
void startShareRequest(String meetingId, String userId, String session);
void pauseShareRequest(String meetingId, String userId, String streamId);
void restartShareRequest(String meetingId, String userId);

View File

@ -5,10 +5,12 @@ public class ScreenShareInfo {
public final String session;
public final String streamId;
public final String publishUrl;
public final Boolean tunnel;
public ScreenShareInfo(String session, String publishUrl, String streamId) {
public ScreenShareInfo(String session, String publishUrl, String streamId, Boolean tunnel) {
this.session = session;
this.streamId = streamId;
this.publishUrl = publishUrl;
this.tunnel = tunnel;
}
}

View File

@ -34,8 +34,8 @@ public class Red5AppHandler {
app.isScreenSharing(meetingId, userId);
}
public void requestShareToken(String meetingId, String userId, Boolean record) {
app.requestShareToken(meetingId, userId, record);
public void requestShareToken(String meetingId, String userId, Boolean record, Boolean tunnel) {
app.requestShareToken(meetingId, userId, record, tunnel);
}
public void startShareRequest(String meetingId, String userId, String session) {

View File

@ -133,12 +133,13 @@ public class Red5AppService {
Boolean record = (Boolean) msg.get("record");
String meetingId = Red5.getConnectionLocal().getScope().getName();
String userId = (String) Red5.getConnectionLocal().getAttribute("USERID");
Boolean tunnel = (Boolean) msg.get("tunnel");
if (log.isDebugEnabled()) {
log.debug("Received startShareRequest for meetingId=" + meetingId + " from user=" + userId);
}
handler.requestShareToken(meetingId, userId, record);
handler.requestShareToken(meetingId, userId, record, tunnel);
}
public void stopShareRequest(Map<String, Object> msg) {

View File

@ -10,6 +10,7 @@ public class JnlpConfigurator {
private IScreenShareApplication screenShareApplication;
private String streamBaseUrl;
private String codecOptions;
private boolean useH264 = false;
public String getJnlpUrl() {
@ -36,6 +37,14 @@ public class JnlpConfigurator {
return codecOptions;
}
public void setUseH264(boolean h264) {
useH264 = h264;
}
public boolean isUseH264() {
return useH264;
}
public ScreenShareInfo getScreenShareInfo(String meetingId, String token) {
ScreenShareInfoResponse resp = screenShareApplication.getScreenShareInfo(meetingId, token);
if (resp.error != null) return null;

View File

@ -98,7 +98,7 @@ class ScreenShareApplication(val bus: IEventsMessageBus, val jnlpFile: String,
val reply = Await.result(future, timeout.duration).asInstanceOf[ScreenShareInfoRequestReply]
val publishUrl = streamBaseUrl + "/" + meetingId
val info = new ScreenShareInfo(reply.session, publishUrl, reply.streamId)
val info = new ScreenShareInfo(reply.session, publishUrl, reply.streamId, reply.tunnel)
new ScreenShareInfoResponse(info, null)
} catch {
case e: TimeoutException =>
@ -157,12 +157,12 @@ class ScreenShareApplication(val bus: IEventsMessageBus, val jnlpFile: String,
}
def requestShareToken(meetingId: String, userId: String, record: java.lang.Boolean) {
def requestShareToken(meetingId: String, userId: String, record: java.lang.Boolean, tunnel: java.lang.Boolean) {
if (logger.isDebugEnabled()) {
logger.debug("Received request share token on meeting=" + meetingId + "for user=" + userId + "]")
}
screenShareManager ! RequestShareTokenMessage(meetingId, userId, jnlpFile, record)
screenShareManager ! RequestShareTokenMessage(meetingId, userId, jnlpFile, record, tunnel)
}
def startShareRequest(meetingId: String, userId: String, session: String) {

View File

@ -6,12 +6,12 @@ import org.bigbluebutton.app.screenshare.events.IEventsMessageBus
object ActiveSession {
def apply(parent: Screenshare, bus: IEventsMessageBus, meetingId: String, streamId: String,
token: String, recorded: Boolean, userId: String)(implicit context: ActorContext) =
new ActiveSession(parent, bus, meetingId, streamId, token, recorded, userId)(context)
token: String, recorded: Boolean, userId: String, tunnel: Boolean)(implicit context: ActorContext) =
new ActiveSession(parent, bus, meetingId, streamId, token, recorded, userId, tunnel)(context)
}
class ActiveSession(parent: Screenshare, bus: IEventsMessageBus, val meetingId: String,
val streamId: String, val token: String, val recorded: Boolean,
val userId: String)(implicit val context: ActorContext) {
val userId: String, val tunnel: Boolean)(implicit val context: ActorContext) {
// val actorRef = context.actorOf(Session.props(parent, bus, meetingId, streamId, token, recorded, userId))
}

View File

@ -143,6 +143,9 @@ class Screenshare(val sessionManager: ScreenshareManager,
private val PRESENTER_AUTO_RECONNECTED_REASON = "PRESENTER_AUTO_RECONNECTED_REASON"
private val JWS_START_FAILED_REASON = "JWS_START_FAILED_REASON"
// RTMP or RTMPT
private var tunnel: Boolean = false;
val sessionAudit = context.actorOf(ScreenShareAuditInternal.props(meetingId))
def receive = {
@ -283,7 +286,7 @@ class Screenshare(val sessionManager: ScreenshareManager,
sss <- screenShareSession
} yield {
if (as.token == msg.token) {
sender ! new ScreenShareInfoRequestReply(msg.meetingId, as.streamId, sss)
sender ! new ScreenShareInfoRequestReply(msg.meetingId, as.streamId, sss, as.tunnel)
}
}
@ -446,7 +449,7 @@ class Screenshare(val sessionManager: ScreenshareManager,
val token = streamId
val userId = trimUserId(msg.userId).getOrElse(msg.userId)
val session = ActiveSession(this, bus, meetingId, streamId, token, record, userId)
val session = ActiveSession(this, bus, meetingId, streamId, token, record, userId, tunnel)
activeSession = Some(session)
sessionStartedTimestamp = TimeUtil.currentMonoTimeInSeconds()
status = START
@ -474,7 +477,8 @@ class Screenshare(val sessionManager: ScreenshareManager,
val userId = trimUserId(msg.userId).getOrElse(msg.userId)
val session = ActiveSession(this, bus, meetingId, streamId, token, msg.record, userId)
tunnel = msg.tunnel
val session = ActiveSession(this, bus, meetingId, streamId, token, msg.record, userId, tunnel)
activeSession = Some(session)
currentPresenterId = Some(msg.userId)

View File

@ -1,6 +1,6 @@
package org.bigbluebutton.app.screenshare.server.sessions.messages
case class RequestShareTokenMessage(meetingId: String, userId: String, jnlp: String, record: Boolean)
case class RequestShareTokenMessage(meetingId: String, userId: String, jnlp: String, record: Boolean, tunnel: Boolean)
case class StartShareRequestMessage(meetingId: String, userId: String, session: String)
@ -37,7 +37,7 @@ case class IsScreenSharingReply(sharing: Boolean, streamId: String,
case class ScreenShareInfoRequest(meetingId: String, token: String)
case class ScreenShareInfoRequestReply(meetingId: String, streamId: String, session: String)
case class ScreenShareInfoRequestReply(meetingId: String, streamId: String, session: String, tunnel: Boolean)
case class UserDisconnected(meetingId: String, userId: String)

View File

@ -83,6 +83,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<property name="jnlpUrl" value="${jnlpUrl}"/>
<property name="streamBaseUrl" value="${streamBaseUrl}"/>
<property name="codecOptions" value="${codecOptions}"/>
<property name="useH264" value="${useH264}"/>
<property name="application" ref="screenShareApplication"/>
</bean>

View File

@ -18,6 +18,7 @@ redis.port=6379
streamBaseUrl=rtmp://192.168.23.53/screenshare
jnlpUrl=http://192.168.23.53/screenshare
jnlpFile=http://192.168.23.53/screenshare/screenshare.jnlp
useH264=false
# NOTES:
# 1. GOP (group of pictures) is calculated as frameRate * keyFrameInterval

View File

@ -0,0 +1,10 @@
apply plugin: 'java'
apply plugin: 'eclipse'
sourceCompatibility=1.6
targetCompatibility=1.6
version = '0.0.1'
archivesBaseName = 'ffmpeg-linux-x86'

View File

@ -0,0 +1,38 @@
<?xml version="1.0" ?>
<project name="ffmpeg-linux-x86-signing" basedir=".">
<!-- Sign jar with Certificate using pkcs12 file -->
<target name="check-certificate">
<input message="Enter cetificate filename:" addproperty="cert.name" />
<input message="Enter cetificate password:" addproperty="cert.password" />
<exec executable="/usr/bin/keytool" outputproperty="cert.info">
<arg line="-list" />
<arg line="-storetype pkcs12" />
<arg line="-keystore ${cert.name}" />
<arg line="-storepass ${cert.password}" />
<arg line="-v" />
</exec>
</target>
<target name="get-alias-name" depends="check-certificate">
<script language="javascript">
<![CDATA[
// getting the value
info = project.getProperty("cert.info");
alias = (info.match(/Alias name:(.*)/)[0]).replace("Alias name: ","");
project.setProperty("cert.alias",alias);
]]>
</script>
</target>
<target name="sign-jar" depends="get-alias-name">
<signjar jar="build/libs/ffmpeg-linux-x86-0.0.1.jar"
storetype="pkcs12"
keystore="${cert.name}"
storepass="${cert.password}"
alias="${cert.alias}" />
</target>
</project>

View File

@ -0,0 +1,18 @@
FFMPEG=ffmpeg-3.0.2-1.2-linux-x86.jar
mkdir workdir
cp $FFMPEG workdir/ffmpeg-linux-x86.jar
rm -rf src
mkdir -p src/main/resources
mkdir -p src/main/java
cd workdir
jar xvf ffmpeg-linux-x86.jar
cp org/bytedeco/javacpp/linux-x86/*.so* ../src/main/resources
cd ..
gradle jar
cp build/libs/ffmpeg-linux-x86-0.0.1.jar ../../unsigned-jars/ffmpeg-linux-x86-svc2-unsigned.jar
ant sign-jar
cp build/libs/ffmpeg-linux-x86-0.0.1.jar ../../../../app/jws/lib/ffmpeg-linux-x86-svc2.jar
rm -rf workdir
rm -rf src

View File

@ -0,0 +1,10 @@
apply plugin: 'java'
apply plugin: 'eclipse'
sourceCompatibility=1.6
targetCompatibility=1.6
version = '0.0.1'
archivesBaseName = 'ffmpeg-linux-x86_64'

View File

@ -0,0 +1,38 @@
<?xml version="1.0" ?>
<project name="ffmpeg-linux-x86_64-signing" basedir=".">
<!-- Sign jar with Certificate using pkcs12 file -->
<target name="check-certificate">
<input message="Enter cetificate filename:" addproperty="cert.name" />
<input message="Enter cetificate password:" addproperty="cert.password" />
<exec executable="/usr/bin/keytool" outputproperty="cert.info">
<arg line="-list" />
<arg line="-storetype pkcs12" />
<arg line="-keystore ${cert.name}" />
<arg line="-storepass ${cert.password}" />
<arg line="-v" />
</exec>
</target>
<target name="get-alias-name" depends="check-certificate">
<script language="javascript">
<![CDATA[
// getting the value
info = project.getProperty("cert.info");
alias = (info.match(/Alias name:(.*)/)[0]).replace("Alias name: ","");
project.setProperty("cert.alias",alias);
]]>
</script>
</target>
<target name="sign-jar" depends="get-alias-name">
<signjar jar="build/libs/ffmpeg-linux-x86_64-0.0.1.jar"
storetype="pkcs12"
keystore="${cert.name}"
storepass="${cert.password}"
alias="${cert.alias}" />
</target>
</project>

View File

@ -0,0 +1,17 @@
FFMPEG=ffmpeg-3.0.2-1.2-linux-x86_64.jar
mkdir workdir
cp $FFMPEG workdir/ffmpeg-linux-x86_64.jar
rm -rf src
mkdir -p src/main/resources
mkdir -p src/main/java
cd workdir
jar xvf ffmpeg-linux-x86_64.jar
cp org/bytedeco/javacpp/linux-x86_64/*.so* ../src/main/resources
cd ..
gradle jar
cp build/libs/ffmpeg-linux-x86_64-0.0.1.jar ../../unsigned-jars/ffmpeg-linux-x86_64-svc2-unsigned.jar
ant sign-jar
cp build/libs/ffmpeg-linux-x86_64-0.0.1.jar ../../../../app/jws/lib/ffmpeg-linux-x86_64-svc2.jar
rm -rf workdir
rm -rf src

View File

@ -0,0 +1,53 @@
<?xml version="1.0" ?>
<project name="bbb-deskshare-applet" basedir=".">
<!-- How to sign the applet. From Ant in Action book -->
<!-- Sign jar with Certificate using pkcs12 file -->
<target name="check-certificate">
<input message="Enter cetificate filename:" addproperty="cert.name" />
<input message="Enter cetificate password:" addproperty="cert.password" />
<exec executable="/usr/bin/keytool" outputproperty="cert.info">
<arg line="-list" />
<arg line="-storetype pkcs12" />
<arg line="-keystore ${cert.name}" />
<arg line="-storepass ${cert.password}" />
<arg line="-v" />
</exec>
</target>
<target name="get-alias-name" depends="check-certificate">
<script language="javascript">
<![CDATA[
// getting the value
info = project.getProperty("cert.info");
alias = (info.match(/Alias name:(.*)/)[0]).replace("Alias name: ","");
project.setProperty("cert.alias",alias);
]]>
</script>
</target>
<target name="sign-javacpp-jar" depends="get-alias-name">
<signjar jar="workdir/javacpp.jar"
storetype="pkcs12"
keystore="${cert.name}"
storepass="${cert.password}"
alias="${cert.alias}" />
</target>
<target name="sign-ffmpeg-jar" depends="get-alias-name">
<signjar jar="workdir/ffmpeg.jar"
storetype="pkcs12"
keystore="${cert.name}"
storepass="${cert.password}"
alias="${cert.alias}" />
</target>
<target name="sign-javacv-jar" depends="get-alias-name">
<signjar jar="workdir/javacv.jar"
storetype="pkcs12"
keystore="${cert.name}"
storepass="${cert.password}"
alias="${cert.alias}" />
</target>
</project>

View File

@ -0,0 +1,16 @@
FFMPEG=ffmpeg-3.0.2-1.2-svc2.jar
if [ -d "workdir" ]; then
rm -rf workdir
fi
mkdir workdir
cp $FFMPEG workdir
cd workdir
jar xf $FFMPEG
rm $FFMPEG
rm -rf META-INF
jar cf ffmpeg.jar *
cd ..
ant sign-ffmpeg-jar
cp workdir/ffmpeg.jar ../../../../../app/jws/lib/ffmpeg-win-x86-svc2.jar
rm -rf workdir

View File

@ -0,0 +1,10 @@
apply plugin: 'java'
apply plugin: 'eclipse'
sourceCompatibility=1.6
targetCompatibility=1.6
version = '0.0.1'
archivesBaseName = 'ffmpeg-windows-x86'

View File

@ -0,0 +1,38 @@
<?xml version="1.0" ?>
<project name="ffmpeg-win-x86-signing" basedir=".">
<!-- Sign jar with Certificate using pkcs12 file -->
<target name="check-certificate">
<input message="Enter cetificate filename:" addproperty="cert.name" />
<input message="Enter cetificate password:" addproperty="cert.password" />
<exec executable="/usr/bin/keytool" outputproperty="cert.info">
<arg line="-list" />
<arg line="-storetype pkcs12" />
<arg line="-keystore ${cert.name}" />
<arg line="-storepass ${cert.password}" />
<arg line="-v" />
</exec>
</target>
<target name="get-alias-name" depends="check-certificate">
<script language="javascript">
<![CDATA[
// getting the value
info = project.getProperty("cert.info");
alias = (info.match(/Alias name:(.*)/)[0]).replace("Alias name: ","");
project.setProperty("cert.alias",alias);
]]>
</script>
</target>
<target name="sign-jar" depends="get-alias-name">
<signjar jar="build/libs/ffmpeg-windows-x86-0.0.1.jar"
storetype="pkcs12"
keystore="${cert.name}"
storepass="${cert.password}"
alias="${cert.alias}" />
</target>
</project>

View File

@ -0,0 +1,17 @@
FFMPEG=ffmpeg-3.0.2-1.2-windows-x86.jar
mkdir workdir
cp $FFMPEG workdir/ffmpeg-windows-x86.jar
rm -rf src
mkdir -p src/main/resources
mkdir -p src/main/java
cd workdir
jar xvf ffmpeg-windows-x86.jar
cp org/bytedeco/javacpp/windows-x86/*.dll ../src/main/resources
cd ..
rm -rf workdir
gradle jar
cp build/libs/ffmpeg-windows-x86-0.0.1.jar ../../../unsigned-jars/ffmpeg-win-x86-native-svc2-unsigned.jar
ant sign-jar
cp build/libs/ffmpeg-windows-x86-0.0.1.jar ../../../../../app/jws/lib/ffmpeg-win-x86-native-svc2.jar
rm -rf src

View File

@ -10,8 +10,8 @@ cp org/bytedeco/javacpp/windows-x86_64/*.dll ../src/main/resources
cd ..
rm -rf workdir
gradle jar
cp build/libs/ffmpeg-windows-x86_64-0.0.1.jar ../unsigned-jars/ffmpeg-windows-x86_64-unsigned.jar
cp build/libs/ffmpeg-windows-x86_64-0.0.1.jar ../unsigned-jars/ffmpeg-win-x86_64-svc2--unsigned.jar
ant sign-jar
cp build/libs/ffmpeg-windows-x86_64-0.0.1.jar ../../../app/jws/lib/ffmpeg-windows-x86_64.jar
cp build/libs/ffmpeg-windows-x86_64-0.0.1.jar ../../../app/jws/lib/ffmpeg-win-x86_64-svc2.jar
rm -rf src

View File

@ -0,0 +1,53 @@
<?xml version="1.0" ?>
<project name="bbb-deskshare-applet" basedir=".">
<!-- How to sign the applet. From Ant in Action book -->
<!-- Sign jar with Certificate using pkcs12 file -->
<target name="check-certificate">
<input message="Enter cetificate filename:" addproperty="cert.name" />
<input message="Enter cetificate password:" addproperty="cert.password" />
<exec executable="/usr/bin/keytool" outputproperty="cert.info">
<arg line="-list" />
<arg line="-storetype pkcs12" />
<arg line="-keystore ${cert.name}" />
<arg line="-storepass ${cert.password}" />
<arg line="-v" />
</exec>
</target>
<target name="get-alias-name" depends="check-certificate">
<script language="javascript">
<![CDATA[
// getting the value
info = project.getProperty("cert.info");
alias = (info.match(/Alias name:(.*)/)[0]).replace("Alias name: ","");
project.setProperty("cert.alias",alias);
]]>
</script>
</target>
<target name="sign-javacpp-jar" depends="get-alias-name">
<signjar jar="workdir/javacpp.jar"
storetype="pkcs12"
keystore="${cert.name}"
storepass="${cert.password}"
alias="${cert.alias}" />
</target>
<target name="sign-ffmpeg-jar" depends="get-alias-name">
<signjar jar="workdir/ffmpeg.jar"
storetype="pkcs12"
keystore="${cert.name}"
storepass="${cert.password}"
alias="${cert.alias}" />
</target>
<target name="sign-javacv-jar" depends="get-alias-name">
<signjar jar="workdir/javacv.jar"
storetype="pkcs12"
keystore="${cert.name}"
storepass="${cert.password}"
alias="${cert.alias}" />
</target>
</project>

View File

@ -0,0 +1,16 @@
FFMPEG=ffmpeg-3.0.2-1.2-svc2.jar
if [ -d "workdir" ]; then
rm -rf workdir
fi
mkdir workdir
cp $FFMPEG workdir
cd workdir
jar xf $FFMPEG
rm $FFMPEG
rm -rf META-INF
jar cf ffmpeg.jar *
cd ..
ant sign-ffmpeg-jar
cp workdir/ffmpeg.jar ../../../../../app/jws/lib/ffmpeg-win-x86_64-svc2.jar
rm -rf workdir

View File

@ -0,0 +1,10 @@
apply plugin: 'java'
apply plugin: 'eclipse'
sourceCompatibility=1.6
targetCompatibility=1.6
version = '0.0.1'
archivesBaseName = 'ffmpeg-windows-x86_64'

View File

@ -0,0 +1,38 @@
<?xml version="1.0" ?>
<project name="ffmpeg-win-x86-signing" basedir=".">
<!-- Sign jar with Certificate using pkcs12 file -->
<target name="check-certificate">
<input message="Enter cetificate filename:" addproperty="cert.name" />
<input message="Enter cetificate password:" addproperty="cert.password" />
<exec executable="/usr/bin/keytool" outputproperty="cert.info">
<arg line="-list" />
<arg line="-storetype pkcs12" />
<arg line="-keystore ${cert.name}" />
<arg line="-storepass ${cert.password}" />
<arg line="-v" />
</exec>
</target>
<target name="get-alias-name" depends="check-certificate">
<script language="javascript">
<![CDATA[
// getting the value
info = project.getProperty("cert.info");
alias = (info.match(/Alias name:(.*)/)[0]).replace("Alias name: ","");
project.setProperty("cert.alias",alias);
]]>
</script>
</target>
<target name="sign-jar" depends="get-alias-name">
<signjar jar="build/libs/ffmpeg-windows-x86_64-0.0.1.jar"
storetype="pkcs12"
keystore="${cert.name}"
storepass="${cert.password}"
alias="${cert.alias}" />
</target>
</project>

View File

@ -0,0 +1,17 @@
FFMPEG=ffmpeg-3.0.2-1.2-windows-x86_64.jar
mkdir workdir
cp $FFMPEG workdir/ffmpeg-windows-x86_64.jar
rm -rf src
mkdir -p src/main/resources
mkdir -p src/main/java
cd workdir
jar xvf ffmpeg-windows-x86_64.jar
cp org/bytedeco/javacpp/windows-x86_64/*.dll ../src/main/resources
cd ..
rm -rf workdir
gradle jar
cp build/libs/ffmpeg-windows-x86_64-0.0.1.jar ../../../unsigned-jars/ffmpeg-win-x86_64-native-svc2-unsigned.jar
ant sign-jar
cp build/libs/ffmpeg-windows-x86_64-0.0.1.jar ../../../../../app/jws/lib/ffmpeg-win-x86_64-native-svc2.jar
rm -rf src

View File

@ -0,0 +1,16 @@
FFMPEG=ffmpeg-3.0.2-1.2-svc2.jar
if [ -d "workdir" ]; then
rm -rf workdir
fi
mkdir workdir
cp $FFMPEG workdir
cd workdir
jar xf $FFMPEG
rm $FFMPEG
rm -rf META-INF
jar cf ffmpeg.jar *
cd ..
ant sign-ffmpeg-jar
cp workdir/ffmpeg.jar ../../../app/jws/lib/ffmpeg-svc2.jar
rm -rf workdir

View File

@ -0,0 +1,2 @@
cp build/libs/javacv-screenshare-0.0.1.jar /usr/share/red5/webapps/screenshare/lib

View File

@ -94,6 +94,7 @@ public class DeskshareClient {
private boolean fullScreen = false;
private String URL = "rtmp://192.168.23.23/live/foo/room2";
private String session = "";
private Boolean useH264 = false;
public NewBuilder host(String host) {
this.host = host;
@ -155,6 +156,11 @@ public class DeskshareClient {
return this;
}
public NewBuilder useH264(boolean useH264) {
this.useH264 = useH264;
return this;
}
public NewBuilder x(int x) {
this.x = x;
return this;
@ -219,6 +225,7 @@ public class DeskshareClient {
ssi.sysTrayIcon = sysTrayIcon;
ssi.enableTrayActions = enableTrayActions;
ssi.session = session;
ssi.useH264 = useH264;
System.out.println("ScreenShareInfo[captureWidth=" + captureWidth + ",captureHeight=" + captureHeight + "][" + x + "," + y +"]"
+ "[scaleWidth=" + scaleWidth + ",scaleHeight=" + scaleHeight + "]");

View File

@ -106,21 +106,25 @@ public class DeskshareMain implements ClientListener, LifeLineListener {
Boolean captureFullScreen = false;
String session = null;
String codecOptions = null;
boolean useH264 = true;
if(args != null && args.length == 8) {
if(args != null && args.length == 9) {
System.out.println("Using passed args: length=[" + args.length + "]");
url = args[0];
serverUrl = args[1];
meetingId = args[2];
streamId = args[3];
captureFullScreen = Boolean.parseBoolean(args[4]);
useH264 = false;
System.out.println("Using passed args: [" + url + "] meetingId=[" + meetingId + "] streamId=[" + streamId + "] captureFullScreen=" + captureFullScreen);
codecOptions = args[5];
session = args[6];
String errorMessage = args[7];
useH264 = Boolean.parseBoolean(args[7]);
String errorMessage = args[8];
if (! errorMessage.equalsIgnoreCase("NO_ERRORS")) {
dsMain.displayJavaWarning(errorMessage);
@ -147,7 +151,8 @@ public class DeskshareMain implements ClientListener, LifeLineListener {
.captureHeight(cHeightValue).scaleWidth(sWidthValue).scaleHeight(sHeightValue)
.quality(true).autoScale(0).codecOptions(codecOptions)
.x(xValue).y(yValue).fullScreen(captureFullScreen).withURL(url)
.httpTunnel(tunnelValue).trayIcon(image).enableTrayIconActions(true).build();
.httpTunnel(tunnelValue).trayIcon(image).enableTrayIconActions(true)
.useH264(useH264).build();
client.addClientListener(dsMain);
client.start();
@ -218,7 +223,7 @@ public class DeskshareMain implements ClientListener, LifeLineListener {
try {
System.out.println("Trigger stop client. " + exitReasonQ.remainingCapacity());
exitReasonQ.put(reason);
System.out.println("Triggered stop client.");
System.out.println("Triggered stop client. reason=" + reason.getExitCode());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();

View File

@ -114,14 +114,14 @@ public class ScreenRegionSharer implements ScreenSharer, NetworkConnectionListen
public void networkConnectionException(ExitCode reason, String streamId) {
if (listener != null) {
if (reason.getExitCode() == ExitCode.PAUSED.getExitCode()) {
//System.out.println(NAME + "Pausing. Reason=" + reason.getExitCode());
System.out.println(NAME + "Pausing. Reason=" + reason.getExitCode());
pause();
} else if (reason.getExitCode() == ExitCode.START.getExitCode()) {
this.streamId = streamId;
//System.out.println(NAME + "starting. StreamId=" + this.streamId + " fullScreen=" + fullScreen);
System.out.println(NAME + "starting. StreamId=" + this.streamId + " fullScreen=" + fullScreen);
start();
} else {
//System.out.println(NAME + "Closing. Reason=" + reason.getExitCode());
System.out.println(NAME + "Closing. Reason=" + reason.getExitCode());
listener.onClientStop(reason);
}
}

View File

@ -40,4 +40,5 @@ public class ScreenShareInfo {
public boolean enableTrayActions;
public String URL;
public String session;
public boolean useH264;
}

View File

@ -39,8 +39,8 @@ public class ScreenSharerRunner {
this.ssi = ssi;
this.listener = listener;
// System.out.println("ScreenSharerRunner[captureWidth=" + ssi.captureWidth + ",captureHeight=" + ssi.captureHeight + "][" + ssi.x + "," + ssi.y +"]"
// + "[scaleWidth=" + ssi.scaleWidth + ",scaleHeight=" + ssi.scaleHeight + "]");
System.out.println("ScreenSharerRunner[captureWidth=" + ssi.captureWidth + ",captureHeight=" + ssi.captureHeight + "][" + ssi.x + "," + ssi.y +"]"
+ "[scaleWidth=" + ssi.scaleWidth + ",scaleHeight=" + ssi.scaleHeight + "]");
jcs = new FfmpegScreenshare(ssi, listener);
}
@ -76,12 +76,12 @@ public class ScreenSharerRunner {
}
public void disconnectSharing(){
//System.out.println(NAME + "Disconnected");
System.out.println(NAME + "Disconnected");
jcs.stop();
}
public void stopSharing() {
//System.out.println(NAME + "Stopping");
System.out.println(NAME + "Stopping");
jcs.stop();
}

View File

@ -77,6 +77,8 @@ public class FfmpegScreenshare {
System.out.println("Platform : " + Loader.getPlatform());
System.out.println("Platform lib path: " + System.getProperty("java.library.path"));
System.out.println("Capturing w=[" + width + "] h=[" + height + "] at x=[" + x + "] y=[" + y + "]");
System.out.println("URL=" + ssi.URL);
System.out.println("useH264=" + ssi.useH264);
Map<String, String> codecOptions = splitToMap(ssi.codecOptions, "&", "=");
Double frameRate = parseFrameRate(codecOptions.get(FRAMERATE_KEY));
@ -85,13 +87,14 @@ public class FfmpegScreenshare {
String osName = System.getProperty("os.name").toLowerCase();
if (platform.startsWith("windows")) {
grabber = setupWindowsGrabber(width, height, x, y);
mainRecorder = setupWindowsRecorder(URL, width, height, codecOptions);
mainRecorder = setupWindowsRecorder(URL, width, height, codecOptions, ssi.useH264);
} else if (platform.startsWith("linux")) {
grabber = setupLinuxGrabber(width, height, x, y);
mainRecorder = setupLinuxRecorder(URL, width, height, codecOptions);
mainRecorder = setupLinuxRecorder(URL, width, height, codecOptions, ssi.useH264);
} else if (platform.startsWith("macosx-x86_64")) {
grabber = setupMacOsXGrabber(width, height, x, y);
mainRecorder = setupMacOsXRecorder(URL, width, height, codecOptions);
mainRecorder = setupMacOsXRecorder(URL, width, height, codecOptions, ssi.useH264);
}
grabber.setFrameRate(frameRate);
@ -99,6 +102,7 @@ public class FfmpegScreenshare {
ignoreDisconnect = false;
grabber.start();
} catch (Exception e) {
System.out.println("Exception starting grabber.");
listener.networkConnectionException(ExitCode.INTERNAL_ERROR, null);
}
@ -109,6 +113,7 @@ public class FfmpegScreenshare {
try {
mainRecorder.start();
} catch (Exception e) {
System.out.println("Exception starting recorder. \n" + e.toString());
listener.networkConnectionException(ExitCode.INTERNAL_ERROR, null);
}
}
@ -153,13 +158,14 @@ public class FfmpegScreenshare {
//System.out.println("frame timestamp=[" + frame.timestamp + "] ");
mainRecorder.record(frame);
} catch (Exception e) {
//System.out.println("CaptureScreen Exception 1");
System.out.println("CaptureScreen Exception 1");
if (!ignoreDisconnect) {
listener.networkConnectionException(ExitCode.INTERNAL_ERROR, null);
}
}
}
} catch (Exception e1) {
System.out.println("Exception grabbing image");
listener.networkConnectionException(ExitCode.INTERNAL_ERROR, null);
}
@ -168,7 +174,7 @@ public class FfmpegScreenshare {
//System.out.println("timestamp=[" + timestamp + "]");
mainRecorder.setFrameNumber(frameNumber);
// System.out.println("[ENCODER] encoded image " + frameNumber + " in " + (System.currentTimeMillis() - now));
//System.out.println("[ENCODER] encoded image " + frameNumber + " in " + (System.currentTimeMillis() - now));
frameNumber++;
long execDuration = (System.currentTimeMillis() - now);
@ -181,6 +187,7 @@ public class FfmpegScreenshare {
try{
Thread.sleep(dur);
} catch (Exception e){
System.out.println("Exception pausing screen share.");
listener.networkConnectionException(ExitCode.INTERNAL_ERROR, null);
}
}
@ -192,28 +199,29 @@ public class FfmpegScreenshare {
while (startBroadcast){
captureScreen();
}
//System.out.println("*******************Stopped screen capture. !!!!!!!!!!!!!!!!!!!");
System.out.println("*******************Stopped screen capture. !!!!!!!!!!!!!!!!!!!");
}
};
startBroadcastExec.execute(startBroadcastRunner);
}
public void stop() {
//System.out.println("Stopping screen capture.");
System.out.println("Stopping screen capture.");
startBroadcast = false;
if (mainRecorder != null) {
try {
ignoreDisconnect = true;
//System.out.println("mainRecorder.stop.");
System.out.println("mainRecorder.stop.");
mainRecorder.stop();
//System.out.println("mainRecorder.release.");
System.out.println("mainRecorder.release.");
mainRecorder.release();
//System.out.println("grabber.stop.");
System.out.println("grabber.stop.");
// Do not invoke grabber.stop as it exits the JWS app.
// Not sure why. (ralam - aug 10, 2016)
//grabber.stop();
//System.out.println("End stop sequence.");
} catch (Exception e) {
System.out.println("Exception stopping screen share.");
listener.networkConnectionException(ExitCode.INTERNAL_ERROR, null);
}
}
@ -263,7 +271,9 @@ public class FfmpegScreenshare {
//==============================================
// RECORDERS
//==============================================
private FFmpegFrameRecorder setupWindowsRecorder(String url, int width, int height, Map<String, String> codecOptions) {
private FFmpegFrameRecorder setupWindowsRecorder(String url, int width, int height,
Map<String, String> codecOptions,
Boolean useH264) {
FFmpegFrameRecorder winRecorder = new FFmpegFrameRecorder(url, grabber.getImageWidth(), grabber.getImageHeight());
Double frameRate = parseFrameRate(codecOptions.get(FRAMERATE_KEY));
winRecorder.setFrameRate(frameRate);
@ -286,18 +296,29 @@ private FFmpegFrameRecorder setupWindowsRecorder(String url, int width, int hei
winRecorder.setFormat("flv");
// H264
winRecorder.setVideoCodec(AV_CODEC_ID_H264);
winRecorder.setPixelFormat(AV_PIX_FMT_YUV420P);
winRecorder.setVideoOption("crf", "38");
winRecorder.setVideoOption("preset", "veryfast");
winRecorder.setVideoOption("tune", "zerolatency");
winRecorder.setVideoOption("intra-refresh", "1");
if (useH264) {
System.out.println("Using H264 codec");
// H264
winRecorder.setVideoCodec(AV_CODEC_ID_H264);
winRecorder.setPixelFormat(AV_PIX_FMT_YUV420P);
winRecorder.setVideoOption("crf", "38");
winRecorder.setVideoOption("preset", "veryfast");
winRecorder.setVideoOption("tune", "zerolatency");
winRecorder.setVideoOption("intra-refresh", "1");
} else {
System.out.println("Using SVC2 codec");
// Flash SVC2
winRecorder.setVideoCodec(AV_CODEC_ID_FLASHSV2);
winRecorder.setPixelFormat(AV_PIX_FMT_BGR24);
}
return winRecorder;
}
private FFmpegFrameRecorder setupLinuxRecorder(String url, int width, int height, Map<String, String> codecOptions) {
private FFmpegFrameRecorder setupLinuxRecorder(String url, int width, int height,
Map<String, String> codecOptions,
Boolean useH264) {
FFmpegFrameRecorder linuxRecorder = new FFmpegFrameRecorder(url, grabber.getImageWidth(), grabber.getImageHeight());
Double frameRate = parseFrameRate(codecOptions.get(FRAMERATE_KEY));
linuxRecorder.setFrameRate(frameRate);
@ -320,18 +341,28 @@ private FFmpegFrameRecorder setupLinuxRecorder(String url, int width, int heigh
linuxRecorder.setFormat("flv");
// H264
linuxRecorder.setVideoCodec(AV_CODEC_ID_H264);
linuxRecorder.setPixelFormat(AV_PIX_FMT_YUV420P);
linuxRecorder.setVideoOption("crf", "38");
linuxRecorder.setVideoOption("preset", "veryfast");
linuxRecorder.setVideoOption("tune", "zerolatency");
linuxRecorder.setVideoOption("intra-refresh", "1");
if (useH264) {
// H264
linuxRecorder.setVideoCodec(AV_CODEC_ID_H264);
linuxRecorder.setPixelFormat(AV_PIX_FMT_YUV420P);
linuxRecorder.setVideoOption("crf", "38");
linuxRecorder.setVideoOption("preset", "veryfast");
linuxRecorder.setVideoOption("tune", "zerolatency");
linuxRecorder.setVideoOption("intra-refresh", "1");
} else {
// Flash SVC2
linuxRecorder.setVideoCodec(AV_CODEC_ID_FLASHSV2);
linuxRecorder.setPixelFormat(AV_PIX_FMT_BGR24);
}
return linuxRecorder;
}
private FFmpegFrameRecorder setupMacOsXRecorder(String url, int width, int height, Map<String, String> codecOptions) {
private FFmpegFrameRecorder setupMacOsXRecorder(String url, int width, int height,
Map<String, String> codecOptions,
Boolean useH264) {
FFmpegFrameRecorder macRecorder = new FFmpegFrameRecorder(url, grabber.getImageWidth(), grabber.getImageHeight());
Double frameRate = parseFrameRate(codecOptions.get(FRAMERATE_KEY));
macRecorder.setFrameRate(frameRate);
@ -354,13 +385,21 @@ private FFmpegFrameRecorder setupMacOsXRecorder(String url, int width, int heig
macRecorder.setFormat("flv");
// H264
macRecorder.setVideoCodec(AV_CODEC_ID_H264);
macRecorder.setPixelFormat(AV_PIX_FMT_YUV420P);
macRecorder.setVideoOption("crf", "34");
macRecorder.setVideoOption("preset", "veryfast");
if (useH264) {
// H264
macRecorder.setVideoCodec(AV_CODEC_ID_H264);
macRecorder.setPixelFormat(AV_PIX_FMT_YUV420P);
macRecorder.setVideoOption("crf", "34");
macRecorder.setVideoOption("preset", "veryfast");
// Mac doesn't support the options below.
// macRecorder.setVideoOption("tune", "zerolatency");
// macRecorder.setVideoOption("intra-refresh", "1");
} else {
// Flash SVC2
macRecorder.setVideoCodec(AV_CODEC_ID_FLASHSV2);
macRecorder.setPixelFormat(AV_PIX_FMT_BGR24);
}
return macRecorder;
}

View File

@ -34,8 +34,8 @@ package org.bigbluebutton.modules.screenshare.services
conn.isScreenSharing(meetingId);
}
public function requestShareToken(meetingId: String, userId: String, record: Boolean):void {
conn.requestShareToken(meetingId, userId, record);
public function requestShareToken(meetingId: String, userId: String, record: Boolean, tunnel: Boolean):void {
conn.requestShareToken(meetingId, userId, record, tunnel);
}
public function startShareRequest(meetingId: String, userId: String, session: String):void {

View File

@ -24,6 +24,7 @@ package org.bigbluebutton.modules.screenshare.services {
import org.as3commons.logging.api.getClassLogger;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.modules.screenshare.services.red5.Connection;
import org.bigbluebutton.core.BBB;
/**
* The DeskShareProxy communicates with the Red5 deskShare server application
@ -81,7 +82,8 @@ package org.bigbluebutton.modules.screenshare.services {
}
public function requestShareToken():void {
sender.requestShareToken(UsersUtil.getInternalMeetingID(), UsersUtil.getMyUserID(), UsersUtil.isRecorded());
sender.requestShareToken(UsersUtil.getInternalMeetingID(), UsersUtil.getMyUserID(), UsersUtil.isRecorded(),
BBB.initConnectionManager().isTunnelling);
}
public function sharingStartMessage(session: String):void {

View File

@ -163,11 +163,12 @@ package org.bigbluebutton.modules.screenshare.services.red5 {
}, message);
}
public function requestShareToken(meetingId:String, userId:String, record:Boolean):void {
public function requestShareToken(meetingId:String, userId:String, record:Boolean, tunnel: Boolean):void {
var message:Object = new Object();
message["meetingId"] = meetingId;
message["userId"] = userId;
message["record"] = record;
message["tunnel"] = tunnel;
sendMessage("screenshare.requestShareToken", function(result:String):void { // On successful result
LOGGER.debug(result);