Merge remote-tracking branch 'upstream/master' into merge-webrtc-screenshare-2

Conflicts:
	bigbluebutton-client/resources/config.xml.template
This commit is contained in:
perroned 2017-02-02 15:27:08 +00:00
commit 1116cc0d1e
1030 changed files with 21332 additions and 10661 deletions

View File

@ -9,6 +9,8 @@ import org.bigbluebutton.core.bus._
import org.bigbluebutton.core.api._
import org.bigbluebutton.SystemConfiguration
import java.util.concurrent.TimeUnit
object BigBlueButtonActor extends SystemConfiguration {
def props(system: ActorSystem,
eventBus: IncomingEventBus,
@ -121,17 +123,26 @@ class BigBlueButtonActor(val system: ActorSystem,
eventBus.publish(BigBlueButtonEvent(m.mProps.parentMeetingID,
BreakoutRoomEnded(m.mProps.parentMeetingID, m.mProps.meetingID)))
}
// Eject all users using the client.
outGW.send(new EndAndKickAll(msg.meetingID, m.mProps.recorded))
outGW.send(new DisconnectAllUsers(msg.meetingID))
log.info("Destroyed meetingId={}", msg.meetingID)
outGW.send(new MeetingDestroyed(msg.meetingID))
// Eject all users from the voice conference
outGW.send(new EjectAllVoiceUsers(msg.meetingID, m.mProps.recorded, m.mProps.voiceBridge))
/** Unsubscribe to meeting and voice events. **/
eventBus.unsubscribe(m.actorRef, m.mProps.meetingID)
eventBus.unsubscribe(m.actorRef, m.mProps.voiceBridge)
// Delay sending DisconnectAllUsers because of RTMPT connection being dropped before UserEject message arrives to the client
context.system.scheduler.scheduleOnce(Duration.create(2500, TimeUnit.MILLISECONDS)) {
// Disconnect all clients
outGW.send(new DisconnectAllUsers(msg.meetingID))
log.info("Destroyed meetingId={}", msg.meetingID)
outGW.send(new MeetingDestroyed(msg.meetingID))
// Stop the meeting actor.
context.stop(m.actorRef)
/** Unsubscribe to meeting and voice events. **/
eventBus.unsubscribe(m.actorRef, m.mProps.meetingID)
eventBus.unsubscribe(m.actorRef, m.mProps.voiceBridge)
// Stop the meeting actor.
context.stop(m.actorRef)
}
}
}
}

View File

