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/11/08 14:54:09 UTC

[openmeetings] branch master updated: [OPENMEETINGS-1955] initial commit on recording for non-interview rooms

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 16d3604  [OPENMEETINGS-1955] initial commit on recording for non-interview rooms
16d3604 is described below

commit 16d3604b3fe20cb0a848b76630bef0d4afae038c
Author: Maxim Solodovnik <so...@gmail.com>
AuthorDate: Thu Nov 8 21:53:56 2018 +0700

    [OPENMEETINGS-1955] initial commit on recording for non-interview rooms
---
 .../org/apache/openmeetings/core/remote/KRoom.java |  9 +++-
 .../openmeetings/core/remote/KurentoHandler.java   | 37 ++++++++++++++--
 .../openmeetings/db/entity/basic/Client.java       | 25 +++++++++--
 .../org/apache/openmeetings/web/room/raw-sharer.js | 49 +++++++++++++++++++---
 .../openmeetings/web/room/raw-video-manager.js     |  8 ++--
 .../apache/openmeetings/web/room/raw-video-util.js |  8 +++-
 .../org/apache/openmeetings/web/room/raw-video.js  | 18 +++++---
 .../openmeetings/web/room/wb/InterviewWbPanel.java |  2 +-
 8 files changed, 130 insertions(+), 26 deletions(-)

diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KRoom.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KRoom.java
index 70c1da5..a9e215c 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KRoom.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KRoom.java
@@ -35,6 +35,7 @@ import org.apache.openmeetings.core.util.WebSocketHelper;
 import org.apache.openmeetings.db.dao.record.RecordingChunkDao;
 import org.apache.openmeetings.db.dao.record.RecordingDao;
 import org.apache.openmeetings.db.entity.basic.Client;
+import org.apache.openmeetings.db.entity.basic.Client.Activity;
 import org.apache.openmeetings.db.entity.basic.Client.StreamDesc;
 import org.apache.openmeetings.db.entity.basic.Client.StreamType;
 import org.apache.openmeetings.db.entity.file.BaseFileItem;
