Merge pull request #679 from ritzalam/reconnect-to-bbb-video

Reconnect to bbb video
This commit is contained in:
Richard Alam 2015-07-02 15:25:08 -04:00
commit 2eb1de6cab
13 changed files with 131 additions and 55 deletions

View File

@ -50,7 +50,7 @@ libraryDependencies ++= {
"com.google.code.gson" % "gson" % "1.7.1",
"redis.clients" % "jedis" % "2.1.0",
"org.apache.commons" % "commons-lang3" % "3.2",
"org.bigbluebutton" % "bbb-common-message" % "0.0.5"
"org.bigbluebutton" % "bbb-common-message" % "0.0.6"
)}

View File

@ -50,7 +50,7 @@ libraryDependencies ++= {
"com.google.code.gson" % "gson" % "1.7.1",
"redis.clients" % "jedis" % "2.1.0",
"org.apache.commons" % "commons-lang3" % "3.2",
"org.bigbluebutton" % "bbb-common-message" % "0.0.5",
"org.bigbluebutton" % "bbb-common-message" % "0.0.6",
"org.bigbluebutton" % "bbb-fsesl-client" % "0.0.2"
)}

View File

@ -4,7 +4,7 @@ name := "bbb-common-message"
organization := "org.bigbluebutton"
version := "0.0.5"
version := "0.0.6"
// We want to have our jar files in lib_managed dir.
// This way we'll have the right path when we import

View File