@ -65,6 +65,7 @@ class BigBlueButtonInGW(
msg.payload.durationInMinutes,
msg.payload.autoStartRecording,
msg.payload.allowStartStopRecording,
msg.payload.webcamsOnlyForModerator,
msg.payload.moderatorPassword,
msg.payload.viewerPassword,
msg.payload.createTime,

View File

@ -114,20 +114,12 @@ class LiveMeeting(val mProps: MeetingProperties,
}
def handleEndMeeting(msg: EndMeeting) {
// Broadcast users the meeting will end
outGW.send(new MeetingEnding(msg.meetingId))
meetingModel.meetingHasEnded
/**
* Check if this meeting has breakout rooms. If so, we also need to end them.
*/
handleEndAllBreakoutRooms(new EndAllBreakoutRooms(msg.meetingId))
outGW.send(new MeetingEnded(msg.meetingId, mProps.recorded, mProps.voiceBridge))
// Delay sending DisconnectAllUsers because of RTMPT connection being dropped before UserEject message arrives to the client
import context.dispatcher
context.system.scheduler.scheduleOnce(Duration.create(2500, TimeUnit.MILLISECONDS)) {
log.info("Sending delayed DisconnectUser. meetingId={}", mProps.meetingID)
outGW.send(new DisconnectAllUsers(msg.meetingId))
}
}
def handleAllowUserToShareDesktop(msg: AllowUserToShareDesktop): Unit = {

View File

@ -6,8 +6,8 @@ import java.util.concurrent.TimeUnit
case object StopMeetingActor
case class MeetingProperties(meetingID: String, externalMeetingID: String, parentMeetingID: String, meetingName: String,
recorded: Boolean, voiceBridge: String, deskshareBridge: String, duration: Int,
autoStartRecording: Boolean, allowStartStopRecording: Boolean, moderatorPass: String,
viewerPass: String, createTime: Long, createDate: String,
autoStartRecording: Boolean, allowStartStopRecording: Boolean, webcamsOnlyForModerator: Boolean,
moderatorPass: String, viewerPass: String, createTime: Long, createDate: String,
red5DeskShareIP: String, red5DeskShareApp: String, isBreakout: Boolean, sequence: Int)
case class MeetingExtensionProp(maxExtensions: Int = 2, numExtensions: Int = 0, extendByMinutes: Int = 20,

View File

@ -54,6 +54,7 @@ class MessageSenderActor(val service: MessageSender)
case msg: VoiceRecordingStopped => handleVoiceRecordingStopped(msg)
case msg: RecordingStatusChanged => handleRecordingStatusChanged(msg)
case msg: GetRecordingStatusReply => handleGetRecordingStatusReply(msg)
case msg: MeetingEnding => handleMeetingEnding(msg)
case msg: MeetingEnded => handleMeetingEnded(msg)
case msg: MeetingHasEnded => handleMeetingHasEnded(msg)
case msg: MeetingDestroyed => handleMeetingDestroyed(msg)
@ -221,7 +222,12 @@ class MessageSenderActor(val service: MessageSender)
service.send(MessagingConstants.FROM_MEETING_CHANNEL, json)
val json2 = UsersMessageToJsonConverter.meetingEnded(msg)
service.send(MessagingConstants.FROM_MEETING_CHANNEL, json2)
service.send(MessagingConstants.FROM_USERS_CHANNEL, json2)
}
private def handleMeetingEnding(msg: MeetingEnding) {
val json = MeetingMessageToJsonConverter.meetingEndingToJson(msg)
service.send(MessagingConstants.FROM_MEETING_CHANNEL, json)
}
private def handleStartRecording(msg: StartRecording) {
@ -265,7 +271,7 @@ class MessageSenderActor(val service: MessageSender)
service.send(MessagingConstants.FROM_MEETING_CHANNEL, json)
val json2 = UsersMessageToJsonConverter.meetingHasEnded(msg)
service.send(MessagingConstants.FROM_MEETING_CHANNEL, json2)
service.send(MessagingConstants.FROM_USERS_CHANNEL, json2)
}
private def handleGetAllMeetingsReply(msg: GetAllMeetingsReply) {

View File

@ -87,6 +87,7 @@ object MessageNames {
val VOICE_RECORDING_STOPPED = "voice_recording_stopped_message"
val RECORDING_STATUS_CHANGED = "recording_status_changed_message"
val GET_RECORDING_STATUS_REPLY = "get_recording_status_reply"
val MEETING_ENDING = "meeting_ending_message"
val MEETING_ENDED = "meeting_ended_message"
val MEETING_HAS_ENDED = "meeting_has_ended_message"
val MEETING_STATE = "meeting_state_message"

View File

@ -17,6 +17,7 @@ case class GetRecordingStatusReply(meetingID: String, recorded: Boolean, userId:
case class MeetingCreated(meetingID: String, externalMeetingID: String, parentMeetingID: String, recorded: Boolean, name: String,
voiceBridge: String, duration: Int, moderatorPass: String, viewerPass: String, createTime: Long, createDate: String, isBreakout: Boolean) extends IOutMessage
case class MeetingMuted(meetingID: String, recorded: Boolean, meetingMuted: Boolean) extends IOutMessage
case class MeetingEnding(meetingID: String) extends IOutMessage
case class MeetingEnded(meetingID: String, recorded: Boolean, voiceBridge: String) extends IOutMessage
case class MeetingState(meetingID: String, recorded: Boolean, userId: String, permissions: Permissions, meetingMuted: Boolean) extends IOutMessage
case class MeetingHasEnded(meetingID: String, userId: String) extends IOutMessage

View File

@ -577,9 +577,8 @@ trait UsersApp {
userLeaving foreach (u => outGW.send(new UserLeft(mProps.meetingID, mProps.recorded, u)))
}
}
stopRecordingVoiceConference()
}
stopRecordingVoiceConference()
}
def handleUserMutedInVoiceConfMessage(msg: UserMutedInVoiceConfMessage) {

View File

@ -52,6 +52,14 @@ object MeetingMessageToJsonConverter {
Util.buildJson(header, payload)
}
def meetingEndingToJson(msg: MeetingEnding): String = {
val payload = new java.util.HashMap[String, Any]()
payload.put(Constants.MEETING_ID, msg.meetingID)
val header = Util.buildHeader(MessageNames.MEETING_ENDING, None)
Util.buildJson(header, payload)
}
def voiceRecordingStartedToJson(msg: VoiceRecordingStarted): String = {
val payload = new java.util.HashMap[String, Any]()
payload.put(Constants.MEETING_ID, msg.meetingID)

View File

@ -13,6 +13,7 @@ trait AppsTestFixtures {
val durationInMinutes = 10
val autoStartRecording = false
val allowStartStopRecording = false
val webcamsOnlyForModerator = false;
val moderatorPassword = "modpass"
val viewerPassword = "viewpass"
val createTime = System.currentTimeMillis
@ -25,7 +26,7 @@ trait AppsTestFixtures {
meetingName, record,
voiceConfId, deskshareConfId,
durationInMinutes,
autoStartRecording, allowStartStopRecording,
autoStartRecording, allowStartStopRecording, webcamsOnlyForModerator,
moderatorPassword, viewerPassword,
createTime, createDate, red5DeskShareIP, red5DeskShareApp,
isBreakout, sequence)

View File

@ -234,10 +234,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
// - username
@ -245,19 +243,16 @@ public String getJoinURL(String username, String meetingID, String record, Strin
// - record ["true", "false"]
// - welcome message (null causes BigBlueButton to use the default welcome message
// - metadata (passed through when record="true"
// - xml (used for pre-upload of slides)_
// - xml (used for pre-upload of slides)
// - isModerator [true, false]
//
// Returned
// - valid join URL using the username
//
// Note this meeting will use username for meetingID
//
// VERSION ADJUSTED TO THE NEEDS OF THE HTML5 CLIENT
// -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) {
public String getJoinURLHTML5(String username, String meetingID, String record, String welcome, Map<String, String> metadata, String xml, boolean isModerator) {
String base_url_create = BigBlueButtonURL + "api/create?";
String base_url_join = BigBlueButtonURL + "api/join?";
@ -272,6 +267,13 @@ public String getJoinURLHTML5(String username, String meetingID, String record,
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();
String voiceBridge_param = "&voiceBridge=" + (70000 + random.nextInt(9999));
@ -290,8 +292,11 @@ public String getJoinURLHTML5(String username, String meetingID, String record,
//
String create_parameters = "name=" + urlEncode(meetingID)
+ "&meetingID=" + urlEncode(meetingID) + welcome_param + voiceBridge_param
+ "&attendeePW=ap&moderatorPW=mp"
+ "&meetingID=" + urlEncode(meetingID)
+ welcome_param
+ voiceBridge_param
+ "&attendeePW=" + defaultAttendeePW
+ "&moderatorPW=" + defaultModeratorPW
+ "&record=" + record + getMetaData( metadata );
@ -314,8 +319,11 @@ public String getJoinURLHTML5(String username, String meetingID, String record,
// 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)
+ "&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="
+ checksum("join" + join_parameters + salt);

View File

@ -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>

View File

@ -35,9 +35,11 @@ Author: Fred Dixon <ffdixon@bigbluebutton.org>
<body>
<p>You must have the BigBlueButton HTML5 client installed to use this API demo.</p>
<%@ include file="bbb_api.jsp"%>
<%
<%
if (request.getParameterMap().isEmpty()) {
//
// Assume we want to create a meeting
@ -47,29 +49,36 @@ if (request.getParameterMap().isEmpty()) {
<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; ">
<tbody>
<tr>
<td>
&nbsp;</td>
<td style="text-align: right; ">
Full Name:</td>
<td style="width: 5px; ">
&nbsp;</td>
<td style="text-align: left ">
<input type="text" autofocus required name="username" /></td>
<td>&nbsp;</td>
<td style="text-align: right; ">Full Name:</td>
<td style="width: 5px; ">&nbsp;</td>
<td style="text-align: left "><input type="text" autofocus required name="username" /></td>
</tr>
<tr>
<td>&nbsp;</td>
<td style="text-align: right; ">Meeting Name:</td>
<td style="width: 5px; ">&nbsp;</td>
<td style="text-align: left "><input type="text" required name="meetingname" value="Demo Meeting" /></td>
<tr>
<tr>
<td>&nbsp;</td>
<td style="text-align: right; ">Moderator Role:</td>
<td style="width: 5px; ">&nbsp;</td>
<td style="text-align: left "><input type=checkbox name=isModerator value="true"></td>
<tr>
<tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td><input type="submit" value="Join" /></td>
<tr>
<td>
&nbsp;</td>
<td>
&nbsp;</td>
<td>
&nbsp;</td>
<td>
<input type="submit" value="Join" /></td>
</tr>
</tbody>
</table>
<INPUT TYPE=hidden NAME=action VALUE="create">
@ -84,10 +93,10 @@ if (request.getParameterMap().isEmpty()) {
//
String username = request.getParameter("username");
String url = BigBlueButtonURL.replace("bigbluebutton/","demo/");
// String preUploadPDF = "<?xml version='1.0' encoding='UTF-8'?><modules><module name='presentation'><document url='"+url+"pdfs/sample.pdf'/></module></modules>";
String meetingname = request.getParameter("meetingname");
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;
doc = parseXml(getURL(joinURL));

View File

@ -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="demo2.jsp">Join Selected</a> |
<a href="demo2.jsp">Join Selected</a> |
<a href="demo3.jsp">Join Password</a> &nbsp;&nbsp;
<a href="demo7.jsp">Join & Upload</a> |
<a href="demo8.jsp">Join & Upload</a> (URL) &nbsp;&nbsp;
<a href="demo10.jsp">Record</a> |
<a href="demo6.jsp">Record</a> (Matterhorn) &nbsp;&nbsp;
<a href="demo10.jsp">Record</a> |
<a href="create.jsp">Create</a> &nbsp;&nbsp;
@ -15,12 +14,9 @@
<a href="demo4.jsp">Activity Monitor</a> &nbsp;&nbsp;
<a href="demo_mozilla_persona.jsp">Login with Persona</a> &nbsp;&nbsp;
<a href="demo_openid.jsp">Login with Openid</a> &nbsp;&nbsp;
<a href="demo11.jsp">Javascript API</a> &nbsp;&nbsp;
<a href="mobile.jsp">Mobile Demo</a> &nbsp;&nbsp;
<a href="demoHTML5.jsp">HTML5 Client Demo</a> &nbsp;&nbsp;

View File

@ -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>
&nbsp;</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>

View File

@ -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>&nbsp;</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>&nbsp;</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>

View File

@ -7,5 +7,3 @@ org.eclipse.ltk.core.refactoring.prefs
FlexPrettyPrintCommand.prefs
index.template.html
conf/config.xml
resources/lib/bbb_webrtc_bridge_sip.js
resources/lib/sip.js

View File

@ -103,11 +103,6 @@
</target>
<target name="Resolve-Dependency"
description="Generate HTML wrapper">
<copy todir="resources/lib/" >
<fileset file="../bigbluebutton-client/resources/prod/lib/bbb_webrtc_bridge_sip.js" />
<fileset file="../bigbluebutton-client/resources/prod/lib/sip.js" />
</copy>
<get src="${TEST_IMAGE_URL}" dest="${html.output}/test_image.jpg" skipexisting="true" />
<copy file="html-template/index.html"
tofile="${html.output}/index.html"/>

View File

@ -6,10 +6,6 @@
<firefoxLatestVersion>FIREFOX_VERSION</firefoxLatestVersion>
<downloadFilePath url="test_image.jpg"/>
<ports>
<port>
<name>Port 9123</name>
<number>9123</number>
</port>
</ports>
<rtmpapps>
<app>
@ -17,8 +13,8 @@
<uri>rtmp://HOST/bigbluebutton</uri>
</app>
<app>
<name>RTMP deskShare app</name>
<uri>rtmp://HOST/deskShare</uri>
<name>RTMP screenshare app</name>
<uri>rtmp://HOST/screenshare</uri>
</app>
<app>
<name>RTMP video app</name>
@ -33,8 +29,8 @@
<uri>rtmpt://HOST/bigbluebutton</uri>
</app>
<app>
<name>RTMPT deskShare app</name>
<uri>rtmpt://HOST/deskShare</uri>
<name>RTMPT screenshare app</name>
<uri>rtmpt://HOST/screenshare</uri>
</app>
<app>
<name>RTMPT video app</name>

44
bbb-client-check/resources/lib/api-bridge.js Executable file → Normal file
View File

@ -210,9 +210,11 @@
webrtc_hangup(function() {
console.log("[BBBClientCheck] Handling webRTC hangup callback");
var userAgentTemp = userAgent;
userAgent = null;
userAgentTemp.stop();
if (userAgent) {
var userAgentTemp = userAgent;
userAgent = null;
userAgentTemp.stop();
}
});
}
@ -224,7 +226,7 @@
myRole: "undefined",
amIPresenter: "undefined",
dialNumber: "undefined",
voiceBridge: "undefined",
voiceBridge: "",
customdata: "undefined"
}
@ -243,7 +245,7 @@
BBB.webRTCEchoTestStarted = function() {
console.log("[BBBClientCheck] Handling webRTCEchoTestStarted");
sendWebRTCEchoTestAnswer(true, 'Connected');
sendWebRTCEchoTestAnswer(true, 'Success');
}
BBB.webRTCEchoTestConnecting = function() {
@ -306,4 +308,36 @@
BBB.webRTCMediaFail = function() {
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");
};
}

View File

@ -0,0 +1,545 @@
var userID, callerIdName=null, conferenceVoiceBridge, userAgent=null, userMicMedia, userWebcamMedia, currentSession=null, callTimeout, callActive, callICEConnected, iceConnectedTimeout, callFailCounter, callPurposefullyEnded, uaConnected, transferTimeout, iceGatheringTimeout;
var inEchoTest = true;
var html5StunTurn = {};
function webRTCCallback(message) {
switch (message.status) {
case 'failed':
if (message.errorcode !== 1004) {
message.cause = null;
}
BBB.webRTCCallFailed(inEchoTest, message.errorcode, message.cause);
break;
case 'ended':
BBB.webRTCCallEnded(inEchoTest);
break;
case 'started':
BBB.webRTCCallStarted(inEchoTest);
break;
case 'connecting':
BBB.webRTCCallConnecting(inEchoTest);
break;
case 'waitingforice':
BBB.webRTCCallWaitingForICE(inEchoTest);
break;
case 'transferring':
BBB.webRTCCallTransferring(inEchoTest);
break;
case 'mediarequest':
BBB.webRTCMediaRequest();
break;
case 'mediasuccess':
BBB.webRTCMediaSuccess();
break;
case 'mediafail':
BBB.webRTCMediaFail();
break;
}
}
function callIntoConference(voiceBridge, callback, isListenOnly, stunTurn = null) {
// root of the call initiation process from the html5 client
// Flash will not pass in the listen only field. For html5 it is optional. Assume NOT listen only if no state passed
if (isListenOnly == null) {
isListenOnly = false;
}
// if additional stun configuration is passed, store the information
if (stunTurn != null) {
html5StunTurn['stunServers'] = stunTurn.stun;
html5StunTurn['turnServers'] = stunTurn.turn;
}
// reset callerIdName
callerIdName = null;
if (!callerIdName) {
BBB.getMyUserInfo(function(userInfo) {
console.log("User info callback [myUserID=" + userInfo.myUserID
+ ",myUsername=" + userInfo.myUsername + ",myAvatarURL=" + userInfo.myAvatarURL
+ ",myRole=" + userInfo.myRole + ",amIPresenter=" + userInfo.amIPresenter
+ ",dialNumber=" + userInfo.dialNumber + ",voiceBridge=" + userInfo.voiceBridge
+ ",isListenOnly=" + isListenOnly + "].");
userID = userInfo.myUserID;
callerIdName = userInfo.myUserID + "-bbbID-" + userInfo.myUsername;
if (isListenOnly) {
//prepend the callerIdName so it is recognized as a global audio user
callerIdName = "GLOBAL_AUDIO_" + callerIdName;
}
conferenceVoiceBridge = userInfo.voiceBridge
if (voiceBridge === "9196") {
voiceBridge = voiceBridge + conferenceVoiceBridge;
} else {
voiceBridge = conferenceVoiceBridge;
}
console.log(callerIdName);
webrtc_call(callerIdName, voiceBridge, callback, isListenOnly);
});
} else {
if (voiceBridge === "9196") {
voiceBridge = voiceBridge + conferenceVoiceBridge;
} else {
voiceBridge = conferenceVoiceBridge;
}
webrtc_call(callerIdName, voiceBridge, callback, isListenOnly);
}
}
function joinWebRTCVoiceConference() {
console.log("Joining to the voice conference directly");
inEchoTest = false;
// set proper callbacks to previously created user agent
if(userAgent) {
setUserAgentListeners(webRTCCallback);
}
callIntoConference(conferenceVoiceBridge, webRTCCallback);
}
function leaveWebRTCVoiceConference() {
console.log("Leaving the voice conference");
webrtc_hangup();
}
function startWebRTCAudioTest(){
console.log("Joining the audio test first");
inEchoTest = true;
callIntoConference("9196", webRTCCallback);
}
function stopWebRTCAudioTest(){
console.log("Stopping webrtc audio test");
webrtc_hangup();
}
function stopWebRTCAudioTestJoinConference(){
console.log("Transferring from audio test to conference");
webRTCCallback({'status': 'transferring'});
transferTimeout = setTimeout( function() {
console.log("Call transfer failed. No response after 3 seconds");
webRTCCallback({'status': 'failed', 'errorcode': 1008});
currentSession = null;
if (userAgent != null) {
var userAgentTemp = userAgent;
userAgent = null;
userAgentTemp.stop();
}
}, 5000);
BBB.listen("UserJoinedVoiceEvent", userJoinedVoiceHandler);
currentSession.dtmf(1);
inEchoTest = false;
}
function userJoinedVoiceHandler(event) {
console.log("UserJoinedVoiceHandler - " + event);
if (inEchoTest === false && userID === event.userID) {
BBB.unlisten("UserJoinedVoiceEvent", userJoinedVoiceHandler);
clearTimeout(transferTimeout);
webRTCCallback({'status': 'started'});
}
}
function createUA(username, server, callback, makeCallFunc) {
if (userAgent) {
console.log("User agent already created");
return;
}
console.log("Fetching STUN/TURN server info for user agent");
console.log(html5StunTurn);
if (html5StunTurn != null) {
createUAWithStuns(username, server, callback, html5StunTurn, makeCallFunc);
return;
}
BBB.getSessionToken(function(sessionToken) {
$.ajax({
dataType: 'json',
url: '/bigbluebutton/api/stuns',
data: {sessionToken:sessionToken}
}).done(function(data) {
var stunsConfig = {};
stunsConfig['stunServers'] = ( data['stunServers'] ? data['stunServers'].map(function(data) {
return data['url'];
}) : [] );
stunsConfig['turnServers'] = ( data['turnServers'] ? data['turnServers'].map(function(data) {
return {
'urls': data['url'],
'username': data['username'],
'password': data['password']
};
}) : [] );
createUAWithStuns(username, server, callback, stunsConfig, makeCallFunc);
}).fail(function(data, textStatus, errorThrown) {
BBBLog.error("Could not fetch stun/turn servers", {error: textStatus, user: callerIdName, voiceBridge: conferenceVoiceBridge});
callback({'status':'failed', 'errorcode': 1009});
});
});
}
function createUAWithStuns(username, server, callback, stunsConfig, makeCallFunc) {
console.log("Creating new user agent");
/* VERY IMPORTANT
* - You must escape the username because spaces will cause the connection to fail
* - We are connecting to the websocket through an nginx redirect instead of directly to 5066
*/
var configuration = {
uri: 'sip:' + encodeURIComponent(username) + '@' + server,
wsServers: 'ws://' + server + '/ws',
displayName: username,
register: false,
traceSip: true,
autostart: false,
userAgentString: "BigBlueButton",
stunServers: stunsConfig['stunServers'],
turnServers: stunsConfig['turnServers']
};
uaConnected = false;
userAgent = new SIP.UA(configuration);
setUserAgentListeners(callback, makeCallFunc);
userAgent.start();
};
function setUserAgentListeners(callback, makeCallFunc) {
console.log("resetting UA callbacks");
userAgent.removeAllListeners('connected');
userAgent.on('connected', function() {
uaConnected = true;
makeCallFunc();
});
userAgent.removeAllListeners('disconnected');
userAgent.on('disconnected', function() {
if (userAgent) {
if (userAgent != null) {
var userAgentTemp = userAgent;
userAgent = null;
userAgentTemp.stop();
}
if (uaConnected) {
callback({'status':'failed', 'errorcode': 1001}); // WebSocket disconnected
} else {
callback({'status':'failed', 'errorcode': 1002}); // Could not make a WebSocket connection
}
}
});
};
function getUserMicMedia(getUserMicMediaSuccess, getUserMicMediaFailure) {
if (userMicMedia == undefined) {
if (SIP.WebRTC.isSupported()) {
SIP.WebRTC.getUserMedia({audio:true, video:false}, getUserMicMediaSuccess, getUserMicMediaFailure);
} else {
console.log("getUserMicMedia: webrtc not supported");
getUserMicMediaFailure("WebRTC is not supported");
}
} else {
console.log("getUserMicMedia: mic already set");
getUserMicMediaSuccess(userMicMedia);
}
};
function webrtc_call(username, voiceBridge, callback, isListenOnly) {
if (!isWebRTCAvailable()) {
callback({'status': 'failed', 'errorcode': 1003}); // Browser version not supported
return;
}
if (isListenOnly == null) { // assume NOT listen only unless otherwise stated
isListenOnly = false;
}
var server = window.document.location.hostname;
console.log("user " + username + " calling to " + voiceBridge);
var makeCallFunc = function() {
// only make the call when both microphone and useragent have been created
// for listen only, stating listen only is a viable substitute for acquiring user media control
if ((isListenOnly||userMicMedia) && userAgent)
make_call(username, voiceBridge, server, callback, false, isListenOnly);
};
// Reset userAgent so we can successfully switch between listenOnly and listen+speak modes
userAgent = null;
if (!userAgent) {
createUA(username, server, callback, makeCallFunc);
}
// if the user requests to proceed as listen only (does not require media) or media is already acquired,
// proceed with making the call
if (isListenOnly || userMicMedia !== undefined) {
makeCallFunc();
} else {
callback({'status':'mediarequest'});
getUserMicMedia(function(stream) {
console.log("getUserMicMedia: success");
userMicMedia = stream;
callback({'status':'mediasuccess'});
makeCallFunc();
}, function(e) {
console.error("getUserMicMedia: failure - " + e);
callback({'status':'mediafail', 'cause': e});
}
);
}
}
function make_call(username, voiceBridge, server, callback, recall, isListenOnly) {
if (isListenOnly == null) {
isListenOnly = false;
}
if (userAgent == null) {
console.log("userAgent is still null. Delaying call");
var callDelayTimeout = setTimeout( function() {
make_call(username, voiceBridge, server, callback, recall, isListenOnly);
}, 100);
return;
}
if (!userAgent.isConnected()) {
console.log("Trying to make call, but UserAgent hasn't connected yet. Delaying call");
userAgent.once('connected', function() {
console.log("UserAgent has now connected, retrying the call");
make_call(username, voiceBridge, server, callback, recall, isListenOnly);
});
return;
}
if (currentSession) {
console.log('Active call detected ignoring second make_call');
return;
}
// Make an audio/video call:
console.log("Setting options.. ");
var options = {};
if (isListenOnly) {
// create necessary options for a listen only stream
var stream = null;
// handle the web browser
// create a stream object through the browser separated from user media
if (typeof webkitMediaStream !== 'undefined') {
// Google Chrome
stream = new webkitMediaStream;
} else {
// Firefox
audioContext = new window.AudioContext;
stream = audioContext.createMediaStreamDestination().stream;
}
options = {
media: {
stream: stream, // use the stream created above
constraints: {
audio: true,
video: false
},
render: {
remote: document.getElementById('remote-media')
}
},
// a list of our RTC Connection constraints
RTCConstraints: {
// our constraints are mandatory. We must received audio and must not receive audio
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: false
}
}
};
} else {
options = {
media: {
stream: userMicMedia,
constraints: {
audio: true,
video: false
},
render: {
remote: document.getElementById('remote-media')
}
}
};
}
callTimeout = setTimeout(function() {
console.log('Ten seconds without updates sending timeout code');
callback({'status':'failed', 'errorcode': 1006}); // Failure on call
currentSession = null;
if (userAgent != null) {
var userAgentTemp = userAgent;
userAgent = null;
userAgentTemp.stop();
}
}, 10000);
callActive = false;
callICEConnected = false;
callPurposefullyEnded = false;
callFailCounter = 0;
console.log("Calling to " + voiceBridge + "....");
currentSession = userAgent.invite('sip:' + voiceBridge + '@' + server, options);
// Only send the callback if it's the first try
if (recall === false) {
console.log('call connecting');
callback({'status':'connecting'});
} else {
console.log('call connecting again');
}
/*
iceGatheringTimeout = setTimeout(function() {
console.log('Thirty seconds without ICE gathering finishing');
callback({'status':'failed', 'errorcode': 1011}); // ICE Gathering Failed
currentSession = null;
if (userAgent != null) {
var userAgentTemp = userAgent;
userAgent = null;
userAgentTemp.stop();
}
}, 30000);
*/
currentSession.mediaHandler.on('iceGatheringComplete', function() {
clearTimeout(iceGatheringTimeout);
});
// The connecting event fires before the listener can be added
currentSession.on('connecting', function(){
clearTimeout(callTimeout);
});
currentSession.on('progress', function(response){
console.log('call progress: ' + response);
clearTimeout(callTimeout);
});
currentSession.on('failed', function(response, cause){
console.log('call failed with cause: '+ cause);
if (currentSession) {
if (callActive === false) {
callback({'status':'failed', 'errorcode': 1004, 'cause': cause}); // Failure on call
currentSession = null;
if (userAgent != null) {
var userAgentTemp = userAgent;
userAgent = null;
userAgentTemp.stop();
}
} else {
callActive = false;
//currentSession.bye();
currentSession = null;
if (userAgent != null) {
userAgent.stop();
}
}
}
clearTimeout(callTimeout);
});
currentSession.on('bye', function(request){
callActive = false;
if (currentSession) {
console.log('call ended ' + currentSession.endTime);
if (callPurposefullyEnded === true) {
callback({'status':'ended'});
} else {
callback({'status':'failed', 'errorcode': 1005}); // Call ended unexpectedly
}
clearTimeout(callTimeout);
currentSession = null;
} else {
console.log('bye event already received');
}
});
currentSession.on('accepted', function(data){
callActive = true;
console.log('BigBlueButton call accepted');
if (callICEConnected === true) {
callback({'status':'started'});
} else {
callback({'status':'waitingforice'});
console.log('Waiting for ICE negotiation');
iceConnectedTimeout = setTimeout(function() {
console.log('60 seconds without ICE finishing');
callback({'status':'failed', 'errorcode': 1010}); // ICE negotiation timeout
currentSession = null;
if (userAgent != null) {
var userAgentTemp = userAgent;
userAgent = null;
userAgentTemp.stop();
}
}, 60000);
}
clearTimeout(callTimeout);
});
currentSession.mediaHandler.on('iceConnectionFailed', function() {
console.log('received ice negotiation failed');
callback({'status':'failed', 'errorcode': 1007}); // Failure on call
currentSession = null;
clearTimeout(iceConnectedTimeout);
if (userAgent != null) {
var userAgentTemp = userAgent;
userAgent = null;
userAgentTemp.stop();
}
clearTimeout(callTimeout);
});
// Some browsers use status of 'connected', others use 'completed', and a couple use both
currentSession.mediaHandler.on('iceConnectionConnected', function() {
console.log('Received ICE status changed to connected');
if (callICEConnected === false) {
callICEConnected = true;
clearTimeout(iceConnectedTimeout);
if (callActive === true) {
callback({'status':'started'});
}
clearTimeout(callTimeout);
}
});
currentSession.mediaHandler.on('iceConnectionCompleted', function() {
console.log('Received ICE status changed to completed');
if (callICEConnected === false) {
callICEConnected = true;
clearTimeout(iceConnectedTimeout);
if (callActive === true) {
callback({'status':'started'});
}
clearTimeout(callTimeout);
}
});
}
function webrtc_hangup(callback) {
callPurposefullyEnded = true;
console.log("Hanging up current session");
if (callback) {
currentSession.on('bye', callback);
}
currentSession.bye();
}
function isWebRTCAvailable() {
return SIP.WebRTC.isSupported();
}
function getCallStatus() {
return currentSession;
}

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,7 @@ public class Constants {
public static final String RECORDING = "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 WEBCAMS_ONLY_FOR_MODERATOR = "webcams_only_for_moderator";
public static final String LAYOUT_ID = "layout_id";
public static final String LISTENONLY = "listenOnly";
public static final String LISTEN_ONLY = "listen_only";

View File

@ -12,6 +12,7 @@ public class CreateMeetingMessage implements IBigBlueButtonMessage {
public final Long duration;
public final Boolean autoStartRecording;
public final Boolean allowStartStopRecording;
public final Boolean webcamsOnlyForModerator;
public final String moderatorPass;
public final String viewerPass;
public final Long createTime;
@ -19,8 +20,9 @@ public class CreateMeetingMessage implements IBigBlueButtonMessage {
public CreateMeetingMessage(String id, String externalId, String name, Boolean record, String voiceBridge,
Long duration, Boolean autoStartRecording,
Boolean allowStartStopRecording, String moderatorPass,
String viewerPass, Long createTime, String createDate) {
Boolean allowStartStopRecording,Boolean webcamsOnlyForModerator,
String moderatorPass, String viewerPass,
Long createTime, String createDate) {
this.id = id;
this.externalId = externalId;
this.name = name;
@ -29,6 +31,7 @@ public class CreateMeetingMessage implements IBigBlueButtonMessage {
this.duration = duration;
this.autoStartRecording = autoStartRecording;
this.allowStartStopRecording = allowStartStopRecording;
this.webcamsOnlyForModerator = webcamsOnlyForModerator;
this.moderatorPass = moderatorPass;
this.viewerPass = viewerPass;
this.createTime = createTime;

View File

@ -0,0 +1,48 @@
package org.bigbluebutton.common.messages;
import java.util.HashMap;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public class MeetingEndingMessage implements ISubscribedMessage {
public static final String MEETING_ENDING = "meeting_ending_message";
public final String VERSION = "0.0.1";
public final String meetingId;
public MeetingEndingMessage(String meetingID) {
this.meetingId = meetingID;
}
public String toJson() {
HashMap<String, Object> payload = new HashMap<String, Object>();
payload.put(Constants.MEETING_ID, meetingId);
java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(MEETING_ENDING, VERSION, null);
return MessageBuilder.buildJson(header, payload);
}
public static MeetingEndingMessage fromJson(String message) {
JsonParser parser = new JsonParser();
JsonObject obj = (JsonObject) parser.parse(message);
if (obj.has("header") && obj.has("payload")) {
JsonObject header = (JsonObject) obj.get("header");
JsonObject payload = (JsonObject) obj.get("payload");
if (header.has("name")) {
String messageName = header.get("name").getAsString();
if (MEETING_ENDING.equals(messageName)) {
if (payload.has(Constants.MEETING_ID)) {
String meetingId = payload.get(Constants.MEETING_ID).getAsString();
return new MeetingEndingMessage(meetingId);
}
}
}
}
return null;
}
}

View File

@ -60,6 +60,7 @@ public class MessageFromJsonConverter {
Long duration = payload.get(Constants.DURATION).getAsLong();
Boolean autoStartRecording = payload.get(Constants.AUTO_START_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 viewerPassword = payload.get(Constants.VIEWER_PASS).getAsString();
Long createTime = payload.get(Constants.CREATE_TIME).getAsLong();
@ -67,7 +68,8 @@ public class MessageFromJsonConverter {
return new CreateMeetingMessage(id, externalId, name, record, voiceBridge,
duration, autoStartRecording, allowStartStopRecording,
moderatorPassword, viewerPassword, createTime, createDate);
webcamsOnlyForModerator, moderatorPassword, viewerPassword,
createTime, createDate);
}
private static IBigBlueButtonMessage processDestroyMeeting(JsonObject payload) {

View File

@ -23,6 +23,7 @@ public class CreateMeetingRequest implements IBigBlueButtonMessage {
public final Integer durationInMinutes;
public final Boolean autoStartRecording;
public final Boolean allowStartStopRecording;
public final Boolean webcamsOnlyForModerator;
public final String moderatorPassword;
public final String viewerPassword;
public final Long createTime;
@ -34,8 +35,9 @@ public class CreateMeetingRequest implements IBigBlueButtonMessage {
String parentId, String name, Boolean record,
String voiceConfId, Integer duration,
Boolean autoStartRecording, Boolean allowStartStopRecording,
String moderatorPass, String viewerPass, Long createTime,
String createDate, Boolean isBreakout, Integer sequence) {
Boolean webcamsOnlyForModerator, String moderatorPass,
String viewerPass, Long createTime, String createDate,
Boolean isBreakout, Integer sequence) {
this.id = id;
this.externalId = externalId;
this.parentId = parentId;
@ -45,6 +47,7 @@ public class CreateMeetingRequest implements IBigBlueButtonMessage {
this.durationInMinutes = duration;
this.autoStartRecording = autoStartRecording;
this.allowStartStopRecording = allowStartStopRecording;
this.webcamsOnlyForModerator = webcamsOnlyForModerator;
this.moderatorPassword = moderatorPass;
this.viewerPassword = viewerPass;
this.createTime = createTime;

View File

@ -8,46 +8,48 @@ import org.junit.Test;
import com.google.gson.Gson;
public class CreateMeetingRequestTest {
@Test
public void testCreateMeetingRequest() {
String meetingId = "abc123";
String externalId = "extabc123";
String parentId = "";
Boolean record = false;
Integer durationInMinutes = 20;
String name = "Breakout room 1";
String voiceConfId = "851153";
Boolean autoStartRecording = false;
Boolean allowStartStopRecording = false;
Boolean isBreakout = true;
Integer sequence = 4;
String viewerPassword = "vp";
String moderatorPassword = "mp";
long createTime = System.currentTimeMillis();
String createDate = new Date(createTime).toString();
@Test
public void testCreateMeetingRequest() {
String meetingId = "abc123";
String externalId = "extabc123";
String parentId = "";
Boolean record = false;
Integer durationInMinutes = 20;
String name = "Breakout room 1";
String voiceConfId = "851153";
Boolean autoStartRecording = false;
Boolean allowStartStopRecording = false;
Boolean webcamsOnlyForModerator = false;
Boolean isBreakout = true;
Integer sequence = 4;
String viewerPassword = "vp";
String moderatorPassword = "mp";
long createTime = System.currentTimeMillis();
String createDate = new Date(createTime).toString();
CreateMeetingRequestPayload payload = new CreateMeetingRequestPayload(
meetingId, externalId, parentId, name, record, voiceConfId,
durationInMinutes, autoStartRecording, allowStartStopRecording,
moderatorPassword, viewerPassword, createTime, createDate,
isBreakout, sequence);
CreateMeetingRequest msg = new CreateMeetingRequest(payload);
Gson gson = new Gson();
String json = gson.toJson(msg);
System.out.println(json);
CreateMeetingRequest rxMsg = gson.fromJson(json, CreateMeetingRequest.class);
Assert.assertEquals(rxMsg.header.name, CreateMeetingRequest.NAME);
Assert.assertEquals(rxMsg.payload.id, meetingId);
Assert.assertEquals(rxMsg.payload.externalId, externalId);
Assert.assertEquals(rxMsg.payload.parentId, parentId);
Assert.assertEquals(rxMsg.payload.name, name);
Assert.assertEquals(rxMsg.payload.voiceConfId, voiceConfId);
Assert.assertEquals(rxMsg.payload.viewerPassword, viewerPassword);
Assert.assertEquals(rxMsg.payload.moderatorPassword, moderatorPassword);
Assert.assertEquals(rxMsg.payload.durationInMinutes, durationInMinutes);
Assert.assertEquals(rxMsg.payload.isBreakout, isBreakout);
Assert.assertEquals(rxMsg.payload.sequence, sequence);
}
webcamsOnlyForModerator, moderatorPassword, viewerPassword,
createTime, createDate, isBreakout, sequence);
CreateMeetingRequest msg = new CreateMeetingRequest(payload);
Gson gson = new Gson();
String json = gson.toJson(msg);
System.out.println(json);
CreateMeetingRequest rxMsg = gson.fromJson(json,
CreateMeetingRequest.class);
Assert.assertEquals(rxMsg.header.name, CreateMeetingRequest.NAME);
Assert.assertEquals(rxMsg.payload.id, meetingId);
Assert.assertEquals(rxMsg.payload.externalId, externalId);
Assert.assertEquals(rxMsg.payload.parentId, parentId);
Assert.assertEquals(rxMsg.payload.name, name);
Assert.assertEquals(rxMsg.payload.voiceConfId, voiceConfId);
Assert.assertEquals(rxMsg.payload.viewerPassword, viewerPassword);
Assert.assertEquals(rxMsg.payload.moderatorPassword, moderatorPassword);
Assert.assertEquals(rxMsg.payload.durationInMinutes, durationInMinutes);
Assert.assertEquals(rxMsg.payload.isBreakout, isBreakout);
Assert.assertEquals(rxMsg.payload.sequence, sequence);
}
}

View File

@ -34,6 +34,7 @@ cd lib
sudo cp -r ~/dev/bigbluebutton/bbb-screenshare/app/jws/lib/* .
cd ..
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 chown -R red5:red5 /usr/share/red5/webapps/screenshare

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -16,23 +16,23 @@
</resources>
<resources os="Windows" arch="amd64">
<nativelib href="ffmpeg-windows-x86_64.jar"/>
<nativelib href="ffmpeg-win-x86_64-svc2.jar"/>
</resources>
<resources os="Windows" arch="x86">
<nativelib href="$$jnlpUrl/lib/ffmpeg-windows-x86.jar"/>
<nativelib href="ffmpeg-win-x86-svc2.jar"/>
</resources>
<resources os="Linux" arch="x86_64 amd64">
<nativelib href="ffmpeg-linux-x86_64.jar"/>
<nativelib href="ffmpeg-linux-x86_64-svc2.jar"/>
</resources>
<resources os="Linux" arch="x86 i386 i486 i586 i686">
<nativelib href="ffmpeg-linux-x86.jar"/>
<nativelib href="ffmpeg-linux-x86-svc2.jar"/>
</resources>
<resources os="Mac OS X">
<nativelib href="ffmpeg-macosx-x86_64.jar"/>
<nativelib href="ffmpeg-macosx-x86_64-svc2.jar"/>
</resources>
<application-desc
@ -45,6 +45,7 @@
<argument>$$fullScreen</argument>
<argument>$$codecOptions</argument>
<argument>$$session</argument>
<argument>$$useH264</argument>
<argument>$$errorMessage</argument>
</application-desc>
<security><all-permissions/></security>

View File

@ -16,23 +16,23 @@
</resources>
<resources os="Windows" arch="amd64">
<nativelib href="ffmpeg-windows-x86_64.jar"/>
<nativelib href="ffmpeg-win-x86_64-h264.jar"/>
</resources>
<resources os="Windows" arch="x86">
<nativelib href="$$jnlpUrl/lib/ffmpeg-windows-x86.jar"/>
<nativelib href="ffmpeg-win-x86-h264.jar"/>
</resources>
<resources os="Linux" arch="x86_64 amd64">
<nativelib href="ffmpeg-linux-x86_64.jar"/>
<nativelib href="ffmpeg-linux-x86_64-h264.jar"/>
</resources>
<resources os="Linux" arch="x86 i386 i486 i586 i686">
<nativelib href="ffmpeg-linux-x86.jar"/>
<nativelib href="ffmpeg-linux-x86-h264.jar"/>
</resources>
<resources os="Mac OS X">
<nativelib href="ffmpeg-macosx-x86_64.jar"/>
<nativelib href="ffmpeg-macosx-x86_64-h264.jar"/>
</resources>
<application-desc
@ -45,6 +45,7 @@
<argument>$$fullScreen</argument>
<argument>$$codecOptions</argument>
<argument>$$session</argument>
<argument>$$useH264</argument>
<argument>$$errorMessage</argument>
</application-desc>
<security><all-permissions/></security>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,15 +1,181 @@
This directory contains the difference JavaCV jar files that we need for our web start application.
** NOTE: **
Taken from https://github.com/bytedeco/javacpp-presets/wiki/Build-Environments
To build each native library and sign each ffmpeg native libraries:
1. cd to the platform directory you want to build (cd ffmpeg-win-x86)
2. type ```gradle jar``` to build the jar file
3. type ```ant sign-jar``` to sign the jar file with your certificate
4. copy the signed-jar to ```bbb-screenshare/app/jws/lib``` to be included when
deploying to red5
We have included unsigned jars for ```ffmpeg.jar```, ```javacpp.jar```, and ```javacv.jar``` in the
unsigned-jars directory. You can sign the jar files there with your certificate.
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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
FFMPEG=ffmpeg-3.0.2-1.2-windows-x86.jar
FFMPEG=ffmpeg-3.0.2-1.2-windows-x86-h264.jar
mkdir workdir
cp $FFMPEG workdir/ffmpeg-windows-x86.jar
rm -rf src
@ -10,8 +10,8 @@ cp org/bytedeco/javacpp/windows-x86/*.dll ../src/main/resources
cd ..
rm -rf workdir
gradle jar
cp build/libs/ffmpeg-windows-x86-0.0.1.jar ../unsigned-jars/ffmpeg-windows-x86-unsigned.jar
cp build/libs/ffmpeg-windows-x86-0.0.1.jar ../../unsigned-jars/ffmpeg-win-x86-h264-unsigned.jar
ant sign-jar
cp build/libs/ffmpeg-windows-x86-0.0.1.jar ../../../app/jws/lib/ffmpeg-windows-x86.jar
cp build/libs/ffmpeg-windows-x86-0.0.1.jar ../../../../app/jws/lib/ffmpeg-win-x86-h264.jar
rm -rf src

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
FFMPEG=ffmpeg-3.0.2-1.2-windows-x86_64.jar
FFMPEG=ffmpeg-3.0.2-1.2-windows-x86_64-h264.jar
mkdir workdir
cp $FFMPEG workdir/ffmpeg-windows-x86_64.jar
rm -rf src
@ -10,8 +10,8 @@ cp org/bytedeco/javacpp/windows-x86_64/*.dll ../src/main/resources
cd ..
rm -rf workdir
gradle jar
cp build/libs/ffmpeg-windows-x86_64-0.0.1.jar ../unsigned-jars/ffmpeg-windows-x86_64-unsigned.jar
cp build/libs/ffmpeg-windows-x86_64-0.0.1.jar ../../unsigned-jars/ffmpeg-win-x86_64-h264-unsigned.jar
ant sign-jar
cp build/libs/ffmpeg-windows-x86_64-0.0.1.jar ../../../app/jws/lib/ffmpeg-windows-x86_64.jar
cp build/libs/ffmpeg-windows-x86_64-0.0.1.jar ../../../../app/jws/lib/ffmpeg-win-x86_64-h264.jar
rm -rf src

View File

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

View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More