You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openmeetings.apache.org by so...@apache.org on 2018/10/04 17:37:25 UTC
[openmeetings] branch master updated: [OPENMEETINGS-1649] initial
work on turn server
This is an automated email from the ASF dual-hosted git repository.
solomax pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openmeetings.git
The following commit(s) were added to refs/heads/master by this push:
new cd49869 [OPENMEETINGS-1649] initial work on turn server
cd49869 is described below
commit cd4986965221fd02df7ea6d2c13b8fb6b902478a
Author: Maxim Solodovnik <so...@gmail.com>
AuthorDate: Fri Oct 5 00:37:07 2018 +0700
[OPENMEETINGS-1649] initial work on turn server
---
.../apache/openmeetings/core/remote/KStream.java | 4 --
.../openmeetings/core/remote/KurentoHandler.java | 71 ++++++++++++++++++++--
openmeetings-server/src/site/site.xml | 1 +
.../src/site/xdoc/InstallMediaServer.xml | 35 +++++++++++
.../apache/openmeetings/web/room/raw-settings.js | 45 +++++++++-----
.../webapp/WEB-INF/classes/applicationContext.xml | 9 ++-
6 files changed, 138 insertions(+), 27 deletions(-)
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KStream.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KStream.java
index f6642a9..835cb6a 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KStream.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KStream.java
@@ -31,7 +31,6 @@ import org.apache.openmeetings.db.entity.basic.Client;
import org.apache.openmeetings.db.entity.basic.Client.Activity;
import org.apache.openmeetings.db.util.ws.RoomMessage;
import org.apache.openmeetings.db.util.ws.TextRoomMessage;
-import org.apache.wicket.util.string.Strings;
import org.kurento.client.Continuation;
import org.kurento.client.EventListener;
import org.kurento.client.IceCandidate;
@@ -160,9 +159,6 @@ public class KStream implements IKStream {
private WebRtcEndpoint createEndpoint(final KurentoHandler h, final KStream sender) {
WebRtcEndpoint endpoint = new WebRtcEndpoint.Builder(pipeline).build();
- if (!Strings.isEmpty(h.getTurnServerUrl())) {
- endpoint.setTurnUrl(h.getTurnServerUrl());
- }
endpoint.addTag("suid", uid);
endpoint.addTag("uid", sender.getUid());
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KurentoHandler.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KurentoHandler.java
index 2dae1dc..9d8eeda 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KurentoHandler.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KurentoHandler.java
@@ -21,6 +21,9 @@ package org.apache.openmeetings.core.remote;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
@@ -29,6 +32,10 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.directory.api.util.Strings;
import org.apache.openmeetings.core.util.WebSocketHelper;
import org.apache.openmeetings.db.entity.basic.Client;
import org.apache.openmeetings.db.entity.basic.Client.StreamDesc;
@@ -53,6 +60,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import com.github.openjson.JSONArray;
import com.github.openjson.JSONObject;
public class KurentoHandler {
@@ -61,10 +69,15 @@ public class KurentoHandler {
private final static String TAG_KUID = "kuid";
private final static String TAG_MODE = "mode";
private final static String TAG_ROOM = "roomId";
+ private final static String HMAC_SHA1_ALGORITHM = "HmacSHA1";
public final static String KURENTO_TYPE = "kurento";
private long checkTimeout = 200; //ms
private String kurentoWsUrl;
- private String turnServerUrl;
+ private String turnUrl;
+ private String turnUser;
+ private String turnSecret;
+ private String turnMode;
+ private int turnTtl = 60; //minutes
private KurentoClient client;
private String kuid;
private ScheduledExecutorService scheduler;
@@ -200,7 +213,13 @@ public class KurentoHandler {
if (MODE_TEST.equals(msg.optString(TAG_MODE))) {
KTestStream user = getTestByUid(_c.getUid());
switch (cmdId) {
- case "start":
+ case "wannaRecord":
+ WebSocketHelper.sendClient(_c, newTestKurentoMsg()
+ .put("id", "canRecord")
+ .put("configuration", new JSONObject().put("iceServers", getTurnServers(true)))
+ );
+ break;
+ case "record":
{
//TODO FIXME assert null user ???
user = new KTestStream(_c, msg, createTestPipeline());
@@ -430,6 +449,34 @@ public class KurentoHandler {
return r;
}
+ private JSONArray getTurnServers(final boolean test) {
+ JSONArray arr = new JSONArray();
+ if (!Strings.isEmpty(turnUrl)) {
+ try {
+ JSONObject turn = new JSONObject();
+ if ("rest".equalsIgnoreCase(turnMode)) {
+ Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
+ mac.init(new SecretKeySpec(turnSecret.getBytes(), HMAC_SHA1_ALGORITHM));
+ StringBuilder user = new StringBuilder()
+ .append((test ? 30 : turnTtl) + System.currentTimeMillis() / 1000L);
+ if (!Strings.isEmpty(turnUser)) {
+ user.append(':').append(turnUser);
+ }
+ turn.put("username", user)
+ .put("credential", Base64.getEncoder().encodeToString(mac.doFinal(user.toString().getBytes())));
+ } else {
+ turn.put("username", turnUser)
+ .put("credential", turnSecret);
+ }
+ turn.put("url", String.format("turn:%s", turnUrl));
+ arr.put(turn);
+ } catch (NoSuchAlgorithmException|InvalidKeyException e) {
+ log.error("Unexpected error while creating turn", e);
+ }
+ }
+ return arr;
+ }
+
public void setCheckTimeout(long checkTimeout) {
this.checkTimeout = checkTimeout;
}
@@ -438,11 +485,23 @@ public class KurentoHandler {
this.kurentoWsUrl = kurentoWsUrl;
}
- public String getTurnServerUrl() {
- return turnServerUrl;
+ public void setTurnUrl(String turnUrl) {
+ this.turnUrl = turnUrl;
+ }
+
+ public void setTurnUser(String turnUser) {
+ this.turnUser = turnUser;
+ }
+
+ public void setTurnSecret(String turnSecret) {
+ this.turnSecret = turnSecret;
+ }
+
+ public void setTurnMode(String turnMode) {
+ this.turnMode = turnMode;
}
- public void setTurnServerUrl(String turnServerUrl) {
- this.turnServerUrl = turnServerUrl;
+ public void setTurnTtl(int turnTtl) {
+ this.turnTtl = turnTtl;
}
}
diff --git a/openmeetings-server/src/site/site.xml b/openmeetings-server/src/site/site.xml
index db9d1fc..faabb8e 100644
--- a/openmeetings-server/src/site/site.xml
+++ b/openmeetings-server/src/site/site.xml
@@ -30,6 +30,7 @@
<menu name="Installation">
<item name="Installation" href="/installation.html" />
<item name="Upgrade" href="/Upgrade.html" />
+ <item name="Media Server Installation" href="/InstallMediaServer.html" />
<item name="Tutorials" href="https://cwiki.apache.org/confluence/display/OPENMEETINGS/Tutorials+for+installing+OpenMeetings+and+Tools" />
<item name="Command Line Admin" href="/CommandLineAdmin.html" />
</menu>
diff --git a/openmeetings-server/src/site/xdoc/InstallMediaServer.xml b/openmeetings-server/src/site/xdoc/InstallMediaServer.xml
new file mode 100644
index 0000000..0e42071
--- /dev/null
+++ b/openmeetings-server/src/site/xdoc/InstallMediaServer.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<document xmlns="http://maven.apache.org/XDOC/2.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
+ <properties>
+ <title>Media Server Installation</title>
+ <author email="dev@openmeetings.apache.org">Apache OpenMeetings Team</author>
+ </properties>
+ <body>
+ <section name="Install Kurento Media server">
+ <p>
+ <a href="https://doc-kurento.readthedocs.io/en/stable/user/installation.html">Install Kurento Media server</a>
+ <div class="bs-callout bs-callout-danger">
+ It should be run under same user as OM
+ </div>
+ </p>
+ </section>
+ <section name="Specify/Install Turn server">
+ <div class="bs-callout bs-callout-info">Optional step</div>
+ </section>
+ </body>
+</document>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-settings.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-settings.js
index 07aaf61..fa51418 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-settings.js
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-settings.js
@@ -65,7 +65,7 @@ var MicLevel = (function() {
};
});
var VideoSettings = (function() {
- let vs, lm, s, cam, mic, res, o, rtcPeer, offerSdp, timer
+ let vs, lm, s, cam, mic, res, o, rtcPeer, timer
, vidScroll, vid, recBtn, playBtn, recAllowed = false
, level;
const MsgBase = {type: 'kurento', mode: 'test'};
@@ -103,7 +103,6 @@ var VideoSettings = (function() {
level = null;
}
_micActivity(0);
- offerSdp = null;
}
function _close() {
_clear();
@@ -159,16 +158,9 @@ var VideoSettings = (function() {
.click(function() {
recBtn.prop('disabled', true).button('refresh');
_setEnabled(true);
-
- OmUtil.info('Invoking SDP offer callback function');
- const cnts = _constraints();
OmUtil.sendMessage({
- id : 'start'
- , sdpOffer: offerSdp
- , video: cnts.video !== false
- , audio: cnts.audio !== false
+ id : 'wannaRecord'
}, MsgBase);
- rtcPeer.on('icecandidate', _onIceCandidate);
});
playBtn = vs.find('.play')
.button({icon: "ui-icon-play"})
@@ -284,7 +276,7 @@ var VideoSettings = (function() {
}
return cnts;
}
- function _readValues() {
+ function _readValues(msg, func) {
const v = cam.find('option:selected')
, m = mic.find('option:selected')
, o = res.find('option:selected').data();
@@ -300,10 +292,16 @@ var VideoSettings = (function() {
_clear();
const cnts = _constraints();
if (cnts.video !== false || cnts.audio !== false) {
+ const options = {
+ localVideo: vid[0]
+ , mediaConstraints: cnts
+ };
+ if (msg && msg.configuration) {
+ options.configuration = msg.configuration;
+ }
rtcPeer = new kurentoUtils.WebRtcPeer.WebRtcPeerSendonly(
- {
- localVideo: vid[0], mediaConstraints: cnts
- }, function(error) {
+ options
+ , function(error) {
if (error) {
return OmUtil.error(error);
}
@@ -313,8 +311,11 @@ var VideoSettings = (function() {
if (error) {
return OmUtil.error('Error generating the offer');
}
- offerSdp = _offerSdp;
- _allowRec(true);
+ if (typeof(func) === 'function') {
+ func(_offerSdp, cnts);
+ } else {
+ _allowRec(true);
+ }
});
});
}
@@ -428,6 +429,18 @@ var VideoSettings = (function() {
if ('test' === m.mode) {
OmUtil.info('Received message: ', m);
switch (m.id) {
+ case 'canRecord':
+ _readValues(m, function(_offerSdp, cnts) {
+ OmUtil.info('Invoking SDP offer callback function');
+ OmUtil.sendMessage({
+ id : 'record'
+ , sdpOffer: _offerSdp
+ , video: cnts.video !== false
+ , audio: cnts.audio !== false
+ }, MsgBase);
+ rtcPeer.on('icecandidate', _onIceCandidate);
+ });
+ break;
case 'playResponse':
case 'startResponse':
OmUtil.log('SDP answer received from server. Processing ...');
diff --git a/openmeetings-web/src/main/webapp/WEB-INF/classes/applicationContext.xml b/openmeetings-web/src/main/webapp/WEB-INF/classes/applicationContext.xml
index 23ba20d..8199493 100644
--- a/openmeetings-web/src/main/webapp/WEB-INF/classes/applicationContext.xml
+++ b/openmeetings-web/src/main/webapp/WEB-INF/classes/applicationContext.xml
@@ -140,5 +140,12 @@
<!-- Kurento -->
<bean id="kurentoHandler" class="org.apache.openmeetings.core.remote.KurentoHandler" init-method="init" destroy-method="destroy"
- p:kurentoWsUrl="ws://127.0.0.1:8888/kurento" p:checkTimeout="200"/>
+ p:kurentoWsUrl="ws://127.0.0.1:8888/kurento"
+ p:turnUrl=""
+ p:turnUser=""
+ p:turnSecret=""
+ p:turnMode="rest"
+ p:turnTtl="3600"
+ p:checkTimeout="200"
+ />
</beans>