Merge branch 'master' of https://github.com/bigbluebutton/bigbluebutton into improving-client-checks
This commit is contained in:
commit
535604b8b6
@ -21,3 +21,5 @@
|
||||
|
||||
<a href="demo11.jsp">Javascript API</a>
|
||||
|
||||
<a href="mobile.jsp">Mobile Demo</a>  
|
||||
|
||||
|
140
bbb-api-demo/src/main/webapp/mobile.jsp
Normal file → Executable file
140
bbb-api-demo/src/main/webapp/mobile.jsp
Normal file → Executable file
@ -1,51 +1,119 @@
|
||||
<%
|
||||
/*
|
||||
BigBlueButton - http://www.bigbluebutton.org
|
||||
<!--
|
||||
|
||||
Copyright (c) 2011 by respective authors (see below). All rights reserved.
|
||||
BigBlueButton - http://www.bigbluebutton.org
|
||||
|
||||
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.
|
||||
Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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/>.
|
||||
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.
|
||||
|
||||
Author: Felipe Cecagno <fcecagno@gmail.com>
|
||||
*/
|
||||
%>
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
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: Chad Pilkey <capilkey@gmail.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>Join Demo Meeting From Mobile</title>
|
||||
</head>
|
||||
|
||||
<%@page import="org.apache.commons.httpclient.HttpClient"%>
|
||||
<%@page import="org.apache.commons.httpclient.HttpMethod"%>
|
||||
<%@page import="org.apache.commons.httpclient.methods.GetMethod"%>
|
||||
<body>
|
||||
|
||||
<%@ include file="mobile_api.jsp"%>
|
||||
<%@ include file="bbb_api.jsp"%>
|
||||
|
||||
<%
|
||||
String result = error(E_INVALID_URL);
|
||||
if (request.getParameterMap().isEmpty()) {
|
||||
result = success("mobileSupported", "This server supports mobile devices.");
|
||||
} else if (request.getParameter("action") == null) {
|
||||
// return the default result
|
||||
} else if (request.getParameter("action").equals("getTimestamp")) {
|
||||
result = getTimestamp(request);
|
||||
} else if (request.getParameter("action").equals("getMeetings")) {
|
||||
result = mobileGetMeetings(request);
|
||||
} else if (request.getParameter("action").equals("join")) {
|
||||
result = mobileJoinMeeting(request);
|
||||
} else if (request.getParameter("action").equals("create")) {
|
||||
result = mobileCreate(request);
|
||||
}
|
||||
if (request.getParameterMap().isEmpty()) {
|
||||
//
|
||||
// Assume we want to create a meeting
|
||||
//
|
||||
%>
|
||||
<%@ include file="demo_header.jsp"%>
|
||||
|
||||
<h2>Join Demo Meeting From Mobile</h2>
|
||||
|
||||
You must have the BigBlueButton mobile client installed on your device for this demo to work.
|
||||
<br /><br />
|
||||
<FORM NAME="form1" METHOD="GET">
|
||||
<table cellpadding="5" cellspacing="5" style="width: 400px; ">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
</td>
|
||||
<td style="text-align: right; ">
|
||||
Full Name:</td>
|
||||
<td style="width: 5px; ">
|
||||
</td>
|
||||
<td style="text-align: left ">
|
||||
<input type="text" autofocus required name="username" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<input type="submit" value="Join" /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<INPUT TYPE=hidden NAME=action VALUE="create">
|
||||
</FORM>
|
||||
|
||||
|
||||
<%
|
||||
} else if (request.getParameter("action").equals("create")) {
|
||||
|
||||
//
|
||||
// Got an action=create
|
||||
//
|
||||
|
||||
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 joinURL = getJoinURL(request.getParameter("username"), "Demo Meeting", "false", null, null, null);
|
||||
|
||||
if (joinURL.startsWith("http://")) {
|
||||
joinURL = joinURL.replace("http", "bigbluebutton");
|
||||
%>
|
||||
<%=result%>
|
||||
|
||||
<script language="javascript" type="text/javascript">
|
||||
window.location.href="<%=joinURL%>";
|
||||
</script>
|
||||
|
||||
<%
|
||||
} else {
|
||||
%>
|
||||
|
||||
Error: getJoinURL() failed
|
||||
<p/>
|
||||
<%=joinURL %>
|
||||
|
||||
<%
|
||||
}
|
||||
}
|
||||
%>
|
||||
|
||||
|
||||
<%@ include file="demo_footer.jsp"%>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,182 +0,0 @@
|
||||
<%
|
||||
/*
|
||||
BigBlueButton - http://www.bigbluebutton.org
|
||||
|
||||
Copyright (c) 2011 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: Felipe Cecagno <fcecagno@gmail.com>
|
||||
*/
|
||||
%>
|
||||
<%@ include file="bbb_api.jsp"%>
|
||||
<%@ include file="mobile_conf.jsp"%>
|
||||
|
||||
<%@page import="org.apache.commons.httpclient.HttpClient"%>
|
||||
<%@page import="org.apache.commons.httpclient.HttpMethod"%>
|
||||
<%@page import="org.apache.commons.httpclient.methods.GetMethod"%>
|
||||
|
||||
<%!
|
||||
public final int E_OK = 0;
|
||||
public final int E_CHECKSUM_NOT_INFORMED = 1;
|
||||
public final int E_INVALID_CHECKSUM = 2;
|
||||
public final int E_INVALID_TIMESTAMP = 3;
|
||||
public final int E_EMPTY_SECURITY_KEY = 4;
|
||||
public final int E_MISSING_PARAM_MEETINGID = 5;
|
||||
public final int E_MISSING_PARAM_FULLNAME = 6;
|
||||
public final int E_MISSING_PARAM_PASSWORD = 7;
|
||||
public final int E_MISSING_PARAM_TIMESTAMP = 8;
|
||||
public final int E_INVALID_URL = 9;
|
||||
|
||||
public String error(int code) {
|
||||
switch(code) {
|
||||
case E_CHECKSUM_NOT_INFORMED:
|
||||
case E_INVALID_CHECKSUM:
|
||||
return error("checksumError", "You did not pass the checksum security check.");
|
||||
case E_INVALID_TIMESTAMP:
|
||||
return error("invalidTimestamp", "You did not pass the timestamp check.");
|
||||
case E_EMPTY_SECURITY_KEY:
|
||||
return error("emptySecurityKey", "The mobile security key is empty. Please contact the administrator.");
|
||||
case E_MISSING_PARAM_MEETINGID:
|
||||
return error("missingParamMeetingID", "You must specify a meeting ID for the meeting.");
|
||||
case E_MISSING_PARAM_FULLNAME:
|
||||
return error("missingParamFullName", "You must specify a name for the attendee who will be joining the meeting.");
|
||||
case E_MISSING_PARAM_PASSWORD:
|
||||
return error("invalidPassword", "You either did not supply a password or the password supplied is neither the attendee or moderator password for this conference.");
|
||||
case E_MISSING_PARAM_TIMESTAMP:
|
||||
return error("missingParamTimestamp", "You must specify the timestamp provided by the server when you called the method getTimestamp.");
|
||||
case E_INVALID_URL:
|
||||
return error("invalidAction", "The requested URL is unavailable.");
|
||||
default:
|
||||
return error("unknownError", "An unexpected error occurred");
|
||||
}
|
||||
}
|
||||
|
||||
private String getRequestURL(HttpServletRequest request) {
|
||||
return request.getQueryString();
|
||||
}
|
||||
|
||||
private String removeChecksum(String requestURL) {
|
||||
return requestURL.substring(0, requestURL.lastIndexOf("&checksum="));
|
||||
}
|
||||
|
||||
private String addValidChecksum(String requestURL) {
|
||||
return requestURL + "&checksum=" + checksum(requestURL + mobileSalt);
|
||||
}
|
||||
|
||||
private int isRequestValid(HttpServletRequest request) {
|
||||
// if there's no checksum parameter, the request isn't valid
|
||||
if (request.getParameter("checksum") == null)
|
||||
return E_CHECKSUM_NOT_INFORMED;
|
||||
|
||||
// check the timestamp for all the requests except getTimestamp
|
||||
if (!request.getParameter("action").equals("getTimestamp")) {
|
||||
String requestTimestamp = request.getParameter("timestamp");
|
||||
if (requestTimestamp == null)
|
||||
return E_MISSING_PARAM_TIMESTAMP;
|
||||
|
||||
Long requestTimestampL = Long.valueOf(requestTimestamp);
|
||||
// the timestamp is valid for 60 seconds
|
||||
if (Math.abs(getTimestamp() - requestTimestampL) > 60)
|
||||
return E_INVALID_TIMESTAMP;
|
||||
}
|
||||
|
||||
if (mobileSalt.isEmpty())
|
||||
return E_EMPTY_SECURITY_KEY;
|
||||
|
||||
String requestURL = getRequestURL(request);
|
||||
String urlWithoutChecksum = removeChecksum(requestURL);
|
||||
String urlWithChecksum = addValidChecksum(urlWithoutChecksum);
|
||||
return (requestURL.equals(urlWithChecksum)? E_OK: E_INVALID_CHECKSUM);
|
||||
}
|
||||
|
||||
private String mountResponse(String returncode, String messageKey, String message) {
|
||||
return "<response><returncode>" + returncode + "</returncode><messageKey>" + messageKey + "</messageKey><message>" + message + "</message></response>";
|
||||
}
|
||||
|
||||
public String success(String messageKey, String message) {
|
||||
return mountResponse("SUCCESS", messageKey, message);
|
||||
}
|
||||
|
||||
public String error(String messageKey, String message) {
|
||||
return mountResponse("FAILED", messageKey, message);
|
||||
}
|
||||
|
||||
private long getTimestamp() {
|
||||
return (System.currentTimeMillis() / 1000L);
|
||||
}
|
||||
|
||||
public String getTimestamp(HttpServletRequest request) {
|
||||
int code = isRequestValid(request);
|
||||
if (code != E_OK)
|
||||
return error(code);
|
||||
|
||||
return "<response><returncode>SUCCESS</returncode><timestamp>" + getTimestamp() + "</timestamp></response>";
|
||||
}
|
||||
|
||||
public String mobileGetMeetings(HttpServletRequest request) {
|
||||
int code = isRequestValid(request);
|
||||
if (code != E_OK)
|
||||
return error(code);
|
||||
|
||||
return getMeetings();
|
||||
}
|
||||
|
||||
public String mobileJoinMeeting(HttpServletRequest request) {
|
||||
int code = isRequestValid(request);
|
||||
if (code != E_OK)
|
||||
return error(code);
|
||||
|
||||
String meetingID = request.getParameter("meetingID");
|
||||
if (meetingID == null) return error(E_MISSING_PARAM_MEETINGID);
|
||||
|
||||
String fullName = request.getParameter("fullName");
|
||||
if (fullName == null) return error(E_MISSING_PARAM_FULLNAME);
|
||||
|
||||
String password = request.getParameter("password");
|
||||
if (password == null) return error(E_MISSING_PARAM_PASSWORD);
|
||||
|
||||
String result = error("failedJoin", "Couldn't join the meeting.");
|
||||
String joinUrl = getJoinMeetingURL(fullName, meetingID, password, null);
|
||||
String enterUrl = BigBlueButtonURL + "api/enter";
|
||||
try {
|
||||
HttpClient client = new HttpClient();
|
||||
HttpMethod method = new GetMethod(joinUrl);
|
||||
client.executeMethod(method);
|
||||
method.releaseConnection();
|
||||
|
||||
method = new GetMethod(enterUrl);
|
||||
client.executeMethod(method);
|
||||
result = method.getResponseBodyAsString();
|
||||
method.releaseConnection();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String mobileCreate(HttpServletRequest request) {
|
||||
int code = isRequestValid(request);
|
||||
if (code != E_OK)
|
||||
return error(code);
|
||||
|
||||
String meetingID = request.getParameter("meetingID");
|
||||
if (meetingID == null) return error(E_MISSING_PARAM_MEETINGID);
|
||||
|
||||
return createMeeting(meetingID, "", "", "", "", 0, BigBlueButtonURL);
|
||||
}
|
||||
|
||||
// it's just for testing purposes
|
||||
private String fixURL(HttpServletRequest request) {
|
||||
return addValidChecksum(removeChecksum(getRequestURL(request)));
|
||||
}
|
||||
%>
|
@ -1,6 +0,0 @@
|
||||
|
||||
<%!
|
||||
// This is the mobile security salt that must be used to check the requests on mobile.jsp
|
||||
String mobileSalt = "";
|
||||
%>
|
||||
|
@ -19,6 +19,11 @@
|
||||
package org.bigbluebutton.voiceconf.red5.media.transcoder;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.bigbluebutton.voiceconf.red5.media.FlashToSipAudioStream.TranscodedAudioListener;
|
||||
import org.red5.app.sip.codecs.Codec;
|
||||
@ -36,9 +41,16 @@ public class SpeexFlashToSipTranscoderImp implements FlashToSipTranscoder {
|
||||
private Codec audioCodec;
|
||||
private long timestamp = 0;
|
||||
private final static int TS_INCREMENT = 320; // Determined from PCAP traces.
|
||||
|
||||
private final Executor exec = Executors.newSingleThreadExecutor();
|
||||
private Runnable audioDataProcessor;
|
||||
private volatile boolean processAudioData = false;
|
||||
private BlockingQueue<SpeexRtpAudioData> audioDataQ;
|
||||
|
||||
private TranscodedAudioListener transcodedAudioListener;
|
||||
|
||||
public SpeexFlashToSipTranscoderImp(Codec audioCodec) {
|
||||
audioDataQ = new LinkedBlockingQueue<SpeexRtpAudioData>();
|
||||
this.audioCodec = audioCodec;
|
||||
Random rgen = new Random();
|
||||
timestamp = rgen.nextInt(1000);
|
||||
@ -49,7 +61,13 @@ public class SpeexFlashToSipTranscoderImp implements FlashToSipTranscoder {
|
||||
// Just copy the audio data removing the codec id which is the first-byte
|
||||
// represented by the startOffset var.
|
||||
System.arraycopy(audioData, startOffset, transcodedAudio, 0, length);
|
||||
transcodedAudioListener.handleTranscodedAudioData(transcodedAudio, timestamp += TS_INCREMENT);
|
||||
|
||||
SpeexRtpAudioData srad = new SpeexRtpAudioData(transcodedAudio, timestamp += TS_INCREMENT);
|
||||
try {
|
||||
audioDataQ.offer(srad, 100, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
log.warn("Failed to add speex audio data into queue.");
|
||||
}
|
||||
}
|
||||
|
||||
public int getCodecId() {
|
||||
@ -74,13 +92,32 @@ public class SpeexFlashToSipTranscoderImp implements FlashToSipTranscoder {
|
||||
this.transcodedAudioListener = transcodedAudioListener;
|
||||
}
|
||||
|
||||
private void processAudioData() {
|
||||
while (processAudioData) {
|
||||
SpeexRtpAudioData srad;
|
||||
try {
|
||||
srad = audioDataQ.take();
|
||||
transcodedAudioListener.handleTranscodedAudioData(srad.audioData, srad.timestamp);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// do nothing. just implement the interface.
|
||||
processAudioData = true;
|
||||
audioDataProcessor = new Runnable() {
|
||||
public void run() {
|
||||
processAudioData();
|
||||
}
|
||||
};
|
||||
exec.execute(audioDataProcessor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
// do nothing. just implement the interface.
|
||||
processAudioData = false;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
package org.bigbluebutton.voiceconf.red5.media.transcoder;
|
||||
|
||||
public class SpeexRtpAudioData {
|
||||
|
||||
public final byte[] audioData;
|
||||
public final long timestamp;
|
||||
|
||||
public SpeexRtpAudioData(byte[] audioData, long timestamp) {
|
||||
this.audioData = audioData;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
@ -2526,6 +2526,15 @@ var Hacks = module.exports = {
|
||||
}
|
||||
}
|
||||
return sdp;
|
||||
},
|
||||
|
||||
hackCLinInIP: function (sdp) {
|
||||
/* Starting in Firefox 34 they have set the c line to 0.0.0.0 which
|
||||
* means "hold" according to legacy SIP standards and Freeswitch
|
||||
* interprets it according to the SIP standards. We replace the
|
||||
* 0.0.0.0 with any other IP so that the call continues.
|
||||
*/
|
||||
return sdp.replace("c=IN IP4 0.0.0.0", "c=IN IP4 127.0.0.1");
|
||||
}
|
||||
},
|
||||
|
||||
@ -6036,6 +6045,9 @@ InviteClientContext.prototype = {
|
||||
if (self.isCanceled || self.status === C.STATUS_TERMINATED) {
|
||||
return;
|
||||
}
|
||||
|
||||
offer = SIP.Hacks.Firefox.hackCLinInIP(offer);
|
||||
|
||||
self.hasOffer = true;
|
||||
self.request.body = offer;
|
||||
self.status = C.STATUS_INVITE_SENT;
|
||||
|
@ -23,7 +23,7 @@ package org.bigbluebutton.clientcheck.command
|
||||
[Inject]
|
||||
public var config:IXMLConfig;
|
||||
|
||||
private var CONFIG_XML:String="client/client-check/conf/config.xml";
|
||||
private var CONFIG_XML:String="check/conf/config.xml";
|
||||
private var _urlRequest:URLRequest;
|
||||
|
||||
public override function execute():void
|
||||
|
Loading…
Reference in New Issue
Block a user