@ -30,6 +30,7 @@ public class GetUsersReplyMessage implements ISubscribedMessage {
return MessageBuilder.buildJson(header, payload);
}
public static GetUsersReplyMessage fromJson(String message) {
JsonParser parser = new JsonParser();
JsonObject obj = (JsonObject) parser.parse(message);

View File

@ -73,7 +73,7 @@ public class Util {
&& user.has(Constants.RAISE_HAND) && user.has(Constants.PHONE_USER)
&& user.has(Constants.PRESENTER) && user.has(Constants.LOCKED)
&& user.has(Constants.EXTERN_USERID) && user.has(Constants.ROLE)
&& user.has(Constants.VOICEUSER)){
&& user.has(Constants.VOICEUSER) && user.has(Constants.WEBCAM_STREAM)){
Map<String, Object> userMap = new HashMap<String, Object>();
@ -87,11 +87,15 @@ public class Util {
Boolean locked = user.get(Constants.LOCKED).getAsBoolean();
String extUserId = user.get(Constants.EXTERN_USERID).getAsString();
String role = user.get(Constants.ROLE).getAsString();
JsonArray webcamStreamJArray = user.get(Constants.WEBCAM_STREAM).getAsJsonArray();
ArrayList<String> webcamStreams = extractWebcamStreams(webcamStreamJArray);
userMap.put("userId", userid);
userMap.put("name", username);
userMap.put("listenOnly", listenOnly);
userMap.put("hasStream", hasStream);
userMap.put("webcamStream", webcamStreams);
userMap.put("raiseHand", raiseHand);
userMap.put("externUserID", extUserId);
userMap.put("phoneUser", phoneUser);
@ -169,6 +173,19 @@ public class Util {
return collection;
}
public ArrayList<String> extractWebcamStreams(JsonArray webcamStreams) {
ArrayList<String> collection = new ArrayList<String>();
Iterator<JsonElement> webcamStreamsIter = webcamStreams.iterator();
while (webcamStreamsIter.hasNext()){
JsonElement stream = webcamStreamsIter.next();
collection.add(stream.getAsString());
}
return collection;
}
public ArrayList<String> extractUserids(JsonArray users) {
ArrayList<String> collection = new ArrayList<String>();

View File

@ -204,7 +204,7 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
scopeName = stream.getScope().getName();
}
log.info("streamBroadcastClose " + stream.getPublishedName() + " " + System.currentTimeMillis() + " " + conn.getScope().getName());
log.info("Stream broadcast closed for stream=[{}] meeting=[{}]", stream.getPublishedName(), scopeName);
String userId = getUserId();
String meetingId = conn.getScope().getName();
@ -214,13 +214,13 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
IStreamListener listener = streamListeners.remove(scopeName + "-" + stream.getPublishedName());
if (listener != null) {
stream.removeStreamListener(listener);
((VideoStreamListener) listener).streamStopped();
stream.removeStreamListener(listener);
}
if (recordVideoStream) {
if (recordVideoStream) {
long publishDuration = (System.currentTimeMillis() - stream.getCreationTime()) / 1000;
log.info("streamBroadcastClose " + stream.getPublishedName() + " " + System.currentTimeMillis() + " " + scopeName);
log.info("Stop recording event for stream=[{}] meeting=[{}]", stream.getPublishedName(), scopeName);
Map<String, String> event = new HashMap<String, String>();
event.put("module", "WEBCAM");
event.put("timestamp", genTimestamp().toString());

View File

@ -75,6 +75,8 @@ public class VideoStreamListener implements IStreamListener {
// Event queue worker job name
private String timeoutJobName;
private volatile boolean publishing = false;
private IScope scope;
public VideoStreamListener(IScope scope, IBroadcastStream stream, Boolean record) {
@ -107,11 +109,12 @@ public class VideoStreamListener implements IStreamListener {
if (! firstPacketReceived) {
firstPacketReceived = true;
// start the worker
publishing = true;
// start the worker to monitor if we are still receiving video packets
timeoutJobName = scheduler.addScheduledJob(videoTimeout, new TimeoutJob());
if (record) {
IConnection conn = Red5.getConnectionLocal();
Map<String, String> event = new HashMap<String, String>();
event.put("module", "WEBCAM");
event.put("timestamp", genTimestamp().toString());
@ -119,7 +122,7 @@ public class VideoStreamListener implements IStreamListener {
event.put("stream", stream.getPublishedName());
event.put("eventName", "StartWebcamShareEvent");
recordingService.record(conn.getScope().getName(), event);
recordingService.record(scope.getName(), event);
}
}
}
@ -129,15 +132,27 @@ public class VideoStreamListener implements IStreamListener {
recordingService = s;
}
public void streamStopped() {
this.publishing = false;
}
private class TimeoutJob implements IScheduledJob {
private boolean streamStopped = false;
public void execute(ISchedulingService service) {
if ((System.currentTimeMillis() - lastVideoTime) > videoTimeout) {
log.warn("No data received for stream[{}] in the last few seconds. Close stream.", stream.getPublishedName());
// remove the scheduled job
scheduler.removeScheduledJob(timeoutJobName);
// stop / clean up
stream.stop();
if (!streamStopped) {
streamStopped = true;
// remove the scheduled job
scheduler.removeScheduledJob(timeoutJobName);
// stop / clean up
if (publishing) {
stream.stop();
}
}
}
}

View File

@ -112,7 +112,7 @@ dependencies {
compile 'com.google.code.gson:gson:1.7.1'
providedCompile 'org.apache.commons:commons-lang3:3.2'
compile 'org.bigbluebutton:bbb-common-message:0.0.5'
compile 'org.bigbluebutton:bbb-common-message:0.0.6'
}
test {

View File

@ -0,0 +1,38 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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.0 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/>.
*
*/
package org.bigbluebutton.main.model.users.events
{
import flash.events.Event;
public class StreamStoppedEvent extends Event
{
public static const STREAM_STOPPED:String = "webcam stream stopped";
public var streamId:String;
public var userId:String
public function StreamStoppedEvent(userId:String, streamId:String)
{
this.userId = userId;
this.streamId = streamId;
super(STREAM_STOPPED, true, false);
}
}
}

View File

@ -42,6 +42,8 @@ package org.bigbluebutton.modules.users.services
import org.bigbluebutton.main.model.users.Conference;
import org.bigbluebutton.main.model.users.IMessageListener;
import org.bigbluebutton.main.model.users.events.RoleChangeEvent;
import org.bigbluebutton.main.model.users.events.StreamStartedEvent;
import org.bigbluebutton.main.model.users.events.StreamStoppedEvent;
import org.bigbluebutton.main.model.users.events.UsersConnectionEvent;
import org.bigbluebutton.modules.present.events.CursorEvent;
import org.bigbluebutton.modules.present.events.NavigationEvent;
@ -517,7 +519,13 @@ package org.bigbluebutton.modules.users.services
trace(LOG + "*** handleUserUnsharedWebcam " + msg.msg + " **** \n");
var map:Object = JSON.parse(msg.msg);
UserManager.getInstance().getConference().unsharedWebcam(map.userId, map.webcamStream);
sendStreamStoppedEvent(map.userId, map.webcamStream);
}
private function sendStreamStoppedEvent(userId: String, streamId: String):void{
var dispatcher:Dispatcher = new Dispatcher();
dispatcher.dispatchEvent(new StreamStoppedEvent(userId, streamId));
}
public function participantStatusChange(userID:String, status:String, value:Object):void {
trace(LOG + "Received status change [" + userID + "," + status + "," + value + "]")

View File

@ -23,22 +23,23 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<EventMap xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="http://mate.asfusion.com/">
<mx:Script>
<![CDATA[
import org.bigbluebutton.core.events.ConnectAppEvent;
import org.bigbluebutton.main.events.BBBEvent;
import org.bigbluebutton.main.events.MadePresenterEvent;
import org.bigbluebutton.main.events.StoppedViewingWebcamEvent;
import org.bigbluebutton.main.events.UserJoinedEvent;
import org.bigbluebutton.main.events.UserLeftEvent;
import org.bigbluebutton.main.model.users.events.StreamStartedEvent;
import org.bigbluebutton.modules.users.events.ViewCameraEvent;
import org.bigbluebutton.modules.videoconf.events.ClosePublishWindowEvent;
import org.bigbluebutton.modules.videoconf.events.ConnectedEvent;
import org.bigbluebutton.modules.videoconf.events.ShareCameraRequestEvent;
import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent;
import org.bigbluebutton.modules.videoconf.events.StopBroadcastEvent;
import org.bigbluebutton.modules.videoconf.events.StopShareCameraRequestEvent;
import org.bigbluebutton.modules.videoconf.events.VideoModuleStartEvent;
import org.bigbluebutton.modules.videoconf.events.VideoModuleStopEvent;
import org.bigbluebutton.core.events.ConnectAppEvent;
import org.bigbluebutton.main.events.BBBEvent;
import org.bigbluebutton.main.events.MadePresenterEvent;
import org.bigbluebutton.main.events.StoppedViewingWebcamEvent;
import org.bigbluebutton.main.events.UserJoinedEvent;
import org.bigbluebutton.main.events.UserLeftEvent;
import org.bigbluebutton.main.model.users.events.StreamStartedEvent;
import org.bigbluebutton.main.model.users.events.StreamStoppedEvent;
import org.bigbluebutton.modules.users.events.ViewCameraEvent;
import org.bigbluebutton.modules.videoconf.events.ClosePublishWindowEvent;
import org.bigbluebutton.modules.videoconf.events.ConnectedEvent;
import org.bigbluebutton.modules.videoconf.events.ShareCameraRequestEvent;
import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent;
import org.bigbluebutton.modules.videoconf.events.StopBroadcastEvent;
import org.bigbluebutton.modules.videoconf.events.StopShareCameraRequestEvent;
import org.bigbluebutton.modules.videoconf.events.VideoModuleStartEvent;
import org.bigbluebutton.modules.videoconf.events.VideoModuleStopEvent;
]]>
</mx:Script>
@ -85,6 +86,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<MethodInvoker generator="{VideoEventMapDelegate}" method="viewCamera" arguments="{[event.userID, event.stream, event.user]}" />
</EventHandlers>
<EventHandlers type="{StreamStoppedEvent.STREAM_STOPPED}">
<MethodInvoker generator="{VideoEventMapDelegate}" method="handleStreamStoppedEvent" arguments="{event}" />
</EventHandlers>
<EventHandlers type="{ViewCameraEvent.VIEW_CAMERA_EVENT}">
<MethodInvoker generator="{VideoEventMapDelegate}" method="viewCamera" arguments="{[event.userID, event.stream, event.viewedName]}" />
</EventHandlers>

View File

@ -18,23 +18,17 @@
*/
package org.bigbluebutton.modules.videoconf.maps
{
import com.asfusion.mate.utils.debug.Debugger;
import com.asfusion.mate.utils.debug.DebuggerUtil;
import flash.events.IEventDispatcher;
import flash.external.ExternalInterface;
import flash.media.Camera;
import mx.collections.ArrayCollection;
import mx.collections.ArrayList;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.common.events.CloseWindowEvent;
import org.bigbluebutton.common.events.OpenWindowEvent;
import org.bigbluebutton.common.events.ToolbarButtonEvent;
import org.bigbluebutton.core.BBB;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.core.events.ConnectAppEvent;
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.core.model.VideoProfile;
import org.bigbluebutton.core.vo.CameraSettingsVO;
@ -46,27 +40,18 @@ package org.bigbluebutton.modules.videoconf.maps
import org.bigbluebutton.main.model.users.BBBUser;
import org.bigbluebutton.main.model.users.events.BroadcastStartedEvent;
import org.bigbluebutton.main.model.users.events.BroadcastStoppedEvent;
import org.bigbluebutton.main.model.users.events.StreamStartedEvent;
import org.bigbluebutton.main.model.users.events.StreamStoppedEvent;
import org.bigbluebutton.modules.videoconf.business.VideoProxy;
import org.bigbluebutton.modules.videoconf.events.CloseAllWindowsEvent;
import org.bigbluebutton.modules.videoconf.events.ClosePublishWindowEvent;
import org.bigbluebutton.modules.videoconf.events.ConnectedEvent;
import org.bigbluebutton.modules.videoconf.events.OpenVideoWindowEvent;
import org.bigbluebutton.modules.videoconf.events.ShareCameraRequestEvent;
import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent;
import org.bigbluebutton.modules.videoconf.events.StopBroadcastEvent;
import org.bigbluebutton.modules.videoconf.events.StopShareCameraRequestEvent;
import org.bigbluebutton.modules.videoconf.events.WebRTCWebcamRequestEvent;
import org.bigbluebutton.modules.videoconf.model.VideoConfOptions;
import org.bigbluebutton.modules.videoconf.views.AvatarWindow;
import org.bigbluebutton.modules.videoconf.views.GraphicsWrapper;
import org.bigbluebutton.modules.videoconf.views.ToolbarPopupButton;
import org.bigbluebutton.modules.videoconf.views.UserAvatar;
import org.bigbluebutton.modules.videoconf.views.UserGraphic;
import org.bigbluebutton.modules.videoconf.views.UserGraphicHolder;
import org.bigbluebutton.modules.videoconf.views.UserVideo;
import org.bigbluebutton.modules.videoconf.views.VideoDock;
import org.flexunit.runner.manipulation.filters.IncludeAllFilter;
public class VideoEventMapDelegate
{
@ -121,6 +106,14 @@ package org.bigbluebutton.modules.videoconf.maps
}
}
public function handleStreamStoppedEvent(event:StreamStoppedEvent):void {
if (UserManager.getInstance().getConference().amIThisUser(event.userId)) {
closePublishWindowWithStream(event.userId, event.streamId);
} else {
closeViewWindowWithStream(event.userId, event.streamId);
}
}
public function handleUserLeftEvent(event:UserLeftEvent):void {
trace("VideoEventMapDelegate:: [" + me + "] handleUserLeftEvent. ready = [" + _ready + "]");
@ -288,7 +281,7 @@ package org.bigbluebutton.modules.videoconf.maps
}
public function startPublishing(e:StartBroadcastEvent):void{
LogUtil.debug("VideoEventMapDelegate:: [" + me + "] startPublishing:: Publishing stream to: " + proxy.connection.uri + "/" + e.stream);
trace("VideoEventMapDelegate:: [" + me + "] startPublishing:: Publishing stream to: " + proxy.connection.uri + "/" + e.stream);
proxy.startPublishing(e);
_isWaitingActivation = false;

View File

@ -134,7 +134,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
}
public function shutdown():void {
trace("[UserGraphicHolder:shutdown]");
video.shutdown();
}