@@ -145,6 +146,10 @@ public class KRoom {
 			log.debug("##REC:: recording created by USER: {}", ownerId);
 
 			for (final KStream stream : streams.values()) {
+				StreamDesc sd = c.getStream(stream.getUid());
+				if (StreamType.SCREEN == sd.getType()) {
+					sd.addActivity(Activity.RECORD);
+				}
 				stream.startRecord();
 			}
 
@@ -178,9 +183,9 @@ public class KRoom {
 		return sharingStarted.get();
 	}
 
-	public void startSharing(KurentoHandler h, IClientManager cm, Client c, JSONObject msg) {
+	public void startSharing(KurentoHandler h, IClientManager cm, Client c, JSONObject msg, Activity...activities) {
 		if (sharingStarted.compareAndSet(false, true)) {
-			StreamDesc sd = c.addStream(StreamType.SCREEN);
+			StreamDesc sd = c.addStream(StreamType.SCREEN, activities);
 			sd.setWidth(msg.getInt("width")).setHeight(msg.getInt("height"));
 			cm.update(c);
 			log.debug("User {}: has started broadcast", sd.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 1fd218f..6191a7f 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
@@ -241,6 +241,9 @@ public class KurentoHandler {
 						sender = room.join(sd);
 					}
 					sender.startBroadcast(this, sd, msg.getString("sdpOffer"));
+					if (StreamType.SCREEN == sd.getType() && sd.hasActivity(Activity.RECORD) && !isRecording(c.getRoomId())) {
+						startRecording(c);
+					}
 					break;
 				case "onIceCandidate":
 					sender = getByUid(uid);
@@ -264,6 +267,20 @@ public class KurentoHandler {
 						startSharing(c, msg);
 					}
 					break;
+				case "wannaRecord":
+					if (recordingAllowed(c)) {
+						Room r = c.getRoom();
+						if (Room.Type.interview == r.getType()) {
+							log.warn("This shouldn't be called for interview room");
+							break;
+						}
+						if (isSharing(r.getId())) {
+							startRecording(c);
+						} else {
+							startSharing(c, msg, Activity.RECORD);
+						}
+					}
+					break;
 				case "stopSharing":
 					sender = getByUid(uid);
 					sd = stopSharing(c.getSid(), uid);
@@ -286,8 +303,10 @@ public class KurentoHandler {
 		}
 		KRoom room = getRoom(roomId);
 		if (room.isRecording()) {
-			List<Client> clients = cm.listByRoom(roomId).parallelStream().filter(c -> c.getStreams().isEmpty()).collect(Collectors.toList());
-			if (clients.isEmpty()) {
+			List<StreamDesc> streams = cm.listByRoom(roomId).parallelStream()
+					.flatMap(c -> c.getStreams().stream())
+					.collect(Collectors.toList());
+			if (streams.isEmpty()) {
 				log.info("No more streams in the room, stopping recording");
 				room.stopRecording(this, null, recDao);
 			}
@@ -369,6 +388,16 @@ public class KurentoHandler {
 		}
 	}
 
+	public boolean recordingAllowed(Client c) {
+		if (client == null) {
+			log.warn(WARN_NO_KURENTO);
+			return false;
+		}
+		Room r = c.getRoom();
+		return r != null && r.isAllowRecording() && c.hasRight(Right.moderator)
+				&& !isRecording(r.getId());
+	}
+
 	public void startRecording(Client c) {
 		if (client == null) {
 			log.warn(WARN_NO_KURENTO);
@@ -418,9 +447,9 @@ public class KurentoHandler {
 				&& !isSharing(r.getId());
 	}
 
-	private void startSharing(Client c, JSONObject msg) {
+	private void startSharing(Client c, JSONObject msg, Activity...activities) {
 		if (client != null && c.getRoomId() != null) {
-			getRoom(c.getRoomId()).startSharing(this, cm, c, msg);
+			getRoom(c.getRoomId()).startSharing(this, cm, c, msg, activities);
 		}
 	}
 
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/basic/Client.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/basic/Client.java
index 4c362b7..d4f5375 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/basic/Client.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/basic/Client.java
@@ -212,8 +212,8 @@ public class Client implements IDataProviderEntity, IWsClient {
 		return this;
 	}
 
-	public StreamDesc addStream(StreamType stype) {
-		StreamDesc sd = new StreamDesc(stype);
+	public StreamDesc addStream(StreamType stype, Activity...activities) {
+		StreamDesc sd = new StreamDesc(stype, activities);
 		streams.put(sd.getUid(), sd);
 		return sd;
 	}
@@ -431,10 +431,14 @@ public class Client implements IDataProviderEntity, IWsClient {
 			sactivities.addAll(sd.sactivities);
 		}
 
-		public StreamDesc(StreamType type) {
+		public StreamDesc(StreamType type, Activity...activities) {
 			this.uuid = randomUUID().toString();
 			this.type = type;
-			setActivities();
+			if (activities == null) {
+				setActivities();
+			} else {
+				sactivities.addAll(Arrays.asList(activities));
+			}
 			if (StreamType.WEBCAM == type) {
 				boolean interview = room != null && Room.Type.interview == room.getType();
 				this.swidth = interview ? 320 : width;
@@ -496,6 +500,14 @@ public class Client implements IDataProviderEntity, IWsClient {
 			return sactivities.contains(a);
 		}
 
+		public void addActivity(Activity a) {
+			sactivities.add(a);
+		}
+
+		public void removeActivity(Activity a) {
+			sactivities.remove(a);
+		}
+
 		public Client getClient() {
 			return Client.this;
 		}
@@ -518,5 +530,10 @@ public class Client implements IDataProviderEntity, IWsClient {
 							.put("lastName", user.getLastname())
 							);
 		}
+
+		@Override
+		public String toString() {
+			return String.format("Stream[uid=%s,type=%s,activities=%s]", uid, type, sactivities);
+		}
 	}
 }
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-sharer.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-sharer.js
index b902e76..63160b8 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-sharer.js
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-sharer.js
@@ -4,7 +4,8 @@ var SHARE_STARTED = 'started';
 var SHARE_STOPED = 'stoped';
 var Sharer = (function() {
 	const self = {};
-	let sharer, type, fps, sbtn, rbtn, width, height, shareState = SHARE_STOPED;
+	let sharer, type, fps, sbtn, rbtn, width, height
+		, shareState = SHARE_STOPED, recState = SHARE_STOPED;
 
 	function _init() {
 		sharer = $('#sharer').dialog({
@@ -21,10 +22,7 @@ var Sharer = (function() {
 		});
 		sbtn = sharer.find('.share-start-stop').button({
 			icon: 'ui-icon-image'
-		});
-		width = sharer.find('.width');
-		height = sharer.find('.height');
-		sbtn.click(function() {
+		}).off().click(function() {
 			if (shareState === SHARE_STOPED) {
 				_setShareState(SHARE_STARTING);
 				VideoManager.sendMessage({
@@ -46,8 +44,31 @@ var Sharer = (function() {
 				_setShareState(SHARE_STOPED);
 			}
 		});
+		width = sharer.find('.width');
+		height = sharer.find('.height');
 		rbtn = sharer.find('.record-start-stop').button({
 			icon: 'ui-icon-bullet'
+		}).off().click(function() {
+			if (recState === SHARE_STOPED) {
+				_setRecState(SHARE_STARTING);
+				VideoManager.sendMessage({
+					id: 'wannaRecord'
+					, shareType: type.val()
+					, fps: fps.val()
+					, width: width.val()
+					, height: height.val()
+				});
+			} else {
+				const cuid = Room.getOptions().uid
+					, v = $('div[data-client-uid="' + cuid + '"][data-client-type="SCREEN"]')
+					, uid = v.data().stream().uid;
+				VideoManager.sendMessage({
+					id: 'stopRecord'
+					, uid: uid
+				});
+				VideoManager.close(uid, false);
+				_setRecState(SHARE_STOPED);
+			}
 		});
 	}
 	function _setShareState(state) {
@@ -67,6 +88,23 @@ var Sharer = (function() {
 			rbtn.button('enable');
 		}
 	}
+	function _setRecState(state) {
+		recState = state;
+		const dis = SHARE_STOPED !== state;
+		type.selectmenu('option', 'disabled', dis || VideoUtil.isEdge());
+		fps.selectmenu('option', 'disabled', dis || VideoUtil.isEdge());
+		width.prop('disabled', dis);
+		height.prop('disabled', dis);
+		rbtn.text(rbtn.data(dis ? 'stop' : 'start'));
+		rbtn.button('option', 'icon', dis ? 'ui-icon-stop' : 'ui-icon-image');
+		if (state === SHARE_STARTING) {
+			sbtn.button('disable');
+			rbtn.button('disable');
+		} else {
+			sbtn.button('enable');
+			rbtn.button('enable');
+		}
+	}
 
 	self.init = _init;
 	self.open = function() {
@@ -80,5 +118,6 @@ var Sharer = (function() {
 		}
 	};
 	self.setShareState = _setShareState;
+	self.setRecState = _setRecState;
 	return self;
 })();
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-video-manager.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-video-manager.js
index 89036c4..6e8a872 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-video-manager.js
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-video-manager.js
@@ -17,9 +17,6 @@ var VideoManager = (function() {
 		const sd = msg.stream
 			, uid = sd.uid;
 		$('#' + VideoUtil.getVid(uid)).remove();
-		if (sd.self && VideoUtil.isSharing(sd)) {
-			return;
-		}
 		Video().init(msg);
 		OmUtil.log(uid + ' registered in room');
 	}
@@ -105,7 +102,7 @@ var VideoManager = (function() {
 		}
 		c.streams.forEach(function(sd) {
 			sd.self = c.self;
-			if (VideoUtil.isSharing(sd)) {
+			if (VideoUtil.isSharing(sd) || VideoUtil.isRecording(sd)) {
 				return;
 			}
 			const _id = VideoUtil.getVid(sd.uid)
@@ -147,6 +144,9 @@ var VideoManager = (function() {
 			return;
 		}
 		streams.forEach(function(sd) {
+			if (VideoUtil.isRecording(sd)) {
+				return;
+			}
 			const m = {stream: sd, iceServers: iceServers};
 			if (VideoUtil.isSharing(sd)) {
 				_highlight(share
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-video-util.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-video-util.js
index 7b21a2e..dcf7304 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-video-util.js
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-video-util.js
@@ -4,13 +4,18 @@ const WBA_WB_SEL = '.room.wb.area .ui-tabs-panel.ui-corner-bottom.ui-widget-cont
 const VID_SEL = '.video.user-video';
 const CAM_ACTIVITY = 'VIDEO';
 const MIC_ACTIVITY = 'AUDIO';
+const SCREEN_ACTIVITY = 'SCREEN';
+const REC_ACTIVITY = 'RECORD';
 var VideoUtil = (function() {
 	const self = {};
 	function _getVid(uid) {
 		return 'video' + uid;
 	}
 	function _isSharing(sd) {
-		return 'SCREEN' === sd.type;
+		return !!sd && 'SCREEN' === sd.type && sd.activities.includes(SCREEN_ACTIVITY);
+	}
+	function _isRecording(sd) {
+		return !!sd && 'SCREEN' === sd.type && sd.activities.includes(REC_ACTIVITY);
 	}
 	function _hasAudio(sd) {
 		return !sd || sd.activities.includes(MIC_ACTIVITY);
@@ -133,6 +138,7 @@ var VideoUtil = (function() {
 
 	self.getVid = _getVid;
 	self.isSharing = _isSharing;
+	self.isRecording = _isRecording;
 	self.hasAudio = _hasAudio;
 	self.hasVideo = _hasVideo;
 	self.getRects = _getRects;
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-video.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-video.js
index 218156f..8b41b3f 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-video.js
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-video.js
@@ -54,6 +54,7 @@ var Video = (function() {
 				callback(msg, cnts, stream);
 			}).catch(function(err) {
 				Sharer.setShareState(SHARE_STOPED);
+				Sharer.setRecState(SHARE_STOPED);
 				OmUtil.error(err);
 			});
 		} else if (b.name === 'Firefox') {
@@ -69,9 +70,12 @@ var Video = (function() {
 				callback(msg, cnts, stream);
 			}).catch(function(err) {
 				Sharer.setShareState(SHARE_STOPED);
+				Sharer.setRecState(SHARE_STOPED);
 				OmUtil.error(err);
 			});
 		} else {
+			Sharer.setShareState(SHARE_STOPED);
+			Sharer.setRecState(SHARE_STOPED);
 			Sharer.close();
 			OmUtil.error('Screen-sharing is not supported in ' + b.name + '[' + b.major + ']');
 		}
@@ -153,11 +157,14 @@ var Video = (function() {
 					if (VideoUtil.isSharing(sd)) {
 						Sharer.setShareState(SHARE_STARTED);
 					}
+					if (VideoUtil.isRecording(sd)) {
+						Sharer.setRecState(SHARE_STARTED);
+					}
 				});
 			});
 	}
 	function _createSendPeer(msg) {
-		if (VideoUtil.isSharing(sd)) {
+		if (VideoUtil.isSharing(sd) || VideoUtil.isRecording(sd)) {
 			_getScreenStream(msg, __createSendPeer);
 		} else {
 			_getVideoStream(msg, __createSendPeer);
@@ -300,6 +307,7 @@ var Video = (function() {
 			, _w = sd.width
 			, _h = sd.height
 			, isSharing = VideoUtil.isSharing(sd)
+			, isRecording = VideoUtil.isRecording(sd)
 			, opts = Room.getOptions();
 		sd.self = sd.cuid === opts.uid;
 		const contSel = _initContainer(_id, name, opts);
@@ -309,7 +317,7 @@ var Video = (function() {
 		if (!sd.self && isSharing) {
 			Sharer.close();
 		}
-		if (sd.self && isSharing) {
+		if (sd.self && (isSharing || isRecording)) {
 			v.hide();
 		} else {
 			v.dialog({
@@ -326,7 +334,7 @@ var Video = (function() {
 			});
 			_initDialog(v, opts);
 		}
-		if (!isSharing) {
+		if (!isSharing && !isRecording) {
 			v.parent().find('.ui-dialog-titlebar-buttonpane')
 				.append($('#video-volume-btn').children().clone())
 				.append($('#video-refresh-btn').children().clone());
@@ -381,7 +389,7 @@ var Video = (function() {
 
 		_refresh(msg);
 
-		if (!isSharing) {
+		if (!isSharing && !isRecording) {
 			VideoUtil.setPos(v, VideoUtil.getPos(VideoUtil.getRects(VID_SEL), sd.width, sd.height + 25));
 		}
 		return v;
@@ -401,7 +409,7 @@ var Video = (function() {
 	function _refresh(msg) {
 		_cleanup();
 		const _id = VideoUtil.getVid(sd.uid);
-		const hasVideo = VideoUtil.hasVideo(sd) || VideoUtil.isSharing(sd)
+		const hasVideo = VideoUtil.hasVideo(sd) || VideoUtil.isSharing(sd) || VideoUtil.isRecording(sd)
 			, imgUrl = 'profile/' + sd.user.id + '?anti=' + new Date().getTime();  //TODO add normal URL ????
 		video = $(hasVideo ? '<video>' : '<audio>').attr('id', 'vid' + _id)
 			.width(vc.width()).height(vc.height())
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/InterviewWbPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/InterviewWbPanel.java
index 93461e3..63c77f6 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/InterviewWbPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/InterviewWbPanel.java
@@ -55,7 +55,7 @@ public class InterviewWbPanel extends AbstractWbPanel {
 	@Override
 	protected void processWbAction(WbAction a, JSONObject obj, AjaxRequestTarget target) throws IOException {
 		Client c = rp.getClient();
-		if (rp.getRoom().isAllowRecording() && c.hasRight(Right.moderator)) {
+		if (kurento.recordingAllowed(c)) {
 			switch (a) {
 				case startRecording:
 					kurento.startRecording(c);