Merge pull request #390 from pedrobmarin/merging-into-bbb-1.1
Remote tracking BBB master
This commit is contained in:
commit
ee099b8f0d
2
.gitignore
vendored
2
.gitignore
vendored
@ -30,3 +30,5 @@ bigbluebutton-web/target-eclipse*
|
|||||||
record-and-playback/.loadpath
|
record-and-playback/.loadpath
|
||||||
clients/flash/**/build
|
clients/flash/**/build
|
||||||
clients/flash/**/.gradle
|
clients/flash/**/.gradle
|
||||||
|
**/.idea/*
|
||||||
|
*.iml
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package org.bigbluebutton.core.pubsub.receivers;
|
package org.bigbluebutton.core.pubsub.receivers;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.bigbluebutton.common.messages.GetPresentationInfoMessage;
|
import org.bigbluebutton.common.messages.GetPresentationInfoMessage;
|
||||||
import org.bigbluebutton.common.messages.GetSlideInfoMessage;
|
import org.bigbluebutton.common.messages.GetSlideInfoMessage;
|
||||||
@ -15,19 +14,18 @@ import org.bigbluebutton.common.messages.SendCursorUpdateMessage;
|
|||||||
import org.bigbluebutton.common.messages.SendPageCountErrorMessage;
|
import org.bigbluebutton.common.messages.SendPageCountErrorMessage;
|
||||||
import org.bigbluebutton.common.messages.SendSlideGeneratedMessage;
|
import org.bigbluebutton.common.messages.SendSlideGeneratedMessage;
|
||||||
import org.bigbluebutton.common.messages.SharePresentationMessage;
|
import org.bigbluebutton.common.messages.SharePresentationMessage;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
|
|
||||||
import org.bigbluebutton.core.api.IBigBlueButtonInGW;
|
import org.bigbluebutton.core.api.IBigBlueButtonInGW;
|
||||||
|
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
public class PresentationMessageListener implements MessageHandler {
|
public class PresentationMessageListener implements MessageHandler {
|
||||||
|
|
||||||
public static final String OFFICE_DOC_CONVERSION_SUCCESS_KEY = "OFFICE_DOC_CONVERSION_SUCCESS";
|
public static final String OFFICE_DOC_CONVERSION_SUCCESS_KEY = "OFFICE_DOC_CONVERSION_SUCCESS";
|
||||||
public static final String OFFICE_DOC_CONVERSION_FAILED_KEY = "OFFICE_DOC_CONVERSION_FAILED";
|
public static final String OFFICE_DOC_CONVERSION_FAILED_KEY = "OFFICE_DOC_CONVERSION_FAILED";
|
||||||
|
public static final String OFFICE_DOC_CONVERSION_INVALID_KEY = "OFFICE_DOC_CONVERSION_INVALID";
|
||||||
public static final String SUPPORTED_DOCUMENT_KEY = "SUPPORTED_DOCUMENT";
|
public static final String SUPPORTED_DOCUMENT_KEY = "SUPPORTED_DOCUMENT";
|
||||||
public static final String UNSUPPORTED_DOCUMENT_KEY = "UNSUPPORTED_DOCUMENT";
|
public static final String UNSUPPORTED_DOCUMENT_KEY = "UNSUPPORTED_DOCUMENT";
|
||||||
public static final String PAGE_COUNT_FAILED_KEY = "PAGE_COUNT_FAILED";
|
public static final String PAGE_COUNT_FAILED_KEY = "PAGE_COUNT_FAILED";
|
||||||
@ -145,13 +143,14 @@ public class PresentationMessageListener implements MessageHandler {
|
|||||||
String conference = (String) map.get("conference");
|
String conference = (String) map.get("conference");
|
||||||
String messageKey = (String) map.get("messageKey");
|
String messageKey = (String) map.get("messageKey");
|
||||||
|
|
||||||
if (messageKey.equalsIgnoreCase(OFFICE_DOC_CONVERSION_SUCCESS_KEY) ||
|
if (messageKey.equalsIgnoreCase(OFFICE_DOC_CONVERSION_SUCCESS_KEY) ||
|
||||||
messageKey.equalsIgnoreCase(OFFICE_DOC_CONVERSION_FAILED_KEY) ||
|
messageKey.equalsIgnoreCase(OFFICE_DOC_CONVERSION_FAILED_KEY) ||
|
||||||
messageKey.equalsIgnoreCase(SUPPORTED_DOCUMENT_KEY) ||
|
messageKey.equalsIgnoreCase(OFFICE_DOC_CONVERSION_INVALID_KEY) ||
|
||||||
messageKey.equalsIgnoreCase(UNSUPPORTED_DOCUMENT_KEY) ||
|
messageKey.equalsIgnoreCase(SUPPORTED_DOCUMENT_KEY) ||
|
||||||
messageKey.equalsIgnoreCase(GENERATING_THUMBNAIL_KEY) ||
|
messageKey.equalsIgnoreCase(UNSUPPORTED_DOCUMENT_KEY) ||
|
||||||
messageKey.equalsIgnoreCase(GENERATED_THUMBNAIL_KEY) ||
|
messageKey.equalsIgnoreCase(GENERATING_THUMBNAIL_KEY) ||
|
||||||
messageKey.equalsIgnoreCase(PAGE_COUNT_FAILED_KEY)){
|
messageKey.equalsIgnoreCase(GENERATED_THUMBNAIL_KEY) ||
|
||||||
|
messageKey.equalsIgnoreCase(PAGE_COUNT_FAILED_KEY)){
|
||||||
|
|
||||||
sendConversionUpdate(messageKey, conference, code, presId, filename);
|
sendConversionUpdate(messageKey, conference, code, presId, filename);
|
||||||
} else if(messageKey.equalsIgnoreCase(PAGE_COUNT_EXCEEDED_KEY)){
|
} else if(messageKey.equalsIgnoreCase(PAGE_COUNT_EXCEEDED_KEY)){
|
||||||
|
@ -66,6 +66,7 @@ class BigBlueButtonInGW(
|
|||||||
msg.payload.durationInMinutes,
|
msg.payload.durationInMinutes,
|
||||||
msg.payload.autoStartRecording,
|
msg.payload.autoStartRecording,
|
||||||
msg.payload.allowStartStopRecording,
|
msg.payload.allowStartStopRecording,
|
||||||
|
msg.payload.webcamsOnlyForModerator,
|
||||||
msg.payload.moderatorPassword,
|
msg.payload.moderatorPassword,
|
||||||
msg.payload.viewerPassword,
|
msg.payload.viewerPassword,
|
||||||
msg.payload.createTime,
|
msg.payload.createTime,
|
||||||
|
@ -8,8 +8,8 @@ import java.util.concurrent.TimeUnit
|
|||||||
case object StopMeetingActor
|
case object StopMeetingActor
|
||||||
case class MeetingProperties(meetingID: String, externalMeetingID: String, parentMeetingID: String, meetingName: String,
|
case class MeetingProperties(meetingID: String, externalMeetingID: String, parentMeetingID: String, meetingName: String,
|
||||||
recorded: Boolean, voiceBridge: String, deskshareBridge: String, duration: Int,
|
recorded: Boolean, voiceBridge: String, deskshareBridge: String, duration: Int,
|
||||||
autoStartRecording: Boolean, allowStartStopRecording: Boolean, moderatorPass: String,
|
autoStartRecording: Boolean, allowStartStopRecording: Boolean, webcamsOnlyForModerator: Boolean,
|
||||||
viewerPass: String, createTime: Long, createDate: String,
|
moderatorPass: String, viewerPass: String, createTime: Long, createDate: String,
|
||||||
red5DeskShareIP: String, red5DeskShareApp: String, isBreakout: Boolean, sequence: Int, metadata: java.util.Map[String, String])
|
red5DeskShareIP: String, red5DeskShareApp: String, isBreakout: Boolean, sequence: Int, metadata: java.util.Map[String, String])
|
||||||
|
|
||||||
case class MeetingExtensionProp(maxExtensions: Int = 2, numExtensions: Int = 0, extendByMinutes: Int = 20,
|
case class MeetingExtensionProp(maxExtensions: Int = 2, numExtensions: Int = 0, extendByMinutes: Int = 20,
|
||||||
|
@ -12,8 +12,8 @@ object Role extends Enumeration {
|
|||||||
|
|
||||||
object Metadata extends Enumeration {
|
object Metadata extends Enumeration {
|
||||||
type Metadata = String
|
type Metadata = String
|
||||||
val INACTIVITY_DEADLINE = "mconf-live-inactivity-deadline"
|
val INACTIVITY_DEADLINE = "inactivity-deadline"
|
||||||
val INACTIVITY_TIMELEFT = "mconf-live-inactivity-timeleft"
|
val INACTIVITY_TIMELEFT = "inactivity-timeleft"
|
||||||
}
|
}
|
||||||
|
|
||||||
object GuestPolicy extends Enumeration {
|
object GuestPolicy extends Enumeration {
|
||||||
|
@ -88,8 +88,13 @@ trait PresentationApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def handleResizeAndMoveSlide(msg: ResizeAndMoveSlide) {
|
def handleResizeAndMoveSlide(msg: ResizeAndMoveSlide) {
|
||||||
val page = presModel.resizePage(msg.xOffset, msg.yOffset,
|
// Force coordinate that are out-of-bounds inside valid values
|
||||||
msg.widthRatio, msg.heightRatio);
|
val xOffset = if (msg.xOffset <= 0) msg.xOffset else 0
|
||||||
|
val yOffset = if (msg.yOffset <= 0) msg.yOffset else 0
|
||||||
|
val width = if (msg.widthRatio <= 100) msg.widthRatio else 100
|
||||||
|
val height = if (msg.heightRatio <= 100) msg.heightRatio else 100
|
||||||
|
|
||||||
|
val page = presModel.resizePage(xOffset, yOffset, width, height);
|
||||||
page foreach (p => outGW.send(new ResizeAndMoveSlideOutMsg(mProps.meetingID, mProps.recorded, p)))
|
page foreach (p => outGW.send(new ResizeAndMoveSlideOutMsg(mProps.meetingID, mProps.recorded, p)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ trait AppsTestFixtures {
|
|||||||
val durationInMinutes = 10
|
val durationInMinutes = 10
|
||||||
val autoStartRecording = false
|
val autoStartRecording = false
|
||||||
val allowStartStopRecording = false
|
val allowStartStopRecording = false
|
||||||
|
val webcamsOnlyForModerator = false;
|
||||||
val moderatorPassword = "modpass"
|
val moderatorPassword = "modpass"
|
||||||
val viewerPassword = "viewpass"
|
val viewerPassword = "viewpass"
|
||||||
val createTime = System.currentTimeMillis
|
val createTime = System.currentTimeMillis
|
||||||
@ -25,7 +26,7 @@ trait AppsTestFixtures {
|
|||||||
meetingName, record,
|
meetingName, record,
|
||||||
voiceConfId, deskshareConfId,
|
voiceConfId, deskshareConfId,
|
||||||
durationInMinutes,
|
durationInMinutes,
|
||||||
autoStartRecording, allowStartStopRecording,
|
autoStartRecording, allowStartStopRecording, webcamsOnlyForModerator,
|
||||||
moderatorPassword, viewerPassword,
|
moderatorPassword, viewerPassword,
|
||||||
createTime, createDate, red5DeskShareIP, red5DeskShareApp,
|
createTime, createDate, red5DeskShareIP, red5DeskShareApp,
|
||||||
isBreakout, sequence)
|
isBreakout, sequence)
|
||||||
|
@ -242,10 +242,8 @@ public String getJoinURL(String username, String meetingID, String record, Strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Create a meeting and return a URL to join it as moderator. This is used for the API demos.
|
// Create a meeting and return a URL to join it as attendee. This is used for the API demos.
|
||||||
//
|
//
|
||||||
// Passed
|
// Passed
|
||||||
// - username
|
// - username
|
||||||
@ -253,19 +251,16 @@ public String getJoinURL(String username, String meetingID, String record, Strin
|
|||||||
// - record ["true", "false"]
|
// - record ["true", "false"]
|
||||||
// - welcome message (null causes BigBlueButton to use the default welcome message
|
// - welcome message (null causes BigBlueButton to use the default welcome message
|
||||||
// - metadata (passed through when record="true"
|
// - metadata (passed through when record="true"
|
||||||
// - xml (used for pre-upload of slides)_
|
// - xml (used for pre-upload of slides)
|
||||||
|
// - isModerator [true, false]
|
||||||
//
|
//
|
||||||
// Returned
|
// Returned
|
||||||
// - valid join URL using the username
|
// - valid join URL using the username
|
||||||
//
|
//
|
||||||
// Note this meeting will use username for meetingID
|
|
||||||
//
|
|
||||||
|
|
||||||
// VERSION ADJUSTED TO THE NEEDS OF THE HTML5 CLIENT
|
// VERSION ADJUSTED TO THE NEEDS OF THE HTML5 CLIENT
|
||||||
// -redirect=false //so that we get xml returned instead of being redirected to the meeting
|
// -redirect=false //so that we get xml returned instead of being redirected to the meeting
|
||||||
// -password=ap //at this stage the html5 client is viewer only (Feb 2015)
|
public String getJoinURLHTML5(String username, String meetingID, String record, String welcome, Map<String, String> metadata, String xml, boolean isModerator) {
|
||||||
|
|
||||||
public String getJoinURLHTML5(String username, String meetingID, String record, String welcome, Map<String, String> metadata, String xml) {
|
|
||||||
|
|
||||||
String base_url_create = BigBlueButtonURL + "api/create?";
|
String base_url_create = BigBlueButtonURL + "api/create?";
|
||||||
String base_url_join = BigBlueButtonURL + "api/join?";
|
String base_url_join = BigBlueButtonURL + "api/join?";
|
||||||
@ -280,6 +275,13 @@ public String getJoinURLHTML5(String username, String meetingID, String record,
|
|||||||
xml_param = xml;
|
xml_param = xml;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String defaultModeratorPW = "mp";
|
||||||
|
String defaultAttendeePW = "ap";
|
||||||
|
String html5UserPassword = defaultAttendeePW; // default html5 user to attendee
|
||||||
|
if (isModerator) {
|
||||||
|
html5UserPassword = defaultModeratorPW;
|
||||||
|
}
|
||||||
|
|
||||||
Random random = new Random();
|
Random random = new Random();
|
||||||
String voiceBridge_param = "&voiceBridge=" + (70000 + random.nextInt(9999));
|
String voiceBridge_param = "&voiceBridge=" + (70000 + random.nextInt(9999));
|
||||||
|
|
||||||
@ -298,8 +300,11 @@ public String getJoinURLHTML5(String username, String meetingID, String record,
|
|||||||
//
|
//
|
||||||
|
|
||||||
String create_parameters = "name=" + urlEncode(meetingID)
|
String create_parameters = "name=" + urlEncode(meetingID)
|
||||||
+ "&meetingID=" + urlEncode(meetingID) + welcome_param + voiceBridge_param
|
+ "&meetingID=" + urlEncode(meetingID)
|
||||||
+ "&attendeePW=ap&moderatorPW=mp"
|
+ welcome_param
|
||||||
|
+ voiceBridge_param
|
||||||
|
+ "&attendeePW=" + defaultAttendeePW
|
||||||
|
+ "&moderatorPW=" + defaultModeratorPW
|
||||||
+ "&record=" + record + getMetaData( metadata );
|
+ "&record=" + record + getMetaData( metadata );
|
||||||
|
|
||||||
|
|
||||||
@ -322,8 +327,11 @@ public String getJoinURLHTML5(String username, String meetingID, String record,
|
|||||||
// Looks good, now return a URL to join that meeting
|
// Looks good, now return a URL to join that meeting
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// Note that REDIRECT=FALSE -- we will use the url to extract meetingID, userID, authToken
|
||||||
|
// and will pass them to the joining url for the html5 client (different format)
|
||||||
|
// Also we set PASSWORD=AP FOR ATTENDEE
|
||||||
String join_parameters = "meetingID=" + urlEncode(meetingID)
|
String join_parameters = "meetingID=" + urlEncode(meetingID)
|
||||||
+ "&fullName=" + urlEncode(username) + "&redirect=false&password=ap"; //REDIRECT=FALSE (HTML5 CLIENT) PASSWORD=AP FOR ATTENDEE
|
+ "&fullName=" + urlEncode(username) + "&redirect=false&password=" + html5UserPassword;
|
||||||
|
|
||||||
return base_url_join + join_parameters + "&checksum="
|
return base_url_join + join_parameters + "&checksum="
|
||||||
+ checksum("join" + join_parameters + salt);
|
+ checksum("join" + join_parameters + salt);
|
||||||
|
@ -1,173 +0,0 @@
|
|||||||
<!--
|
|
||||||
|
|
||||||
BigBlueButton - http://www.bigbluebutton.org
|
|
||||||
|
|
||||||
Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
|
|
||||||
|
|
||||||
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, If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Author: Fred Dixon <ffdixon@bigbluebutton.org>
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
<%@ page language="java" contentType="text/html; charset=UTF-8"
|
|
||||||
pageEncoding="UTF-8"%>
|
|
||||||
<%
|
|
||||||
request.setCharacterEncoding("UTF-8");
|
|
||||||
response.setCharacterEncoding("UTF-8");
|
|
||||||
%>
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
||||||
<title>Record (Matterhorn)</title>
|
|
||||||
<style type="text/css">
|
|
||||||
#formcreate{
|
|
||||||
width:500px;
|
|
||||||
height:500px;
|
|
||||||
}
|
|
||||||
#formcreate ul{
|
|
||||||
list-style:none;
|
|
||||||
}
|
|
||||||
#formcreate li{
|
|
||||||
display:block;
|
|
||||||
width:400px;
|
|
||||||
margin-bottom:5px;
|
|
||||||
}
|
|
||||||
#formcreate label{
|
|
||||||
display:block;
|
|
||||||
float:left;
|
|
||||||
width:150px;
|
|
||||||
text-align:right;
|
|
||||||
}
|
|
||||||
#labdescription{
|
|
||||||
vertical-align:top;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
|
|
||||||
<%@ include file="bbb_api.jsp"%>
|
|
||||||
<%@ include file="demo_header.jsp"%>
|
|
||||||
|
|
||||||
<%
|
|
||||||
if (request.getParameterMap().isEmpty()) {
|
|
||||||
//
|
|
||||||
// Assume we want to create a meeting
|
|
||||||
//
|
|
||||||
%>
|
|
||||||
<h2>Record (Matterhorn)</h2>
|
|
||||||
|
|
||||||
<form id="formcreate" name="formcreate" method="get" action="">
|
|
||||||
<fieldset>
|
|
||||||
<legend>Meeting Information</legend>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<label for="confname">Meeting Name:</label>
|
|
||||||
<input id="confname" autofocus required name="confname" type="text" />
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for="username1">Your Name:</label>
|
|
||||||
<input id="username1" required name="username1" type="text" />
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</fieldset>
|
|
||||||
<fieldset>
|
|
||||||
<legend>Metadata Details</legend>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<label for="meta_title">Title:</label>
|
|
||||||
<input type="text" id="meta_title" name="meta_title" />
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for="meta_subject">Subject:</label>
|
|
||||||
<input type="text" id="meta_subject" name="meta_subject" />
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label id="labdescription" for="meta_description">Description:</label>
|
|
||||||
<textarea id="meta_description" name="meta_description" cols="17" rows="3"></textarea>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for="meta_creator">Creator:</label>
|
|
||||||
<input type="text" id="meta_creator" name="meta_creator" />
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for="meta_contributor">Contributor:</label>
|
|
||||||
<input type="text" id="meta_contributor" name="meta_contributor" />
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for="meta_language">Language:</label>
|
|
||||||
<input type="text" id="meta_language" name="meta_language" />
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for="meta_identifier">Identifier:</label>
|
|
||||||
<input type="text" id="meta_identifier" name="meta_identifier" />
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</fieldset>
|
|
||||||
<input type="submit" value="Create" >
|
|
||||||
<input type="hidden" name="action" value="create" />
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<%
|
|
||||||
} else if (request.getParameter("action").equals("create")) {
|
|
||||||
|
|
||||||
String confname = request.getParameter("confname");
|
|
||||||
String username = request.getParameter("username1");
|
|
||||||
|
|
||||||
//metadata
|
|
||||||
Map<String,String> metadata=new HashMap<String,String>();
|
|
||||||
|
|
||||||
metadata.put("title",request.getParameter("meta_title"));
|
|
||||||
metadata.put("subject",request.getParameter("meta_subject"));
|
|
||||||
metadata.put("description",request.getParameter("meta_description"));
|
|
||||||
metadata.put("creator",request.getParameter("meta_creator"));
|
|
||||||
metadata.put("contributor",request.getParameter("meta_contributor"));
|
|
||||||
metadata.put("language",request.getParameter("meta_language"));
|
|
||||||
metadata.put("identifier",request.getParameter("meta_identifier"));
|
|
||||||
|
|
||||||
//
|
|
||||||
// This is the URL for to join the meeting as moderator
|
|
||||||
//
|
|
||||||
String url = BigBlueButtonURL.replace("bigbluebutton/","demo/");
|
|
||||||
String preUploadPDF = "<?xml version='1.0' encoding='UTF-8'?><modules><module name='presentation'><document url='"+url+"pdfs/matterhorn.pdf'/></module></modules>";
|
|
||||||
String joinURL = getJoinURL(username, confname, "true", null, metadata, preUploadPDF);
|
|
||||||
|
|
||||||
if (joinURL.startsWith("http://") || joinURL.startsWith("https://")) {
|
|
||||||
%>
|
|
||||||
|
|
||||||
<script language="javascript" type="text/javascript">
|
|
||||||
window.location.href="<%=joinURL%>";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<%
|
|
||||||
} else {
|
|
||||||
%>
|
|
||||||
|
|
||||||
Error: getJoinURL() failed
|
|
||||||
<p/>
|
|
||||||
<%=joinURL %>
|
|
||||||
|
|
||||||
<%
|
|
||||||
}
|
|
||||||
}
|
|
||||||
%>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
See: <a href="http://code.google.com/p/bigbluebutton/wiki/MatterhornIntegration">Matterhorn Integration</a>
|
|
||||||
|
|
||||||
<%@ include file="demo_footer.jsp"%>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -35,9 +35,11 @@ Author: Fred Dixon <ffdixon@bigbluebutton.org>
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
<p>You must have the BigBlueButton HTML5 client installed to use this API demo.</p>
|
||||||
|
|
||||||
<%@ include file="bbb_api.jsp"%>
|
<%@ include file="bbb_api.jsp"%>
|
||||||
|
|
||||||
<%
|
<%
|
||||||
if (request.getParameterMap().isEmpty()) {
|
if (request.getParameterMap().isEmpty()) {
|
||||||
//
|
//
|
||||||
// Assume we want to create a meeting
|
// Assume we want to create a meeting
|
||||||
@ -47,29 +49,36 @@ if (request.getParameterMap().isEmpty()) {
|
|||||||
|
|
||||||
<h2>Join Meeting via HTML5 Client</h2>
|
<h2>Join Meeting via HTML5 Client</h2>
|
||||||
|
|
||||||
<FORM NAME="form1" METHOD="GET">
|
<FORM NAME="form1" METHOD="GET">
|
||||||
<table cellpadding="5" cellspacing="5" style="width: 400px; ">
|
<table cellpadding="5" cellspacing="5" style="width: 400px; ">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td> </td>
|
||||||
</td>
|
<td style="text-align: right; ">Full Name:</td>
|
||||||
<td style="text-align: right; ">
|
<td style="width: 5px; "> </td>
|
||||||
Full Name:</td>
|
<td style="text-align: left "><input type="text" autofocus required name="username" /></td>
|
||||||
<td style="width: 5px; ">
|
|
||||||
</td>
|
|
||||||
<td style="text-align: left ">
|
|
||||||
<input type="text" autofocus required name="username" /></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td> </td>
|
||||||
|
<td style="text-align: right; ">Meeting Name:</td>
|
||||||
|
<td style="width: 5px; "> </td>
|
||||||
|
<td style="text-align: left "><input type="text" required name="meetingname" value="Demo Meeting" /></td>
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td> </td>
|
||||||
|
<td style="text-align: right; ">Moderator Role:</td>
|
||||||
|
<td style="width: 5px; "> </td>
|
||||||
|
<td style="text-align: left "><input type=checkbox name=isModerator value="true"></td>
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td> </td>
|
||||||
|
<td> </td>
|
||||||
|
<td> </td>
|
||||||
|
<td><input type="submit" value="Join" /></td>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="submit" value="Join" /></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<INPUT TYPE=hidden NAME=action VALUE="create">
|
<INPUT TYPE=hidden NAME=action VALUE="create">
|
||||||
@ -84,10 +93,10 @@ if (request.getParameterMap().isEmpty()) {
|
|||||||
//
|
//
|
||||||
|
|
||||||
String username = request.getParameter("username");
|
String username = request.getParameter("username");
|
||||||
String url = BigBlueButtonURL.replace("bigbluebutton/","demo/");
|
String meetingname = request.getParameter("meetingname");
|
||||||
// String preUploadPDF = "<?xml version='1.0' encoding='UTF-8'?><modules><module name='presentation'><document url='"+url+"pdfs/sample.pdf'/></module></modules>";
|
boolean isModerator = Boolean.parseBoolean(request.getParameter("isModerator"));
|
||||||
|
|
||||||
String joinURL = getJoinURLHTML5(request.getParameter("username"), "Demo Meeting", "false", null, null, null);
|
String joinURL = getJoinURLHTML5(username, meetingname, "false", null, null, null, isModerator);
|
||||||
Document doc = null;
|
Document doc = null;
|
||||||
doc = parseXml(getURL(joinURL));
|
doc = parseXml(getURL(joinURL));
|
||||||
|
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
<img src="images/bbb_banner.jpg" /><br>
|
<img src="images/bbb_banner.jpg" /><br>
|
||||||
<a href="demo1.jsp">Join</a> |
|
<a href="demo1.jsp">Join</a> |
|
||||||
<a href="demo2.jsp">Join Selected</a> |
|
<a href="demo2.jsp">Join Selected</a> |
|
||||||
<a href="demo3.jsp">Join Password</a>
|
<a href="demo3.jsp">Join Password</a>
|
||||||
|
|
||||||
<a href="demo7.jsp">Join & Upload</a> |
|
<a href="demo7.jsp">Join & Upload</a> |
|
||||||
<a href="demo8.jsp">Join & Upload</a> (URL)
|
<a href="demo8.jsp">Join & Upload</a> (URL)
|
||||||
|
|
||||||
<a href="demo10.jsp">Record</a> |
|
<a href="demo10.jsp">Record</a> |
|
||||||
<a href="demo6.jsp">Record</a> (Matterhorn)
|
|
||||||
|
|
||||||
<a href="create.jsp">Create</a>
|
<a href="create.jsp">Create</a>
|
||||||
|
|
||||||
@ -15,12 +14,9 @@
|
|||||||
|
|
||||||
<a href="demo4.jsp">Activity Monitor</a>
|
<a href="demo4.jsp">Activity Monitor</a>
|
||||||
|
|
||||||
<a href="demo_mozilla_persona.jsp">Login with Persona</a>
|
|
||||||
|
|
||||||
<a href="demo_openid.jsp">Login with Openid</a>
|
|
||||||
|
|
||||||
<a href="demo11.jsp">Javascript API</a>
|
<a href="demo11.jsp">Javascript API</a>
|
||||||
|
|
||||||
<a href="mobile.jsp">Mobile Demo</a>
|
<a href="mobile.jsp">Mobile Demo</a>
|
||||||
|
|
||||||
<a href="demoHTML5.jsp">HTML5 Client Demo</a>
|
<a href="demoHTML5.jsp">HTML5 Client Demo</a>
|
||||||
|
|
||||||
|
@ -1,169 +0,0 @@
|
|||||||
<!--
|
|
||||||
|
|
||||||
BigBlueButton - http://www.bigbluebutton.org
|
|
||||||
|
|
||||||
Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
|
|
||||||
|
|
||||||
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, If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Author: Marcos Calderon <mcmarkos86@gmail.com>
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
<%@ page language="java" contentType="text/html; charset=UTF-8"
|
|
||||||
pageEncoding="UTF-8"%>
|
|
||||||
<%
|
|
||||||
request.setCharacterEncoding("UTF-8");
|
|
||||||
response.setCharacterEncoding("UTF-8");
|
|
||||||
%>
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
||||||
<title>Join Demo Meeting using Mozilla Persona</title>
|
|
||||||
<script src="https://login.persona.org/include.js" type="text/javascript"></script>
|
|
||||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<%@ include file="bbb_api.jsp"%>
|
|
||||||
<%@ page import="com.google.gson.Gson"%>
|
|
||||||
<%@ page import="com.google.gson.reflect.TypeToken"%>
|
|
||||||
|
|
||||||
<%
|
|
||||||
if (request.getParameterMap().isEmpty()) {
|
|
||||||
//
|
|
||||||
// Assume we want to create a meeting
|
|
||||||
//
|
|
||||||
%>
|
|
||||||
<%@ include file="demo_header.jsp"%>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
//browserid
|
|
||||||
$(function() {
|
|
||||||
$('#browserid').click(function() {
|
|
||||||
navigator.id.get(gotAssertion);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function gotAssertion(assertion) {
|
|
||||||
if (assertion) {
|
|
||||||
var assertion_field = document.getElementById("assertion-field");
|
|
||||||
assertion_field.value = assertion;
|
|
||||||
var login_form = document.getElementById("form1");
|
|
||||||
login_form.submit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function loggedIn(res){
|
|
||||||
alert(res.email);
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<h2>Join Demo Meeting using BrowserID (<a href="http://mozilla.org/persona/">Mozilla Persona</a>)</h2>
|
|
||||||
|
|
||||||
|
|
||||||
<FORM id="form1" NAME="form1" METHOD="GET">
|
|
||||||
<table cellpadding="5" cellspacing="5" style="width: 400px; ">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
</td>
|
|
||||||
<td style="text-align: left ">
|
|
||||||
<a href="#" id="browserid" title="Sign-in with BrowserID">
|
|
||||||
<img src="https://browserid.org/i/sign_in_blue.png" alt="Sign in">
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<INPUT TYPE=hidden NAME=action VALUE="create">
|
|
||||||
<input type="hidden" name="assertion" id="assertion-field" />
|
|
||||||
</FORM>
|
|
||||||
|
|
||||||
|
|
||||||
<%
|
|
||||||
} else if (request.getParameter("action").equals("create")) {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Got an action=create
|
|
||||||
//
|
|
||||||
|
|
||||||
String url = BigBlueButtonURL.replace("bigbluebutton/","demo/");
|
|
||||||
String joinURL = "";
|
|
||||||
|
|
||||||
try{
|
|
||||||
|
|
||||||
String data = URLEncoder.encode("assertion", "UTF-8") + "=" + URLEncoder.encode(request.getParameter("assertion"), "UTF-8");
|
|
||||||
data += "&" + URLEncoder.encode("audience", "UTF-8") + "=" + URLEncoder.encode(BigBlueButtonURL.replace("/bigbluebutton/",""),"UTF-8");
|
|
||||||
URL urlBrowserID = new URL("https://verifier.login.persona.org/verify");
|
|
||||||
|
|
||||||
|
|
||||||
URLConnection conn = urlBrowserID.openConnection();
|
|
||||||
((HttpURLConnection)conn).setRequestMethod("POST");
|
|
||||||
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
|
||||||
conn.setDoOutput(true);
|
|
||||||
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
|
|
||||||
wr.write(data);
|
|
||||||
wr.flush();
|
|
||||||
|
|
||||||
// Get the response
|
|
||||||
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
|
||||||
String jsonResp = "";
|
|
||||||
String line;
|
|
||||||
while ((line = rd.readLine()) != null) {
|
|
||||||
jsonResp += line;
|
|
||||||
}
|
|
||||||
wr.close();
|
|
||||||
rd.close();
|
|
||||||
|
|
||||||
Gson gson = new Gson();
|
|
||||||
HashMap<String,String> map = gson.fromJson(jsonResp, new TypeToken<Map<String, String>>() {}.getType());
|
|
||||||
if(map.get("status").equalsIgnoreCase("okay")){
|
|
||||||
joinURL = getJoinURL(map.get("email"), "Demo Meeting", "false", null, null, null);
|
|
||||||
}
|
|
||||||
}catch(Exception e){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// String preUploadPDF = "<?xml version='1.0' encoding='UTF-8'?><modules><module name='presentation'><document url='"+url+"pdfs/sample.pdf'/></module></modules>";
|
|
||||||
|
|
||||||
|
|
||||||
if (joinURL.startsWith("http://") || joinURL.startsWith("https://")) {
|
|
||||||
%>
|
|
||||||
|
|
||||||
<script language="javascript" type="text/javascript">
|
|
||||||
window.location.href="<%=joinURL%>";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<%
|
|
||||||
} else {
|
|
||||||
%>
|
|
||||||
|
|
||||||
Error: getJoinURL() failed
|
|
||||||
<p/>
|
|
||||||
<%=joinURL %>
|
|
||||||
|
|
||||||
<%
|
|
||||||
}
|
|
||||||
}
|
|
||||||
%>
|
|
||||||
|
|
||||||
|
|
||||||
<%@ include file="demo_footer.jsp"%>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,166 +0,0 @@
|
|||||||
<!--
|
|
||||||
|
|
||||||
BigBlueButton - http://www.bigbluebutton.org
|
|
||||||
|
|
||||||
Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
|
|
||||||
|
|
||||||
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/>.
|
|
||||||
|
|
||||||
Author: Jesus Federico <jesus@123it.ca>
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
<%@ page language="java" contentType="text/html; charset=UTF-8"
|
|
||||||
pageEncoding="UTF-8"%>
|
|
||||||
<%
|
|
||||||
request.setCharacterEncoding("UTF-8");
|
|
||||||
response.setCharacterEncoding("UTF-8");
|
|
||||||
%>
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
||||||
<title>Join Demo Meeting using OpenID</title>
|
|
||||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
|
|
||||||
<script type="text/javascript">
|
|
||||||
$(function() {
|
|
||||||
var form = $('#form1');
|
|
||||||
$('#google').click(function() {
|
|
||||||
$("<input>").attr({
|
|
||||||
'type':'hidden',
|
|
||||||
'name':'connect',
|
|
||||||
'value':'google'
|
|
||||||
}).appendTo(form);
|
|
||||||
$('#form1').submit();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
$('#yahoo').click(function() {
|
|
||||||
$("<input>").attr({
|
|
||||||
'type':'hidden',
|
|
||||||
'name':'connect',
|
|
||||||
'value':'yahoo'
|
|
||||||
}).appendTo(form);
|
|
||||||
$('#form1').submit();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
$('#custom').click(function() {
|
|
||||||
$("<input>").attr({
|
|
||||||
'type':'hidden',
|
|
||||||
'name':'connect',
|
|
||||||
'value':'custom'
|
|
||||||
}).appendTo(form);
|
|
||||||
$('#form1').submit();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<%@ include file="bbb_api.jsp"%>
|
|
||||||
<%@ include file="bbb_jopenid.jsp"%>
|
|
||||||
|
|
||||||
<%
|
|
||||||
String urlPath = request.getRequestURI();
|
|
||||||
String urlHost = new URL(BigBlueButtonURL).getProtocol() + "://" + new URL(BigBlueButtonURL).getAuthority();
|
|
||||||
|
|
||||||
if (request.getParameterMap().isEmpty()) {
|
|
||||||
//
|
|
||||||
// Assume we want to create a meeting
|
|
||||||
//
|
|
||||||
%>
|
|
||||||
<%@ include file="demo_header.jsp"%>
|
|
||||||
|
|
||||||
<h2>Join Demo Meeting using openID</h2>
|
|
||||||
|
|
||||||
<FORM id="form1" NAME="form1" METHOD="GET" ACTION="#">
|
|
||||||
<table cellpadding="5" cellspacing="5" style="width: 400px; ">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td> </td>
|
|
||||||
<td style="text-align: left ">
|
|
||||||
<a href="#" id="yahoo" title="Sign-in with Yahoo OpenID">
|
|
||||||
<img src="images/yahoo.png" alt="Sign in"></br>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<!--
|
|
||||||
<tr>
|
|
||||||
<td> </td>
|
|
||||||
<td style="text-align: left ">
|
|
||||||
<a href="#" id="custom" title="Sign-in with Custom OpenID">
|
|
||||||
<img src="images/openid.png" alt="Sign in"></br>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
-->
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</FORM>
|
|
||||||
|
|
||||||
<%
|
|
||||||
} else if (request.getParameter("connect")!=null ) {
|
|
||||||
manager.setRealm(urlHost);
|
|
||||||
manager.setReturnTo(urlHost + urlPath);
|
|
||||||
Endpoint endpoint = null;
|
|
||||||
|
|
||||||
if (request.getParameter("connect").equals("google")) {
|
|
||||||
endpoint = manager.lookupEndpoint("Google");
|
|
||||||
|
|
||||||
} else if (request.getParameter("connect").equals("yahoo")) {
|
|
||||||
endpoint = manager.lookupEndpoint("Yahoo");
|
|
||||||
|
|
||||||
} else if (request.getParameter("connect").equals("custom")) {
|
|
||||||
endpoint = manager.lookupEndpoint("Google");
|
|
||||||
//endpoint = manager.lookupEndpoint("Custom");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Association association = manager.lookupAssociation(endpoint);
|
|
||||||
request.getSession().setAttribute(ATTR_MAC, association.getRawMacKey());
|
|
||||||
request.getSession().setAttribute(ATTR_ALIAS, endpoint.getAlias());
|
|
||||||
String url = manager.getAuthenticationUrl(endpoint, association);
|
|
||||||
response.sendRedirect(url);
|
|
||||||
|
|
||||||
} else if (request.getParameter("openid.ns")!=null && !request.getParameter("openid.ns").equals("")) {
|
|
||||||
|
|
||||||
byte[] mac_key = (byte[]) request.getSession().getAttribute(ATTR_MAC);
|
|
||||||
String alias = (String) request.getSession().getAttribute(ATTR_ALIAS);
|
|
||||||
Authentication authentication = manager.getAuthentication(request, mac_key, alias);
|
|
||||||
String joinURL = getJoinURL(authentication.getFullname(), "Demo Meeting", null, null, null, null );
|
|
||||||
|
|
||||||
if (joinURL.startsWith("http://") || joinURL.startsWith("https://")) {
|
|
||||||
%>
|
|
||||||
|
|
||||||
<script language="javascript" type="text/javascript">
|
|
||||||
window.location.href="<%=joinURL%>";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<%
|
|
||||||
} else {
|
|
||||||
%>
|
|
||||||
|
|
||||||
Error: getJoinURL() failed
|
|
||||||
<p/>
|
|
||||||
<%=joinURL %>
|
|
||||||
|
|
||||||
<%
|
|
||||||
}
|
|
||||||
}
|
|
||||||
%>
|
|
||||||
|
|
||||||
|
|
||||||
<%@ include file="demo_footer.jsp"%>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -109,7 +109,7 @@ function createMeetingTable(meeting) {
|
|||||||
form += '<input type="submit" value="End"/></FORM>';
|
form += '<input type="submit" value="End"/></FORM>';
|
||||||
form += '</th>';
|
form += '</th>';
|
||||||
|
|
||||||
var tableContent = '<table name="' + meeting.meetingID + '" class="hor-minimalist-b" cellspacing="0" summary="The current participants in a meeting"><caption>' + meeting.meetingID + '<caption><tr><th scope="col" abbr="Participants">Participants</th><th scope="col" abbr="Name">Name</th><th scope="col" abbr="Role">Role</th>';
|
var tableContent = '<table name="' + meeting.meetingID + '" class="hor-minimalist-b" cellspacing="0" summary="The current participants in a meeting"><caption>' + meeting.meetingName + '<caption><tr><th scope="col" abbr="Participants">Participants</th><th scope="col" abbr="Name">Name</th><th scope="col" abbr="Role">Role</th>';
|
||||||
|
|
||||||
//uncomment below to add the ability to end meetings in the activity monitor
|
//uncomment below to add the ability to end meetings in the activity monitor
|
||||||
//tableContent += form;
|
//tableContent += form;
|
||||||
@ -157,4 +157,5 @@ function createMeetingTable(meeting) {
|
|||||||
// 2. has no spaces and/or special characters
|
// 2. has no spaces and/or special characters
|
||||||
function encode(string) {
|
function encode(string) {
|
||||||
return hex_md5(string);
|
return hex_md5(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
bbbsystemcheck.title = Mconf-Live Client Check
|
bbbsystemcheck.title = BigBlueButton Client Check
|
||||||
bbbsystemcheck.refresh = Refresh
|
bbbsystemcheck.refresh = Refresh
|
||||||
bbbsystemcheck.mail = Mail
|
bbbsystemcheck.mail = Mail
|
||||||
bbbsystemcheck.version = Client Check Version
|
bbbsystemcheck.version = Client Check Version
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
bbbsystemcheck.title = Diagnóstico do cliente Mconf-Live
|
bbbsystemcheck.title = Diagnóstico do cliente BigBlueButton
|
||||||
bbbsystemcheck.refresh = Recarregar
|
bbbsystemcheck.refresh = Recarregar
|
||||||
bbbsystemcheck.mail = E-mail
|
bbbsystemcheck.mail = E-mail
|
||||||
bbbsystemcheck.version = Versão deste verificador
|
bbbsystemcheck.version = Versão deste verificador
|
||||||
|
@ -208,9 +208,14 @@
|
|||||||
var swfObj = getSwfObj();
|
var swfObj = getSwfObj();
|
||||||
swfObj.webRTCEchoTest(success, errorcode);
|
swfObj.webRTCEchoTest(success, errorcode);
|
||||||
|
|
||||||
if (callActive === true) {
|
webrtc_hangup(function() {
|
||||||
leaveWebRTCVoiceConference();
|
console.log("[BBBClientCheck] Handling webRTC hangup callback");
|
||||||
}
|
if (userAgent) {
|
||||||
|
var userAgentTemp = userAgent;
|
||||||
|
userAgent = null;
|
||||||
|
userAgentTemp.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
BBB.getMyUserInfo = function(callback) {
|
BBB.getMyUserInfo = function(callback) {
|
||||||
@ -221,7 +226,7 @@
|
|||||||
myRole: "undefined",
|
myRole: "undefined",
|
||||||
amIPresenter: "undefined",
|
amIPresenter: "undefined",
|
||||||
dialNumber: "undefined",
|
dialNumber: "undefined",
|
||||||
voiceBridge: "00000",
|
voiceBridge: "",
|
||||||
customdata: "undefined"
|
customdata: "undefined"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,42 +234,67 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// webrtc test callbacks
|
// webrtc test callbacks
|
||||||
BBB.webRTCCallSucceeded = function() {
|
BBB.webRTCEchoTestFailed = function(errorcode) {
|
||||||
console.log("[BBBClientCheck] Handling webRTCCallSucceeded");
|
console.log("[BBBClientCheck] Handling webRTCEchoTestFailed");
|
||||||
|
sendWebRTCEchoTestAnswer(false, errorcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
BBB.webRTCEchoTestEnded = function() {
|
||||||
|
console.log("[BBBClientCheck] Handling webRTCEchoTestEnded");
|
||||||
|
}
|
||||||
|
|
||||||
|
BBB.webRTCEchoTestStarted = function() {
|
||||||
|
console.log("[BBBClientCheck] Handling webRTCEchoTestStarted");
|
||||||
|
sendWebRTCEchoTestAnswer(true, 'Success');
|
||||||
|
}
|
||||||
|
|
||||||
|
BBB.webRTCEchoTestConnecting = function() {
|
||||||
|
console.log("[BBBClientCheck] Handling webRTCEchoTestConnecting");
|
||||||
|
}
|
||||||
|
|
||||||
|
BBB.webRTCEchoTestWaitingForICE = function() {
|
||||||
|
console.log("[BBBClientCheck] Handling webRTCEchoTestWaitingForICE");
|
||||||
|
}
|
||||||
|
|
||||||
|
BBB.webRTCEchoTestWebsocketSucceeded = function() {
|
||||||
|
console.log("[BBBClientCheck] Handling webRTCEchoTestWebsocketSucceeded");
|
||||||
var swfObj = getSwfObj();
|
var swfObj = getSwfObj();
|
||||||
swfObj.webRTCSocketTest(true, 'Connected');
|
swfObj.webRTCSocketTest(true, 'Connected');
|
||||||
}
|
}
|
||||||
|
|
||||||
BBB.webRTCCallFailed = function(inEchoTest, errorcode, cause) {
|
BBB.webRTCEchoTestWebsocketFailed = function(errorcode) {
|
||||||
console.log("[BBBClientCheck] Handling webRTCCallFailed, errorcode " + errorcode + ", cause: " + cause);
|
console.log("[BBBClientCheck] Handling webRTCEchoTestWebsocketFailed");
|
||||||
if (errorcode == 1002) {
|
var swfObj = getSwfObj();
|
||||||
// failed to connect the websocket
|
swfObj.webRTCSocketTest(false, errorcode);
|
||||||
var swfObj = getSwfObj();
|
|
||||||
swfObj.webRTCSocketTest(false, errorcode);
|
|
||||||
} else {
|
|
||||||
sendWebRTCEchoTestAnswer(false, errorcode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BBB.webRTCCallEnded = function(inEchoTest) {
|
// webrtc callbacks
|
||||||
console.log("[BBBClientCheck] Handling webRTCCallEnded");
|
BBB.webRTCConferenceCallFailed = function(errorcode) {
|
||||||
|
console.log("[BBBClientCheck] Handling webRTCConferenceCallFailed");
|
||||||
}
|
}
|
||||||
|
|
||||||
BBB.webRTCCallStarted = function(inEchoTest) {
|
BBB.webRTCConferenceCallEnded = function() {
|
||||||
console.log("[BBBClientCheck] Handling webRTCCallStarted");
|
console.log("[BBBClientCheck] Handling webRTCConferenceCallEnded");
|
||||||
sendWebRTCEchoTestAnswer(true, 'Connected');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BBB.webRTCCallConnecting = function(inEchoTest) {
|
BBB.webRTCConferenceCallStarted = function() {
|
||||||
console.log("[BBBClientCheck] Handling webRTCCallConnecting");
|
console.log("[BBBClientCheck] Handling webRTCConferenceCallStarted");
|
||||||
}
|
}
|
||||||
|
|
||||||
BBB.webRTCCallWaitingForICE = function(inEchoTest) {
|
BBB.webRTCConferenceCallConnecting = function() {
|
||||||
console.log("[BBBClientCheck] Handling webRTCCallWaitingForICE");
|
console.log("[BBBClientCheck] Handling webRTCConferenceCallConnecting");
|
||||||
}
|
}
|
||||||
|
|
||||||
BBB.webRTCCallTransferring = function(inEchoTest) {
|
BBB.webRTCConferenceCallWaitingForICE = function() {
|
||||||
console.log("[BBBClientCheck] Handling webRTCCallTransferring");
|
console.log("[BBBClientCheck] Handling webRTCConferenceCallWaitingForICE");
|
||||||
|
}
|
||||||
|
|
||||||
|
BBB.webRTCConferenceCallWebsocketSucceeded = function() {
|
||||||
|
console.log("[BBBClientCheck] Handling webRTCConferenceCallWebsocketSucceeded");
|
||||||
|
}
|
||||||
|
|
||||||
|
BBB.webRTCConferenceCallWebsocketFailed = function(errorcode) {
|
||||||
|
console.log("[BBBClientCheck] Handling webRTCConferenceCallWebsocketFailed");
|
||||||
}
|
}
|
||||||
|
|
||||||
BBB.webRTCMediaRequest = function() {
|
BBB.webRTCMediaRequest = function() {
|
||||||
@ -278,4 +308,36 @@
|
|||||||
BBB.webRTCMediaFail = function() {
|
BBB.webRTCMediaFail = function() {
|
||||||
console.log("[BBBClientCheck] Handling webRTCMediaFail");
|
console.log("[BBBClientCheck] Handling webRTCMediaFail");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BBB.webRTCCallStarted = function(inEchoTest) {
|
||||||
|
console.log("[BBBClientCheck] Handling webRTCCallStarted");
|
||||||
|
BBB.webRTCEchoTestStarted();
|
||||||
|
};
|
||||||
|
|
||||||
|
BBB.webRTCCallConnecting = function(inEchoTest) {
|
||||||
|
console.log("[BBBClientCheck] Handling webRTCCallConnecting");
|
||||||
|
BBB.webRTCEchoTestWebsocketSucceeded();
|
||||||
|
};
|
||||||
|
|
||||||
|
BBB.webRTCCallEnded = function(inEchoTest) {
|
||||||
|
console.log("[BBBClientCheck] Handling webRTCCallEnded");
|
||||||
|
};
|
||||||
|
|
||||||
|
BBB.webRTCCallFailed = function(inEchoTest, errorcode, cause) {
|
||||||
|
console.log("[BBBClientCheck] Handling webRTCCallFailed");
|
||||||
|
BBB.webRTCEchoTestFailed(errorcode);
|
||||||
|
BBB.webRTCEchoTestWebsocketFailed();
|
||||||
|
};
|
||||||
|
|
||||||
|
BBB.webRTCCallWaitingForICE = function(inEchoTest) {
|
||||||
|
console.log("[BBBClientCheck] Handling webRTCCallWaitingForICE");
|
||||||
|
};
|
||||||
|
|
||||||
|
BBB.webRTCCallTransferring = function(inEchoTest) {
|
||||||
|
console.log("[BBBClientCheck] Handling webRTCCallTransferring");
|
||||||
|
};
|
||||||
|
|
||||||
|
BBB.webRTCCallProgressCallback = function(progress) {
|
||||||
|
console.log("[BBBClientCheck] Handling webRTCCallProgressCallback");
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -192,7 +192,7 @@ function createUAWithStuns(username, server, callback, stunsConfig, makeCallFunc
|
|||||||
*/
|
*/
|
||||||
var configuration = {
|
var configuration = {
|
||||||
uri: 'sip:' + encodeURIComponent(username) + '@' + server,
|
uri: 'sip:' + encodeURIComponent(username) + '@' + server,
|
||||||
wsServers: 'ws://' + server + '/ws',
|
wsServers: ('https:' == document.location.protocol ? 'wss://' : 'ws://') + server + '/ws',
|
||||||
displayName: username,
|
displayName: username,
|
||||||
register: false,
|
register: false,
|
||||||
traceSip: true,
|
traceSip: true,
|
||||||
|
@ -32,6 +32,7 @@ public class Constants {
|
|||||||
public static final String RECORDING = "recording";
|
public static final String RECORDING = "recording";
|
||||||
public static final String AUTO_START_RECORDING = "auto_start_recording";
|
public static final String AUTO_START_RECORDING = "auto_start_recording";
|
||||||
public static final String ALLOW_START_STOP_RECORDING = "allow_start_stop_recording";
|
public static final String ALLOW_START_STOP_RECORDING = "allow_start_stop_recording";
|
||||||
|
public static final String WEBCAMS_ONLY_FOR_MODERATOR = "webcams_only_for_moderator";
|
||||||
public static final String LAYOUT_ID = "layout_id";
|
public static final String LAYOUT_ID = "layout_id";
|
||||||
public static final String LISTENONLY = "listenOnly";
|
public static final String LISTENONLY = "listenOnly";
|
||||||
public static final String LISTEN_ONLY = "listen_only";
|
public static final String LISTEN_ONLY = "listen_only";
|
||||||
|
@ -14,6 +14,7 @@ public class CreateMeetingMessage implements IBigBlueButtonMessage {
|
|||||||
public final Long duration;
|
public final Long duration;
|
||||||
public final Boolean autoStartRecording;
|
public final Boolean autoStartRecording;
|
||||||
public final Boolean allowStartStopRecording;
|
public final Boolean allowStartStopRecording;
|
||||||
|
public final Boolean webcamsOnlyForModerator;
|
||||||
public final String moderatorPass;
|
public final String moderatorPass;
|
||||||
public final String viewerPass;
|
public final String viewerPass;
|
||||||
public final Long createTime;
|
public final Long createTime;
|
||||||
@ -22,8 +23,9 @@ public class CreateMeetingMessage implements IBigBlueButtonMessage {
|
|||||||
|
|
||||||
public CreateMeetingMessage(String id, String externalId, String name, Boolean record, String voiceBridge,
|
public CreateMeetingMessage(String id, String externalId, String name, Boolean record, String voiceBridge,
|
||||||
Long duration, Boolean autoStartRecording,
|
Long duration, Boolean autoStartRecording,
|
||||||
Boolean allowStartStopRecording, String moderatorPass,
|
Boolean allowStartStopRecording,Boolean webcamsOnlyForModerator,
|
||||||
String viewerPass, Long createTime, String createDate, Map<String, String> metadata) {
|
String moderatorPass, String viewerPass,
|
||||||
|
Long createTime, String createDate, Map<String, String> metadata) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.externalId = externalId;
|
this.externalId = externalId;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@ -32,6 +34,7 @@ public class CreateMeetingMessage implements IBigBlueButtonMessage {
|
|||||||
this.duration = duration;
|
this.duration = duration;
|
||||||
this.autoStartRecording = autoStartRecording;
|
this.autoStartRecording = autoStartRecording;
|
||||||
this.allowStartStopRecording = allowStartStopRecording;
|
this.allowStartStopRecording = allowStartStopRecording;
|
||||||
|
this.webcamsOnlyForModerator = webcamsOnlyForModerator;
|
||||||
this.moderatorPass = moderatorPass;
|
this.moderatorPass = moderatorPass;
|
||||||
this.viewerPass = viewerPass;
|
this.viewerPass = viewerPass;
|
||||||
this.createTime = createTime;
|
this.createTime = createTime;
|
||||||
|
@ -63,6 +63,7 @@ public class MessageFromJsonConverter {
|
|||||||
Long duration = payload.get(Constants.DURATION).getAsLong();
|
Long duration = payload.get(Constants.DURATION).getAsLong();
|
||||||
Boolean autoStartRecording = payload.get(Constants.AUTO_START_RECORDING).getAsBoolean();
|
Boolean autoStartRecording = payload.get(Constants.AUTO_START_RECORDING).getAsBoolean();
|
||||||
Boolean allowStartStopRecording = payload.get(Constants.ALLOW_START_STOP_RECORDING).getAsBoolean();
|
Boolean allowStartStopRecording = payload.get(Constants.ALLOW_START_STOP_RECORDING).getAsBoolean();
|
||||||
|
Boolean webcamsOnlyForModerator = payload.get(Constants.WEBCAMS_ONLY_FOR_MODERATOR).getAsBoolean();
|
||||||
String moderatorPassword = payload.get(Constants.MODERATOR_PASS).getAsString();
|
String moderatorPassword = payload.get(Constants.MODERATOR_PASS).getAsString();
|
||||||
String viewerPassword = payload.get(Constants.VIEWER_PASS).getAsString();
|
String viewerPassword = payload.get(Constants.VIEWER_PASS).getAsString();
|
||||||
Long createTime = payload.get(Constants.CREATE_TIME).getAsLong();
|
Long createTime = payload.get(Constants.CREATE_TIME).getAsLong();
|
||||||
@ -74,7 +75,8 @@ public class MessageFromJsonConverter {
|
|||||||
|
|
||||||
return new CreateMeetingMessage(id, externalId, name, record, voiceBridge,
|
return new CreateMeetingMessage(id, externalId, name, record, voiceBridge,
|
||||||
duration, autoStartRecording, allowStartStopRecording,
|
duration, autoStartRecording, allowStartStopRecording,
|
||||||
moderatorPassword, viewerPassword, createTime, createDate, metadata);
|
webcamsOnlyForModerator, moderatorPassword, viewerPassword,
|
||||||
|
createTime, createDate, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IBigBlueButtonMessage processDestroyMeeting(JsonObject payload) {
|
private static IBigBlueButtonMessage processDestroyMeeting(JsonObject payload) {
|
||||||
|
@ -25,6 +25,7 @@ public class CreateMeetingRequest implements IBigBlueButtonMessage {
|
|||||||
public final Integer durationInMinutes;
|
public final Integer durationInMinutes;
|
||||||
public final Boolean autoStartRecording;
|
public final Boolean autoStartRecording;
|
||||||
public final Boolean allowStartStopRecording;
|
public final Boolean allowStartStopRecording;
|
||||||
|
public final Boolean webcamsOnlyForModerator;
|
||||||
public final String moderatorPassword;
|
public final String moderatorPassword;
|
||||||
public final String viewerPassword;
|
public final String viewerPassword;
|
||||||
public final Long createTime;
|
public final Long createTime;
|
||||||
@ -37,9 +38,9 @@ public class CreateMeetingRequest implements IBigBlueButtonMessage {
|
|||||||
String parentId, String name, Boolean record,
|
String parentId, String name, Boolean record,
|
||||||
String voiceConfId, Integer duration,
|
String voiceConfId, Integer duration,
|
||||||
Boolean autoStartRecording, Boolean allowStartStopRecording,
|
Boolean autoStartRecording, Boolean allowStartStopRecording,
|
||||||
String moderatorPass, String viewerPass, Long createTime,
|
Boolean webcamsOnlyForModerator, String moderatorPass,
|
||||||
String createDate, Boolean isBreakout, Integer sequence,
|
String viewerPass, Long createTime, String createDate,
|
||||||
Map<String, String> metadata) {
|
Boolean isBreakout, Integer sequence, Map<String, String> metadata) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.externalId = externalId;
|
this.externalId = externalId;
|
||||||
this.parentId = parentId;
|
this.parentId = parentId;
|
||||||
@ -49,6 +50,7 @@ public class CreateMeetingRequest implements IBigBlueButtonMessage {
|
|||||||
this.durationInMinutes = duration;
|
this.durationInMinutes = duration;
|
||||||
this.autoStartRecording = autoStartRecording;
|
this.autoStartRecording = autoStartRecording;
|
||||||
this.allowStartStopRecording = allowStartStopRecording;
|
this.allowStartStopRecording = allowStartStopRecording;
|
||||||
|
this.webcamsOnlyForModerator = webcamsOnlyForModerator;
|
||||||
this.moderatorPassword = moderatorPass;
|
this.moderatorPassword = moderatorPass;
|
||||||
this.viewerPassword = viewerPass;
|
this.viewerPassword = viewerPass;
|
||||||
this.createTime = createTime;
|
this.createTime = createTime;
|
||||||
|
@ -10,48 +10,50 @@ import org.junit.Test;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
public class CreateMeetingRequestTest {
|
public class CreateMeetingRequestTest {
|
||||||
@Test
|
@Test
|
||||||
public void testCreateMeetingRequest() {
|
public void testCreateMeetingRequest() {
|
||||||
String meetingId = "abc123";
|
String meetingId = "abc123";
|
||||||
String externalId = "extabc123";
|
String externalId = "extabc123";
|
||||||
String parentId = "";
|
String parentId = "";
|
||||||
Boolean record = false;
|
Boolean record = false;
|
||||||
Integer durationInMinutes = 20;
|
Integer durationInMinutes = 20;
|
||||||
String name = "Breakout room 1";
|
String name = "Breakout room 1";
|
||||||
String voiceConfId = "851153";
|
String voiceConfId = "851153";
|
||||||
Boolean autoStartRecording = false;
|
Boolean autoStartRecording = false;
|
||||||
Boolean allowStartStopRecording = false;
|
Boolean allowStartStopRecording = false;
|
||||||
Boolean isBreakout = true;
|
Boolean webcamsOnlyForModerator = false;
|
||||||
Integer sequence = 4;
|
Boolean isBreakout = true;
|
||||||
String viewerPassword = "vp";
|
Integer sequence = 4;
|
||||||
String moderatorPassword = "mp";
|
String viewerPassword = "vp";
|
||||||
long createTime = System.currentTimeMillis();
|
String moderatorPassword = "mp";
|
||||||
String createDate = new Date(createTime).toString();
|
long createTime = System.currentTimeMillis();
|
||||||
|
String createDate = new Date(createTime).toString();
|
||||||
Map<String, String> metadata = new HashMap<String, String>();
|
Map<String, String> metadata = new HashMap<String, String>();
|
||||||
metadata.put("meta_test", "test");
|
metadata.put("meta_test", "test");
|
||||||
|
|
||||||
CreateMeetingRequestPayload payload = new CreateMeetingRequestPayload(
|
CreateMeetingRequestPayload payload = new CreateMeetingRequestPayload(
|
||||||
meetingId, externalId, parentId, name, record, voiceConfId,
|
meetingId, externalId, parentId, name, record, voiceConfId,
|
||||||
durationInMinutes, autoStartRecording, allowStartStopRecording,
|
durationInMinutes, autoStartRecording, allowStartStopRecording,
|
||||||
moderatorPassword, viewerPassword, createTime, createDate,
|
webcamsOnlyForModerator, moderatorPassword, viewerPassword,
|
||||||
isBreakout, sequence, metadata);
|
createTime, createDate, isBreakout, sequence, metadata);
|
||||||
CreateMeetingRequest msg = new CreateMeetingRequest(payload);
|
CreateMeetingRequest msg = new CreateMeetingRequest(payload);
|
||||||
Gson gson = new Gson();
|
Gson gson = new Gson();
|
||||||
String json = gson.toJson(msg);
|
String json = gson.toJson(msg);
|
||||||
System.out.println(json);
|
System.out.println(json);
|
||||||
|
|
||||||
CreateMeetingRequest rxMsg = gson.fromJson(json, CreateMeetingRequest.class);
|
CreateMeetingRequest rxMsg = gson.fromJson(json,
|
||||||
|
CreateMeetingRequest.class);
|
||||||
Assert.assertEquals(rxMsg.header.name, CreateMeetingRequest.NAME);
|
|
||||||
Assert.assertEquals(rxMsg.payload.id, meetingId);
|
Assert.assertEquals(rxMsg.header.name, CreateMeetingRequest.NAME);
|
||||||
Assert.assertEquals(rxMsg.payload.externalId, externalId);
|
Assert.assertEquals(rxMsg.payload.id, meetingId);
|
||||||
Assert.assertEquals(rxMsg.payload.parentId, parentId);
|
Assert.assertEquals(rxMsg.payload.externalId, externalId);
|
||||||
Assert.assertEquals(rxMsg.payload.name, name);
|
Assert.assertEquals(rxMsg.payload.parentId, parentId);
|
||||||
Assert.assertEquals(rxMsg.payload.voiceConfId, voiceConfId);
|
Assert.assertEquals(rxMsg.payload.name, name);
|
||||||
Assert.assertEquals(rxMsg.payload.viewerPassword, viewerPassword);
|
Assert.assertEquals(rxMsg.payload.voiceConfId, voiceConfId);
|
||||||
Assert.assertEquals(rxMsg.payload.moderatorPassword, moderatorPassword);
|
Assert.assertEquals(rxMsg.payload.viewerPassword, viewerPassword);
|
||||||
Assert.assertEquals(rxMsg.payload.durationInMinutes, durationInMinutes);
|
Assert.assertEquals(rxMsg.payload.moderatorPassword, moderatorPassword);
|
||||||
Assert.assertEquals(rxMsg.payload.isBreakout, isBreakout);
|
Assert.assertEquals(rxMsg.payload.durationInMinutes, durationInMinutes);
|
||||||
Assert.assertEquals(rxMsg.payload.sequence, sequence);
|
Assert.assertEquals(rxMsg.payload.isBreakout, isBreakout);
|
||||||
}
|
Assert.assertEquals(rxMsg.payload.sequence, sequence);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
56
bbb-common-web/.gitignore
vendored
Normal file
56
bbb-common-web/.gitignore
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
.DS_Store
|
||||||
|
._.DS_Store*
|
||||||
|
.metadata
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.settings
|
||||||
|
.history
|
||||||
|
.worksheet
|
||||||
|
gen
|
||||||
|
**/*.swp
|
||||||
|
**/*~.nib
|
||||||
|
**/build/
|
||||||
|
**/*.pbxuser
|
||||||
|
**/*.perspective
|
||||||
|
**/*.perspectivev3
|
||||||
|
*.xcworkspace
|
||||||
|
*.xcuserdatad
|
||||||
|
**/target
|
||||||
|
target
|
||||||
|
*.iml
|
||||||
|
project/*.ipr
|
||||||
|
project/*.iml
|
||||||
|
project/*.iws
|
||||||
|
project/out
|
||||||
|
project/*/target
|
||||||
|
project/target
|
||||||
|
project/*/bin
|
||||||
|
project/*/build
|
||||||
|
project/*.iml
|
||||||
|
project/*/*.iml
|
||||||
|
project/.idea
|
||||||
|
project/.idea/*
|
||||||
|
.idea
|
||||||
|
.idea/*
|
||||||
|
.idea/**/*
|
||||||
|
.DS_Store
|
||||||
|
project/.DS_Store
|
||||||
|
project/*/.DS_Store
|
||||||
|
tm.out
|
||||||
|
tmlog*.log
|
||||||
|
*.tm*.epoch
|
||||||
|
out/
|
||||||
|
provisioning/.vagrant
|
||||||
|
provisioning/*/.vagrant
|
||||||
|
provisioning/*/*.known
|
||||||
|
/sbt/akka-patterns-store/
|
||||||
|
/daemon/src/build/
|
||||||
|
*.lock
|
||||||
|
log/
|
||||||
|
tmp/
|
||||||
|
build/
|
||||||
|
akka-patterns-store/
|
||||||
|
lib_managed/
|
||||||
|
.cache
|
||||||
|
bin/
|
||||||
|
|
1
bbb-common-web/README.md
Normal file
1
bbb-common-web/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
see http://code.google.com/p/bigbluebutton/wiki/DevelopingBBB
|
117
bbb-common-web/build.sbt
Executable file
117
bbb-common-web/build.sbt
Executable file
@ -0,0 +1,117 @@
|
|||||||
|
name := "bbb-common-web"
|
||||||
|
|
||||||
|
organization := "org.bigbluebutton"
|
||||||
|
|
||||||
|
version := "0.0.1-SNAPSHOT"
|
||||||
|
|
||||||
|
scalaVersion := "2.11.7"
|
||||||
|
|
||||||
|
scalacOptions ++= Seq(
|
||||||
|
"-unchecked",
|
||||||
|
"-deprecation",
|
||||||
|
"-Xlint",
|
||||||
|
"-Ywarn-dead-code",
|
||||||
|
"-language:_",
|
||||||
|
"-target:jvm-1.8",
|
||||||
|
"-encoding", "UTF-8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// We want to have our jar files in lib_managed dir.
|
||||||
|
// This way we'll have the right path when we import
|
||||||
|
// into eclipse.
|
||||||
|
retrieveManaged := true
|
||||||
|
|
||||||
|
testOptions in Test += Tests.Argument(TestFrameworks.Specs2, "html", "console", "junitxml")
|
||||||
|
|
||||||
|
testOptions in Test += Tests.Argument(TestFrameworks.ScalaTest, "-h", "target/scalatest-reports")
|
||||||
|
|
||||||
|
val scalaV = "2.11.7"
|
||||||
|
|
||||||
|
libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaV
|
||||||
|
libraryDependencies += "org.scala-lang" % "scala-library" % scalaV
|
||||||
|
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaV
|
||||||
|
|
||||||
|
// https://mvnrepository.com/artifact/org.apache.commons/commons-lang3
|
||||||
|
libraryDependencies += "org.apache.commons" % "commons-lang3" % "3.5"
|
||||||
|
|
||||||
|
|
||||||
|
libraryDependencies += "commons-io" % "commons-io" % "2.4"
|
||||||
|
libraryDependencies += "org.freemarker" % "freemarker" % "2.3.23"
|
||||||
|
libraryDependencies += "com.fasterxml.jackson.dataformat" % "jackson-dataformat-xml" % "2.6.3"
|
||||||
|
// https://mvnrepository.com/artifact/org.codehaus.woodstox/woodstox-core-asl
|
||||||
|
libraryDependencies += "org.codehaus.woodstox" % "woodstox-core-asl" % "4.4.1"
|
||||||
|
|
||||||
|
libraryDependencies += "org.slf4j" % "slf4j-api" % "1.7.5"
|
||||||
|
|
||||||
|
libraryDependencies += "org.pegdown" % "pegdown" % "1.4.0" % "test"
|
||||||
|
libraryDependencies += "junit" % "junit" % "4.12" % "test"
|
||||||
|
libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % "test"
|
||||||
|
|
||||||
|
// https://mvnrepository.com/artifact/org.mockito/mockito-core
|
||||||
|
libraryDependencies += "org.mockito" % "mockito-core" % "2.7.12" % "test"
|
||||||
|
libraryDependencies += "org.scalactic" %% "scalactic" % "3.0.1" % "test"
|
||||||
|
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.1" % "test"
|
||||||
|
|
||||||
|
seq(Revolver.settings: _*)
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
// Packaging
|
||||||
|
//
|
||||||
|
// Reference:
|
||||||
|
// http://xerial.org/blog/2014/03/24/sbt/
|
||||||
|
// http://www.scala-sbt.org/sbt-pgp/usage.html
|
||||||
|
// http://www.scala-sbt.org/0.13/docs/Using-Sonatype.html
|
||||||
|
// http://central.sonatype.org/pages/requirements.html
|
||||||
|
// http://central.sonatype.org/pages/releasing-the-deployment.html
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
// Build pure Java lib (i.e. without scala)
|
||||||
|
// Do not append Scala versions to the generated artifacts
|
||||||
|
crossPaths := false
|
||||||
|
|
||||||
|
// This forbids including Scala related libraries into the dependency
|
||||||
|
autoScalaLibrary := false
|
||||||
|
|
||||||
|
/***************************
|
||||||
|
* When developing, change the version above to x.x.x-SNAPSHOT then use the file resolver to
|
||||||
|
* publish to the local maven repo using "sbt publish"
|
||||||
|
*/
|
||||||
|
// Uncomment this to publish to local maven repo while commenting out the nexus repo
|
||||||
|
publishTo := Some(Resolver.file("file", new File(Path.userHome.absolutePath+"/.m2/repository")))
|
||||||
|
|
||||||
|
|
||||||
|
// Comment this out when publishing to local maven repo using SNAPSHOT version.
|
||||||
|
// To push to sonatype "sbt publishSigned"
|
||||||
|
//publishTo := {
|
||||||
|
// val nexus = "https://oss.sonatype.org/"
|
||||||
|
// if (isSnapshot.value)
|
||||||
|
// Some("snapshots" at nexus + "content/repositories/snapshots")
|
||||||
|
// else
|
||||||
|
// Some("releases" at nexus + "service/local/staging/deploy/maven2")
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Enables publishing to maven repo
|
||||||
|
publishMavenStyle := true
|
||||||
|
|
||||||
|
publishArtifact in Test := false
|
||||||
|
|
||||||
|
pomIncludeRepository := { _ => false }
|
||||||
|
|
||||||
|
pomExtra := (
|
||||||
|
<scm>
|
||||||
|
<url>git@github.com:bigbluebutton/bigbluebutton.git</url>
|
||||||
|
<connection>scm:git:git@github.com:bigbluebutton/bigbluebutton.git</connection>
|
||||||
|
</scm>
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<id>ritzalam</id>
|
||||||
|
<name>Richard Alam</name>
|
||||||
|
<url>http://www.bigbluebutton.org</url>
|
||||||
|
</developer>
|
||||||
|
</developers>)
|
||||||
|
|
||||||
|
licenses := Seq("LGPL-3.0" -> url("http://opensource.org/licenses/LGPL-3.0"))
|
||||||
|
|
||||||
|
homepage := Some(url("http://www.bigbluebutton.org"))
|
||||||
|
|
||||||
|
|
0
bbb-common-web/project/Build.scala
Executable file
0
bbb-common-web/project/Build.scala
Executable file
1
bbb-common-web/project/build.properties
Executable file
1
bbb-common-web/project/build.properties
Executable file
@ -0,0 +1 @@
|
|||||||
|
sbt.version=0.13.8
|
9
bbb-common-web/project/plugins.sbt
Executable file
9
bbb-common-web/project/plugins.sbt
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
addSbtPlugin("io.spray" % "sbt-revolver" % "0.7.2")
|
||||||
|
|
||||||
|
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.2.0")
|
||||||
|
|
||||||
|
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")
|
||||||
|
|
||||||
|
addSbtPlugin("com.artima.supersafe" % "sbtplugin" % "1.1.0")
|
||||||
|
|
||||||
|
|
@ -33,8 +33,12 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.bigbluebutton.api.domain.Recording;
|
import org.bigbluebutton.api.domain.Recording;
|
||||||
import org.bigbluebutton.api.messaging.MessagingService;
|
import org.bigbluebutton.api.domain.RecordingMetadata;
|
||||||
|
import org.bigbluebutton.api.util.RecordingMetadataReaderHelper;
|
||||||
|
// TODO: REVIEW THIS REDIS SERVICE
|
||||||
|
//import org.bigbluebutton.api.messaging.MessagingService;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -46,7 +50,7 @@ public class RecordingService {
|
|||||||
private String unpublishedDir = "/var/bigbluebutton/unpublished";
|
private String unpublishedDir = "/var/bigbluebutton/unpublished";
|
||||||
private String deletedDir = "/var/bigbluebutton/deleted";
|
private String deletedDir = "/var/bigbluebutton/deleted";
|
||||||
private RecordingServiceHelper recordingServiceHelper;
|
private RecordingServiceHelper recordingServiceHelper;
|
||||||
private MessagingService messagingService;
|
//private MessagingService messagingService;
|
||||||
private String recordStatusDir;
|
private String recordStatusDir;
|
||||||
|
|
||||||
public void startIngestAndProcessing(String meetingId) {
|
public void startIngestAndProcessing(String meetingId) {
|
||||||
@ -66,6 +70,38 @@ public class RecordingService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<RecordingMetadata> getRecordingsMetadata(List<String> recordIDs, List<String> states) {
|
||||||
|
List<RecordingMetadata> recs = new ArrayList<RecordingMetadata>();
|
||||||
|
|
||||||
|
Map<String, List<File>> allDirectories = getAllDirectories(states);
|
||||||
|
if (recordIDs.isEmpty()) {
|
||||||
|
for (Map.Entry<String, List<File>> entry : allDirectories.entrySet()) {
|
||||||
|
recordIDs.addAll(getAllRecordingIds(entry.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String recordID : recordIDs) {
|
||||||
|
for (Map.Entry<String, List<File>> entry : allDirectories.entrySet()) {
|
||||||
|
List<File> _recs = getRecordingsForPath(recordID, entry.getValue());
|
||||||
|
Iterator<File> iterator = _recs.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
RecordingMetadata r = getRecordingMetadata(iterator.next());
|
||||||
|
if (r != null) {
|
||||||
|
recs.add(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return recs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RecordingMetadata getRecordingMetadata(File dir) {
|
||||||
|
File file = new File(dir.getPath() + File.separatorChar + "metadata.xml");
|
||||||
|
RecordingMetadata rec = RecordingMetadataReaderHelper.getRecordingMetadata(file);
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
public List<Recording> getRecordings(List<String> recordIDs, List<String> states) {
|
public List<Recording> getRecordings(List<String> recordIDs, List<String> states) {
|
||||||
List<Recording> recs = new ArrayList<Recording>();
|
List<Recording> recs = new ArrayList<Recording>();
|
||||||
|
|
||||||
@ -121,6 +157,45 @@ public class RecordingService {
|
|||||||
return matchesMetadata;
|
return matchesMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean recordingMatchesMetadata(RecordingMetadata recording, Map<String, String> metadataFilters) {
|
||||||
|
boolean matchesMetadata = true;
|
||||||
|
for (Map.Entry<String, String> filter : metadataFilters.entrySet()) {
|
||||||
|
String metadataValue = recording.getMeta().get().get(filter.getKey());
|
||||||
|
if ( metadataValue == null ) {
|
||||||
|
// The recording doesn't have metadata specified
|
||||||
|
matchesMetadata = false;
|
||||||
|
} else {
|
||||||
|
String filterValue = filter.getValue();
|
||||||
|
if( filterValue.charAt(0) == '%' && filterValue.charAt(filterValue.length()-1) == '%' && metadataValue.contains(filterValue.substring(1, filterValue.length()-1)) ){
|
||||||
|
// Filter value embraced by two wild cards
|
||||||
|
// AND the filter value is part of the metadata value
|
||||||
|
} else if( filterValue.charAt(0) == '%' && metadataValue.endsWith(filterValue.substring(1, filterValue.length())) ) {
|
||||||
|
// Filter value starts with a wild cards
|
||||||
|
// AND the filter value ends with the metadata value
|
||||||
|
} else if( filterValue.charAt(filterValue.length()-1) == '%' && metadataValue.startsWith(filterValue.substring(0, filterValue.length()-1)) ) {
|
||||||
|
// Filter value ends with a wild cards
|
||||||
|
// AND the filter value starts with the metadata value
|
||||||
|
} else if( metadataValue.equals(filterValue) ) {
|
||||||
|
// Filter value doesnt have wildcards
|
||||||
|
// AND the filter value is the same as metadata value
|
||||||
|
} else {
|
||||||
|
matchesMetadata = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matchesMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<RecordingMetadata> filterRecordingsByMetadata(List<RecordingMetadata> recordings, Map<String, String> metadataFilters) {
|
||||||
|
List<RecordingMetadata> resultRecordings = new ArrayList<RecordingMetadata>();
|
||||||
|
for (RecordingMetadata entry : recordings) {
|
||||||
|
if (recordingMatchesMetadata(entry, metadataFilters))
|
||||||
|
resultRecordings.add(entry);
|
||||||
|
}
|
||||||
|
return resultRecordings;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<String, Recording> filterRecordingsByMetadata(Map<String, Recording> recordings, Map<String, String> metadataFilters) {
|
public Map<String, Recording> filterRecordingsByMetadata(Map<String, Recording> recordings, Map<String, String> metadataFilters) {
|
||||||
Map<String, Recording> resultRecordings = new HashMap<String, Recording>();
|
Map<String, Recording> resultRecordings = new HashMap<String, Recording>();
|
||||||
for (Map.Entry<String, Recording> entry : recordings.entrySet()) {
|
for (Map.Entry<String, Recording> entry : recordings.entrySet()) {
|
||||||
@ -191,7 +266,7 @@ public class RecordingService {
|
|||||||
return rec;
|
return rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteRecording(String id, String path) {
|
private static void deleteRecording(String id, String path) {
|
||||||
String[] format = getPlaybackFormats(path);
|
String[] format = getPlaybackFormats(path);
|
||||||
for (int i = 0; i < format.length; i++) {
|
for (int i = 0; i < format.length; i++) {
|
||||||
List<File> recordings = getDirectories(path + File.separatorChar + format[i]);
|
List<File> recordings = getDirectories(path + File.separatorChar + format[i]);
|
||||||
@ -204,12 +279,12 @@ public class RecordingService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createDirectory(File directory) {
|
private static void createDirectory(File directory) {
|
||||||
if (!directory.exists())
|
if (!directory.exists())
|
||||||
directory.mkdirs();
|
directory.mkdirs();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteDirectory(File directory) {
|
private static void deleteDirectory(File directory) {
|
||||||
/**
|
/**
|
||||||
* Go through each directory and check if it's not empty. We need to
|
* Go through each directory and check if it's not empty. We need to
|
||||||
* delete files inside a directory before a directory can be deleted.
|
* delete files inside a directory before a directory can be deleted.
|
||||||
@ -226,7 +301,7 @@ public class RecordingService {
|
|||||||
directory.delete();
|
directory.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<File> getDirectories(String path) {
|
private static List<File> getDirectories(String path) {
|
||||||
List<File> files = new ArrayList<File>();
|
List<File> files = new ArrayList<File>();
|
||||||
try {
|
try {
|
||||||
DirectoryStream<Path> stream = Files.newDirectoryStream(FileSystems.getDefault().getPath(path));
|
DirectoryStream<Path> stream = Files.newDirectoryStream(FileSystems.getDefault().getPath(path));
|
||||||
@ -242,7 +317,7 @@ public class RecordingService {
|
|||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] getPlaybackFormats(String path) {
|
private static String[] getPlaybackFormats(String path) {
|
||||||
List<File> dirs = getDirectories(path);
|
List<File> dirs = getDirectories(path);
|
||||||
String[] formats = new String[dirs.size()];
|
String[] formats = new String[dirs.size()];
|
||||||
|
|
||||||
@ -297,80 +372,121 @@ public class RecordingService {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean changeState(String recordingId, String state) {
|
public void changeState(String recordingId, String state) {
|
||||||
boolean anyResult = false;
|
|
||||||
if (state.equals(Recording.STATE_PUBLISHED)) {
|
if (state.equals(Recording.STATE_PUBLISHED)) {
|
||||||
// It can only be published if it is unpublished
|
// It can only be published if it is unpublished
|
||||||
anyResult |= changeState(unpublishedDir, recordingId, state);
|
changeState(unpublishedDir, recordingId, state);
|
||||||
} else if (state.equals(Recording.STATE_UNPUBLISHED)) {
|
} else if (state.equals(Recording.STATE_UNPUBLISHED)) {
|
||||||
// It can only be unpublished if it is published
|
// It can only be unpublished if it is published
|
||||||
anyResult |= changeState(publishedDir, recordingId, state);
|
changeState(publishedDir, recordingId, state);
|
||||||
} else if (state.equals(Recording.STATE_DELETED)) {
|
} else if (state.equals(Recording.STATE_DELETED)) {
|
||||||
// It can be deleted from any state
|
// It can be deleted from any state
|
||||||
anyResult |= changeState(publishedDir, recordingId, state);
|
changeState(publishedDir, recordingId, state);
|
||||||
anyResult |= changeState(unpublishedDir, recordingId, state);
|
changeState(unpublishedDir, recordingId, state);
|
||||||
}
|
}
|
||||||
return anyResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean changeState(String path, String recordingId, String state) {
|
private void changeState(String path, String recordingId, String state) {
|
||||||
String[] format = getPlaybackFormats(path);
|
String[] format = getPlaybackFormats(path);
|
||||||
boolean anyResult = false;
|
|
||||||
for (int i = 0; i < format.length; i++) {
|
for (int i = 0; i < format.length; i++) {
|
||||||
List<File> recordings = getDirectories(path + File.separatorChar + format[i]);
|
List<File> recordings = getDirectories(path + File.separatorChar + format[i]);
|
||||||
for (int f = 0; f < recordings.size(); f++) {
|
for (int f = 0; f < recordings.size(); f++) {
|
||||||
if (recordings.get(f).getName().equalsIgnoreCase(recordingId)) {
|
if (recordings.get(f).getName().equalsIgnoreCase(recordingId)) {
|
||||||
Recording r = getRecordingInfo(recordings.get(f));
|
File dest;
|
||||||
if (r != null) {
|
if (state.equals(Recording.STATE_PUBLISHED)) {
|
||||||
File dest;
|
dest = new File(publishedDir + File.separatorChar + format[i]);
|
||||||
if (state.equals(Recording.STATE_PUBLISHED)) {
|
RecordingService.publishRecording(dest, recordingId, recordings.get(f), format[i]);
|
||||||
dest = new File(publishedDir + File.separatorChar + format[i]);
|
} else if (state.equals(Recording.STATE_UNPUBLISHED)) {
|
||||||
} else if (state.equals(Recording.STATE_UNPUBLISHED)) {
|
dest = new File(unpublishedDir + File.separatorChar + format[i]);
|
||||||
dest = new File(unpublishedDir + File.separatorChar + format[i]);
|
RecordingService.unpublishRecording(dest, recordingId, recordings.get(f), format[i]);
|
||||||
} else if (state.equals(Recording.STATE_DELETED)) {
|
} else if (state.equals(Recording.STATE_DELETED)) {
|
||||||
dest = new File(deletedDir + File.separatorChar + format[i]);
|
dest = new File(deletedDir + File.separatorChar + format[i]);
|
||||||
} else {
|
RecordingService.deleteRecording(dest, recordingId, recordings.get(f), format[i]);
|
||||||
log.debug(String.format("State: %s, is not supported", state));
|
} else {
|
||||||
return anyResult;
|
log.debug(String.format("State: %s, is not supported", state));
|
||||||
}
|
return;
|
||||||
if (!dest.exists())
|
|
||||||
dest.mkdirs();
|
|
||||||
boolean moved = recordings.get(f).renameTo(new File(dest, recordings.get(f).getName()));
|
|
||||||
if (moved) {
|
|
||||||
log.debug("Recording successfully moved!");
|
|
||||||
r.setState(state);
|
|
||||||
r.setPublished(state.equals(Recording.STATE_PUBLISHED));
|
|
||||||
if (state.equals(Recording.STATE_DELETED)) {
|
|
||||||
r.setPlaybackFormat(null);
|
|
||||||
deleteRecording(recordingId, deletedDir);
|
|
||||||
}
|
|
||||||
recordingServiceHelper.writeRecordingInfo(dest.getAbsolutePath() + File.separatorChar + recordings.get(f).getName(), r);
|
|
||||||
sendRedisEvent(r.getId(), r.getId(), r.getExternalMeetingId(), format[i], state);
|
|
||||||
log.debug(String.format("Recording successfully %s!", state));
|
|
||||||
} else {
|
|
||||||
log.debug("Recording was not moved");
|
|
||||||
}
|
|
||||||
anyResult |= moved;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return anyResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendRedisEvent(String recordId, String meetingId, String externalMeetingId, String format, String state) {
|
public static void publishRecording(File destDir, String recordingId, File recordingDir, String format) {
|
||||||
log.debug("Sending Redis event for meeting {} {}", meetingId, format);
|
File metadataXml = RecordingMetadataReaderHelper.getMetadataXmlLocation(recordingDir.getPath());
|
||||||
if (state.equals(Recording.STATE_PUBLISHED)) {
|
RecordingMetadata r = RecordingMetadataReaderHelper.getRecordingMetadata(metadataXml);
|
||||||
messagingService.publishRecording(recordId, meetingId, externalMeetingId, format, true);
|
if (r != null) {
|
||||||
} else if (state.equals(Recording.STATE_UNPUBLISHED)) {
|
if (!destDir.exists()) destDir.mkdirs();
|
||||||
messagingService.publishRecording(recordId, meetingId, externalMeetingId, format, false);
|
|
||||||
} else if (state.equals(Recording.STATE_DELETED)) {
|
try {
|
||||||
messagingService.deleteRecording(recordId, meetingId, externalMeetingId, format);
|
FileUtils.moveDirectory(recordingDir, new File(destDir.getPath() + File.separatorChar + recordingId));
|
||||||
} else {
|
|
||||||
log.debug("No event for {}", state);
|
r.setState(Recording.STATE_PUBLISHED);
|
||||||
|
r.setPublished(true);
|
||||||
|
|
||||||
|
File medataXmlFile = RecordingMetadataReaderHelper.getMetadataXmlLocation(
|
||||||
|
destDir.getAbsolutePath() + File.separatorChar + recordingId);
|
||||||
|
|
||||||
|
// Process the changes by saving the recording into metadata.xml
|
||||||
|
RecordingMetadataReaderHelper.saveRecordingMetadata(medataXmlFile, r);
|
||||||
|
//Recording rec = recordingServiceHelper.getRecordingInfo(recordingDir);
|
||||||
|
//messagingService.publishRecording(rec.getId(), rec.getId(), rec.getExternalMeetingId(), format, true);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Failed to publish recording : " + recordingId, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void unpublishRecording(File destDir, String recordingId, File recordingDir, String format) {
|
||||||
|
File metadataXml = RecordingMetadataReaderHelper.getMetadataXmlLocation(recordingDir.getPath());
|
||||||
|
|
||||||
|
RecordingMetadata r = RecordingMetadataReaderHelper.getRecordingMetadata(metadataXml);
|
||||||
|
if (r != null) {
|
||||||
|
if (!destDir.exists()) destDir.mkdirs();
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileUtils.moveDirectory(recordingDir, new File(destDir.getPath() + File.separatorChar + recordingId));
|
||||||
|
r.setState(Recording.STATE_UNPUBLISHED);
|
||||||
|
r.setPublished(false);
|
||||||
|
|
||||||
|
File medataXmlFile = RecordingMetadataReaderHelper.getMetadataXmlLocation(
|
||||||
|
destDir.getAbsolutePath() + File.separatorChar + recordingId);
|
||||||
|
|
||||||
|
// Process the changes by saving the recording into metadata.xml
|
||||||
|
RecordingMetadataReaderHelper.saveRecordingMetadata(medataXmlFile, r);
|
||||||
|
//Recording rec = recordingServiceHelper.getRecordingInfo(recordingDir);
|
||||||
|
//messagingService.publishRecording(rec.getId(), rec.getId(), rec.getExternalMeetingId(), format, false);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Failed to unpublish recording : " + recordingId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void deleteRecording(File destDir, String recordingId, File recordingDir, String format) {
|
||||||
|
File metadataXml = RecordingMetadataReaderHelper.getMetadataXmlLocation(recordingDir.getPath());
|
||||||
|
|
||||||
|
RecordingMetadata r = RecordingMetadataReaderHelper.getRecordingMetadata(metadataXml);
|
||||||
|
if (r != null) {
|
||||||
|
if (!destDir.exists()) destDir.mkdirs();
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileUtils.moveDirectory(recordingDir, new File(destDir.getPath() + File.separatorChar + recordingId));
|
||||||
|
r.setState(Recording.STATE_DELETED);
|
||||||
|
r.setPublished(false);
|
||||||
|
|
||||||
|
File medataXmlFile = RecordingMetadataReaderHelper.getMetadataXmlLocation(
|
||||||
|
destDir.getAbsolutePath() + File.separatorChar + recordingId);
|
||||||
|
|
||||||
|
// Process the changes by saving the recording into metadata.xml
|
||||||
|
RecordingMetadataReaderHelper.saveRecordingMetadata(medataXmlFile, r);
|
||||||
|
//Recording rec = recordingServiceHelper.getRecordingInfo(recordingDir);
|
||||||
|
//messagingService.deleteRecording(rec.getId(), rec.getId(), rec.getExternalMeetingId(), format);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Failed to delete recording : " + recordingId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private List<File> getAllDirectories(String state) {
|
private List<File> getAllDirectories(String state) {
|
||||||
List<File> allDirectories = new ArrayList<File>();
|
List<File> allDirectories = new ArrayList<File>();
|
||||||
|
|
||||||
@ -436,22 +552,8 @@ public class RecordingService {
|
|||||||
Map<String,File> recsIndexed = indexRecordings(recs);
|
Map<String,File> recsIndexed = indexRecordings(recs);
|
||||||
if ( recsIndexed.containsKey(recordID) ) {
|
if ( recsIndexed.containsKey(recordID) ) {
|
||||||
File recFile = recsIndexed.get(recordID);
|
File recFile = recsIndexed.get(recordID);
|
||||||
Recording rec = getRecordingInfo(recFile);
|
File metadataXml = RecordingMetadataReaderHelper.getMetadataXmlLocation(recFile.getPath());
|
||||||
if (rec != null) {
|
updateRecordingMetadata(metadataXml, metaParams, metadataXml);
|
||||||
for (Map.Entry<String,String> meta : metaParams.entrySet()) {
|
|
||||||
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 {
|
|
||||||
// As it doesn't have a value, if it exists delete it
|
|
||||||
if ( rec.containsMetadata(meta.getKey()) ) {
|
|
||||||
rec.deleteMetadata(meta.getKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Process the changes by saving the recording into metadata.xml
|
|
||||||
recordingServiceHelper.writeRecordingInfo(recFile.getAbsolutePath(), rec);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -459,6 +561,27 @@ public class RecordingService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void updateRecordingMetadata(File srxMetadataXml, Map<String,String> metaParams, File destMetadataXml) {
|
||||||
|
RecordingMetadata rec = RecordingMetadataReaderHelper.getRecordingMetadata(srxMetadataXml);
|
||||||
|
if (rec != null && rec.getMeta() != null) {
|
||||||
|
for (Map.Entry<String,String> meta : metaParams.entrySet()) {
|
||||||
|
if ( !"".equals(meta.getValue()) ) {
|
||||||
|
// As it has a value, if the meta parameter exists update it, otherwise add it
|
||||||
|
rec.getMeta().set(meta.getKey(), meta.getValue());
|
||||||
|
} else {
|
||||||
|
// As it doesn't have a value, if it exists delete it
|
||||||
|
if ( rec.getMeta().containsKey(meta.getKey()) ) {
|
||||||
|
rec.getMeta().remove(meta.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the changes by saving the recording into metadata.xml
|
||||||
|
RecordingMetadataReaderHelper.saveRecordingMetadata(destMetadataXml, rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private Map<String,File> indexRecordings(List<File> recs) {
|
private Map<String,File> indexRecordings(List<File> recs) {
|
||||||
Map<String,File> indexedRecs = new HashMap<String,File>();
|
Map<String,File> indexedRecs = new HashMap<String,File>();
|
||||||
|
|
||||||
@ -492,7 +615,7 @@ public class RecordingService {
|
|||||||
return baseDir;
|
return baseDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMessagingService(MessagingService service) {
|
//public void setMessagingService(MessagingService service) {
|
||||||
messagingService = service;
|
// messagingService = service;
|
||||||
}
|
//}
|
||||||
}
|
}
|
44
bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Breakout.java
Executable file
44
bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Breakout.java
Executable file
@ -0,0 +1,44 @@
|
|||||||
|
package org.bigbluebutton.api.domain;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;
|
||||||
|
|
||||||
|
|
||||||
|
public class Breakout {
|
||||||
|
/**
|
||||||
|
* <breakout parentMeetingId="f3ffe06acedf425565cc024c8ebe89a6552e8782-1489172964374" sequence="2" meetingId="f2041d123b6a4b994e7ad87ee9d348496a73472c-1489173065780"/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private String parentMeetingId = "";
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private int sequence = 0;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private String meetingId = "";
|
||||||
|
|
||||||
|
public void setParentMeetingId(String parentMeetingId) {
|
||||||
|
this.parentMeetingId = parentMeetingId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getParentMeetingId() {
|
||||||
|
return parentMeetingId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSequence(int sequence) {
|
||||||
|
this.sequence = sequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSequence() {
|
||||||
|
return sequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMeetingId(String meetingId) {
|
||||||
|
this.meetingId = meetingId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMeetingId() {
|
||||||
|
return meetingId;
|
||||||
|
}
|
||||||
|
}
|
18
bbb-common-web/src/main/java/org/bigbluebutton/api/domain/BreakoutRoom.java
Executable file
18
bbb-common-web/src/main/java/org/bigbluebutton/api/domain/BreakoutRoom.java
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
package org.bigbluebutton.api.domain;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;
|
||||||
|
|
||||||
|
|
||||||
|
public class BreakoutRoom {
|
||||||
|
|
||||||
|
@JacksonXmlText
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
package org.bigbluebutton.api.domain;
|
||||||
|
|
||||||
|
public class Download {
|
||||||
|
private String format;
|
||||||
|
private String url;
|
||||||
|
private int length;
|
||||||
|
private String md5;
|
||||||
|
private String key;
|
||||||
|
private String size;
|
||||||
|
public Download(String format, String url, String md5, String key, String size, int length) {
|
||||||
|
this.format = format;
|
||||||
|
this.url = url;
|
||||||
|
this.length = length;
|
||||||
|
this.md5 = md5;
|
||||||
|
this.size = size;
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
public String getFormat() {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
public void setFormat(String format) {
|
||||||
|
this.format = format;
|
||||||
|
}
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
public int getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
public void setLength(int length) {
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
public void setMd5(String md5) {
|
||||||
|
this.md5 = md5;
|
||||||
|
}
|
||||||
|
public String getMd5() {
|
||||||
|
return md5;
|
||||||
|
}
|
||||||
|
public void setSize(String size) {
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
public String getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
public void setKey(String key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
21
bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Extensions.java
Executable file
21
bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Extensions.java
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
package org.bigbluebutton.api.domain;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ritz on 2017-03-11.
|
||||||
|
*/
|
||||||
|
public class Extensions {
|
||||||
|
@JacksonXmlProperty(localName = "preview")
|
||||||
|
@JacksonXmlElementWrapper(useWrapping = false)
|
||||||
|
private Preview preview;
|
||||||
|
|
||||||
|
public void setPreview(Preview preview) {
|
||||||
|
this.preview = preview;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Preview getPreview() {
|
||||||
|
return preview;
|
||||||
|
}
|
||||||
|
}
|
59
bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Image.java
Executable file
59
bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Image.java
Executable file
@ -0,0 +1,59 @@
|
|||||||
|
package org.bigbluebutton.api.domain;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;
|
||||||
|
|
||||||
|
public class Image {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <image width="176" height="136" alt="Welcome to">
|
||||||
|
* http://192.168.23.22/presentation/32ee8bcccfad34f85c58a12f87fc4268130a4fd3-1489173065780/presentation/743dd59a958334b4cdcdaa302846d0c0eadcf9ff-1489173070800/thumbnails/thumb-1.png
|
||||||
|
* </image>
|
||||||
|
*/
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private String width;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private String height;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private String alt;
|
||||||
|
|
||||||
|
@JacksonXmlText
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
|
||||||
|
public void setWidth(String width) {
|
||||||
|
this.width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeight(String height) {
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlt(String alt) {
|
||||||
|
this.alt = alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlt() {
|
||||||
|
return alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -19,20 +19,14 @@
|
|||||||
|
|
||||||
package org.bigbluebutton.api.domain;
|
package org.bigbluebutton.api.domain;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
|
|
||||||
import org.apache.commons.lang.RandomStringUtils;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class Meeting {
|
public class Meeting {
|
||||||
private static Logger log = LoggerFactory.getLogger(Meeting.class);
|
|
||||||
|
|
||||||
private static final long MILLIS_IN_A_MINUTE = 60000;
|
private static final long MILLIS_IN_A_MINUTE = 60000;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
@ -57,6 +51,7 @@ public class Meeting {
|
|||||||
private boolean record;
|
private boolean record;
|
||||||
private boolean autoStartRecording = false;
|
private boolean autoStartRecording = false;
|
||||||
private boolean allowStartStopRecording = false;
|
private boolean allowStartStopRecording = false;
|
||||||
|
private boolean webcamsOnlyForModerator = false;
|
||||||
private String dialNumber;
|
private String dialNumber;
|
||||||
private String defaultAvatarURL;
|
private String defaultAvatarURL;
|
||||||
private String defaultConfigToken;
|
private String defaultConfigToken;
|
||||||
@ -67,6 +62,7 @@ public class Meeting {
|
|||||||
private final ConcurrentMap<String, Long> registeredUsers;
|
private final ConcurrentMap<String, Long> registeredUsers;
|
||||||
private final ConcurrentMap<String, Config> configs;
|
private final ConcurrentMap<String, Config> configs;
|
||||||
private final Boolean isBreakout;
|
private final Boolean isBreakout;
|
||||||
|
private final List<String> breakoutRooms = new ArrayList();
|
||||||
|
|
||||||
private long lastUserLeftOn = 0;
|
private long lastUserLeftOn = 0;
|
||||||
|
|
||||||
@ -82,6 +78,7 @@ public class Meeting {
|
|||||||
record = builder.record;
|
record = builder.record;
|
||||||
autoStartRecording = builder.autoStartRecording;
|
autoStartRecording = builder.autoStartRecording;
|
||||||
allowStartStopRecording = builder.allowStartStopRecording;
|
allowStartStopRecording = builder.allowStartStopRecording;
|
||||||
|
webcamsOnlyForModerator = builder.webcamsOnlyForModerator;
|
||||||
duration = builder.duration;
|
duration = builder.duration;
|
||||||
webVoice = builder.webVoice;
|
webVoice = builder.webVoice;
|
||||||
telVoice = builder.telVoice;
|
telVoice = builder.telVoice;
|
||||||
@ -100,6 +97,14 @@ public class Meeting {
|
|||||||
configs = new ConcurrentHashMap<String, Config>();
|
configs = new ConcurrentHashMap<String, Config>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addBreakoutRoom(String meetingId) {
|
||||||
|
breakoutRooms.add(meetingId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getBreakoutRooms() {
|
||||||
|
return breakoutRooms;
|
||||||
|
}
|
||||||
|
|
||||||
public String storeConfig(boolean defaultConfig, String config) {
|
public String storeConfig(boolean defaultConfig, String config) {
|
||||||
String token = RandomStringUtils.randomAlphanumeric(8);
|
String token = RandomStringUtils.randomAlphanumeric(8);
|
||||||
while (configs.containsKey(token)) {
|
while (configs.containsKey(token)) {
|
||||||
@ -267,6 +272,10 @@ public class Meeting {
|
|||||||
return allowStartStopRecording;
|
return allowStartStopRecording;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getWebcamsOnlyForModerator() {
|
||||||
|
return webcamsOnlyForModerator;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasUserJoined() {
|
public boolean hasUserJoined() {
|
||||||
return userHasJoined;
|
return userHasJoined;
|
||||||
}
|
}
|
||||||
@ -397,7 +406,8 @@ public class Meeting {
|
|||||||
private int maxUsers;
|
private int maxUsers;
|
||||||
private boolean record;
|
private boolean record;
|
||||||
private boolean autoStartRecording;
|
private boolean autoStartRecording;
|
||||||
private boolean allowStartStopRecording;
|
private boolean allowStartStopRecording;
|
||||||
|
private boolean webcamsOnlyForModerator;
|
||||||
private String moderatorPass;
|
private String moderatorPass;
|
||||||
private String viewerPass;
|
private String viewerPass;
|
||||||
private int duration;
|
private int duration;
|
||||||
@ -448,6 +458,11 @@ public class Meeting {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder withWebcamsOnlyForModerator(boolean only) {
|
||||||
|
this.webcamsOnlyForModerator = only;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder withWebVoice(String w) {
|
public Builder withWebVoice(String w) {
|
||||||
this.webVoice = w;
|
this.webVoice = w;
|
||||||
return this;
|
return this;
|
53
bbb-common-web/src/main/java/org/bigbluebutton/api/domain/MeetingInfo.java
Executable file
53
bbb-common-web/src/main/java/org/bigbluebutton/api/domain/MeetingInfo.java
Executable file
@ -0,0 +1,53 @@
|
|||||||
|
package org.bigbluebutton.api.domain;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||||
|
|
||||||
|
public class MeetingInfo {
|
||||||
|
/**
|
||||||
|
* <meeting id="random-2810069" name="random-2810069" breakout="false"/>
|
||||||
|
*/
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private String externalId;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true)
|
||||||
|
private boolean breakout;
|
||||||
|
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExternalId(String externalId) {
|
||||||
|
this.externalId = externalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExternalId() {
|
||||||
|
return externalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBreakout(boolean breakout) {
|
||||||
|
this.breakout = breakout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBreakout() {
|
||||||
|
return breakout;
|
||||||
|
}
|
||||||
|
}
|
31
bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Metadata.java
Executable file
31
bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Metadata.java
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
package org.bigbluebutton.api.domain;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAnyGetter;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
@JacksonXmlRootElement(localName = "meta")
|
||||||
|
public class Metadata {
|
||||||
|
private Map<String,String> map = new TreeMap<String,String>();
|
||||||
|
|
||||||
|
@JsonAnyGetter
|
||||||
|
public Map<String, String> get() {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonAnySetter
|
||||||
|
public void set(String name, String value) {
|
||||||
|
map.put(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(String key) {
|
||||||
|
map.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsKey(String key) {
|
||||||
|
return map.containsKey(key);
|
||||||
|
}
|
||||||
|
}
|
18
bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Preview.java
Executable file
18
bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Preview.java
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
package org.bigbluebutton.api.domain;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||||
|
|
||||||
|
public class Preview {
|
||||||
|
@JacksonXmlElementWrapper(localName = "images")
|
||||||
|
@JacksonXmlProperty(localName = "image")
|
||||||
|
private Image[] images;
|
||||||
|
|
||||||
|
public void setImages(Image[] images) {
|
||||||
|
this.images = images;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image[] getImages() {
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
}
|
@ -35,6 +35,7 @@ public class Recording {
|
|||||||
private boolean published;
|
private boolean published;
|
||||||
private String startTime;
|
private String startTime;
|
||||||
private String endTime;
|
private String endTime;
|
||||||
|
private String numParticipants;
|
||||||
private String rawSize;
|
private String rawSize;
|
||||||
private Map<String, String> metadata = new TreeMap<String, String>();
|
private Map<String, String> metadata = new TreeMap<String, String>();
|
||||||
private List<Playback> playbacks=new ArrayList<Playback>();
|
private List<Playback> playbacks=new ArrayList<Playback>();
|
||||||
@ -61,7 +62,7 @@ public class Recording {
|
|||||||
public static final String STATE_PUBLISHED = "published";
|
public static final String STATE_PUBLISHED = "published";
|
||||||
public static final String STATE_UNPUBLISING = "unpublishing";
|
public static final String STATE_UNPUBLISING = "unpublishing";
|
||||||
public static final String STATE_UNPUBLISHED = "unpublished";
|
public static final String STATE_UNPUBLISHED = "unpublished";
|
||||||
public static final String STATE_DELETING = "deleting";
|
public static final String STATE_DELETING = "deleting";
|
||||||
public static final String STATE_DELETED = "deleted";
|
public static final String STATE_DELETED = "deleted";
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
@ -104,6 +105,14 @@ public class Recording {
|
|||||||
return endTime;
|
return endTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setNumParticipants(String numParticipants) {
|
||||||
|
this.numParticipants = numParticipants;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNumParticipants() {
|
||||||
|
return numParticipants;
|
||||||
|
}
|
||||||
|
|
||||||
public void setEndTime(String endTime) {
|
public void setEndTime(String endTime) {
|
||||||
this.endTime = convertOldDateFormat(endTime);
|
this.endTime = convertOldDateFormat(endTime);
|
||||||
}
|
}
|
207
bbb-common-web/src/main/java/org/bigbluebutton/api/domain/RecordingMetadata.java
Executable file
207
bbb-common-web/src/main/java/org/bigbluebutton/api/domain/RecordingMetadata.java
Executable file
@ -0,0 +1,207 @@
|
|||||||
|
package org.bigbluebutton.api.domain;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
@JacksonXmlRootElement(localName = "recording")
|
||||||
|
public class RecordingMetadata {
|
||||||
|
/**
|
||||||
|
* <recording>
|
||||||
|
<id>32ee8bcccfad34f85c58a12f87fc4268130a4fd3-1489173065780</id>
|
||||||
|
<state>published</state>
|
||||||
|
<published>true</published>
|
||||||
|
<start_time>1489173065780</start_time>
|
||||||
|
<end_time>1489173199386</end_time>
|
||||||
|
<breakout parentMeetingId="f3ffe06acedf425565cc024c8ebe89a6552e8782-1489172964374" sequence="2" meetingId="f2041d123b6a4b994e7ad87ee9d348496a73472c-1489173065780"/>
|
||||||
|
<meta>
|
||||||
|
<meetingId>f2041d123b6a4b994e7ad87ee9d348496a73472c-1489173065780</meetingId>
|
||||||
|
<meetingName>random-2810069 (Room - 2)</meetingName>
|
||||||
|
<isBreakout>true</isBreakout>
|
||||||
|
</meta>
|
||||||
|
<playback>
|
||||||
|
<format>presentation</format>
|
||||||
|
<link>http://192.168.23.22/playback/presentation/0.9.0/playback.html?meetingId=32ee8bcccfad34f85c58a12f87fc4268130a4fd3-1489173065780</link>
|
||||||
|
<processing_time>9841</processing_time>
|
||||||
|
<duration>126376</duration>
|
||||||
|
<extensions>
|
||||||
|
<preview>
|
||||||
|
<images>
|
||||||
|
<image width="176" height="136" alt="Welcome to">http://192.168.23.22/presentation/32ee8bcccfad34f85c58a12f87fc4268130a4fd3-1489173065780/presentation/743dd59a958334b4cdcdaa302846d0c0eadcf9ff-1489173070800/thumbnails/thumb-1.png</image>
|
||||||
|
</images>
|
||||||
|
</preview>
|
||||||
|
</extensions>
|
||||||
|
</playback>
|
||||||
|
</recording>
|
||||||
|
*/
|
||||||
|
|
||||||
|
private String metadataXml;
|
||||||
|
private Boolean processingError = false;
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
private String state;
|
||||||
|
private boolean published;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(localName = "start_time")
|
||||||
|
private String startTime;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(localName = "end_time")
|
||||||
|
private String endTime;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(localName = "participants")
|
||||||
|
private int participants;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(localName = "meeting")
|
||||||
|
private MeetingInfo meetingInfo;
|
||||||
|
|
||||||
|
private String meetingId = "";
|
||||||
|
|
||||||
|
private String meetingName = "";
|
||||||
|
|
||||||
|
private Breakout breakout;
|
||||||
|
|
||||||
|
@JacksonXmlElementWrapper(localName = "breakoutRooms")
|
||||||
|
@JacksonXmlProperty(localName = "breakoutRoom")
|
||||||
|
private BreakoutRoom[] breakoutRooms;
|
||||||
|
|
||||||
|
private Metadata meta;
|
||||||
|
|
||||||
|
private RecordingMetadataPlayback playback;
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMeetingId() {
|
||||||
|
MeetingInfo info = getMeeting();
|
||||||
|
if (info == null) {
|
||||||
|
// return the recording id
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
return info.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMeetingName() {
|
||||||
|
MeetingInfo info = getMeeting();
|
||||||
|
if (info == null) {
|
||||||
|
return getMeta().get().get("meetingName");
|
||||||
|
}
|
||||||
|
return info.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isBreakout() {
|
||||||
|
MeetingInfo info = getMeeting();
|
||||||
|
if (info == null) {
|
||||||
|
return Boolean.parseBoolean(getMeta().get().get("isBreakout"));
|
||||||
|
}
|
||||||
|
return info.isBreakout();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(String state) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPublished(boolean published) {
|
||||||
|
this.published = published;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getPublished() {
|
||||||
|
return published;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartTime(String startTime) {
|
||||||
|
this.startTime = startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStartTime() {
|
||||||
|
return startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndTime(String endTime) {
|
||||||
|
this.endTime = endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEndTime() {
|
||||||
|
return endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParticipants(int participants) {
|
||||||
|
this.participants = participants;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getParticipants() {
|
||||||
|
return participants;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMeeting(MeetingInfo meetingInfo) {
|
||||||
|
this.meetingInfo = meetingInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MeetingInfo getMeeting() {
|
||||||
|
return meetingInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBreakout(Breakout breakout) {
|
||||||
|
this.breakout = breakout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Breakout getBreakout() {
|
||||||
|
return breakout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBreakoutRooms(BreakoutRoom[] breakoutRooms) {
|
||||||
|
this.breakoutRooms = breakoutRooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BreakoutRoom[] getBreakoutRooms() {
|
||||||
|
return breakoutRooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMeta(Metadata meta) {
|
||||||
|
this.meta = meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Metadata getMeta() {
|
||||||
|
return meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordingMetadataPlayback getPlayback() {
|
||||||
|
return playback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMetadataXml(String metadataXml) {
|
||||||
|
this.metadataXml = metadataXml;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMetadataXml() {
|
||||||
|
return metadataXml;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProcessingError(Boolean error) {
|
||||||
|
processingError = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean hasError() {
|
||||||
|
return processingError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer calculateDuration() {
|
||||||
|
if ((endTime == null) || (endTime == "") || (startTime == null) || (startTime == "")) return 0;
|
||||||
|
|
||||||
|
int start = (int) Math.ceil((Long.parseLong(startTime)) / 60000.0);
|
||||||
|
int end = (int) Math.ceil((Long.parseLong(endTime)) / 60000.0);
|
||||||
|
|
||||||
|
return end - start;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package org.bigbluebutton.api.domain;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
||||||
|
|
||||||
|
@JacksonXmlRootElement(localName = "playback")
|
||||||
|
public class RecordingMetadataPlayback {
|
||||||
|
private String format;
|
||||||
|
private String link;
|
||||||
|
|
||||||
|
@JacksonXmlProperty(localName = "processing_time")
|
||||||
|
private Long processingTime = 0L;
|
||||||
|
|
||||||
|
private Long duration = 0L;
|
||||||
|
|
||||||
|
private Extensions extensions;
|
||||||
|
|
||||||
|
public void setFormat(String format) {
|
||||||
|
this.format = format;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFormat() {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLink(String link) {
|
||||||
|
this.link = link;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLink() {
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProcessingTime(Long processingTime) {
|
||||||
|
this.processingTime = processingTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getProcessingTime() {
|
||||||
|
return processingTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDuration(Long duration) {
|
||||||
|
this.duration = duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDuration() {
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long calculateDuration() {
|
||||||
|
if (duration > 0) {
|
||||||
|
// convert to minutes
|
||||||
|
return duration / 60000;
|
||||||
|
} else {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExtensions(Extensions extensions) {
|
||||||
|
this.extensions = extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Extensions getExtensions() {
|
||||||
|
return extensions;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package org.bigbluebutton.api.util;
|
||||||
|
|
||||||
|
|
||||||
|
import org.bigbluebutton.api.domain.Meeting;
|
||||||
|
|
||||||
|
public class MeetingResponseDetail {
|
||||||
|
|
||||||
|
private final String createdOn;
|
||||||
|
private final Meeting meeting;
|
||||||
|
|
||||||
|
public MeetingResponseDetail(String createdOn, Meeting meeting) {
|
||||||
|
this.createdOn = createdOn;
|
||||||
|
this.meeting = meeting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreatedOn() {
|
||||||
|
return createdOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Meeting getMeeting() {
|
||||||
|
return meeting;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package org.bigbluebutton.api.util;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class MeetingsResponse {
|
||||||
|
|
||||||
|
public final Collection<MeetingResponseDetail> meetings;
|
||||||
|
|
||||||
|
public MeetingsResponse(Collection<MeetingResponseDetail> meetings) {
|
||||||
|
this.meetings = meetings;
|
||||||
|
}
|
||||||
|
}
|
26
bbb-common-web/src/main/java/org/bigbluebutton/api/util/ParamsUtil.java
Executable file
26
bbb-common-web/src/main/java/org/bigbluebutton/api/util/ParamsUtil.java
Executable file
@ -0,0 +1,26 @@
|
|||||||
|
package org.bigbluebutton.api.util;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class ParamsUtil {
|
||||||
|
private static final Pattern VALID_ID_PATTERN = Pattern.compile("[a-zA-Z][a-zA-Z0-9- ]*$");
|
||||||
|
|
||||||
|
public static final String invalidChars = ",";
|
||||||
|
|
||||||
|
public static String stripControlChars(String text) {
|
||||||
|
return text.replaceAll("\\p{Cc}", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isValidMeetingId(String meetingId) {
|
||||||
|
//return VALID_ID_PATTERN.matcher(meetingId).matches();
|
||||||
|
return !containsChar(meetingId, invalidChars);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean containsChar(String text, String chars) {
|
||||||
|
return StringUtils.containsAny(text, chars);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
package org.bigbluebutton.api.util;
|
||||||
|
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule;
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||||
|
import org.bigbluebutton.api.domain.RecordingMetadata;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
|
||||||
|
import javax.xml.stream.*;
|
||||||
|
import java.io.*;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class RecordingMetadataReaderHelper {
|
||||||
|
private static Logger log = LoggerFactory.getLogger(RecordingMetadataReaderHelper.class);
|
||||||
|
|
||||||
|
public static String inputStreamToString(InputStream is) throws IOException {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(is));
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
sb.append(line);
|
||||||
|
}
|
||||||
|
br.close();
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RecordingMetadata getRecordingMetadata(File metadataXml) {
|
||||||
|
XMLInputFactory factory = XMLInputFactory.newInstance();
|
||||||
|
|
||||||
|
JacksonXmlModule module = new JacksonXmlModule();
|
||||||
|
// and then configure, for example:
|
||||||
|
module.setDefaultUseWrapper(false);
|
||||||
|
|
||||||
|
XmlMapper mapper = new XmlMapper(module);
|
||||||
|
|
||||||
|
//Reading from xml file and creating XMLStreamReader
|
||||||
|
XMLStreamReader reader = null;
|
||||||
|
RecordingMetadata recMeta = null;
|
||||||
|
try {
|
||||||
|
reader = factory.createXMLStreamReader(new FileInputStream(metadataXml));
|
||||||
|
recMeta = mapper.readValue(reader, RecordingMetadata.class);
|
||||||
|
recMeta.setMetadataXml(metadataXml.getParentFile().getName());
|
||||||
|
} catch (XMLStreamException e) {
|
||||||
|
log.error("Failed to read metadata xml for recording: " + metadataXml.getAbsolutePath(), e);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
log.error("File not found: " + metadataXml.getAbsolutePath(), e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("IOException on " + metadataXml.getAbsolutePath(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recMeta == null) {
|
||||||
|
recMeta = new RecordingMetadata();
|
||||||
|
recMeta.setMetadataXml(metadataXml.getParentFile().getName());
|
||||||
|
recMeta.setProcessingError(true);
|
||||||
|
}
|
||||||
|
return recMeta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File getMetadataXmlLocation(String destDir) {
|
||||||
|
return new File(destDir + File.separatorChar + "metadata.xml");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void saveRecordingMetadata(File metadataXml, RecordingMetadata recordingMetadata) {
|
||||||
|
|
||||||
|
//XMLOutputFactory factory = XMLOutputFactory.newInstance();
|
||||||
|
JacksonXmlModule module = new JacksonXmlModule();
|
||||||
|
module.setDefaultUseWrapper(false);
|
||||||
|
|
||||||
|
XmlMapper mapper = new XmlMapper(module);
|
||||||
|
|
||||||
|
//Reading from xml file and creating XMLStreamReader
|
||||||
|
//XMLStreamWriter writer = null;
|
||||||
|
try {
|
||||||
|
//writer = factory.createXMLStreamWriter(new FileOutputStream(metadataXml));
|
||||||
|
mapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||||
|
mapper.writeValue(metadataXml, recordingMetadata);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
log.error("File not found: " + metadataXml.getAbsolutePath(), e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("IOException on " + metadataXml.getAbsolutePath(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
124
bbb-common-web/src/main/java/org/bigbluebutton/api/util/ResponseBuilder.java
Executable file
124
bbb-common-web/src/main/java/org/bigbluebutton/api/util/ResponseBuilder.java
Executable file
@ -0,0 +1,124 @@
|
|||||||
|
package org.bigbluebutton.api.util;
|
||||||
|
|
||||||
|
import org.bigbluebutton.api.domain.Meeting;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import freemarker.template.*;
|
||||||
|
import org.bigbluebutton.api.domain.RecordingMetadata;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class ResponseBuilder {
|
||||||
|
private static Logger log = LoggerFactory.getLogger(ResponseBuilder.class);
|
||||||
|
|
||||||
|
Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
|
||||||
|
|
||||||
|
public ResponseBuilder(File templatesLoc) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
cfg.setDirectoryForTemplateLoading(templatesLoc);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
cfg.setDefaultEncoding("UTF-8");
|
||||||
|
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
|
||||||
|
cfg.setLogTemplateExceptions(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String formatPrettyDate(Long timestamp) {
|
||||||
|
return new Date(timestamp).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String buildGetMeetingInfoResponse(Meeting meeting, String returnCode) {
|
||||||
|
String createdOn = formatPrettyDate(meeting.getCreateTime());
|
||||||
|
|
||||||
|
Template ftl = null;
|
||||||
|
try {
|
||||||
|
ftl = cfg.getTemplate("get-meeting-info.ftlx");
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Cannot find get-meeting-info.ftl template for meeting : " + meeting.getInternalId(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringWriter xmlText = new StringWriter();
|
||||||
|
|
||||||
|
Map root = new HashMap();
|
||||||
|
root.put("returnCode", returnCode);
|
||||||
|
root.put("createdOn", createdOn);
|
||||||
|
root.put("meeting", meeting);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ftl.process(root, xmlText);
|
||||||
|
} catch (TemplateException e) {
|
||||||
|
log.error("Template exception for meeting : " + meeting.getInternalId(), e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("IO exception for meeting : " + meeting.getInternalId(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return xmlText.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String buildGetMeetingsResponse(Collection<Meeting> meetings, String returnCode) {
|
||||||
|
|
||||||
|
ArrayList<MeetingResponseDetail> meetingResponseDetails = new ArrayList<MeetingResponseDetail>();
|
||||||
|
|
||||||
|
for (Meeting meeting : meetings) {
|
||||||
|
String createdOn = formatPrettyDate(meeting.getCreateTime());
|
||||||
|
MeetingResponseDetail details = new MeetingResponseDetail(createdOn, meeting);
|
||||||
|
meetingResponseDetails.add(details);
|
||||||
|
}
|
||||||
|
|
||||||
|
Template ftl = null;
|
||||||
|
try {
|
||||||
|
ftl = cfg.getTemplate("get-meetings.ftlx");
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("IO exception for get-meetings.ftlx : ", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringWriter xmlText = new StringWriter();
|
||||||
|
|
||||||
|
Map root = new HashMap();
|
||||||
|
root.put("returnCode", returnCode);
|
||||||
|
root.put("meetingDetailsList", meetingResponseDetails);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ftl.process(root, xmlText);
|
||||||
|
} catch (TemplateException e) {
|
||||||
|
log.error("Template exception : ", e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("IO exception for get-meetings.ftlx : ", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return xmlText.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String buildGetRecordingsResponse(List<RecordingMetadata> recordings, String returnCode) {
|
||||||
|
|
||||||
|
Template ftl = null;
|
||||||
|
try {
|
||||||
|
ftl = cfg.getTemplate("get-recordings.ftlx");
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("IO exception for get-recordings.ftl : ", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringWriter xmlText = new StringWriter();
|
||||||
|
|
||||||
|
Map root = new HashMap();
|
||||||
|
root.put("returnCode", returnCode);
|
||||||
|
root.put("recordings", recordings);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ftl.process(root, xmlText);
|
||||||
|
} catch (TemplateException e) {
|
||||||
|
log.error("Template exception : ", e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("IO exception for get-recordings.ftlx : ", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return xmlText.toString();
|
||||||
|
}
|
||||||
|
}
|
25
bbb-common-web/src/test/resources/breakout-room-metadata.xml
Executable file
25
bbb-common-web/src/test/resources/breakout-room-metadata.xml
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
<recording>
|
||||||
|
<id>3c97908bb2dc4f794914776d639405709479c3da-1490721543626</id>
|
||||||
|
<state>published</state>
|
||||||
|
<published>true</published>
|
||||||
|
<start_time>1490721543626</start_time>
|
||||||
|
<end_time>1490721560835</end_time>
|
||||||
|
<participants>1</participants>
|
||||||
|
|
||||||
|
<meta>
|
||||||
|
<meeting-name>grailserror</meeting-name>
|
||||||
|
<room-id>bn-19631b57</room-id>
|
||||||
|
<isBreakout>false</isBreakout>
|
||||||
|
<meetingName>grailserror</meetingName>
|
||||||
|
<gl-listed>false</gl-listed>
|
||||||
|
<gl-token>bn-19631b57-grailserror</gl-token>
|
||||||
|
<gl-webhooks-callback-url>http://localhost/b/rooms/bn-19631b57/grailserror/callback</gl-webhooks-callback-url>
|
||||||
|
<meetingId>77f6566f80654ce7dff9e14b2c01cbd99fb75abc</meetingId>
|
||||||
|
</meta>
|
||||||
|
<playback>
|
||||||
|
<format>presentation</format>
|
||||||
|
<link>http://demo.bigbluebutton.org/playback/presentation/0.9.0/playback.html?meetingId=3c97908bb2dc4f794914776d639405709479c3da-1490721543626</link>
|
||||||
|
<processing_time>20772</processing_time>
|
||||||
|
<duration>9807</duration>
|
||||||
|
</playback>
|
||||||
|
</recording>
|
79
bbb-common-web/src/test/resources/get-meeting-info.ftlx
Executable file
79
bbb-common-web/src/test/resources/get-meeting-info.ftlx
Executable file
@ -0,0 +1,79 @@
|
|||||||
|
<#compress>
|
||||||
|
<response>
|
||||||
|
<#-- Where code is a 'SUCCESS' or 'FAILED' String -->
|
||||||
|
<returncode>${returnCode}</returncode>
|
||||||
|
<meetingName>${meeting.getName()?html}</meetingName>
|
||||||
|
<meetingID>${meeting.getExternalId()?html}</meetingID>
|
||||||
|
<internalMeetingID>${meeting.getInternalId()}</internalMeetingID>
|
||||||
|
<createTime>${meeting.getCreateTime()?c}</createTime>
|
||||||
|
<createDate>${createdOn}</createDate>
|
||||||
|
<voiceBridge>${meeting.getTelVoice()}</voiceBridge>
|
||||||
|
<dialNumber>${meeting.getDialNumber()}</dialNumber>
|
||||||
|
<attendeePW>${meeting.getViewerPassword()?html}</attendeePW>
|
||||||
|
<moderatorPW>${meeting.getModeratorPassword()?html}</moderatorPW>
|
||||||
|
<running>${meeting.isRunning()?c}</running>
|
||||||
|
<duration>${meeting.getDuration()}</duration>
|
||||||
|
<hasUserJoined>${meeting.hasUserJoined()?c}</hasUserJoined>
|
||||||
|
<recording>${meeting.isRecord()?c}</recording>
|
||||||
|
<hasBeenForciblyEnded>${meeting.isForciblyEnded()?c}</hasBeenForciblyEnded>
|
||||||
|
<startTime>${meeting.getStartTime()?c}</startTime>
|
||||||
|
<endTime>${meeting.getEndTime()}</endTime>
|
||||||
|
<participantCount>${meeting.getNumUsers()}</participantCount>
|
||||||
|
<listenerCount>${meeting.getNumListenOnly()}</listenerCount>
|
||||||
|
<voiceParticipantCount>${meeting.getNumVoiceJoined()}</voiceParticipantCount>
|
||||||
|
<videoCount>${meeting.getNumVideos()}</videoCount>
|
||||||
|
<maxUsers>${meeting.getMaxUsers()}</maxUsers>
|
||||||
|
<moderatorCount>${meeting.getNumModerators()}</moderatorCount>
|
||||||
|
<attendees>
|
||||||
|
<#list meeting.getUsers() as att>
|
||||||
|
<attendee>
|
||||||
|
<userID>${att.getInternalUserId()}</userID>
|
||||||
|
<fullName>${att.getFullname()?html}</fullName>
|
||||||
|
<role>${att.getRole()}</role>
|
||||||
|
<isPresenter>${att.isPresenter()?c}</isPresenter>
|
||||||
|
<isListeningOnly>${att.isListeningOnly()?c}</isListeningOnly>
|
||||||
|
<hasJoinedVoice>${att.isVoiceJoined()?c}</hasJoinedVoice>
|
||||||
|
<hasVideo>${att.hasVideo()?c}</hasVideo>
|
||||||
|
<#if meeting.getUserCustomData(att.getExternalUserId())??>
|
||||||
|
<#assign ucd = meeting.getUserCustomData(att.getExternalUserId())>
|
||||||
|
<customdata>
|
||||||
|
<#list ucd?keys as prop>
|
||||||
|
<${(prop)?html}>${(ucd[prop])?html}</${(prop)?html}>
|
||||||
|
</#list>
|
||||||
|
</customdata>
|
||||||
|
</#if>
|
||||||
|
</attendee>
|
||||||
|
</#list>
|
||||||
|
</attendees>
|
||||||
|
<#assign m = meeting.getMetadata()>
|
||||||
|
<metadata>
|
||||||
|
<#list m?keys as prop>
|
||||||
|
<${(prop)?html}>${(m[prop])?html}</${(prop)?html}>
|
||||||
|
</#list>
|
||||||
|
</metadata>
|
||||||
|
|
||||||
|
<#if messageKey?has_content>
|
||||||
|
<messageKey>${messageKey}</messageKey>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if message?has_content>
|
||||||
|
<message>${message}</message>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<isBreakout>${meeting.isBreakout()?c}</isBreakout>
|
||||||
|
|
||||||
|
<#if meeting.isBreakout()>
|
||||||
|
<parentMeetingID>${meeting.getParentMeetingId()}</parentMeetingID>
|
||||||
|
<sequence>${meeting.getSequence()}</sequence>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#list meeting.getBreakoutRooms()>
|
||||||
|
<breakoutRooms>
|
||||||
|
<#items as room>
|
||||||
|
<breakout>${room}</breakout>
|
||||||
|
</#items>
|
||||||
|
</breakoutRooms>
|
||||||
|
</#list>
|
||||||
|
|
||||||
|
</response>
|
||||||
|
</#compress>
|
79
bbb-common-web/src/test/resources/get-meetings.ftlx
Executable file
79
bbb-common-web/src/test/resources/get-meetings.ftlx
Executable file
@ -0,0 +1,79 @@
|
|||||||
|
<#compress>
|
||||||
|
<response>
|
||||||
|
<#-- Where code is a 'SUCCESS' or 'FAILED' String -->
|
||||||
|
<returncode>${returnCode}</returncode>
|
||||||
|
<#list meetingDetailsList>
|
||||||
|
<meetings>
|
||||||
|
<#items as meetingDetail>
|
||||||
|
<#assign meeting = meetingDetail.getMeeting()>
|
||||||
|
<meeting>
|
||||||
|
<meetingName>${meeting.getName()?html}</meetingName>
|
||||||
|
<meetingID>${meeting.getExternalId()?html}</meetingID>
|
||||||
|
<internalMeetingID>${meeting.getInternalId()}</internalMeetingID>
|
||||||
|
<createTime>${meeting.getCreateTime()?c}</createTime>
|
||||||
|
<createDate>${meetingDetail.getCreatedOn()}</createDate>
|
||||||
|
<voiceBridge>${meeting.getTelVoice()}</voiceBridge>
|
||||||
|
<dialNumber>${meeting.getDialNumber()}</dialNumber>
|
||||||
|
<attendeePW>${meeting.getViewerPassword()?html}</attendeePW>
|
||||||
|
<moderatorPW>${meeting.getModeratorPassword()?html}</moderatorPW>
|
||||||
|
<running>${meeting.isRunning()?c}</running>
|
||||||
|
<duration>${meeting.getDuration()}</duration>
|
||||||
|
<hasUserJoined>${meeting.hasUserJoined()?c}</hasUserJoined>
|
||||||
|
<recording>${meeting.isRecord()?c}</recording>
|
||||||
|
<hasBeenForciblyEnded>${meeting.isForciblyEnded()?c}</hasBeenForciblyEnded>
|
||||||
|
<startTime>${meeting.getStartTime()?c}</startTime>
|
||||||
|
<endTime>${meeting.getEndTime()}</endTime>
|
||||||
|
<participantCount>${meeting.getNumUsers()}</participantCount>
|
||||||
|
<listenerCount>${meeting.getNumListenOnly()}</listenerCount>
|
||||||
|
<voiceParticipantCount>${meeting.getNumVoiceJoined()}</voiceParticipantCount>
|
||||||
|
<videoCount>${meeting.getNumVideos()}</videoCount>
|
||||||
|
<maxUsers>${meeting.getMaxUsers()}</maxUsers>
|
||||||
|
<moderatorCount>${meeting.getNumModerators()}</moderatorCount>
|
||||||
|
<attendees>
|
||||||
|
<#list meetingDetail.meeting.getUsers() as att>
|
||||||
|
<attendee>
|
||||||
|
<userID>${att.getInternalUserId()}</userID>
|
||||||
|
<fullName>${att.getFullname()?html}</fullName>
|
||||||
|
<role>${att.getRole()}</role>
|
||||||
|
<isPresenter>${att.isPresenter()?c}</isPresenter>
|
||||||
|
<isListeningOnly>${att.isListeningOnly()?c}</isListeningOnly>
|
||||||
|
<hasJoinedVoice>${att.isVoiceJoined()?c}</hasJoinedVoice>
|
||||||
|
<hasVideo>${att.hasVideo()?c}</hasVideo>
|
||||||
|
<#if meeting.getUserCustomData(att.getExternalUserId())??>
|
||||||
|
<#assign ucd = meetingDetail.meeting.getUserCustomData(att.getExternalUserId())>
|
||||||
|
<customdata>
|
||||||
|
<#list ucd?keys as prop>
|
||||||
|
<${(prop)?html}>${(ucd[prop])?html}</${(prop)?html}>
|
||||||
|
</#list>
|
||||||
|
</customdata>
|
||||||
|
</#if>
|
||||||
|
</attendee>
|
||||||
|
</#list>
|
||||||
|
</attendees>
|
||||||
|
<#assign m = meetingDetail.meeting.getMetadata()>
|
||||||
|
<metadata>
|
||||||
|
<#list m?keys as prop>
|
||||||
|
<${(prop)?html}>${(m[prop])?html}</${(prop)?html}>
|
||||||
|
</#list>
|
||||||
|
</metadata>
|
||||||
|
|
||||||
|
<isBreakout>${meetingDetail.meeting.isBreakout()?c}</isBreakout>
|
||||||
|
|
||||||
|
<#if meetingDetail.meeting.isBreakout()>
|
||||||
|
<parentMeetingID>${meetingDetail.meeting.getParentMeetingId()}</parentMeetingID>
|
||||||
|
<sequence>${meetingDetail.meeting.getSequence()}</sequence>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#list meetingDetail.meeting.getBreakoutRooms()>
|
||||||
|
<breakoutRooms>
|
||||||
|
<#items as room>
|
||||||
|
<breakout>${room}</breakout>
|
||||||
|
</#items>
|
||||||
|
</breakoutRooms>
|
||||||
|
</#list>
|
||||||
|
</meeting>
|
||||||
|
</#items>
|
||||||
|
</meetings>
|
||||||
|
</#list>
|
||||||
|
</response>
|
||||||
|
</#compress>
|
20
bbb-common-web/src/test/resources/get-recordings.ftlx
Executable file
20
bbb-common-web/src/test/resources/get-recordings.ftlx
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
<#-- GET_RECORDINGS FreeMarker XML template -->
|
||||||
|
<#compress>
|
||||||
|
<response>
|
||||||
|
<#-- Where code is a 'SUCCESS' or 'FAILED' String -->
|
||||||
|
<returncode>${returnCode}</returncode>
|
||||||
|
<recordings>
|
||||||
|
<#list recordings as r>
|
||||||
|
<recording>
|
||||||
|
<#if r.hasError()>
|
||||||
|
<error>
|
||||||
|
<recordID>${r.getMetadataXml()?html}</recordID>
|
||||||
|
</error>
|
||||||
|
<#else>
|
||||||
|
<#include "include-recording.ftlx">
|
||||||
|
</#if>
|
||||||
|
</recording>
|
||||||
|
</#list>
|
||||||
|
</recordings>
|
||||||
|
</response>
|
||||||
|
</#compress>
|
77
bbb-common-web/src/test/resources/include-recording.ftlx
Executable file
77
bbb-common-web/src/test/resources/include-recording.ftlx
Executable file
@ -0,0 +1,77 @@
|
|||||||
|
<recordID>${r.getId()}</recordID>
|
||||||
|
|
||||||
|
<#if r.getMeeting()??>
|
||||||
|
<meetingID>${r.getMeeting().getId()?html}</meetingID>
|
||||||
|
<externalMeetingID>${r.getMeeting().getExternalId()?html}</externalMeetingID>
|
||||||
|
<name>${r.getMeeting().getName()?html}</name>
|
||||||
|
<isBreakout>${r.getMeeting().isBreakout()?c}</isBreakout>
|
||||||
|
<#else>
|
||||||
|
<meetingID>${r.getMeetingId()?html}</meetingID>
|
||||||
|
<name>${r.getMeetingName()?html}></name>
|
||||||
|
<isBreakout>${r.isBreakout()?c}</isBreakout>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<published>${r.getPublished()?string}</published>
|
||||||
|
<state>${r.getState()?string}</state>
|
||||||
|
<startTime><#if r.getStartTime()?? && r.getStartTime() != "">${r.getStartTime()}</#if></startTime>
|
||||||
|
<endTime><#if r.getEndTime()?? && r.getEndTime() != "">${r.getEndTime()}</#if></endTime>
|
||||||
|
<participants><#if r.getParticipants()??>${r.getParticipants()}</#if></participants>
|
||||||
|
|
||||||
|
<#if r.getBreakout()??>
|
||||||
|
<#assign breakout = r.getBreakout()>
|
||||||
|
<breakout>
|
||||||
|
<parentId>${breakout.getParentMeetingId()}</parentId>
|
||||||
|
<sequence>${breakout.getSequence()?c}</sequence>
|
||||||
|
</breakout>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if r.getBreakoutRooms()??>
|
||||||
|
<#list r.getBreakoutRooms()>
|
||||||
|
<breakoutRooms>
|
||||||
|
<#items as broom>
|
||||||
|
<breakoutRoom>${broom.getValue()}</breakoutRoom>
|
||||||
|
</#items>
|
||||||
|
</breakoutRooms>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#assign m = r.getMeta().get()>
|
||||||
|
<metadata>
|
||||||
|
<#list m?keys as prop>
|
||||||
|
<${(prop)?html}>${((m[prop])?html)!""}</${(prop)?html}>
|
||||||
|
</#list>
|
||||||
|
</metadata>
|
||||||
|
|
||||||
|
<#assign pb = r.getPlayback()>
|
||||||
|
<playback>
|
||||||
|
<format>
|
||||||
|
<type>${pb.getFormat()}</type>
|
||||||
|
<url>${pb.getLink()}</url>
|
||||||
|
<processingTime>${pb.getProcessingTime()?c}</processingTime>
|
||||||
|
|
||||||
|
<#if pb.getDuration() == 0>
|
||||||
|
<length>${r.calculateDuration()?c}</length>
|
||||||
|
<#else>
|
||||||
|
<length>${pb.calculateDuration()?c}</length>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if pb.getExtensions()??>
|
||||||
|
<#if pb.getExtensions().getPreview()??>
|
||||||
|
<#assign prev = pb.getExtensions().getPreview()>
|
||||||
|
<preview>
|
||||||
|
<#if prev.getImages()??>
|
||||||
|
<#list prev.getImages()>
|
||||||
|
<images>
|
||||||
|
<#items as image>
|
||||||
|
<#if image??>
|
||||||
|
<image width="${image.getWidth()}" height="${image.getHeight()}" alt="${image.getAlt()?html}">${image.getValue()!"Link not found."}</image>
|
||||||
|
</#if>
|
||||||
|
</#items>
|
||||||
|
</images>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
</preview>
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</format>
|
||||||
|
</playback>
|
22
bbb-common-web/src/test/resources/meeting-has-breakout-metadata.xml
Executable file
22
bbb-common-web/src/test/resources/meeting-has-breakout-metadata.xml
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
<recording>
|
||||||
|
<id>f3ffe06acedf425565cc024c8ebe89a6552e8782-1489172964374</id>
|
||||||
|
<state>published</state>
|
||||||
|
<published>true</published>
|
||||||
|
<start_time>1489172964374</start_time>
|
||||||
|
<end_time>1489173221647</end_time>
|
||||||
|
<breakoutRooms>
|
||||||
|
<breakoutRoom>32ee8bcccfad34f85c58a12f87fc4268130a4fd3-1489173065780</breakoutRoom>
|
||||||
|
<breakoutRoom>721d83a3907548734d4a505992ebb94ec1454a91-1489173065780</breakoutRoom>
|
||||||
|
</breakoutRooms>
|
||||||
|
<meta>
|
||||||
|
<isBreakout>false</isBreakout>
|
||||||
|
<meetingId>random-2810069</meetingId>
|
||||||
|
<meetingName>random-2810069</meetingName>
|
||||||
|
</meta>
|
||||||
|
<playback>
|
||||||
|
<format>presentation</format>
|
||||||
|
<link>http://192.168.23.22/playback/presentation/0.9.0/playback.html?meetingId=f3ffe06acedf425565cc024c8ebe89a6552e8782-1489172964374</link>
|
||||||
|
<processing_time>87598</processing_time>
|
||||||
|
<duration>226417</duration>
|
||||||
|
</playback>
|
||||||
|
</recording>
|
18
bbb-common-web/src/test/resources/meeting-no-breakout-metadata.xml
Executable file
18
bbb-common-web/src/test/resources/meeting-no-breakout-metadata.xml
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
<recording>
|
||||||
|
<id>f3ffe06acedf425565cc024c8ebe89a6552e8782-1489095153417</id>
|
||||||
|
<state>published</state>
|
||||||
|
<published>true</published>
|
||||||
|
<start_time>1489095153417</start_time>
|
||||||
|
<end_time>1489095772224</end_time>
|
||||||
|
<meta>
|
||||||
|
<meetingId>random-2810069</meetingId>
|
||||||
|
<meetingName>random-2810069</meetingName>
|
||||||
|
<isBreakout>false</isBreakout>
|
||||||
|
</meta>
|
||||||
|
<playback>
|
||||||
|
<format>presentation</format>
|
||||||
|
<link>http://192.168.23.22/playback/presentation/0.9.0/playback.html?meetingId=f3ffe06acedf425565cc024c8ebe89a6552e8782-1489095153417</link>
|
||||||
|
<processing_time>191283</processing_time>
|
||||||
|
<duration>545949</duration>
|
||||||
|
</playback>
|
||||||
|
</recording>
|
7
bbb-common-web/src/test/resources/playback-metadata.xml
Executable file
7
bbb-common-web/src/test/resources/playback-metadata.xml
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
<playback>
|
||||||
|
<format>presentation</format>
|
||||||
|
<link>http://192.168.23.22/playback/presentation/0.9.0/playback.html?meetingId=f3ffe06acedf425565cc024c8ebe89a6552e8782-1489095153417</link>
|
||||||
|
<processing_time>191283</processing_time>
|
||||||
|
<duration>545949</duration>
|
||||||
|
|
||||||
|
</playback>
|
@ -0,0 +1 @@
|
|||||||
|
[]
|
@ -0,0 +1,31 @@
|
|||||||
|
<recording>
|
||||||
|
<id>f3ffe06acedf425565cc024c8ebe89a6552e8782-1489435015784</id>
|
||||||
|
<state>foo</state>
|
||||||
|
<published>false</published>
|
||||||
|
<start_time>1489435015784</start_time>
|
||||||
|
<end_time>1489435076055</end_time>
|
||||||
|
<meeting id="f3ffe06acedf425565cc024c8ebe89a6552e8782-1489435015784" externalId="random-2810069" name="random-2810069" breakout="false"/>
|
||||||
|
<breakout parentMeetingId="f3ffe06acedf425565cc024c8ebe89a6552e8782-1489172964374" sequence="2" meetingId="f2041d123b6a4b994e7ad87ee9d348496a73472c-1489173065780"/>
|
||||||
|
<breakoutRooms>
|
||||||
|
<breakoutRoom>32ee8bcccfad34f85c58a12f87fc4268130a4fd3-1489173065780</breakoutRoom>
|
||||||
|
<breakoutRoom>721d83a3907548734d4a505992ebb94ec1454a91-1489173065780</breakoutRoom>
|
||||||
|
</breakoutRooms>
|
||||||
|
<meta>
|
||||||
|
<meetingName>random-2810069</meetingName>
|
||||||
|
<meetingId>random-2810069</meetingId>
|
||||||
|
<isBreakout>false</isBreakout>
|
||||||
|
</meta>
|
||||||
|
<playback>
|
||||||
|
<format>presentation</format>
|
||||||
|
<link>http://192.168.23.22/playback/presentation/0.9.0/playback.html?meetingId=f3ffe06acedf425565cc024c8ebe89a6552e8782-1489435015784</link>
|
||||||
|
<processing_time>28627</processing_time>
|
||||||
|
<duration>32213</duration>
|
||||||
|
<extensions>
|
||||||
|
<preview>
|
||||||
|
<images>
|
||||||
|
<image width="176" height="136" alt="Welcome to">http://192.168.23.22/presentation/32ee8bcccfad34f85c58a12f87fc4268130a4fd3-1489173065780/presentation/743dd59a958334b4cdcdaa302846d0c0eadcf9ff-1489173070800/thumbnails/thumb-1.png</image>
|
||||||
|
</images>
|
||||||
|
</preview>
|
||||||
|
</extensions>
|
||||||
|
</playback>
|
||||||
|
</recording>
|
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<recording id="panzoom_events">
|
||||||
|
<event timestamp="0.0" orig="2440467878.0">
|
||||||
|
<viewBox>0.0 0.0 1600.0 1200.0</viewBox>
|
||||||
|
</event>
|
||||||
|
<event timestamp="19.1" orig="2440504635.0">
|
||||||
|
<viewBox>0.0 0.0 1600.0 1200.0</viewBox>
|
||||||
|
</event>
|
||||||
|
<event timestamp="22.6" orig="2440508157.0">
|
||||||
|
<viewBox>0.0 0.0 1600.0 1200.0</viewBox>
|
||||||
|
</event>
|
||||||
|
</recording>
|
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<popcorn/>
|
@ -0,0 +1,23 @@
|
|||||||
|
package org.bigbluebutton.api.util
|
||||||
|
|
||||||
|
import org.scalatest._
|
||||||
|
|
||||||
|
class ParamsUtilTest extends UnitSpec {
|
||||||
|
|
||||||
|
it should "strip out control chars from text" in {
|
||||||
|
val text = "a\u0000b\u0007c\u008fd"
|
||||||
|
val cleaned = ParamsUtil.stripControlChars(text)
|
||||||
|
assert("abcd" == cleaned)
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "complain about invalid chars in meetingId" in {
|
||||||
|
val meetingId = "Demo , Meeting"
|
||||||
|
assert(ParamsUtil.isValidMeetingId(meetingId) == false)
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "accept valid chars in meetingId" in {
|
||||||
|
val meetingId = "Demo Meeting - 123"
|
||||||
|
assert(ParamsUtil.isValidMeetingId(meetingId) == true)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
package org.bigbluebutton.api.util
|
||||||
|
|
||||||
|
import java.io.{File, FileInputStream}
|
||||||
|
import javax.xml.stream.{XMLInputFactory, XMLStreamReader}
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.{JacksonXmlModule, XmlMapper}
|
||||||
|
import org.bigbluebutton.api.domain.{RecordingMetadata, RecordingMetadataPlayback}
|
||||||
|
|
||||||
|
class RecordingMetadataReaderHelperTest extends UnitSpec {
|
||||||
|
|
||||||
|
it should "deserialize playback part of metadata.xml" in {
|
||||||
|
val factory: XMLInputFactory = XMLInputFactory.newInstance();
|
||||||
|
|
||||||
|
val xml = new File("src/test/resources/playback-metadata.xml")
|
||||||
|
val module: JacksonXmlModule = new JacksonXmlModule();
|
||||||
|
// and then configure, for example:
|
||||||
|
module.setDefaultUseWrapper(false);
|
||||||
|
|
||||||
|
val mapper: XmlMapper = new XmlMapper(module)
|
||||||
|
|
||||||
|
//Reading from xml file and creating XMLStreamReader
|
||||||
|
val reader: XMLStreamReader = factory.createXMLStreamReader(new FileInputStream(xml))
|
||||||
|
|
||||||
|
val playback: RecordingMetadataPlayback = mapper.readValue(reader, classOf[RecordingMetadataPlayback])
|
||||||
|
|
||||||
|
println("***** FOOO =" + mapper.writeValueAsString(playback))
|
||||||
|
|
||||||
|
assert(playback.getDuration == 545949)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "deserialize metadata.xml" in {
|
||||||
|
val factory: XMLInputFactory = XMLInputFactory.newInstance();
|
||||||
|
|
||||||
|
val xml = new File("src/test/resources/breakout-room-metadata.xml")
|
||||||
|
val module: JacksonXmlModule = new JacksonXmlModule();
|
||||||
|
// and then configure, for example:
|
||||||
|
module.setDefaultUseWrapper(false);
|
||||||
|
|
||||||
|
val mapper: XmlMapper = new XmlMapper(module)
|
||||||
|
|
||||||
|
//Reading from xml file and creating XMLStreamReader
|
||||||
|
val reader: XMLStreamReader = factory.createXMLStreamReader(new FileInputStream(xml))
|
||||||
|
|
||||||
|
val recMeta: RecordingMetadata = mapper.readValue(reader, classOf[RecordingMetadata])
|
||||||
|
|
||||||
|
println("***** FOOO =" + mapper.writeValueAsString(recMeta))
|
||||||
|
|
||||||
|
//assert(recMeta.getPlayback.getDuration == 126376)
|
||||||
|
assert(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "save metadata.xml" in {
|
||||||
|
val factory: XMLInputFactory = XMLInputFactory.newInstance();
|
||||||
|
|
||||||
|
val xml = new File("src/test/resources/breakout-room-metadata.xml")
|
||||||
|
val module: JacksonXmlModule = new JacksonXmlModule();
|
||||||
|
// and then configure, for example:
|
||||||
|
module.setDefaultUseWrapper(false);
|
||||||
|
|
||||||
|
val mapper: XmlMapper = new XmlMapper(module)
|
||||||
|
|
||||||
|
//Reading from xml file and creating XMLStreamReader
|
||||||
|
val reader: XMLStreamReader = factory.createXMLStreamReader(new FileInputStream(xml))
|
||||||
|
|
||||||
|
val recMeta: RecordingMetadata = mapper.readValue(reader, classOf[RecordingMetadata])
|
||||||
|
|
||||||
|
recMeta.getMeta().set("FOO", "BAR");
|
||||||
|
|
||||||
|
val metadataXml = RecordingMetadataReaderHelper.getMetadataXmlLocation("target")
|
||||||
|
if (metadataXml.exists()) metadataXml.delete()
|
||||||
|
|
||||||
|
RecordingMetadataReaderHelper.saveRecordingMetadata(metadataXml, recMeta)
|
||||||
|
|
||||||
|
assert(metadataXml.exists())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
package org.bigbluebutton.api.util
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import java.util
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils
|
||||||
|
import org.bigbluebutton.api.RecordingService
|
||||||
|
|
||||||
|
class RecordingServiceTest extends UnitSpec {
|
||||||
|
|
||||||
|
it should "deserialize playback part of metadata.xml" in {
|
||||||
|
val srcXml = new File("src/test/resources/breakout-room-metadata.xml")
|
||||||
|
val metaParams: util.Map[String, String] = new util.TreeMap[String, String]()
|
||||||
|
|
||||||
|
metaParams.put("foo", "bar")
|
||||||
|
metaParams.put("bar", "baz")
|
||||||
|
|
||||||
|
val destXml = new File("target/updated-metadata.xml")
|
||||||
|
RecordingService.updateRecordingMetadata(srcXml, metaParams, destXml)
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "publish recording" in {
|
||||||
|
// Make a copy of our sample recording
|
||||||
|
val destDir = new File("target/sample-recording/publish")
|
||||||
|
if (destDir.exists()) FileUtils.deleteDirectory(destDir)
|
||||||
|
|
||||||
|
val srcDir = new File("src/test/resources/sample-recording")
|
||||||
|
FileUtils.copyDirectory(srcDir, destDir)
|
||||||
|
|
||||||
|
val recordingId = "foo"
|
||||||
|
val recordingDir = new File(destDir.getPath() + File.separatorChar + recordingId)
|
||||||
|
|
||||||
|
val publishedDir = new File("target/recording/published")
|
||||||
|
RecordingService.publishRecording(publishedDir, recordingId, recordingDir)
|
||||||
|
|
||||||
|
assert(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "unpublish recording" in {
|
||||||
|
// Make a copy of our sample recording
|
||||||
|
val destDir = new File("target/sample-recording/unpublish")
|
||||||
|
if (destDir.exists()) FileUtils.deleteDirectory(destDir)
|
||||||
|
|
||||||
|
val srcDir = new File("src/test/resources/sample-recording")
|
||||||
|
FileUtils.copyDirectory(srcDir, destDir)
|
||||||
|
|
||||||
|
val recordingId = "foo"
|
||||||
|
val recordingDir = new File(destDir.getPath() + File.separatorChar + recordingId)
|
||||||
|
|
||||||
|
val unpublishedDir = new File("target/recording/unpublished")
|
||||||
|
if (unpublishedDir.exists()) FileUtils.deleteDirectory(unpublishedDir)
|
||||||
|
|
||||||
|
RecordingService.unpublishRecording(unpublishedDir, recordingId, recordingDir)
|
||||||
|
|
||||||
|
assert(unpublishedDir.exists())
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "delete recording" in {
|
||||||
|
// Make a copy of our sample recording
|
||||||
|
val destDir = new File("target/sample-recording/delete")
|
||||||
|
if (destDir.exists()) FileUtils.deleteDirectory(destDir)
|
||||||
|
|
||||||
|
val srcDir = new File("src/test/resources/sample-recording")
|
||||||
|
FileUtils.copyDirectory(srcDir, destDir)
|
||||||
|
|
||||||
|
val recordingId = "foo"
|
||||||
|
val recordingDir = new File(destDir.getPath() + File.separatorChar + recordingId)
|
||||||
|
|
||||||
|
val deletedDir = new File("target/recording/deleted")
|
||||||
|
if (deletedDir.exists()) FileUtils.deleteDirectory(deletedDir)
|
||||||
|
|
||||||
|
RecordingService.deleteRecording(deletedDir, recordingId, recordingDir)
|
||||||
|
|
||||||
|
assert(deletedDir.exists())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,234 @@
|
|||||||
|
package org.bigbluebutton.api.util
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import java.util
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils
|
||||||
|
import org.bigbluebutton.api.domain.{Meeting, RecordingMetadata, User}
|
||||||
|
import org.scalatest._
|
||||||
|
|
||||||
|
class ResponseBuilderTest extends UnitSpec {
|
||||||
|
|
||||||
|
it should "find template" in {
|
||||||
|
val current = new java.io.File( "." ).getCanonicalPath()
|
||||||
|
println("Current dir:"+current)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
val meetingInfo = new util.TreeMap[String, String]()
|
||||||
|
meetingInfo.put("foo", "foo")
|
||||||
|
meetingInfo.put("bar", "baz")
|
||||||
|
|
||||||
|
val meeting: Meeting = new Meeting.Builder("extMid", "intMid", System.currentTimeMillis())
|
||||||
|
.withName("Demo Meeting").withMaxUsers(25)
|
||||||
|
.withModeratorPass("mp").withViewerPass("ap")
|
||||||
|
.withRecording(true).withDuration(600)
|
||||||
|
.withLogoutUrl("/logoutUrl").withTelVoice("85115").withWebVoice("85115")
|
||||||
|
.withDialNumber("6135551234").withDefaultAvatarURL("/avatar")
|
||||||
|
.withAutoStartRecording(false).withAllowStartStopRecording(true)
|
||||||
|
.withWebcamsOnlyForModerator(false).withMetadata(meetingInfo)
|
||||||
|
.withWelcomeMessageTemplate("hello").withWelcomeMessage("hello")
|
||||||
|
.isBreakout(false).build
|
||||||
|
|
||||||
|
meeting.setParentMeetingId("ParentMeetingId")
|
||||||
|
meeting.setSequence(0);
|
||||||
|
|
||||||
|
meeting.addBreakoutRoom("breakout-room-id-1")
|
||||||
|
meeting.addBreakoutRoom("breakout-room-id-2")
|
||||||
|
meeting.addBreakoutRoom("breakout-room-id-3")
|
||||||
|
|
||||||
|
val user: User = new User("uid1", "extuid1", "Richard", "moderator", "/aygwapo")
|
||||||
|
meeting.userJoined(user)
|
||||||
|
|
||||||
|
val user2: User = new User("uid2", "extuid2", "Richard 2", "moderator", "/aygwapo")
|
||||||
|
meeting.userJoined(user2)
|
||||||
|
|
||||||
|
val user3: User = new User("uid3", "extuid3", "Richard 3", "moderator", "/aygwapo")
|
||||||
|
meeting.userJoined(user2)
|
||||||
|
|
||||||
|
val custData = new util.HashMap[String, String]()
|
||||||
|
custData.put("gwapo", "totoo")
|
||||||
|
|
||||||
|
meeting.addUserCustomData("extuid1", custData)
|
||||||
|
|
||||||
|
val templateLoc = new File("src/test/resources")
|
||||||
|
val builder = new ResponseBuilder(templateLoc)
|
||||||
|
def response = builder.buildGetMeetingInfoResponse(meeting, "success")
|
||||||
|
// println(response)
|
||||||
|
|
||||||
|
assert(templateLoc.exists())
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "return meetings" in {
|
||||||
|
val meetingInfo1 = new util.TreeMap[String, String]()
|
||||||
|
meetingInfo1.put("foo", "foo")
|
||||||
|
meetingInfo1.put("bar", "baz")
|
||||||
|
|
||||||
|
val meeting1: Meeting = new Meeting.Builder("extMid1", "intMid1", System.currentTimeMillis())
|
||||||
|
.withName("Demo Meeting 1").withMaxUsers(25)
|
||||||
|
.withModeratorPass("mp").withViewerPass("ap")
|
||||||
|
.withRecording(true).withDuration(600)
|
||||||
|
.withLogoutUrl("/logoutUrl").withTelVoice("85115").withWebVoice("85115")
|
||||||
|
.withDialNumber("6135551234").withDefaultAvatarURL("/avatar")
|
||||||
|
.withAutoStartRecording(false).withAllowStartStopRecording(true)
|
||||||
|
.withWebcamsOnlyForModerator(false).withMetadata(meetingInfo1)
|
||||||
|
.withWelcomeMessageTemplate("hello").withWelcomeMessage("hello")
|
||||||
|
.isBreakout(false).build
|
||||||
|
|
||||||
|
meeting1.setParentMeetingId("ParentMeetingId")
|
||||||
|
meeting1.setSequence(0);
|
||||||
|
|
||||||
|
meeting1.addBreakoutRoom("breakout-room-id-1")
|
||||||
|
meeting1.addBreakoutRoom("breakout-room-id-2")
|
||||||
|
meeting1.addBreakoutRoom("breakout-room-id-3")
|
||||||
|
|
||||||
|
val userm11: User = new User("uid1", "extuid1", "Richard", "moderator", "/aygwapo")
|
||||||
|
meeting1.userJoined(userm11)
|
||||||
|
|
||||||
|
val userm12: User = new User("uid2", "extuid2", "Richard 2", "moderator", "/aygwapo")
|
||||||
|
meeting1.userJoined(userm12)
|
||||||
|
|
||||||
|
val userm13: User = new User("uid3", "extuid3", "Richard 3", "moderator", "/aygwapo")
|
||||||
|
meeting1.userJoined(userm13)
|
||||||
|
|
||||||
|
val custDatam1 = new util.HashMap[String, String]()
|
||||||
|
custDatam1.put("gwapo", "totoo")
|
||||||
|
|
||||||
|
meeting1.addUserCustomData("extuid1", custDatam1)
|
||||||
|
|
||||||
|
val meetingInfo2 = new util.TreeMap[String, String]()
|
||||||
|
meetingInfo2.put("foo", "foo")
|
||||||
|
meetingInfo2.put("bar", "baz")
|
||||||
|
|
||||||
|
val meeting2: Meeting = new Meeting.Builder("extMid2", "intMid2", System.currentTimeMillis())
|
||||||
|
.withName("Demo Meeting 2").withMaxUsers(25)
|
||||||
|
.withModeratorPass("mp").withViewerPass("ap")
|
||||||
|
.withRecording(true).withDuration(600)
|
||||||
|
.withLogoutUrl("/logoutUrl").withTelVoice("85115").withWebVoice("85115")
|
||||||
|
.withDialNumber("6135551234").withDefaultAvatarURL("/avatar")
|
||||||
|
.withAutoStartRecording(false).withAllowStartStopRecording(true)
|
||||||
|
.withWebcamsOnlyForModerator(false).withMetadata(meetingInfo2)
|
||||||
|
.withWelcomeMessageTemplate("hello").withWelcomeMessage("hello")
|
||||||
|
.isBreakout(false).build
|
||||||
|
|
||||||
|
meeting2.setParentMeetingId("ParentMeetingId")
|
||||||
|
meeting2.setSequence(0);
|
||||||
|
|
||||||
|
meeting2.addBreakoutRoom("breakout-room-id-1")
|
||||||
|
meeting2.addBreakoutRoom("breakout-room-id-2")
|
||||||
|
meeting2.addBreakoutRoom("breakout-room-id-3")
|
||||||
|
|
||||||
|
val userm21: User = new User("uid1", "extuid1", "Richard", "moderator", "/aygwapo")
|
||||||
|
meeting2.userJoined(userm21)
|
||||||
|
|
||||||
|
val userm22: User = new User("uid2", "extuid2", "Richard 2", "moderator", "/aygwapo")
|
||||||
|
meeting2.userJoined(userm22)
|
||||||
|
|
||||||
|
val userm23: User = new User("uid3", "extuid3", "Richard 3", "moderator", "/aygwapo")
|
||||||
|
meeting2.userJoined(userm23)
|
||||||
|
|
||||||
|
val custDatam2 = new util.HashMap[String, String]()
|
||||||
|
custDatam2.put("gwapo", "totoo")
|
||||||
|
|
||||||
|
meeting2.addUserCustomData("extuid1", custDatam2)
|
||||||
|
|
||||||
|
|
||||||
|
val meetingInfo3 = new util.TreeMap[String, String]()
|
||||||
|
meetingInfo3.put("foo", "foo")
|
||||||
|
meetingInfo3.put("bar", "baz")
|
||||||
|
|
||||||
|
val meeting3: Meeting = new Meeting.Builder("extMid", "intMid", System.currentTimeMillis())
|
||||||
|
.withName("Demo Meeting").withMaxUsers(25)
|
||||||
|
.withModeratorPass("mp").withViewerPass("ap")
|
||||||
|
.withRecording(true).withDuration(600)
|
||||||
|
.withLogoutUrl("/logoutUrl").withTelVoice("85115").withWebVoice("85115")
|
||||||
|
.withDialNumber("6135551234").withDefaultAvatarURL("/avatar")
|
||||||
|
.withAutoStartRecording(false).withAllowStartStopRecording(true)
|
||||||
|
.withWebcamsOnlyForModerator(false).withMetadata(meetingInfo3)
|
||||||
|
.withWelcomeMessageTemplate("hello").withWelcomeMessage("hello")
|
||||||
|
.isBreakout(false).build
|
||||||
|
|
||||||
|
meeting3.setParentMeetingId("ParentMeetingId")
|
||||||
|
meeting3.setSequence(0);
|
||||||
|
|
||||||
|
meeting3.addBreakoutRoom("breakout-room-id-1")
|
||||||
|
meeting3.addBreakoutRoom("breakout-room-id-2")
|
||||||
|
meeting3.addBreakoutRoom("breakout-room-id-3")
|
||||||
|
|
||||||
|
val user: User = new User("uid1", "extuid1", "Richard", "moderator", "/aygwapo")
|
||||||
|
meeting3.userJoined(user)
|
||||||
|
|
||||||
|
val user2: User = new User("uid2", "extuid2", "Richard 2", "moderator", "/aygwapo")
|
||||||
|
meeting3.userJoined(user2)
|
||||||
|
|
||||||
|
val user3: User = new User("uid3", "extuid3", "Richard 3", "moderator", "/aygwapo")
|
||||||
|
meeting3.userJoined(user2)
|
||||||
|
|
||||||
|
val custData = new util.HashMap[String, String]()
|
||||||
|
custData.put("gwapo", "totoo")
|
||||||
|
|
||||||
|
meeting3.addUserCustomData("extuid1", custData)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
val meetings = new util.ArrayList[Meeting]()
|
||||||
|
meetings.add(meeting1)
|
||||||
|
meetings.add(meeting2)
|
||||||
|
meetings.add(meeting3)
|
||||||
|
|
||||||
|
val templateLoc = new File("src/test/resources")
|
||||||
|
val builder = new ResponseBuilder(templateLoc)
|
||||||
|
def response = builder.buildGetMeetingsResponse(meetings, "success")
|
||||||
|
// println(response)
|
||||||
|
|
||||||
|
assert(templateLoc.exists())
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "reply to getRecordings api call" in {
|
||||||
|
val templateLoc = new File("src/test/resources")
|
||||||
|
val builder = new ResponseBuilder(templateLoc)
|
||||||
|
|
||||||
|
val metadataXml = new File("src/test/resources/breakout-room-metadata.xml")
|
||||||
|
val recMeta = RecordingMetadataReaderHelper.getRecordingMetadata(metadataXml);
|
||||||
|
val recList = new util.ArrayList[RecordingMetadata]()
|
||||||
|
recList.add(recMeta)
|
||||||
|
def response = builder.buildGetRecordingsResponse(recList, "success")
|
||||||
|
println(response)
|
||||||
|
|
||||||
|
assert(templateLoc.exists())
|
||||||
|
}
|
||||||
|
|
||||||
|
it should "support old metadata.xml in getRecordings api call" in {
|
||||||
|
val templateLoc = new File("src/test/resources")
|
||||||
|
val builder = new ResponseBuilder(templateLoc)
|
||||||
|
|
||||||
|
// Make a copy of our sample recording
|
||||||
|
val destDir = new File("target/recording-metadata/presentation")
|
||||||
|
if (destDir.exists()) FileUtils.deleteDirectory(destDir)
|
||||||
|
|
||||||
|
val srcDir = new File("src/test/resources/recording-metadata/presentation")
|
||||||
|
FileUtils.copyDirectory(srcDir, destDir)
|
||||||
|
|
||||||
|
val recDirs = destDir.listFiles()
|
||||||
|
val recList = new util.ArrayList[RecordingMetadata]()
|
||||||
|
println("START **********************")
|
||||||
|
|
||||||
|
recDirs.map {rec =>
|
||||||
|
val metadataXml = new File(rec.getAbsolutePath + File.separatorChar + "metadata.xml")
|
||||||
|
// println(metadataXml.getAbsolutePath)
|
||||||
|
val recMeta = RecordingMetadataReaderHelper.getRecordingMetadata(metadataXml);
|
||||||
|
// val recList = new util.ArrayList[RecordingMetadata]()
|
||||||
|
// println("START **********************")
|
||||||
|
if (recMeta != null) recList.add(recMeta)
|
||||||
|
// val response = builder.buildGetRecordingsResponse(recList, "success")
|
||||||
|
// println(response)
|
||||||
|
// println("END **********************")
|
||||||
|
}
|
||||||
|
|
||||||
|
val response = builder.buildGetRecordingsResponse(recList, "success")
|
||||||
|
println(response)
|
||||||
|
println("END **********************")
|
||||||
|
|
||||||
|
assert(templateLoc.exists())
|
||||||
|
}
|
||||||
|
}
|
8
bbb-common-web/src/test/scala/org/bigbluebutton/api/util/UnitSpec.scala
Executable file
8
bbb-common-web/src/test/scala/org/bigbluebutton/api/util/UnitSpec.scala
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
package org.bigbluebutton.api.util
|
||||||
|
|
||||||
|
import org.scalatest.FlatSpec
|
||||||
|
import org.scalatest.BeforeAndAfterAll
|
||||||
|
import org.scalatest.WordSpec
|
||||||
|
import org.scalatest.Matchers
|
||||||
|
|
||||||
|
abstract class UnitSpec extends FlatSpec with Matchers with BeforeAndAfterAll
|
@ -20,14 +20,14 @@
|
|||||||
|
|
||||||
# BigBlueButton integration information
|
# BigBlueButton integration information
|
||||||
#----------------------------------------------------
|
#----------------------------------------------------
|
||||||
# This URL is where the BBB client is accessible.
|
# This URL is where the BBB client is accessible.
|
||||||
bigbluebuttonURL=http://localhost/bigbluebutton
|
bigbluebuttonURL=http://localhost/bigbluebutton
|
||||||
# Salt which is used by 3rd-party apps to authenticate api calls
|
# Salt which is used by 3rd-party apps to authenticate api calls
|
||||||
bigbluebuttonSalt=bbb_salt
|
bigbluebuttonSalt=bbb_salt
|
||||||
|
|
||||||
# LTI basic information
|
# LTI basic information
|
||||||
#----------------------------------------------------
|
#----------------------------------------------------
|
||||||
# This URL is where the LTI plugin is accessible. It can be a different server than the BigBluebutton one
|
# This URL is where the LTI plugin is accessible. It can be a different server than the BigBluebutton one
|
||||||
# Only the hostname or IP address is required, plus the port number in case it is other than port 80
|
# Only the hostname or IP address is required, plus the port number in case it is other than port 80
|
||||||
# e.g. localhost or localhost:port
|
# e.g. localhost or localhost:port
|
||||||
ltiEndPoint=localhost
|
ltiEndPoint=localhost
|
||||||
@ -41,6 +41,9 @@ ltiMode=extended
|
|||||||
# Defines if LTI credentials are required
|
# Defines if LTI credentials are required
|
||||||
# Format: [false|<true>]
|
# Format: [false|<true>]
|
||||||
ltiRestrictedAccess=true
|
ltiRestrictedAccess=true
|
||||||
|
# Sets all the meetings to be recorded by default
|
||||||
|
# Format: [<false>|true]
|
||||||
|
ltiAllRecordedByDefault=false
|
||||||
|
|
||||||
#----------------------------------------------------
|
#----------------------------------------------------
|
||||||
# Inject configuration values into BigbluebuttonSrvice beans
|
# Inject configuration values into BigbluebuttonSrvice beans
|
||||||
@ -53,4 +56,4 @@ beans.ltiService.endPoint=${ltiEndPoint}
|
|||||||
beans.ltiService.consumers=${ltiConsumers}
|
beans.ltiService.consumers=${ltiConsumers}
|
||||||
beans.ltiService.mode=${ltiMode}
|
beans.ltiService.mode=${ltiMode}
|
||||||
beans.ltiService.restrictedAccess=${ltiRestrictedAccess}
|
beans.ltiService.restrictedAccess=${ltiRestrictedAccess}
|
||||||
|
beans.ltiService.recordedByDefault=${ltiAllRecordedByDefault}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
package org.bigbluebutton
|
package org.bigbluebutton
|
||||||
/*
|
/*
|
||||||
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
|
||||||
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||||
@ -83,8 +83,8 @@ class ToolController {
|
|||||||
result = doJoinMeeting(params)
|
result = doJoinMeeting(params)
|
||||||
} else {
|
} else {
|
||||||
log.debug "LTI service running in extended mode."
|
log.debug "LTI service running in extended mode."
|
||||||
if ( !Boolean.parseBoolean(params.get(Parameter.CUSTOM_RECORD)) ) {
|
if ( !Boolean.parseBoolean(params.get(Parameter.CUSTOM_RECORD)) && !ltiService.allRecordedByDefault() ) {
|
||||||
log.debug "No bbb_record parameter was sent; immediately redirecting to BBB session!"
|
log.debug "Parameter custom_record was not sent; immediately redirecting to BBB session!"
|
||||||
result = doJoinMeeting(params)
|
result = doJoinMeeting(params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,7 +222,7 @@ class ToolController {
|
|||||||
log.debug "Overriding default welcome message with: [" + welcome + "]"
|
log.debug "Overriding default welcome message with: [" + welcome + "]"
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( params.containsKey(Parameter.CUSTOM_RECORD) && Boolean.parseBoolean(params.get(Parameter.CUSTOM_RECORD)) ) {
|
if ( params.containsKey(Parameter.CUSTOM_RECORD) && Boolean.parseBoolean(params.get(Parameter.CUSTOM_RECORD)) || ltiService.allRecordedByDefault() ) {
|
||||||
welcome += "<br><b>" + message(code: "bigbluebutton.welcome.record") + "</b><br>"
|
welcome += "<br><b>" + message(code: "bigbluebutton.welcome.record") + "</b><br>"
|
||||||
log.debug "Adding record warning to welcome message, welcome is now: [" + welcome + "]"
|
log.debug "Adding record warning to welcome message, welcome is now: [" + welcome + "]"
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
package org.bigbluebutton
|
package org.bigbluebutton
|
||||||
/*
|
/*
|
||||||
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
|
||||||
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||||
@ -92,7 +92,7 @@ class BigbluebuttonService {
|
|||||||
Integer duration = 0
|
Integer duration = 0
|
||||||
if( "extended".equals(mode) ){
|
if( "extended".equals(mode) ){
|
||||||
voiceBridge = getValidatedBBBVoiceBridge(params.get(Parameter.CUSTOM_VOICEBRIDGE))
|
voiceBridge = getValidatedBBBVoiceBridge(params.get(Parameter.CUSTOM_VOICEBRIDGE))
|
||||||
record = getValidatedBBBRecord(params.get(Parameter.CUSTOM_RECORD))
|
record = getValidatedBBBRecord(params.get(Parameter.CUSTOM_RECORD)) || ltiService.allRecordedByDefault()
|
||||||
duration = getValidatedBBBDuration(params.get(Parameter.CUSTOM_DURATION))
|
duration = getValidatedBBBDuration(params.get(Parameter.CUSTOM_DURATION))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,7 +240,7 @@ class BigbluebuttonService {
|
|||||||
private String getValidatedUserId(String userId){
|
private String getValidatedUserId(String userId){
|
||||||
return (userId == null)? "": userId
|
return (userId == null)? "": userId
|
||||||
}
|
}
|
||||||
|
|
||||||
private Integer getValidatedBBBVoiceBridge(String voiceBridge){
|
private Integer getValidatedBBBVoiceBridge(String voiceBridge){
|
||||||
return (voiceBridge != null )? voiceBridge.toInteger(): 0
|
return (voiceBridge != null )? voiceBridge.toInteger(): 0
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
package org.bigbluebutton
|
package org.bigbluebutton
|
||||||
/*
|
/*
|
||||||
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||||
|
|
||||||
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
||||||
@ -32,9 +32,10 @@ class LtiService {
|
|||||||
def consumers = "demo:welcome"
|
def consumers = "demo:welcome"
|
||||||
def mode = "simple"
|
def mode = "simple"
|
||||||
def restrictedAccess = "true"
|
def restrictedAccess = "true"
|
||||||
|
def recordedByDefault = "false"
|
||||||
|
|
||||||
Map<String, String> consumerMap
|
Map<String, String> consumerMap
|
||||||
|
|
||||||
def retrieveIconEndpoint() {
|
def retrieveIconEndpoint() {
|
||||||
return endPoint.replaceFirst("tool", "images/icon.ico")
|
return endPoint.replaceFirst("tool", "images/icon.ico")
|
||||||
}
|
}
|
||||||
@ -42,16 +43,16 @@ class LtiService {
|
|||||||
def retrieveBasicLtiEndpoint() {
|
def retrieveBasicLtiEndpoint() {
|
||||||
return endPoint
|
return endPoint
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, String> getConsumer(consumerId) {
|
private Map<String, String> getConsumer(consumerId) {
|
||||||
Map<String, String> consumer = null
|
Map<String, String> consumer = null
|
||||||
|
|
||||||
if( this.consumerMap.containsKey(consumerId) ){
|
if( this.consumerMap.containsKey(consumerId) ){
|
||||||
consumer = new HashMap<String, String>()
|
consumer = new HashMap<String, String>()
|
||||||
consumer.put("key", consumerId);
|
consumer.put("key", consumerId);
|
||||||
consumer.put("secret", this.consumerMap.get(consumerId))
|
consumer.put("secret", this.consumerMap.get(consumerId))
|
||||||
}
|
}
|
||||||
|
|
||||||
return consumer
|
return consumer
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,19 +67,19 @@ class LtiService {
|
|||||||
this.consumerMap.put(consumer[0], consumer[1])
|
this.consumerMap.put(consumer[0], consumer[1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String sign(String sharedSecret, String data) throws Exception
|
public String sign(String sharedSecret, String data) throws Exception
|
||||||
{
|
{
|
||||||
Mac mac = setKey(sharedSecret)
|
Mac mac = setKey(sharedSecret)
|
||||||
|
|
||||||
// Signed String must be BASE64 encoded.
|
// Signed String must be BASE64 encoded.
|
||||||
byte[] signBytes = mac.doFinal(data.getBytes("UTF8"));
|
byte[] signBytes = mac.doFinal(data.getBytes("UTF8"));
|
||||||
String signature = encodeBase64(signBytes);
|
String signature = encodeBase64(signBytes);
|
||||||
return signature;
|
return signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mac setKey(String sharedSecret) throws Exception
|
private Mac setKey(String sharedSecret) throws Exception
|
||||||
{
|
{
|
||||||
Mac mac = Mac.getInstance("HmacSHA1");
|
Mac mac = Mac.getInstance("HmacSHA1");
|
||||||
@ -137,10 +138,14 @@ class LtiService {
|
|||||||
log.debug("Exception: Message=" + e.getMessage())
|
log.debug("Exception: Message=" + e.getMessage())
|
||||||
}
|
}
|
||||||
|
|
||||||
return ssl_enabled
|
return ssl_enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
def boolean hasRestrictedAccess() {
|
def boolean hasRestrictedAccess() {
|
||||||
return Boolean.parseBoolean(this.restrictedAccess);
|
return Boolean.parseBoolean(this.restrictedAccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def boolean allRecordedByDefault() {
|
||||||
|
return Boolean.parseBoolean(this.recordedByDefault);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
184
bbb-screenshare/NOTES.md
Executable file
184
bbb-screenshare/NOTES.md
Executable file
@ -0,0 +1,184 @@
|
|||||||
|
|
||||||
|
These are instructions taken from JavaCV website to write the instructions above. We keep a copy here to make sure the instructions we have are compatible with out version of javacpp-presets.
|
||||||
|
|
||||||
|
|
||||||
|
** NOTE: **
|
||||||
|
Taken from https://github.com/bytedeco/javacpp-presets/wiki/Build-Environments
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
This page contains a description of the environments that are used to build the JavaCPP Presets for [Android (ARM and x86)](#android-arm-and-x86), [Linux (x86 and x86_64)](#linux-x86-and-x86_64), [Linux (ARM)](#linux-arm), [Mac OS X (x86_64)](#mac-os-x-x86_64), and [Windows (x86 and x86_64)](#windows-x86-and-x86_64). We also explain our choices given the requirements and provide some recommendations. Furthermore, JavaCPP is by no means limited to these platforms, so if you happen to know how to set up an environment for other platforms, by all means, please do add that information to this page to share with others. Thank you!
|
||||||
|
|
||||||
|
|
||||||
|
Prerequisites for all platforms
|
||||||
|
-------------------------------
|
||||||
|
The build process for the modules of `javacpp-presets` usually depends on the same version of the `javacpp` module. To insure that you have the latest matching version of both, please execute the following before starting the build in the `javacpp-presets` directory:
|
||||||
|
```bash
|
||||||
|
$ git clone https://github.com/bytedeco/javacpp.git --branch <tag>
|
||||||
|
$ git clone https://github.com/bytedeco/javacpp-presets.git --branch <tag>
|
||||||
|
$ cd javacpp
|
||||||
|
$ mvn clean install
|
||||||
|
```
|
||||||
|
For the latest tag please check
|
||||||
|
https://github.com/bytedeco/javacpp-presets/tags
|
||||||
|
|
||||||
|
Android (ARM and x86)
|
||||||
|
---------------------
|
||||||
|
To produce native libraries for Android, we basically only need to install the JDK and the NDK, which is available for Linux, Mac OS X, and Windows. However, the build scripts of some libraries only run correctly under Linux, so we recommend using a recent distribution of Linux (such as Fedora or Ubuntu) as build environment for Android.
|
||||||
|
|
||||||
|
### Preparations
|
||||||
|
1. Download the latest version of the [NDK](https://developer.android.com/ndk/downloads/), which is r10e at the time of this writing and contains important fixes for OpenMP, among other things
|
||||||
|
2. Install the NDK under `~/Android/android-ndk`, where the build scripts will look for it by default
|
||||||
|
3. Finally, make sure to have installed at least OpenJDK and Maven as per the instructions of your distribution
|
||||||
|
|
||||||
|
After which the following commands can be used to start the build inside the `javacpp-presets` directory:
|
||||||
|
```bash
|
||||||
|
$ ANDROID_NDK=/path/to/android-ndk/ bash cppbuild.sh -platform android-xxx install
|
||||||
|
$ mvn clean install -Djavacpp.platform=android-xxx -Djavacpp.platform.root=/path/to/android-ndk/ -Djavacpp.platform.compiler=/path/to/target-g++
|
||||||
|
```
|
||||||
|
where `android-xxx` is either `android-arm` or `android-x86`, and where `target-g++` is either `arm-linux-androideabi-g++` or `i686-linux-android-g++`.
|
||||||
|
|
||||||
|
|
||||||
|
Linux (x86 and x86_64)
|
||||||
|
----------------------
|
||||||
|
To produce native libraries that can run on the largest possible number of Linux installations out there, it is recommended to build under CentOS 7. This is because it relies on an old enough version of glibc, which nevertheless works for all the libraries found in the JavaCPP Presets, and since newer versions of glibc are backward compatible, all recent distributions of Linux should support the binaries generated. We do not actually need to install CentOS 7 though. Pretty much any recent distribution of Linux comes with a package for [Docker](https://www.docker.com/). It is also possible to map existing directories, for example `/usr/local/lib/bazel` and `/usr/local/cuda` as shown in the steps below, to reuse an existing [Bazel](http://bazel.io/docs/install.html) or [CUDA](https://developer.nvidia.com/cuda-downloads) installation as well as any other set of files for the purpose of the build.
|
||||||
|
|
||||||
|
### Preparations
|
||||||
|
1. Install Docker under, for example, Fedora and Ubuntu, respectively:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ sudo yum install docker
|
||||||
|
$ sudo apt-get install docker.io
|
||||||
|
```
|
||||||
|
|
||||||
|
2. When using SELinux, it might also be necessary to disable temporarily the firewall, for example:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo systemctl stop firewalld
|
||||||
|
$ sudo systemctl start docker
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Start the container for CentOS 7 (the command might be `docker.io` instead of `docker`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ sudo docker run --privileged -it -v /usr/local/lib/bazel:/usr/local/lib/bazel -v /usr/local/cuda:/usr/local/cuda centos:7 /bin/bash
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Finally, inside the container, we need to install a bunch of things:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ ln -s /usr/local/lib/bazel/bin/bazel /usr/local/bin/bazel
|
||||||
|
$ yum install epel-release
|
||||||
|
$ yum install clang gcc-c++ gcc-gfortran java-devel maven python numpy swig git file which wget unzip tar bzip2 gzip xz patch make cmake3 perl nasm yasm alsa-lib-devel freeglut-devel gtk2-devel libusb-devel libusb1-devel zlib-devel
|
||||||
|
$ yum install `rpm -qa | sed s/.x86_64$/.i686/`
|
||||||
|
```
|
||||||
|
|
||||||
|
After which the following commands can be used to start the build inside the `javacpp-presets` directory:
|
||||||
|
```bash
|
||||||
|
$ bash cppbuild.sh -platform linux-xxx install
|
||||||
|
$ mvn clean install -Djavacpp.platform=linux-xxx
|
||||||
|
```
|
||||||
|
where `linux-xxx` is either `linux-x86` or `linux-x86_64`.
|
||||||
|
|
||||||
|
|
||||||
|
Linux (ARM)
|
||||||
|
-----------
|
||||||
|
There are a growing number of arm platforms running Linux, though testing of this build has mainly focussed on the Pi family of products. Compiling natively on these platforms can be quite time consuming, and as well to automate the build process, the build setup here relies on cross-compiling for the target arm platform. This has been tested using Ubuntu x64 15.10, but it should be reasonably similar approach for other host OS's.
|
||||||
|
|
||||||
|
You'll need to have setup a build environment with the usual packages (pkgconfig, build-essentials, yasm, nasm, maven3, etc). The major addition you'll need is a set of cross compilers: arm-linux-gnueabihf-gcc, arm-linux-gnueabihf-g++ and arm-linux-gnueabihf-cpp. It's best to get these via your OS's package manager, as there are other dependencies for these.
|
||||||
|
|
||||||
|
Originally a 5.x compiler was used, but this seems to caused problems in creating a dependency on newer glibc functionality which might not be present on your target arm device. The 4.8 or 4.9 version of the compiler seems to work fine, but, in targetting support for the Pi1 and well as Pi2-Pi3 (i.e. arm6 as well as arm7) it seems some compiler flag combinations might not be support by the standard gnueabihf compiler toolchain.
|
||||||
|
|
||||||
|
There are pi specific compilers available, so these have been used in the current setup.
|
||||||
|
|
||||||
|
1. Get the Pi tools: git clone https://github.com/raspberrypi/tools.git
|
||||||
|
2. From this folder, move out a specific compiler version to a more generic location: sudo cp -r ./tools/arm-bcm2708/arm-bcm2708-linux-gnueabi /opt
|
||||||
|
3. Setup alternatives of the generic compiler names in /usr/bin to point to this new compiler
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ update-alternatives --install /usr/bin/arm-linux-gnueabihf-gcc arm-linux-gnueabihf-gcc /opt/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-gcc 46
|
||||||
|
$ update-alternatives --install /usr/bin/arm-linux-gnueabihf-g++ arm-linux-gnueabihf-g++ /opt/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-g++ 46
|
||||||
|
$ update-alternatives --install /usr/bin/arm-linux-gnueabihf-cpp arm-linux-gnueabihf-cpp /opt/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-cpp 46
|
||||||
|
```
|
||||||
|
|
||||||
|
(This way if you want to explore using other newer compilers, just add them to alternatives and the same build setup should work fine)
|
||||||
|
|
||||||
|
This should now have you setup ready to build for arm. It could be an idea to test at this stage with building a simple hello world executable (save your hello world test code as hello.cpp):
|
||||||
|
|
||||||
|
$ arm-linux-gnueabihf-g++ -O3 -g3 -Wall -fPIC -march=armv6 -mfpu=vfp -mfloat-abi=hard hello.cpp -c -o hello.o
|
||||||
|
$ arm-linux-gnueabihf-g++ -o hello hello.o
|
||||||
|
$ file hello
|
||||||
|
|
||||||
|
And you should see in the returned info that hello is built for ARM
|
||||||
|
|
||||||
|
With the build environment setup, now its on to building JavaCV. Not all components have been setup with the linux-armhf build configurations, so rather than building the entire project only a subset are built here, but enough to have core functionality (OpenCV, FFmpeg) working with some additional parts (artoolkitplus, flycapture, flandmark, libfreenect, libdc1394) built but not tested. For flycapture, you need to download the arm SDK (currently flycapture.2.9.3.13_armhf) and make these .so libs available, either in your path, or setting up a /usr/include/flycapture directory and moving them there.
|
||||||
|
|
||||||
|
Now all the dependencies are setup, the build can be started (assuming you've done a git clone of javacv, javacpp and javacpp-presets all to the same folder)
|
||||||
|
|
||||||
|
$ cd javacpp
|
||||||
|
$ mvn install
|
||||||
|
$ cd ..
|
||||||
|
$ cd javacpp-presets
|
||||||
|
$ ./cppbuild.sh -platform linux-armhf install
|
||||||
|
$ mvn install -Djavacpp.platform=linux-armhf -Djavacpp.platform.compiler=arm-linux-gnueabihf-g++
|
||||||
|
$ cd platform
|
||||||
|
$ mvn install -Djavacpp.platform=linux-armhf
|
||||||
|
|
||||||
|
Hopefully that all runs OK, and then in ./javacpp-presets/platform/target/ you should find there are platform specific (opencv-linux-armhf.jar, ffmpeg-linux-armhf.jar, etc) files built.
|
||||||
|
|
||||||
|
If you want to try alternative flags, you need to modify in javacpp, ./src/main/resources/org/bytedeco/javacpp/properties/linux-armhf.properties and then in javacpp-presets any project cppbuild.sh file where you want to update too (e.g. ./opencv/cppbuild.sh linux-armhf section). For newer Pis on arm7 it does look like there are potential performance gains in armv7 and neon flags, and using a newer compiler rather than the bcm2708 build used here may further improve things (some earlier builds specific for armv7 did look faster). Also if you are using onboard picam devices, make sure you load the module with "modprobe bcm2835-v4l2 max_video_width=2592 max_video_height=1944" - this way if you test just using OpenCV or FFMPEG grabber you should get at least 30fps as a start point. The more computation you then do on each frame, the more this will drop.
|
||||||
|
|
||||||
|
|
||||||
|
Mac OS X (x86_64)
|
||||||
|
-----------------
|
||||||
|
OS X Mavericks (10.9) is the first version of Mac OS X to support C++11 fully and properly, so to preserve your sanity, we do not recommend trying to build or use the JavaCPP Presets on any older versions of Mac OS X.
|
||||||
|
|
||||||
|
### Preparations
|
||||||
|
1. Install [Xcode](https://developer.apple.com/xcode/) and [Homebrew](http://brew.sh/)
|
||||||
|
2. Ensure the command line tools for Xcode are installed
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ xcode-select --install
|
||||||
|
```
|
||||||
|
3. Run the following commands to install the JDK, among other things Apple left out of Xcode:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ brew install caskroom/cask/brew-cask
|
||||||
|
$ brew cask install cuda java
|
||||||
|
$ brew install gcc5 swig bazel cmake libusb maven nasm yasm xz pkg-config
|
||||||
|
```
|
||||||
|
|
||||||
|
After which the following commands can be used to start the build inside the `javacpp-presets` directory:
|
||||||
|
```bash
|
||||||
|
$ bash cppbuild.sh install
|
||||||
|
$ mvn clean install
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Windows (x86 and x86_64)
|
||||||
|
------------------------
|
||||||
|
Visual Studio Community 2013 is the first free version to have been decently bundled with support for C++11, OpenMP, the Windows SDK, and everything else from Microsoft, so we recommend installing that version of Visual Studio, which consequently requires Windows 7. Still, to run the bash scripts and compile some things that the Microsoft C/C++ Compiler does not support, we need to install manually a few other things.
|
||||||
|
|
||||||
|
### Preparations
|
||||||
|
1. Install the [Java SE Development Kit](http://www.oracle.com/technetwork/java/javase/downloads/), [Maven](https://maven.apache.org/download.cgi), [MSYS2](https://msys2.github.io/), [Visual Studio Community 2013](https://www.visualstudio.com/en-us/news/vs2013-community-vs.aspx), and [CUDA](https://developer.nvidia.com/cuda-downloads)
|
||||||
|
2. Under an "MSYS2 Shell", run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ pacman -S base-devel tar patch make git unzip zip nasm yasm pkg-config mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc mingw-w64-i686-gcc mingw-w64-x86_64-gcc-fortran mingw-w64-i686-gcc-fortran mingw-w64-x86_64-libwinpthread-git mingw-w64-i686-libwinpthread-git
|
||||||
|
```
|
||||||
|
|
||||||
|
3. From the "Visual Studio Tools" found inside the Start menu, open:
|
||||||
|
- "VS2013 x86 Native Tools Command Prompt" and run `c:\msys64\mingw32_shell.bat` inside
|
||||||
|
- "VS2013 x64 Native Tools Command Prompt" and run `c:\msys64\mingw64_shell.bat` inside
|
||||||
|
- Making sure the `set MSYS2_PATH_TYPE=inherit` line is *not* commented out in either of those batch files.
|
||||||
|
|
||||||
|
4. Run the "Prerequisites for all platforms" tasks inside the shell
|
||||||
|
|
||||||
|
Afterwards the following commands can be used to start the build inside the `javacpp-presets` directory:
|
||||||
|
```bash
|
||||||
|
$ bash cppbuild.sh -platform windows-xxx install
|
||||||
|
$ mvn clean install -Djavacpp.platform=windows-xxx
|
||||||
|
```
|
||||||
|
where `windows-xxx` is either `windows-x86` or `windows-x86_64`. Run the builds for `windows-x86` inside the "MINGW32" window, and the ones for `windows-x86_64` in the "MINGW64" one.
|
||||||
|
|
||||||
|
|
176
bbb-screenshare/README.md
Executable file
176
bbb-screenshare/README.md
Executable file
@ -0,0 +1,176 @@
|
|||||||
|
This document contains instructions on how to build your own native libraries, screenshare webstart app, and how to deploy screenshare application.
|
||||||
|
|
||||||
|
|
||||||
|
Building your own native libraries
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
Linux (x86 and x86_64)
|
||||||
|
----------------------
|
||||||
|
To produce native libraries that can run on the largest possible number of Linux installations out there, it is recommended to build under CentOS 7. This is because it relies on an old enough version of glibc, which nevertheless works for all the libraries found in the JavaCPP Presets, and since newer versions of glibc are backward compatible, all recent distributions of Linux should support the binaries generated. We do not actually need to install CentOS 7 though. Pretty much any recent distribution of Linux comes with a package for [Docker](https://www.docker.com/). It is also possible to map existing directories, for example `/usr/local/lib/bazel` and `/usr/local/cuda` as shown in the steps below, to reuse an existing [Bazel](http://bazel.io/docs/install.html) or [CUDA](https://developer.nvidia.com/cuda-downloads) installation as well as any other set of files for the purpose of the build.
|
||||||
|
|
||||||
|
### Preparations
|
||||||
|
1. Install Docker under, for example, Fedora and Ubuntu, respectively:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ sudo yum install docker
|
||||||
|
$ sudo apt-get install docker.io
|
||||||
|
```
|
||||||
|
|
||||||
|
2. When using SELinux, it might also be necessary to disable temporarily the firewall, for example:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo systemctl stop firewalld
|
||||||
|
$ sudo systemctl start docker
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Start the container for CentOS 7 (the command might be `docker.io` instead of `docker`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ sudo docker run --privileged -it -v /usr/local/lib/bazel:/usr/local/lib/bazel -v /usr/local/cuda:/usr/local/cuda centos:7 /bin/bash
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Finally, inside the container, we need to install a bunch of things:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ ln -s /usr/local/lib/bazel/bin/bazel /usr/local/bin/bazel
|
||||||
|
$ yum install epel-release
|
||||||
|
$ yum install clang gcc-c++ gcc-gfortran java-devel maven python numpy swig git file which wget unzip tar bzip2 gzip xz patch make cmake3 perl nasm yasm alsa-lib-devel freeglut-devel gtk2-devel libusb-devel libusb1-devel zlib-devel
|
||||||
|
$ yum install `rpm -qa | sed s/.x86_64$/.i686/`
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Checkout `https://github.com/bigbluebutton/javacpp-presets` and use branch `min-build-1.2-svc2`
|
||||||
|
|
||||||
|
6. cd to `javacpp-presets/ffmpeg`
|
||||||
|
|
||||||
|
7. If you want to build SVC2 libraries, you copy `cppbuild.sh.svc2` to `cppbuild.sh`
|
||||||
|
|
||||||
|
8. After which the following commands inside the `ffmpeg` dir:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash cppbuild.sh -platform linux-xxx install
|
||||||
|
|
||||||
|
mvn clean install -Djavacpp.platform=linux-xxx
|
||||||
|
```
|
||||||
|
|
||||||
|
where `linux-xxx` is either `linux-x86` or `linux-x86_64`.
|
||||||
|
|
||||||
|
If things go well, copy the resulting jar into `native-libs/ffmpeg-linux-xxx` and sign the jar.
|
||||||
|
|
||||||
|
|
||||||
|
Mac OS X (x86_64)
|
||||||
|
-----------------
|
||||||
|
OS X Mavericks (10.9) is the first version of Mac OS X to support C++11 fully and properly, so to preserve your sanity, we do not recommend trying to build or use the JavaCPP Presets on any older versions of Mac OS X.
|
||||||
|
|
||||||
|
### Preparations
|
||||||
|
1. Install [Xcode](https://developer.apple.com/xcode/) and [Homebrew](http://brew.sh/)
|
||||||
|
2. Ensure the command line tools for Xcode are installed
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ xcode-select --install
|
||||||
|
```
|
||||||
|
3. Run the following commands to install the JDK, among other things Apple left out of Xcode:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ brew install caskroom/cask/brew-cask
|
||||||
|
$ brew cask install cuda java
|
||||||
|
$ brew install gcc5 swig bazel cmake libusb maven nasm yasm xz pkg-config
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Checkout `https://github.com/bigbluebutton/javacpp-presets` and use branch `min-build-1.2-svc2`
|
||||||
|
|
||||||
|
5. cd to `javacpp-presets/ffmpeg`
|
||||||
|
|
||||||
|
6. If you want to build SVC2 libraries, you copy `cppbuild.sh.svc2` to `cppbuild.sh`
|
||||||
|
|
||||||
|
7. After which the following commands inside the `ffmpeg` dir:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ bash cppbuild.sh install
|
||||||
|
$ mvn clean install
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
If things go well, copy the resulting jar into `native-libs/ffmpeg-macosx-x86_64` and sign the jar.
|
||||||
|
|
||||||
|
|
||||||
|
Windows (x86 and x86_64)
|
||||||
|
------------------------
|
||||||
|
Visual Studio Community 2013 is the first free version to have been decently bundled with support for C++11, OpenMP, the Windows SDK, and everything else from Microsoft, so we recommend installing that version of Visual Studio, which consequently requires Windows 7. Still, to run the bash scripts and compile some things that the Microsoft C/C++ Compiler does not support, we need to install manually a few other things.
|
||||||
|
|
||||||
|
### Preparations
|
||||||
|
1. Install the [Java SE Development Kit](http://www.oracle.com/technetwork/java/javase/downloads/), [Maven](https://maven.apache.org/download.cgi), [MSYS2](https://msys2.github.io/), [Visual Studio Community 2013](https://www.visualstudio.com/en-us/news/vs2013-community-vs.aspx), and [CUDA](https://developer.nvidia.com/cuda-downloads)
|
||||||
|
2. Under an "MSYS2 Shell", run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ pacman -S base-devel tar patch make git unzip zip nasm yasm pkg-config mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc mingw-w64-i686-gcc mingw-w64-x86_64-gcc-fortran mingw-w64-i686-gcc-fortran mingw-w64-x86_64-libwinpthread-git mingw-w64-i686-libwinpthread-git
|
||||||
|
```
|
||||||
|
|
||||||
|
3. From the "Visual Studio Tools" found inside the Start menu, open:
|
||||||
|
- "VS2013 x86 Native Tools Command Prompt" and run `c:\msys64\mingw32_shell.bat` inside
|
||||||
|
- "VS2013 x64 Native Tools Command Prompt" and run `c:\msys64\mingw64_shell.bat` inside
|
||||||
|
- Making sure the `set MSYS2_PATH_TYPE=inherit` line is *not* commented out in either of those batch files.
|
||||||
|
|
||||||
|
4. Run the "Prerequisites for all platforms" tasks inside the shell
|
||||||
|
|
||||||
|
5. Checkout `https://github.com/bigbluebutton/javacpp-presets` and use branch `min-build-1.2-svc2`
|
||||||
|
|
||||||
|
6. cd to `javacpp-presets/ffmpeg`
|
||||||
|
|
||||||
|
7. If you want to build SVC2 libraries, you copy `cppbuild.sh.svc2` to `cppbuild.sh`
|
||||||
|
|
||||||
|
8. After which the following commands inside the `ffmpeg` dir:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ bash cppbuild.sh -platform windows-xxx install
|
||||||
|
$ mvn clean install -Djavacpp.platform=windows-xxx
|
||||||
|
```
|
||||||
|
where `windows-xxx` is either `windows-x86` or `windows-x86_64`. Run the builds for `windows-x86` inside the "MINGW32" window, and the ones for `windows-x86_64` in the "MINGW64" one.
|
||||||
|
|
||||||
|
If things go well, copy the resulting jar into `native-libs/ffmpeg-windows-xxx` and sign the jar.
|
||||||
|
|
||||||
|
|
||||||
|
Signing the jar files
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
To sign the native libraries, cd to the location of the jar. Copy tour cert into the dir and run `sign-jar.sh`. You will be prompted for
|
||||||
|
your cert file and password of your cert.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd ffmpeg-linux-x86/svc2
|
||||||
|
|
||||||
|
Copy your cert into this directory
|
||||||
|
|
||||||
|
./sign-jar.sh
|
||||||
|
|
||||||
|
You will be prompted for your cert file and password.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting signed jar file will be in `bbb-screenshare/apps/jws/lib`
|
||||||
|
|
||||||
|
Aside from the native jar files, you will need to sign the `ffmpeg.jar` found in `jws/signed-jars`. Follow the README doc in that directory.
|
||||||
|
|
||||||
|
|
||||||
|
Building screenshare webstart application
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
1. Go to `jws/webstart` directory.
|
||||||
|
|
||||||
|
2. Copy your cert into the dir.
|
||||||
|
|
||||||
|
3. Run `build.sh` and you will be prompted for your cert file and cert password in order to sign the jar file.
|
||||||
|
|
||||||
|
|
||||||
|
Deploying and testing the screenshare application
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
1. Go to `app` directory.
|
||||||
|
|
||||||
|
2. Edit `src/main/webapp/WEB-INF/screenshare.properties` to point to your server's IP address.
|
||||||
|
|
||||||
|
3. Run `deploy.sh` to build the whole application and deploy to your local red5 server.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -34,6 +34,7 @@ cd lib
|
|||||||
sudo cp -r ~/dev/bigbluebutton/bbb-screenshare/app/jws/lib/* .
|
sudo cp -r ~/dev/bigbluebutton/bbb-screenshare/app/jws/lib/* .
|
||||||
cd ..
|
cd ..
|
||||||
sudo cp ~/dev/bigbluebutton/bbb-screenshare/app/jws/screenshare.jnlp .
|
sudo cp ~/dev/bigbluebutton/bbb-screenshare/app/jws/screenshare.jnlp .
|
||||||
|
sudo cp ~/dev/bigbluebutton/bbb-screenshare/app/jws/screenshare.jnlp.h264 .
|
||||||
|
|
||||||
sudo chmod -R 777 /usr/share/red5/webapps/screenshare
|
sudo chmod -R 777 /usr/share/red5/webapps/screenshare
|
||||||
sudo chown -R red5:red5 /usr/share/red5/webapps/screenshare
|
sudo chown -R red5:red5 /usr/share/red5/webapps/screenshare
|
||||||
|
BIN
bbb-screenshare/app/jws/lib/ffmpeg-linux-x86-svc2.jar
Normal file
BIN
bbb-screenshare/app/jws/lib/ffmpeg-linux-x86-svc2.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
bbb-screenshare/app/jws/lib/ffmpeg-linux-x86_64-svc2.jar
Normal file
BIN
bbb-screenshare/app/jws/lib/ffmpeg-linux-x86_64-svc2.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
bbb-screenshare/app/jws/lib/ffmpeg-macosx-x86_64-svc2.jar
Normal file
BIN
bbb-screenshare/app/jws/lib/ffmpeg-macosx-x86_64-svc2.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
bbb-screenshare/app/jws/lib/ffmpeg-win-x86-svc2.jar
Normal file
BIN
bbb-screenshare/app/jws/lib/ffmpeg-win-x86-svc2.jar
Normal file
Binary file not shown.
BIN
bbb-screenshare/app/jws/lib/ffmpeg-win-x86_64-svc2.jar
Normal file
BIN
bbb-screenshare/app/jws/lib/ffmpeg-win-x86_64-svc2.jar
Normal 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.
@ -16,23 +16,23 @@
|
|||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
<resources os="Windows" arch="amd64">
|
<resources os="Windows" arch="amd64">
|
||||||
<nativelib href="ffmpeg-windows-x86_64.jar"/>
|
<nativelib href="ffmpeg-win-x86_64-svc2.jar"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
<resources os="Windows" arch="x86">
|
<resources os="Windows" arch="x86">
|
||||||
<nativelib href="$$jnlpUrl/lib/ffmpeg-windows-x86.jar"/>
|
<nativelib href="ffmpeg-win-x86-svc2.jar"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
<resources os="Linux" arch="x86_64 amd64">
|
<resources os="Linux" arch="x86_64 amd64">
|
||||||
<nativelib href="ffmpeg-linux-x86_64.jar"/>
|
<nativelib href="ffmpeg-linux-x86_64-svc2.jar"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
<resources os="Linux" arch="x86 i386 i486 i586 i686">
|
<resources os="Linux" arch="x86 i386 i486 i586 i686">
|
||||||
<nativelib href="ffmpeg-linux-x86.jar"/>
|
<nativelib href="ffmpeg-linux-x86-svc2.jar"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
<resources os="Mac OS X">
|
<resources os="Mac OS X">
|
||||||
<nativelib href="ffmpeg-macosx-x86_64.jar"/>
|
<nativelib href="ffmpeg-macosx-x86_64-svc2.jar"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
<application-desc
|
<application-desc
|
||||||
@ -45,6 +45,7 @@
|
|||||||
<argument>$$fullScreen</argument>
|
<argument>$$fullScreen</argument>
|
||||||
<argument>$$codecOptions</argument>
|
<argument>$$codecOptions</argument>
|
||||||
<argument>$$session</argument>
|
<argument>$$session</argument>
|
||||||
|
<argument>$$useH264</argument>
|
||||||
<argument>$$errorMessage</argument>
|
<argument>$$errorMessage</argument>
|
||||||
</application-desc>
|
</application-desc>
|
||||||
<security><all-permissions/></security>
|
<security><all-permissions/></security>
|
||||||
|
@ -16,23 +16,23 @@
|
|||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
<resources os="Windows" arch="amd64">
|
<resources os="Windows" arch="amd64">
|
||||||
<nativelib href="ffmpeg-windows-x86_64.jar"/>
|
<nativelib href="ffmpeg-win-x86_64-h264.jar"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
<resources os="Windows" arch="x86">
|
<resources os="Windows" arch="x86">
|
||||||
<nativelib href="$$jnlpUrl/lib/ffmpeg-windows-x86.jar"/>
|
<nativelib href="ffmpeg-win-x86-h264.jar"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
<resources os="Linux" arch="x86_64 amd64">
|
<resources os="Linux" arch="x86_64 amd64">
|
||||||
<nativelib href="ffmpeg-linux-x86_64.jar"/>
|
<nativelib href="ffmpeg-linux-x86_64-h264.jar"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
<resources os="Linux" arch="x86 i386 i486 i586 i686">
|
<resources os="Linux" arch="x86 i386 i486 i586 i686">
|
||||||
<nativelib href="ffmpeg-linux-x86.jar"/>
|
<nativelib href="ffmpeg-linux-x86-h264.jar"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
<resources os="Mac OS X">
|
<resources os="Mac OS X">
|
||||||
<nativelib href="ffmpeg-macosx-x86_64.jar"/>
|
<nativelib href="ffmpeg-macosx-x86_64-h264.jar"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
<application-desc
|
<application-desc
|
||||||
@ -45,6 +45,7 @@
|
|||||||
<argument>$$fullScreen</argument>
|
<argument>$$fullScreen</argument>
|
||||||
<argument>$$codecOptions</argument>
|
<argument>$$codecOptions</argument>
|
||||||
<argument>$$session</argument>
|
<argument>$$session</argument>
|
||||||
|
<argument>$$useH264</argument>
|
||||||
<argument>$$errorMessage</argument>
|
<argument>$$errorMessage</argument>
|
||||||
</application-desc>
|
</application-desc>
|
||||||
<security><all-permissions/></security>
|
<security><all-permissions/></security>
|
@ -41,6 +41,8 @@ import java.io.*;
|
|||||||
import javax.servlet.*;
|
import javax.servlet.*;
|
||||||
import javax.servlet.http.*;
|
import javax.servlet.http.*;
|
||||||
import javax.xml.parsers.*;
|
import javax.xml.parsers.*;
|
||||||
|
|
||||||
|
import com.sun.org.apache.xpath.internal.operations.Bool;
|
||||||
import org.xml.sax.*;
|
import org.xml.sax.*;
|
||||||
import javax.xml.transform.*;
|
import javax.xml.transform.*;
|
||||||
import javax.xml.transform.dom.DOMSource;
|
import javax.xml.transform.dom.DOMSource;
|
||||||
@ -314,12 +316,23 @@ public class JnlpFileHandler {
|
|||||||
if (sInfo == null) {
|
if (sInfo == null) {
|
||||||
errorMessage = "ERROR_GETTING_INFO_USING_TOKEN";
|
errorMessage = "ERROR_GETTING_INFO_USING_TOKEN";
|
||||||
} else {
|
} else {
|
||||||
publishUrl = sInfo.publishUrl;
|
|
||||||
|
System.out.println("********* URL=" + sInfo.publishUrl);
|
||||||
|
if (sInfo.tunnel) {
|
||||||
|
publishUrl = sInfo.publishUrl.replaceFirst("rtmp","rtmpt");
|
||||||
|
} else {
|
||||||
|
publishUrl = sInfo.publishUrl;
|
||||||
|
}
|
||||||
|
|
||||||
streamId = sInfo.streamId;
|
streamId = sInfo.streamId;
|
||||||
session = sInfo.session;
|
session = sInfo.session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
System.out.println("********* URL=" + publishUrl);
|
||||||
|
|
||||||
String jnlpUrl = configurator.getJnlpUrl();
|
String jnlpUrl = configurator.getJnlpUrl();
|
||||||
|
Boolean useH264 = configurator.isUseH264();
|
||||||
|
|
||||||
String codecOptions = configurator.getCodecOptions();
|
String codecOptions = configurator.getCodecOptions();
|
||||||
log.debug("Codec Options = [" + codecOptions + "]");
|
log.debug("Codec Options = [" + codecOptions + "]");
|
||||||
@ -337,6 +350,7 @@ public class JnlpFileHandler {
|
|||||||
jnlpTemplate = substitute(jnlpTemplate, "$$session", session);
|
jnlpTemplate = substitute(jnlpTemplate, "$$session", session);
|
||||||
jnlpTemplate = substitute(jnlpTemplate, "$$streamId", streamId);
|
jnlpTemplate = substitute(jnlpTemplate, "$$streamId", streamId);
|
||||||
jnlpTemplate = substitute(jnlpTemplate, "$$codecOptions", codecOptions);
|
jnlpTemplate = substitute(jnlpTemplate, "$$codecOptions", codecOptions);
|
||||||
|
jnlpTemplate = substitute(jnlpTemplate, "$$useH264", useH264.toString());
|
||||||
jnlpTemplate = substitute(jnlpTemplate, "$$errorMessage", errorMessage);
|
jnlpTemplate = substitute(jnlpTemplate, "$$errorMessage", errorMessage);
|
||||||
// fix for 5039951: Add $$hostname macro
|
// fix for 5039951: Add $$hostname macro
|
||||||
jnlpTemplate = substitute(jnlpTemplate, "$$hostname", request.getServerName());
|
jnlpTemplate = substitute(jnlpTemplate, "$$hostname", request.getServerName());
|
||||||
|
@ -11,7 +11,7 @@ public interface IScreenShareApplication {
|
|||||||
Boolean recordStream(String meetingId, String streamId);
|
Boolean recordStream(String meetingId, String streamId);
|
||||||
|
|
||||||
void isScreenSharing(String meetingId, String userId);
|
void isScreenSharing(String meetingId, String userId);
|
||||||
void requestShareToken(String meetingId, String userId, Boolean record);
|
void requestShareToken(String meetingId, String userId, Boolean record, Boolean tunnel);
|
||||||
void startShareRequest(String meetingId, String userId, String session);
|
void startShareRequest(String meetingId, String userId, String session);
|
||||||
void pauseShareRequest(String meetingId, String userId, String streamId);
|
void pauseShareRequest(String meetingId, String userId, String streamId);
|
||||||
void restartShareRequest(String meetingId, String userId);
|
void restartShareRequest(String meetingId, String userId);
|
||||||
|
@ -5,10 +5,12 @@ public class ScreenShareInfo {
|
|||||||
public final String session;
|
public final String session;
|
||||||
public final String streamId;
|
public final String streamId;
|
||||||
public final String publishUrl;
|
public final String publishUrl;
|
||||||
|
public final Boolean tunnel;
|
||||||
|
|
||||||
public ScreenShareInfo(String session, String publishUrl, String streamId) {
|
public ScreenShareInfo(String session, String publishUrl, String streamId, Boolean tunnel) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.streamId = streamId;
|
this.streamId = streamId;
|
||||||
this.publishUrl = publishUrl;
|
this.publishUrl = publishUrl;
|
||||||
|
this.tunnel = tunnel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,8 +34,8 @@ public class Red5AppHandler {
|
|||||||
app.isScreenSharing(meetingId, userId);
|
app.isScreenSharing(meetingId, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestShareToken(String meetingId, String userId, Boolean record) {
|
public void requestShareToken(String meetingId, String userId, Boolean record, Boolean tunnel) {
|
||||||
app.requestShareToken(meetingId, userId, record);
|
app.requestShareToken(meetingId, userId, record, tunnel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startShareRequest(String meetingId, String userId, String session) {
|
public void startShareRequest(String meetingId, String userId, String session) {
|
||||||
|
@ -133,12 +133,13 @@ public class Red5AppService {
|
|||||||
Boolean record = (Boolean) msg.get("record");
|
Boolean record = (Boolean) msg.get("record");
|
||||||
String meetingId = Red5.getConnectionLocal().getScope().getName();
|
String meetingId = Red5.getConnectionLocal().getScope().getName();
|
||||||
String userId = (String) Red5.getConnectionLocal().getAttribute("USERID");
|
String userId = (String) Red5.getConnectionLocal().getAttribute("USERID");
|
||||||
|
Boolean tunnel = (Boolean) msg.get("tunnel");
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug("Received startShareRequest for meetingId=" + meetingId + " from user=" + userId);
|
log.debug("Received startShareRequest for meetingId=" + meetingId + " from user=" + userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.requestShareToken(meetingId, userId, record);
|
handler.requestShareToken(meetingId, userId, record, tunnel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopShareRequest(Map<String, Object> msg) {
|
public void stopShareRequest(Map<String, Object> msg) {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user