Merge remote-tracking branch 'upstream/master' into merge-webrtc-screenshare-2
Conflicts: bigbluebutton-client/resources/config.xml.template bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/ScreenshareManager.as
This commit is contained in:
commit
c057111367
@ -117,7 +117,7 @@ class BigBlueButtonActor(val system: ActorSystem,
|
||||
meetings -= msg.meetingID
|
||||
log.info("Kick everyone out on meetingId={}", msg.meetingID)
|
||||
if (m.mProps.isBreakout) {
|
||||
log.info("Informing parent meeting {} that a breakout room has been ended{}", m.mProps.externalMeetingID, m.mProps.meetingID)
|
||||
log.info("Informing parent meeting {} that a breakout room has been ended {}", m.mProps.externalMeetingID, m.mProps.meetingID)
|
||||
eventBus.publish(BigBlueButtonEvent(m.mProps.externalMeetingID,
|
||||
BreakoutRoomEnded(m.mProps.externalMeetingID, m.mProps.meetingID)))
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ Author: Jesus Federico <jesus@123it.ca>
|
||||
String url = BigBlueButtonURL.replace("bigbluebutton/","demo/");
|
||||
String joinURL = getJoinURLwithDynamicConfigXML(username, confname, configXML);
|
||||
|
||||
if (joinURL.startsWith("https://") || joinURL.startsWith("https://")) {
|
||||
if (joinURL.startsWith("http://") || joinURL.startsWith("https://")) {
|
||||
%>
|
||||
<h2>Customized sessions using a dynamic config.xml, submit</h2>
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
51
bbb-screenshare/app/screenshare.jnlp
Executable file
51
bbb-screenshare/app/screenshare.jnlp
Executable file
@ -0,0 +1,51 @@
|
||||
<?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>$$errorMessage</argument>
|
||||
</application-desc>
|
||||
<security><all-permissions/></security>
|
||||
<update check="always" policy="always"/>
|
||||
</jnlp>
|
@ -1,88 +1,103 @@
|
||||
package org.bigbluebutton.app.screenshare.red5;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.red5.logging.Red5LoggerFactory;
|
||||
import org.red5.server.api.Red5;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
|
||||
public class Red5AppService {
|
||||
private static Logger log = Red5LoggerFactory.getLogger(Red5AppService.class, "screenshare");
|
||||
|
||||
private Red5AppHandler handler;
|
||||
|
||||
/**
|
||||
* Called from the client to pass us the userId.
|
||||
*
|
||||
* We need to do this as we can't have params on the connect call
|
||||
* as FFMpeg won't be able to connect.
|
||||
* @param userId
|
||||
*/
|
||||
public void setUserId(Map<String, Object> msg) {
|
||||
String meetingId = Red5.getConnectionLocal().getScope().getName();
|
||||
String userId = (String) msg.get("userId");
|
||||
|
||||
Red5.getConnectionLocal().setAttribute("MEETING_ID", meetingId);
|
||||
Red5.getConnectionLocal().setAttribute("USERID", userId);
|
||||
|
||||
String connType = getConnectionType(Red5.getConnectionLocal().getType());
|
||||
String connId = Red5.getConnectionLocal().getSessionId();
|
||||
|
||||
Map<String, Object> logData = new HashMap<String, Object>();
|
||||
logData.put("meetingId", meetingId);
|
||||
logData.put("userId", userId);
|
||||
logData.put("connType", connType);
|
||||
logData.put("connId", connId);
|
||||
logData.put("event", "user_joining_bbb_screenshare");
|
||||
logData.put("description", "User joining BBB Screenshare.");
|
||||
|
||||
Gson gson = new Gson();
|
||||
String logStr = gson.toJson(logData);
|
||||
|
||||
log.info("User joining bbb-screenshare: data={}", logStr);
|
||||
}
|
||||
|
||||
private String getConnectionType(String connType) {
|
||||
if ("persistent".equals(connType.toLowerCase())) {
|
||||
return "RTMP";
|
||||
} else if("polling".equals(connType.toLowerCase())) {
|
||||
return "RTMPT";
|
||||
} else {
|
||||
return connType.toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
public void isScreenSharing(Map<String, Object> msg) {
|
||||
String meetingId = Red5.getConnectionLocal().getScope().getName();
|
||||
log.debug("Received check if publishing for meeting=[{}]", meetingId);
|
||||
String userId = (String) Red5.getConnectionLocal().getAttribute("USERID");
|
||||
|
||||
handler.isScreenSharing(meetingId, userId);
|
||||
}
|
||||
|
||||
public void startShareRequest(Map<String, Object> msg) {
|
||||
Boolean record = (Boolean) msg.get("record");
|
||||
String meetingId = Red5.getConnectionLocal().getScope().getName();
|
||||
log.debug("Received startShareRequest for meeting=[{}]", meetingId);
|
||||
String userId = (String) Red5.getConnectionLocal().getAttribute("USERID");
|
||||
|
||||
handler.startShareRequest(meetingId, userId, record);
|
||||
}
|
||||
|
||||
public void stopShareRequest(Map<String, Object> msg) {
|
||||
String meetingId = Red5.getConnectionLocal().getScope().getName();
|
||||
String streamId = (String) msg.get("streamId");
|
||||
log.debug("Received stopShareRequest for meeting=[{}]", meetingId);
|
||||
|
||||
handler.stopShareRequest(meetingId, streamId);
|
||||
}
|
||||
|
||||
|
||||
public void setAppHandler(Red5AppHandler handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
}
|
||||
package org.bigbluebutton.app.screenshare.red5;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.red5.logging.Red5LoggerFactory;
|
||||
import org.red5.server.api.IConnection;
|
||||
import org.red5.server.api.Red5;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
|
||||
public class Red5AppService {
|
||||
private static Logger log = Red5LoggerFactory.getLogger(Red5AppService.class, "screenshare");
|
||||
|
||||
private Red5AppHandler handler;
|
||||
|
||||
/**
|
||||
* Called from the client to pass us the userId.
|
||||
*
|
||||
* We need to do this as we can't have params on the connect call
|
||||
* as FFMpeg won't be able to connect.
|
||||
* @param userId
|
||||
*/
|
||||
public void setUserId(Map<String, Object> msg) {
|
||||
String meetingId = Red5.getConnectionLocal().getScope().getName();
|
||||
String userId = (String) msg.get("userId");
|
||||
|
||||
String connType = getConnectionType(Red5.getConnectionLocal().getType());
|
||||
String sessionId = Red5.getConnectionLocal().getSessionId();
|
||||
|
||||
/**
|
||||
* Find if there are any other connections owned by this user. If we find one,
|
||||
* that means that the connection is old and the user reconnected. Clear the
|
||||
* userId attribute so that messages would not be sent in the defunct connection.
|
||||
*/
|
||||
Set<IConnection> conns = Red5.getConnectionLocal().getScope().getClientConnections();
|
||||
for (IConnection conn : conns) {
|
||||
String connUserId = (String) conn.getAttribute("USERID");
|
||||
if (connUserId != null && connUserId.equals(userId) && conn.getSessionId().equals(sessionId)) {
|
||||
conn.removeAttribute("USERID");
|
||||
}
|
||||
}
|
||||
|
||||
Red5.getConnectionLocal().setAttribute("MEETING_ID", meetingId);
|
||||
Red5.getConnectionLocal().setAttribute("USERID", userId);
|
||||
|
||||
Map<String, Object> logData = new HashMap<String, Object>();
|
||||
logData.put("meetingId", meetingId);
|
||||
logData.put("userId", userId);
|
||||
logData.put("connType", connType);
|
||||
logData.put("connId", sessionId);
|
||||
logData.put("event", "user_joining_bbb_screenshare");
|
||||
logData.put("description", "User joining BBB Screenshare.");
|
||||
|
||||
Gson gson = new Gson();
|
||||
String logStr = gson.toJson(logData);
|
||||
|
||||
log.info("User joining bbb-screenshare: data={}", logStr);
|
||||
}
|
||||
|
||||
private String getConnectionType(String connType) {
|
||||
if ("persistent".equals(connType.toLowerCase())) {
|
||||
return "RTMP";
|
||||
} else if("polling".equals(connType.toLowerCase())) {
|
||||
return "RTMPT";
|
||||
} else {
|
||||
return connType.toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
public void isScreenSharing(Map<String, Object> msg) {
|
||||
String meetingId = Red5.getConnectionLocal().getScope().getName();
|
||||
log.debug("Received check if publishing for meeting=[{}]", meetingId);
|
||||
String userId = (String) Red5.getConnectionLocal().getAttribute("USERID");
|
||||
|
||||
handler.isScreenSharing(meetingId, userId);
|
||||
}
|
||||
|
||||
public void startShareRequest(Map<String, Object> msg) {
|
||||
Boolean record = (Boolean) msg.get("record");
|
||||
String meetingId = Red5.getConnectionLocal().getScope().getName();
|
||||
log.debug("Received startShareRequest for meeting=[{}]", meetingId);
|
||||
String userId = (String) Red5.getConnectionLocal().getAttribute("USERID");
|
||||
|
||||
handler.startShareRequest(meetingId, userId, record);
|
||||
}
|
||||
|
||||
public void stopShareRequest(Map<String, Object> msg) {
|
||||
String meetingId = Red5.getConnectionLocal().getScope().getName();
|
||||
String streamId = (String) msg.get("streamId");
|
||||
log.debug("Received stopShareRequest for meeting=[{}]", meetingId);
|
||||
|
||||
handler.stopShareRequest(meetingId, streamId);
|
||||
}
|
||||
|
||||
|
||||
public void setAppHandler(Red5AppHandler handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
BIN
bbb-screenshare/jws/native-libs/ffmpeg-linux-x86/ffmpeg-3.0.2-1.2-linux-x86.jar
Executable file
BIN
bbb-screenshare/jws/native-libs/ffmpeg-linux-x86/ffmpeg-3.0.2-1.2-linux-x86.jar
Executable file
Binary file not shown.
Binary file not shown.
@ -1,7 +1,8 @@
|
||||
FFMPEG=ffmpeg-2.8.5-1.2-SNAPSHOT-linux-x86.jar
|
||||
cp ffmpeg-2.8.5-1.2-SNAPSHOT-linux-x86.jar build/libs/ffmpeg-linux-x86-0.0.1.jar
|
||||
FFMPEG=ffmpeg-3.0.2-1.2-linux-x86.jar
|
||||
cp $FFMPEG build/libs/ffmpeg-linux-x86-0.0.1.jar
|
||||
mkdir workdir
|
||||
rm -rf src
|
||||
rm -rf workdir
|
||||
cp build/libs/ffmpeg-linux-x86-0.0.1.jar ../unsigned-jars/ffmpeg-linux-x86-unsigned.jar
|
||||
ant sign-jar
|
||||
cp build/libs/ffmpeg-linux-x86-0.0.1.jar ../../../app/jws/lib/ffmpeg-linux-x86.jar
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,6 +1,7 @@
|
||||
FFMPEG=ffmpeg-2.8.5-1.2-SNAPSHOT-linux-x86_64.jar
|
||||
FFMPEG=ffmpeg-3.0.2-1.2-linux-x86_64.jar
|
||||
mkdir workdir
|
||||
rm -rf workdir
|
||||
cp $FFMPEG build/libs/ffmpeg-linux-x86_64-0.0.1.jar
|
||||
cp build/libs/ffmpeg-linux-x86_64-0.0.1.jar ../unsigned-jars/ffmpeg-linux-x86_64-unsigned.jar
|
||||
ant sign-jar
|
||||
cp build/libs/ffmpeg-linux-x86_64-0.0.1.jar ../../../app/jws/lib/ffmpeg-linux-x86_64.jar
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -9,5 +9,8 @@ cp org/bytedeco/javacpp/macosx-x86_64/* ../src/main/resources
|
||||
cd ..
|
||||
rm -rf workdir
|
||||
gradle jar
|
||||
cp build/libs/ffmpeg-macosx-x86_64-0.0.1.jar ../unsigned-jars/ffmpeg-macosx-x86_64-unsigned.jar
|
||||
ant sign-jar
|
||||
cp build/libs/ffmpeg-macosx-x86_64-0.0.1.jar ../../../app/jws/lib/ffmpeg-macosx-x86_64.jar
|
||||
rm -rf src
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
gradle jar
|
||||
ant sign-jar
|
||||
cp build/libs/ffmpeg-win-x86-0.0.1.jar ../../../app/jws/lib/ffmpeg-windows-x86.jar
|
||||
|
Binary file not shown.
@ -1,18 +0,0 @@
|
||||
FFMPEG=ffmpeg-3.0.2-1.2-windows-x86.jar
|
||||
mkdir workdir
|
||||
cp $FFMPEG workdir/ffmpeg-windows-x86.jar
|
||||
SRC_DIR=src
|
||||
if [ -d "$SRC_DIR" ]; then
|
||||
rm -rf src
|
||||
mkdir -p src/main/resources
|
||||
fi
|
||||
cd workdir
|
||||
jar xvf ffmpeg-windows-x86.jar
|
||||
cp org/bytedeco/javacpp/windows-x86/*.dll ../src/main/resources
|
||||
cd ..
|
||||
rm -rf workdir
|
||||
gradle jar
|
||||
ant sign-jar
|
||||
cp build/libs/ffmpeg-windows-x86-0.0.1.jar ../../../app/jws/lib/ffmpeg-windows-x86.jar
|
||||
rm -rf src
|
||||
|
@ -1,16 +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 $FFMPEG build/libs/ffmpeg-windows-x86-0.0.1.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-windows-x86-unsigned.jar
|
||||
ant sign-jar
|
||||
cp build/libs/ffmpeg-windows-x86-0.0.1.jar ../../../app/jws/lib/ffmpeg-windows-x86.jar
|
||||
rm -rf src
|
||||
|
||||
|
Binary file not shown.
@ -10,6 +10,7 @@ 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
|
||||
ant sign-jar
|
||||
cp build/libs/ffmpeg-windows-x86_64-0.0.1.jar ../../../app/jws/lib/ffmpeg-windows-x86_64.jar
|
||||
rm -rf src
|
||||
|
Binary file not shown.
Binary file not shown.
BIN
bbb-screenshare/jws/native-libs/unsigned-jars/ffmpeg-linux-x86-unsigned.jar
Executable file
BIN
bbb-screenshare/jws/native-libs/unsigned-jars/ffmpeg-linux-x86-unsigned.jar
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -441,10 +441,12 @@
|
||||
<copy todir="${OUTPUT_DIR}/lib/" >
|
||||
<fileset dir="${PROD_RESOURCES_DIR}/lib"/>
|
||||
</copy>
|
||||
<copy todir="${OUTPUT_DIR}/help/" >
|
||||
<fileset dir="${PROD_RESOURCES_DIR}/help"/>
|
||||
</copy>
|
||||
<copy file="${PROD_RESOURCES_DIR}/BigBlueButtonTest.html" todir="${OUTPUT_DIR}" overwrite="true"/>
|
||||
<copy file="${PROD_RESOURCES_DIR}/BigBlueButton.html" todir="${OUTPUT_DIR}" overwrite="true"/>
|
||||
<copy file="${PROD_RESOURCES_DIR}/DeskshareStandalone.html" todir="${OUTPUT_DIR}" overwrite="true"/>
|
||||
<copy file="${PROD_RESOURCES_DIR}/screenshare-help.html" todir="${OUTPUT_DIR}" overwrite="true"/>
|
||||
<copy file="${PROD_RESOURCES_DIR}/get_flash_player.gif" todir="${OUTPUT_DIR}" overwrite="true"/>
|
||||
<copy file="${PROD_RESOURCES_DIR}/bbb.gif" todir="${OUTPUT_DIR}" overwrite="true"/>
|
||||
<copy file="${PROD_RESOURCES_DIR}/avatar.png" todir="${OUTPUT_DIR}" overwrite="true"/>
|
||||
|
@ -55,7 +55,7 @@
|
||||
vertoHostName="HOST.NAME"
|
||||
vertoLogin="LOGIN"
|
||||
vertoPassword="PASSWORD"
|
||||
help="http://HOST/client/screenshare-help.html"
|
||||
help="http://HOST/client/help/screenshare-help.html"
|
||||
/>
|
||||
|
||||
<module name="PhoneModule" url="http://HOST/client/PhoneModule.swf?v=VERSION"
|
||||
|
116
bigbluebutton-client/resources/prod/help/CSS/bbb-bootstrap.css
Executable file
116
bigbluebutton-client/resources/prod/help/CSS/bbb-bootstrap.css
Executable file
@ -0,0 +1,116 @@
|
||||
/*!
|
||||
* This stylesheet is a subset of Bootstrap v3.3.6 (http://getbootstrap.com)
|
||||
* Copyright 2011-2015 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
*/
|
||||
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
|
||||
|
||||
.alert {
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.alert h4 {
|
||||
margin-top: 0;
|
||||
color: inherit;
|
||||
}
|
||||
.alert .alert-link {
|
||||
font-weight: bold;
|
||||
}
|
||||
.alert > p,
|
||||
.alert > ul {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.alert > p + p {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.alert-dismissable,
|
||||
.alert-dismissible {
|
||||
padding-right: 35px;
|
||||
}
|
||||
.alert-dismissable .close,
|
||||
.alert-dismissible .close {
|
||||
position: relative;
|
||||
top: -2px;
|
||||
right: -21px;
|
||||
color: inherit;
|
||||
}
|
||||
.alert-success {
|
||||
color: #3c763d;
|
||||
background-color: #dff0d8;
|
||||
border-color: #d6e9c6;
|
||||
}
|
||||
.alert-success hr {
|
||||
border-top-color: #c9e2b3;
|
||||
}
|
||||
.alert-success .alert-link {
|
||||
color: #2b542c;
|
||||
}
|
||||
.alert-info {
|
||||
color: #31708f;
|
||||
background-color: #d9edf7;
|
||||
border-color: #bce8f1;
|
||||
}
|
||||
.alert-info hr {
|
||||
border-top-color: #a6e1ec;
|
||||
}
|
||||
.alert-info .alert-link {
|
||||
color: #245269;
|
||||
}
|
||||
.alert-warning {
|
||||
color: #8a6d3b;
|
||||
background-color: #fcf8e3;
|
||||
border-color: #faebcc;
|
||||
}
|
||||
.alert-warning hr {
|
||||
border-top-color: #f7e1b5;
|
||||
}
|
||||
.alert-warning .alert-link {
|
||||
color: #66512c;
|
||||
}
|
||||
.alert-danger {
|
||||
color: #a94442;
|
||||
background-color: #f2dede;
|
||||
border-color: #ebccd1;
|
||||
}
|
||||
.alert-danger hr {
|
||||
border-top-color: #e4b9c0;
|
||||
}
|
||||
.alert-danger .alert-link {
|
||||
color: #843534;
|
||||
}
|
||||
.close {
|
||||
float: right;
|
||||
font-size: 21px;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
color: #000;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
filter: alpha(opacity=20);
|
||||
opacity: .2;
|
||||
}
|
||||
.close:hover,
|
||||
.close:focus {
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
filter: alpha(opacity=50);
|
||||
opacity: .5;
|
||||
}
|
||||
button.close {
|
||||
-webkit-appearance: none;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
}
|
||||
.fade {
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity .15s linear;
|
||||
-o-transition: opacity .15s linear;
|
||||
transition: opacity .15s linear;
|
||||
}
|
||||
.fade.in {
|
||||
opacity: 1;
|
||||
}
|
241
bigbluebutton-client/resources/prod/help/CSS/bijou.min.css
vendored
Executable file
241
bigbluebutton-client/resources/prod/help/CSS/bijou.min.css
vendored
Executable file
@ -0,0 +1,241 @@
|
||||
a {
|
||||
font-size:.95em;
|
||||
text-decoration:none;
|
||||
color:#5f90b0
|
||||
}
|
||||
a:hover {
|
||||
color:#406882
|
||||
}
|
||||
* {
|
||||
margin:0;
|
||||
padding:0;
|
||||
font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;
|
||||
-webkit-box-sizing:border-box;
|
||||
-moz-box-sizing:border-box;
|
||||
box-sizing:border-box
|
||||
}
|
||||
.container {
|
||||
width:1000px;
|
||||
margin:0 auto
|
||||
}
|
||||
.pull-left {
|
||||
float:left
|
||||
}
|
||||
.pull-right {
|
||||
float:right
|
||||
}
|
||||
.row {
|
||||
min-height:2em;
|
||||
line-height:2em;
|
||||
width:100%
|
||||
}
|
||||
.span {
|
||||
float:left;
|
||||
display:inline;
|
||||
min-height:1em;
|
||||
margin:0 .5% 20px
|
||||
}
|
||||
.span:four-child {
|
||||
margin-left:0
|
||||
}
|
||||
.span:last-child {
|
||||
margin-right:0
|
||||
}
|
||||
.one {
|
||||
width:8%
|
||||
}
|
||||
.two {
|
||||
width:16%
|
||||
}
|
||||
.three {
|
||||
width:24%
|
||||
}
|
||||
.four {
|
||||
width:32%
|
||||
}
|
||||
.five {
|
||||
width:40%
|
||||
}
|
||||
.six {
|
||||
width:48%
|
||||
}
|
||||
.seven {
|
||||
width:56%
|
||||
}
|
||||
.eight {
|
||||
width:64%
|
||||
}
|
||||
.nine {
|
||||
width:72%
|
||||
}
|
||||
.ten {
|
||||
width:80%
|
||||
}
|
||||
.eleven {
|
||||
width:88%
|
||||
}
|
||||
.twelve {
|
||||
width:100%
|
||||
}
|
||||
.container:after {
|
||||
content:"\0020";
|
||||
display:block;
|
||||
height:0;
|
||||
clear:both;
|
||||
visibility:hidden
|
||||
}
|
||||
.row:after,.row:before {
|
||||
content:'\0020';
|
||||
display:block;
|
||||
overflow:hidden;
|
||||
visibility:hidden;
|
||||
width:0;
|
||||
height:0
|
||||
}
|
||||
.row:after {
|
||||
clear:both
|
||||
}
|
||||
.row {
|
||||
zoom:1
|
||||
}
|
||||
h1,h2,h3,h4,h5,h6 {
|
||||
font-weight:400;
|
||||
color:#42444c
|
||||
}
|
||||
h1 {
|
||||
font-size:2.5em;
|
||||
line-height:1em
|
||||
}
|
||||
h2 {
|
||||
font-size:1.75em;
|
||||
line-height:1em;
|
||||
margin-bottom:.375em
|
||||
}
|
||||
h3 {
|
||||
font-size:1.125em
|
||||
}
|
||||
h4 {
|
||||
font-size:1.1em;
|
||||
font-weight:700
|
||||
}
|
||||
.table {
|
||||
width:100%;
|
||||
border-spacing:0;
|
||||
border-collapse:collapse;
|
||||
text-align:left
|
||||
}
|
||||
.table td,.table th {
|
||||
border-bottom:2px #d1d1d1 solid;
|
||||
padding:8px 12px
|
||||
}
|
||||
.table td {
|
||||
border-bottom:1px #d4d4d4 solid
|
||||
}
|
||||
.table.table-striped tbody tr:nth-child(2n+1) {
|
||||
background-color:#f3f3f3
|
||||
}
|
||||
.table.table-bordered,.table.table-bordered td,.table.table-bordered th {
|
||||
border:1px solid #CCC
|
||||
}
|
||||
.button {
|
||||
border:0;
|
||||
border-radius:4px;
|
||||
outline:0;
|
||||
cursor:pointer
|
||||
}
|
||||
.button.small {
|
||||
padding:7px 20px;
|
||||
font-size:.95em
|
||||
}
|
||||
.button.large {
|
||||
padding:10px 45px;
|
||||
font-size:1.1em
|
||||
}
|
||||
.button.primary {
|
||||
color:#FFF;
|
||||
background:#5f90b0
|
||||
}
|
||||
.button.primary:hover {
|
||||
background:#5589ab
|
||||
}
|
||||
.button.success {
|
||||
color:#FFF;
|
||||
background:#4daf7c
|
||||
}
|
||||
.button.success:hover {
|
||||
background:#48a474
|
||||
}
|
||||
.button.danger {
|
||||
color:#FFF;
|
||||
background:#e6623c
|
||||
}
|
||||
.button.danger:hover {
|
||||
background:#e4572e
|
||||
}
|
||||
.navbar {
|
||||
background:#FFF;
|
||||
padding:10px;
|
||||
margin-bottom:60px;
|
||||
border-bottom:1px #F2F2F2 solid;
|
||||
text-align:center
|
||||
}
|
||||
.navbar h4 {
|
||||
color:#191919;
|
||||
font-weight:200
|
||||
}
|
||||
.navbar li {
|
||||
display:inline-block;
|
||||
padding:.3em 15px 0 0
|
||||
}
|
||||
.navbar li:last-child {
|
||||
padding-right:0
|
||||
}
|
||||
.navbar.fixed {
|
||||
position:fixed;
|
||||
left:0;
|
||||
right:0;
|
||||
top:0
|
||||
}
|
||||
.alert {
|
||||
padding:15px;
|
||||
margin:10px 0;
|
||||
border-radius:3px
|
||||
}
|
||||
.alert.primary {
|
||||
background:#e8eff3;
|
||||
border:1px solid #c5d7e3
|
||||
}
|
||||
.alert.success {
|
||||
background:#daeee4;
|
||||
border:1px solid #b6dfca
|
||||
}
|
||||
.alert.danger {
|
||||
background:#fdf4f1;
|
||||
border:1px solid #f7cfc4
|
||||
}
|
||||
@media only screen and (min-width:768px) and (max-width:999px) {
|
||||
.container {
|
||||
width:768px
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width:767px) {
|
||||
.container {
|
||||
width:300px
|
||||
}
|
||||
.container .span {
|
||||
width:100%!important
|
||||
}
|
||||
.container .table {
|
||||
width:100%;
|
||||
display:block;
|
||||
overflow:auto
|
||||
}
|
||||
}
|
||||
@media only screen and (min-width:480px) and (max-width:767px) {
|
||||
.container {
|
||||
width:420px
|
||||
}
|
||||
.container .table {
|
||||
display:table
|
||||
}
|
||||
}
|
8
bigbluebutton-client/resources/prod/help/CSS/css
Executable file
8
bigbluebutton-client/resources/prod/help/CSS/css
Executable file
@ -0,0 +1,8 @@
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Rokkitt';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Rokkitt'), local('Rokkitt-Regular'), url(http://fonts.gstatic.com/s/rokkitt/v10/o9LMKUV9IIiOIghfS6ZGbALUuEpTyoUstqEm5AMlJo4.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
284
bigbluebutton-client/resources/prod/help/CSS/diggdigg-style.css
Executable file
284
bigbluebutton-client/resources/prod/help/CSS/diggdigg-style.css
Executable file
@ -0,0 +1,284 @@
|
||||
.FBConnectButton_Small,.FBConnectButton_RTL_Small {
|
||||
border-left:1px solid #1a356e;
|
||||
width:54px;
|
||||
background:-5px -232px!important
|
||||
}
|
||||
|
||||
.FBConnectButton_Small .FBConnectButton_Text {
|
||||
margin-left:12px!important
|
||||
}
|
||||
|
||||
.dd-digg-ajax-load,.dd-reddit-ajax-load,.dd-dzone-ajax-load,.dd-ybuzz-ajax-load,.dd-twitter-ajax-load,.dd-fbshare-ajax-load,.dd-fblike-ajax-load,.dd-delicious-ajax-load,.dd-sphinn-ajax-load,.dd-gbuzz-ajax-load,.dd-fbshareme-ajax-load,.dd-tweetmeme-ajax-load,.dd-linkedin-ajax-load,.dd-google1-ajax-load {
|
||||
width:50px;
|
||||
height:22px;
|
||||
background:url(../image/ajax-loader.gif) no-repeat center
|
||||
}
|
||||
|
||||
.dd_delicious {
|
||||
display:block;
|
||||
color:#000;
|
||||
font:16px arial;
|
||||
text-decoration:none;
|
||||
width:50px;
|
||||
height:60px;
|
||||
text-align:center
|
||||
}
|
||||
|
||||
.dd_delicious a:link,.dd_delicious a:visited,.dd_delicious a:active,.dd_delicious a:hover {
|
||||
text-decoration:none;
|
||||
color:#000
|
||||
}
|
||||
|
||||
.dd_delicious_normal_image {
|
||||
text-align:center;
|
||||
height:60px;
|
||||
margin-top:3px;
|
||||
padding:0;
|
||||
text-align:center;
|
||||
width:50px;
|
||||
display:block;
|
||||
background:url(../image/delicious.png) no-repeat
|
||||
}
|
||||
|
||||
.dd_delicious_compact_image {
|
||||
text-align:center;
|
||||
height:22px;
|
||||
padding:0;
|
||||
text-align:center;
|
||||
width:50px;
|
||||
display:block;
|
||||
background:url(../image/delicious-compact.png) no-repeat
|
||||
}
|
||||
|
||||
.dd_delicious_compact_image span {
|
||||
font-size:10px
|
||||
}
|
||||
|
||||
.dd_comments {
|
||||
text-align:center;
|
||||
height:16px;
|
||||
margin-top:3px;
|
||||
padding:0;
|
||||
text-align:center;
|
||||
width:50px;
|
||||
display:block;
|
||||
background:url(../image/comments-link.png) no-repeat
|
||||
}
|
||||
|
||||
.dd_button a:link,.dd_button a:visited,.dd_button a:active {
|
||||
text-decoration:none;
|
||||
color:#000
|
||||
}
|
||||
|
||||
#dd_ajax_float {
|
||||
text-align:center;
|
||||
border:1px solid #bbb;
|
||||
min-width:55px;
|
||||
width:auto;
|
||||
-webkit-border-top-right-radius:5px;
|
||||
-webkit-border-bottom-right-radius:5px;
|
||||
-webkit-border-bottom-left-radius:5px;
|
||||
-webkit-border-top-left-radius:5px;
|
||||
-moz-border-radius-topright:5px;
|
||||
-moz-border-radius-bottomright:5px;
|
||||
-moz-border-radius-bottomleft:5px;
|
||||
-moz-border-radius-topleft:5px;
|
||||
border-top-right-radius:5px;
|
||||
border-bottom-right-radius:5px;
|
||||
border-bottom-left-radius:5px;
|
||||
border-top-left-radius:5px;
|
||||
-moz-background-clip:padding;
|
||||
-webkit-background-clip:padding-box;
|
||||
-webkit-box-shadow:1px 0 15px rgba(0,0,0,.2);
|
||||
-moz-box-shadow:1px 0 15px rgba(0,0,0,.2);
|
||||
box-shadow:1px 0 15px rgba(0,0,0,.2);
|
||||
padding:5px;
|
||||
position:absolute;
|
||||
display:none;
|
||||
left:-120px;
|
||||
font:10px/16px Arial;
|
||||
background:padding-box #fff
|
||||
}
|
||||
|
||||
#dd_ajax_float .dd_button_v {
|
||||
width:auto;
|
||||
height:auto;
|
||||
line-height:0;
|
||||
padding:4px 1px
|
||||
}
|
||||
|
||||
#dd_ajax_float iframe {
|
||||
margin:0
|
||||
}
|
||||
|
||||
#dd_start,#dd_end {
|
||||
float:left;
|
||||
clear:both
|
||||
}
|
||||
|
||||
.dd_outer {
|
||||
width:100%;
|
||||
height:0;
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
z-index:9999
|
||||
}
|
||||
|
||||
.dd_inner {
|
||||
margin:0 auto;
|
||||
position:relative
|
||||
}
|
||||
|
||||
.dd_post_share {
|
||||
padding:0;
|
||||
margin-bottom:6px;
|
||||
display:block
|
||||
}
|
||||
|
||||
.dd_post_share_left {
|
||||
float:left
|
||||
}
|
||||
|
||||
.dd_post_share_right {
|
||||
float:right
|
||||
}
|
||||
|
||||
.dd_buttons img {
|
||||
border:none;
|
||||
border-width:0;
|
||||
border-color:#000;
|
||||
border-style:none
|
||||
}
|
||||
|
||||
#dd_name {
|
||||
color:#a9a9a9;
|
||||
font-size:8px;
|
||||
text-align:center;
|
||||
margin:8px 0 6px;
|
||||
padding:0;
|
||||
line-height:0
|
||||
}
|
||||
|
||||
#dd_name a:link,#dd_name a:visited,#dd_name a:active {
|
||||
text-decoration:none;
|
||||
color:#a9a9a9;
|
||||
border:0
|
||||
}
|
||||
|
||||
#dd_name a:hover {
|
||||
text-decoration:underline;
|
||||
color:#a9a9a9;
|
||||
border:0
|
||||
}
|
||||
|
||||
.dd_button {
|
||||
float:left;
|
||||
padding:4px
|
||||
}
|
||||
|
||||
.dd_fblike_xfbml_ajax_left_float {
|
||||
padding-left:3px
|
||||
}
|
||||
|
||||
.dd_google1_ajax_left_float {
|
||||
margin-left:-1px
|
||||
}
|
||||
|
||||
.dd_linkedin_ajax_left_float {
|
||||
margin-left:-2px;
|
||||
margin-bottom:-5px
|
||||
}
|
||||
|
||||
html {
|
||||
overflow-y:scroll
|
||||
}
|
||||
|
||||
.dd_button_spacer {
|
||||
padding-top:8px
|
||||
}
|
||||
|
||||
#dd_comments {
|
||||
clear:both!important;
|
||||
width:50px;
|
||||
height:60px;
|
||||
font-family:arial
|
||||
}
|
||||
|
||||
#dd_comments a:link,#dd_comments a:visited,#dd_comments a:active,#dd_comments a:hover {
|
||||
text-decoration:none
|
||||
}
|
||||
|
||||
#dd_comments .clcount {
|
||||
text-align:center;
|
||||
color:#444;
|
||||
display:block;
|
||||
font-size:20px;
|
||||
height:34px;
|
||||
padding:4px 0;
|
||||
position:relative;
|
||||
text-align:center;
|
||||
width:50px;
|
||||
line-height:24px;
|
||||
background:url(../image/comments-count.png) no-repeat left top
|
||||
}
|
||||
|
||||
#dd_comments .ccount {
|
||||
color:#444;
|
||||
font-size:17px;
|
||||
text-align:center;
|
||||
text-decoration:none
|
||||
}
|
||||
|
||||
#dd_comments .clink {
|
||||
text-align:center;
|
||||
height:16px;
|
||||
margin-top:3px;
|
||||
padding:0;
|
||||
text-align:center;
|
||||
width:50px;
|
||||
display:block;
|
||||
background:url(../image/comments-link.png) no-repeat
|
||||
}
|
||||
|
||||
.dd_button_extra_v {
|
||||
padding:1px 4px
|
||||
}
|
||||
|
||||
.st_email_custom {
|
||||
padding:2px 4px 3px;
|
||||
border:1px solid #ddd;
|
||||
-moz-border-radius:2px;
|
||||
cursor:pointer;
|
||||
margin-bottom:2px;
|
||||
background:url(../image/email.png) no-repeat 3px 4px
|
||||
}
|
||||
|
||||
#dd_print_button {
|
||||
padding:1px 4px 3px;
|
||||
border:1px solid #ddd;
|
||||
-moz-border-radius:2px;
|
||||
cursor:pointer;
|
||||
margin-bottom:2px;
|
||||
background:url(../image/print.png) no-repeat 3px 2px
|
||||
}
|
||||
|
||||
#dd_email_text {
|
||||
padding:0 0 0 18px;
|
||||
font-size:10px
|
||||
}
|
||||
|
||||
#dd_print_text {
|
||||
padding:0 0 0 14px;
|
||||
font-size:10px
|
||||
}
|
||||
|
||||
#dd_print_text a:link,#dd_print_text a:visited,#dd_print_text a:active {
|
||||
color:#000;
|
||||
text-decoration:none
|
||||
}
|
||||
|
||||
#dd_print_text a:hover {
|
||||
color:#00f;
|
||||
text-decoration:underline
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
/*****************************/
|
||||
/* Hide the WordPress commenting form
|
||||
/*****************************/
|
||||
|
||||
#respond, #commentform, #addcomment, .entry-comments {
|
||||
display: none;
|
||||
}
|
77
bigbluebutton-client/resources/prod/help/CSS/facebook-comments-widgets.css
Executable file
77
bigbluebutton-client/resources/prod/help/CSS/facebook-comments-widgets.css
Executable file
@ -0,0 +1,77 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
/*****************************/
|
||||
/* Dashboard widget styles
|
||||
/*****************************/
|
||||
|
||||
|
||||
/*****************************/
|
||||
/* Normal, page widget styles
|
||||
|
||||
displayed here in order rendered
|
||||
/*****************************/
|
||||
/* Each post is styled as follows:
|
||||
<li class="fbc_rc_comment old/even">
|
||||
<div class="fbc_rc_comment-meta">
|
||||
<cite class="fbc_rc_comment-author">
|
||||
<a href="https://www.facebook.com/profile.php?id=FACEBOOKID">
|
||||
USERNAME
|
||||
</a>
|
||||
</cite>
|
||||
<abbr class="fbc_rc_date">
|
||||
Date/Time
|
||||
</abbr>
|
||||
</div>
|
||||
<img class="avatar" height="50" width="50" />
|
||||
<div class="fbc_rc_text">
|
||||
COMMENT CONTENT
|
||||
</div>
|
||||
<div class="fbc_rc_permalink">
|
||||
<a href=permalink>
|
||||
Post or Page Title
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
*/
|
||||
|
||||
/* Main widget, which is enclosed in a ul */
|
||||
#fbc_rc_widget {
|
||||
width: auto;
|
||||
margin-left:0 !important; /* override WP default */
|
||||
}
|
||||
li.fbc_rc_comment {
|
||||
min-height: 80px; /* to prevent overlap */
|
||||
height:100%;
|
||||
position:relative;
|
||||
margin:2px;
|
||||
border-bottom: 1px dotted rgba(88,88,88,1);
|
||||
}
|
||||
/* odd and even are so you can style alternating posts differently, if you'd like to */
|
||||
ul#fbc_rc_widget li.odd { }
|
||||
ul#fbc_rc_widget li.even {
|
||||
background-color:rgba(222,222,251,1);
|
||||
}/* change to float:left to display avatars on the left of comments */
|
||||
|
||||
/* encloses both author and date */
|
||||
.fbc_rc_comment-meta { }
|
||||
.fbc_rc_comment-author { }
|
||||
.fbc_rc_date {
|
||||
font-size:.8em;
|
||||
}
|
||||
|
||||
ul#fbc_rc_widget .avatar {
|
||||
float: right; /* change to float:left to display avatars on the left of comments */
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
/* main comment text */
|
||||
.fbc_rc_text {
|
||||
margin: 5px;
|
||||
padding-bottom:25px; /* to prevent post titles from overlapping with comment text */
|
||||
}
|
||||
|
||||
.fbc_rc_permalink {
|
||||
position: absolute;
|
||||
bottom: 2px;
|
||||
}
|
||||
|
1495
bigbluebutton-client/resources/prod/help/CSS/font-awesome.min.css
vendored
Executable file
1495
bigbluebutton-client/resources/prod/help/CSS/font-awesome.min.css
vendored
Executable file
File diff suppressed because it is too large
Load Diff
3
bigbluebutton-client/resources/prod/help/CSS/inlinestylesheet0
Executable file
3
bigbluebutton-client/resources/prod/help/CSS/inlinestylesheet0
Executable file
@ -0,0 +1,3 @@
|
||||
.SandboxRoot {
|
||||
display: none;
|
||||
}
|
35
bigbluebutton-client/resources/prod/help/CSS/inlinestylesheetnum10
Executable file
35
bigbluebutton-client/resources/prod/help/CSS/inlinestylesheetnum10
Executable file
@ -0,0 +1,35 @@
|
||||
.home-highlights .home-highlights-content {
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
color: #464646;
|
||||
}
|
||||
|
||||
.home-highlights h4 {
|
||||
margin: 0;
|
||||
font-size: 160%;
|
||||
line-height: 120%;
|
||||
color: #30406b;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: 'Open Sans', sans-serif !important;
|
||||
|
||||
}
|
||||
|
||||
h1.overview {
|
||||
font-family: "Open Sans","Lucida Grande","Lucida Sans Unicode",Helvetica,Arial,sans-serif;
|
||||
|
||||
}
|
||||
|
||||
img.aligncenter {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
span.post-comment iframe {
|
||||
width:150px !important;
|
||||
}
|
||||
|
||||
.post-meta .post-comment{
|
||||
background: none!important;
|
||||
padding-left:0px;
|
||||
}
|
13
bigbluebutton-client/resources/prod/help/CSS/inlinestylesheetnum5
Executable file
13
bigbluebutton-client/resources/prod/help/CSS/inlinestylesheetnum5
Executable file
@ -0,0 +1,13 @@
|
||||
|
||||
img.wp-smiley,
|
||||
img.emoji {
|
||||
display: inline !important;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
height: 1em !important;
|
||||
width: 1em !important;
|
||||
margin: 0 .07em !important;
|
||||
vertical-align: -0.1em !important;
|
||||
background: none !important;
|
||||
padding: 0 !important;
|
||||
}
|
75
bigbluebutton-client/resources/prod/help/CSS/inlinestylesheetnum9
Executable file
75
bigbluebutton-client/resources/prod/help/CSS/inlinestylesheetnum9
Executable file
@ -0,0 +1,75 @@
|
||||
|
||||
#headerwrap {
|
||||
background-image: none;
|
||||
background-color: #dbebf6;
|
||||
}
|
||||
|
||||
#nav-bar {
|
||||
background-image: url(http://r2.bigbluebutton.org/wp-content/themes/suco/uploads/bg/bg1.png);
|
||||
background-color: #30406b;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
#upperwrap {
|
||||
background-image: url(http://r2.bigbluebutton.org/wp-content/themes/suco/uploads/bg/bg1.png);
|
||||
background-color: #F4F4F4 ;
|
||||
}
|
||||
|
||||
.home-highlightswrap {
|
||||
background-image: none;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
#body {
|
||||
background-image: none;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.footer-widgetswrap {
|
||||
background-image: none;
|
||||
background-color: #262626;
|
||||
}
|
||||
|
||||
#footerwrap {
|
||||
background-image: none;
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: #00445e;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: #00445e;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: #00445e;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: #30406b;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: #30406b;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
#main-nav a:hover, #main-nav li:hover > a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#main-nav .current_page_item a, #main-nav .current-menu-item a {
|
||||
color: #fff;
|
||||
background-color: #1a243f;
|
||||
}
|
||||
|
470
bigbluebutton-client/resources/prod/help/CSS/media-queries.css
Executable file
470
bigbluebutton-client/resources/prod/help/CSS/media-queries.css
Executable file
@ -0,0 +1,470 @@
|
||||
@media screen and (max-width: 980px) {
|
||||
|
||||
/* set img max-width */
|
||||
img {
|
||||
width: auto\9; /* ie8 */
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
STRUCTURE
|
||||
*************************************************************************************/
|
||||
.pagewidth, #slider {
|
||||
max-width: 94%;
|
||||
}
|
||||
|
||||
/* content */
|
||||
#content {
|
||||
margin: 7% 0 5%;
|
||||
}
|
||||
.sidebar1 #content {
|
||||
max-width: 67.8%;
|
||||
}
|
||||
|
||||
/* sidebar */
|
||||
#sidebar {
|
||||
margin: 7% 0 5%;
|
||||
max-width: 26.2%;
|
||||
}
|
||||
#sidebar .secondary {
|
||||
max-width: 47%;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
GRID
|
||||
*************************************************************************************/
|
||||
.col4-1,
|
||||
.col4-2,
|
||||
.col4-3,
|
||||
.col3-1,
|
||||
.col3-2,
|
||||
.col2-1
|
||||
{
|
||||
margin-left: 2%;
|
||||
}
|
||||
.col4-1 {
|
||||
max-width: 23%;
|
||||
}
|
||||
.col4-2, .col2-1 {
|
||||
max-width: 48%;
|
||||
}
|
||||
.col4-3 {
|
||||
max-width: 72%;
|
||||
}
|
||||
.col3-1 {
|
||||
max-width: 31%;
|
||||
}
|
||||
.col3-2 {
|
||||
max-width: 62%;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
SLIDER
|
||||
*************************************************************************************/
|
||||
#slider .slide-feature-image {
|
||||
max-width: 40%;
|
||||
margin-right: 3%;
|
||||
margin-bottom: 2%;
|
||||
}
|
||||
#slider .slide-content {
|
||||
padding: 1% 0 0;
|
||||
font-size: 100%;
|
||||
line-height: 130%;
|
||||
overflow: visible;
|
||||
}
|
||||
#slider img {
|
||||
width: auto\9; /* ie8 */
|
||||
max-width: 98.5%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
LAYOUTS
|
||||
*************************************************************************************/
|
||||
/* list post */
|
||||
.list-post .post,
|
||||
.list-post .type-page,
|
||||
.list-post .attachment {
|
||||
width: 80% !important;
|
||||
}
|
||||
|
||||
/* grid4 */
|
||||
.grid4 .post {
|
||||
width: 23.125%;
|
||||
margin-left: 2.5%;
|
||||
}
|
||||
|
||||
/* grid3 */
|
||||
.grid3 .post {
|
||||
width: 31%;
|
||||
margin-left: 3.5%;
|
||||
}
|
||||
|
||||
/* grid2 */
|
||||
.grid2 .post {
|
||||
width: 48%;
|
||||
margin-left: 3.75%;
|
||||
}
|
||||
|
||||
.social-widget {
|
||||
color:#30406B;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media screen and (max-width: 760px) {
|
||||
|
||||
/************************************************************************************
|
||||
STRUCTURE
|
||||
*************************************************************************************/
|
||||
.sidebar1 #content {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
float: none;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* sidebar */
|
||||
#sidebar {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
float: none;
|
||||
clear: both;
|
||||
}
|
||||
#sidebar .secondary {
|
||||
width: 48%;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
HEADER
|
||||
*************************************************************************************/
|
||||
/* reset absolute elements to static */
|
||||
#header .social-widget, #site-logo, #site-description, #header #searchform, #main-nav {
|
||||
position: static !important;
|
||||
float: none;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* header */
|
||||
#header {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#header .rss a {
|
||||
color:#30406B;
|
||||
}
|
||||
|
||||
/* header widget */
|
||||
.header-widget {
|
||||
position: static !important;
|
||||
float: none;
|
||||
text-align: left;
|
||||
clear: both;
|
||||
margin: 0;
|
||||
}
|
||||
.header-widget .widget {
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
/* nav bar */
|
||||
#nav-bar {
|
||||
height: 10px;
|
||||
position: static !important;
|
||||
}
|
||||
|
||||
/* social widget */
|
||||
#header .social-widget {
|
||||
padding: 5px 0 20px;
|
||||
}
|
||||
|
||||
/* search form */
|
||||
#header #searchform {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: inherit;
|
||||
right: 0;
|
||||
width: 150px;
|
||||
}
|
||||
#header #searchform #s {
|
||||
display:none;
|
||||
/* float: right;
|
||||
width: 85px;*/
|
||||
}
|
||||
#header #searchform input#s:focus {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
/* site logo */
|
||||
#site-logo {
|
||||
/* margin: 15px 100px 10px 0; */
|
||||
padding-top:30px;
|
||||
}
|
||||
#site-logo a {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
/* site description */
|
||||
#site-description {
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
MAIN NAV
|
||||
*************************************************************************************/
|
||||
#main-nav {
|
||||
width:100%;
|
||||
height: auto;
|
||||
margin: 10px 0;
|
||||
padding:10px;
|
||||
background-color: #30406B;
|
||||
}
|
||||
#main-nav a {
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
SLIDER
|
||||
*************************************************************************************/
|
||||
#slider .slide-post-title {
|
||||
font-size: 260%;
|
||||
line-height: 100%;
|
||||
margin: 0 0 1%;
|
||||
}
|
||||
#slider .slide-content {
|
||||
font-size: 90%;
|
||||
}
|
||||
#slider .caption {
|
||||
font-size: 80%;
|
||||
line-height: 120%;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
HOME HIGHLIGHTS
|
||||
*************************************************************************************/
|
||||
.home-highlights .home-highlights-content {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
LAYOUTS
|
||||
*************************************************************************************/
|
||||
/* list post */
|
||||
.list-post .post,
|
||||
.list-post .type-page,
|
||||
.list-post .attachment {
|
||||
width: 78% !important;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
FOOTER
|
||||
*************************************************************************************/
|
||||
.footer-nav {
|
||||
padding-right: 200px;
|
||||
}
|
||||
.footer-nav li {
|
||||
margin: 0 8px 5px 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
|
||||
/************************************************************************************
|
||||
LAYOUTS
|
||||
*************************************************************************************/
|
||||
/* list post */
|
||||
.list-post .post,
|
||||
.list-post .type-page,
|
||||
.list-post .attachment {
|
||||
padding-left: 0 !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
.list-post .post-meta {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
/* position: static; */
|
||||
display: block;
|
||||
height: 60px;
|
||||
}
|
||||
.list-post .post-meta span {
|
||||
display: block;
|
||||
margin: 0 5px 0 0;
|
||||
border: none;
|
||||
clear:both;
|
||||
}
|
||||
.list-post .post-icon {
|
||||
/* width: 27px;
|
||||
height: 30px;
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 2px 14px 5px 0;
|
||||
border: none;
|
||||
position: static; */
|
||||
}
|
||||
|
||||
.list-post .post-title {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.list-post .post-meta .post-date {
|
||||
margin-bottom:0px;
|
||||
}
|
||||
|
||||
|
||||
/* grid4 */
|
||||
.grid4 .post, .sidebar1 .grid4 .post {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
float: none;
|
||||
}
|
||||
|
||||
/* grid3 */
|
||||
.grid3 .post, .sidebar1 .grid3 .post {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
float: none;
|
||||
}
|
||||
|
||||
/* action text */
|
||||
.action-text {
|
||||
padding: 3% 4%;
|
||||
}
|
||||
.action-text .button {
|
||||
position: static;
|
||||
clear: both;
|
||||
width: auto;
|
||||
margin: 2% 0 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
|
||||
/* disable webkit text size adjust (for iPhone) */
|
||||
html {
|
||||
-webkit-text-size-adjust: none;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
GRID
|
||||
*************************************************************************************/
|
||||
.col4-1,
|
||||
.col4-2, .col2-1,
|
||||
.col4-3,
|
||||
.col3-1,
|
||||
.col3-2 {
|
||||
margin-left: 0;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
HEADER
|
||||
*************************************************************************************/
|
||||
#header hgroup {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* site logo */
|
||||
#site-logo {
|
||||
font-size: 42px;
|
||||
text-align: left;
|
||||
padding: 0 90px 0 0;
|
||||
width: auto;
|
||||
/* margin: 10px 0; */
|
||||
padding-top: 30px;
|
||||
}
|
||||
|
||||
/* site description */
|
||||
#site-description {
|
||||
text-align: left;
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
/* searchform */
|
||||
#header #searchform {
|
||||
top: 0;
|
||||
left: inherit;
|
||||
right: 0;
|
||||
width: 150px;
|
||||
}
|
||||
#header #searchform #s {
|
||||
display:none;
|
||||
/* float: right;
|
||||
width: 85px; */
|
||||
}
|
||||
|
||||
/* social widget */
|
||||
.social-widget {
|
||||
position: static !important;
|
||||
margin: 10px 0;
|
||||
float: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
LAYOUTS
|
||||
*************************************************************************************/
|
||||
/* grid4 */
|
||||
.grid4 .post {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
/* grid2 */
|
||||
.grid2 .post, .sidebar1 .grid2 .post {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
float: none;
|
||||
}
|
||||
|
||||
/* post title */
|
||||
.post-title {
|
||||
margin: 0 0 2px !important;
|
||||
padding-top: 4px;
|
||||
font-size: 2em !important;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
POST NAV
|
||||
*************************************************************************************/
|
||||
.post-nav .prev, .post-nav .next {
|
||||
display: block;
|
||||
width: 100%;
|
||||
clear: both;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
COMMENTS
|
||||
*************************************************************************************/
|
||||
.commentlist {
|
||||
padding-left: 0;
|
||||
}
|
||||
.commentlist .commententry {
|
||||
clear: left;
|
||||
}
|
||||
.commentlist .avatar {
|
||||
float: left;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 10px 10px 0;
|
||||
}
|
||||
|
||||
/* commentlist sub-levels */
|
||||
.commentlist ul, .commentlist ol {
|
||||
margin: 0 0 0 7%;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
FOOTER
|
||||
*************************************************************************************/
|
||||
#footer-logo {
|
||||
position: static !important;
|
||||
}
|
||||
.footer-nav {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
}
|
6
bigbluebutton-client/resources/prod/help/CSS/prettyPhoto.css
Executable file
6
bigbluebutton-client/resources/prod/help/CSS/prettyPhoto.css
Executable file
File diff suppressed because one or more lines are too long
1039
bigbluebutton-client/resources/prod/help/CSS/shortcodes.css
Executable file
1039
bigbluebutton-client/resources/prod/help/CSS/shortcodes.css
Executable file
File diff suppressed because it is too large
Load Diff
739
bigbluebutton-client/resources/prod/help/CSS/style.css
Executable file
739
bigbluebutton-client/resources/prod/help/CSS/style.css
Executable file
@ -0,0 +1,739 @@
|
||||
/*
|
||||
Theme Name: Suco Child
|
||||
Description: Child theme for Suco theme
|
||||
Template: suco
|
||||
*/
|
||||
|
||||
@import url("../suco/style.css");
|
||||
|
||||
/* write custom css below */
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
CUSTOM TYPOGRAPHY
|
||||
*************************************************************************************/
|
||||
p { margin: 0.5em 0 1.0em; padding: 0; line-height: 20px; }
|
||||
p.imgtext { margin: 0 0 0 0; padding: 0 0 35px 0; font-family: Georgia; font-style: italic; color: #666; font-size: 14px; text-align: center; }
|
||||
p.subhead { margin-top:-15px; padding-bottom:10px; font-family: Georgia; font-style: italic; color: #666; font-size: 22px; text-align: center;}
|
||||
p.subfeat { margin-top:-10px; padding-bottom:15px; font-family: Georgia; font-style: italic; color: #666; font-size: 18px; }
|
||||
.list-post .post-title { margin: 0 0 10px 0; font-size: 28px !important; text-align: left !important; }
|
||||
#slider p { /* color:#6d8c9e;*/ color: #777;}
|
||||
.action-text h2, .action-text h3, .action-text h4 { font-size: 26px; line-height: 110%; margin: 0 0 2px; color: #333333; }
|
||||
#overview h1 { text-align: center; font-size: 48px; padding: 20px 0 0 0; }
|
||||
h4 { color: #333; }
|
||||
h5 { color: ##00445E !important;}
|
||||
/************************************************************************************
|
||||
CUSTOM BUTTONS
|
||||
*************************************************************************************/
|
||||
/* Orange Action Button */
|
||||
.action-text .button {
|
||||
background: #e08e19;
|
||||
background-image: -webkit-gradient(linear, center top, center bottom, from(#f2ab2b), to(#e17b19));
|
||||
background-image: -webkit-linear-gradient(top, #f2ab2b, #e17b19);
|
||||
background-image: -moz-linear-gradient(top, #f2ab2b, #e17b19);
|
||||
background-image: -o-linear-gradient(top, #f2ab2b, #e17b19);
|
||||
background-image: -ms-linear-gradient(top, #f2ab2b, #e17b19);
|
||||
background-image: linear-gradient(top, #f2ab2b, #e17b19);
|
||||
padding: 10px 20px;
|
||||
font: 26px/100% Rokkitt, Arial, Helvetica, sans-serif;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 20px;
|
||||
border: solid 1px #cb8521;
|
||||
-webkit-border-radius: 10px;
|
||||
-moz-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.5);
|
||||
-moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.5);
|
||||
box-shadow: inset 0 1px 0 rgba(255,255,255,.5);
|
||||
}
|
||||
.action-text .button:hover { background:#e08e19; text-decoration: none; }
|
||||
|
||||
|
||||
/*Buttons*/
|
||||
a.button.green {
|
||||
border-color: #4e7521;
|
||||
|
||||
background: #76ab3b;
|
||||
background: -moz-linear-gradient(top, #90c356 0%, #649a27 100%);
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#90c356), color-stop(100%,#649a27));
|
||||
background: -webkit-linear-gradient(top, #90c356 0%,#649a27 100%);
|
||||
background: -o-linear-gradient(top, #90c356 0%,#649a27 100%);
|
||||
background: -ms-linear-gradient(top, #90c356 0%,#649a27 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#90c356', endColorstr='#649a27',GradientType=0 );
|
||||
background: linear-gradient(top, #90c356 0%,#649a27 100%);
|
||||
|
||||
|
||||
color: #fff !important;
|
||||
text-shadow: 0 -1px 0 rgba(0,0,0,.4);
|
||||
}
|
||||
a.button.green:hover {
|
||||
background: #90c356;
|
||||
}
|
||||
a.button.green.flat {
|
||||
background: #76ab3b;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
HEADER
|
||||
*************************************************************************************/
|
||||
#header #searchform #s {
|
||||
width: 120px;
|
||||
color: #666;
|
||||
background: #f2f2f2;
|
||||
padding-left: 10px !important;
|
||||
float: right;
|
||||
-webkit-box-shadow: inset 0 2px 2px rgba(0,0,0,.7), 0 1px 0 rgba(255,255,255,.1);
|
||||
-moz-box-shadow: inset 0 2px 2px rgba(0,0,0,.7), 0 1px 0 rgba(255,255,255,.1);
|
||||
box-shadow: inset 0 2px 2px rgba(0,0,0,.7), 0 1px 0 rgba(255,255,255,.1);
|
||||
-webkit-border-radius: 12px;
|
||||
-moz-border-radius: 12px;
|
||||
border-radius: 12px;
|
||||
-webkit-transition: width .7s;
|
||||
-moz-transition: width .7s;
|
||||
transition: width .7s;
|
||||
}
|
||||
|
||||
#header a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #30406b;
|
||||
}
|
||||
|
||||
.social-widget {
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
#header #searchform { display:none;}
|
||||
|
||||
/************************************************************************************
|
||||
MAIN NAVIGATION
|
||||
*************************************************************************************/
|
||||
#main-nav {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 12px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#main-nav li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
float: left;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
MAIN LEVEL NAVIGATION
|
||||
*************************************************************************************/
|
||||
#main-nav a {
|
||||
color: #fff;
|
||||
display: block;
|
||||
padding: 5px 15px;
|
||||
margin: 0 5px 0 0;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* main level link :hover */
|
||||
#main-nav a:hover, #main-nav li:hover > a {
|
||||
background: #1a243f;
|
||||
color: #fff;
|
||||
-webkit-box-shadow: inset 0 2px 2px rgba(0,0,0,.7), 0 1px 0 rgba(255,255,255,.1);
|
||||
-moz-box-shadow: inset 0 2px 2px rgba(0,0,0,.7), 0 1px 0 rgba(255,255,255,.1);
|
||||
box-shadow: inset 0 2px 2px rgba(0,0,0,.7), 0 1px 0 rgba(255,255,255,.1);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* current link */
|
||||
#main-nav .current_page_item a, #main-nav .current-menu-item a {
|
||||
background: #161211;
|
||||
color: #c8ad6c;
|
||||
-webkit-box-shadow: inset 0 2px 2px rgba(0,0,0,.7), 0 1px 0 rgba(255,255,255,.1);
|
||||
-moz-box-shadow: inset 0 2px 2px rgba(0,0,0,.7), 0 1px 0 rgba(255,255,255,.1);
|
||||
box-shadow: inset 0 2px 2px rgba(0,0,0,.7), 0 1px 0 rgba(255,255,255,.1);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* current link :hover */
|
||||
#main-nav .current_page_item a:hover, #main-nav .current-menu-item a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* sub-levels link */
|
||||
#main-nav ul a, #main-nav .current_page_item ul a, #main-nav ul .current_page_item a, #main-nav .current-menu-item ul a, #main-nav ul .current-menu-item a, #main-nav li:hover > ul a {
|
||||
color: #666;
|
||||
font-weight: normal;
|
||||
padding: 7px 0 7px 15px;
|
||||
margin: 0;
|
||||
width: 180px;
|
||||
background: none;
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* sub-levels link :hover */
|
||||
#main-nav ul a:hover, #main-nav .current_page_item ul a:hover, #main-nav ul .current_page_item a:hover, #main-nav .current-menu-item ul a:hover, #main-nav ul .current-menu-item a:hover, #main-nav li:hover > ul a:hover {
|
||||
color: #00445E;
|
||||
background-color: #EFF8FB;
|
||||
}
|
||||
/* sub-level ul */
|
||||
#main-nav ul {
|
||||
margin-top: -3px;
|
||||
padding: 5px 0;
|
||||
list-style: none;
|
||||
position: absolute;
|
||||
background: #fff;
|
||||
border: solid 1px #ccc;
|
||||
z-index: 100;
|
||||
display: none;
|
||||
-webkit-border-top-left-radius: 0px;
|
||||
-webkit-border-top-right-radius: 5px;
|
||||
-webkit-border-bottom-right-radius: 5px;
|
||||
-webkit-border-bottom-left-radius: 5px;
|
||||
-moz-border-radius-topleft: 0px;
|
||||
-moz-border-radius-topright: 5px;
|
||||
-moz-border-radius-bottomright: 5px;
|
||||
-moz-border-radius-bottomleft: 5px;
|
||||
border-top-left-radius: 0px;
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
#main-nav ul li {
|
||||
background: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: block;
|
||||
}
|
||||
/* sub-sub-level dropdown */
|
||||
#main-nav ul ul {
|
||||
left: 190px;
|
||||
top: -2px;
|
||||
}
|
||||
/* show dropdown ul on hover */
|
||||
#main-nav li:hover > ul {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
PAGE NAVIGATION (BLOG)
|
||||
*************************************************************************************/
|
||||
.pagenav a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
background: #273d6c;
|
||||
padding: 2px 6px;
|
||||
border: solid 1px #1a2744;
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2);
|
||||
-moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.2);
|
||||
box-shadow: inset 0 1px 0 rgba(255,255,255,.2);
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
border-image: initial;
|
||||
}
|
||||
|
||||
.pagenav a:hover {
|
||||
background:#142240;
|
||||
}
|
||||
|
||||
a.button.blue-opaque {
|
||||
border: 1px solid #7996ac;
|
||||
background: #b1c8da;
|
||||
color: #fff !important;
|
||||
text-shadow: 0 1px #71AEC2;
|
||||
}
|
||||
a.button.blue-opaque:hover {
|
||||
background: #9ab3c7;
|
||||
}
|
||||
a.button.blue-opaque.flat {
|
||||
background: #76ab3b;
|
||||
}
|
||||
|
||||
|
||||
input[type="reset"], input[type="submit"] {
|
||||
background: #273D6C !important;
|
||||
border: 1px solid #1A2744;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
BANNER
|
||||
*************************************************************************************/
|
||||
#headerwrap {
|
||||
background-color: #EFF8FB;
|
||||
}
|
||||
|
||||
.welcome-message {
|
||||
font: 280%/110% Rokkitt, Arial, Helvetica, sans-serif;
|
||||
color: #573a1e;
|
||||
text-align: center;
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
|
||||
/* Slider */
|
||||
#slider .slides li {
|
||||
background: none !important;
|
||||
position: relative;
|
||||
color:#6D8C9E;;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 978px;
|
||||
list-style-type:square;
|
||||
float: left;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
FEATURE HIGHLIGHTS
|
||||
*************************************************************************************/
|
||||
.home-highlightswrap {
|
||||
position: relative;
|
||||
background: #3D2C29 url(images/dash-bg.png) repeat-x 0 bottom;
|
||||
border-top: 0 !important;
|
||||
-webkit-box-shadow: inset 0 2px 3px rgba(0,0,0,.3);
|
||||
-moz-box-shadow: inset 0 2px 3px rgba(0,0,0,.3);
|
||||
box-shadow: inset 0 2px 3px rgba(0,0,0,.3);
|
||||
}
|
||||
|
||||
.home-highlights .home-highlights-content {
|
||||
color:#777 !important;
|
||||
}
|
||||
|
||||
.home-highlights .icon {
|
||||
padding: 0 0 0 5px;
|
||||
float: left;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
FEATURE PAGE
|
||||
*************************************************************************************/
|
||||
#roles { height:520px; }
|
||||
#roles .first{ margin-left:0px; padding: 10px 0px 10px 0px; clear:left;}
|
||||
#roles .col3-1{ padding: 10px 0px 0px 0px; }
|
||||
|
||||
#presentations { height:425px; padding-top:45px; }
|
||||
#listeners { padding-top:45px; height:350px;}
|
||||
#chat { padding-top:45px; height:350px;}
|
||||
#deskshare { padding-top:45px; height:375px;}
|
||||
#small-f {padding-top:45px; height:325px; }
|
||||
|
||||
/************************************************************************************
|
||||
OPEN SOURCE COMPONENTS PAGE
|
||||
*************************************************************************************/
|
||||
#os_cmp img { float:left; padding: 0 15px 0 0; }
|
||||
#os_cmp .first{ margin-left:0px; padding: 10px 20px 10px 0px; clear:left; max-width: 45%;}
|
||||
#os_cmp .col2-1{ padding: 15px 20px 0px 0px; max-width: 45%; }
|
||||
|
||||
/************************************************************************************
|
||||
VIDEO PAGE
|
||||
*************************************************************************************/
|
||||
/* Tutorial Videos */
|
||||
#vid_tut{ height:100%; width:auto; display:block; float:left; }
|
||||
#vid_tut img { border: 5px solid #fff;}
|
||||
#vid_tut .first { margin-left:0px; clear:left; }
|
||||
#vid_tut .col2-1{ max-width: 42%; }
|
||||
|
||||
/* Developer Videos */
|
||||
#vid_dev{ height:100%; width:auto; display:block; float:left; margin:20px 0 0 0; }
|
||||
#vid_dev img { border: 5px solid #fff;}
|
||||
#vid_dev .first { margin-left:0px !important; clear:left; }
|
||||
#vid_dev .col2-1{ max-width: 42%; }
|
||||
|
||||
.play { background:transparent url(/wp-content/uploads/2011/12/play.png) no-repeat; padding: 8px 6px 15px 40px; font-weight:bold; }
|
||||
.youvid{ border:5px white; }
|
||||
|
||||
/************************************************************************************
|
||||
SUPPORT PAGE
|
||||
*************************************************************************************/
|
||||
#c_support .first{ margin-left:0px; padding: 10px 20px 10px 0px; clear:left; max-width: 45%; height:215px;}
|
||||
#c_support .col2-1 { padding: 15px 20px 0px 0px; max-width: 45%; height:215px;}
|
||||
#open_source .first{ margin-left:0px; padding: 10px 20px 10px 0px; clear:left; max-width: 45%;}
|
||||
#open_source .col2-1{ padding: 15px 20px 0px 0px; max-width: 45%; }
|
||||
|
||||
/************************************************************************************
|
||||
COMMERCIAL SUPPORT
|
||||
*************************************************************************************/
|
||||
.heading {
|
||||
padding: 8px 6px 5px 50px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: #30406B;
|
||||
font-size: 1.6em;
|
||||
line-height: 1.4em;
|
||||
font-weight: normal;
|
||||
text-shadow: 0 2px 0 rgba(0, 0, 0, .15);
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
OPEN SOURCE INTEGRATIONS
|
||||
*************************************************************************************/
|
||||
.wordpress { background:transparent url(/wp-content/uploads/2011/12/wordpress_icon.png) no-repeat; }
|
||||
.joomla { background:transparent url(/wp-content/uploads/2011/12/joomla_icon.png) no-repeat; }
|
||||
.drupal { background:transparent url(/wp-content/uploads/2011/12/drupal_icon.png) no-repeat; }
|
||||
.moodle { background:transparent url(/wp-content/uploads/2011/12/moodle_icon.png) no-repeat; }
|
||||
.sakai{ background:transparent url(/wp-content/uploads/2011/12/sakai_icon.png) no-repeat; }
|
||||
.tiki { background:transparent url(/wp-content/uploads/2011/12/tiki_icon.png) no-repeat; }
|
||||
.efront { background:transparent url(/wp-content/uploads/2011/12/efront_icon.png) no-repeat; }
|
||||
.redmine { background:transparent url(/wp-content/uploads/2011/12/redmine_icon.png) no-repeat; }
|
||||
.foswiki { background:transparent url(/wp-content/uploads/2011/12/foswiki_icon.png) no-repeat; }
|
||||
.atutor { background:transparent url(/wp-content/uploads/2012/04/atutor_logo.png) no-repeat; }
|
||||
.fedena { background:transparent url(/wp-content/uploads/2012/09/fedena_logo.png) no-repeat; }
|
||||
|
||||
/************************************************************************************
|
||||
BLOG
|
||||
*************************************************************************************/
|
||||
.post-title a {
|
||||
color: #30406B;
|
||||
text-decoration: none;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.post-image img, .widget .feature-posts-list .post-img, .widget .flickr_badge_image img, .commentlist .avatar, .recent-comments-list .avatar, #body .gallery img, .attachment img {
|
||||
adding: 2px;
|
||||
background: white;
|
||||
border: solid 2px #E3E3E3;
|
||||
border-bottom-color: #DDD;
|
||||
border-image: initial;
|
||||
}
|
||||
|
||||
.list-post .post-image {
|
||||
margin: 15px 0 15px;
|
||||
}
|
||||
|
||||
.sidebar1 .list-post .post, .sidebar1 .list-post .hentry, .sidebar1 .list-post .type-page, .sidebar1 .list-post .attachment {
|
||||
padding-left: 130px;
|
||||
width: 550px;
|
||||
position: relative;
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
|
||||
.h_overview { text-align:center; padding-bottom:20px;}
|
||||
.header-widget h1, .header-widget h2, .header-widget h3, .header-widget h4, .header-widget h5, .header-widget h6 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #00445E;
|
||||
}
|
||||
.blue {color: #00445E !important; }
|
||||
|
||||
|
||||
input[type="text"], input[type="password"], textarea, input[type="search"] {
|
||||
background: #eee;
|
||||
border: 1px solid #cccccc;
|
||||
padding: 6px 10px;
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
-webkit-appearance: none;
|
||||
border-image: initial;
|
||||
}
|
||||
|
||||
.post-nav span span { background: #273D6C !important; border:1px solid #1a2744; }
|
||||
.commentlist .comment-reply-link { background: #273D6C !important; border:1px solid #1a2744; }
|
||||
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
SIDEBAR WIDGET
|
||||
*************************************************************************************/
|
||||
.action-text {
|
||||
background: #f9f9f8;
|
||||
border: solid 1px #ccc;
|
||||
position: relative;
|
||||
margin-top: 40px;
|
||||
padding: 15px 200px 15px 25px;
|
||||
-webkit-border-radius: 10px;
|
||||
-moz-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
-webkit-box-shadow: 0 1px 0 rgba(0,0,0,.1);
|
||||
-moz-box-shadow: 0 1px 0 rgba(0,0,0,.1);
|
||||
box-shadow: 0 1px 0 rgba(0,0,0,.1);
|
||||
clear:both;
|
||||
}
|
||||
|
||||
#text-4{
|
||||
border-bottom: solid 1px #CCC;
|
||||
padding: 40px 0 30px;
|
||||
border: 1px solid #CCC;
|
||||
border: 1px solid white;
|
||||
-moz-box-shadow: 0 0 5px #999;
|
||||
-webkit-box-shadow: 0 0 5px #999;
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
background: -moz-linear-gradient(top, whiteSmoke, #F0F0F0);
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(whiteSmoke), to(#F0F0F0));
|
||||
}
|
||||
|
||||
#text-4{ padding: 20px !important; }
|
||||
|
||||
#themify-feature-posts-3, #themify-recent-comments-3{
|
||||
border-bottom: solid 1px #CCC;
|
||||
padding: 20px !important;
|
||||
border: 1px solid #CCC;
|
||||
border: 1px solid white;
|
||||
-moz-box-shadow: 0 0 5px #999;
|
||||
-webkit-box-shadow: 0 0 5px #999;
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
background: -moz-linear-gradient(top, whiteSmoke, #F0F0F0);
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(whiteSmoke), to(#F0F0F0));
|
||||
}
|
||||
|
||||
#sidebar .widget_text{
|
||||
border-bottom: solid 1px #CCC;
|
||||
padding: 20px !important;
|
||||
border: 1px solid #CCC;
|
||||
border: 1px solid white;
|
||||
-moz-box-shadow: 0 0 5px #999;
|
||||
-webkit-box-shadow: 0 0 5px #999;
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
background: -moz-linear-gradient(top, whiteSmoke, #F0F0F0);
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(whiteSmoke), to(#F0F0F0));
|
||||
}
|
||||
|
||||
|
||||
#sidebar .widget_ns_mailchimp {
|
||||
border-bottom: solid 1px #CCC;
|
||||
padding: 20px !important;
|
||||
border: 1px solid #CCC;
|
||||
border: 1px solid white;
|
||||
-moz-box-shadow: 0 0 5px #999;
|
||||
-webkit-box-shadow: 0 0 5px #999;
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
background: -moz-linear-gradient(top, whiteSmoke, #F0F0F0);
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(whiteSmoke), to(#F0F0F0));
|
||||
}
|
||||
|
||||
#ns_widget_mailchimp-email-3 {
|
||||
|
||||
background-color:#fff;
|
||||
width:90%;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
WRAPS
|
||||
*************************************************************************************/
|
||||
.sub_wrap{
|
||||
display: block;
|
||||
float:left;
|
||||
padding: 20px;
|
||||
border: 1px solid #CCC;
|
||||
border: 1px solid white;
|
||||
-moz-box-shadow: 0 0 5px #999;
|
||||
-webkit-box-shadow: 0 0 5px #999;
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
background: -moz-linear-gradient(top, whiteSmoke, #F0F0F0);
|
||||
margin: 0 0 40px 35px;
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(whiteSmoke), to(#F0F0F0));
|
||||
}
|
||||
|
||||
#upperwrap {
|
||||
background-image: url(http://r2.bigbluebutton.org/wp-content/themes/suco/uploads/bg/bg1.png);
|
||||
background-color: #fff;
|
||||
background: #fff url(images/fibre-bg.png);
|
||||
border-bottom: none !important;
|
||||
padding: 40px 0 30px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
Turning Off ShareThis On The Slider Section
|
||||
*************************************************************************************/
|
||||
.slide-content .stButton .facebook {
|
||||
display:none;
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
.slide-content .stButton .twitter {
|
||||
display:none;
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
.slide-content .stButton .email {
|
||||
display:none;
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
.slide-content .stButton .sharethis {
|
||||
display:none;
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Turning Off ShareThis On The Highlights Section
|
||||
*************************************************************************************/
|
||||
.home-highlights .home-highlights-content .stButton .facebook {
|
||||
display:none;
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
.home-highlights .home-highlights-content .stButton .twitter {
|
||||
display:none;
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
.home-highlights .home-highlights-content .stButton .email {
|
||||
display:none;
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
.home-highlights .home-highlights-content .stButton .sharethis {
|
||||
display:none;
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
CUSTOM TABLE
|
||||
*************************************************************************************/
|
||||
table.table2{
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
line-height: 22px;
|
||||
border-collapse:collapse;
|
||||
border-right:1px dotted #e0e0e0;
|
||||
border-left:1px dotted #e0e0e0;
|
||||
border-bottom:1px dotted #e0e0e0;
|
||||
}
|
||||
|
||||
.table2 thead th {
|
||||
padding:20px 10px 20px 10px;
|
||||
color:#fff;
|
||||
font-size: 20px;
|
||||
background-color:#252625;
|
||||
font-weight:normal;
|
||||
text-shadow:1px 1px 1px #000;
|
||||
}
|
||||
|
||||
.table2 thead th:empty{
|
||||
background:transparent;
|
||||
-moz-box-shadow:none;
|
||||
-webkit-box-shadow:none;
|
||||
box-shadow:none;
|
||||
}
|
||||
.table2 thead :nth-last-child(1){
|
||||
border-right:none;
|
||||
}
|
||||
|
||||
.table2 thead :first-child,
|
||||
.table2 tbody :nth-last-child(1){
|
||||
border:none;
|
||||
}
|
||||
|
||||
.table2 tbody th{
|
||||
vertical-align:top;
|
||||
color: #00445E;
|
||||
padding:25px;
|
||||
text-shadow:1px 1px 1px #ccc;
|
||||
background-color:#eff8fb;
|
||||
}
|
||||
|
||||
.table2 tbody td{
|
||||
padding:25px;
|
||||
background: -moz-linear-gradient(100% 25% 90deg, #fefefe, #f9f9f9);
|
||||
background: -webkit-gradient(linear, 0% 0%, 0% 25%, from(#f9f9f9), to(#fefefe));
|
||||
border-right:1px dotted #e0e0e0;
|
||||
text-shadow:-1px 1px 1px #fff;
|
||||
color:#777;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
FOOTER
|
||||
*************************************************************************************/
|
||||
#footer-logo { display:none; }
|
||||
#footer { clear: both; position: relative; min-height: 25px; color: #B3AEAC; padding: 15px 0; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------
|
||||
styling for the tables
|
||||
------------------ */
|
||||
|
||||
#hor-minimalist-b
|
||||
{
|
||||
font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
|
||||
font-size: 12px;
|
||||
background: #fff;
|
||||
/* margin: 45px; */
|
||||
width: 480px;
|
||||
border-collapse: collapse;
|
||||
text-align: left;
|
||||
}
|
||||
#hor-minimalist-b th
|
||||
{
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #00445E;
|
||||
padding: 10px 8px;
|
||||
border-bottom: 2px solid #00445E;
|
||||
}
|
||||
#hor-minimalist-b td
|
||||
{
|
||||
border-bottom: 1px solid #ccc;
|
||||
color: #777;
|
||||
padding: 6px 8px;
|
||||
}
|
||||
#hor-minimalist-b tbody tr:hover td
|
||||
{
|
||||
color: #444;
|
||||
}
|
||||
|
||||
|
||||
/* My changes */
|
||||
p.nocomments, #respond h3 { display: none; }
|
||||
|
||||
.clearfix {
|
||||
*zoom: 1;
|
||||
&:before,
|
||||
&:after {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
&:after {
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
.home-highlights div:nth-child(7) {
|
||||
margin-left:0 !important;
|
||||
}
|
||||
|
||||
.home-highlights div:nth-child(8) {
|
||||
margin-left:30px;
|
||||
clear:none !important;
|
||||
}
|
1787
bigbluebutton-client/resources/prod/help/CSS/style1.css
Executable file
1787
bigbluebutton-client/resources/prod/help/CSS/style1.css
Executable file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
584
bigbluebutton-client/resources/prod/help/screenshare-help.html
Executable file
584
bigbluebutton-client/resources/prod/help/screenshare-help.html
Executable file
@ -0,0 +1,584 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
|
||||
<meta name="viewport" content="width=device-width,minimum-scale=1,maximum-scale=1">
|
||||
|
||||
<title> Videos</title>
|
||||
|
||||
<link rel="alternate" type="application/rss+xml" title="BigBluebutton RSS Feed" href="http://bigbluebutton.org/feed/">
|
||||
|
||||
<link rel="stylesheet" href="http://bigbluebutton.org/wp-content/themes/suco/themify/css/shortcodes.css" type="text/css" media="screen">
|
||||
|
||||
<link href="http://bigbluebutton.org/wp-content/themes/suco-child/style.css" rel="stylesheet" type="text/css">
|
||||
|
||||
<!-- google font -->
|
||||
<link href="http://fonts.googleapis.com/css?family=Rokkitt&v1" rel="stylesheet" type="text/css">
|
||||
|
||||
<!-- media queries -->
|
||||
<link rel="stylesheet" href="http://bigbluebutton.org/wp-content/themes/suco/media-queries.css" type="text/css">
|
||||
|
||||
<!-- media-queries.js (fallback) -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="http://css3-mediaqueries-js.googlecode.com/svn/trunk/css3-mediaqueries.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
<!-- html5.js -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
<!-- jquery -->
|
||||
<script src="http://platform.twitter.com/widgets.js" id="twitter-wjs"></script><script src="http://www.google-analytics.com/ga.js" async="" type="text/javascript"></script><script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
|
||||
|
||||
<!-- audio player -->
|
||||
<script type="text/javascript" src="http://bigbluebutton.org/wp-content/themes/suco/js/audio-player.js"></script>
|
||||
<script type="text/javascript">
|
||||
AudioPlayer.setup("http://bigbluebutton.org/wp-content/themes/suco/player.swf", {
|
||||
width: '90%',
|
||||
transparentpagebg: 'yes'
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- comment-reply js -->
|
||||
|
||||
<!-- wp_header -->
|
||||
<script type="text/javascript">
|
||||
window._wpemojiSettings = {"baseUrl":"https:\/\/s.w.org\/images\/core\/emoji\/72x72\/","ext":".png","source":{"concatemoji":"http:\/\/bigbluebutton.org\/wp-includes\/js\/wp-emoji-release.min.js?ver=21e517e0ddb856c019dcb251670c2be4"}};
|
||||
!function(a,b,c){function d(a){var c,d,e,f=b.createElement("canvas"),g=f.getContext&&f.getContext("2d"),h=String.fromCharCode;if(!g||!g.fillText)return!1;switch(g.textBaseline="top",g.font="600 32px Arial",a){case"flag":return g.fillText(h(55356,56806,55356,56826),0,0),f.toDataURL().length>3e3;case"diversity":return g.fillText(h(55356,57221),0,0),c=g.getImageData(16,16,1,1).data,d=c[0]+","+c[1]+","+c[2]+","+c[3],g.fillText(h(55356,57221,55356,57343),0,0),c=g.getImageData(16,16,1,1).data,e=c[0]+","+c[1]+","+c[2]+","+c[3],d!==e;case"simple":return g.fillText(h(55357,56835),0,0),0!==g.getImageData(16,16,1,1).data[0];case"unicode8":return g.fillText(h(55356,57135),0,0),0!==g.getImageData(16,16,1,1).data[0]}return!1}function e(a){var c=b.createElement("script");c.src=a,c.type="text/javascript",b.getElementsByTagName("head")[0].appendChild(c)}var f,g,h,i;for(i=Array("simple","flag","unicode8","diversity"),c.supports={everything:!0,everythingExceptFlag:!0},h=0;h<i.length;h++)c.supports[i[h]]=d(i[h]),c.supports.everything=c.supports.everything&&c.supports[i[h]],"flag"!==i[h]&&(c.supports.everythingExceptFlag=c.supports.everythingExceptFlag&&c.supports[i[h]]);c.supports.everythingExceptFlag=c.supports.everythingExceptFlag&&!c.supports.flag,c.DOMReady=!1,c.readyCallback=function(){c.DOMReady=!0},c.supports.everything||(g=function(){c.readyCallback()},b.addEventListener?(b.addEventListener("DOMContentLoaded",g,!1),a.addEventListener("load",g,!1)):(a.attachEvent("onload",g),b.attachEvent("onreadystatechange",function(){"complete"===b.readyState&&c.readyCallback()})),f=c.source||{},f.concatemoji?e(f.concatemoji):f.wpemoji&&f.twemoji&&(e(f.twemoji),e(f.wpemoji)))}(window,document,window._wpemojiSettings);
|
||||
</script>
|
||||
<style type="text/css">
|
||||
img.wp-smiley,
|
||||
img.emoji {
|
||||
display: inline !important;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
height: 1em !important;
|
||||
width: 1em !important;
|
||||
margin: 0 .07em !important;
|
||||
vertical-align: -0.1em !important;
|
||||
background: none !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" id="fbComments_hideWpComments-css" href="http://bigbluebutton.org/wp-content/plugins/facebook-comments-for-wordpress/css/facebook-comments-hidewpcomments.css?ver=3.1.3" type="text/css" media="all">
|
||||
<link rel="stylesheet" id="fbc_rc_widgets-style-css" href="http://bigbluebutton.org/wp-content/plugins/facebook-comments-for-wordpress/css/facebook-comments-widgets.css?ver=21e517e0ddb856c019dcb251670c2be4" type="text/css" media="all">
|
||||
<link rel="stylesheet" id="digg-digg-css" href="http://bigbluebutton.org/wp-content/plugins/digg-digg/css/diggdigg-style.css?ver=5.3.6" type="text/css" media="screen">
|
||||
<script type="text/javascript" src="http://bigbluebutton.org/wp-includes/js/jquery/jquery.js?ver=1.12.4"></script>
|
||||
<script type="text/javascript" src="http://bigbluebutton.org/wp-includes/js/jquery/jquery-migrate.min.js?ver=1.4.1"></script>
|
||||
<script type="text/javascript" src="http://bigbluebutton.org/wp-content/plugins/mailchimp-widget/js/mailchimp-widget-min.js?ver=21e517e0ddb856c019dcb251670c2be4"></script>
|
||||
<link rel="https://api.w.org/" href="http://bigbluebutton.org/wp-json/">
|
||||
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://bigbluebutton.org/xmlrpc.php?rsd">
|
||||
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://bigbluebutton.org/wp-includes/wlwmanifest.xml">
|
||||
|
||||
<link rel="canonical" href="http://bigbluebutton.org/videos/">
|
||||
<link rel="shortlink" href="http://bigbluebutton.org/?p=6">
|
||||
<link rel="alternate" type="application/json+oembed" href="http://bigbluebutton.org/wp-json/oembed/1.0/embed?url=http%3A%2F%2Fbigbluebutton.org%2Fvideos%2F">
|
||||
<link rel="alternate" type="text/xml+oembed" href="http://bigbluebutton.org/wp-json/oembed/1.0/embed?url=http%3A%2F%2Fbigbluebutton.org%2Fvideos%2F&format=xml">
|
||||
<script type="text/javascript">
|
||||
(function(url){
|
||||
if(/(?:Chrome\/26\.0\.1410\.63 Safari\/537\.31|WordfenceTestMonBot)/.test(navigator.userAgent)){ return; }
|
||||
var addEvent = function(evt, handler) {
|
||||
if (window.addEventListener) {
|
||||
document.addEventListener(evt, handler, false);
|
||||
} else if (window.attachEvent) {
|
||||
document.attachEvent('on' + evt, handler);
|
||||
}
|
||||
};
|
||||
var removeEvent = function(evt, handler) {
|
||||
if (window.removeEventListener) {
|
||||
document.removeEventListener(evt, handler, false);
|
||||
} else if (window.detachEvent) {
|
||||
document.detachEvent('on' + evt, handler);
|
||||
}
|
||||
};
|
||||
var evts = 'contextmenu dblclick drag dragend dragenter dragleave dragover dragstart drop keydown keypress keyup mousedown mousemove mouseout mouseover mouseup mousewheel scroll'.split(' ');
|
||||
var logHuman = function() {
|
||||
var wfscr = document.createElement('script');
|
||||
wfscr.type = 'text/javascript';
|
||||
wfscr.async = true;
|
||||
wfscr.src = url + '&r=' + Math.random();
|
||||
(document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(wfscr);
|
||||
for (var i = 0; i < evts.length; i++) {
|
||||
removeEvent(evts[i], logHuman);
|
||||
}
|
||||
};
|
||||
for (var i = 0; i < evts.length; i++) {
|
||||
addEvent(evts[i], logHuman);
|
||||
}
|
||||
})('//bigbluebutton.org/?wordfence_logHuman=1&hid=4A32C1A289EB14E197561B7A60F05460');
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
#headerwrap {
|
||||
background-image: none;
|
||||
background-color: #dbebf6;
|
||||
}
|
||||
|
||||
#nav-bar {
|
||||
background-image: url(http://r2.bigbluebutton.org/wp-content/themes/suco/uploads/bg/bg1.png);
|
||||
background-color: #30406b;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
#upperwrap {
|
||||
background-image: url(http://r2.bigbluebutton.org/wp-content/themes/suco/uploads/bg/bg1.png);
|
||||
background-color: #F4F4F4 ;
|
||||
}
|
||||
|
||||
.home-highlightswrap {
|
||||
background-image: none;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
#body {
|
||||
background-image: none;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.footer-widgetswrap {
|
||||
background-image: none;
|
||||
background-color: #262626;
|
||||
}
|
||||
|
||||
#footerwrap {
|
||||
background-image: none;
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: #00445e;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: #00445e;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: #00445e;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: #30406b;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: #30406b;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
#main-nav a:hover, #main-nav li:hover > a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#main-nav .current_page_item a, #main-nav .current-menu-item a {
|
||||
color: #fff;
|
||||
background-color: #1a243f;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<link href="http://www.bigbluebutton.org/wp-content/themes/suco/uploads/favicon/favicon.png" rel="shortcut icon">
|
||||
|
||||
|
||||
|
||||
<!-- custom css -->
|
||||
|
||||
<style type="text/css">.home-highlights .home-highlights-content {
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
color: #464646;
|
||||
}
|
||||
|
||||
.home-highlights h4 {
|
||||
margin: 0;
|
||||
font-size: 160%;
|
||||
line-height: 120%;
|
||||
color: #30406b;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: 'Open Sans', sans-serif !important;
|
||||
|
||||
}
|
||||
|
||||
h1.overview {
|
||||
font-family: "Open Sans","Lucida Grande","Lucida Sans Unicode",Helvetica,Arial,sans-serif;
|
||||
|
||||
}
|
||||
|
||||
img.aligncenter {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
span.post-comment iframe {
|
||||
width:150px !important;
|
||||
}
|
||||
|
||||
.post-meta .post-comment{
|
||||
background: none!important;
|
||||
padding-left:0px;
|
||||
}</style>
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-9394204-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<script src="//bigbluebutton.org/?wordfence_logHuman=1&hid=4A32C1A289EB14E197561B7A60F05460&r=0.7928567202447322" async="" type="text/javascript"></script><script src="https://platform.twitter.com/js/timeline.d5ee0c695f13b8ee1c5f4f85a8c10e39.js" async="" charset="utf-8" type="text/javascript"></script></head>
|
||||
<body class="page page-id-6 page-template-default">
|
||||
|
||||
<div id="pagewrap">
|
||||
|
||||
<div id="headerwrap">
|
||||
|
||||
<header id="header" class="pagewidth">
|
||||
<hgroup>
|
||||
<div id="site-logo"><a href="http://bigbluebutton.org"><img src="http://bigbluebutton.org/wp-content/themes/suco/themify/img.php?src=/wp-content/uploads/2011/12/logo.png&w=330&h=71" alt="BigBluebutton" height="71" width="330"></a></div>
|
||||
<h2 id="site-description"></h2>
|
||||
</hgroup>
|
||||
|
||||
<nav>
|
||||
<ul id="main-nav" class="main-nav"><li id="menu-item-30" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-30"><a href="http://bigbluebutton.org/">Home</a></li>
|
||||
<li id="menu-item-2665" class="menu-item menu-item-type-post_type menu-item-object-page current-menu-ancestor current-menu-parent current_page_parent current_page_ancestor menu-item-has-children menu-item-2665"><a href="http://bigbluebutton.org/overview/">Overview</a>
|
||||
<ul class="sub-menu">
|
||||
<li id="menu-item-2667" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-2667"><a href="http://bigbluebutton.org/overview/">Overview</a></li>
|
||||
<li id="menu-item-1424" class="menu-item menu-item-type-post_type menu-item-object-page current-menu-item page_item page-item-6 current_page_item menu-item-1424"><a href="http://bigbluebutton.org/videos/">Videos</a></li>
|
||||
<li id="menu-item-3083" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-3083"><a href="http://bigbluebutton.org/accessibility/">Accessibility</a></li>
|
||||
<li id="menu-item-1538" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-1538"><a href="http://bigbluebutton.org/history/">History of BigBlueButton</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li id="menu-item-18" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-18"><a href="http://demo.bigbluebutton.org/">Demo</a></li>
|
||||
<li id="menu-item-494" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children menu-item-494"><a href="http://bigbluebutton.org/support/">Support</a>
|
||||
<ul class="sub-menu">
|
||||
<li id="menu-item-1088" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-1088"><a href="http://bigbluebutton.org/support/">Support</a></li>
|
||||
<li id="menu-item-231" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-231"><a href="http://bigbluebutton.org/components/">Open Source Components</a></li>
|
||||
<li id="menu-item-1614" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-1614"><a href="http://bigbluebutton.org/open-source-integrations/">Open Source Integrations</a></li>
|
||||
<li id="menu-item-713" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-713"><a href="http://bigbluebutton.org/commercial-support/">Commercial Support</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li id="menu-item-337" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-337"><a href="http://bigbluebutton.org/blog/">Blog</a></li>
|
||||
<li id="menu-item-716" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children menu-item-716"><a href="http://bigbluebutton.org/foundation/">License</a>
|
||||
<ul class="sub-menu">
|
||||
<li id="menu-item-731" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-731"><a href="http://bigbluebutton.org/trademark/">Trademark</a></li>
|
||||
<li id="menu-item-3077" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-3077"><a href="http://bigbluebutton.org/open-source-license/">Open Source License</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li id="menu-item-1163" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-1163"><a href="http://docs.bigbluebutton.org/">Docs</a></li>
|
||||
</ul> <!-- /#main-nav -->
|
||||
</nav>
|
||||
|
||||
|
||||
<div class="social-widget">
|
||||
<div id="text-6" class="widget widget_text"><strong class="widgettitle">Follow Us</strong> <div class="textwidget"><ul class="links-list">
|
||||
<li><a href="http://facebook.com/bigbluebutton" title="BigBlueButton Facebook Page" target="_BLANK"><img src="/wp-content/uploads/2011/12/facebook.png" alt="Facebook"></a></li>
|
||||
<li><a href="https://twitter.com/bigbluebutton" title="BigBlueButton Twitter Page" target="_BLANK"><img src="/wp-content/uploads/2011/12/twitter.png" alt="Twitter"></a></li>
|
||||
<li><a href="http://www.youtube.com/bigbluebuttonshare" title="BigBlueButton YouTube Page" target="_BLANK"><img src="/wp-content/uploads/2011/12/youtube_icon.png" alt="YouTube"></a></li>
|
||||
<li><a href="https://plus.google.com/b/108594579970371808676/108594579970371808676/posts" title="BigBlueButton Google Plus Page" target="_BLANK"><img src="/wp-content/uploads/2012/07/googleplus.png" alt="Google Plus"></a></li>
|
||||
<!-- <li><a href="http://flickr.com" title="BigBlueButton Flickr Page"><img src="/wp-content/uploads/2011/12/flickr.png" alt="Flickr"></a></li> -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rss"><a href="http://bigbluebutton.org/feed/">RSS</a></div>
|
||||
</div>
|
||||
<!-- /.social-widget -->
|
||||
|
||||
<div class="header-widget">
|
||||
</div>
|
||||
<!-- /.header-widget -->
|
||||
|
||||
</header>
|
||||
<!-- /#header -->
|
||||
|
||||
<div id="nav-bar">
|
||||
</div>
|
||||
<!-- /#nav-bar -->
|
||||
|
||||
</div>
|
||||
<!-- /.headerwrap -->
|
||||
|
||||
<div id="body" class="clearfix">
|
||||
<div id="upperwrap">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="pagewidth">
|
||||
<h1 class="page-title">Videos</h1>
|
||||
</div>
|
||||
|
||||
<!-- /.page-title -->
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<!-- /#upperwrap -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- layout-container -->
|
||||
<div id="layout" class="pagewidth clearfix sidebar-none">
|
||||
|
||||
<!-- content -->
|
||||
<div id="content">
|
||||
|
||||
<div class="clearfix"></div>
|
||||
<h2><strong> Desktop Sharing Tutorial Videos (1.1)</strong></h2>
|
||||
<p>The following videos give you an overview of using Desktop Sharing in BigBlueButton.</p>
|
||||
<div class="shortcode col3-1 first"><a class="lightbox" title="Desktop Sharing on Windows using Internet Explorer" href="https://www.youtube.com/watch?v=w0qei2-uDpI" rel="prettyPhoto"><img title="Desktop Sharing on Windows using Internet Explorer" src="/wp-content/uploads/2013/06/p-overview-081.png" alt="Desktop Sharing on Windows using Internet Explorer" width="285"></a><p></p>
|
||||
<h5>Desktop Sharing on Windows using Internet Explorer</h5>
|
||||
<p>This video gives you an overview of how to use desktop sharing on Windows OS using Internet Explorer.</p>
|
||||
<p><a class="shortcode button green lightbox" title="Desktop Sharing on Windows using Internet Explorer" href="https://www.youtube.com/watch?v=w0qei2-uDpI" rel="prettyPhoto">Play Video </a>
|
||||
</p></div>
|
||||
<div class="shortcode col3-1"><a class="lightbox" title="Desktop Sharing on Windows using Firefox" href="https://www.youtube.com/watch?v=7ZuunBQbmj8" rel="prettyPhoto"><img title="Desktop Sharing on Windows using Firefox" src="/wp-content/uploads/2013/06/p-overview-081.png" alt="Desktop Sharing on Windows using Firefox" width="285"></a><p></p>
|
||||
<h5>Desktop Sharing on Windows using Firefox</h5>
|
||||
<p>This video gives you an overview of how to use desktop sharing on Windows OS using Firefox.</p>
|
||||
<p><a class="shortcode button green lightbox" title="Desktop Sharing on Windows using Firefox" href="https://www.youtube.com/watch?v=7ZuunBQbmj8" rel="prettyPhoto">Play Video </a>
|
||||
</p></div>
|
||||
<div class="shortcode col3-1"><a class="lightbox" title="Desktop Sharing on Windows using Chrome" href="https://www.youtube.com/watch?v=bx9Tupfro_I" rel="prettyPhoto"><img title="Desktop Sharing on Windows using Chrome" src="/wp-content/uploads/2013/06/p-overview-081.png" alt="Desktop Sharing on Windows using Chrome" width="285"></a><p></p>
|
||||
<h5>Desktop Sharing on Windows using Chrome</h5>
|
||||
<p>This video gives you an overview of how to use desktop sharing on Windows OS using Chrome.</p>
|
||||
<p><a class="shortcode button green lightbox" title="Desktop Sharing on Windows using Chrome" href="https://www.youtube.com/watch?v=bx9Tupfro_I" rel="prettyPhoto">Play Video </a>
|
||||
</p></div>
|
||||
<div class="shortcode col3-1 first"><a class="lightbox" title="Desktop Sharing on Mac OS X using Chrome" href="https://www.youtube.com/watch?v=Xezw2moXZQE" rel="prettyPhoto"><img title="Desktop Sharing on Mac OS X using Chrome" src="/wp-content/uploads/2013/06/p_student-081.png" alt="Desktop Sharing on Mac OS X using Chrome" width="285"></a><p></p>
|
||||
<h5>Desktop Sharing on Mac OS X using Chrome</h5>
|
||||
<p>This video gives you an overview of using desktop sharing on Mac OS X using Chrome.</p>
|
||||
<p><a class="shortcode button green lightbox" title="Desktop Sharing on Mac OS X using Chrome" href="https://www.youtube.com/watch?v=Xezw2moXZQE" rel="prettyPhoto">Play Video </a>
|
||||
</p></div>
|
||||
<div class="shortcode col3-1"><a class="lightbox" title="Desktop Sharing on Mac OS X using Safari" href="https://www.youtube.com/watch?v=SmIMd8abeec" rel="prettyPhoto"><img title="Desktop Sharing on Mac OS X using Safari" src="/wp-content/uploads/2011/12/safari_new.png" alt="Desktop Sharing on Mac OS X using Safari" width="285"></a><p></p>
|
||||
<h5>Desktop Sharing on Mac OS X using Safari</h5>
|
||||
<p>This video gives you an overview of using desktop sharing on Mac OS X using Safari.</p>
|
||||
<p><a class="shortcode button green lightbox" title="Desktop Sharing on Mac OS X using Safari" href="https://www.youtube.com/watch?v=SmIMd8abeec" rel="prettyPhoto">Play Video </a></p>
|
||||
</div>
|
||||
<div class="shortcode col3-1"><a class="lightbox" title="Desktop Sharing on Mac OS X using FireFox" href="https://www.youtube.com/watch?v=FmTJOB4SODc" rel="prettyPhoto"><img title="Desktop Sharing on Mac OS X using FireFox" src="/wp-content/uploads/2011/12/macosx-firefox.png" alt="Desktop Sharing on Mac OS X using FireFox" width="285"></a><p></p>
|
||||
<h5>Desktop Sharing on Mac OS X using FireFox</h5>
|
||||
<p>This video gives you an overview of using desktop sharing on Mac OS X using FireFox.</p>
|
||||
<p><a class="shortcode button green lightbox" title="Desktop Sharing on Mac OS X using FireFox" href="https://www.youtube.com/watch?v=FmTJOB4SODc" rel="prettyPhoto">Play Video </a></p>
|
||||
</div>
|
||||
<p><!--
|
||||
|
||||
<a class="lightbox" title="Viewer Overview" href="http://www.youtube.com/watch?v=4C-rOd8bi6s&width=800&height=600" rel="prettyPhoto"><img title="Viewer Overview" src="/wp-content/uploads/2013/06/dev-08.png" alt="Student Overview" width="285" /></a>
|
||||
|
||||
<h5>Developer Overview</h5>
|
||||
|
||||
|
||||
This video gives you an overview of setting up BigBlueButton.
|
||||
|
||||
<a class="shortcode button green lightbox" title="Viewer Overview" href="http://www.youtube.com/watch?v=4C-rOd8bi6s&width=800&height=600" rel="prettyPhoto">Play Video </a>
|
||||
|
||||
|
||||
|
||||
<div id="vid_tut">
|
||||
|
||||
<h2><strong> Tutorial Videos (0.8)</strong></h2>
|
||||
|
||||
|
||||
The BigBlueButton community wants to make the process of learning and understanding our open source web conferencing software as easy as possible. Therefore, we have created the following “How-To” videos.
|
||||
|
||||
<div class="shortcode col3-1 first"><a class="lightbox" title="BigBlueButton Teacher Overview" href="http://www.youtube.com/watch?v=S4eNl9Afipo?width=800&height=600" rel="prettyPhoto"><img title="Teacher Overview" src="/wp-content/uploads/2013/06/teacher-overview-0.8.png" alt="Teacher Overview" width="285" /></a>
|
||||
|
||||
<h5>Teacher Overview</h5>
|
||||
|
||||
|
||||
This video shows you how to present information to remote students using BigBlueButton.
|
||||
|
||||
<a class="shortcode button green lightbox" title="BigBlueButton Teacher Overview" href="http://www.youtube.com/watch?v=S4eNl9Afipo" rel="prettyPhoto">Play Video </a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="shortcode col3-1"><a class="lightbox" title="BigBlueButton Student Overview" href="http://www.youtube.com/watch?v=U8P9RJDk42M&width=800&height=600" rel="prettyPhoto"><img title="Student Overview" src="/wp-content/uploads/2013/06/student-overview-08.png" alt="Student Overview" width="285" /></a>
|
||||
|
||||
<h5>Student Overview</h5>
|
||||
|
||||
|
||||
Student tutorial video for BigBlueButton. Here you will be given an overview of the open source software and a break down of all the individual modules.
|
||||
|
||||
<a class="shortcode button green lightbox" title="BigBlueButton Student Overview" href="http://www.youtube.com/watch?v=U8P9RJDk42M&width=800&height=600" rel="prettyPhoto">Play Video </a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="shortcode col3-1"><a class="lightbox" title="Viewer Overview" href="http://www.youtube.com/watch?v=4C-rOd8bi6s&width=800&height=600" rel="prettyPhoto"><img title="Viewer Overview" src="/wp-content/uploads/2013/06/dev-08.png" alt="Student Overview" width="285" /></a>
|
||||
|
||||
<h5>Developer Overview</h5>
|
||||
|
||||
|
||||
This video gives you an overview of setting up BigBlueButton.
|
||||
|
||||
<a class="shortcode button green lightbox" title="Viewer Overview" href="http://www.youtube.com/watch?v=4C-rOd8bi6s&width=800&height=600" rel="prettyPhoto">Play Video </a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
--></p>
|
||||
<div class="clearfix"></div>
|
||||
|
||||
|
||||
<!-- comments -->
|
||||
<!-- /comments -->
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<!-- /content -->
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<!-- /layout-container -->
|
||||
|
||||
</div>
|
||||
<!-- /body -->
|
||||
|
||||
<div class="footer-widgetswrap clearfix">
|
||||
<div class="footer-widgets pagewidth clearfix">
|
||||
<div class="col3-1 first">
|
||||
<section id="text-3" class="widget widget_text"><h4 class="widgettitle">Overview</h4> <div class="textwidget"><ul>
|
||||
<li class="menu item">
|
||||
<a href="/home" title="BigBlueButton Home">Home</a>
|
||||
</li>
|
||||
<li class="menu item">
|
||||
<a href="/overview" title="BigBlueButton Overview">Overview</a>
|
||||
</li>
|
||||
<li class="menu item">
|
||||
<a href="/videos" title="BigBlueButton Videos">Videos</a>
|
||||
</li>
|
||||
<li class="menu item" title="BigBlueButton Demo">
|
||||
<a href="http://demo.bigbluebutton.org">Demo</a>
|
||||
</li>
|
||||
<li class="menu item">
|
||||
<a href="/blog">Blog</a>
|
||||
</li>
|
||||
<li class="menu item">
|
||||
<a href="/support" title="BigBlueButton Developer Community">Support</a>
|
||||
</li>
|
||||
<li class="menu item">
|
||||
<a href="http://code.google.com/p/bigbluebutton/" title="Download BigBlueButton">Download</a>
|
||||
</li>
|
||||
|
||||
</ul></div>
|
||||
</section> </div>
|
||||
<div class="col3-1 ">
|
||||
<section id="themify-feature-posts-2" class="widget feature-posts"><h4 class="widgettitle">Recent Posts</h4><ul class="feature-posts-list"><li><a href="http://bigbluebutton.org/2016/05/17/bigbluebutton-1-0-released/" class="feature-posts-title">BigBlueButton 1.0 Released</a> <br><small>May 17, 2016</small> <br><span class="post-excerpt">The BigBlueButton project is pleased to announce the</span></li><li><a href="http://bigbluebutton.org/2016/05/03/bigbluebutton-summit-viii-ottawa-ontario-canada/" class="feature-posts-title">BigBlueButton Summit VIII: Ottawa, Ontario, Canada</a> <br><small>May 03, 2016</small> <br><span class="post-excerpt">The BigBlueButton developer community met in Ottawa,</span></li><li><a href="http://bigbluebutton.org/2016/04/06/agora-learning-integrates-with-bigbluebutton/" class="feature-posts-title">Agora Learning integrates with BigBlueButton</a> <br><small>Apr 06, 2016</small> <br><span class="post-excerpt">Agora Learning, a learning Management System from Tree</span></li><li><a href="http://bigbluebutton.org/2016/01/21/nice-tweet-from-boston-college/" class="feature-posts-title">Nice tweet from Boston College</a> <br><small>Jan 21, 2016</small> <br><span class="post-excerpt">Just saw this tweet from Boston College. Looks like</span></li></ul></section> </div>
|
||||
<div class="col3-1 ">
|
||||
<section id="text-12" class="widget widget_text"> <div class="textwidget"><iframe title="Twitter Timeline" data-widget-id="346300284898783232" style="position: static; visibility: visible; display: inline-block; width: 520px; height: 300px; padding: 0px; border: medium none; max-width: 100%; min-width: 180px; margin-top: 0px; margin-bottom: 0px; min-height: 200px;" class="twitter-timeline twitter-timeline-rendered" allowfullscreen="true" allowtransparency="true" scrolling="no" id="twitter-widget-0" frameborder="0"></iframe>
|
||||
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
|
||||
</div>
|
||||
</section> </div>
|
||||
</div>
|
||||
<!-- /.footer-widgets -->
|
||||
</div>
|
||||
<!-- /.footer-widgetswrap -->
|
||||
|
||||
<div id="footerwrap">
|
||||
<footer id="footer" class="pagewidth clearfix">
|
||||
|
||||
<div id="footer-logo">
|
||||
<a href="http://bigbluebutton.org/">BigBluebutton</a>
|
||||
</div>
|
||||
<!-- /footer-logo -->
|
||||
|
||||
|
||||
<div class="footer-text clearfix">
|
||||
<!-- div class="one"><center> Copyright © 2014 BigBlueButton Inc </center></div -->
|
||||
<div class="one"><center> Copyright © 2016 BigBlueButton Inc. </center></div>
|
||||
<div class="two"> </div>
|
||||
</div>
|
||||
<!-- /.footer-text -->
|
||||
|
||||
</footer>
|
||||
<!-- /#footer -->
|
||||
</div>
|
||||
<!-- /#footerwrap -->
|
||||
|
||||
|
||||
<!-- /#pagewrap -->
|
||||
|
||||
<!-- jquery -->
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
!window.jQuery && document.write('<script type="text/javascript" src="http://bigbluebutton.org/wp-content/themes/suco/js/jquery.js"><\/script>')
|
||||
</script>
|
||||
|
||||
<!-- prettyphoto -->
|
||||
<script type="text/javascript" src="http://bigbluebutton.org/wp-content/themes/suco/js/jquery.prettyPhoto.js"></script>
|
||||
<link rel="stylesheet" href="http://bigbluebutton.org/wp-content/themes/suco/prettyPhoto.css" type="text/css" media="screen">
|
||||
<script type="text/javascript">
|
||||
if (screen.width>=480) {
|
||||
jQuery(function($) {
|
||||
$("a[rel^='prettyPhoto']").prettyPhoto({ social_tools: false, deeplinking: false });
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- theme function script -->
|
||||
<script type="text/javascript" src="http://bigbluebutton.org/wp-content/themes/suco/js/script.js"></script>
|
||||
|
||||
<!-- wp_footer -->
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
!window.jQuery && document.write('<script type="text/javascript" src="http://bigbluebutton.org/wp-content/themes/suco/themify/js/jquery.js"><\/script>')
|
||||
</script>
|
||||
<!-- slider -->
|
||||
<script type="text/javascript" src="http://bigbluebutton.org/wp-content/themes/suco/js/slider.js"></script>
|
||||
<script>
|
||||
jQuery(document).ready(function($) {
|
||||
$('#slider').flexslider({
|
||||
animation: "slide",
|
||||
slideshow: true,
|
||||
animationLoop: true,
|
||||
directionNav: true,
|
||||
prevText: "«",
|
||||
nextText: "»",
|
||||
slideshowSpeed: 6000,
|
||||
pauseOnHover: true
|
||||
});
|
||||
});
|
||||
|
||||
// expand slider
|
||||
$('#slider .slides').css('height','auto');
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/javascript" src="http://bigbluebutton.org/wp-includes/js/wp-embed.min.js?ver=21e517e0ddb856c019dcb251670c2be4"></script>
|
||||
|
||||
|
||||
|
||||
<iframe style="position: absolute; visibility: hidden; display: none; width: 0px; height: 0px; padding: 0px; border: medium none;" allowfullscreen="true" allowtransparency="true" scrolling="no" id="rufous-sandbox" frameborder="0"></iframe></body>
|
||||
<html/>
|
@ -1,100 +1,97 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.bigbluebutton.modules.screenshare.managers
|
||||
{
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
|
||||
import flash.events.TimerEvent;
|
||||
import flash.utils.Timer;
|
||||
|
||||
import org.as3commons.logging.api.ILogger;
|
||||
import org.as3commons.logging.api.getClassLogger;
|
||||
import org.bigbluebutton.common.IBbbModuleWindow;
|
||||
import org.bigbluebutton.common.LogUtil;
|
||||
import org.bigbluebutton.common.events.CloseWindowEvent;
|
||||
import org.bigbluebutton.common.events.OpenWindowEvent;
|
||||
import org.bigbluebutton.modules.screenshare.services.ScreenshareService;
|
||||
import org.bigbluebutton.modules.screenshare.view.components.ScreensharePublishWindow;
|
||||
|
||||
public class PublishWindowManager {
|
||||
private static const LOGGER:ILogger = getClassLogger(PublishWindowManager);
|
||||
|
||||
private var shareWindow:ScreensharePublishWindow;
|
||||
private var globalDispatcher:Dispatcher;
|
||||
private var service:ScreenshareService;
|
||||
private var buttonShownOnToolbar:Boolean = false;
|
||||
|
||||
// Timer to auto-publish webcam. We need this timer to delay
|
||||
// the auto-publishing until after the Viewers's window has loaded
|
||||
// to receive the publishing events. Otherwise, the user joining next
|
||||
// won't be able to view the webcam.
|
||||
private var autoPublishTimer:Timer;
|
||||
|
||||
|
||||
|
||||
public function PublishWindowManager(service:ScreenshareService) {
|
||||
LOGGER.debug("PublishWindowManager init");
|
||||
globalDispatcher = new Dispatcher();
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
public function stopSharing():void {
|
||||
if (shareWindow != null) shareWindow.stopSharing();
|
||||
}
|
||||
|
||||
public function startSharing(uri:String, room:String, autoStart:Boolean, autoFullScreen:Boolean):void {
|
||||
LOGGER.debug("DS:PublishWindowManager::opening desk share window, autostart=" + autoStart + " autoFullScreen=" + autoFullScreen);
|
||||
shareWindow = new ScreensharePublishWindow();
|
||||
shareWindow.initWindow(service.getConnection(), uri, room, autoStart, autoFullScreen);
|
||||
shareWindow.visible = true;
|
||||
openWindow(shareWindow);
|
||||
if (autoStart || autoFullScreen) {
|
||||
/*
|
||||
* Need to have a timer to trigger auto-publishing of deskshare.
|
||||
*/
|
||||
shareWindow.btnFSPublish.enabled = false;
|
||||
shareWindow.btnRegionPublish.enabled = false;
|
||||
autoPublishTimer = new Timer(2000, 1);
|
||||
autoPublishTimer.addEventListener(TimerEvent.TIMER, autopublishTimerHandler);
|
||||
autoPublishTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
private function autopublishTimerHandler(event:TimerEvent):void {
|
||||
shareWindow.shareScreen(true);
|
||||
}
|
||||
|
||||
public function handleShareWindowCloseEvent():void {
|
||||
closeWindow(shareWindow);
|
||||
}
|
||||
|
||||
private function openWindow(window:IBbbModuleWindow):void {
|
||||
var event:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
|
||||
event.window = window;
|
||||
globalDispatcher.dispatchEvent(event);
|
||||
}
|
||||
|
||||
private function closeWindow(window:IBbbModuleWindow):void {
|
||||
var event:CloseWindowEvent = new CloseWindowEvent(CloseWindowEvent.CLOSE_WINDOW_EVENT);
|
||||
event.window = window;
|
||||
globalDispatcher.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.bigbluebutton.modules.screenshare.managers {
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
|
||||
import flash.events.TimerEvent;
|
||||
import flash.utils.Timer;
|
||||
|
||||
import org.as3commons.logging.api.ILogger;
|
||||
import org.as3commons.logging.api.getClassLogger;
|
||||
import org.bigbluebutton.common.IBbbModuleWindow;
|
||||
import org.bigbluebutton.common.LogUtil;
|
||||
import org.bigbluebutton.common.events.CloseWindowEvent;
|
||||
import org.bigbluebutton.common.events.OpenWindowEvent;
|
||||
import org.bigbluebutton.modules.screenshare.services.ScreenshareService;
|
||||
import org.bigbluebutton.modules.screenshare.view.components.ScreensharePublishWindow;
|
||||
|
||||
public class PublishWindowManager {
|
||||
private static const LOGGER:ILogger = getClassLogger(PublishWindowManager);
|
||||
|
||||
private var shareWindow:ScreensharePublishWindow;
|
||||
private var globalDispatcher:Dispatcher;
|
||||
private var service:ScreenshareService;
|
||||
private var buttonShownOnToolbar:Boolean = false;
|
||||
|
||||
// Timer to auto-publish webcam. We need this timer to delay
|
||||
// the auto-publishing until after the Viewers's window has loaded
|
||||
// to receive the publishing events. Otherwise, the user joining next
|
||||
// won't be able to view the webcam.
|
||||
private var autoPublishTimer:Timer;
|
||||
|
||||
public function PublishWindowManager(service:ScreenshareService) {
|
||||
LOGGER.debug("PublishWindowManager init");
|
||||
globalDispatcher = new Dispatcher();
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
public function stopSharing():void {
|
||||
if (shareWindow != null) shareWindow.stopSharing();
|
||||
}
|
||||
|
||||
public function startSharing(uri:String, room:String, autoStart:Boolean, autoFullScreen:Boolean):void {
|
||||
LOGGER.debug("DS:PublishWindowManager::opening desk share window, autostart=" + autoStart + " autoFullScreen=" + autoFullScreen);
|
||||
shareWindow = new ScreensharePublishWindow();
|
||||
shareWindow.initWindow(service.getConnection(), uri, room, autoStart, autoFullScreen);
|
||||
shareWindow.visible = true;
|
||||
openWindow(shareWindow);
|
||||
if (autoStart || autoFullScreen) {
|
||||
/*
|
||||
* Need to have a timer to trigger auto-publishing of deskshare.
|
||||
*/
|
||||
shareWindow.btnFSPublish.enabled = false;
|
||||
shareWindow.btnRegionPublish.enabled = false;
|
||||
autoPublishTimer = new Timer(2000, 1);
|
||||
autoPublishTimer.addEventListener(TimerEvent.TIMER, autopublishTimerHandler);
|
||||
autoPublishTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
private function autopublishTimerHandler(event:TimerEvent):void {
|
||||
shareWindow.shareScreen(true);
|
||||
}
|
||||
|
||||
public function handleShareWindowCloseEvent():void {
|
||||
closeWindow(shareWindow);
|
||||
}
|
||||
|
||||
private function openWindow(window:IBbbModuleWindow):void {
|
||||
var event:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
|
||||
event.window = window;
|
||||
globalDispatcher.dispatchEvent(event);
|
||||
}
|
||||
|
||||
private function closeWindow(window:IBbbModuleWindow):void {
|
||||
var event:CloseWindowEvent = new CloseWindowEvent(CloseWindowEvent.CLOSE_WINDOW_EVENT);
|
||||
event.window = window;
|
||||
globalDispatcher.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,267 +1,223 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.bigbluebutton.modules.screenshare.managers
|
||||
{
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
import org.as3commons.logging.api.ILogger;
|
||||
import org.as3commons.logging.api.getClassLogger;
|
||||
import org.bigbluebutton.core.UsersUtil;
|
||||
import org.bigbluebutton.main.events.MadePresenterEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.IsSharingScreenEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.ShareStartRequestResponseEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.StartShareRequestFailedEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.StartShareRequestSuccessEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.UseJavaModeCommand;
|
||||
import org.bigbluebutton.modules.screenshare.events.StreamStartedEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.ViewStreamEvent;
|
||||
import org.bigbluebutton.modules.screenshare.model.ScreenshareModel;
|
||||
import org.bigbluebutton.modules.screenshare.model.ScreenshareOptions;
|
||||
import org.bigbluebutton.modules.screenshare.services.ScreenshareService;
|
||||
import org.bigbluebutton.modules.screenshare.utils.BrowserCheck;
|
||||
import org.bigbluebutton.main.api.JSLog;
|
||||
|
||||
public class ScreenshareManager {
|
||||
private static const LOGGER:ILogger = getClassLogger(ScreenshareManager);
|
||||
private static const LOG:String = "SC::ScreenshareManager - ";
|
||||
private var publishWindowManager:PublishWindowManager;
|
||||
private var viewWindowManager:ViewerWindowManager;
|
||||
private var toolbarButtonManager:ToolbarButtonManager;
|
||||
private var module:ScreenshareModule;
|
||||
private var service:ScreenshareService;
|
||||
private var globalDispatcher:Dispatcher;
|
||||
private var sharing:Boolean = false;
|
||||
private var usingJava:Boolean = true;
|
||||
|
||||
public function ScreenshareManager() {
|
||||
JSLog.warn("ScreenshareManager::ScreenshareManager", {});
|
||||
service = new ScreenshareService();
|
||||
globalDispatcher = new Dispatcher();
|
||||
publishWindowManager = new PublishWindowManager(service);
|
||||
viewWindowManager = new ViewerWindowManager(service);
|
||||
toolbarButtonManager = new ToolbarButtonManager();
|
||||
}
|
||||
|
||||
public function handleStartModuleEvent(module:ScreenshareModule):void {
|
||||
JSLog.warn("ScreenshareManager::handleStartModuleEvent", {});
|
||||
LOGGER.debug("Screenshare Module starting");
|
||||
this.module = module;
|
||||
service.handleStartModuleEvent(module);
|
||||
|
||||
if (UsersUtil.amIPresenter()) {
|
||||
initDeskshare();
|
||||
}
|
||||
}
|
||||
|
||||
public function handleStopModuleEvent():void {
|
||||
LOGGER.debug("Screenshare Module stopping");
|
||||
publishWindowManager.stopSharing();
|
||||
viewWindowManager.stopViewing();
|
||||
service.disconnect();
|
||||
}
|
||||
|
||||
public function handleConnectionSuccessEvent():void {
|
||||
LOGGER.debug("handle Connection Success Event");
|
||||
service.checkIfPresenterIsSharingScreen();
|
||||
}
|
||||
|
||||
public function handleStreamStoppedEvent():void {
|
||||
LOGGER.debug("Sending deskshare stopped command");
|
||||
service.stopSharingDesktop(module.getRoom(), module.getRoom());
|
||||
}
|
||||
|
||||
public function handleStreamStartedEvent(event: StreamStartedEvent):void {
|
||||
ScreenshareModel.getInstance().streamId = event.streamId;
|
||||
ScreenshareModel.getInstance().width = event.width;
|
||||
ScreenshareModel.getInstance().height = event.height;
|
||||
ScreenshareModel.getInstance().url = event.url;
|
||||
|
||||
if (UsersUtil.amIPresenter()) {
|
||||
// var dispatcher:Dispatcher = new Dispatcher();
|
||||
// dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.START));
|
||||
} else {
|
||||
handleStreamStartEvent(ScreenshareModel.getInstance().streamId, event.width, event.height);
|
||||
}
|
||||
|
||||
var dispatcher:Dispatcher = new Dispatcher();
|
||||
dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.START));
|
||||
}
|
||||
|
||||
public function handleIsSharingScreenEvent(event: IsSharingScreenEvent):void {
|
||||
ScreenshareModel.getInstance().streamId = event.streamId;
|
||||
ScreenshareModel.getInstance().width = event.width;
|
||||
ScreenshareModel.getInstance().height = event.height;
|
||||
ScreenshareModel.getInstance().url = event.url;
|
||||
|
||||
if (UsersUtil.amIPresenter()) {
|
||||
// var dispatcher:Dispatcher = new Dispatcher();
|
||||
// dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.START));
|
||||
} else {
|
||||
handleStreamStartEvent(ScreenshareModel.getInstance().streamId, event.width, event.height);
|
||||
|
||||
}
|
||||
|
||||
var dispatcher:Dispatcher = new Dispatcher();
|
||||
dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.START));
|
||||
}
|
||||
|
||||
|
||||
public function handleStartedViewingEvent(stream:String):void {
|
||||
LOGGER.debug("handleStartedViewingEvent [" + stream + "]");
|
||||
service.sendStartedViewingNotification(stream);
|
||||
}
|
||||
|
||||
private function initDeskshare():void {
|
||||
JSLog.warn("ScreenshareManager::initDeskshare", {});
|
||||
sharing = false;
|
||||
var option:ScreenshareOptions = new ScreenshareOptions();
|
||||
option.parseOptions();
|
||||
if (option.autoStart) {
|
||||
handleStartSharingEvent(true);
|
||||
}
|
||||
if(option.showButton){
|
||||
toolbarButtonManager.addToolbarButton();
|
||||
}
|
||||
}
|
||||
|
||||
public function handleMadePresenterEvent(e:MadePresenterEvent):void {
|
||||
LOGGER.debug("Got MadePresenterEvent ");
|
||||
initDeskshare();
|
||||
}
|
||||
|
||||
public function handleMadeViewerEvent(e:MadePresenterEvent):void{
|
||||
LOGGER.debug("Got MadeViewerEvent ");
|
||||
toolbarButtonManager.removeToolbarButton();
|
||||
if (sharing) {
|
||||
service.requestStopSharing(ScreenshareModel.getInstance().streamId);
|
||||
publishWindowManager.stopSharing();
|
||||
}
|
||||
sharing = false;
|
||||
}
|
||||
|
||||
public function handleRequestStartSharingEvent():void {
|
||||
JSLog.warn("ScreenshareManager::handleRequestStartSharingEvent", {});
|
||||
toolbarButtonManager.startedSharing();
|
||||
var option:ScreenshareOptions = new ScreenshareOptions();
|
||||
option.parseOptions();
|
||||
|
||||
if (option.useWebRTCIfAvailable && !BrowserCheck.isWebRTCSupported()) {
|
||||
usingJava = true;
|
||||
var autoStart:Boolean = false; // harcode for now
|
||||
publishWindowManager.startSharing(module.getCaptureServerUri(), module.getRoom(), autoStart, option.autoFullScreen);
|
||||
sharing = true;
|
||||
service.requestStartSharing();
|
||||
} else {
|
||||
usingJava = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function handleRequestStopSharingEvent():void {
|
||||
JSLog.warn("ScreenshareManager::handleRequestStopSharingEvent", {});
|
||||
service.requestStopSharing(ScreenshareModel.getInstance().streamId);
|
||||
}
|
||||
|
||||
public function handleShareStartRequestResponseEvent(event:ShareStartRequestResponseEvent):void {
|
||||
JSLog.warn("ScreenshareManager::handleShareStartRequestResponseEvent", {});
|
||||
LOGGER.debug("handleShareStartRequestResponseEvent");
|
||||
var dispatcher:Dispatcher = new Dispatcher();
|
||||
if (event.success) {
|
||||
ScreenshareModel.getInstance().authToken = event.token;
|
||||
ScreenshareModel.getInstance().jnlp = event.jnlp;
|
||||
dispatcher.dispatchEvent(new StartShareRequestSuccessEvent(ScreenshareModel.getInstance().authToken));
|
||||
} else {
|
||||
dispatcher.dispatchEvent(new StartShareRequestFailedEvent());
|
||||
}
|
||||
}
|
||||
|
||||
public function handleStartSharingEvent(autoStart:Boolean):void {
|
||||
JSLog.warn("ScreenshareManager::handleStartSharingEvent", {});
|
||||
LOGGER.debug("handleStartSharingEvent");
|
||||
//toolbarButtonManager.disableToolbarButton();
|
||||
/*toolbarButtonManager.startedSharing();*/
|
||||
var option:ScreenshareOptions = new ScreenshareOptions();
|
||||
option.parseOptions();
|
||||
/**/
|
||||
|
||||
|
||||
/*options.useWebRTCIfAvailable && !BrowserCheck.isWebRTCSupported()*/
|
||||
publishWindowManager.startSharing(module.getCaptureServerUri(), module.getRoom(), autoStart, option.autoFullScreen);
|
||||
sharing = true;
|
||||
|
||||
// falling back to java, or we can't use WebRTC
|
||||
/*if (autoStart || (options.useWebRTCIfAvailable && !BrowserCheck.isWebRTCSupported())) {
|
||||
if (BrowserCheck.isUsingLessThanChrome38OnMac()) {
|
||||
usingJava = false;
|
||||
publishWindowManager.startSharing(module.getCaptureServerUri(), module.getRoom(), autoStart, option.autoFullScreen);
|
||||
} else {
|
||||
var javaIssue:String = JavaCheck.checkJava();
|
||||
|
||||
if (javaIssue != null) {
|
||||
if (BrowserCheck.isChrome42OrHigher()) {
|
||||
usingJava = false;
|
||||
publishWindowManager.startSharing(module.getCaptureServerUri(), module.getRoom(), autoStart, option.autoFullScreen);
|
||||
} else {
|
||||
usingJava = false;
|
||||
publishWindowManager.startSharing(module.getCaptureServerUri(), module.getRoom(), autoStart, option.autoFullScreen);
|
||||
}
|
||||
} else {
|
||||
usingJava = true;
|
||||
toolbarButtonManager.startedSharing();
|
||||
|
||||
publishWindowManager.startSharing(module.getCaptureServerUri(), module.getRoom(), autoStart, option.autoFullScreen);
|
||||
sharing = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// using WebRTC or not a fallback case
|
||||
usingJava = false;
|
||||
}*/
|
||||
}
|
||||
|
||||
public function handleShareWindowCloseEvent():void {
|
||||
//toolbarButtonManager.enableToolbarButton();
|
||||
publishWindowManager.handleShareWindowCloseEvent();
|
||||
sharing = false;
|
||||
toolbarButtonManager.stopedSharing();
|
||||
}
|
||||
|
||||
public function handleViewWindowCloseEvent():void {
|
||||
LOGGER.debug("Received stop viewing command");
|
||||
viewWindowManager.handleViewWindowCloseEvent();
|
||||
}
|
||||
|
||||
private function handleStreamStartEvent(streamId: String, videoWidth:Number, videoHeight:Number):void{
|
||||
trace(LOG + "Received start vieweing command");
|
||||
LOGGER.debug("Received start vieweing command");
|
||||
if (!usingJava) { return; }
|
||||
viewWindowManager.startViewing(streamId, videoWidth, videoHeight);
|
||||
}
|
||||
|
||||
public function handleUseJavaModeCommand():void {
|
||||
JSLog.warn("ScreenshareManager::handleUseJavaModeCommand", {});
|
||||
usingJava = true;
|
||||
handleStartSharingEvent(true);
|
||||
}
|
||||
|
||||
public function handleDeskshareToolbarStopEvent():void {
|
||||
JSLog.warn("ScreenshareManager::handleDeskshareToolbarStopEvent", {});
|
||||
toolbarButtonManager.stopedSharing();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.bigbluebutton.modules.screenshare.managers {
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
import org.as3commons.logging.api.ILogger;
|
||||
import org.as3commons.logging.api.getClassLogger;
|
||||
import org.bigbluebutton.core.UsersUtil;
|
||||
import org.bigbluebutton.main.events.MadePresenterEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.IsSharingScreenEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.ShareStartRequestResponseEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.StartShareRequestFailedEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.StartShareRequestSuccessEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.StreamStartedEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.ViewStreamEvent;
|
||||
import org.bigbluebutton.modules.screenshare.model.ScreenshareModel;
|
||||
import org.bigbluebutton.modules.screenshare.model.ScreenshareOptions;
|
||||
import org.bigbluebutton.modules.screenshare.services.ScreenshareService;
|
||||
import org.bigbluebutton.modules.screenshare.events.UseJavaModeCommand;
|
||||
import org.bigbluebutton.modules.screenshare.utils.BrowserCheck;
|
||||
|
||||
public class ScreenshareManager {
|
||||
private static const LOGGER:ILogger = getClassLogger(ScreenshareManager);
|
||||
|
||||
private var publishWindowManager:PublishWindowManager;
|
||||
private var viewWindowManager:ViewerWindowManager;
|
||||
private var toolbarButtonManager:ToolbarButtonManager;
|
||||
private var module:ScreenshareModule;
|
||||
private var service:ScreenshareService;
|
||||
private var globalDispatcher:Dispatcher;
|
||||
private var sharing:Boolean = false;
|
||||
private var usingJava:Boolean = true;
|
||||
|
||||
public function ScreenshareManager() {
|
||||
service = new ScreenshareService();
|
||||
globalDispatcher = new Dispatcher();
|
||||
publishWindowManager = new PublishWindowManager(service);
|
||||
viewWindowManager = new ViewerWindowManager(service);
|
||||
toolbarButtonManager = new ToolbarButtonManager();
|
||||
}
|
||||
|
||||
public function handleStartModuleEvent(module:ScreenshareModule):void {
|
||||
LOGGER.debug("Screenshare Module starting");
|
||||
this.module = module;
|
||||
service.handleStartModuleEvent(module);
|
||||
|
||||
if (UsersUtil.amIPresenter()) {
|
||||
initDeskshare();
|
||||
}
|
||||
}
|
||||
|
||||
public function handleStopModuleEvent():void {
|
||||
LOGGER.debug("Screenshare Module stopping");
|
||||
publishWindowManager.stopSharing();
|
||||
viewWindowManager.stopViewing();
|
||||
service.disconnect();
|
||||
}
|
||||
|
||||
public function handleConnectionSuccessEvent():void {
|
||||
LOGGER.debug("handle Connection Success Event");
|
||||
service.checkIfPresenterIsSharingScreen();
|
||||
}
|
||||
|
||||
public function handleStreamStoppedEvent():void {
|
||||
LOGGER.debug("Sending deskshare stopped command");
|
||||
service.stopSharingDesktop(module.getRoom(), module.getRoom());
|
||||
}
|
||||
|
||||
public function handleStreamStartedEvent(event:StreamStartedEvent):void {
|
||||
ScreenshareModel.getInstance().streamId = event.streamId;
|
||||
ScreenshareModel.getInstance().width = event.width;
|
||||
ScreenshareModel.getInstance().height = event.height;
|
||||
ScreenshareModel.getInstance().url = event.url;
|
||||
|
||||
if (UsersUtil.amIPresenter()) {
|
||||
// var dispatcher:Dispatcher = new Dispatcher();
|
||||
// dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.START));
|
||||
} else {
|
||||
handleStreamStartEvent(ScreenshareModel.getInstance().streamId, event.width, event.height);
|
||||
}
|
||||
|
||||
var dispatcher:Dispatcher = new Dispatcher();
|
||||
dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.START));
|
||||
}
|
||||
|
||||
public function handleIsSharingScreenEvent(event:IsSharingScreenEvent):void {
|
||||
ScreenshareModel.getInstance().streamId = event.streamId;
|
||||
ScreenshareModel.getInstance().width = event.width;
|
||||
ScreenshareModel.getInstance().height = event.height;
|
||||
ScreenshareModel.getInstance().url = event.url;
|
||||
|
||||
if (UsersUtil.amIPresenter()) {
|
||||
// var dispatcher:Dispatcher = new Dispatcher();
|
||||
// dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.START));
|
||||
} else {
|
||||
handleStreamStartEvent(ScreenshareModel.getInstance().streamId, event.width, event.height);
|
||||
|
||||
}
|
||||
|
||||
var dispatcher:Dispatcher = new Dispatcher();
|
||||
dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.START));
|
||||
}
|
||||
|
||||
public function handleStartedViewingEvent(stream:String):void {
|
||||
LOGGER.debug("handleStartedViewingEvent [" + stream + "]");
|
||||
service.sendStartedViewingNotification(stream);
|
||||
}
|
||||
|
||||
private function initDeskshare():void {
|
||||
sharing = false;
|
||||
var option:ScreenshareOptions = new ScreenshareOptions();
|
||||
option.parseOptions();
|
||||
if (option.autoStart) {
|
||||
handleStartSharingEvent(true);
|
||||
}
|
||||
if (option.showButton) {
|
||||
toolbarButtonManager.addToolbarButton();
|
||||
}
|
||||
}
|
||||
|
||||
public function handleMadePresenterEvent(e:MadePresenterEvent):void {
|
||||
LOGGER.debug("Got MadePresenterEvent ");
|
||||
initDeskshare();
|
||||
}
|
||||
|
||||
public function handleMadeViewerEvent(e:MadePresenterEvent):void {
|
||||
LOGGER.debug("Got MadeViewerEvent ");
|
||||
toolbarButtonManager.removeToolbarButton();
|
||||
if (sharing) {
|
||||
service.requestStopSharing(ScreenshareModel.getInstance().streamId);
|
||||
publishWindowManager.stopSharing();
|
||||
}
|
||||
sharing = false;
|
||||
}
|
||||
|
||||
public function handleRequestStartSharingEvent():void {
|
||||
toolbarButtonManager.startedSharing();
|
||||
var option:ScreenshareOptions = new ScreenshareOptions();
|
||||
option.parseOptions();
|
||||
|
||||
if (option.useWebRTCIfAvailable && !BrowserCheck.isWebRTCSupported()) {
|
||||
usingJava = true;
|
||||
var autoStart:Boolean = false; // harcode for now
|
||||
publishWindowManager.startSharing(module.getCaptureServerUri(), module.getRoom(), autoStart, option.autoFullScreen);
|
||||
sharing = true;
|
||||
service.requestStartSharing();
|
||||
} else {
|
||||
usingJava = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function handleRequestStopSharingEvent():void {
|
||||
service.requestStopSharing(ScreenshareModel.getInstance().streamId);
|
||||
}
|
||||
|
||||
public function handleShareStartRequestResponseEvent(event:ShareStartRequestResponseEvent):void {
|
||||
LOGGER.debug("handleShareStartRequestResponseEvent");
|
||||
var dispatcher:Dispatcher = new Dispatcher();
|
||||
if (event.success) {
|
||||
ScreenshareModel.getInstance().authToken = event.token;
|
||||
ScreenshareModel.getInstance().jnlp = event.jnlp;
|
||||
dispatcher.dispatchEvent(new StartShareRequestSuccessEvent(ScreenshareModel.getInstance().authToken));
|
||||
} else {
|
||||
dispatcher.dispatchEvent(new StartShareRequestFailedEvent());
|
||||
}
|
||||
}
|
||||
|
||||
public function handleStartSharingEvent(autoStart:Boolean):void {
|
||||
LOGGER.debug("handleStartSharingEvent");
|
||||
//toolbarButtonManager.disableToolbarButton();
|
||||
toolbarButtonManager.startedSharing();
|
||||
var option:ScreenshareOptions = new ScreenshareOptions();
|
||||
option.parseOptions();
|
||||
publishWindowManager.startSharing(module.getCaptureServerUri(), module.getRoom(), autoStart, option.autoFullScreen);
|
||||
sharing = true;
|
||||
}
|
||||
|
||||
public function handleShareWindowCloseEvent():void {
|
||||
//toolbarButtonManager.enableToolbarButton();
|
||||
publishWindowManager.handleShareWindowCloseEvent();
|
||||
sharing = false;
|
||||
toolbarButtonManager.stopedSharing();
|
||||
}
|
||||
|
||||
public function handleViewWindowCloseEvent():void {
|
||||
LOGGER.debug("Received stop viewing command");
|
||||
viewWindowManager.handleViewWindowCloseEvent();
|
||||
}
|
||||
|
||||
private function handleStreamStartEvent(streamId:String, videoWidth:Number, videoHeight:Number):void {
|
||||
LOGGER.debug("Received start vieweing command");
|
||||
if (!usingJava) { return; }
|
||||
viewWindowManager.startViewing(streamId, videoWidth, videoHeight);
|
||||
}
|
||||
|
||||
public function handleUseJavaModeCommand():void {
|
||||
JSLog.warn("ScreenshareManager::handleUseJavaModeCommand", {});
|
||||
usingJava = true;
|
||||
handleStartSharingEvent(true);
|
||||
}
|
||||
|
||||
public function handleDeskshareToolbarStopEvent():void {
|
||||
JSLog.warn("ScreenshareManager::handleDeskshareToolbarStopEvent", {});
|
||||
toolbarButtonManager.stopedSharing();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,82 +1,81 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.bigbluebutton.modules.screenshare.managers
|
||||
{
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
|
||||
import org.as3commons.logging.api.ILogger;
|
||||
import org.as3commons.logging.api.getClassLogger;
|
||||
import org.bigbluebutton.common.IBbbModuleWindow;
|
||||
import org.bigbluebutton.common.LogUtil;
|
||||
import org.bigbluebutton.common.events.CloseWindowEvent;
|
||||
import org.bigbluebutton.common.events.OpenWindowEvent;
|
||||
import org.bigbluebutton.modules.screenshare.services.ScreenshareService;
|
||||
import org.bigbluebutton.modules.screenshare.view.components.ScreenshareViewWindow;
|
||||
|
||||
public class ViewerWindowManager {
|
||||
private static const LOGGER:ILogger = getClassLogger(ViewerWindowManager);
|
||||
|
||||
private var viewWindow:ScreenshareViewWindow;
|
||||
private var service:ScreenshareService;
|
||||
private var isViewing:Boolean = false;
|
||||
private var globalDispatcher:Dispatcher;
|
||||
|
||||
public function ViewerWindowManager(service:ScreenshareService) {
|
||||
this.service = service;
|
||||
globalDispatcher = new Dispatcher();
|
||||
}
|
||||
|
||||
public function stopViewing():void {
|
||||
if (isViewing) viewWindow.stopViewing();
|
||||
}
|
||||
|
||||
public function handleStartedViewingEvent(stream:String):void{
|
||||
LOGGER.debug("ViewerWindowManager handleStartedViewingEvent");
|
||||
service.sendStartedViewingNotification(stream);
|
||||
}
|
||||
|
||||
private function openWindow(window:IBbbModuleWindow):void{
|
||||
var event:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
|
||||
event.window = window;
|
||||
globalDispatcher.dispatchEvent(event);
|
||||
}
|
||||
|
||||
public function handleViewWindowCloseEvent():void {
|
||||
LOGGER.debug("ViewerWindowManager Received stop viewing command");
|
||||
closeWindow(viewWindow);
|
||||
isViewing = false;
|
||||
}
|
||||
|
||||
private function closeWindow(window:IBbbModuleWindow):void {
|
||||
var event:CloseWindowEvent = new CloseWindowEvent(CloseWindowEvent.CLOSE_WINDOW_EVENT);
|
||||
event.window = window;
|
||||
globalDispatcher.dispatchEvent(event);
|
||||
}
|
||||
|
||||
public function startViewing(streamId:String, videoWidth:Number, videoHeight:Number):void{
|
||||
LOGGER.debug("ViewerWindowManager::startViewing");
|
||||
viewWindow = new ScreenshareViewWindow();
|
||||
viewWindow.startVideo(service.getConnection());
|
||||
openWindow(viewWindow);
|
||||
|
||||
isViewing = true;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.bigbluebutton.modules.screenshare.managers {
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
|
||||
import org.as3commons.logging.api.ILogger;
|
||||
import org.as3commons.logging.api.getClassLogger;
|
||||
import org.bigbluebutton.common.IBbbModuleWindow;
|
||||
import org.bigbluebutton.common.LogUtil;
|
||||
import org.bigbluebutton.common.events.CloseWindowEvent;
|
||||
import org.bigbluebutton.common.events.OpenWindowEvent;
|
||||
import org.bigbluebutton.modules.screenshare.services.ScreenshareService;
|
||||
import org.bigbluebutton.modules.screenshare.view.components.ScreenshareViewWindow;
|
||||
|
||||
public class ViewerWindowManager {
|
||||
private static const LOGGER:ILogger = getClassLogger(ViewerWindowManager);
|
||||
|
||||
private var viewWindow:ScreenshareViewWindow;
|
||||
private var service:ScreenshareService;
|
||||
private var isViewing:Boolean = false;
|
||||
private var globalDispatcher:Dispatcher;
|
||||
|
||||
public function ViewerWindowManager(service:ScreenshareService) {
|
||||
this.service = service;
|
||||
globalDispatcher = new Dispatcher();
|
||||
}
|
||||
|
||||
public function stopViewing():void {
|
||||
if (isViewing) viewWindow.stopViewing();
|
||||
}
|
||||
|
||||
public function handleStartedViewingEvent(stream:String):void {
|
||||
LOGGER.debug("ViewerWindowManager handleStartedViewingEvent");
|
||||
service.sendStartedViewingNotification(stream);
|
||||
}
|
||||
|
||||
private function openWindow(window:IBbbModuleWindow):void {
|
||||
var event:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
|
||||
event.window = window;
|
||||
globalDispatcher.dispatchEvent(event);
|
||||
}
|
||||
|
||||
public function handleViewWindowCloseEvent():void {
|
||||
LOGGER.debug("ViewerWindowManager Received stop viewing command");
|
||||
closeWindow(viewWindow);
|
||||
isViewing = false;
|
||||
}
|
||||
|
||||
private function closeWindow(window:IBbbModuleWindow):void {
|
||||
var event:CloseWindowEvent = new CloseWindowEvent(CloseWindowEvent.CLOSE_WINDOW_EVENT);
|
||||
event.window = window;
|
||||
globalDispatcher.dispatchEvent(event);
|
||||
}
|
||||
|
||||
public function startViewing(streamId:String, videoWidth:Number, videoHeight:Number):void {
|
||||
LOGGER.debug("ViewerWindowManager::startViewing");
|
||||
viewWindow = new ScreenshareViewWindow();
|
||||
viewWindow.startVideo(service.getConnection());
|
||||
openWindow(viewWindow);
|
||||
|
||||
isViewing = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,79 +1,78 @@
|
||||
package org.bigbluebutton.modules.screenshare.model
|
||||
{
|
||||
public class ScreenshareModel
|
||||
{
|
||||
|
||||
private static var instance:ScreenshareModel = null;
|
||||
|
||||
private var _isScreenSharing:Boolean = false;
|
||||
private var _stream: ScreenshareStream = new ScreenshareStream();
|
||||
|
||||
|
||||
public function ScreenshareModel(enforcer:SingletonEnforcer) {
|
||||
if (enforcer == null){
|
||||
throw new Error("There can only be 1 ScreenshareModel instance");
|
||||
}
|
||||
}
|
||||
|
||||
public static function getInstance():ScreenshareModel{
|
||||
if (instance == null){
|
||||
instance = new ScreenshareModel(new SingletonEnforcer());
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public function get isSharing():Boolean {
|
||||
return _isScreenSharing;
|
||||
}
|
||||
|
||||
public function get width():int {
|
||||
return _stream.width;
|
||||
}
|
||||
|
||||
public function set width(w: int):void {
|
||||
_stream.width = w;
|
||||
}
|
||||
|
||||
public function get height():int {
|
||||
return _stream.height;
|
||||
}
|
||||
|
||||
public function set height(h: int):void {
|
||||
_stream.height = h;
|
||||
}
|
||||
|
||||
public function get url():String {
|
||||
return _stream.url;
|
||||
}
|
||||
|
||||
public function set url(u: String):void {
|
||||
_stream.url = u;
|
||||
}
|
||||
|
||||
public function get streamId():String {
|
||||
return _stream.streamId;
|
||||
}
|
||||
|
||||
public function set streamId(s: String):void {
|
||||
_stream.streamId = s;
|
||||
}
|
||||
|
||||
public function get authToken():String {
|
||||
return _stream.authToken;
|
||||
}
|
||||
|
||||
public function set authToken(token:String):void {
|
||||
_stream.authToken = token;
|
||||
}
|
||||
|
||||
public function get jnlp():String {
|
||||
return _stream.jnlp;
|
||||
}
|
||||
|
||||
public function set jnlp(j:String):void {
|
||||
_stream.jnlp = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SingletonEnforcer{}
|
||||
package org.bigbluebutton.modules.screenshare.model {
|
||||
|
||||
public class ScreenshareModel {
|
||||
|
||||
private static var instance:ScreenshareModel = null;
|
||||
|
||||
private var _isScreenSharing:Boolean = false;
|
||||
private var _stream:ScreenshareStream = new ScreenshareStream();
|
||||
|
||||
public function ScreenshareModel(enforcer:SingletonEnforcer) {
|
||||
if (enforcer == null) {
|
||||
throw new Error("There can only be 1 ScreenshareModel instance");
|
||||
}
|
||||
}
|
||||
|
||||
public static function getInstance():ScreenshareModel {
|
||||
if (instance == null) {
|
||||
instance = new ScreenshareModel(new SingletonEnforcer());
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public function get isSharing():Boolean {
|
||||
return _isScreenSharing;
|
||||
}
|
||||
|
||||
public function get width():int {
|
||||
return _stream.width;
|
||||
}
|
||||
|
||||
public function set width(w:int):void {
|
||||
_stream.width = w;
|
||||
}
|
||||
|
||||
public function get height():int {
|
||||
return _stream.height;
|
||||
}
|
||||
|
||||
public function set height(h:int):void {
|
||||
_stream.height = h;
|
||||
}
|
||||
|
||||
public function get url():String {
|
||||
return _stream.url;
|
||||
}
|
||||
|
||||
public function set url(u:String):void {
|
||||
_stream.url = u;
|
||||
}
|
||||
|
||||
public function get streamId():String {
|
||||
return _stream.streamId;
|
||||
}
|
||||
|
||||
public function set streamId(s:String):void {
|
||||
_stream.streamId = s;
|
||||
}
|
||||
|
||||
public function get authToken():String {
|
||||
return _stream.authToken;
|
||||
}
|
||||
|
||||
public function set authToken(token:String):void {
|
||||
_stream.authToken = token;
|
||||
}
|
||||
|
||||
public function get jnlp():String {
|
||||
return _stream.jnlp;
|
||||
}
|
||||
|
||||
public function set jnlp(j:String):void {
|
||||
_stream.jnlp = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SingletonEnforcer {
|
||||
}
|
@ -1,107 +1,104 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package org.bigbluebutton.modules.screenshare.services
|
||||
{
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
|
||||
import flash.net.NetConnection;
|
||||
import org.as3commons.logging.api.ILogger;
|
||||
import org.as3commons.logging.api.getClassLogger;
|
||||
import org.bigbluebutton.core.UsersUtil;
|
||||
import org.bigbluebutton.modules.screenshare.services.red5.Connection;
|
||||
|
||||
/**
|
||||
* The DeskShareProxy communicates with the Red5 deskShare server application
|
||||
* @author Snap
|
||||
*
|
||||
*/
|
||||
public class ScreenshareService
|
||||
{
|
||||
private static const LOG:String = "SC::ScreenshareService - ";
|
||||
private static const LOGGER:ILogger = getClassLogger(ScreenshareService);
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package org.bigbluebutton.modules.screenshare.services {
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
|
||||
private var conn:Connection;
|
||||
|
||||
private var module:ScreenshareModule;
|
||||
private var dispatcher:Dispatcher;
|
||||
|
||||
|
||||
private var uri:String;
|
||||
private var room:String;
|
||||
private var sender: MessageSender;
|
||||
private var receiver: MessageReceiver;
|
||||
import flash.net.NetConnection;
|
||||
import org.as3commons.logging.api.ILogger;
|
||||
import org.as3commons.logging.api.getClassLogger;
|
||||
import org.bigbluebutton.core.UsersUtil;
|
||||
import org.bigbluebutton.modules.screenshare.services.red5.Connection;
|
||||
|
||||
public function ScreenshareService() {
|
||||
this.dispatcher = new Dispatcher();
|
||||
}
|
||||
|
||||
public function handleStartModuleEvent(module:ScreenshareModule):void {
|
||||
LOGGER.debug("Screenshare Module starting");
|
||||
this.module = module;
|
||||
connect(module.uri, module.getRoom());
|
||||
}
|
||||
|
||||
public function connect(uri:String, room:String):void {
|
||||
this.uri = uri;
|
||||
this.room = room;
|
||||
LOGGER.debug("Screenshare Service connecting to " + uri);
|
||||
conn = new Connection(room);
|
||||
|
||||
sender = new MessageSender(conn);
|
||||
receiver = new MessageReceiver(conn);
|
||||
|
||||
conn.setURI(uri);
|
||||
conn.connect();
|
||||
}
|
||||
|
||||
public function getConnection():NetConnection{
|
||||
return conn.getConnection();
|
||||
}
|
||||
/**
|
||||
* The DeskShareProxy communicates with the Red5 deskShare server application
|
||||
* @author Snap
|
||||
*
|
||||
*/
|
||||
public class ScreenshareService {
|
||||
private static const LOG:String = "SC::ScreenshareService - ";
|
||||
private static const LOGGER:ILogger = getClassLogger(ScreenshareService);
|
||||
|
||||
private var conn:Connection;
|
||||
|
||||
private var module:ScreenshareModule;
|
||||
private var dispatcher:Dispatcher;
|
||||
|
||||
private var uri:String;
|
||||
private var room:String;
|
||||
private var sender:MessageSender;
|
||||
private var receiver:MessageReceiver;
|
||||
|
||||
public function ScreenshareService() {
|
||||
this.dispatcher = new Dispatcher();
|
||||
}
|
||||
|
||||
public function handleStartModuleEvent(module:ScreenshareModule):void {
|
||||
LOGGER.debug("Screenshare Module starting");
|
||||
this.module = module;
|
||||
connect(module.uri, module.getRoom());
|
||||
}
|
||||
|
||||
public function connect(uri:String, room:String):void {
|
||||
this.uri = uri;
|
||||
this.room = room;
|
||||
LOGGER.debug("Screenshare Service connecting to " + uri);
|
||||
conn = new Connection(room);
|
||||
|
||||
sender = new MessageSender(conn);
|
||||
receiver = new MessageReceiver(conn);
|
||||
|
||||
conn.setURI(uri);
|
||||
conn.connect();
|
||||
}
|
||||
|
||||
public function getConnection():NetConnection {
|
||||
return conn.getConnection();
|
||||
}
|
||||
|
||||
public function disconnect():void {
|
||||
conn.disconnect();
|
||||
}
|
||||
|
||||
public function checkIfPresenterIsSharingScreen():void {
|
||||
LOGGER.debug("check if presenter is sharing screen");
|
||||
sender.isScreenSharing(UsersUtil.getInternalMeetingID());
|
||||
}
|
||||
|
||||
public function requestStartSharing():void {
|
||||
sender.startShareRequest(UsersUtil.getInternalMeetingID(), UsersUtil.getMyUserID(), UsersUtil.isRecorded());
|
||||
}
|
||||
|
||||
public function requestStopSharing(streamId:String):void {
|
||||
sender.stopShareRequest(UsersUtil.getInternalMeetingID(), streamId);
|
||||
}
|
||||
|
||||
public function sendStartViewingNotification(captureWidth:Number, captureHeight:Number):void {
|
||||
conn.sendStartViewingNotification(captureWidth, captureHeight);
|
||||
}
|
||||
|
||||
public function sendStartedViewingNotification(stream:String):void {
|
||||
conn.sendStartedViewingNotification(stream);
|
||||
}
|
||||
|
||||
public function stopSharingDesktop(meetingId:String, stream:String):void {
|
||||
conn.stopSharingDesktop(meetingId, stream);
|
||||
}
|
||||
|
||||
public function disconnect():void{
|
||||
conn.disconnect();
|
||||
}
|
||||
|
||||
public function checkIfPresenterIsSharingScreen():void {
|
||||
LOGGER.debug("check if presenter is sharing screen");
|
||||
sender.isScreenSharing(UsersUtil.getInternalMeetingID());
|
||||
}
|
||||
|
||||
public function requestStartSharing():void {
|
||||
sender.startShareRequest(UsersUtil.getInternalMeetingID(), UsersUtil.getMyUserID(), UsersUtil.isRecorded());
|
||||
}
|
||||
|
||||
public function requestStopSharing(streamId: String):void {
|
||||
sender.stopShareRequest(UsersUtil.getInternalMeetingID(), streamId);
|
||||
}
|
||||
|
||||
public function sendStartViewingNotification(captureWidth:Number, captureHeight:Number):void{
|
||||
conn.sendStartViewingNotification(captureWidth, captureHeight);
|
||||
}
|
||||
|
||||
public function sendStartedViewingNotification(stream:String):void{
|
||||
conn.sendStartedViewingNotification(stream);
|
||||
}
|
||||
|
||||
public function stopSharingDesktop(meetingId: String, stream: String):void {
|
||||
conn.stopSharingDesktop(meetingId, stream);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,419 +1,434 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.bigbluebutton.modules.screenshare.services.red5
|
||||
{
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
import flash.events.NetStatusEvent;
|
||||
import flash.events.SecurityErrorEvent;
|
||||
import flash.events.TimerEvent;
|
||||
import flash.net.NetConnection;
|
||||
import flash.net.ObjectEncoding;
|
||||
import flash.net.Responder;
|
||||
import flash.net.SharedObject;
|
||||
import flash.utils.Timer;
|
||||
import org.as3commons.logging.api.ILogger;
|
||||
import org.as3commons.logging.api.getClassLogger;
|
||||
import org.bigbluebutton.common.LogUtil;
|
||||
import org.bigbluebutton.core.UsersUtil;
|
||||
import org.bigbluebutton.modules.screenshare.events.AppletStartedEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.CursorEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.ViewStreamEvent;
|
||||
|
||||
|
||||
public class Connection {
|
||||
private static const LOGGER:ILogger = getClassLogger(Connection);
|
||||
package org.bigbluebutton.modules.screenshare.services.red5 {
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
import flash.events.NetStatusEvent;
|
||||
import flash.events.SecurityErrorEvent;
|
||||
import flash.events.TimerEvent;
|
||||
import flash.net.NetConnection;
|
||||
import flash.net.ObjectEncoding;
|
||||
import flash.net.Responder;
|
||||
import flash.net.SharedObject;
|
||||
import flash.utils.Timer;
|
||||
import org.as3commons.logging.api.ILogger;
|
||||
import org.as3commons.logging.api.getClassLogger;
|
||||
import org.bigbluebutton.common.LogUtil;
|
||||
import org.bigbluebutton.core.UsersUtil;
|
||||
import org.bigbluebutton.modules.screenshare.events.AppletStartedEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.CursorEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.ViewStreamEvent;
|
||||
import org.bigbluebutton.core.managers.ReconnectionManager;
|
||||
import org.bigbluebutton.main.events.BBBEvent;
|
||||
import org.bigbluebutton.modules.screenshare.model.ScreenshareModel;
|
||||
|
||||
private var netConn:NetConnection;
|
||||
private var uri:String;
|
||||
private const connectionTimeout:int = 5000;
|
||||
private var retryTimer:Timer = null;
|
||||
private var retryCount:int = 0;
|
||||
private const MAX_RETRIES:int = 5;
|
||||
private var deskSO:SharedObject;
|
||||
private var responder:Responder;
|
||||
private var width:Number;
|
||||
private var height:Number;
|
||||
private var meetingId:String;
|
||||
|
||||
private var dispatcher:Dispatcher = new Dispatcher();
|
||||
private var _messageListeners:Array = new Array();
|
||||
|
||||
public function Connection(meetingId:String) {
|
||||
this.meetingId = meetingId;
|
||||
}
|
||||
|
||||
public function connect(retry:Boolean = false):void {
|
||||
netConn = new NetConnection();
|
||||
netConn.proxyType = "best";
|
||||
netConn.objectEncoding = ObjectEncoding.AMF0;
|
||||
netConn.client = this;
|
||||
|
||||
netConn.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
|
||||
netConn.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
|
||||
|
||||
if (getURI().length == 0){
|
||||
LOGGER.debug("please provide a valid URI connection string. URI Connection String missing");
|
||||
return;
|
||||
} else if (netConn.connected){
|
||||
LOGGER.debug("You are already connected to " + getURI());
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER.debug("Trying to connect to [" + getURI() + "] retry=[" + retry + "]");
|
||||
if (! (retryCount > 0)) {
|
||||
var ce:ConnectionEvent = new ConnectionEvent(ConnectionEvent.CONNECTING);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
}
|
||||
|
||||
netConn.connect(getURI());
|
||||
|
||||
if (!retry) {
|
||||
retryTimer = new Timer(connectionTimeout, 1);
|
||||
retryTimer.addEventListener(TimerEvent.TIMER_COMPLETE, connectTimeoutHandler);
|
||||
retryTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
public function addMessageListener(listener:IMessageListener):void {
|
||||
_messageListeners.push(listener);
|
||||
}
|
||||
|
||||
public function removeMessageListener(listener:IMessageListener):void {
|
||||
for (var ob:int=0; ob<_messageListeners.length; ob++) {
|
||||
if (_messageListeners[ob] == listener) {
|
||||
_messageListeners.splice (ob,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function notifyListeners(messageName:String, message:Object):void {
|
||||
if (messageName != null && messageName != "") {
|
||||
for (var notify:String in _messageListeners) {
|
||||
_messageListeners[notify].onMessage(messageName, message);
|
||||
}
|
||||
} else {
|
||||
LOGGER.debug("Message name is undefined");
|
||||
}
|
||||
}
|
||||
|
||||
public function onMessageFromServer(messageName:String, msg:Object):void {
|
||||
LOGGER.debug("Got message from server [" + messageName + "] data=" + msg.msg);
|
||||
notifyListeners(messageName, msg);
|
||||
}
|
||||
|
||||
private function connectTimeoutHandler(e:TimerEvent):void {
|
||||
LOGGER.debug("Connection attempt to [" + getURI() + "] timedout. Retrying.");
|
||||
retryTimer.stop();
|
||||
retryTimer = null;
|
||||
|
||||
netConn.close();
|
||||
netConn = null;
|
||||
|
||||
var ce:ConnectionEvent;
|
||||
|
||||
retryCount++;
|
||||
if (retryCount < MAX_RETRIES) {
|
||||
ce = new ConnectionEvent(ConnectionEvent.CONNECTING_RETRY);
|
||||
ce.retryAttempts = retryCount;
|
||||
dispatcher.dispatchEvent(ce);
|
||||
public class Connection {
|
||||
private static const LOGGER:ILogger = getClassLogger(Connection);
|
||||
|
||||
connect(false);
|
||||
} else {
|
||||
ce = new ConnectionEvent(ConnectionEvent.CONNECTING_MAX_RETRY);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function close():void{
|
||||
netConn.close();
|
||||
}
|
||||
|
||||
public function isScreenSharing(meetingId: String):void {
|
||||
var message:Object = new Object();
|
||||
message["meetingId"] = meetingId;
|
||||
|
||||
sendMessage("screenshare.isScreenSharing",
|
||||
function(result:String):void { // On successful result
|
||||
LOGGER.debug(result);
|
||||
},
|
||||
function(status:String):void { // status - On error occurred
|
||||
LOGGER.error(status);
|
||||
},
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
private function sendMessage(service:String, onSuccess:Function, onFailure:Function, message:Object=null):void {
|
||||
LOGGER.debug("SENDING [" + service + "]");
|
||||
var responder:Responder = new Responder(
|
||||
function(result:Object):void { // On successful result
|
||||
onSuccess("Successfully sent [" + service + "].");
|
||||
},
|
||||
function(status:Object):void { // status - On error occurred
|
||||
var errorReason:String = "Failed to send [" + service + "]:\n";
|
||||
for (var x:Object in status) {
|
||||
errorReason += "\t" + x + " : " + status[x];
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (message == null) {
|
||||
netConn.call(service, responder);
|
||||
} else {
|
||||
netConn.call(service, responder, message);
|
||||
}
|
||||
}
|
||||
|
||||
public function startShareRequest(meetingId: String, userId: String, record: Boolean):void {
|
||||
var message:Object = new Object();
|
||||
message["meetingId"] = meetingId;
|
||||
message["userId"] = userId;
|
||||
message["record"] = record;
|
||||
|
||||
sendMessage("screenshare.startShareRequest",
|
||||
function(result:String):void { // On successful result
|
||||
LOGGER.debug(result);
|
||||
},
|
||||
function(status:String):void { // status - On error occurred
|
||||
LOGGER.error(status);
|
||||
},
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
public function stopShareRequest(meetingId: String, streamId: String):void {
|
||||
var message:Object = new Object();
|
||||
message["meetingId"] = meetingId;
|
||||
message["streamId"] = streamId;
|
||||
|
||||
sendMessage("screenshare.stopShareRequest",
|
||||
function(result:String):void { // On successful result
|
||||
LOGGER.debug(result);
|
||||
},
|
||||
function(status:String):void { // status - On error occurred
|
||||
LOGGER.error(status);
|
||||
},
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function setURI(p_URI:String):void{
|
||||
uri = p_URI;
|
||||
}
|
||||
|
||||
public function getURI():String{
|
||||
return uri + "/" + UsersUtil.getInternalMeetingID();
|
||||
}
|
||||
|
||||
public function onBWCheck(... rest):Number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function onBWDone(... rest):void {
|
||||
var p_bw:Number;
|
||||
if (rest.length > 0) p_bw = rest[0];
|
||||
// your application should do something here
|
||||
// when the bandwidth check is complete
|
||||
LOGGER.debug("bandwidth = " + p_bw + " Kbps.");
|
||||
}
|
||||
|
||||
private function sendUserIdToServer():void {
|
||||
var message:Object = new Object();
|
||||
message["meetingId"] = meetingId;
|
||||
message["userId"] = UsersUtil.getMyUserID();
|
||||
|
||||
sendMessage("screenshare.setUserId",
|
||||
function(result:String):void { // On successful result
|
||||
LOGGER.debug(result);
|
||||
},
|
||||
function(status:String):void { // status - On error occurred
|
||||
LOGGER.error(status);
|
||||
},
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
private function netStatusHandler(event:NetStatusEvent):void {
|
||||
LOGGER.debug("Connected to [" + getURI() + "]. [" + event.info.code + "]");
|
||||
|
||||
if (retryTimer) {
|
||||
retryCount = 0;
|
||||
LOGGER.debug("Cancelling retry timer.");
|
||||
retryTimer.stop();
|
||||
retryTimer = null;
|
||||
}
|
||||
|
||||
|
||||
var ce:ConnectionEvent;
|
||||
switch(event.info.code){
|
||||
case "NetConnection.Connect.Failed":
|
||||
ce = new ConnectionEvent(ConnectionEvent.FAILED);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
break;
|
||||
|
||||
case "NetConnection.Connect.Success":
|
||||
sendUserIdToServer();
|
||||
ce = new ConnectionEvent(ConnectionEvent.SUCCESS);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
break;
|
||||
|
||||
case "NetConnection.Connect.Rejected":
|
||||
ce = new ConnectionEvent(ConnectionEvent.REJECTED);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
break;
|
||||
|
||||
case "NetConnection.Connect.Closed":
|
||||
LOGGER.debug("Screenshare connection closed.");
|
||||
ce = new ConnectionEvent(ConnectionEvent.CLOSED);
|
||||
break;
|
||||
|
||||
case "NetConnection.Connect.InvalidApp":
|
||||
ce = new ConnectionEvent(ConnectionEvent.INVALIDAPP);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
break;
|
||||
|
||||
case "NetConnection.Connect.AppShutdown":
|
||||
ce = new ConnectionEvent(ConnectionEvent.APPSHUTDOWN);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
break;
|
||||
|
||||
case "NetConnection.Connect.NetworkChange":
|
||||
LOGGER.debug("Detected network change. User might be on a wireless and temporarily dropped connection. Doing nothing. Just making a note.");
|
||||
break;
|
||||
|
||||
default :
|
||||
// I dispatch DISCONNECTED incase someone just simply wants to know if we're not connected'
|
||||
// rather than having to subscribe to the events individually
|
||||
ce = new ConnectionEvent(ConnectionEvent.DISCONNECTED);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function securityErrorHandler(event:SecurityErrorEvent):void{
|
||||
var ce:ConnectionEvent = new ConnectionEvent(ConnectionEvent.SECURITYERROR);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
}
|
||||
|
||||
public function mouseLocationCallback(x:Number, y:Number):void {
|
||||
var event:CursorEvent = new CursorEvent(CursorEvent.UPDATE_CURSOR_LOC_EVENT);
|
||||
event.x = x;
|
||||
event.y = y;
|
||||
dispatcher.dispatchEvent(event);
|
||||
}
|
||||
|
||||
public function disconnect():void{
|
||||
if (netConn != null) netConn.close();
|
||||
}
|
||||
private var netConn:NetConnection;
|
||||
private var uri:String;
|
||||
private const connectionTimeout:int = 5000;
|
||||
private var retryTimer:Timer = null;
|
||||
private var retryCount:int = 0;
|
||||
private const MAX_RETRIES:int = 5;
|
||||
private var deskSO:SharedObject;
|
||||
private var responder:Responder;
|
||||
private var width:Number;
|
||||
private var height:Number;
|
||||
private var meetingId:String;
|
||||
|
||||
public function getConnection():NetConnection{
|
||||
return netConn;
|
||||
private var dispatcher:Dispatcher = new Dispatcher();
|
||||
private var _messageListeners:Array = new Array();
|
||||
private var logoutOnUserCommand:Boolean = false;
|
||||
private var reconnecting:Boolean = false;
|
||||
|
||||
public function Connection(meetingId:String) {
|
||||
this.meetingId = meetingId;
|
||||
}
|
||||
|
||||
public function connect(retry:Boolean = false):void {
|
||||
netConn = new NetConnection();
|
||||
netConn.proxyType = "best";
|
||||
netConn.objectEncoding = ObjectEncoding.AMF0;
|
||||
netConn.client = this;
|
||||
|
||||
netConn.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
|
||||
netConn.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
|
||||
|
||||
if (getURI().length == 0) {
|
||||
LOGGER.debug("please provide a valid URI connection string. URI Connection String missing");
|
||||
return;
|
||||
} else if (netConn.connected) {
|
||||
LOGGER.debug("You are already connected to " + getURI());
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER.debug("Trying to connect to [" + getURI() + "] retry=[" + retry + "]");
|
||||
if (!(retryCount > 0)) {
|
||||
var ce:ConnectionEvent = new ConnectionEvent(ConnectionEvent.CONNECTING);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
}
|
||||
|
||||
netConn.connect(getURI());
|
||||
|
||||
if (!retry) {
|
||||
retryTimer = new Timer(connectionTimeout, 1);
|
||||
retryTimer.addEventListener(TimerEvent.TIMER_COMPLETE, connectTimeoutHandler);
|
||||
retryTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
public function addMessageListener(listener:IMessageListener):void {
|
||||
_messageListeners.push(listener);
|
||||
}
|
||||
|
||||
public function removeMessageListener(listener:IMessageListener):void {
|
||||
for (var ob:int = 0; ob < _messageListeners.length; ob++) {
|
||||
if (_messageListeners[ob] == listener) {
|
||||
_messageListeners.splice(ob, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function notifyListeners(messageName:String, message:Object):void {
|
||||
if (messageName != null && messageName != "") {
|
||||
for (var notify:String in _messageListeners) {
|
||||
_messageListeners[notify].onMessage(messageName, message);
|
||||
}
|
||||
} else {
|
||||
LOGGER.debug("Message name is undefined");
|
||||
}
|
||||
}
|
||||
|
||||
public function onMessageFromServer(messageName:String, msg:Object):void {
|
||||
LOGGER.debug("Got message from server [" + messageName + "] data=" + msg.msg);
|
||||
notifyListeners(messageName, msg);
|
||||
}
|
||||
|
||||
private function connectTimeoutHandler(e:TimerEvent):void {
|
||||
LOGGER.debug("Connection attempt to [" + getURI() + "] timedout. Retrying.");
|
||||
retryTimer.stop();
|
||||
retryTimer = null;
|
||||
|
||||
netConn.close();
|
||||
netConn = null;
|
||||
|
||||
var ce:ConnectionEvent;
|
||||
|
||||
retryCount++;
|
||||
if (retryCount < MAX_RETRIES) {
|
||||
ce = new ConnectionEvent(ConnectionEvent.CONNECTING_RETRY);
|
||||
ce.retryAttempts = retryCount;
|
||||
dispatcher.dispatchEvent(ce);
|
||||
|
||||
connect(false);
|
||||
} else {
|
||||
ce = new ConnectionEvent(ConnectionEvent.CONNECTING_MAX_RETRY);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function close():void {
|
||||
netConn.close();
|
||||
}
|
||||
|
||||
public function isScreenSharing(meetingId:String):void {
|
||||
var message:Object = new Object();
|
||||
message["meetingId"] = meetingId;
|
||||
|
||||
sendMessage("screenshare.isScreenSharing", function(result:String):void { // On successful result
|
||||
LOGGER.debug(result);
|
||||
}, function(status:String):void { // status - On error occurred
|
||||
LOGGER.error(status);
|
||||
}, message);
|
||||
}
|
||||
|
||||
private function sendMessage(service:String, onSuccess:Function, onFailure:Function, message:Object = null):void {
|
||||
LOGGER.debug("SENDING [" + service + "]");
|
||||
var responder:Responder = new Responder(function(result:Object):void { // On successful result
|
||||
onSuccess("Successfully sent [" + service + "].");
|
||||
}, function(status:Object):void { // status - On error occurred
|
||||
var errorReason:String = "Failed to send [" + service + "]:\n";
|
||||
for (var x:Object in status) {
|
||||
errorReason += "\t" + x + " : " + status[x];
|
||||
}
|
||||
});
|
||||
|
||||
if (message == null) {
|
||||
netConn.call(service, responder);
|
||||
} else {
|
||||
netConn.call(service, responder, message);
|
||||
}
|
||||
}
|
||||
|
||||
public function startShareRequest(meetingId:String, userId:String, record:Boolean):void {
|
||||
var message:Object = new Object();
|
||||
message["meetingId"] = meetingId;
|
||||
message["userId"] = userId;
|
||||
message["record"] = record;
|
||||
|
||||
sendMessage("screenshare.startShareRequest", function(result:String):void { // On successful result
|
||||
LOGGER.debug(result);
|
||||
}, function(status:String):void { // status - On error occurred
|
||||
LOGGER.error(status);
|
||||
}, message);
|
||||
}
|
||||
|
||||
public function stopShareRequest(meetingId:String, streamId:String):void {
|
||||
var message:Object = new Object();
|
||||
message["meetingId"] = meetingId;
|
||||
message["streamId"] = streamId;
|
||||
|
||||
sendMessage("screenshare.stopShareRequest", function(result:String):void { // On successful result
|
||||
LOGGER.debug(result);
|
||||
}, function(status:String):void { // status - On error occurred
|
||||
LOGGER.error(status);
|
||||
}, message);
|
||||
}
|
||||
|
||||
public function setURI(p_URI:String):void {
|
||||
uri = p_URI;
|
||||
}
|
||||
|
||||
public function getURI():String {
|
||||
return uri + "/" + UsersUtil.getInternalMeetingID();
|
||||
}
|
||||
|
||||
public function onBWCheck(... rest):Number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function onBWDone(... rest):void {
|
||||
var p_bw:Number;
|
||||
if (rest.length > 0) p_bw = rest[0];
|
||||
// your application should do something here
|
||||
// when the bandwidth check is complete
|
||||
LOGGER.debug("bandwidth = " + p_bw + " Kbps.");
|
||||
}
|
||||
|
||||
private function sendUserIdToServer():void {
|
||||
var message:Object = new Object();
|
||||
message["meetingId"] = meetingId;
|
||||
message["userId"] = UsersUtil.getMyUserID();
|
||||
|
||||
sendMessage("screenshare.setUserId", function(result:String):void { // On successful result
|
||||
LOGGER.debug(result);
|
||||
}, function(status:String):void { // status - On error occurred
|
||||
LOGGER.error(status);
|
||||
}, message);
|
||||
}
|
||||
|
||||
private function netStatusHandler(event:NetStatusEvent):void {
|
||||
LOGGER.debug("Connected to [" + getURI() + "]. [" + event.info.code + "]");
|
||||
|
||||
if (retryTimer) {
|
||||
retryCount = 0;
|
||||
LOGGER.debug("Cancelling retry timer.");
|
||||
retryTimer.stop();
|
||||
retryTimer = null;
|
||||
}
|
||||
|
||||
var ce:ConnectionEvent;
|
||||
switch (event.info.code) {
|
||||
case "NetConnection.Connect.Failed":
|
||||
if (reconnecting) {
|
||||
var attemptFailedEvent:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_CONNECTION_ATTEMPT_FAILED_EVENT);
|
||||
attemptFailedEvent.payload.type = ReconnectionManager.DESKSHARE_CONNECTION;
|
||||
dispatcher.dispatchEvent(attemptFailedEvent);
|
||||
}
|
||||
ce = new ConnectionEvent(ConnectionEvent.FAILED);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
break;
|
||||
|
||||
case "NetConnection.Connect.Success":
|
||||
if (reconnecting) {
|
||||
reconnecting = false;
|
||||
if (ScreenshareModel.getInstance().isSharing) {
|
||||
stopShareRequest(UsersUtil.getInternalMeetingID(), ScreenshareModel.getInstance().streamId)
|
||||
}
|
||||
|
||||
var attemptSucceeded:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_CONNECTION_ATTEMPT_SUCCEEDED_EVENT);
|
||||
attemptSucceeded.payload.type = ReconnectionManager.DESKSHARE_CONNECTION;
|
||||
dispatcher.dispatchEvent(attemptSucceeded);
|
||||
}
|
||||
|
||||
sendUserIdToServer();
|
||||
ce = new ConnectionEvent(ConnectionEvent.SUCCESS);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
|
||||
break;
|
||||
|
||||
case "NetConnection.Connect.Rejected":
|
||||
ce = new ConnectionEvent(ConnectionEvent.REJECTED);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
break;
|
||||
|
||||
case "NetConnection.Connect.Closed":
|
||||
LOGGER.debug("Screenshare connection closed.");
|
||||
if (UsersUtil.amIPresenter()) {
|
||||
// Let's keep our presenter status before disconnected. We can't
|
||||
// tell the other user's to stop desktop sharing as our connection is broken. (ralam july 24, 2015)
|
||||
|
||||
} else {
|
||||
stopViewing();
|
||||
}
|
||||
|
||||
if (!logoutOnUserCommand) {
|
||||
reconnecting = true;
|
||||
|
||||
var disconnectedEvent:BBBEvent = new BBBEvent(BBBEvent.RECONNECT_DISCONNECTED_EVENT);
|
||||
disconnectedEvent.payload.type = ReconnectionManager.DESKSHARE_CONNECTION;
|
||||
disconnectedEvent.payload.callback = connect;
|
||||
disconnectedEvent.payload.callbackParameters = [];
|
||||
dispatcher.dispatchEvent(disconnectedEvent);
|
||||
}
|
||||
ce = new ConnectionEvent(ConnectionEvent.CLOSED);
|
||||
break;
|
||||
|
||||
case "NetConnection.Connect.InvalidApp":
|
||||
ce = new ConnectionEvent(ConnectionEvent.INVALIDAPP);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
break;
|
||||
|
||||
case "NetConnection.Connect.AppShutdown":
|
||||
ce = new ConnectionEvent(ConnectionEvent.APPSHUTDOWN);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
break;
|
||||
|
||||
case "NetConnection.Connect.NetworkChange":
|
||||
LOGGER.debug("Detected network change. User might be on a wireless and temporarily dropped connection. Doing nothing. Just making a note.");
|
||||
break;
|
||||
|
||||
default:
|
||||
// I dispatch DISCONNECTED incase someone just simply wants to know if we're not connected'
|
||||
// rather than having to subscribe to the events individually
|
||||
ce = new ConnectionEvent(ConnectionEvent.DISCONNECTED);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function securityErrorHandler(event:SecurityErrorEvent):void {
|
||||
var ce:ConnectionEvent = new ConnectionEvent(ConnectionEvent.SECURITYERROR);
|
||||
dispatcher.dispatchEvent(ce);
|
||||
}
|
||||
|
||||
public function mouseLocationCallback(x:Number, y:Number):void {
|
||||
var event:CursorEvent = new CursorEvent(CursorEvent.UPDATE_CURSOR_LOC_EVENT);
|
||||
event.x = x;
|
||||
event.y = y;
|
||||
dispatcher.dispatchEvent(event);
|
||||
}
|
||||
|
||||
public function disconnect():void {
|
||||
logoutOnUserCommand = true;
|
||||
if (netConn != null) netConn.close();
|
||||
}
|
||||
|
||||
public function getConnection():NetConnection {
|
||||
return netConn;
|
||||
}
|
||||
|
||||
public function connectionFailedHandler(e:ConnectionEvent):void {
|
||||
LOGGER.error("connection failed to " + uri + " with message " + e.toString());
|
||||
}
|
||||
|
||||
public function connectionRejectedHandler(e:ConnectionEvent):void {
|
||||
LOGGER.error("connection rejected " + uri + " with message " + e.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked on the server once the clients' applet has started sharing and the server has started a video stream
|
||||
*
|
||||
*/
|
||||
public function appletStarted(videoWidth:Number, videoHeight:Number):void {
|
||||
LOGGER.debug("Got applet started");
|
||||
var event:AppletStartedEvent = new AppletStartedEvent();
|
||||
event.videoWidth = videoWidth;
|
||||
event.videoHeight = videoHeight;
|
||||
dispatcher.dispatchEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method to send out a room-wide notification to start viewing the stream
|
||||
*
|
||||
*/
|
||||
public function sendStartViewingNotification(captureWidth:Number, captureHeight:Number):void {
|
||||
try {
|
||||
deskSO.send("startViewing", captureWidth, captureHeight);
|
||||
} catch (e:Error) {
|
||||
LOGGER.error("error while trying to send start viewing notification");
|
||||
}
|
||||
}
|
||||
|
||||
public function sendStartedViewingNotification(stream:String):void {
|
||||
LOGGER.debug("Sending start viewing to server");
|
||||
netConn.call("deskshare.startedToViewStream", null, stream);
|
||||
}
|
||||
|
||||
public function stopSharingDesktop(meetingId:String, stream:String):void {
|
||||
netConn.call("deskshare.stopSharingDesktop", null, meetingId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the server when a notification is received to start viewing the broadcast stream .
|
||||
* This method is called on successful execution of sendStartViewingNotification()
|
||||
*
|
||||
*/
|
||||
public function startViewing(videoWidth:Number, videoHeight:Number):void {
|
||||
LOGGER.debug("startViewing invoked by server");
|
||||
|
||||
var event:ViewStreamEvent = new ViewStreamEvent(ViewStreamEvent.START);
|
||||
dispatcher.dispatchEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a notification through the server to all the participants in the room to stop viewing the stream
|
||||
*
|
||||
*/
|
||||
public function sendStopViewingNotification():void {
|
||||
LOGGER.debug("Sending stop viewing notification to other clients.");
|
||||
try {
|
||||
deskSO.send("stopViewing");
|
||||
} catch (e:Error) {
|
||||
LOGGER.debug("could not send stop viewing notification");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the server to notify clients that the deskshare stream has stooped.
|
||||
*/
|
||||
public function deskshareStreamStopped():void {
|
||||
stopViewing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a notification to the module to stop viewing the stream
|
||||
* This method is called on successful execution of sendStopViewingNotification()
|
||||
*
|
||||
*/
|
||||
public function stopViewing():void {
|
||||
LOGGER.debug("Received dekskshareStreamStopped");
|
||||
dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.STOP));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function connectionFailedHandler(e:ConnectionEvent):void{
|
||||
LOGGER.error("connection failed to " + uri + " with message " + e.toString());
|
||||
}
|
||||
|
||||
public function connectionRejectedHandler(e:ConnectionEvent):void{
|
||||
LOGGER.error("connection rejected " + uri + " with message " + e.toString());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invoked on the server once the clients' applet has started sharing and the server has started a video stream
|
||||
*
|
||||
*/
|
||||
public function appletStarted(videoWidth:Number, videoHeight:Number):void{
|
||||
LOGGER.debug("Got applet started");
|
||||
var event:AppletStartedEvent = new AppletStartedEvent();
|
||||
event.videoWidth = videoWidth;
|
||||
event.videoHeight = videoHeight;
|
||||
dispatcher.dispatchEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method to send out a room-wide notification to start viewing the stream
|
||||
*
|
||||
*/
|
||||
public function sendStartViewingNotification(captureWidth:Number, captureHeight:Number):void{
|
||||
try{
|
||||
deskSO.send("startViewing", captureWidth, captureHeight);
|
||||
} catch(e:Error){
|
||||
LOGGER.error("error while trying to send start viewing notification");
|
||||
}
|
||||
}
|
||||
|
||||
public function sendStartedViewingNotification(stream:String):void{
|
||||
LOGGER.debug("Sending start viewing to server");
|
||||
netConn.call("deskshare.startedToViewStream", null, stream);
|
||||
}
|
||||
|
||||
public function stopSharingDesktop(meetingId: String, stream: String):void {
|
||||
netConn.call("deskshare.stopSharingDesktop", null, meetingId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the server when a notification is received to start viewing the broadcast stream .
|
||||
* This method is called on successful execution of sendStartViewingNotification()
|
||||
*
|
||||
*/
|
||||
public function startViewing(videoWidth:Number, videoHeight:Number):void{
|
||||
LOGGER.debug("startViewing invoked by server");
|
||||
|
||||
var event:ViewStreamEvent = new ViewStreamEvent(ViewStreamEvent.START);
|
||||
dispatcher.dispatchEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a notification through the server to all the participants in the room to stop viewing the stream
|
||||
*
|
||||
*/
|
||||
public function sendStopViewingNotification():void{
|
||||
LOGGER.debug("Sending stop viewing notification to other clients.");
|
||||
try{
|
||||
deskSO.send("stopViewing");
|
||||
} catch(e:Error){
|
||||
LOGGER.debug("could not send stop viewing notification");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the server to notify clients that the deskshare stream has stooped.
|
||||
*/
|
||||
public function deskshareStreamStopped():void {
|
||||
stopViewing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a notification to the module to stop viewing the stream
|
||||
* This method is called on successful execution of sendStopViewingNotification()
|
||||
*
|
||||
*/
|
||||
public function stopViewing():void{
|
||||
LOGGER.debug("Received dekskshareStreamStopped");
|
||||
dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.STOP));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<mate:Listener type="{LocaleChangeEvent.LOCALE_CHANGED}" method="localeChanged" />
|
||||
<mate:Listener type="{StopSharingButtonEvent.STOP_SHARING}" method="stopSharingEvent" />
|
||||
<mate:Listener type="{ShortcutEvent.REMOTE_FOCUS_DESKTOP}" method="remoteFocus" />
|
||||
|
||||
<mate:Listener type="{BBBEvent.RECONNECT_DISCONNECTED_EVENT}" method="handleDisconnectedEvent" />
|
||||
|
||||
<mx:Script>
|
||||
<![CDATA[
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
@ -65,7 +66,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
import org.bigbluebutton.core.BBB;
|
||||
import org.as3commons.logging.api.ILogger;
|
||||
import org.as3commons.logging.api.getClassLogger;
|
||||
|
||||
import org.bigbluebutton.core.managers.ReconnectionManager;
|
||||
|
||||
private static const LOGGER:ILogger = getClassLogger(ScreensharePublishWindow);
|
||||
|
||||
public static const SCALE:Number = 5;
|
||||
@ -143,18 +145,24 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
return MainCanvas.DESKTOP_SHARING_PUBLISH;
|
||||
}
|
||||
|
||||
public function handleDisconnectedEvent(event:BBBEvent):void {
|
||||
if (event.payload.type == ReconnectionManager.DESKSHARE_CONNECTION) {
|
||||
closeWindow();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement resizeable interface.
|
||||
*/
|
||||
*/
|
||||
public function resetWidthAndHeight():void{/* do nothing */}
|
||||
|
||||
public function initWindow(connection:NetConnection, uri:String, room:String, autoStart:Boolean, autoFullScreen:Boolean):void {
|
||||
this.connection = connection;
|
||||
this.uri = uri;
|
||||
this.room = room;
|
||||
this.room = room;
|
||||
this.autoStart = autoStart;
|
||||
/*if(autoFullScreen)
|
||||
shareScreen(true);*/
|
||||
shareScreen(true);*/
|
||||
}
|
||||
|
||||
private function handleStartShareRequestSuccessEvent(event:StartShareRequestSuccessEvent):void {
|
||||
@ -170,7 +178,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
private function startSharing(connection:NetConnection, uri:String, room:String, fullScreen:Boolean):void {
|
||||
var captureX:Number = 0;
|
||||
var captureY:Number = 0;
|
||||
var captureY:Number = 0;
|
||||
sharingFullScreen = fullScreen;
|
||||
var authToken:String = ScreenshareModel.getInstance().authToken;
|
||||
var jnlp: String = ScreenshareModel.getInstance().jnlp;
|
||||
@ -183,7 +191,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
if (streaming) {
|
||||
stopStream();
|
||||
var streamEvent:RequestToStopSharing = new RequestToStopSharing();
|
||||
dispatchEvent(streamEvent);
|
||||
dispatchEvent(streamEvent);
|
||||
}
|
||||
sharingFullScreen = false;
|
||||
streaming = false;
|
||||
@ -195,7 +203,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
if (streaming) {
|
||||
stopStream();
|
||||
var streamEvent:StreamEvent = new StreamEvent(StreamEvent.STOP);
|
||||
dispatchEvent(streamEvent);
|
||||
dispatchEvent(streamEvent);
|
||||
}
|
||||
sharingFullScreen = false;
|
||||
streaming = false;
|
||||
@ -266,7 +274,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
ns.play(streamId);
|
||||
|
||||
btnClosePublish.enabled = true;
|
||||
btnFSPublish.enabled = false;
|
||||
btnFSPublish.enabled = false;
|
||||
btnRegionPublish.enabled = false;
|
||||
}
|
||||
|
||||
@ -305,9 +313,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
closeWindow();
|
||||
}
|
||||
|
||||
private function closeWindow():void {
|
||||
dispatchEvent(new ShareWindowEvent(ShareWindowEvent.CLOSE));
|
||||
}
|
||||
private function closeWindow():void {
|
||||
dispatchEvent(new ShareWindowEvent(ShareWindowEvent.CLOSE));
|
||||
}
|
||||
|
||||
private function restartJava():void {
|
||||
shareScreen(sharingFullScreen);
|
||||
|
@ -1,354 +1,367 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
|
||||
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
|
||||
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
-->
|
||||
|
||||
<MDIWindow xmlns="flexlib.mdi.containers.*"
|
||||
xmlns:mx="http://www.adobe.com/2006/mxml"
|
||||
width="600" height="400"
|
||||
initialize="init()"
|
||||
creationComplete="onCreationComplete()"
|
||||
implements="org.bigbluebutton.common.IBbbModuleWindow"
|
||||
xmlns:mate="http://mate.asfusion.com/"
|
||||
title="{ResourceUtil.getInstance().getString('bbb.screenshareView.title')}"
|
||||
showCloseButton="false"
|
||||
resize="fitToWindow()" >
|
||||
|
||||
<mate:Listener type="{ViewStreamEvent.STOP}" method="onStopViewStreamEvent" />
|
||||
<mate:Listener type="{LocaleChangeEvent.LOCALE_CHANGED}" method="localeChanged" />
|
||||
|
||||
<mx:Script>
|
||||
<![CDATA[
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
import flexlib.mdi.events.MDIWindowEvent;
|
||||
import mx.core.UIComponent;
|
||||
import org.bigbluebutton.common.Images;
|
||||
import org.bigbluebutton.common.events.LocaleChangeEvent;
|
||||
import org.bigbluebutton.core.managers.UserManager;
|
||||
import org.bigbluebutton.main.api.JSLog;
|
||||
import org.bigbluebutton.main.views.MainCanvas;
|
||||
import org.bigbluebutton.modules.screenshare.events.CursorEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.StartedViewingEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.ViewStreamEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.ViewWindowEvent;
|
||||
import org.bigbluebutton.modules.screenshare.model.ScreenshareModel;
|
||||
import org.bigbluebutton.modules.screenshare.model.ScreenshareOptions;
|
||||
import org.bigbluebutton.util.i18n.ResourceUtil;
|
||||
import org.as3commons.logging.api.ILogger;
|
||||
import org.as3commons.logging.api.getClassLogger;
|
||||
|
||||
private static const LOG:String = "SC::ScreenshareViewWIndow - ";
|
||||
private static const LOGGER:ILogger = getClassLogger(ScreenshareViewWindow);
|
||||
|
||||
private var screenHeight:Number = Capabilities.screenResolutionY;
|
||||
private var screenWidth:Number = Capabilities.screenResolutionX;
|
||||
|
||||
private var images:Images = new Images();
|
||||
[Bindable] public var fitToWidthIcon:Class = images.magnifier;
|
||||
[Bindable] public var fitToActualSizeIcon:Class = images.mag_reset;
|
||||
|
||||
private var streamAvailable:Boolean = false;
|
||||
|
||||
private var video:Video;
|
||||
private var ns:NetStream;
|
||||
private var videoHolder:UIComponent = new UIComponent();
|
||||
private var streamId:String;
|
||||
private var videoHeight:Number = 1;
|
||||
private var videoWidth:Number = 1;
|
||||
|
||||
private static const VIDEO_WIDTH_PADDING:int = 7;
|
||||
private static const VIDEO_HEIGHT_PADDING:int = 65;
|
||||
|
||||
// The following code block is to deal with a bug in FLexLib
|
||||
// with MDI windows not responding well to being maximized
|
||||
private var savedWindowWidth:Number;
|
||||
private var savedWindowHeight:Number;
|
||||
private var savedX:Number;
|
||||
private var savedY:Number;
|
||||
private var isMaximized:Boolean = false;
|
||||
private var connection:NetConnection;
|
||||
|
||||
[Bindable] private var baseIndex:int;
|
||||
[Bindable] private var dsOptions:ScreenshareOptions;
|
||||
|
||||
private function init():void{
|
||||
dsOptions = new ScreenshareOptions();
|
||||
baseIndex = dsOptions.baseTabIndex;
|
||||
}
|
||||
|
||||
private function onCreationComplete():void{
|
||||
viewScreenshareStream();
|
||||
|
||||
videoHolder.addChild(video);
|
||||
this.addChild(videoHolder);
|
||||
videoHolder.percentWidth = 100;
|
||||
videoHolder.percentHeight = 100;
|
||||
addEventListener(MDIWindowEvent.RESIZE_END, onResizeEndEvent);
|
||||
fitToActualSize();
|
||||
maximize();
|
||||
|
||||
resourcesChanged();
|
||||
|
||||
titleBarOverlay.tabIndex = baseIndex;
|
||||
minimizeBtn.tabIndex = baseIndex+1;
|
||||
maximizeRestoreBtn.tabIndex = baseIndex+2;
|
||||
closeBtn.tabIndex = baseIndex+3;
|
||||
|
||||
var logData:Object = new Object();
|
||||
logData.width = videoWidth;
|
||||
logData.height = videoHeight;
|
||||
logData.streamId = streamId;
|
||||
|
||||
JSLog.debug(LOG + "onCreationComplete", logData);
|
||||
}
|
||||
|
||||
private function onResizeEndEvent(event:MDIWindowEvent):void {
|
||||
if (event.window == this && streamAvailable) {
|
||||
fitToWindow();
|
||||
}
|
||||
}
|
||||
|
||||
public function startVideo(connection:NetConnection):void{
|
||||
var logData:Object = new Object();
|
||||
logData.width = videoWidth;
|
||||
logData.height = videoHeight;
|
||||
logData.streamId = streamId;
|
||||
|
||||
JSLog.debug(LOG + "startVideo", logData);
|
||||
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
private function viewScreenshareStream():void{
|
||||
videoWidth = ScreenshareModel.getInstance().width;
|
||||
videoHeight = ScreenshareModel.getInstance().height;
|
||||
streamId = ScreenshareModel.getInstance().streamId;
|
||||
|
||||
var logData:Object = new Object();
|
||||
logData.width = videoWidth;
|
||||
logData.height = videoHeight;
|
||||
logData.streamId = streamId;
|
||||
|
||||
JSLog.debug(LOG + "viewScreenshareStream Chrome", logData);
|
||||
|
||||
ns = new NetStream(connection);
|
||||
ns.addEventListener( NetStatusEvent.NET_STATUS, onNetStatus );
|
||||
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
|
||||
ns.client = this;
|
||||
ns.bufferTime = 0;
|
||||
ns.receiveVideo(true);
|
||||
ns.receiveAudio(false);
|
||||
|
||||
video = new Video(videoWidth, videoHeight);
|
||||
video.width = videoWidth;
|
||||
video.height = videoHeight;
|
||||
video.smoothing = true;
|
||||
video.attachNetStream(ns);
|
||||
ns.play(streamId);
|
||||
this.title = "Viewing Remote Desktop";
|
||||
streamAvailable = true;
|
||||
|
||||
fitToWindow();
|
||||
}
|
||||
|
||||
public function onMetaData(info:Object):void{
|
||||
trace("metadata: width=" + info.width + " height=" + info.height);
|
||||
|
||||
var logData:Object = new Object();
|
||||
logData.width = info.width;
|
||||
logData.height = info.height;
|
||||
|
||||
JSLog.debug(LOG + "onMetaData", logData);
|
||||
}
|
||||
|
||||
protected function updateButtonsPosition():void {
|
||||
if (this.width < bottomBar.width) {
|
||||
bottomBar.visible = false;
|
||||
}
|
||||
|
||||
if (bottomBar.visible == false) {
|
||||
bottomBar.y = bottomBar.x = 0;
|
||||
} else {
|
||||
bottomBar.y = (this.height - bottomBar.height) / 2;
|
||||
bottomBar.x = (this.width - bottomBar.width) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
public function stopViewing():void {
|
||||
ns.close();
|
||||
closeWindow();
|
||||
}
|
||||
|
||||
private function onStopViewStreamEvent(event:ViewStreamEvent):void {
|
||||
stopViewing();
|
||||
}
|
||||
|
||||
private function onAsyncError(e:AsyncErrorEvent):void{
|
||||
LOGGER.debug("asyncerror " + e.toString());
|
||||
var logData:Object = new Object();
|
||||
logData.error = e.toString();
|
||||
JSLog.debug(LOG + "asyncerror ", logData);
|
||||
}
|
||||
|
||||
private function onNetStatus(e:NetStatusEvent):void{
|
||||
var logData:Object = new Object();
|
||||
logData.stream = streamId;
|
||||
|
||||
switch(e.info.code){
|
||||
case "NetStream.Play.Start":
|
||||
LOGGER.debug("NetStream.Publish.Start for broadcast stream " + streamId);
|
||||
JSLog.debug(LOG + "NetStream.Publish.Start for broadcast stream ", logData);
|
||||
var dispatcher: Dispatcher = new Dispatcher();
|
||||
var viewEvent:StartedViewingEvent = new StartedViewingEvent(StartedViewingEvent.STARTED_VIEWING_EVENT);
|
||||
viewEvent.stream = streamId;
|
||||
dispatcher.dispatchEvent(viewEvent);
|
||||
break;
|
||||
case "NetStream.Play.UnpublishNotify":
|
||||
LOGGER.debug("NetStream.Play.UnpublishNotify for broadcast stream " + streamId);
|
||||
JSLog.debug(LOG + "NetStream.Play.UnpublishNotify for broadcast stream ", logData);
|
||||
stopViewing();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function getPrefferedPosition():String{
|
||||
return MainCanvas.DESKTOP_SHARING_VIEW;
|
||||
}
|
||||
|
||||
/**
|
||||
* resizes the desktop sharing video to fit to this window
|
||||
*/
|
||||
private function fitToWindow():void{
|
||||
if (!streamAvailable) return;
|
||||
|
||||
if (videoIsSmallerThanWindow()) {
|
||||
fitWindowToVideo();
|
||||
}
|
||||
|
||||
// Ignore if we are displaying the actual size of the video
|
||||
if (! btnActualSize.selected) {
|
||||
fitVideoToWindow();
|
||||
}
|
||||
}
|
||||
|
||||
private function fitVideoToWindow():void {
|
||||
if (this.width < this.height) {
|
||||
fitToWidthAndAdjustHeightToMaintainAspectRatio();
|
||||
} else {
|
||||
fitToHeightAndAdjustWidthToMaintainAspectRatio();
|
||||
}
|
||||
}
|
||||
|
||||
private function fitWindowToVideo():void {
|
||||
video.width = videoWidth;
|
||||
videoHolder.width = videoWidth;
|
||||
video.height = videoHeight;
|
||||
videoHolder.height = videoHeight;
|
||||
this.height = videoHeight + VIDEO_HEIGHT_PADDING;
|
||||
this.width = videoWidth + VIDEO_WIDTH_PADDING;
|
||||
}
|
||||
|
||||
private function videoIsSmallerThanWindow():Boolean {
|
||||
return (videoHeight < this.height) && (videoWidth < this.width);
|
||||
}
|
||||
|
||||
|
||||
private function fitToWidthAndAdjustHeightToMaintainAspectRatio():void {
|
||||
video.width = this.width - VIDEO_WIDTH_PADDING;
|
||||
videoHolder.width = video.width;
|
||||
// Maintain aspect-ratio
|
||||
video.height = (videoHeight * video.width) / videoWidth;
|
||||
videoHolder.height = video.height;
|
||||
this.height = video.height + VIDEO_HEIGHT_PADDING;
|
||||
}
|
||||
|
||||
private function fitToHeightAndAdjustWidthToMaintainAspectRatio():void {
|
||||
video.height = this.height - VIDEO_HEIGHT_PADDING;
|
||||
videoHolder.height = video.height;
|
||||
// Maintain aspect-ratio
|
||||
video.width = (videoWidth * video.height) / videoHeight;
|
||||
videoHolder.width = video.width;
|
||||
this.width = video.width + VIDEO_WIDTH_PADDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* resizes the desktop sharing video to actual video resolution
|
||||
*/
|
||||
private function fitToActualSize():void{
|
||||
if (videoIsSmallerThanWindow()) {
|
||||
fitWindowToVideo();
|
||||
} else {
|
||||
video.width = videoWidth;
|
||||
videoHolder.width = videoWidth;
|
||||
video.height = videoHeight;
|
||||
videoHolder.height = videoHeight;
|
||||
}
|
||||
}
|
||||
|
||||
private function determineHowToDisplayVideo():void {
|
||||
if (btnActualSize.selected) {
|
||||
fitToActualSize();
|
||||
btnActualSize.toolTip = ResourceUtil.getInstance().getString('bbb.screenshareView.fitToWindow');
|
||||
btnActualSize.label = ResourceUtil.getInstance().getString('bbb.screenshareView.fitToWindow');
|
||||
} else {
|
||||
fitToWindow();
|
||||
btnActualSize.toolTip = ResourceUtil.getInstance().getString('bbb.screenshareView.actualSize');
|
||||
btnActualSize.label = ResourceUtil.getInstance().getString('bbb.screenshareView.actualSize');
|
||||
}
|
||||
}
|
||||
|
||||
private function closeWindow():void {
|
||||
dispatchEvent(new ViewWindowEvent(ViewWindowEvent.CLOSE));
|
||||
}
|
||||
|
||||
override protected function resourcesChanged():void{
|
||||
super.resourcesChanged();
|
||||
this.title = ResourceUtil.getInstance().getString('bbb.screenshareView.title');
|
||||
|
||||
if (windowControls != null) {
|
||||
minimizeBtn.toolTip = ResourceUtil.getInstance().getString("bbb.window.minimizeBtn.toolTip");
|
||||
minimizeBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.screenshareView.minimizeBtn.accessibilityName");
|
||||
|
||||
maximizeRestoreBtn.toolTip = ResourceUtil.getInstance().getString("bbb.window.maximizeRestoreBtn.toolTip");
|
||||
maximizeRestoreBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.screenshareView.maximizeRestoreBtn.accessibilityName");
|
||||
|
||||
closeBtn.toolTip = ResourceUtil.getInstance().getString("bbb.window.closeBtn.toolTip");
|
||||
closeBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.screenshareView.closeBtn.accessibilityName");
|
||||
}
|
||||
}
|
||||
|
||||
private function localeChanged(e:Event):void{
|
||||
resourcesChanged();
|
||||
}
|
||||
|
||||
]]>
|
||||
</mx:Script>
|
||||
|
||||
<mx:HBox id="bottomBar" visible="true" height="30" horizontalAlign="center" paddingTop="0" paddingBottom="0" width="100%" >
|
||||
<mx:Button id="btnActualSize" paddingTop="0" paddingBottom="0" styleName="deskshareControlButtonStyle"
|
||||
toggle="true"
|
||||
click="determineHowToDisplayVideo()"
|
||||
selected="false"
|
||||
height="90%"
|
||||
label="{btnActualSize.selected ? ResourceUtil.getInstance().getString('bbb.screenshareView.fitToWindow') : ResourceUtil.getInstance().getString('bbb.screenshareView.actualSize')}"
|
||||
toolTip="{btnActualSize.selected ? ResourceUtil.getInstance().getString('bbb.screenshareView.fitToWindow') : ResourceUtil.getInstance().getString('bbb.screenshareView.actualSize')}"
|
||||
tabIndex="{baseIndex+4}"/>
|
||||
</mx:HBox>
|
||||
</MDIWindow>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
|
||||
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
|
||||
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
-->
|
||||
|
||||
<MDIWindow xmlns="flexlib.mdi.containers.*"
|
||||
xmlns:mx="http://www.adobe.com/2006/mxml"
|
||||
width="600"
|
||||
height="400"
|
||||
initialize="init()"
|
||||
creationComplete="onCreationComplete()"
|
||||
implements="org.bigbluebutton.common.IBbbModuleWindow"
|
||||
xmlns:mate="http://mate.asfusion.com/"
|
||||
title="{ ResourceUtil.getInstance().getString('bbb.screenshareView.title') }"
|
||||
showCloseButton="false"
|
||||
resize="fitToWindow()">
|
||||
|
||||
<mate:Listener type="{ ViewStreamEvent.STOP }" method="onStopViewStreamEvent" />
|
||||
<mate:Listener type="{ LocaleChangeEvent.LOCALE_CHANGED }" method="localeChanged" />
|
||||
<mate:Listener type="{ BBBEvent.RECONNECT_DISCONNECTED_EVENT }" method="handleDisconnectedEvent" />
|
||||
|
||||
<mx:Script>
|
||||
<![CDATA[
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
import flexlib.mdi.events.MDIWindowEvent;
|
||||
import mx.core.UIComponent;
|
||||
import org.bigbluebutton.common.Images;
|
||||
import org.bigbluebutton.common.events.LocaleChangeEvent;
|
||||
import org.bigbluebutton.core.managers.UserManager;
|
||||
import org.bigbluebutton.main.api.JSLog;
|
||||
import org.bigbluebutton.main.views.MainCanvas;
|
||||
import org.bigbluebutton.modules.screenshare.events.CursorEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.StartedViewingEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.ViewStreamEvent;
|
||||
import org.bigbluebutton.modules.screenshare.events.ViewWindowEvent;
|
||||
import org.bigbluebutton.modules.screenshare.model.ScreenshareModel;
|
||||
import org.bigbluebutton.modules.screenshare.model.ScreenshareOptions;
|
||||
import org.bigbluebutton.util.i18n.ResourceUtil;
|
||||
import org.as3commons.logging.api.ILogger;
|
||||
import org.as3commons.logging.api.getClassLogger;
|
||||
import org.bigbluebutton.core.managers.ReconnectionManager;
|
||||
import org.bigbluebutton.main.events.BBBEvent;
|
||||
|
||||
private static const LOG:String = "SC::ScreenshareViewWIndow - ";
|
||||
private static const LOGGER:ILogger = getClassLogger(ScreenshareViewWindow);
|
||||
|
||||
private var screenHeight:Number = Capabilities.screenResolutionY;
|
||||
private var screenWidth:Number = Capabilities.screenResolutionX;
|
||||
|
||||
private var images:Images = new Images();
|
||||
[Bindable] public var fitToWidthIcon:Class = images.magnifier;
|
||||
[Bindable] public var fitToActualSizeIcon:Class = images.mag_reset;
|
||||
|
||||
private var streamAvailable:Boolean = false;
|
||||
|
||||
private var video:Video;
|
||||
private var ns:NetStream;
|
||||
private var videoHolder:UIComponent = new UIComponent();
|
||||
private var streamId:String;
|
||||
private var videoHeight:Number = 1;
|
||||
private var videoWidth:Number = 1;
|
||||
|
||||
private static const VIDEO_WIDTH_PADDING:int = 7;
|
||||
private static const VIDEO_HEIGHT_PADDING:int = 65;
|
||||
|
||||
// The following code block is to deal with a bug in FLexLib
|
||||
// with MDI windows not responding well to being maximized
|
||||
private var savedWindowWidth:Number;
|
||||
private var savedWindowHeight:Number;
|
||||
private var savedX:Number;
|
||||
private var savedY:Number;
|
||||
private var isMaximized:Boolean = false;
|
||||
private var connection:NetConnection;
|
||||
|
||||
[Bindable] private var baseIndex:int;
|
||||
[Bindable] private var dsOptions:ScreenshareOptions;
|
||||
|
||||
private function init():void{
|
||||
dsOptions = new ScreenshareOptions();
|
||||
baseIndex = dsOptions.baseTabIndex;
|
||||
}
|
||||
|
||||
private function onCreationComplete():void{
|
||||
viewScreenshareStream();
|
||||
|
||||
videoHolder.addChild(video);
|
||||
this.addChild(videoHolder);
|
||||
videoHolder.percentWidth = 100;
|
||||
videoHolder.percentHeight = 100;
|
||||
addEventListener(MDIWindowEvent.RESIZE_END, onResizeEndEvent);
|
||||
fitToActualSize();
|
||||
maximize();
|
||||
|
||||
resourcesChanged();
|
||||
|
||||
titleBarOverlay.tabIndex = baseIndex;
|
||||
minimizeBtn.tabIndex = baseIndex+1;
|
||||
maximizeRestoreBtn.tabIndex = baseIndex+2;
|
||||
closeBtn.tabIndex = baseIndex+3;
|
||||
|
||||
var logData:Object = new Object();
|
||||
logData.width = videoWidth;
|
||||
logData.height = videoHeight;
|
||||
logData.streamId = streamId;
|
||||
|
||||
JSLog.debug(LOG + "onCreationComplete", logData);
|
||||
}
|
||||
|
||||
private function onResizeEndEvent(event:MDIWindowEvent):void {
|
||||
if (event.window == this && streamAvailable) {
|
||||
fitToWindow();
|
||||
}
|
||||
}
|
||||
|
||||
public function startVideo(connection:NetConnection):void{
|
||||
var logData:Object = new Object();
|
||||
logData.width = videoWidth;
|
||||
logData.height = videoHeight;
|
||||
logData.streamId = streamId;
|
||||
|
||||
JSLog.debug(LOG + "startVideo", logData);
|
||||
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
private function viewScreenshareStream():void{
|
||||
videoWidth = ScreenshareModel.getInstance().width;
|
||||
videoHeight = ScreenshareModel.getInstance().height;
|
||||
streamId = ScreenshareModel.getInstance().streamId;
|
||||
|
||||
var logData:Object = new Object();
|
||||
logData.width = videoWidth;
|
||||
logData.height = videoHeight;
|
||||
logData.streamId = streamId;
|
||||
|
||||
JSLog.debug(LOG + "viewScreenshareStream Chrome", logData);
|
||||
|
||||
ns = new NetStream(connection);
|
||||
ns.addEventListener( NetStatusEvent.NET_STATUS, onNetStatus );
|
||||
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
|
||||
ns.client = this;
|
||||
ns.bufferTime = 0;
|
||||
ns.receiveVideo(true);
|
||||
ns.receiveAudio(false);
|
||||
|
||||
video = new Video(videoWidth, videoHeight);
|
||||
video.width = videoWidth;
|
||||
video.height = videoHeight;
|
||||
video.smoothing = true;
|
||||
video.attachNetStream(ns);
|
||||
ns.play(streamId);
|
||||
this.title = "Viewing Remote Desktop";
|
||||
streamAvailable = true;
|
||||
|
||||
fitToWindow();
|
||||
}
|
||||
|
||||
public function onMetaData(info:Object):void{
|
||||
trace("metadata: width=" + info.width + " height=" + info.height);
|
||||
|
||||
var logData:Object = new Object();
|
||||
logData.width = info.width;
|
||||
logData.height = info.height;
|
||||
|
||||
JSLog.debug(LOG + "onMetaData", logData);
|
||||
}
|
||||
|
||||
protected function updateButtonsPosition():void {
|
||||
if (this.width < bottomBar.width) {
|
||||
bottomBar.visible = false;
|
||||
}
|
||||
|
||||
if (bottomBar.visible == false) {
|
||||
bottomBar.y = bottomBar.x = 0;
|
||||
} else {
|
||||
bottomBar.y = (this.height - bottomBar.height) / 2;
|
||||
bottomBar.x = (this.width - bottomBar.width) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
public function stopViewing():void {
|
||||
ns.close();
|
||||
closeWindow();
|
||||
}
|
||||
|
||||
private function onStopViewStreamEvent(event:ViewStreamEvent):void {
|
||||
stopViewing();
|
||||
}
|
||||
|
||||
private function onAsyncError(e:AsyncErrorEvent):void{
|
||||
LOGGER.debug("asyncerror " + e.toString());
|
||||
var logData:Object = new Object();
|
||||
logData.error = e.toString();
|
||||
JSLog.debug(LOG + "asyncerror ", logData);
|
||||
}
|
||||
|
||||
private function onNetStatus(e:NetStatusEvent):void{
|
||||
var logData:Object = new Object();
|
||||
logData.stream = streamId;
|
||||
|
||||
switch(e.info.code){
|
||||
case "NetStream.Play.Start":
|
||||
LOGGER.debug("NetStream.Publish.Start for broadcast stream " + streamId);
|
||||
JSLog.debug(LOG + "NetStream.Publish.Start for broadcast stream ", logData);
|
||||
var dispatcher: Dispatcher = new Dispatcher();
|
||||
var viewEvent:StartedViewingEvent = new StartedViewingEvent(StartedViewingEvent.STARTED_VIEWING_EVENT);
|
||||
viewEvent.stream = streamId;
|
||||
dispatcher.dispatchEvent(viewEvent);
|
||||
break;
|
||||
case "NetStream.Play.UnpublishNotify":
|
||||
LOGGER.debug("NetStream.Play.UnpublishNotify for broadcast stream " + streamId);
|
||||
JSLog.debug(LOG + "NetStream.Play.UnpublishNotify for broadcast stream ", logData);
|
||||
stopViewing();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function getPrefferedPosition():String{
|
||||
return MainCanvas.DESKTOP_SHARING_VIEW;
|
||||
}
|
||||
|
||||
/**
|
||||
* resizes the desktop sharing video to fit to this window
|
||||
*/
|
||||
private function fitToWindow():void{
|
||||
if (!streamAvailable) return;
|
||||
|
||||
if (videoIsSmallerThanWindow()) {
|
||||
fitWindowToVideo();
|
||||
}
|
||||
|
||||
// Ignore if we are displaying the actual size of the video
|
||||
if (! btnActualSize.selected) {
|
||||
fitVideoToWindow();
|
||||
}
|
||||
}
|
||||
|
||||
private function fitVideoToWindow():void {
|
||||
if (this.width < this.height) {
|
||||
fitToWidthAndAdjustHeightToMaintainAspectRatio();
|
||||
} else {
|
||||
fitToHeightAndAdjustWidthToMaintainAspectRatio();
|
||||
}
|
||||
}
|
||||
|
||||
private function fitWindowToVideo():void {
|
||||
video.width = videoWidth;
|
||||
videoHolder.width = videoWidth;
|
||||
video.height = videoHeight;
|
||||
videoHolder.height = videoHeight;
|
||||
this.height = videoHeight + VIDEO_HEIGHT_PADDING;
|
||||
this.width = videoWidth + VIDEO_WIDTH_PADDING;
|
||||
}
|
||||
|
||||
private function videoIsSmallerThanWindow():Boolean {
|
||||
return (videoHeight < this.height) && (videoWidth < this.width);
|
||||
}
|
||||
|
||||
|
||||
private function fitToWidthAndAdjustHeightToMaintainAspectRatio():void {
|
||||
video.width = this.width - VIDEO_WIDTH_PADDING;
|
||||
videoHolder.width = video.width;
|
||||
// Maintain aspect-ratio
|
||||
video.height = (videoHeight * video.width) / videoWidth;
|
||||
videoHolder.height = video.height;
|
||||
this.height = video.height + VIDEO_HEIGHT_PADDING;
|
||||
}
|
||||
|
||||
private function fitToHeightAndAdjustWidthToMaintainAspectRatio():void {
|
||||
video.height = this.height - VIDEO_HEIGHT_PADDING;
|
||||
videoHolder.height = video.height;
|
||||
// Maintain aspect-ratio
|
||||
video.width = (videoWidth * video.height) / videoHeight;
|
||||
videoHolder.width = video.width;
|
||||
this.width = video.width + VIDEO_WIDTH_PADDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* resizes the desktop sharing video to actual video resolution
|
||||
*/
|
||||
private function fitToActualSize():void{
|
||||
if (videoIsSmallerThanWindow()) {
|
||||
fitWindowToVideo();
|
||||
} else {
|
||||
video.width = videoWidth;
|
||||
videoHolder.width = videoWidth;
|
||||
video.height = videoHeight;
|
||||
videoHolder.height = videoHeight;
|
||||
}
|
||||
}
|
||||
|
||||
private function determineHowToDisplayVideo():void {
|
||||
if (btnActualSize.selected) {
|
||||
fitToActualSize();
|
||||
btnActualSize.toolTip = ResourceUtil.getInstance().getString('bbb.screenshareView.fitToWindow');
|
||||
btnActualSize.label = ResourceUtil.getInstance().getString('bbb.screenshareView.fitToWindow');
|
||||
} else {
|
||||
fitToWindow();
|
||||
btnActualSize.toolTip = ResourceUtil.getInstance().getString('bbb.screenshareView.actualSize');
|
||||
btnActualSize.label = ResourceUtil.getInstance().getString('bbb.screenshareView.actualSize');
|
||||
}
|
||||
}
|
||||
|
||||
private function closeWindow():void {
|
||||
dispatchEvent(new ViewWindowEvent(ViewWindowEvent.CLOSE));
|
||||
}
|
||||
|
||||
override protected function resourcesChanged():void{
|
||||
super.resourcesChanged();
|
||||
this.title = ResourceUtil.getInstance().getString('bbb.screenshareView.title');
|
||||
|
||||
if (windowControls != null) {
|
||||
minimizeBtn.toolTip = ResourceUtil.getInstance().getString("bbb.window.minimizeBtn.toolTip");
|
||||
minimizeBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.screenshareView.minimizeBtn.accessibilityName");
|
||||
|
||||
maximizeRestoreBtn.toolTip = ResourceUtil.getInstance().getString("bbb.window.maximizeRestoreBtn.toolTip");
|
||||
maximizeRestoreBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.screenshareView.maximizeRestoreBtn.accessibilityName");
|
||||
|
||||
closeBtn.toolTip = ResourceUtil.getInstance().getString("bbb.window.closeBtn.toolTip");
|
||||
closeBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.screenshareView.closeBtn.accessibilityName");
|
||||
}
|
||||
}
|
||||
|
||||
private function localeChanged(e:Event):void{
|
||||
resourcesChanged();
|
||||
}
|
||||
|
||||
public function handleDisconnectedEvent(event:BBBEvent):void {
|
||||
if (event.payload.type == ReconnectionManager.DESKSHARE_CONNECTION) {
|
||||
closeWindow();
|
||||
}
|
||||
}
|
||||
|
||||
]]>
|
||||
</mx:Script>
|
||||
|
||||
<mx:HBox id="bottomBar" visible="true" height="30" horizontalAlign="center" paddingTop="0" paddingBottom="0" width="100%">
|
||||
<mx:Button id="btnActualSize"
|
||||
paddingTop="0"
|
||||
paddingBottom="0"
|
||||
styleName="deskshareControlButtonStyle"
|
||||
toggle="true"
|
||||
click="determineHowToDisplayVideo()"
|
||||
selected="false"
|
||||
height="90%"
|
||||
label="{ btnActualSize.selected ? ResourceUtil.getInstance().getString('bbb.screenshareView.fitToWindow') : ResourceUtil.getInstance().getString('bbb.screenshareView.actualSize') }"
|
||||
toolTip="{ btnActualSize.selected ? ResourceUtil.getInstance().getString('bbb.screenshareView.fitToWindow') : ResourceUtil.getInstance().getString('bbb.screenshareView.actualSize') }"
|
||||
tabIndex="{ baseIndex + 4 }" />
|
||||
</mx:HBox>
|
||||
</MDIWindow>
|
||||
|
@ -281,7 +281,7 @@ uncomment () {
|
||||
stop_bigbluebutton () {
|
||||
echo "Stopping BigBlueButton"
|
||||
if command -v systemctl >/dev/null; then
|
||||
systemctl stop red5 tomcat7 nginx freeswitch bbb-apps-akka bbb-fsesl-akka
|
||||
systemctl stop red5 tomcat7 nginx freeswitch bbb-apps-akka bbb-fsesl-akka bbb-record-core.service bbb-record-core.timer
|
||||
else
|
||||
/etc/init.d/monit stop
|
||||
|
||||
@ -324,7 +324,7 @@ stop_bigbluebutton () {
|
||||
start_bigbluebutton () {
|
||||
echo "Starting BigBlueButton"
|
||||
if command -v systemctl >/dev/null; then
|
||||
systemctl start red5 tomcat7 nginx freeswitch bbb-apps-akka bbb-fsesl-akka
|
||||
systemctl start red5 tomcat7 nginx freeswitch bbb-apps-akka bbb-fsesl-akka bbb-record-core.timer
|
||||
else
|
||||
$FREESWITCH_INIT_D start
|
||||
|
||||
@ -580,10 +580,10 @@ while [ $# -gt 0 ]; do
|
||||
SALT="${2}"
|
||||
if [ -z "$SALT" ]; then
|
||||
BBB_WEB_URL=$(cat ${SERVLET_DIR}/bigbluebutton/WEB-INF/classes/bigbluebutton.properties | grep -v '#' | sed -n '/^bigbluebutton.web.serverURL/{s/.*=//;p}')
|
||||
SALT=$(cat ${SERVLET_DIR}/bigbluebutton/WEB-INF/classes/bigbluebutton.properties | grep -v '#' | grep securitySalt | cut -d= -f2);
|
||||
SECRET=$(cat ${SERVLET_DIR}/bigbluebutton/WEB-INF/classes/bigbluebutton.properties | grep -v '#' | grep securitySalt | cut -d= -f2);
|
||||
echo
|
||||
echo " URL: $BBB_WEB_URL/bigbluebutton/"
|
||||
echo " Salt: $SALT"
|
||||
echo " Secret: $SECRET"
|
||||
echo
|
||||
exit 0
|
||||
fi
|
||||
@ -646,11 +646,10 @@ if [ $SALT ]; then
|
||||
fi
|
||||
|
||||
if [ -f /usr/share/bbb-apps-akka/conf/application.conf ]; then
|
||||
sed -i "s/sharedSecret.[ ]*=[ ]*\"[^\"]*\"/sharedSecret.=\"$SALT\"/g" \
|
||||
sed -i "s/sharedSecret[ ]*=[ ]*\"[^\"]*\"/sharedSecret=\"$SALT\"/g" \
|
||||
/usr/share/bbb-apps-akka/conf/application.conf
|
||||
fi
|
||||
|
||||
change_var_salt ${SERVLET_DIR}/bigbluebutton/WEB-INF/classes/bigbluebutton.properties securitySalt $SALT
|
||||
echo "Changed BigBlueButton's shared secret to $SALT"
|
||||
echo
|
||||
fi
|
||||
@ -891,6 +890,14 @@ check_configuration() {
|
||||
echo "# /var/bigbluebutton"
|
||||
echo "# is not owned by $TOMCAT_USER"
|
||||
fi
|
||||
|
||||
if [ $PROTOCOL_HTTP == "https" ]; then
|
||||
if ! grep jnlpUrl /usr/share/red5/webapps/screenshare/WEB-INF/screenshare.properties | grep -q https; then
|
||||
echo "# Warning: Detected the value for jnlpUrl is not configured for HTTPS"
|
||||
echo "# /usr/share/red5/webapps/screenshare/WEB-INF/screenshare.properties"
|
||||
echo "#"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@ -1686,11 +1693,10 @@ if [ -n "$HOST" ]; then
|
||||
/usr/share/bbb-apps-akka/conf/application.conf
|
||||
sed -i "s/defaultPresentationURL[ ]*=[ ]*\"[^\"]*\"/defaultPresentationURL=\"${PROTOCOL_HTTP}:\/\/$HOST\/default.pdf\"/g" \
|
||||
/usr/share/bbb-apps-akka/conf/application.conf
|
||||
if grep sharedSecret /usr/share/bbb-apps-akka/conf/application.conf | grep -q \"changeme\"; then
|
||||
SECRET=$(cat ${SERVLET_DIR}/bigbluebutton/WEB-INF/classes/bigbluebutton.properties | grep -v '#' | grep securitySalt | cut -d= -f2);
|
||||
sed -i "s/sharedSecret[ ]*=[ ]*\"[^\"]*\"/sharedSecret=\"$SECRET\"/g" \
|
||||
/usr/share/bbb-apps-akka/conf/application.conf
|
||||
fi
|
||||
# XXX Temporary fix to ensure application.conf has the latest shared secret
|
||||
SECRET=$(cat ${SERVLET_DIR}/bigbluebutton/WEB-INF/classes/bigbluebutton.properties | grep -v '#' | grep securitySalt | cut -d= -f2);
|
||||
sed -i "s/sharedSecret[ ]*=[ ]*\"[^\"]*\"/sharedSecret=\"$SECRET\"/g" \
|
||||
/usr/share/bbb-apps-akka/conf/application.conf
|
||||
fi
|
||||
|
||||
#
|
||||
|
@ -201,15 +201,15 @@ eventEmitter.on('presenter_assigned_message', function (arg) {
|
||||
});
|
||||
|
||||
const handleRemoveUserEvent = function (arg) {
|
||||
if (arg.payload.user != null &&
|
||||
arg.payload.user.userid != null &&
|
||||
arg.payload.meeting_id != null) {
|
||||
const meetingId = arg.payload.meeting_id;
|
||||
const userId = arg.payload.user.userid;
|
||||
return markUserOffline(meetingId, userId, arg.callback);
|
||||
const { payload, callback } = arg;
|
||||
if ((payload.userid || payload.user.userid) &&
|
||||
payload.meeting_id) {
|
||||
const meetingId = payload.meeting_id;
|
||||
const userId = payload.userid || payload.user.userid;
|
||||
return markUserOffline(meetingId, userId, callback);
|
||||
} else {
|
||||
logger.info('could not perform handleRemoveUserEvent');
|
||||
return arg.callback();
|
||||
return callback();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -9,5 +9,6 @@
|
||||
"app.chat.titlePublic": "Public Chat",
|
||||
"app.chat.titlePrivate": "Private Chat with {name}",
|
||||
"app.chat.partnerDisconnected": "{name} has left the meeting",
|
||||
"app.chat.moreMessages": "More messages below"
|
||||
"app.chat.moreMessages": "More messages below",
|
||||
"app.kickMessage": "You have been kicked out of the meeting"
|
||||
}
|
||||
|
@ -9,5 +9,6 @@
|
||||
"app.chat.titlePublic": "Conversa Publíca",
|
||||
"app.chat.titlePrivate": "Conversa Privada com {name}",
|
||||
"app.chat.partnerDisconnected": "{name} saiu da sala",
|
||||
"app.chat.moreMessages": "Mais mensagens abaixo"
|
||||
"app.chat.moreMessages": "Mais mensagens abaixo",
|
||||
"app.kickMessage": "Você foi expulso da apresentação"
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import { subscribeToCollections, setCredentials } from '/imports/ui/components/a
|
||||
|
||||
import ChatContainer from '/imports/ui/components/chat/container';
|
||||
import UserListContainer from '/imports/ui/components/user-list/container';
|
||||
import Loader from '/imports/ui/components/loader/component';
|
||||
|
||||
const browserHistory = useRouterHistory(createHistory)({
|
||||
basename: '/html5client',
|
||||
|
@ -1,5 +1,8 @@
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import Loader from '../loader/component';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import LoadingScreen from '../loading-screen/component';
|
||||
import KickedScreen from '../kicked-screen/component';
|
||||
import Button from '../button/component';
|
||||
import styles from './styles';
|
||||
|
||||
const propTypes = {
|
||||
@ -117,8 +120,24 @@ export default class App extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.wasKicked) {
|
||||
return (
|
||||
<KickedScreen>
|
||||
<FormattedMessage
|
||||
id="app.kickMessage"
|
||||
description="Message when the user is kicked out of the meeting"
|
||||
defaultMessage="You have been kicked out of the meeting"
|
||||
/>
|
||||
<br/><br/>
|
||||
<Button
|
||||
label={'OK'}
|
||||
onClick={this.props.redirectToLogoutUrl}/>
|
||||
</KickedScreen>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.props.isLoading) {
|
||||
return <Loader/>;
|
||||
return <LoadingScreen/>;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -1,8 +1,7 @@
|
||||
import React, { Component, PropTypes, cloneElement } from 'react';
|
||||
import { createContainer } from 'meteor/react-meteor-data';
|
||||
import App from './component';
|
||||
import { subscribeForData, pollExists } from './service';
|
||||
|
||||
import { subscribeForData, pollExists, wasUserKicked, redirectToLogoutUrl } from './service';
|
||||
import NavBarContainer from '../nav-bar/container';
|
||||
import ActionsBarContainer from '../actions-bar/container';
|
||||
import MediaContainer from '../media/container';
|
||||
@ -59,11 +58,12 @@ export default createContainer(() => {
|
||||
Promise.all(subscribeForData())
|
||||
.then(() => {
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(reason => console.error(reason));
|
||||
});
|
||||
|
||||
return {
|
||||
wasKicked: wasUserKicked(),
|
||||
isLoading: getLoading(),
|
||||
redirectToLogoutUrl,
|
||||
actionsbar: <ActionsBarContainer />,
|
||||
};
|
||||
}, AppContainer);
|
||||
|
@ -45,26 +45,51 @@ function subscribeFor(collectionName) {
|
||||
};
|
||||
|
||||
function subscribeToCollections(cb) {
|
||||
subscribeFor('users').then(() => {
|
||||
Promise.all(subscribeForData()).then(() => {
|
||||
if (cb) {
|
||||
cb();
|
||||
subscribeFor('users')
|
||||
.then(() => {
|
||||
observeUserKick();
|
||||
return Promise.all(subscribeForData())
|
||||
.then(() => {
|
||||
if (cb) {
|
||||
return cb();
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(redirectToLogoutUrl);
|
||||
};
|
||||
|
||||
function redirectToLogoutUrl(reason) {
|
||||
console.error(reason);
|
||||
console.log('Redirecting user to the logoutURL...');
|
||||
document.location.href = Auth.logoutURL;
|
||||
}
|
||||
|
||||
let wasKicked = false;
|
||||
const wasKickedDep = new Tracker.Dependency;
|
||||
|
||||
function observeUserKick() {
|
||||
Users.find().observe({
|
||||
removed(old) {
|
||||
if (old.userId === Auth.userID) {
|
||||
Auth.clearCredentials(() => {
|
||||
wasKicked = true;
|
||||
wasKickedDep.changed();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function onStop(error, result) {
|
||||
console.log('OnError', error, result);
|
||||
};
|
||||
|
||||
function onReady() {
|
||||
console.log('OnReady');
|
||||
};
|
||||
function wasUserKicked() {
|
||||
wasKickedDep.depend();
|
||||
return wasKicked;
|
||||
}
|
||||
|
||||
export {
|
||||
subscribeForData,
|
||||
setCredentials,
|
||||
subscribeFor,
|
||||
subscribeToCollections,
|
||||
wasUserKicked,
|
||||
redirectToLogoutUrl
|
||||
};
|
||||
|
@ -0,0 +1,18 @@
|
||||
import React, { Component } from 'react';
|
||||
import styles from './styles.scss';
|
||||
|
||||
import Icon from '../icon/component';
|
||||
|
||||
class KickedScreen extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className={styles.background}>
|
||||
<Icon iconName="sad" className={styles.icon}/>
|
||||
<div className={styles.message}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default KickedScreen;
|
@ -0,0 +1,28 @@
|
||||
@import '../../stylesheets/variables/palette';
|
||||
|
||||
$bg: $color-gray-dark;
|
||||
$color: $color-white;
|
||||
|
||||
.background {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: $bg;
|
||||
color: $color;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 100%;
|
||||
font-size: 10rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.message {
|
||||
text-transform: uppercase;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import React, { Component } from 'react';
|
||||
import styles from './styles.scss';
|
||||
|
||||
class Loader extends Component {
|
||||
class LoadingScreen extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className={styles.background}>
|
||||
@ -14,4 +14,4 @@ class Loader extends Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
export default Loader;
|
||||
export default LoadingScreen;
|
@ -51,7 +51,3 @@
|
||||
.recordImage {
|
||||
margin-left: -5px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
border: 10px solid red;
|
||||
}
|
||||
|
@ -393,8 +393,13 @@ class ApiController {
|
||||
// Check if this config is one of our pre-built config
|
||||
configxml = configService.getConfig(params.configToken)
|
||||
if (configxml == null) {
|
||||
// Default to the default config.
|
||||
configxml = conf.config;
|
||||
// BEGIN - backward compatibility
|
||||
invalid("noConfigFound","We could not find a config for this request.", REDIRECT_RESPONSE);
|
||||
return
|
||||
// END - backward compatibility
|
||||
|
||||
errors.noConfigFound();
|
||||
respondWithErrors(errors);
|
||||
}
|
||||
} else {
|
||||
configxml = conf.config;
|
||||
@ -402,6 +407,11 @@ class ApiController {
|
||||
} else {
|
||||
Config conf = meeting.getDefaultConfig();
|
||||
if (conf == null) {
|
||||
// BEGIN - backward compatibility
|
||||
invalid("noConfigFound","We could not find a config for this request.", REDIRECT_RESPONSE);
|
||||
return
|
||||
// END - backward compatibility
|
||||
|
||||
errors.noConfigFound();
|
||||
respondWithErrors(errors);
|
||||
} else {
|
||||
@ -410,6 +420,11 @@ class ApiController {
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(configxml)) {
|
||||
// BEGIN - backward compatibility
|
||||
invalid("noConfigFound","We could not find a config for this request.", REDIRECT_RESPONSE);
|
||||
return
|
||||
// END - backward compatibility
|
||||
|
||||
errors.noConfigFound();
|
||||
respondWithErrors(errors);
|
||||
}
|
||||
@ -1398,11 +1413,19 @@ class ApiController {
|
||||
String API_CALL = "getDefaultConfigXML"
|
||||
ApiErrors errors = new ApiErrors();
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
return
|
||||
}
|
||||
|
||||
if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
return
|
||||
}
|
||||
// END - backward compatibility
|
||||
|
||||
|
||||
// Do we agree on the checksum? If not, complain.
|
||||
if (!paramsProcessorUtil.isChecksumSame(API_CALL, params.checksum, request.getQueryString())) {
|
||||
errors.checksumError()
|
||||
@ -1484,7 +1507,7 @@ class ApiController {
|
||||
reject = true;
|
||||
else {
|
||||
us = meetingService.getUserSession(sessionToken);
|
||||
meeting = meetingService.getMeeting(us.meetingID, true);
|
||||
meeting = meetingService.getMeeting(us.meetingID);
|
||||
if (meeting == null || meeting.isForciblyEnded()) {
|
||||
reject = true
|
||||
}
|
||||
@ -1984,17 +2007,11 @@ class ApiController {
|
||||
// END - backward compatibility
|
||||
}
|
||||
|
||||
// Do we have a publish status? If none, set default value.
|
||||
String force = params.force
|
||||
if (StringUtils.isEmpty(force)) {
|
||||
force = "false"
|
||||
}
|
||||
|
||||
//Execute code specific for this call
|
||||
Map<String, String> metaParams = ParamsProcessorUtil.processMetaParam(params)
|
||||
if ( !metaParams.empty ) {
|
||||
//Proceed with the update
|
||||
meetingService.updateRecordings(recordIdList, metaParams, force.toBoolean());
|
||||
meetingService.updateRecordings(recordIdList, metaParams);
|
||||
}
|
||||
withFormat {
|
||||
xml {
|
||||
@ -2240,7 +2257,7 @@ class ApiController {
|
||||
//TODO: method added for backward compatibility, it will be removed in next versions after 0.8
|
||||
private void invalid(key, msg, redirectResponse=false) {
|
||||
// Note: This xml scheme will be DEPRECATED.
|
||||
log.debug CONTROLLER_NAME + "#invalid"
|
||||
log.debug CONTROLLER_NAME + "#invalid " + msg
|
||||
if (redirectResponse) {
|
||||
ArrayList<Object> errors = new ArrayList<Object>();
|
||||
Map<String,String> errorMap = new LinkedHashMap<String,String>()
|
||||
|
@ -352,16 +352,15 @@ public class MeetingService implements MessageListener {
|
||||
}
|
||||
|
||||
public Meeting getMeeting(String meetingId) {
|
||||
return getMeeting(meetingId, false);
|
||||
}
|
||||
|
||||
public Meeting getMeeting(String meetingId, Boolean exactMatch) {
|
||||
if (meetingId == null)
|
||||
return null;
|
||||
int dashes = meetingId.split("-", -1).length - 1;
|
||||
for (String key : meetings.keySet()) {
|
||||
if ((!exactMatch && key.startsWith(meetingId))
|
||||
|| (exactMatch && key.equals(meetingId)))
|
||||
int keyDashes = key.split("-", -1).length - 1;
|
||||
if (dashes == 2 && key.equals(meetingId)
|
||||
|| (dashes < 2 && keyDashes < 2 && key.startsWith(meetingId))) {
|
||||
return (Meeting) meetings.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -485,8 +484,8 @@ public class MeetingService implements MessageListener {
|
||||
}
|
||||
}
|
||||
|
||||
public void updateRecordings(List<String> idList, Map<String, String> metaParams, boolean force) {
|
||||
recordingService.updateMetaParams(idList, metaParams, force);
|
||||
public void updateRecordings(List<String> idList, Map<String, String> metaParams) {
|
||||
recordingService.updateMetaParams(idList, metaParams);
|
||||
}
|
||||
|
||||
public void processRecording(String meetingId) {
|
||||
|
@ -397,10 +397,6 @@ public class RecordingService {
|
||||
}
|
||||
|
||||
public void updateMetaParams(List<String> recordIDs, Map<String,String> metaParams) {
|
||||
updateMetaParams(recordIDs, metaParams, false);
|
||||
}
|
||||
|
||||
public void updateMetaParams(List<String> recordIDs, Map<String,String> metaParams, boolean force) {
|
||||
|
||||
// Define the directories used to lookup the recording
|
||||
List<String> states = new ArrayList<String>();
|
||||
@ -422,20 +418,13 @@ public class RecordingService {
|
||||
Recording rec = getRecordingInfo(recFile);
|
||||
if (rec != null) {
|
||||
for (Map.Entry<String,String> meta : metaParams.entrySet()) {
|
||||
if ( rec.containsMetadata(meta.getKey()) ) {
|
||||
// The meta parameter already exists
|
||||
if ( !"".equals(meta.getValue()) || !force ) {
|
||||
// update it
|
||||
rec.updateMetadata(meta.getKey(), meta.getValue());
|
||||
} else {
|
||||
// delete it
|
||||
rec.deleteMetadata(meta.getKey());
|
||||
}
|
||||
if ( !"".equals(meta.getValue()) ) {
|
||||
// As it has a value, if the meta parameter exists update it, otherwise add it
|
||||
rec.updateMetadata(meta.getKey(), meta.getValue());
|
||||
} else {
|
||||
// The meta parameter doesn't exist
|
||||
if ( force ) {
|
||||
// but force is set to true, then add it
|
||||
rec.updateMetadata(meta.getKey(), meta.getValue());
|
||||
// As it doesn't have a value, if it exists delete it
|
||||
if ( rec.containsMetadata(meta.getKey()) ) {
|
||||
rec.deleteMetadata(meta.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ require 'recordandplayback/events_archiver'
|
||||
require 'recordandplayback/video_archiver'
|
||||
require 'recordandplayback/presentation_archiver'
|
||||
require 'recordandplayback/deskshare_archiver'
|
||||
require 'recordandplayback/webrtc_deskshare_archiver'
|
||||
require 'recordandplayback/generators/events'
|
||||
require 'recordandplayback/generators/audio'
|
||||
require 'recordandplayback/generators/video'
|
||||
@ -126,7 +125,7 @@ module BigBlueButton
|
||||
def self.exec_ret(*command)
|
||||
BigBlueButton.logger.info "Executing: #{command.join(' ')}"
|
||||
IO.popen([*command, :err => [:child, :out]]) do |io|
|
||||
io.lines.each do |line|
|
||||
io.each_line do |line|
|
||||
BigBlueButton.logger.info line.chomp
|
||||
end
|
||||
end
|
||||
@ -140,7 +139,7 @@ module BigBlueButton
|
||||
IO.pipe do |r, w|
|
||||
pid = spawn(*command, :out => outio, :err => w)
|
||||
w.close
|
||||
r.lines.each do |line|
|
||||
r.each_line do |line|
|
||||
BigBlueButton.logger.info line.chomp
|
||||
end
|
||||
Process.waitpid(pid)
|
||||
|
399
record-and-playback/core/scripts/utils/gen_webvtt
Executable file
399
record-and-playback/core/scripts/utils/gen_webvtt
Executable file
@ -0,0 +1,399 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# This file is part of BigBlueButton.
|
||||
#
|
||||
# BigBlueButton is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BigBlueButton is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with BigBlueButton. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# To install dependencies on Ubuntu:
|
||||
# apt-get install python3 python3-lxml python3-pyicu
|
||||
|
||||
from lxml import etree
|
||||
from collections import deque
|
||||
from fractions import Fraction
|
||||
import io
|
||||
from icu import Locale, BreakIterator
|
||||
import unicodedata
|
||||
import html
|
||||
import logging
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
import argparse
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def webvtt_timestamp(ms):
|
||||
frac_s = int(ms % 1000)
|
||||
s = int(ms / 1000 % 60)
|
||||
m = int(ms / 1000 / 60 % 60)
|
||||
h = int(ms / 1000 / 60 / 60)
|
||||
return '{:02}:{:02}:{:02}.{:03}'.format(h, m, s, frac_s)
|
||||
|
||||
class CaptionLine:
|
||||
def __init__(self):
|
||||
self.text = ""
|
||||
self.start_time = 0
|
||||
self.end_time = 0
|
||||
|
||||
class Caption:
|
||||
def __init__(self, locale):
|
||||
self.locale = locale
|
||||
self.text = list()
|
||||
self.timestamps = list()
|
||||
self._del_timestamps = list()
|
||||
|
||||
def apply_edit(self, i, j, timestamp, text):
|
||||
del_timestamp = None
|
||||
if j > i:
|
||||
if self._del_timestamps[i] is not None:
|
||||
del_timestamp = self._del_timestamps[i]
|
||||
else:
|
||||
del_timestamp = self.timestamps[i]
|
||||
self._del_timestamps[i] = del_timestamp
|
||||
logger.debug("Removing text %s at %d:%d, del_ts: %d",
|
||||
repr(''.join(self.text[i:j])), i, j, del_timestamp)
|
||||
|
||||
if len(text) > 0:
|
||||
logger.debug("Inserting text %s at %d:%d, ts: %d",
|
||||
repr(''.join(text)), i, j, timestamp)
|
||||
|
||||
if i < len(self.timestamps) and timestamp > self.timestamps[i]:
|
||||
timestamp = self._del_timestamps[i]
|
||||
if timestamp is None and i > 0:
|
||||
timestamp = self.timestamps[i-1]
|
||||
logger.debug("Out of order timestamps, using ts: %d", timestamp)
|
||||
|
||||
self._del_timestamps[i:j] = [del_timestamp] * len(text)
|
||||
if (i < len(self._del_timestamps)):
|
||||
self._del_timestamps[i] = del_timestamp
|
||||
|
||||
self.text[i:j] = text
|
||||
self.timestamps[i:j] = [timestamp] * len(text)
|
||||
|
||||
def apply_record_events(self, events):
|
||||
record = False
|
||||
ts_offset = 0
|
||||
stop_ts = 0
|
||||
start_ts = None
|
||||
stop_pos = 0
|
||||
start_pos = None
|
||||
for event in events:
|
||||
if event['name'] == 'record_status':
|
||||
status = event['status']
|
||||
timestamp = event['timestamp']
|
||||
|
||||
if status and not record:
|
||||
record = True
|
||||
start_ts = timestamp
|
||||
logger.debug("Recording started at ts: %d", start_ts)
|
||||
|
||||
# Find the position of the first character after recording
|
||||
# started
|
||||
start_pos = stop_pos
|
||||
while start_pos < len(self.timestamps) and \
|
||||
self.timestamps[start_pos] < start_ts:
|
||||
start_pos += 1
|
||||
|
||||
logger.debug("Replacing characters %d:%d",
|
||||
stop_pos, start_pos)
|
||||
self.text[stop_pos:start_pos] = ["\n"]
|
||||
self.timestamps[stop_pos:start_pos] = [stop_ts - ts_offset]
|
||||
|
||||
start_pos = stop_pos + 1
|
||||
ts_offset += start_ts - stop_ts
|
||||
logger.debug("Timestamp offset now %d", ts_offset)
|
||||
|
||||
stop_ts = None
|
||||
stop_pos = None
|
||||
|
||||
if not status and record:
|
||||
record = False
|
||||
stop_ts = timestamp
|
||||
logger.debug("Recording stopped at ts: %d", stop_ts)
|
||||
|
||||
# Find the position of the first character after recording
|
||||
# stopped, and apply ts offsets
|
||||
stop_pos = start_pos
|
||||
while stop_pos < len(self.timestamps) and \
|
||||
self.timestamps[stop_pos] < stop_ts:
|
||||
self.timestamps[stop_pos] -= ts_offset
|
||||
stop_pos += 1
|
||||
|
||||
if record:
|
||||
logger.debug("No recording stop, applying final ts offsets")
|
||||
|
||||
while start_pos < len(self.timestamps):
|
||||
self.timestamps[start_pos] -= ts_offset
|
||||
start_pos += 1
|
||||
|
||||
@classmethod
|
||||
def from_events(cls, events, apply_record_events=True):
|
||||
captions = {}
|
||||
|
||||
# Apply all of the caption events to generate the full text
|
||||
# with per-character timestamps
|
||||
for event in events:
|
||||
if event['name'] == 'edit_caption_history':
|
||||
locale = event['locale']
|
||||
i = event['start_index']
|
||||
j = event['end_index']
|
||||
timestamp = event['timestamp']
|
||||
text = event['text']
|
||||
|
||||
caption = captions.get(locale)
|
||||
if caption is None:
|
||||
logger.info("Started caption stream for locale '%s'",
|
||||
locale)
|
||||
captions[locale] = caption = cls(locale)
|
||||
|
||||
caption.apply_edit(i, j, timestamp, text)
|
||||
|
||||
if apply_record_events:
|
||||
for locale, caption in captions.items():
|
||||
logger.info("Applying recording events to locale '%s'", locale)
|
||||
caption.apply_record_events(events)
|
||||
|
||||
logger.info("Generated %d caption stream(s)", len(captions))
|
||||
return captions
|
||||
|
||||
def split_lines(self, max_length=32):
|
||||
lines = list()
|
||||
|
||||
str_text = "".join(self.text)
|
||||
|
||||
locale = Locale(self.locale)
|
||||
logger.debug("Using locale %s for word-wrapping",
|
||||
locale.getDisplayName(locale))
|
||||
|
||||
break_iter = BreakIterator.createLineInstance(locale)
|
||||
break_iter.setText(str_text)
|
||||
|
||||
line = CaptionLine()
|
||||
line_start = 0
|
||||
prev_break = 0
|
||||
next_break = break_iter.following(prev_break)
|
||||
|
||||
# Super simple "greedy" line break algorithm.
|
||||
while prev_break < len(self.text):
|
||||
status = break_iter.getRuleStatus()
|
||||
|
||||
line_end = next_break
|
||||
while line_end > line_start and ( \
|
||||
self.text[line_end-1].isspace() or \
|
||||
unicodedata.category(self.text[line_end-1]) in ['Cc', 'Mn']
|
||||
):
|
||||
line_end -= 1
|
||||
|
||||
do_break = False
|
||||
text_section = unicodedata.normalize(
|
||||
'NFC', "".join(self.text[line_start:line_end]))
|
||||
timestamps_section = self.timestamps[line_start:next_break]
|
||||
start_time = min(timestamps_section)
|
||||
end_time = max(timestamps_section)
|
||||
if len(text_section) > max_length:
|
||||
if prev_break == line_start:
|
||||
# Over-long string. Just chop it into bits
|
||||
line_end = next_break = prev_break + max_length
|
||||
else:
|
||||
next_break = prev_break
|
||||
do_break = True
|
||||
|
||||
else:
|
||||
# Status [100,200) indicates a required (hard) line break
|
||||
if next_break >= len(self.text) or \
|
||||
(status >= 100 and status < 200):
|
||||
line.text = text_section
|
||||
line.start_time = start_time
|
||||
line.end_time = end_time
|
||||
do_break = True
|
||||
|
||||
if do_break:
|
||||
logger.debug("text section %d -> %d (%d): %s",
|
||||
line.start_time, line.end_time,
|
||||
len(line.text), repr(line.text))
|
||||
lines.append(line)
|
||||
line = CaptionLine()
|
||||
line_start = next_break
|
||||
else:
|
||||
line.text = text_section
|
||||
line.start_time = start_time
|
||||
line.end_time = end_time
|
||||
|
||||
prev_break = next_break
|
||||
next_break = break_iter.following(prev_break)
|
||||
|
||||
return lines
|
||||
|
||||
def write_webvtt(self, f):
|
||||
# Write magic
|
||||
f.write("WEBVTT\n\n".encode('utf-8'))
|
||||
|
||||
lines = self.split_lines()
|
||||
for i, line in enumerate(lines):
|
||||
# Don't generate a cue for empty lines
|
||||
if len(line.text) == 0:
|
||||
continue
|
||||
|
||||
start_time = line.start_time
|
||||
end_time = line.end_time
|
||||
|
||||
if i + 1 < len(lines):
|
||||
next_start_time = lines[i + 1].start_time
|
||||
# If the next line is close after the current line, make the
|
||||
# timestamps continuous so the subtitle doesn't "blink"
|
||||
if next_start_time - end_time < 1000:
|
||||
end_time = next_start_time
|
||||
|
||||
# Apply some duration cleanup heuristics to give some reasonable
|
||||
# line durations
|
||||
duration = end_time - start_time
|
||||
# Make lines go away if they've been showing for >16 seconds
|
||||
if duration > 16000:
|
||||
duration = 16000
|
||||
# A minimum per-character time for display (up to 3.2s for 32char)
|
||||
if duration < 100 * len(line.text):
|
||||
duration = 100 * len(line.text)
|
||||
# Never show a caption (even a short one) for less than 1s
|
||||
if duration < 1000:
|
||||
duration = 1000
|
||||
|
||||
end_time = start_time + duration
|
||||
|
||||
f.write("{} --> {}\n".format(
|
||||
webvtt_timestamp(start_time),
|
||||
webvtt_timestamp(end_time)
|
||||
).encode('utf-8'))
|
||||
f.write(html.escape(line.text, quote=False).encode('utf-8'))
|
||||
f.write("\n\n".encode('utf-8'))
|
||||
|
||||
def caption_desc(self):
|
||||
locale = Locale(self.locale)
|
||||
return {
|
||||
"locale": self.locale,
|
||||
"localeName": locale.getDisplayName(locale)
|
||||
}
|
||||
|
||||
|
||||
def parse_record_status(event, element):
|
||||
userId = element.find('userId')
|
||||
status = element.find('status')
|
||||
|
||||
event['name'] = 'record_status'
|
||||
event['user_id'] = userId.text
|
||||
event['status'] = (status.text == 'true')
|
||||
|
||||
def parse_caption_edit(event, element):
|
||||
locale = element.find('locale')
|
||||
text = element.find('text')
|
||||
startIndex = element.find('startIndex')
|
||||
endIndex = element.find('endIndex')
|
||||
localeCode = element.find('localeCode')
|
||||
|
||||
event['name'] = 'edit_caption_history'
|
||||
event['locale_name'] = locale.text
|
||||
if localeCode is not None:
|
||||
event['locale'] = localeCode.text
|
||||
else:
|
||||
# Fallback for missing 'localeCode'
|
||||
event['locale'] = "en"
|
||||
if text.text is None:
|
||||
event['text'] = list()
|
||||
else:
|
||||
event['text'] = list(text.text)
|
||||
event['start_index'] = int(startIndex.text)
|
||||
event['end_index'] = int(endIndex.text)
|
||||
|
||||
|
||||
def parse_events(directory="."):
|
||||
start_time = None
|
||||
have_record_events = False
|
||||
events = deque()
|
||||
|
||||
with open("{}/events.xml".format(directory), "rb") as f:
|
||||
for _, element in etree.iterparse(f, tag="event"):
|
||||
try:
|
||||
event = {}
|
||||
|
||||
# Convert timestamps to be in seconds from recording start
|
||||
timestamp = int(element.attrib['timestamp'])
|
||||
if not start_time:
|
||||
start_time = timestamp
|
||||
timestamp = timestamp - start_time
|
||||
|
||||
# Only need events from these modules
|
||||
if not element.attrib['module'] in ['CAPTION','PARTICIPANT']:
|
||||
continue
|
||||
|
||||
event['name'] = name = element.attrib['eventname']
|
||||
event['timestamp'] = timestamp
|
||||
|
||||
if name == 'RecordStatusEvent':
|
||||
parse_record_status(event, element)
|
||||
have_record_events = True
|
||||
elif name == 'EditCaptionHistoryEvent':
|
||||
parse_caption_edit(event, element)
|
||||
else:
|
||||
logger.debug("Unhandled event: %s", name)
|
||||
continue
|
||||
|
||||
events.append(event)
|
||||
finally:
|
||||
element.clear()
|
||||
|
||||
if not have_record_events:
|
||||
# Add a fake record start event to the events list
|
||||
event = {
|
||||
'name': 'record_status',
|
||||
'user_id': None,
|
||||
'timestamp': 0,
|
||||
'status': True
|
||||
}
|
||||
events.appendleft(event)
|
||||
|
||||
return events
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate WebVTT files from BigBlueButton captions",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument("-i", "--input", metavar="PATH",
|
||||
help="input directory with events.xml file",
|
||||
default=os.curdir)
|
||||
parser.add_argument("-o", "--output", metavar="PATH",
|
||||
help="output directory",
|
||||
default=os.curdir)
|
||||
args = parser.parse_args()
|
||||
|
||||
rawdir = args.input
|
||||
outputdir = args.output
|
||||
|
||||
logger.info("Reading recording events file")
|
||||
events = parse_events(rawdir)
|
||||
|
||||
logger.info("Generating caption data from recording events")
|
||||
captions = Caption.from_events(events)
|
||||
for locale, caption in captions.items():
|
||||
filename = os.path.join(outputdir, "caption_{}.vtt".format(locale))
|
||||
logger.info("Writing captions for locale %s to %s", locale, filename)
|
||||
with open(filename, "wb") as f:
|
||||
caption.write_webvtt(f)
|
||||
|
||||
filename = os.path.join(outputdir, "captions.json")
|
||||
logger.info("Writing captions index file to %s", filename)
|
||||
|
||||
caption_descs = [ caption.caption_desc() for caption in captions.values() ]
|
||||
with open(filename, "w") as f:
|
||||
json.dump(caption_descs, f)
|
@ -271,11 +271,6 @@
|
||||
acorn.$seek.slider('value', currenttime);
|
||||
}
|
||||
}
|
||||
|
||||
// If captions are active, update them
|
||||
if(captionsActive) {
|
||||
updateCaption();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@ -692,33 +687,14 @@
|
||||
var captionRadioName = 'acornCaptions' + uniqueID();
|
||||
|
||||
var captionOff = function() {
|
||||
captions = '';
|
||||
acorn.$caption.hide();
|
||||
activeCaptions = false;
|
||||
|
||||
acorn.$transcriptBtn.removeClass(transcriptBtnActiveClass).hide();
|
||||
acorn.$transcript.hide();
|
||||
for (var i = 0; i < acorn.$track.length; i++) {
|
||||
var track = acorn.$track[i];
|
||||
track.track.mode = "disabled";
|
||||
}
|
||||
|
||||
acorn.$captionBtn.removeClass(captionBtnActiveClass);
|
||||
};
|
||||
|
||||
/*
|
||||
* Update caption based on "currentTime"
|
||||
* Borrowed and adapted from Bruce Lawson's “Accessible HTML5 Video with JavaScripted captions”
|
||||
* http://dev.opera.com/articles/view/accessible-html5-video-with-javascripted-captions/
|
||||
*/
|
||||
var updateCaption = function() {
|
||||
var now = acorn.$self[0].currentTime; // how soon is now?
|
||||
var text = "";
|
||||
for (var i = 0; i < captions.length; i++) {
|
||||
if (now >= captions[i].start && now <= captions[i].end) {
|
||||
text = captions[i].content; // yes? then load it into a variable called text
|
||||
break;
|
||||
}
|
||||
}
|
||||
acorn.$caption.html(text); // and put contents of text into caption div
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the Caption Selector
|
||||
* Used when multiple <track>s are present
|
||||
@ -792,54 +768,33 @@
|
||||
* Takes the url as a parameter
|
||||
*/
|
||||
var loadCaption = function(url) {
|
||||
// add a loading class to the Caption Button when starting to load the caption
|
||||
acorn.$captionBtn.addClass(captionBtnLoadingClass);
|
||||
// make an AJAX request to load the file
|
||||
$.ajax({
|
||||
url: url,
|
||||
success: function(data) {
|
||||
/*
|
||||
* On success use a SRT parser on the loaded data
|
||||
* Using JavaScript SRT parser by Silvia Pfeiffer <silvia@siliva-pfeiffer.de>
|
||||
* parseSrt included at the end of this file
|
||||
*/
|
||||
captions = parseSrt(data);
|
||||
|
||||
// Iterate through the available captions, and disable all but the selected one
|
||||
for (var i = 0; i < acorn.$track.length; i++) {
|
||||
var track = acorn.$track[i];
|
||||
if (track.getAttribute('src') == url) {
|
||||
track.track.mode = "showing";
|
||||
|
||||
// TODO transcript markup?
|
||||
// show the Transcript Button
|
||||
acorn.$transcriptBtn.show();
|
||||
//acorn.$transcriptBtn.show();
|
||||
|
||||
/*
|
||||
* Generate the markup for the transcript
|
||||
* Markup based on Bruce Lawson's “Accessible HTML5 Video with JavaScripted captions”
|
||||
* http://dev.opera.com/articles/view/accessible-html5-video-with-javascripted-captions/
|
||||
*/
|
||||
var transcriptText = '';
|
||||
$(captions).each(function() {
|
||||
transcriptText += '<span data-begin="' + parseInt(this.start, 10) + '" data-end=' + parseInt(this.end, 10) + '>' + this.content.replace("'","") + '</span>';
|
||||
});
|
||||
//var transcriptText = '';
|
||||
//$(captions).each(function() {
|
||||
// transcriptText += '<span data-begin="' + parseInt(this.start, 10) + '" data-end=' + parseInt(this.end, 10) + '>' + this.content.replace("'","") + '</span>';
|
||||
//});
|
||||
// append the generated markup
|
||||
acorn.$transcript.html(transcriptText);
|
||||
|
||||
// show caption
|
||||
acorn.$caption.show();
|
||||
captionsActive = true;
|
||||
|
||||
// in case the media is paused and timeUpdate is not triggered, trigger it
|
||||
if(acorn.$self.prop('paused')) {
|
||||
updateCaption();
|
||||
}
|
||||
|
||||
acorn.$captionBtn.addClass(captionBtnActiveClass).removeClass(captionBtnLoadingClass);
|
||||
},
|
||||
error: function() {
|
||||
// if an error occurs while loading the caption, turn captions off
|
||||
captionOff();
|
||||
// if a console is available, log error
|
||||
if(console) {
|
||||
console.log('Error loading captions');
|
||||
}
|
||||
//acorn.$transcript.html(transcriptText);
|
||||
} else {
|
||||
track.track.mode = "disabled";
|
||||
}
|
||||
});
|
||||
}
|
||||
captionsActive = true;
|
||||
acorn.$captionBtn.addClass(captionBtnActiveClass);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -858,6 +813,11 @@
|
||||
* Caption loading and initialization
|
||||
*/
|
||||
var initCaption = function() {
|
||||
// Check if we have browser support for captions
|
||||
if (typeof(TextTrack) === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
// get all <track> elements
|
||||
acorn.$track = $('track', acorn.$self);
|
||||
|
||||
@ -919,7 +879,6 @@
|
||||
} else {
|
||||
loadCaption(tracksrc);
|
||||
}
|
||||
$(this).toggleClass(captionBtnActiveClass);
|
||||
});
|
||||
|
||||
// load default caption if captionsOn is true
|
||||
@ -1002,66 +961,3 @@
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
|
||||
/*
|
||||
* parseSrt function
|
||||
* JavaScript SRT parser by Silvia Pfeiffer <silvia@siliva-pfeiffer.de>
|
||||
* http://silvia-pfeiffer.de/
|
||||
*
|
||||
* Tri-licensed under MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Silvia Pfeiffer <silvia@siliva-pfeiffer.de>
|
||||
*
|
||||
*
|
||||
*/
|
||||
function parseSrt(data) {
|
||||
var srt = data.replace(/\r+/g, ''); // remove dos newlines
|
||||
srt = srt.replace(/^\s+|\s+$/g, ''); // trim white space start and end
|
||||
srt = srt.replace(/<[a-zA-Z\/][^>]*>/g, ''); // remove all html tags for security reasons
|
||||
|
||||
// get captions
|
||||
var captions = [];
|
||||
var caplist = srt.split('\n\n');
|
||||
for (var i = 0; i < caplist.length; i=i+1) {
|
||||
var caption = "";
|
||||
var content, start, end, s;
|
||||
caption = caplist[i];
|
||||
s = caption.split(/\n/);
|
||||
if (s[0].match(/^\d+$/) && s[1].match(/\d+:\d+:\d+/)) {
|
||||
// ignore caption number in s[0]
|
||||
// parse time string
|
||||
var m = s[1].match(/(\d+):(\d+):(\d+)(?:,(\d+))?\s*--?>\s*(\d+):(\d+):(\d+)(?:,(\d+))?/);
|
||||
if (m) {
|
||||
start =
|
||||
(parseInt(m[1], 10) * 60 * 60) +
|
||||
(parseInt(m[2], 10) * 60) +
|
||||
(parseInt(m[3], 10)) +
|
||||
(parseInt(m[4], 10) / 1000);
|
||||
end =
|
||||
(parseInt(m[5], 10) * 60 * 60) +
|
||||
(parseInt(m[6], 10) * 60) +
|
||||
(parseInt(m[7], 10)) +
|
||||
(parseInt(m[8], 10) / 1000);
|
||||
} else {
|
||||
// Unrecognized timestring
|
||||
continue;
|
||||
}
|
||||
// concatenate text lines to html text
|
||||
content = s.slice(2).join("<br>");
|
||||
} else {
|
||||
// file format error or comment lines
|
||||
continue;
|
||||
}
|
||||
captions.push({start: start, end: end, content: content});
|
||||
}
|
||||
|
||||
return captions;
|
||||
}
|
||||
|
@ -310,6 +310,25 @@ load_video = function(){
|
||||
webmsource.setAttribute('type','video/webm; codecs="vp8.0, vorbis"');
|
||||
video.appendChild(webmsource);
|
||||
|
||||
// Try to load the captions
|
||||
// TODO this all should be done asynchronously...
|
||||
var capReq = new XMLHttpRequest();
|
||||
capReq.open('GET', RECORDINGS + '/captions.json', /*async=*/false);
|
||||
capReq.send();
|
||||
if (capReq.status == 200) {
|
||||
console.log("==Loading closed captions");
|
||||
// With sync request, responseType should always be blank (=="text")
|
||||
var captions = JSON.parse(capReq.responseText);
|
||||
for (var i = 0; i < captions.length; i++) {
|
||||
var track = document.createElement("track");
|
||||
track.setAttribute('kind', 'captions');
|
||||
track.setAttribute('label', captions[i]['localeName']);
|
||||
track.setAttribute('srclang', captions[i]['locale']);
|
||||
track.setAttribute('src', RECORDINGS + '/caption_' + captions[i]['locale'] + '.vtt');
|
||||
video.appendChild(track);
|
||||
}
|
||||
}
|
||||
|
||||
/*var time_manager = Popcorn("#video");
|
||||
var pc_webcam = Popcorn("#webcam");
|
||||
time_manager.on( "timeupdate", function() {
|
||||
|
@ -182,6 +182,12 @@ if not FileTest.directory?(target_dir)
|
||||
BigBlueButton.process_multiple_videos(target_dir, temp_dir, meeting_id, width, height, presentation_props['audio_offset'], presentation_props['include_deskshare'])
|
||||
end
|
||||
|
||||
BigBlueButton.logger.info("Generating closed captions")
|
||||
ret = BigBlueButton.exec_ret('utils/gen_webvtt', '-i', raw_archive_dir, '-o', target_dir)
|
||||
if ret != 0
|
||||
raise "Generating closed caption files failed"
|
||||
end
|
||||
|
||||
process_done = File.new("#{recording_dir}/status/processed/#{meeting_id}-presentation.done", "w")
|
||||
process_done.write("Processed #{meeting_id}")
|
||||
process_done.close
|
||||
|
@ -960,6 +960,15 @@ begin
|
||||
BigBlueButton.logger.info("Copied audio.ogg file")
|
||||
end
|
||||
|
||||
if File.exist?("#{$process_dir}/captions.json")
|
||||
BigBlueButton.logger.info("Copying caption files")
|
||||
FileUtils.cp("#{$process_dir}/captions.json", package_dir)
|
||||
Dir.glob("#{$process_dir}/caption_*.vtt").each do |caption|
|
||||
BigBlueButton.logger.debug(caption)
|
||||
FileUtils.cp(caption, package_dir)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
processing_time = File.read("#{$process_dir}/processing_time")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user