From 2a5f4ebedb7ce15d45378c58834ff2accb2a3b97 Mon Sep 17 00:00:00 2001 From: Felipe Cecagno <fcecagno@gmail.com> Date: Sun, 17 May 2015 23:08:41 -0300 Subject: [PATCH] cleanup; reverted the implementation which avoid the user to join twice using the same internal user id because the enter call was modified to change the internal user id everytime it's called; reverted a few files with different line endings than the original; merged properly the html5 client code --- README.md | 33 +- .../app/video/VideoApplication.java | 69 +- .../conference/BigBlueButtonApplication.java | 8 +- .../red5/ConnectionInvokerService.java | 33 - .../ConversionUpdatesProcessor.java | 3 +- .../whiteboard/WhiteboardListener.java | 3 +- .../core/BigBlueButtonActor.scala | 3 - .../core/BigBlueButtonInGW.scala | 4 - .../org/bigbluebutton/core/MeetingActor.scala | 1 - .../red5/LayoutClientMessageSender.scala | 4 +- .../core/apps/users/UsersApp.scala | 20 +- .../redis/UsersMessageToJsonConverter.scala | 2 +- .../branding/default/style/css/BBBBlack.css | 11 +- .../locale/en_US/bbbResources.properties | 2 +- .../locale/pt_BR/bbbResources.properties | 2 +- .../prod/lib/bbb_webrtc_bridge_sip.js | 107 +-- .../resources/prod/lib/deployJava.js | 2 +- .../main/model/modules/ModulesDispatcher.as | 394 ++++----- .../main/model/users/NetConnectionDelegate.as | 824 +++++++++--------- .../main/views/LockSettings.mxml | 2 +- .../modules/chat/maps/ChatEventMap.mxml | 218 ++--- .../modules/chat/views/AddChatTabBox.mxml | 2 +- .../modules/chat/views/ChatView.mxml | 12 +- .../modules/present/events/UploadEvent.as | 0 .../present/managers/PresentManager.as | 4 +- .../modules/videoconf/business/VideoProxy.as | 764 ++++++++-------- .../modules/videoconf/maps/VideoEventMap.mxml | 288 +++--- .../videoconf/model/VideoConfOptions.as | 5 +- .../modules/videoconf/views/AvatarWindow.mxml | 54 +- bigbluebutton-config/bigbluebutton-release | 2 +- bigbluebutton-config/web/default.pdf | Bin bigbluebutton-html5/app/client/globals.coffee | 78 +- .../app/client/lib/bbb_api_bridge.coffee | 54 +- bigbluebutton-html5/app/client/main.coffee | 197 ++--- bigbluebutton-html5/app/client/main.html | 144 ++- .../app/client/stylesheets/chat.less | 51 +- .../app/client/stylesheets/style.less | 198 ++--- .../app/client/stylesheets/users.less | 3 - .../app/client/views/chat/chat_bar.coffee | 18 - .../app/client/views/chat/chat_bar.html | 146 ++-- .../app/client/views/users/user_item.coffee | 13 - .../app/client/views/users/user_item.html | 41 +- .../app/client/views/users/user_list.coffee | 7 +- .../app/client/views/users/users_list.html | 2 +- .../client/views/whiteboard/whiteboard.html | 2 +- bigbluebutton-html5/app/config.coffee | 7 - bigbluebutton-html5/app/lib/router.coffee | 0 .../packages/ionicons/fonts/ionicons.ttf | Bin 188508 -> 139648 bytes .../packages/ionicons/fonts/ionicons.woff | Bin 67904 -> 48380 bytes .../server/collection_methods/meetings.coffee | 33 +- .../server/collection_methods/users.coffee | 80 +- .../app/server/redispubsub.coffee | 71 +- .../app/server/user_permissions.coffee | 44 +- .../web/services/PresentationService.groovy | 366 ++++---- .../api/messaging/MeetingMessageHandler.java | 2 +- .../api/messaging/MessagingConstants.java | 1 + 56 files changed, 1960 insertions(+), 2474 deletions(-) mode change 100644 => 100755 bigbluebutton-client/src/org/bigbluebutton/modules/present/events/UploadEvent.as mode change 100644 => 100755 bigbluebutton-config/web/default.pdf mode change 100755 => 100644 bigbluebutton-html5/app/client/lib/bbb_api_bridge.coffee mode change 100755 => 100644 bigbluebutton-html5/app/lib/router.coffee mode change 100755 => 100644 bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.ttf mode change 100755 => 100644 bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.woff mode change 100755 => 100644 bigbluebutton-html5/app/server/user_permissions.coffee diff --git a/README.md b/README.md index bcd9aad86f..0f59ec0810 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,36 @@ BigBlueButton ============= -BigBlueButton is an open source web conferencing system for on-line learning. +BigBlueButton is an open source web conferencing system for on-line learning. We believe that every student with a web browser should have access to a high-quality on-line learning experience. We intend to make that possible with BigBlueButton. -We believe that every student with a web browser should have access to a high-quality on-line learning experience. We intend to make that possible with BigBlueButton. - -BigBlueButton supports real-time sharing of slides (PDF and any document readable by LibreOffice), webcams, whiteboard, chat, voice over IP (using FreeSWITCH), and desktop. It can record and playback all content shared in a session. The use cases for BigBlueButton are +BigBlueButton supports real-time sharing of slides (PDF and any document readable by OpenOffice), webcams, whiteboard, chat, voice over IP (using FreeSWITCH), and desktop. It can record and playback all content shared in a session. The BigBlueButton project is is supported by a [community of developers] (http://www.bigbluebutton.org/support/) that care about good design and a streamlined user experience. +The use cases for BigBlueButton are * One-to-one on-line tutoring * Small group collaboration - * On-line classes (50 or less) + * On-line classes (25 or less) + +BigBlueButton is built on the [shoulders of giants] (http://www.bigbluebutton.org/components/). + +Getting Started +=============== +All the core information is at the [Google Code project page] (http://code.google.com/p/bigbluebutton/). Here are a few quick links + +If you want to see how BigBlueButton works, check out these two videos + * [presenter] (http://www.bigbluebutton.org/videos/) + * [viewer] (http://www.bigbluebutton.org/videos/) + +After watching the videos, if you want to immediately try out BigBlueButton, the project maintains a live [demo server] (http://demo.bigbluebutton.org) that anyone can join. + +To quickly get started running your own BigBlueButton server + * [Install on Ubunt 10.04 64-bit] (http://code.google.com/p/bigbluebutton/wiki/InstallationUbuntu) + * [Download the BigBlueButton 0.81 Virtual Machine] (http://code.google.com/p/bigbluebutton/wiki/BigBlueButtonVM) + +See also [history of project] (http://www.bigbluebutton.org/history/). + +If you like the work we've done with BigBlueButton and would like to contribute improvemets to the project, see [Contribute to BigBlueButton] (http://code.google.com/p/bigbluebutton/wiki/FAQ#Contributing_to_BigBlueButton). -For more information on the latest release -- including installation instructions, demo server, API, and overview of architecture -- see [http://docs.bigbluebutton.org/](http://docs.bigbluebutton.org/). +License +======= +BigBlueButton is licensed under the LGPL 3.0. BigBlueButton and the BigBlueButton Logo are trademarks of [BigBlueButton Inc] (http://bigbluebutton.org) . diff --git a/bbb-video/src/main/java/org/bigbluebutton/app/video/VideoApplication.java b/bbb-video/src/main/java/org/bigbluebutton/app/video/VideoApplication.java index 147e96fc7a..3ae50c5bb6 100755 --- a/bbb-video/src/main/java/org/bigbluebutton/app/video/VideoApplication.java +++ b/bbb-video/src/main/java/org/bigbluebutton/app/video/VideoApplication.java @@ -25,14 +25,15 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.Timer; import java.util.TimerTask; +import org.apache.commons.lang3.StringUtils; import org.bigbluebutton.app.video.h263.H263Converter; import org.red5.logging.Red5LoggerFactory; import org.red5.server.adapter.MultiThreadedApplicationAdapter; import org.red5.server.api.IConnection; import org.red5.server.api.Red5; -import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IBasicScope; import org.red5.server.api.scope.IBroadcastScope; +import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.ScopeType; import org.red5.server.api.stream.IBroadcastStream; import org.red5.server.api.stream.IPlayItem; @@ -41,7 +42,6 @@ import org.red5.server.api.stream.IStreamListener; import org.red5.server.api.stream.ISubscriberStream; import org.red5.server.stream.ClientBroadcastStream; import org.slf4j.Logger; -import org.apache.commons.lang3.StringUtils; import com.google.gson.Gson; public class VideoApplication extends MultiThreadedApplicationAdapter { @@ -53,15 +53,15 @@ public class VideoApplication extends MultiThreadedApplicationAdapter { private boolean recordVideoStream = false; private EventRecordingService recordingService; private final Map<String, IStreamListener> streamListeners = new HashMap<String, IStreamListener>(); - - private Map<String, CustomStreamRelay> remoteStreams = new ConcurrentHashMap<String, CustomStreamRelay>(); - private Map<String, Integer> listenersOnRemoteStream = new ConcurrentHashMap<String, Integer>(); + + private Map<String, CustomStreamRelay> remoteStreams = new ConcurrentHashMap<String, CustomStreamRelay>(); + private Map<String, Integer> listenersOnRemoteStream = new ConcurrentHashMap<String, Integer>(); // Proxy disconnection timer private Timer timer; // Proxy disconnection timeout private long relayTimeout; - + private final Map<String, H263Converter> h263Converters = new HashMap<String, H263Converter>(); @Override @@ -191,16 +191,14 @@ public class VideoApplication extends MultiThreadedApplicationAdapter { super.streamPublishStart(stream); } - public IBroadcastScope getBroadcastScope(IScope scope, String name) { - IBasicScope basicScope = scope.getBasicScope(ScopeType.BROADCAST, name); - if (!(basicScope instanceof IBroadcastScope)) { - return null; - } else { - return (IBroadcastScope) basicScope; + IBasicScope basicScope = scope.getBasicScope(ScopeType.BROADCAST, name); + if (basicScope instanceof IBroadcastScope) { + return (IBroadcastScope) basicScope; + } else { + return null; + } } -} - @Override public void streamBroadcastStart(IBroadcastStream stream) { @@ -220,14 +218,11 @@ public class VideoApplication extends MultiThreadedApplicationAdapter { private Long genTimestamp() { return TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); } - - private boolean isH263Stream(ISubscriberStream stream) { - String streamName = stream.getBroadcastStreamPublishName(); - if(streamName.startsWith(H263Converter.H263PREFIX)) { - return true; - } - return false; - } + + private boolean isH263Stream(ISubscriberStream stream) { + String streamName = stream.getBroadcastStreamPublishName(); + return streamName.startsWith(H263Converter.H263PREFIX); + } @Override public void streamBroadcastClose(IBroadcastStream stream) { @@ -258,10 +253,10 @@ public class VideoApplication extends MultiThreadedApplicationAdapter { recordingService.record(scopeName, event); } - if(h263Converters.containsKey(stream.getName())) { - // Stop converter - h263Converters.remove(stream.getName()).stopConverter(); - } + if (h263Converters.containsKey(stream.getName())) { + // Stop converter + h263Converters.remove(stream.getName()).stopConverter(); + } } /** @@ -290,15 +285,16 @@ public class VideoApplication extends MultiThreadedApplicationAdapter { public void setEventRecordingService(EventRecordingService s) { recordingService = s; } - + public void setRelayTimeout(long timeout) { this.relayTimeout = timeout; } - @Override - public void streamPlayItemPlay(ISubscriberStream stream, IPlayItem item, boolean isLive) { - // log w3c connect event - String streamName = item.getName(); - streamName = streamName.replaceAll(H263Converter.H263PREFIX, ""); + + @Override + public void streamPlayItemPlay(ISubscriberStream stream, IPlayItem item, boolean isLive) { + // log w3c connect event + String streamName = item.getName(); + streamName = streamName.replaceAll(H263Converter.H263PREFIX, ""); if(isH263Stream(stream)) { log.trace("Detected H263 stream request [{}]", streamName); @@ -315,7 +311,7 @@ public class VideoApplication extends MultiThreadedApplicationAdapter { } } } - if(streamName.contains("/")) { + if(streamName.contains("/")) { synchronized(remoteStreams) { if(remoteStreams.containsKey(streamName) == false) { String[] parts = streamName.split("/"); @@ -346,9 +342,8 @@ public class VideoApplication extends MultiThreadedApplicationAdapter { log.info("W3C x-category:stream x-event:play c-ip:{} x-sname:{} x-name:{}", new Object[] { Red5.getConnectionLocal().getRemoteAddress(), stream.getName(), item.getName() }); } - @Override - public void streamSubscriberClose(ISubscriberStream stream) { - + @Override + public void streamSubscriberClose(ISubscriberStream stream) { String streamName = stream.getBroadcastStreamPublishName(); streamName = streamName.replaceAll(H263Converter.H263PREFIX, ""); @@ -382,7 +377,7 @@ public class VideoApplication extends MultiThreadedApplicationAdapter { } } } - } + } private final class DisconnectProxyTask extends TimerTask { // Stream name that should be disconnected diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/BigBlueButtonApplication.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/BigBlueButtonApplication.java index ef1602b6cd..206fe69b5e 100755 --- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/BigBlueButtonApplication.java +++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/BigBlueButtonApplication.java @@ -91,14 +91,12 @@ public class BigBlueButtonApplication extends MultiThreadedApplicationAdapter { @Override public boolean roomStart(IScope room) { - connInvokerService.addScope(room.getName(), room); return super.roomStart(room); } @Override public void roomStop(IScope room) { recorderApplication.destroyRecordSession(room.getName()); - connInvokerService.removeScope(room.getName()); super.roomStop(room); } @@ -154,8 +152,6 @@ public class BigBlueButtonApplication extends MultiThreadedApplicationAdapter { bbbGW.initAudioSettings(room, internalUserID, muted); - boolean success = connInvokerService.addConnection(internalUserID, connection); - String meetingId = bbbSession.getRoom(); String connType = getConnectionType(Red5.getConnectionLocal().getType()); @@ -182,7 +178,7 @@ public class BigBlueButtonApplication extends MultiThreadedApplicationAdapter { log.info("User joining bbb-apps: data={}", logStr); - return success && super.roomConnect(connection, params); + return super.roomConnect(connection, params); } @@ -204,8 +200,6 @@ public class BigBlueButtonApplication extends MultiThreadedApplicationAdapter { String clientId = Red5.getConnectionLocal().getClient().getId(); log.info("***** " + APP + "[clientid=" + clientId + "] disconnnected from " + remoteHost + ":" + remotePort + "."); - connInvokerService.removeConnection(getBbbSession().getInternalUserID()); - BigBlueButtonSession bbbSession = (BigBlueButtonSession) Red5.getConnectionLocal().getAttribute(Constants.SESSION); String meetingId = bbbSession.getRoom(); diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/meeting/messaging/red5/ConnectionInvokerService.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/meeting/messaging/red5/ConnectionInvokerService.java index 2ed65996ae..9988ef9e79 100755 --- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/meeting/messaging/red5/ConnectionInvokerService.java +++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/meeting/messaging/red5/ConnectionInvokerService.java @@ -49,38 +49,17 @@ public class ConnectionInvokerService { private BlockingQueue<ClientMessage> messages; - private ConcurrentHashMap<String, IConnection> connections; - private ConcurrentHashMap<String, IScope> scopes; - private volatile boolean sendMessages = false; private IScope bbbAppScope; public ConnectionInvokerService() { messages = new LinkedBlockingQueue<ClientMessage>(); - - connections = new ConcurrentHashMap<String, IConnection>(); - scopes = new ConcurrentHashMap<String, IScope>(); } public void setAppScope(IScope scope) { bbbAppScope = scope; } - public boolean addConnection(String id, IConnection conn) { - if (connections == null) { - System.out.println("Connections is null!!!!"); - return false; - } - if (id == null) { - System.out.println("CONN ID IS NULL!!!"); - - } - if (conn == null) { - System.out.println("CONN IS NULL"); - } - return connections.putIfAbsent(id, conn) == null; - } - public void start() { sendMessages = true; Runnable sender = new Runnable() { @@ -105,18 +84,6 @@ public class ConnectionInvokerService { sendMessages = false; } - public void removeConnection(String id) { - connections.remove(id); - } - - public void addScope(String id, IScope scope) { - scopes.putIfAbsent(id, scope); - } - - public void removeScope(String id) { - scopes.remove(id); - } - public void sendMessage(final ClientMessage message) { messages.offer(message); } diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/presentation/ConversionUpdatesProcessor.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/presentation/ConversionUpdatesProcessor.java index 78c58fa102..33f022c403 100755 --- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/presentation/ConversionUpdatesProcessor.java +++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/presentation/ConversionUpdatesProcessor.java @@ -19,8 +19,7 @@ package org.bigbluebutton.conference.service.presentation; import org.slf4j.Logger; -import org.red5.logging.Red5LoggerFactory; - +import org.red5.logging.Red5LoggerFactory; public class ConversionUpdatesProcessor { private static Logger log = Red5LoggerFactory.getLogger(ConversionUpdatesProcessor.class, "bigbluebutton"); diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/whiteboard/WhiteboardListener.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/whiteboard/WhiteboardListener.java index 8f80bdb8bd..47bc7b68c6 100644 --- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/whiteboard/WhiteboardListener.java +++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/whiteboard/WhiteboardListener.java @@ -20,6 +20,7 @@ public class WhiteboardListener implements MessageHandler{ @Override public void handleMessage(String pattern, String channel, String message) { if (channel.equalsIgnoreCase(MessagingConstants.TO_WHITEBOARD_CHANNEL)) { + System.out.println("AntonChannel=(whiteboard)" + channel); JsonParser parser = new JsonParser(); JsonObject obj = (JsonObject) parser.parse(message); @@ -43,7 +44,7 @@ public class WhiteboardListener implements MessageHandler{ else { System.out.println("\n DID NOT FIND A whiteboardID \n"); } - System.out.println("\n user<" + requesterID + "> requested the shapes.\n"); + System.out.println("\n\n\n user<" + requesterID + "> requested the shapes.\n\n"); } } } diff --git a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonActor.scala b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonActor.scala index 3b3702d983..9980fda2e5 100755 --- a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonActor.scala +++ b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonActor.scala @@ -158,9 +158,6 @@ class BigBlueButtonActor(outGW: MessageOutGateway) extends Actor with LogHelper //send chat history this ! (new GetChatHistoryRequest(id, "nodeJSapp", "nodeJSapp")) - - //send lock settings - this ! (new GetLockSettings(id, "nodeJSapp")) } outGW.send(new GetAllMeetingsReply(resultArray)) diff --git a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonInGW.scala b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonInGW.scala index a360550d2f..ffcede9aed 100755 --- a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonInGW.scala +++ b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonInGW.scala @@ -197,14 +197,10 @@ class BigBlueButtonInGW(bbbGW: BigBlueButtonGateway, presUtil: PreuploadedPresen } def userConnectedToGlobalAudio(voiceConf: String, userid: String, name: String) { - // we are required to pass the meeting_id as first parameter (just to satisfy trait) - // but it's not used anywhere. That's why we pass voiceConf twice instead bbbGW.accept(new UserConnectedToGlobalAudio(voiceConf, voiceConf, userid, name)) } def userDisconnectedFromGlobalAudio(voiceConf: String, userid: String, name: String) { - // we are required to pass the meeting_id as first parameter (just to satisfy trait) - // but it's not used anywhere. That's why we pass voiceConf twice instead bbbGW.accept(new UserDisconnectedFromGlobalAudio(voiceConf, voiceConf, userid, name)) } diff --git a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala index 96dd63e40b..9a7ba08db6 100755 --- a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala +++ b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala @@ -93,7 +93,6 @@ class MeetingActor(val meetingID: String, val externalMeetingID: String, val mee case msg: MuteUserRequest => handleMuteUserRequest(msg) case msg: EjectUserFromVoiceRequest => handleEjectUserRequest(msg) case msg: SetLockSettings => handleSetLockSettings(msg) - case msg: GetLockSettings => handleGetLockSettings(msg) case msg: LockUserRequest => handleLockUserRequest(msg) case msg: InitLockSettings => handleInitLockSettings(msg) case msg: InitAudioSettings => handleInitAudioSettings(msg) diff --git a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/layout/red5/LayoutClientMessageSender.scala b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/layout/red5/LayoutClientMessageSender.scala index 190167883f..9f1820498c 100755 --- a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/layout/red5/LayoutClientMessageSender.scala +++ b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/layout/red5/LayoutClientMessageSender.scala @@ -30,10 +30,10 @@ class LayoutClientMessageSender(service: ConnectionInvokerService) extends OutMe private def handleBroadcastLayoutEvent(msg: BroadcastLayoutEvent) { val message = new java.util.HashMap[String, Object]() message.put("locked", msg.locked:java.lang.Boolean); - message.put("setByUserID", msg.requesterID); + message.put("setByUserID", msg.setByUserID); message.put("layout", msg.layoutID); - msg.applyTo.filter(_.userID != msg.requesterID) foreach {u => + msg.applyTo foreach {u => var m = new DirectClientMessage(msg.meetingID, u.userID, "syncLayout", message); service.sendMessage(m); } diff --git a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala index 53334d73a5..4311242bdd 100644 --- a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala +++ b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala @@ -82,11 +82,18 @@ trait UsersApp { //send the reply outGW.send(new ValidateAuthTokenReply(meetingID, msg.userId, msg.token, true, msg.correlationId, msg.sessionId)) + //send the list of users in the meeting + outGW.send(new GetUsersReply(meetingID, msg.userId, users.getUsers, msg.sessionId)) + + //send chat history + this ! (new GetChatHistoryRequest(meetingID, msg.userId, msg.userId)) + //join the user handleUserJoin(new UserJoining(meetingID, msg.userId, msg.token)) //send the presentation logger.info("ValidateToken success: mid=[" + meetingID + "] uid=[" + msg.userId + "]") + this ! (new GetPresentationInfo(meetingID, msg.userId, msg.userId)) } case None => { logger.info("ValidateToken failed: mid=[" + meetingID + "] uid=[" + msg.userId + "]") @@ -97,7 +104,7 @@ trait UsersApp { /** * Send a reply to BigBlueButtonActor to let it know this MeetingActor hasn't hung! * Sometimes, the actor seems to hang and doesn't anymore accept messages. This is a simple - * audit to check whether the actor is still alive. (ralam feb 25, 2015) + * audit to check whether the actor is still alive. (ralam feb 25, 2015) */ reply(new ValidateAuthTokenReply(meetingID, msg.userId, msg.token, false, msg.correlationId)) } @@ -147,14 +154,11 @@ trait UsersApp { case None => // do nothing } } - + def handleGetLockSettings(msg: GetLockSettings) { - //println("*************** Reply with current lock settings ********************") - - //reusing the existing handle for NewPermissionsSettings to reply to the GetLockSettings request - outGW.send(new NewPermissionsSetting(meetingID, msg.userId, permissions, users.getUsers)) + logger.info("Not implemented: handleGetLockSettings") } - + def handleSetLockSettings(msg: SetLockSettings) { // println("*************** Received new lock settings ********************") if (!permissionsEqual(msg.settings)) { @@ -316,7 +320,7 @@ trait UsersApp { if (u.presenter) { /* The current presenter has left the meeting. Find a moderator and make * him presenter. This way, if there is a moderator in the meeting, there - * will always be a presenter. + * will always be a presenter. */ val moderator = users.findAModerator() moderator.foreach { mod => diff --git a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/redis/UsersMessageToJsonConverter.scala b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/redis/UsersMessageToJsonConverter.scala index ae70ada5d8..693c75c283 100644 --- a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/redis/UsersMessageToJsonConverter.scala +++ b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/redis/UsersMessageToJsonConverter.scala @@ -137,7 +137,7 @@ object UsersMessageToJsonConverter { payload.put(Constants.STATUS, msg.status) payload.put(Constants.VALUE, msg.value.toString) - val header = Util.buildHeader(MessageNames.USER_STATUS_CHANGED, msg.version, None) + val header = Util.buildHeader(MessageNames.USER_STATUS_CHANGED, msg.version, None) Util.buildJson(header, payload) } diff --git a/bigbluebutton-client/branding/default/style/css/BBBBlack.css b/bigbluebutton-client/branding/default/style/css/BBBBlack.css index 10d9f8d963..af1050468f 100755 --- a/bigbluebutton-client/branding/default/style/css/BBBBlack.css +++ b/bigbluebutton-client/branding/default/style/css/BBBBlack.css @@ -46,7 +46,7 @@ ToolTip { paddingRight: 3; } -Button, .logoutButtonStyle, .chatSendButtonStyle, .helpLinkButtonStyle, .bandwidthButtonStyle { +Button, .logoutButtonStyle, .chatSendButtonStyle, .helpLinkButtonStyle { textIndent: 0; paddingLeft: 10; paddingRight: 10; @@ -643,11 +643,4 @@ MDIWindow { /*None of the following properties are overridden by the MDIWindow c fontFamily: Arial; fontSize: 20; fontWeight: bold; -} - -.bandwidthButtonStyle { - paddingTop: 0; - paddingBottom: 0; - height: 22; - icon: Embed('assets/images/bandwidth.png'); -} +} \ No newline at end of file diff --git a/bigbluebutton-client/locale/en_US/bbbResources.properties b/bigbluebutton-client/locale/en_US/bbbResources.properties index cc2875fd2d..b401d55f49 100755 --- a/bigbluebutton-client/locale/en_US/bbbResources.properties +++ b/bigbluebutton-client/locale/en_US/bbbResources.properties @@ -394,7 +394,7 @@ bbb.logout.appshutdown = The server app has been shut down bbb.logout.asyncerror = An Async Error occured bbb.logout.connectionclosed = The connection to the server has been closed bbb.logout.connectionfailed = The connection to the server has failed -bbb.logout.rejected = The connection to the server has been rejected\n\nIt may occur when you try to use the same session in multiple tabs in your browser +bbb.logout.rejected = The connection to the server has been rejected bbb.logout.invalidapp = The red5 app does not exist bbb.logout.unknown = Your client has lost connection with the server bbb.logout.guestkickedout = The moderator didn't allow you to join this meeting diff --git a/bigbluebutton-client/locale/pt_BR/bbbResources.properties b/bigbluebutton-client/locale/pt_BR/bbbResources.properties index ab62ac3bc1..66d4bb885b 100755 --- a/bigbluebutton-client/locale/pt_BR/bbbResources.properties +++ b/bigbluebutton-client/locale/pt_BR/bbbResources.properties @@ -393,7 +393,7 @@ bbb.logout.appshutdown = A aplicação no servidor foi interrompida bbb.logout.asyncerror = Um erro assÃncrono ocorreu bbb.logout.connectionclosed = A conexão com o servidor foi fechada bbb.logout.connectionfailed = A conexão com o servidor falhou -bbb.logout.rejected = A conexão com o servidor foi rejeitada\n\nIsso pode ocorrer quando você tenta utilizar a mesma sessão em múltiplas abas no seu navegador +bbb.logout.rejected = A conexão com o servidor foi rejeitada bbb.logout.invalidapp = O aplicativo red5 não existe bbb.logout.unknown = Seu cliente perdeu conexão com o servidor bbb.logout.guestkickedout = O moderador não permitiu sua entrada na sala diff --git a/bigbluebutton-client/resources/prod/lib/bbb_webrtc_bridge_sip.js b/bigbluebutton-client/resources/prod/lib/bbb_webrtc_bridge_sip.js index 0a5eb75c59..245ba860ee 100755 --- a/bigbluebutton-client/resources/prod/lib/bbb_webrtc_bridge_sip.js +++ b/bigbluebutton-client/resources/prod/lib/bbb_webrtc_bridge_sip.js @@ -37,26 +37,15 @@ function webRTCCallback(message) { } } -function callIntoConference(voiceBridge, callback, isListenOnly) { - // 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; - } - +function callIntoConference(voiceBridge, callback) { 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 + "]."); + + ",dialNumber=" + userInfo.dialNumber + ",voiceBridge=" + userInfo.voiceBridge + "]."); 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; @@ -64,7 +53,7 @@ function callIntoConference(voiceBridge, callback, isListenOnly) { voiceBridge = conferenceVoiceBridge; } console.log(callerIdName); - webrtc_call(callerIdName, voiceBridge, callback, isListenOnly); + webrtc_call(callerIdName, voiceBridge, callback); }); } else { if (voiceBridge === "9196") { @@ -72,7 +61,7 @@ function callIntoConference(voiceBridge, callback, isListenOnly) { } else { voiceBridge = conferenceVoiceBridge; } - webrtc_call(callerIdName, voiceBridge, callback, isListenOnly); + webrtc_call(callerIdName, voiceBridge, callback); } } @@ -220,30 +209,25 @@ function getUserMicMedia(getUserMicMediaSuccess, getUserMicMediaFailure) { } }; -function webrtc_call(username, voiceBridge, callback, isListenOnly) { +function webrtc_call(username, voiceBridge, callback) { 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); + if (userMicMedia && userAgent) // only make the call when both microphone and useragent have been created + make_call(username, voiceBridge, server, callback, false); }; + 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) { + + if (userMicMedia !== undefined) { makeCallFunc(); } else { callback({'status':'mediarequest'}); @@ -260,15 +244,11 @@ function webrtc_call(username, voiceBridge, callback, isListenOnly) { } } -function make_call(username, voiceBridge, server, callback, recall, isListenOnly) { - if (isListenOnly == null) { - isListenOnly = false; - } - +function make_call(username, voiceBridge, server, callback, recall) { if (userAgent == null) { console.log("userAgent is still null. Delaying call"); var callDelayTimeout = setTimeout( function() { - make_call(username, voiceBridge, server, callback, recall, isListenOnly); + make_call(username, voiceBridge, server, callback, recall); }, 100); return; } @@ -277,7 +257,7 @@ function make_call(username, voiceBridge, server, callback, recall, isListenOnly 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); + make_call(username, voiceBridge, server, callback, recall); }); return; } @@ -289,53 +269,16 @@ function make_call(username, voiceBridge, server, callback, recall, isListenOnly // 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 - render: { - remote: { - // select an element to render the incoming stream data - audio: 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, - render: { - remote: { - audio: document.getElementById('remote-media') - } + var options = { + media: { + stream: userMicMedia, + render: { + remote: { + audio: document.getElementById('remote-media') } } - }; - } + } + }; callTimeout = setTimeout(function() { console.log('Ten seconds without updates sending timeout code'); @@ -489,7 +432,3 @@ function webrtc_hangup(callback) { function isWebRTCAvailable() { return SIP.WebRTC.isSupported(); } - -function getCallStatus() { - return currentSession; -} diff --git a/bigbluebutton-client/resources/prod/lib/deployJava.js b/bigbluebutton-client/resources/prod/lib/deployJava.js index 8cfb0afcc1..7d06cb5ca1 100755 --- a/bigbluebutton-client/resources/prod/lib/deployJava.js +++ b/bigbluebutton-client/resources/prod/lib/deployJava.js @@ -1,2 +1,2 @@ -/* Copy of the file found at http://www.java.com/js/deployJava.js - January 18, 2015 */ +/* Copy of the file found at http://www.java.com/js/deployJava.js - January 18, 2015 */ var deployJava=function(){var l={core:["id","class","title","style"],i18n:["lang","dir"],events:["onclick","ondblclick","onmousedown","onmouseup","onmouseover","onmousemove","onmouseout","onkeypress","onkeydown","onkeyup"],applet:["codebase","code","name","archive","object","width","height","alt","align","hspace","vspace"],object:["classid","codebase","codetype","data","type","archive","declare","standby","height","width","usemap","name","tabindex","align","border","hspace","vspace"]};var b=l.object.concat(l.core,l.i18n,l.events);var m=l.applet.concat(l.core);function g(o){if(!d.debug){return}if(console.log){console.log(o)}else{alert(o)}}function k(p,o){if(p==null||p.length==0){return true}var r=p.charAt(p.length-1);if(r!="+"&&r!="*"&&(p.indexOf("_")!=-1&&r!="_")){p=p+"*";r="*"}p=p.substring(0,p.length-1);if(p.length>0){var q=p.charAt(p.length-1);if(q=="."||q=="_"){p=p.substring(0,p.length-1)}}if(r=="*"){return(o.indexOf(p)==0)}else{if(r=="+"){return p<=o}}return false}function e(){var o="//java.com/js/webstart.png";try{return document.location.protocol.indexOf("http")!=-1?o:"http:"+o}catch(p){return"http:"+o}}function n(p){var o="http://java.com/dt-redirect";if(p==null||p.length==0){return o}if(p.charAt(0)=="&"){p=p.substring(1,p.length)}return o+"?"+p}function j(q,p){var o=q.length;for(var r=0;r<o;r++){if(q[r]===p){return true}}return false}function c(o){return j(m,o.toLowerCase())}function i(o){return j(b,o.toLowerCase())}function a(o){if("MSIE"!=deployJava.browserName){return true}if(deployJava.compareVersionToPattern(deployJava.getPlugin().version,["10","0","0"],false,true)){return true}if(o==null){return false}return !k("1.6.0_33+",o)}var d={debug:null,version:"20120801",firefoxJavaVersion:null,myInterval:null,preInstallJREList:null,returnPage:null,brand:null,locale:null,installType:null,EAInstallEnabled:false,EarlyAccessURL:null,oldMimeType:"application/npruntime-scriptable-plugin;DeploymentToolkit",mimeType:"application/java-deployment-toolkit",launchButtonPNG:e(),browserName:null,browserName2:null,getJREs:function(){var t=new Array();if(this.isPluginInstalled()){var r=this.getPlugin();var o=r.jvms;for(var q=0;q<o.getLength();q++){t[q]=o.get(q).version}}else{var p=this.getBrowser();if(p=="MSIE"){if(this.testUsingActiveX("1.7.0")){t[0]="1.7.0"}else{if(this.testUsingActiveX("1.6.0")){t[0]="1.6.0"}else{if(this.testUsingActiveX("1.5.0")){t[0]="1.5.0"}else{if(this.testUsingActiveX("1.4.2")){t[0]="1.4.2"}else{if(this.testForMSVM()){t[0]="1.1"}}}}}}else{if(p=="Netscape Family"){this.getJPIVersionUsingMimeType();if(this.firefoxJavaVersion!=null){t[0]=this.firefoxJavaVersion}else{if(this.testUsingMimeTypes("1.7")){t[0]="1.7.0"}else{if(this.testUsingMimeTypes("1.6")){t[0]="1.6.0"}else{if(this.testUsingMimeTypes("1.5")){t[0]="1.5.0"}else{if(this.testUsingMimeTypes("1.4.2")){t[0]="1.4.2"}else{if(this.browserName2=="Safari"){if(this.testUsingPluginsArray("1.7.0")){t[0]="1.7.0"}else{if(this.testUsingPluginsArray("1.6")){t[0]="1.6.0"}else{if(this.testUsingPluginsArray("1.5")){t[0]="1.5.0"}else{if(this.testUsingPluginsArray("1.4.2")){t[0]="1.4.2"}}}}}}}}}}}}}if(this.debug){for(var q=0;q<t.length;++q){g("[getJREs()] We claim to have detected Java SE "+t[q])}}return t},installJRE:function(r,p){var o=false;if(this.isPluginInstalled()&&this.isAutoInstallEnabled(r)){var q=false;if(this.isCallbackSupported()){q=this.getPlugin().installJRE(r,p)}else{q=this.getPlugin().installJRE(r)}if(q){this.refresh();if(this.returnPage!=null){document.location=this.returnPage}}return q}else{return this.installLatestJRE()}},isAutoInstallEnabled:function(o){if(!this.isPluginInstalled()){return false}if(typeof o=="undefined"){o=null}return a(o)},isCallbackSupported:function(){return this.isPluginInstalled()&&this.compareVersionToPattern(this.getPlugin().version,["10","2","0"],false,true)},installLatestJRE:function(q){if(this.isPluginInstalled()&&this.isAutoInstallEnabled()){var r=false;if(this.isCallbackSupported()){r=this.getPlugin().installLatestJRE(q)}else{r=this.getPlugin().installLatestJRE()}if(r){this.refresh();if(this.returnPage!=null){document.location=this.returnPage}}return r}else{var p=this.getBrowser();var o=navigator.platform.toLowerCase();if((this.EAInstallEnabled=="true")&&(o.indexOf("win")!=-1)&&(this.EarlyAccessURL!=null)){this.preInstallJREList=this.getJREs();if(this.returnPage!=null){this.myInterval=setInterval("deployJava.poll()",3000)}location.href=this.EarlyAccessURL;return false}else{if(p=="MSIE"){return this.IEInstall()}else{if((p=="Netscape Family")&&(o.indexOf("win32")!=-1)){return this.FFInstall()}else{location.href=n(((this.returnPage!=null)?("&returnPage="+this.returnPage):"")+((this.locale!=null)?("&locale="+this.locale):"")+((this.brand!=null)?("&brand="+this.brand):""))}}return false}}},runApplet:function(p,u,r){if(r=="undefined"||r==null){r="1.1"}var t="^(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(?:_(\\d+))?)?)?$";var o=r.match(t);if(this.returnPage==null){this.returnPage=document.location}if(o!=null){var q=this.getBrowser();if(q!="?"){if(this.versionCheck(r+"+")){this.writeAppletTag(p,u)}else{if(this.installJRE(r+"+")){this.refresh();location.href=document.location;this.writeAppletTag(p,u)}}}else{this.writeAppletTag(p,u)}}else{g("[runApplet()] Invalid minimumVersion argument to runApplet():"+r)}},writeAppletTag:function(r,w){var o="<"+"applet ";var q="";var t="<"+"/"+"applet"+">";var x=true;if(null==w||typeof w!="object"){w=new Object()}for(var p in r){if(!c(p)){w[p]=r[p]}else{o+=(" "+p+'="'+r[p]+'"');if(p=="code"){x=false}}}var v=false;for(var u in w){if(u=="codebase_lookup"){v=true}if(u=="object"||u=="java_object"||u=="java_code"){x=false}q+='<param name="'+u+'" value="'+w[u]+'"/>'}if(!v){q+='<param name="codebase_lookup" value="false"/>'}if(x){o+=(' code="dummy"')}o+=">";document.write(o+"\n"+q+"\n"+t)},versionCheck:function(p){var v=0;var x="^(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(?:_(\\d+))?)?)?(\\*|\\+)?$";var y=p.match(x);if(y!=null){var r=false;var u=false;var q=new Array();for(var t=1;t<y.length;++t){if((typeof y[t]=="string")&&(y[t]!="")){q[v]=y[t];v++}}if(q[q.length-1]=="+"){u=true;r=false;q.length--}else{if(q[q.length-1]=="*"){u=false;r=true;q.length--}else{if(q.length<4){u=false;r=true}}}var w=this.getJREs();for(var t=0;t<w.length;++t){if(this.compareVersionToPattern(w[t],q,r,u)){return true}}return false}else{var o="Invalid versionPattern passed to versionCheck: "+p;g("[versionCheck()] "+o);alert(o);return false}},isWebStartInstalled:function(r){var q=this.getBrowser();if(q=="?"){return true}if(r=="undefined"||r==null){r="1.4.2"}var p=false;var t="^(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(?:_(\\d+))?)?)?$";var o=r.match(t);if(o!=null){p=this.versionCheck(r+"+")}else{g("[isWebStartInstaller()] Invalid minimumVersion argument to isWebStartInstalled(): "+r);p=this.versionCheck("1.4.2+")}return p},getJPIVersionUsingMimeType:function(){for(var p=0;p<navigator.mimeTypes.length;++p){var q=navigator.mimeTypes[p].type;var o=q.match(/^application\/x-java-applet;jpi-version=(.*)$/);if(o!=null){this.firefoxJavaVersion=o[1];if("Opera"!=this.browserName2){break}}}},launchWebStartApplication:function(r){var o=navigator.userAgent.toLowerCase();this.getJPIVersionUsingMimeType();if(this.isWebStartInstalled("1.7.0")==false){if((this.installJRE("1.7.0+")==false)||((this.isWebStartInstalled("1.7.0")==false))){return false}}var u=null;if(document.documentURI){u=document.documentURI}if(u==null){u=document.URL}var p=this.getBrowser();var q;if(p=="MSIE"){q="<"+'object classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" '+'width="0" height="0">'+"<"+'PARAM name="launchjnlp" value="'+r+'"'+">"+"<"+'PARAM name="docbase" value="'+u+'"'+">"+"<"+"/"+"object"+">"}else{if(p=="Netscape Family"){q="<"+'embed type="application/x-java-applet;jpi-version='+this.firefoxJavaVersion+'" '+'width="0" height="0" '+'launchjnlp="'+r+'"'+'docbase="'+u+'"'+" />"}}if(document.body=="undefined"||document.body==null){document.write(q);document.location=u}else{var t=document.createElement("div");t.id="div1";t.style.position="relative";t.style.left="-10000px";t.style.margin="0px auto";t.className="dynamicDiv";t.innerHTML=q;document.body.appendChild(t)}},createWebStartLaunchButtonEx:function(q,p){if(this.returnPage==null){this.returnPage=q}var o="javascript:deployJava.launchWebStartApplication('"+q+"');";document.write("<"+'a href="'+o+"\" onMouseOver=\"window.status=''; "+'return true;"><'+"img "+'src="'+this.launchButtonPNG+'" '+'border="0" /><'+"/"+"a"+">")},createWebStartLaunchButton:function(q,p){if(this.returnPage==null){this.returnPage=q}var o="javascript:"+"if (!deployJava.isWebStartInstalled(""+p+"")) {"+"if (deployJava.installLatestJRE()) {"+"if (deployJava.launch(""+q+"")) {}"+"}"+"} else {"+"if (deployJava.launch(""+q+"")) {}"+"}";document.write("<"+'a href="'+o+"\" onMouseOver=\"window.status=''; "+'return true;"><'+"img "+'src="'+this.launchButtonPNG+'" '+'border="0" /><'+"/"+"a"+">")},launch:function(o){document.location=o;return true},isPluginInstalled:function(){var o=this.getPlugin();if(o&&o.jvms){return true}else{return false}},isAutoUpdateEnabled:function(){if(this.isPluginInstalled()){return this.getPlugin().isAutoUpdateEnabled()}return false},setAutoUpdateEnabled:function(){if(this.isPluginInstalled()){return this.getPlugin().setAutoUpdateEnabled()}return false},setInstallerType:function(o){this.installType=o;if(this.isPluginInstalled()){return this.getPlugin().setInstallerType(o)}return false},setAdditionalPackages:function(o){if(this.isPluginInstalled()){return this.getPlugin().setAdditionalPackages(o)}return false},setEarlyAccess:function(o){this.EAInstallEnabled=o},isPlugin2:function(){if(this.isPluginInstalled()){if(this.versionCheck("1.6.0_10+")){try{return this.getPlugin().isPlugin2()}catch(o){}}}return false},allowPlugin:function(){this.getBrowser();var o=("Safari"!=this.browserName2&&"Opera"!=this.browserName2);return o},getPlugin:function(){this.refresh();var o=null;if(this.allowPlugin()){o=document.getElementById("deployJavaPlugin")}return o},compareVersionToPattern:function(v,p,r,t){if(v==undefined||p==undefined){return false}var w="^(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(?:_(\\d+))?)?)?$";var x=v.match(w);if(x!=null){var u=0;var y=new Array();for(var q=1;q<x.length;++q){if((typeof x[q]=="string")&&(x[q]!="")){y[u]=x[q];u++}}var o=Math.min(y.length,p.length);if(t){for(var q=0;q<o;++q){if(y[q]<p[q]){return false}else{if(y[q]>p[q]){return true}}}return true}else{for(var q=0;q<o;++q){if(y[q]!=p[q]){return false}}if(r){return true}else{return(y.length==p.length)}}}else{return false}},getBrowser:function(){if(this.browserName==null){var o=navigator.userAgent.toLowerCase();g("[getBrowser()] navigator.userAgent.toLowerCase() -> "+o);if((o.indexOf("msie")!=-1)&&(o.indexOf("opera")==-1)){this.browserName="MSIE";this.browserName2="MSIE"}else{if(o.indexOf("trident")!=-1||o.indexOf("Trident")!=-1){this.browserName="MSIE";this.browserName2="MSIE"}else{if(o.indexOf("iphone")!=-1){this.browserName="Netscape Family";this.browserName2="iPhone"}else{if((o.indexOf("firefox")!=-1)&&(o.indexOf("opera")==-1)){this.browserName="Netscape Family";this.browserName2="Firefox"}else{if(o.indexOf("chrome")!=-1){this.browserName="Netscape Family";this.browserName2="Chrome"}else{if(o.indexOf("safari")!=-1){this.browserName="Netscape Family";this.browserName2="Safari"}else{if((o.indexOf("mozilla")!=-1)&&(o.indexOf("opera")==-1)){this.browserName="Netscape Family";this.browserName2="Other"}else{if(o.indexOf("opera")!=-1){this.browserName="Netscape Family";this.browserName2="Opera"}else{this.browserName="?";this.browserName2="unknown"}}}}}}}}g("[getBrowser()] Detected browser name:"+this.browserName+", "+this.browserName2)}return this.browserName},testUsingActiveX:function(o){var q="JavaWebStart.isInstalled."+o+".0";if(typeof ActiveXObject=="undefined"||!ActiveXObject){g("[testUsingActiveX()] Browser claims to be IE, but no ActiveXObject object?");return false}try{return(new ActiveXObject(q)!=null)}catch(p){return false}},testForMSVM:function(){var p="{08B0E5C0-4FCB-11CF-AAA5-00401C608500}";if(typeof oClientCaps!="undefined"){var o=oClientCaps.getComponentVersion(p,"ComponentID");if((o=="")||(o=="5,0,5000,0")){return false}else{return true}}else{return false}},testUsingMimeTypes:function(p){if(!navigator.mimeTypes){g("[testUsingMimeTypes()] Browser claims to be Netscape family, but no mimeTypes[] array?");return false}for(var q=0;q<navigator.mimeTypes.length;++q){s=navigator.mimeTypes[q].type;var o=s.match(/^application\/x-java-applet\x3Bversion=(1\.8|1\.7|1\.6|1\.5|1\.4\.2)$/);if(o!=null){if(this.compareVersions(o[1],p)){return true}}}return false},testUsingPluginsArray:function(p){if((!navigator.plugins)||(!navigator.plugins.length)){return false}var o=navigator.platform.toLowerCase();for(var q=0;q<navigator.plugins.length;++q){s=navigator.plugins[q].description;if(s.search(/^Java Switchable Plug-in (Cocoa)/)!=-1){if(this.compareVersions("1.5.0",p)){return true}}else{if(s.search(/^Java/)!=-1){if(o.indexOf("win")!=-1){if(this.compareVersions("1.5.0",p)||this.compareVersions("1.6.0",p)){return true}}}}}if(this.compareVersions("1.5.0",p)){return true}return false},IEInstall:function(){location.href=n(((this.returnPage!=null)?("&returnPage="+this.returnPage):"")+((this.locale!=null)?("&locale="+this.locale):"")+((this.brand!=null)?("&brand="+this.brand):""));return false},done:function(p,o){},FFInstall:function(){location.href=n(((this.returnPage!=null)?("&returnPage="+this.returnPage):"")+((this.locale!=null)?("&locale="+this.locale):"")+((this.brand!=null)?("&brand="+this.brand):"")+((this.installType!=null)?("&type="+this.installType):""));return false},compareVersions:function(r,t){var p=r.split(".");var o=t.split(".");for(var q=0;q<p.length;++q){p[q]=Number(p[q])}for(var q=0;q<o.length;++q){o[q]=Number(o[q])}if(p.length==2){p[2]=0}if(p[0]>o[0]){return true}if(p[0]<o[0]){return false}if(p[1]>o[1]){return true}if(p[1]<o[1]){return false}if(p[2]>o[2]){return true}if(p[2]<o[2]){return false}return true},enableAlerts:function(){this.browserName=null;this.debug=true},poll:function(){this.refresh();var o=this.getJREs();if((this.preInstallJREList.length==0)&&(o.length!=0)){clearInterval(this.myInterval);if(this.returnPage!=null){location.href=this.returnPage}}if((this.preInstallJREList.length!=0)&&(o.length!=0)&&(this.preInstallJREList[0]!=o[0])){clearInterval(this.myInterval);if(this.returnPage!=null){location.href=this.returnPage}}},writePluginTag:function(){var o=this.getBrowser();if(o=="MSIE"){document.write("<"+'object classid="clsid:CAFEEFAC-DEC7-0000-0001-ABCDEFFEDCBA" '+'id="deployJavaPlugin" width="0" height="0">'+"<"+"/"+"object"+">")}else{if(o=="Netscape Family"&&this.allowPlugin()){this.writeEmbedTag()}}},refresh:function(){navigator.plugins.refresh(false);var o=this.getBrowser();if(o=="Netscape Family"&&this.allowPlugin()){var p=document.getElementById("deployJavaPlugin");if(p==null){this.writeEmbedTag()}}},writeEmbedTag:function(){var o=false;if(navigator.mimeTypes!=null){for(var p=0;p<navigator.mimeTypes.length;p++){if(navigator.mimeTypes[p].type==this.mimeType){if(navigator.mimeTypes[p].enabledPlugin){document.write("<"+'embed id="deployJavaPlugin" type="'+this.mimeType+'" hidden="true" />');o=true}}}if(!o){for(var p=0;p<navigator.mimeTypes.length;p++){if(navigator.mimeTypes[p].type==this.oldMimeType){if(navigator.mimeTypes[p].enabledPlugin){document.write("<"+'embed id="deployJavaPlugin" type="'+this.oldMimeType+'" hidden="true" />')}}}}}}};d.writePluginTag();if(d.locale==null){var h=null;if(h==null){try{h=navigator.userLanguage}catch(f){}}if(h==null){try{h=navigator.systemLanguage}catch(f){}}if(h==null){try{h=navigator.language}catch(f){}}if(h!=null){h.replace("-","_");d.locale=h}}return d}(); \ No newline at end of file diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesDispatcher.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesDispatcher.as index a682d08105..2767503df1 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesDispatcher.as +++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesDispatcher.as @@ -1,198 +1,198 @@ -/** - * 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.modules -{ - import com.asfusion.mate.events.Dispatcher; - import flash.events.TimerEvent; - import flash.utils.Timer; - import org.bigbluebutton.common.LogUtil; - import org.bigbluebutton.core.BBB; - import org.bigbluebutton.core.UsersUtil; - import org.bigbluebutton.core.vo.Config; - import org.bigbluebutton.core.vo.ConfigBuilder; - import org.bigbluebutton.main.api.JSLog; - import org.bigbluebutton.main.events.BBBEvent; - import org.bigbluebutton.main.events.ConfigEvent; - import org.bigbluebutton.main.events.ModuleLoadEvent; - import org.bigbluebutton.main.events.PortTestEvent; - import org.bigbluebutton.main.events.UserServicesEvent; - import org.bigbluebutton.main.model.ConfigParameters; - import org.bigbluebutton.main.model.modules.EnterApiService; - - public class ModulesDispatcher - { - private static const LOG:String = "Main::ModulesDispatcher - "; - private var dispatcher:Dispatcher; - private var enterApiService: EnterApiService; - private var meetingInfo:Object = new Object(); - private var enterApiUrl:String; - - public function ModulesDispatcher() - { - dispatcher = new Dispatcher(); - - } - - public function sendLoadProgressEvent(moduleName:String, loadProgress:Number):void{ - var loadEvent:ModuleLoadEvent = new ModuleLoadEvent(ModuleLoadEvent.MODULE_LOAD_PROGRESS); - loadEvent.moduleName = moduleName; - loadEvent.progress = loadProgress; - dispatcher.dispatchEvent(loadEvent); - } - - public function sendModuleLoadReadyEvent(moduleName:String):void{ - var loadReadyEvent:ModuleLoadEvent = new ModuleLoadEvent(ModuleLoadEvent.MODULE_LOAD_READY); - loadReadyEvent.moduleName = moduleName; - dispatcher.dispatchEvent(loadReadyEvent); - } - - public function sendAllModulesLoadedEvent():void{ - dispatcher.dispatchEvent(new ModuleLoadEvent(ModuleLoadEvent.ALL_MODULES_LOADED)); - - var loginEvent:BBBEvent = new BBBEvent(BBBEvent.LOGIN_EVENT); - dispatcher.dispatchEvent(loginEvent); - } - - public function sendStartUserServicesEvent(application:String, host:String, isTunnelling:Boolean):void{ - var e:UserServicesEvent = new UserServicesEvent(UserServicesEvent.START_USER_SERVICES); - e.applicationURI = application; - e.hostURI = host; - e.isTunnelling = isTunnelling; - dispatcher.dispatchEvent(e); - } - - public function sendPortTestEvent():void { - getMeetingAndUserInfo(); - } - - private function getMeetingAndUserInfo():void { - enterApiService = new EnterApiService(); - enterApiService.addResultListener(resultListener); - enterApiService.load(enterApiUrl); - } - - private function resultListener(success:Boolean, result:Object):void { - if (success) { - trace(LOG + "Saving meeting and user info " + JSON.stringify(result)); - - meetingInfo.username = result.username; - meetingInfo.userId = result.userId; - meetingInfo.meetingName = result.meetingName; - meetingInfo.meetingId = result.meetingId; - - doPortTesting(); - } else { - var logData:Object = new Object(); - JSLog.critical("Failed to get meeting and user info from Enter API", logData); - - dispatcher.dispatchEvent(new PortTestEvent(PortTestEvent.TUNNELING_FAILED)); - } - } - - private function doPortTesting():void { - trace(LOG + "Sending TEST_RTMP Event"); - var e:PortTestEvent = new PortTestEvent(PortTestEvent.TEST_RTMP); - dispatcher.dispatchEvent(e); - } - - private function timerHandler(e:TimerEvent):void{ - trace(LOG + "Sending PORT_TEST_UPDATE Event"); - var evt:PortTestEvent = new PortTestEvent(PortTestEvent.PORT_TEST_UPDATE); - dispatcher.dispatchEvent(evt); - } - - public function sendTunnelingFailedEvent(server: String, app: String):void{ - trace(LOG + "Sending TunnelingFailed Event"); - var logData:Object = new Object(); - logData.server = server; - logData.app = app; - logData.userId = meetingInfo.userId; - logData.username = meetingInfo.username; - logData.meetingName = meetingInfo.meetingName; - logData.meetingId = meetingInfo.meetingId; - trace(LOG + "Cannot connect to Red5 using RTMP and RTMPT", JSON.stringify(logData)); - JSLog.critical("Cannot connect to Red5 using RTMP and RTMPT", logData); - - dispatcher.dispatchEvent(new PortTestEvent(PortTestEvent.TUNNELING_FAILED)); - } - - public function sendPortTestSuccessEvent(port:String, host:String, protocol:String, app:String):void{ - trace(LOG + "Sending PORT_TEST_SUCCESS Event"); - var logData:Object = new Object(); - logData.port = port; - logData.server = host; - logData.protocol = protocol; - logData.app = app; - logData.userId = meetingInfo.userId; - logData.username = meetingInfo.username; - logData.meetingName = meetingInfo.meetingName; - logData.meetingId = meetingInfo.meetingId; - JSLog.debug("Successfully connected on test connection.", logData); - - var portEvent:PortTestEvent = new PortTestEvent(PortTestEvent.PORT_TEST_SUCCESS); - portEvent.port = port; - portEvent.hostname = host; - portEvent.protocol = protocol; - portEvent.app = app; - dispatcher.dispatchEvent(portEvent); - - } - - public function sendPortTestFailedEvent(port:String, host:String, protocol:String, app:String):void{ - trace(LOG + "Sending PORT_TEST_FAILED Event"); - var portFailEvent:PortTestEvent = new PortTestEvent(PortTestEvent.PORT_TEST_FAILED); - portFailEvent.port = port; - portFailEvent.hostname = host; - portFailEvent.protocol = protocol; - portFailEvent.app = app; - dispatcher.dispatchEvent(portFailEvent); - - } - - public function sendModuleLoadingStartedEvent(modules:XMLList):void{ - var event:ModuleLoadEvent = new ModuleLoadEvent(ModuleLoadEvent.MODULE_LOADING_STARTED); - event.modules = modules; - dispatcher.dispatchEvent(event); - } - - public function sendConfigParameters(c:ConfigParameters):void{ - enterApiUrl = c.host; - - var event:ConfigEvent = new ConfigEvent(ConfigEvent.CONFIG_EVENT); - var config:Config; - config = new ConfigBuilder(c.version, c.localeVersion) - .withApplication(c.application) - .withHelpUrl(c.helpURL) - .withHost(c.host) - .withLanguageEnabled(c.languageEnabled) - .withShortcutKeysShowButton(c.shortcutKeysShowButton) - .withNumModule(c.numModules) - .withPortTestApplication(c.portTestApplication) - .withPortTestHost(c.portTestHost) - .withShowDebug(c.showDebug) - .withSkinning(c.skinning) - .withCopyright(c.copyright) - .withLogo(c.logo) - .withBackground(c.background) - .build() - event.config = config; - dispatcher.dispatchEvent(event); - } - } +/** + * 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.modules +{ + import com.asfusion.mate.events.Dispatcher; + import flash.events.TimerEvent; + import flash.utils.Timer; + import org.bigbluebutton.common.LogUtil; + import org.bigbluebutton.core.BBB; + import org.bigbluebutton.core.UsersUtil; + import org.bigbluebutton.core.vo.Config; + import org.bigbluebutton.core.vo.ConfigBuilder; + import org.bigbluebutton.main.api.JSLog; + import org.bigbluebutton.main.events.BBBEvent; + import org.bigbluebutton.main.events.ConfigEvent; + import org.bigbluebutton.main.events.ModuleLoadEvent; + import org.bigbluebutton.main.events.PortTestEvent; + import org.bigbluebutton.main.events.UserServicesEvent; + import org.bigbluebutton.main.model.ConfigParameters; + import org.bigbluebutton.main.model.modules.EnterApiService; + + public class ModulesDispatcher + { + private static const LOG:String = "Main::ModulesDispatcher - "; + private var dispatcher:Dispatcher; + private var enterApiService: EnterApiService; + private var meetingInfo:Object = new Object(); + private var enterApiUrl:String; + + public function ModulesDispatcher() + { + dispatcher = new Dispatcher(); + + } + + public function sendLoadProgressEvent(moduleName:String, loadProgress:Number):void{ + var loadEvent:ModuleLoadEvent = new ModuleLoadEvent(ModuleLoadEvent.MODULE_LOAD_PROGRESS); + loadEvent.moduleName = moduleName; + loadEvent.progress = loadProgress; + dispatcher.dispatchEvent(loadEvent); + } + + public function sendModuleLoadReadyEvent(moduleName:String):void{ + var loadReadyEvent:ModuleLoadEvent = new ModuleLoadEvent(ModuleLoadEvent.MODULE_LOAD_READY); + loadReadyEvent.moduleName = moduleName; + dispatcher.dispatchEvent(loadReadyEvent); + } + + public function sendAllModulesLoadedEvent():void{ + dispatcher.dispatchEvent(new ModuleLoadEvent(ModuleLoadEvent.ALL_MODULES_LOADED)); + + var loginEvent:BBBEvent = new BBBEvent(BBBEvent.LOGIN_EVENT); + dispatcher.dispatchEvent(loginEvent); + } + + public function sendStartUserServicesEvent(application:String, host:String, isTunnelling:Boolean):void{ + var e:UserServicesEvent = new UserServicesEvent(UserServicesEvent.START_USER_SERVICES); + e.applicationURI = application; + e.hostURI = host; + e.isTunnelling = isTunnelling; + dispatcher.dispatchEvent(e); + } + + public function sendPortTestEvent():void { + getMeetingAndUserInfo(); + } + + private function getMeetingAndUserInfo():void { + enterApiService = new EnterApiService(); + enterApiService.addResultListener(resultListener); + enterApiService.load(enterApiUrl); + } + + private function resultListener(success:Boolean, result:Object):void { + if (success) { + trace(LOG + "Saving meeting and user info " + JSON.stringify(result)); + + meetingInfo.username = result.username; + meetingInfo.userId = result.userId; + meetingInfo.meetingName = result.meetingName; + meetingInfo.meetingId = result.meetingId; + + doPortTesting(); + } else { + var logData:Object = new Object(); + JSLog.critical("Failed to get meeting and user info from Enter API", logData); + + dispatcher.dispatchEvent(new PortTestEvent(PortTestEvent.TUNNELING_FAILED)); + } + } + + private function doPortTesting():void { + trace(LOG + "Sending TEST_RTMP Event"); + var e:PortTestEvent = new PortTestEvent(PortTestEvent.TEST_RTMP); + dispatcher.dispatchEvent(e); + } + + private function timerHandler(e:TimerEvent):void{ + trace(LOG + "Sending PORT_TEST_UPDATE Event"); + var evt:PortTestEvent = new PortTestEvent(PortTestEvent.PORT_TEST_UPDATE); + dispatcher.dispatchEvent(evt); + } + + public function sendTunnelingFailedEvent(server: String, app: String):void{ + trace(LOG + "Sending TunnelingFailed Event"); + var logData:Object = new Object(); + logData.server = server; + logData.app = app; + logData.userId = meetingInfo.userId; + logData.username = meetingInfo.username; + logData.meetingName = meetingInfo.meetingName; + logData.meetingId = meetingInfo.meetingId; + trace(LOG + "Cannot connect to Red5 using RTMP and RTMPT", JSON.stringify(logData)); + JSLog.critical("Cannot connect to Red5 using RTMP and RTMPT", logData); + + dispatcher.dispatchEvent(new PortTestEvent(PortTestEvent.TUNNELING_FAILED)); + } + + public function sendPortTestSuccessEvent(port:String, host:String, protocol:String, app:String):void{ + trace(LOG + "Sending PORT_TEST_SUCCESS Event"); + var logData:Object = new Object(); + logData.port = port; + logData.server = host; + logData.protocol = protocol; + logData.app = app; + logData.userId = meetingInfo.userId; + logData.username = meetingInfo.username; + logData.meetingName = meetingInfo.meetingName; + logData.meetingId = meetingInfo.meetingId; + JSLog.debug("Successfully connected on test connection.", logData); + + var portEvent:PortTestEvent = new PortTestEvent(PortTestEvent.PORT_TEST_SUCCESS); + portEvent.port = port; + portEvent.hostname = host; + portEvent.protocol = protocol; + portEvent.app = app; + dispatcher.dispatchEvent(portEvent); + + } + + public function sendPortTestFailedEvent(port:String, host:String, protocol:String, app:String):void{ + trace(LOG + "Sending PORT_TEST_FAILED Event"); + var portFailEvent:PortTestEvent = new PortTestEvent(PortTestEvent.PORT_TEST_FAILED); + portFailEvent.port = port; + portFailEvent.hostname = host; + portFailEvent.protocol = protocol; + portFailEvent.app = app; + dispatcher.dispatchEvent(portFailEvent); + + } + + public function sendModuleLoadingStartedEvent(modules:XMLList):void{ + var event:ModuleLoadEvent = new ModuleLoadEvent(ModuleLoadEvent.MODULE_LOADING_STARTED); + event.modules = modules; + dispatcher.dispatchEvent(event); + } + + public function sendConfigParameters(c:ConfigParameters):void{ + enterApiUrl = c.host; + + var event:ConfigEvent = new ConfigEvent(ConfigEvent.CONFIG_EVENT); + var config:Config; + config = new ConfigBuilder(c.version, c.localeVersion) + .withApplication(c.application) + .withHelpUrl(c.helpURL) + .withHost(c.host) + .withLanguageEnabled(c.languageEnabled) + .withShortcutKeysShowButton(c.shortcutKeysShowButton) + .withNumModule(c.numModules) + .withPortTestApplication(c.portTestApplication) + .withPortTestHost(c.portTestHost) + .withShowDebug(c.showDebug) + .withSkinning(c.skinning) + .withCopyright(c.copyright) + .withLogo(c.logo) + .withBackground(c.background) + .build() + event.config = config; + dispatcher.dispatchEvent(event); + } + } } \ No newline at end of file diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as index 80cefc3ef9..27b806cf04 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as +++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as @@ -1,412 +1,412 @@ -/** -* 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 -{ - import com.adobe.protocols.dict.events.ErrorEvent; - import com.asfusion.mate.events.Dispatcher; - - import flash.events.*; - import flash.net.NetConnection; - import flash.net.Responder; - import flash.utils.Timer; - - import org.bigbluebutton.common.LogUtil; - import org.bigbluebutton.core.UsersUtil; - import org.bigbluebutton.core.services.BandwidthMonitor; - import org.bigbluebutton.main.api.JSLog; - import org.bigbluebutton.main.events.InvalidAuthTokenEvent; - import org.bigbluebutton.main.model.ConferenceParameters; - import org.bigbluebutton.main.model.users.events.ConnectionFailedEvent; - import org.bigbluebutton.main.model.users.events.UsersConnectionEvent; - - public class NetConnectionDelegate - { - public static const LOG:String = "NetConnectionDelegate - "; - - private var _netConnection:NetConnection; - private var connectionId:Number; - private var connected:Boolean = false; - - private var _userid:Number = -1; - private var _role:String = "unknown"; - private var _applicationURI:String; - private var _conferenceParameters:ConferenceParameters; - - // These two are just placeholders. We'll get this from the server later and - // then pass to other modules. - private var _authToken:String = "AUTHORIZED"; - private var _room:String; - private var tried_tunneling:Boolean = false; - private var logoutOnUserCommand:Boolean = false; - private var guestKickedOutCommand:Boolean = false; - private var backoff:Number = 2000; - - private var dispatcher:Dispatcher; - private var _messageListeners:Array = new Array(); - - private var authenticated: Boolean = false; - - public function NetConnectionDelegate():void - { - dispatcher = new Dispatcher(); - - _netConnection = new NetConnection(); - _netConnection.proxyType = "best"; - _netConnection.client = this; - _netConnection.addEventListener( NetStatusEvent.NET_STATUS, netStatus ); - _netConnection.addEventListener( AsyncErrorEvent.ASYNC_ERROR, netASyncError ); - _netConnection.addEventListener( SecurityErrorEvent.SECURITY_ERROR, netSecurityError ); - _netConnection.addEventListener( IOErrorEvent.IO_ERROR, netIOError ); - } - - public function setUri(uri:String):void { - _applicationURI = uri; - - var pattern:RegExp = /(?P<protocol>.+):\/\/(?P<server>.+)\/(?P<app>.+)/; - var result:Array = pattern.exec(uri); - BandwidthMonitor.getInstance().serverURL = result.server; - } - - - public function get connection():NetConnection { - return _netConnection; - } - - public function addMessageListener(listener:IMessageListener):void { - _messageListeners.push(listener); - } - - public function removeMessageListener(listener:IMessageListener):void { - for (var ob:int=0; ob<_messageListeners.length; ob++) { - if (_messageListeners[ob] == listener) { - _messageListeners.splice (ob,1); - break; - } - } - } - - private function notifyListeners(messageName:String, message:Object):void { - if (messageName != null && messageName != "") { - for (var notify:String in _messageListeners) { - _messageListeners[notify].onMessage(messageName, message); - } - } else { - LogUtil.debug("Message name is undefined"); - } - } - - public function onMessageFromServer(messageName:String, msg:Object):void { - trace(LOG + "Got message from server [" + messageName + "]"); - if (!authenticated && (messageName == "validateAuthTokenReply")) { - handleValidateAuthTokenReply(msg) - } else if (messageName == "validateAuthTokenTimedOut") { - handleValidateAuthTokenTimedOut(msg) - } else if (authenticated) { - notifyListeners(messageName, msg); - } else { - trace(LOG + "Ignoring message=[" + messageName + "] as our token hasn't been validated yet."); - } - } - - private function validateToken():void { - var message:Object = new Object(); - message["userId"] = _conferenceParameters.internalUserID; - message["authToken"] = _conferenceParameters.authToken; - - sendMessage( - "validateToken",// Remote function name - // result - On successful result - function(result:Object):void { - trace(LOG + "validating token for [" + _conferenceParameters.internalUserID + "]"); - }, - // status - On error occurred - function(status:Object):void { - LogUtil.error("Error occurred:"); - for (var x:Object in status) { - LogUtil.error(x + " : " + status[x]); - } - }, - message - ); //_netConnection.call - } - - private function handleValidateAuthTokenTimedOut(msg: Object):void { - trace(LOG + "*** handleValidateAuthTokenTimedOut " + msg.msg + " **** \n"); - var map:Object = JSON.parse(msg.msg); - var tokenValid: Boolean = map.valid as Boolean; - var userId: String = map.userId as String; - - var logData:Object = new Object(); - logData.user = UsersUtil.getUserData(); - JSLog.critical("Validate auth token timed out.", logData); - - if (tokenValid) { - authenticated = true; - trace(LOG + "*** handleValidateAuthTokenTimedOut. valid=[ " + tokenValid + "] **** \n"); - } else { - trace(LOG + "*** handleValidateAuthTokenTimedOut. valid=[ " + tokenValid + "] **** \n"); - dispatcher.dispatchEvent(new InvalidAuthTokenEvent()); - } - } - - private function handleValidateAuthTokenReply(msg: Object):void { - trace(LOG + "*** handleValidateAuthTokenReply " + msg.msg + " **** \n"); - var map:Object = JSON.parse(msg.msg); - var tokenValid: Boolean = map.valid as Boolean; - var userId: String = map.userId as String; - - if (tokenValid) { - authenticated = true; - trace(LOG + "*** handleValidateAuthTokenReply. valid=[ " + tokenValid + "] **** \n"); - } else { - trace(LOG + "*** handleValidateAuthTokenReply. valid=[ " + tokenValid + "] **** \n"); - dispatcher.dispatchEvent(new InvalidAuthTokenEvent()); - } - } - - private function sendConnectionSuccessEvent(userid:String):void{ - var e:UsersConnectionEvent = new UsersConnectionEvent(UsersConnectionEvent.CONNECTION_SUCCESS); - e.userid = userid; - dispatcher.dispatchEvent(e); - - } - - public function sendMessage(service:String, onSuccess:Function, onFailure:Function, message:Object=null):void { - trace(LOG + "SENDING [" + service + "]"); - var responder:Responder = new Responder( - function(result:Object):void { // On successful result - onSuccess("Successfully sent [" + service + "]."); - }, - function(status:Object):void { // status - On error occurred - var errorReason:String = "Failed to send [" + service + "]:\n"; - for (var x:Object in status) { - errorReason += "\t" + x + " : " + status[x]; - } - } - ); - - if (message == null) { - _netConnection.call(service, responder); - } else { - _netConnection.call(service, responder, message); - } - } - - /** - * Connect to the server. - * uri: The uri to the conference application. - * username: Fullname of the participant. - * role: MODERATOR/VIEWER - * conference: The conference room - * mode: LIVE/PLAYBACK - Live:when used to collaborate, Playback:when being used to playback a recorded conference. - * room: Need the room number when playing back a recorded conference. When LIVE, the room is taken from the URI. - */ - public function connect(params:ConferenceParameters, tunnel:Boolean = false):void { - _conferenceParameters = params; - - tried_tunneling = tunnel; - - try { - var uri:String = _applicationURI + "/" + _conferenceParameters.room; - - trace(LOG + "::Connecting to " + uri + " [" + _conferenceParameters.username + "," + _conferenceParameters.role + "," + - _conferenceParameters.conference + "," + _conferenceParameters.record + "," + _conferenceParameters.room + ", " + _conferenceParameters.lockSettings.lockOnJoin + "]"); - _netConnection.connect(uri, _conferenceParameters.username, _conferenceParameters.role, - _conferenceParameters.room, _conferenceParameters.voicebridge, - _conferenceParameters.record, _conferenceParameters.externUserID, - _conferenceParameters.internalUserID, _conferenceParameters.muteOnStart, _conferenceParameters.lockSettings, - _conferenceParameters.guest); - } catch(e:ArgumentError) { - // Invalid parameters. - switch (e.errorID) { - case 2004 : - LogUtil.debug("Error! Invalid server location: " + uri); - break; - default : - LogUtil.debug("UNKNOWN Error! Invalid server location: " + uri); - break; - } - } - } - - public function disconnect(logoutOnUserCommand:Boolean):void { - this.logoutOnUserCommand = logoutOnUserCommand; - _netConnection.close(); - } - - public function guestDisconnect() : void - { - this.guestKickedOutCommand = true; - _netConnection.close(); - } - - - public function forceClose():void { - _netConnection.close(); - } - - protected function netStatus(event:NetStatusEvent):void { - handleResult( event ); - } - - private var autoReconnectTimer:Timer = new Timer(1000, 1); - - public function handleResult(event:Object):void { - var info : Object = event.info; - var statusCode : String = info.code; - - var logData:Object = new Object(); - logData.user = UsersUtil.getUserData(); - - switch (statusCode) { - case "NetConnection.Connect.Success": - trace(LOG + ":Connection to viewers application succeeded."); - JSLog.debug("Successfully connected to BBB App.", logData); - - validateToken(); - - break; - - case "NetConnection.Connect.Failed": - if (tried_tunneling) { - trace(LOG + ":Connection to viewers application failed...even when tunneling"); - sendConnectionFailedEvent(ConnectionFailedEvent.CONNECTION_FAILED); - } else { - disconnect(false); - trace(LOG + ":Connection to viewers application failed...try tunneling"); - var rtmptRetryTimer:Timer = new Timer(1000, 1); - rtmptRetryTimer.addEventListener("timer", rtmptRetryTimerHandler); - rtmptRetryTimer.start(); - } - break; - - case "NetConnection.Connect.Closed": - trace(LOG + "Connection to viewers application closed"); - sendConnectionFailedEvent(ConnectionFailedEvent.CONNECTION_CLOSED); - - break; - - case "NetConnection.Connect.InvalidApp": - trace(LOG + ":viewers application not found on server"); - sendConnectionFailedEvent(ConnectionFailedEvent.INVALID_APP); - break; - - case "NetConnection.Connect.AppShutDown": - trace(LOG + ":viewers application has been shutdown"); - sendConnectionFailedEvent(ConnectionFailedEvent.APP_SHUTDOWN); - break; - - case "NetConnection.Connect.Rejected": - trace(LOG + ":Connection to the server rejected. Uri: " + _applicationURI + ". Check if the red5 specified in the uri exists and is running" ); - sendConnectionFailedEvent(ConnectionFailedEvent.CONNECTION_REJECTED); - break; - - case "NetConnection.Connect.NetworkChange": - JSLog.warn("Detected network change to BBB App", logData); - trace(LOG + "Detected network change. User might be on a wireless and temporarily dropped connection. Doing nothing. Just making a note."); - break; - - default : - trace(LOG + ":Default status to the viewers application" ); - sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON); - break; - } - } - - private function autoReconnectTimerHandler(event:TimerEvent):void { - trace(LOG + "autoReconnectTimerHandler: " + event); - connect(_conferenceParameters, tried_tunneling); - } - - private function rtmptRetryTimerHandler(event:TimerEvent):void { - trace(LOG + "rtmptRetryTimerHandler: " + event); - connect(_conferenceParameters, true); - } - - protected function netSecurityError(event: SecurityErrorEvent):void { - trace(LOG + "Security error - " + event.text); - sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON); - } - - protected function netIOError(event: IOErrorEvent):void { - trace(LOG + "Input/output error - " + event.text); - sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON); - } - - protected function netASyncError(event: AsyncErrorEvent):void { - trace(LOG + "Asynchronous code error - " + event.toString() ); - - LogUtil.debug("Asynchronous code error - " + event.toString() ); - sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON); - } - - private function sendConnectionFailedEvent(reason:String):void{ - var logData:Object = new Object(); - - if (this.guestKickedOutCommand) { - logData.reason = "Guest kicked out"; - logData.user = UsersUtil.getUserData(); - JSLog.warn("User disconnected from BBB App.", logData); - sendGuestUserKickedOutEvent(); - } else if (this.logoutOnUserCommand) { - logData.reason = "User requested."; - logData.user = UsersUtil.getUserData(); - JSLog.debug("User logged out from BBB App.", logData); - sendUserLoggedOutEvent(); - } else { - logData.reason = reason; - logData.user = UsersUtil.getUserData(); - JSLog.warn("User disconnected from BBB App.", logData); - var e:ConnectionFailedEvent = new ConnectionFailedEvent(reason); - dispatcher.dispatchEvent(e); - } - } - - private function sendUserLoggedOutEvent():void{ - var e:ConnectionFailedEvent = new ConnectionFailedEvent(ConnectionFailedEvent.USER_LOGGED_OUT); - dispatcher.dispatchEvent(e); - } - - private function sendGuestUserKickedOutEvent():void { - var e:ConnectionFailedEvent = new ConnectionFailedEvent(ConnectionFailedEvent.MODERATOR_DENIED_ME); - dispatcher.dispatchEvent(e); - } - - private function attemptReconnect(backoff:Number):void{ - var retryTimer:Timer = new Timer(backoff, 1); - retryTimer.addEventListener(TimerEvent.TIMER, function():void{ - connect(_conferenceParameters, tried_tunneling); - }); - retryTimer.start(); - if (this.backoff < 16000) this.backoff = backoff *2; - } - - public function onBWCheck(... rest):Number { - return 0; - } - - public function onBWDone(... rest):void { - var p_bw:Number; - if (rest.length > 0) p_bw = rest[0]; - // your application should do something here - // when the bandwidth check is complete - trace("bandwidth = " + p_bw + " Kbps."); - } - } -} +/** +* 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 +{ + import com.adobe.protocols.dict.events.ErrorEvent; + import com.asfusion.mate.events.Dispatcher; + + import flash.events.*; + import flash.net.NetConnection; + import flash.net.Responder; + import flash.utils.Timer; + + import org.bigbluebutton.common.LogUtil; + import org.bigbluebutton.core.UsersUtil; + import org.bigbluebutton.core.services.BandwidthMonitor; + import org.bigbluebutton.main.api.JSLog; + import org.bigbluebutton.main.events.InvalidAuthTokenEvent; + import org.bigbluebutton.main.model.ConferenceParameters; + import org.bigbluebutton.main.model.users.events.ConnectionFailedEvent; + import org.bigbluebutton.main.model.users.events.UsersConnectionEvent; + + public class NetConnectionDelegate + { + public static const LOG:String = "NetConnectionDelegate - "; + + private var _netConnection:NetConnection; + private var connectionId:Number; + private var connected:Boolean = false; + + private var _userid:Number = -1; + private var _role:String = "unknown"; + private var _applicationURI:String; + private var _conferenceParameters:ConferenceParameters; + + // These two are just placeholders. We'll get this from the server later and + // then pass to other modules. + private var _authToken:String = "AUTHORIZED"; + private var _room:String; + private var tried_tunneling:Boolean = false; + private var logoutOnUserCommand:Boolean = false; + private var guestKickedOutCommand:Boolean = false; + private var backoff:Number = 2000; + + private var dispatcher:Dispatcher; + private var _messageListeners:Array = new Array(); + + private var authenticated: Boolean = false; + + public function NetConnectionDelegate():void + { + dispatcher = new Dispatcher(); + + _netConnection = new NetConnection(); + _netConnection.proxyType = "best"; + _netConnection.client = this; + _netConnection.addEventListener( NetStatusEvent.NET_STATUS, netStatus ); + _netConnection.addEventListener( AsyncErrorEvent.ASYNC_ERROR, netASyncError ); + _netConnection.addEventListener( SecurityErrorEvent.SECURITY_ERROR, netSecurityError ); + _netConnection.addEventListener( IOErrorEvent.IO_ERROR, netIOError ); + } + + public function setUri(uri:String):void { + _applicationURI = uri; + + var pattern:RegExp = /(?P<protocol>.+):\/\/(?P<server>.+)\/(?P<app>.+)/; + var result:Array = pattern.exec(uri); + BandwidthMonitor.getInstance().serverURL = result.server; + } + + + public function get connection():NetConnection { + return _netConnection; + } + + public function addMessageListener(listener:IMessageListener):void { + _messageListeners.push(listener); + } + + public function removeMessageListener(listener:IMessageListener):void { + for (var ob:int=0; ob<_messageListeners.length; ob++) { + if (_messageListeners[ob] == listener) { + _messageListeners.splice (ob,1); + break; + } + } + } + + private function notifyListeners(messageName:String, message:Object):void { + if (messageName != null && messageName != "") { + for (var notify:String in _messageListeners) { + _messageListeners[notify].onMessage(messageName, message); + } + } else { + LogUtil.debug("Message name is undefined"); + } + } + + public function onMessageFromServer(messageName:String, msg:Object):void { + trace(LOG + "Got message from server [" + messageName + "]"); + if (!authenticated && (messageName == "validateAuthTokenReply")) { + handleValidateAuthTokenReply(msg) + } else if (messageName == "validateAuthTokenTimedOut") { + handleValidateAuthTokenTimedOut(msg) + } else if (authenticated) { + notifyListeners(messageName, msg); + } else { + trace(LOG + "Ignoring message=[" + messageName + "] as our token hasn't been validated yet."); + } + } + + private function validateToken():void { + var message:Object = new Object(); + message["userId"] = _conferenceParameters.internalUserID; + message["authToken"] = _conferenceParameters.authToken; + + sendMessage( + "validateToken",// Remote function name + // result - On successful result + function(result:Object):void { + trace(LOG + "validating token for [" + _conferenceParameters.internalUserID + "]"); + }, + // status - On error occurred + function(status:Object):void { + LogUtil.error("Error occurred:"); + for (var x:Object in status) { + LogUtil.error(x + " : " + status[x]); + } + }, + message + ); //_netConnection.call + } + + private function handleValidateAuthTokenTimedOut(msg: Object):void { + trace(LOG + "*** handleValidateAuthTokenTimedOut " + msg.msg + " **** \n"); + var map:Object = JSON.parse(msg.msg); + var tokenValid: Boolean = map.valid as Boolean; + var userId: String = map.userId as String; + + var logData:Object = new Object(); + logData.user = UsersUtil.getUserData(); + JSLog.critical("Validate auth token timed out.", logData); + + if (tokenValid) { + authenticated = true; + trace(LOG + "*** handleValidateAuthTokenTimedOut. valid=[ " + tokenValid + "] **** \n"); + } else { + trace(LOG + "*** handleValidateAuthTokenTimedOut. valid=[ " + tokenValid + "] **** \n"); + dispatcher.dispatchEvent(new InvalidAuthTokenEvent()); + } + } + + private function handleValidateAuthTokenReply(msg: Object):void { + trace(LOG + "*** handleValidateAuthTokenReply " + msg.msg + " **** \n"); + var map:Object = JSON.parse(msg.msg); + var tokenValid: Boolean = map.valid as Boolean; + var userId: String = map.userId as String; + + if (tokenValid) { + authenticated = true; + trace(LOG + "*** handleValidateAuthTokenReply. valid=[ " + tokenValid + "] **** \n"); + } else { + trace(LOG + "*** handleValidateAuthTokenReply. valid=[ " + tokenValid + "] **** \n"); + dispatcher.dispatchEvent(new InvalidAuthTokenEvent()); + } + } + + private function sendConnectionSuccessEvent(userid:String):void{ + var e:UsersConnectionEvent = new UsersConnectionEvent(UsersConnectionEvent.CONNECTION_SUCCESS); + e.userid = userid; + dispatcher.dispatchEvent(e); + + } + + public function sendMessage(service:String, onSuccess:Function, onFailure:Function, message:Object=null):void { + trace(LOG + "SENDING [" + service + "]"); + var responder:Responder = new Responder( + function(result:Object):void { // On successful result + onSuccess("Successfully sent [" + service + "]."); + }, + function(status:Object):void { // status - On error occurred + var errorReason:String = "Failed to send [" + service + "]:\n"; + for (var x:Object in status) { + errorReason += "\t" + x + " : " + status[x]; + } + } + ); + + if (message == null) { + _netConnection.call(service, responder); + } else { + _netConnection.call(service, responder, message); + } + } + + /** + * Connect to the server. + * uri: The uri to the conference application. + * username: Fullname of the participant. + * role: MODERATOR/VIEWER + * conference: The conference room + * mode: LIVE/PLAYBACK - Live:when used to collaborate, Playback:when being used to playback a recorded conference. + * room: Need the room number when playing back a recorded conference. When LIVE, the room is taken from the URI. + */ + public function connect(params:ConferenceParameters, tunnel:Boolean = false):void { + _conferenceParameters = params; + + tried_tunneling = tunnel; + + try { + var uri:String = _applicationURI + "/" + _conferenceParameters.room; + + trace(LOG + "::Connecting to " + uri + " [" + _conferenceParameters.username + "," + _conferenceParameters.role + "," + + _conferenceParameters.conference + "," + _conferenceParameters.record + "," + _conferenceParameters.room + ", " + _conferenceParameters.lockSettings.lockOnJoin + "]"); + _netConnection.connect(uri, _conferenceParameters.username, _conferenceParameters.role, + _conferenceParameters.room, _conferenceParameters.voicebridge, + _conferenceParameters.record, _conferenceParameters.externUserID, + _conferenceParameters.internalUserID, _conferenceParameters.muteOnStart, _conferenceParameters.lockSettings, + _conferenceParameters.guest); + } catch(e:ArgumentError) { + // Invalid parameters. + switch (e.errorID) { + case 2004 : + LogUtil.debug("Error! Invalid server location: " + uri); + break; + default : + LogUtil.debug("UNKNOWN Error! Invalid server location: " + uri); + break; + } + } + } + + public function disconnect(logoutOnUserCommand:Boolean):void { + this.logoutOnUserCommand = logoutOnUserCommand; + _netConnection.close(); + } + + public function guestDisconnect() : void + { + this.guestKickedOutCommand = true; + _netConnection.close(); + } + + + public function forceClose():void { + _netConnection.close(); + } + + protected function netStatus(event:NetStatusEvent):void { + handleResult( event ); + } + + private var autoReconnectTimer:Timer = new Timer(1000, 1); + + public function handleResult(event:Object):void { + var info : Object = event.info; + var statusCode : String = info.code; + + var logData:Object = new Object(); + logData.user = UsersUtil.getUserData(); + + switch (statusCode) { + case "NetConnection.Connect.Success": + trace(LOG + ":Connection to viewers application succeeded."); + JSLog.debug("Successfully connected to BBB App.", logData); + + validateToken(); + + break; + + case "NetConnection.Connect.Failed": + if (tried_tunneling) { + trace(LOG + ":Connection to viewers application failed...even when tunneling"); + sendConnectionFailedEvent(ConnectionFailedEvent.CONNECTION_FAILED); + } else { + disconnect(false); + trace(LOG + ":Connection to viewers application failed...try tunneling"); + var rtmptRetryTimer:Timer = new Timer(1000, 1); + rtmptRetryTimer.addEventListener("timer", rtmptRetryTimerHandler); + rtmptRetryTimer.start(); + } + break; + + case "NetConnection.Connect.Closed": + trace(LOG + "Connection to viewers application closed"); + sendConnectionFailedEvent(ConnectionFailedEvent.CONNECTION_CLOSED); + + break; + + case "NetConnection.Connect.InvalidApp": + trace(LOG + ":viewers application not found on server"); + sendConnectionFailedEvent(ConnectionFailedEvent.INVALID_APP); + break; + + case "NetConnection.Connect.AppShutDown": + trace(LOG + ":viewers application has been shutdown"); + sendConnectionFailedEvent(ConnectionFailedEvent.APP_SHUTDOWN); + break; + + case "NetConnection.Connect.Rejected": + trace(LOG + ":Connection to the server rejected. Uri: " + _applicationURI + ". Check if the red5 specified in the uri exists and is running" ); + sendConnectionFailedEvent(ConnectionFailedEvent.CONNECTION_REJECTED); + break; + + case "NetConnection.Connect.NetworkChange": + JSLog.warn("Detected network change to BBB App", logData); + trace(LOG + "Detected network change. User might be on a wireless and temporarily dropped connection. Doing nothing. Just making a note."); + break; + + default : + trace(LOG + ":Default status to the viewers application" ); + sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON); + break; + } + } + + private function autoReconnectTimerHandler(event:TimerEvent):void { + trace(LOG + "autoReconnectTimerHandler: " + event); + connect(_conferenceParameters, tried_tunneling); + } + + private function rtmptRetryTimerHandler(event:TimerEvent):void { + trace(LOG + "rtmptRetryTimerHandler: " + event); + connect(_conferenceParameters, true); + } + + protected function netSecurityError(event: SecurityErrorEvent):void { + trace(LOG + "Security error - " + event.text); + sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON); + } + + protected function netIOError(event: IOErrorEvent):void { + trace(LOG + "Input/output error - " + event.text); + sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON); + } + + protected function netASyncError(event: AsyncErrorEvent):void { + trace(LOG + "Asynchronous code error - " + event.toString() ); + + LogUtil.debug("Asynchronous code error - " + event.toString() ); + sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON); + } + + private function sendConnectionFailedEvent(reason:String):void{ + var logData:Object = new Object(); + + if (this.guestKickedOutCommand) { + logData.reason = "Guest kicked out"; + logData.user = UsersUtil.getUserData(); + JSLog.warn("User disconnected from BBB App.", logData); + sendGuestUserKickedOutEvent(); + } else if (this.logoutOnUserCommand) { + logData.reason = "User requested."; + logData.user = UsersUtil.getUserData(); + JSLog.debug("User logged out from BBB App.", logData); + sendUserLoggedOutEvent(); + } else { + logData.reason = reason; + logData.user = UsersUtil.getUserData(); + JSLog.warn("User disconnected from BBB App.", logData); + var e:ConnectionFailedEvent = new ConnectionFailedEvent(reason); + dispatcher.dispatchEvent(e); + } + } + + private function sendUserLoggedOutEvent():void{ + var e:ConnectionFailedEvent = new ConnectionFailedEvent(ConnectionFailedEvent.USER_LOGGED_OUT); + dispatcher.dispatchEvent(e); + } + + private function sendGuestUserKickedOutEvent():void { + var e:ConnectionFailedEvent = new ConnectionFailedEvent(ConnectionFailedEvent.MODERATOR_DENIED_ME); + dispatcher.dispatchEvent(e); + } + + private function attemptReconnect(backoff:Number):void{ + var retryTimer:Timer = new Timer(backoff, 1); + retryTimer.addEventListener(TimerEvent.TIMER, function():void{ + connect(_conferenceParameters, tried_tunneling); + }); + retryTimer.start(); + if (this.backoff < 16000) this.backoff = backoff *2; + } + + public function onBWCheck(... rest):Number { + return 0; + } + + public function onBWDone(... rest):void { + var p_bw:Number; + if (rest.length > 0) p_bw = rest[0]; + // your application should do something here + // when the bandwidth check is complete + trace("bandwidth = " + p_bw + " Kbps."); + } + } +} diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/LockSettings.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/LockSettings.mxml index 2c4aa7cbc9..698863eca2 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/main/views/LockSettings.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/LockSettings.mxml @@ -160,7 +160,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. <mx:HBox width="100%" horizontalAlign="right" horizontalGap="18" paddingTop="20"> <mx:Button id="saveBtn" label="{ResourceUtil.getInstance().getString('bbb.lockSettings.save')}" click="onSaveClicked()" tabIndex="{baseIndex+8}" - toolTip="{ResourceUtil.getInstance().getString('bbb.lockSettings.save.tooltip')}"/> + toolTip="{ResourceUtil.getInstance().getString('bbb.lockSettings.save.toolTip')}"/> <mx:Button id="cancelBtn" label="{ResourceUtil.getInstance().getString('bbb.lockSettings.cancel')}" click="onCancelClicked()" tabIndex="{baseIndex+9}" diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/maps/ChatEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/maps/ChatEventMap.mxml index 4fec5fa026..c4f7100c6d 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/maps/ChatEventMap.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/maps/ChatEventMap.mxml @@ -1,109 +1,109 @@ -<?xml version="1.0" encoding="utf-8"?> - -<!-- - -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/>. - ---> - -<EventMap xmlns="http://mate.asfusion.com/" - xmlns:mx="http://www.adobe.com/2006/mxml"> - <mx:Script> - <![CDATA[ - import com.asfusion.mate.events.Dispatcher; - import mx.events.FlexEvent; - import org.bigbluebutton.common.events.OpenWindowEvent; - import org.bigbluebutton.core.EventConstants; - import org.bigbluebutton.main.events.ModuleStartedEvent; - import org.bigbluebutton.modules.chat.events.ChatCopyEvent; - import org.bigbluebutton.modules.chat.events.ChatEvent; - import org.bigbluebutton.modules.chat.events.ChatSaveEvent; - import org.bigbluebutton.modules.chat.events.SendPrivateChatMessageEvent; - import org.bigbluebutton.modules.chat.events.SendPublicChatMessageEvent; - import org.bigbluebutton.modules.chat.events.StartChatModuleEvent; - import org.bigbluebutton.modules.chat.events.StopChatModuleEvent; - import org.bigbluebutton.modules.chat.events.TranscriptEvent; - import org.bigbluebutton.modules.chat.services.ChatMessageService; - import org.bigbluebutton.modules.chat.services.MessageReceiver; - import org.bigbluebutton.modules.chat.services.MessageSender; - import org.bigbluebutton.modules.chat.services.ChatCopy; - import org.bigbluebutton.modules.chat.services.ChatSaver; - import org.bigbluebutton.modules.chat.views.ChatView; - import org.bigbluebutton.modules.chat.views.ChatWindow; - ]]> - </mx:Script> - - <EventHandlers type="{FlexEvent.PREINITIALIZE}"> - <ObjectBuilder generator="{ChatEventMapDelegate}" constructorArguments="{scope.dispatcher}"/> - </EventHandlers> - - <EventHandlers type="{StartChatModuleEvent.START_CHAT_MODULE_EVENT}"> - <MethodInvoker generator="{ChatEventMapDelegate}" method="openChatWindow" /> - <ObjectBuilder generator="{ChatMessageService}"/> - </EventHandlers> - - <EventHandlers type="{StopChatModuleEvent.STOP_CHAT_MODULE_EVENT}"> - <MethodInvoker generator="{ChatEventMapDelegate}" method="closeChatWindow" /> - </EventHandlers> - - <EventHandlers type="{EventConstants.SEND_PUBLIC_CHAT_REQ}"> - <MethodInvoker generator="{ChatMessageService}" method="sendPublicMessageFromApi" arguments="{event.message}"/> - </EventHandlers> - - <EventHandlers type="{EventConstants.SEND_PRIVATE_CHAT_REQ}"> - <MethodInvoker generator="{ChatMessageService}" method="sendPrivateMessageFromApi" arguments="{event.message}"/> - </EventHandlers> - - <EventHandlers type="{SendPublicChatMessageEvent.SEND_PUBLIC_CHAT_MESSAGE_EVENT}"> - <MethodInvoker generator="{ChatMessageService}" method="sendPublicMessage" arguments="{event.chatMessage}"/> - </EventHandlers> - - <EventHandlers type="{SendPrivateChatMessageEvent.SEND_PRIVATE_CHAT_MESSAGE_EVENT}"> - <MethodInvoker generator="{ChatMessageService}" method="sendPrivateMessage" arguments="{event.chatMessage}"/> - </EventHandlers> - - <EventHandlers type="{TranscriptEvent.LOAD_TRANSCRIPT}" > - <MethodInvoker generator="{ChatMessageService}" method="getPublicChatMessages"/> - </EventHandlers> - - <EventHandlers type="{TranscriptEvent.TRANSCRIPT_EVENT}" > - <MethodInvoker generator="{ChatMessageService}" method="sendWelcomeMessage"/> - </EventHandlers> - - <EventHandlers type="{ChatSaveEvent.SAVE_CHAT_EVENT}"> - <MethodInvoker generator="{ChatSaver}" method="saveChatToFile" arguments="{event}"/> - </EventHandlers> - - <EventHandlers type="{ChatCopyEvent.COPY_CHAT_EVENT}"> - <MethodInvoker generator="{ChatCopy}" method="copyAllText" arguments="{event}"/> - </EventHandlers> - - <Injectors target="{ChatMessageService}"> - <PropertyInjector targetKey="dispatcher" source="{scope.dispatcher}"/> - <PropertyInjector targetKey="receiver" source="{MessageReceiver}"/> - <PropertyInjector targetKey="sender" source="{MessageSender}"/> - </Injectors> - - <Injectors target="{MessageReceiver}"> - <PropertyInjector targetKey="dispatcher" source="{scope.dispatcher}"/> - </Injectors> - - <Injectors target="{MessageSender}"> - <PropertyInjector targetKey="dispatcher" source="{scope.dispatcher}"/> - </Injectors> - -</EventMap> +<?xml version="1.0" encoding="utf-8"?> + +<!-- + +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/>. + +--> + +<EventMap xmlns="http://mate.asfusion.com/" + xmlns:mx="http://www.adobe.com/2006/mxml"> + <mx:Script> + <![CDATA[ + import com.asfusion.mate.events.Dispatcher; + import mx.events.FlexEvent; + import org.bigbluebutton.common.events.OpenWindowEvent; + import org.bigbluebutton.core.EventConstants; + import org.bigbluebutton.main.events.ModuleStartedEvent; + import org.bigbluebutton.modules.chat.events.ChatCopyEvent; + import org.bigbluebutton.modules.chat.events.ChatEvent; + import org.bigbluebutton.modules.chat.events.ChatSaveEvent; + import org.bigbluebutton.modules.chat.events.SendPrivateChatMessageEvent; + import org.bigbluebutton.modules.chat.events.SendPublicChatMessageEvent; + import org.bigbluebutton.modules.chat.events.StartChatModuleEvent; + import org.bigbluebutton.modules.chat.events.StopChatModuleEvent; + import org.bigbluebutton.modules.chat.events.TranscriptEvent; + import org.bigbluebutton.modules.chat.services.ChatMessageService; + import org.bigbluebutton.modules.chat.services.MessageReceiver; + import org.bigbluebutton.modules.chat.services.MessageSender; + import org.bigbluebutton.modules.chat.services.ChatCopy; + import org.bigbluebutton.modules.chat.services.ChatSaver; + import org.bigbluebutton.modules.chat.views.ChatView; + import org.bigbluebutton.modules.chat.views.ChatWindow; + ]]> + </mx:Script> + + <EventHandlers type="{FlexEvent.PREINITIALIZE}"> + <ObjectBuilder generator="{ChatEventMapDelegate}" constructorArguments="{scope.dispatcher}"/> + </EventHandlers> + + <EventHandlers type="{StartChatModuleEvent.START_CHAT_MODULE_EVENT}"> + <MethodInvoker generator="{ChatEventMapDelegate}" method="openChatWindow" /> + <ObjectBuilder generator="{ChatMessageService}"/> + </EventHandlers> + + <EventHandlers type="{StopChatModuleEvent.STOP_CHAT_MODULE_EVENT}"> + <MethodInvoker generator="{ChatEventMapDelegate}" method="closeChatWindow" /> + </EventHandlers> + + <EventHandlers type="{EventConstants.SEND_PUBLIC_CHAT_REQ}"> + <MethodInvoker generator="{ChatMessageService}" method="sendPublicMessageFromApi" arguments="{event.message}"/> + </EventHandlers> + + <EventHandlers type="{EventConstants.SEND_PRIVATE_CHAT_REQ}"> + <MethodInvoker generator="{ChatMessageService}" method="sendPrivateMessageFromApi" arguments="{event.message}"/> + </EventHandlers> + + <EventHandlers type="{SendPublicChatMessageEvent.SEND_PUBLIC_CHAT_MESSAGE_EVENT}"> + <MethodInvoker generator="{ChatMessageService}" method="sendPublicMessage" arguments="{event.chatMessage}"/> + </EventHandlers> + + <EventHandlers type="{SendPrivateChatMessageEvent.SEND_PRIVATE_CHAT_MESSAGE_EVENT}"> + <MethodInvoker generator="{ChatMessageService}" method="sendPrivateMessage" arguments="{event.chatMessage}"/> + </EventHandlers> + + <EventHandlers type="{TranscriptEvent.LOAD_TRANSCRIPT}" > + <MethodInvoker generator="{ChatMessageService}" method="getPublicChatMessages"/> + </EventHandlers> + + <EventHandlers type="{TranscriptEvent.TRANSCRIPT_EVENT}" > + <MethodInvoker generator="{ChatMessageService}" method="sendWelcomeMessage"/> + </EventHandlers> + + <EventHandlers type="{ChatSaveEvent.SAVE_CHAT_EVENT}"> + <MethodInvoker generator="{ChatSaver}" method="saveChatToFile" arguments="{event}"/> + </EventHandlers> + + <EventHandlers type="{ChatCopyEvent.COPY_CHAT_EVENT}"> + <MethodInvoker generator="{ChatCopy}" method="copyAllText" arguments="{event}"/> + </EventHandlers> + + <Injectors target="{ChatMessageService}"> + <PropertyInjector targetKey="dispatcher" source="{scope.dispatcher}"/> + <PropertyInjector targetKey="receiver" source="{MessageReceiver}"/> + <PropertyInjector targetKey="sender" source="{MessageSender}"/> + </Injectors> + + <Injectors target="{MessageReceiver}"> + <PropertyInjector targetKey="dispatcher" source="{scope.dispatcher}"/> + </Injectors> + + <Injectors target="{MessageSender}"> + <PropertyInjector targetKey="dispatcher" source="{scope.dispatcher}"/> + </Injectors> + +</EventMap> diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AddChatTabBox.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AddChatTabBox.mxml index 21353a36eb..cf3d4f34d5 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AddChatTabBox.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AddChatTabBox.mxml @@ -27,7 +27,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. <mate:Listener type="{LockControlEvent.CHANGED_LOCK_SETTINGS}" method="lockSettingsChanged" /> <mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="refreshRole" /> - + <mx:Script> <![CDATA[ import com.asfusion.mate.events.Dispatcher; diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatView.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatView.mxml index 87bc8ec6a5..db0c333296 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatView.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatView.mxml @@ -27,7 +27,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. xmlns:flexlib="http://code.google.com/p/flexlib/" width="100%" height="100%" xmlns:containers="flexlib.containers.*" verticalScrollPolicy="off"> - + <mate:Listener type="{PrivateChatMessageEvent.PRIVATE_CHAT_MESSAGE_EVENT}" method="handlePrivateChatMessageEvent"/> <mate:Listener type="{PublicChatMessageEvent.PUBLIC_CHAT_MESSAGE_EVENT}" method="handlePublicChatMessageEvent"/> <mate:Listener type="{EventConstants.START_PRIVATE_CHAT}" method="handleStartPrivateChatMessageEvent"/> @@ -90,7 +90,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. private static const PUBLIC_TAB_NEW:String = ResourceUtil.getInstance().getString("bbb.accessibility.chat.chatView.publicTabNew"); private var publicWaiting:Boolean = false; - private var publicFocus:Boolean = false; + private var publicFocus:Boolean = false; private var noticeLabel:String; [Embed(source="../sounds/notice.mp3")] @@ -98,7 +98,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. private var noticeSound:Sound = new noticeSoundClass() as Sound; // All author and license information for the use of this sound can be found in: // src/org/bigbluebutton/modules/chat/sounds/license.txt - + // Initialization private function init():void { chatOptions = new ChatOptions(); @@ -107,7 +107,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. baseIndex = chatOptions.getBaseIndex() + 4; } - + private function onCreationComplete():void{ openChatBoxFor(PUBLIC_CHAT_USERID, true); makePublicChatUncloseable(); @@ -341,7 +341,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. // Activates an audio alert for screen-reader users on public message reception - private function publicNotification():void { + private function publicNotification():void { publicWaiting = true; if (Accessibility.active){ noticeSound.play(); @@ -359,7 +359,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. } } - public function publicChatFocus(event:FocusEvent):void{ + public function publicChatFocus(event:FocusEvent):void{ publicFocus = true; publicWaiting = false; } diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/events/UploadEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/events/UploadEvent.as old mode 100644 new mode 100755 diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/managers/PresentManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/managers/PresentManager.as index 2af363e4fe..d34439227d 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/managers/PresentManager.as +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/managers/PresentManager.as @@ -68,8 +68,8 @@ package org.bigbluebutton.modules.present.managers private function openWindow(window:IBbbModuleWindow):void{ var event:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT); - event.window = window; - globalDispatcher.dispatchEvent(event); + event.window = window; + globalDispatcher.dispatchEvent(event); } public function handleOpenUploadWindow(e:UploadEvent):void{ diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/business/VideoProxy.as b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/business/VideoProxy.as index 7033929c21..50ea8fdd25 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/business/VideoProxy.as +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/business/VideoProxy.as @@ -1,382 +1,382 @@ -/** -* 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.modules.videoconf.business -{ - import com.asfusion.mate.events.Dispatcher; - - import flash.events.AsyncErrorEvent; - import flash.events.IOErrorEvent; - import flash.events.NetStatusEvent; - import flash.events.SecurityErrorEvent; - import flash.media.H264Level; - import flash.media.H264Profile; - import flash.media.H264VideoStreamSettings; - import flash.net.NetConnection; - import flash.net.NetStream; - import flash.system.Capabilities; - import flash.utils.Dictionary; - - import mx.collections.ArrayCollection; - - import org.bigbluebutton.common.LogUtil; - import org.bigbluebutton.core.BBB; - import org.bigbluebutton.core.UsersUtil; - import org.bigbluebutton.core.managers.UserManager; - import org.bigbluebutton.modules.videoconf.events.ConnectedEvent; - import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent; - import org.bigbluebutton.modules.videoconf.model.VideoConfOptions; - import org.bigbluebutton.modules.videoconf.events.PlayConnectionReady; - import org.bigbluebutton.modules.videoconf.services.messaging.MessageSender; - import org.bigbluebutton.modules.videoconf.services.messaging.MessageReceiver; - import org.bigbluebutton.modules.videoconf.events.PlayConnectionClosedEvent; - - - public class VideoProxy - { - public var videoOptions:VideoConfOptions; - - // NetConnection used for stream publishing - private var nc:NetConnection; - // NetStream used for stream publishing - private var ns:NetStream; - private var _url:String; - private var camerasPublishing:Object = new Object(); - private var connected:Boolean = false; - - // Message sender to request stream path - private var msgSender:MessageSender; - // Message receiver to receive the stream path - private var msgReceiver:MessageReceiver; - - // Dictionary<url,NetConnection> used for stream playing - private var playConnectionDict:Dictionary; - // Dictionary<url,Array<streamName>> used to keep track of streams using a URL - private var urlStreamsDict:Dictionary; - // Dictionary<streamName,streamNamePrefix> used for stream playing - private var streamNamePrefixDict:Dictionary; - // Dictionary<streamName,url> - private var streamUrlDict:Dictionary; - - private function parseOptions():void { - videoOptions = new VideoConfOptions(); - videoOptions.parseOptions(); - } - - public function VideoProxy(url:String) - { - _url = url; - parseOptions(); - nc = new NetConnection(); - nc.proxyType = "best"; - nc.client = this; - nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError); - nc.addEventListener(IOErrorEvent.IO_ERROR, onIOError); - nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); - nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError); - playConnectionDict = new Dictionary(); - urlStreamsDict = new Dictionary(); - streamNamePrefixDict = new Dictionary(); - streamUrlDict = new Dictionary(); - msgReceiver = new MessageReceiver(this); - msgSender = new MessageSender(); - } - - public function connect():void { - nc.connect(_url, UsersUtil.getInternalMeetingID(), UsersUtil.getMyUserID()); - playConnectionDict[_url] = nc; - urlStreamsDict[_url] = new Array(); - } - - private function onAsyncError(event:AsyncErrorEvent):void{ - } - - private function onIOError(event:NetStatusEvent):void{ - } - - private function onConnectedToVideoApp():void{ - var dispatcher:Dispatcher = new Dispatcher(); - dispatcher.dispatchEvent(new ConnectedEvent(ConnectedEvent.VIDEO_CONNECTED)); - } - - private function onNetStatus(event:NetStatusEvent):void{ - switch(event.info.code){ - case "NetConnection.Connect.Success": - connected = true; - //ns = new NetStream(nc); - onConnectedToVideoApp(); - break; - default: - LogUtil.debug("[" + event.info.code + "] for [" + _url + "]"); - connected = false; - break; - } - } - - private function onSecurityError(event:NetStatusEvent):void{ - } - - public function get publishConnection():NetConnection{ - return this.nc; - } - - private function onPlayNetStatus(event:NetStatusEvent):void { - var url:String = event.target.uri; - var streams:Array = urlStreamsDict[url]; - var dispatcher:Dispatcher = new Dispatcher(); - var prefix:String; - var stream:String; - switch(event.info.code){ - case "NetConnection.Connect.Success": - // Notify streams from this connection - var conn:NetConnection = playConnectionDict[url]; - for each (stream in streams) { - prefix = streamNamePrefixDict[stream]; - dispatcher.dispatchEvent(new PlayConnectionReady(stream, conn, prefix)); - } - break; - case "NetConnection.Connect.Failed": - case "NetConnection.Connect.Closed": - trace("[" + event.info.code + "] for a play connection at [" + url + "]"); - trace("Affected streams: ["+streams+"]"); - for each (stream in streams) { - prefix = streamNamePrefixDict[stream]; - delete streamNamePrefixDict[stream]; - delete streamUrlDict[stream]; - dispatcher.dispatchEvent(new PlayConnectionClosedEvent(stream, prefix)); - } - delete playConnectionDict[url]; - delete urlStreamsDict[url]; - break; - default: - LogUtil.debug("[" + event.info.code + "] for a play connection at [" + url + "]"); - break; - } - } - - public function createPlayConnectionFor(streamName:String):void { - LogUtil.debug("VideoProxy::createPlayConnectionFor:: Requesting path for stream [" + streamName + "]"); - // Check if a connection already exists - if(!streamUrlDict[streamName]) { - trace("VideoProxy::createPlayConnectionFor:: Requesting path for stream [" + streamName + "]"); - // Ask red5 the path to stream - msgSender.getStreamPath(streamName); - } - else { - trace("VideoProxy::createPlayConnectionFor:: Found connection for stream [" + streamName + "]"); - } - } - - public function handleStreamPathReceived(streamName:String, connectionPath:String):void { - trace("VideoProxy::handleStreamPathReceived:: Path for stream [" + streamName + "]: [" + connectionPath + "]"); - - var newUrl:String; - var streamPrefix:String; - - // Check whether the is through proxy servers or not - if(connectionPath == "") { - newUrl = _url; - streamPrefix = ""; - } - else { - var ipRegex:RegExp = /([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/; - var serverIp:String = connectionPath.split("/")[0]; - newUrl = _url.replace(ipRegex, serverIp); - streamPrefix = connectionPath.replace(serverIp, ""); - } - - if(streamPrefix != "") - streamPrefix = streamPrefix + "/"; - - // Store URL for this stream - streamUrlDict[streamName] = newUrl; - - // Set current streamPrefix to use the current path - streamNamePrefixDict[streamName] = streamPrefix; - - if(urlStreamsDict[newUrl] == null) { - urlStreamsDict[newUrl] = new Array(); - urlStreamsDict[streamPrefix+streamName] = urlStreamsDict[newUrl]; - } - urlStreamsDict[newUrl].push(streamName); - - // If connection with this URL does not exist - if(!playConnectionDict[newUrl]){ - // Create new NetConnection and store it - var connection:NetConnection = new NetConnection(); - connection.client = this; - connection.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError); - connection.addEventListener(IOErrorEvent.IO_ERROR, onIOError); - connection.addEventListener(NetStatusEvent.NET_STATUS, onPlayNetStatus); - connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError); - connection.connect(newUrl, UsersUtil.getInternalMeetingID(), UsersUtil.getMyUserID()); - trace("VideoProxy::handleStreamPathReceived:: Creating NetConnection for [" + newUrl + "]"); - playConnectionDict[newUrl] = connection; - } - else { - if(playConnectionDict[newUrl].connected) { - // Connection is ready, send event - var dispatcher:Dispatcher = new Dispatcher(); - dispatcher.dispatchEvent(new PlayConnectionReady(streamName, playConnectionDict[newUrl], streamPrefix)); - } - trace("VideoProxy::handleStreamPathReceived:: Found NetConnection for [" + newUrl + "]"); - } - } - - public function getConnectionForStream(stream:String):NetConnection { - var url:String = streamUrlDict[stream]; - return playConnectionDict[url]; - } - - public function getPrefixForStream(stream:String):String { - if(streamNamePrefixDict[stream]) - return streamNamePrefixDict[stream]; - else - return ""; - } - - public function closePlayConnectionFor(streamName:String):void { - var temp:Array = streamName.split("/"); - var stream:String = temp[temp.length-1]; - var streamUrl:String = streamUrlDict[stream]; - - // Remove the url entry for this stream - delete streamUrlDict[stream]; - - // Check if the connection should be closed - var streams:Array = urlStreamsDict[streamUrl]; - if(streams != null) { - streams = streams.filter(function(item:*, index:int, array:Array):Boolean { return item != stream }); - urlStreamsDict[streamUrl] = streams; - } - // Do not close publish connection, no matter what - if(playConnectionDict[streamUrl] == nc) - return; - if(streams == null || streams.length <= 0) { - trace("VideoProxy:: closePlayConnectionFor:: Closing connection with: [" + streamUrl + "]"); - // No one else is using this NetConnection - var connection:NetConnection = playConnectionDict[streamUrl]; - if(connection != null) connection.close(); - delete playConnectionDict[streamUrl]; - delete urlStreamsDict[streamUrl]; - } - else { - trace("VideoProxy:: closePlayConnectionFor:: Connection with: [" + streamUrl + "] has [" + streams.length + "] streams"); - } - } - - public function startPublishing(e:StartBroadcastEvent):void{ - var ns:NetStream = new NetStream(nc); - ns.addEventListener( NetStatusEvent.NET_STATUS, onNetStatus ); - ns.addEventListener( IOErrorEvent.IO_ERROR, onIOError ); - ns.addEventListener( AsyncErrorEvent.ASYNC_ERROR, onAsyncError ); - ns.client = this; - ns.attachCamera(e.camera); -// Uncomment if you want to build support for H264. But you need at least FP 11. (ralam july 23, 2011) -// if (Capabilities.version.search("11,0") != -1) { - if ((BBB.getFlashPlayerVersion() >= 11) && e.videoProfile.enableH264) { -// if (BBB.getFlashPlayerVersion() >= 11) { - LogUtil.info("Using H264 codec for video."); - var h264:H264VideoStreamSettings = new H264VideoStreamSettings(); - var h264profile:String = H264Profile.MAIN; - if (e.videoProfile.h264Profile != "main") { - h264profile = H264Profile.BASELINE; - } - var h264Level:String = H264Level.LEVEL_4_1; - switch (e.videoProfile.h264Level) { - case "1": h264Level = H264Level.LEVEL_1; break; - case "1.1": h264Level = H264Level.LEVEL_1_1; break; - case "1.2": h264Level = H264Level.LEVEL_1_2; break; - case "1.3": h264Level = H264Level.LEVEL_1_3; break; - case "1b": h264Level = H264Level.LEVEL_1B; break; - case "2": h264Level = H264Level.LEVEL_2; break; - case "2.1": h264Level = H264Level.LEVEL_2_1; break; - case "2.2": h264Level = H264Level.LEVEL_2_2; break; - case "3": h264Level = H264Level.LEVEL_3; break; - case "3.1": h264Level = H264Level.LEVEL_3_1; break; - case "3.2": h264Level = H264Level.LEVEL_3_2; break; - case "4": h264Level = H264Level.LEVEL_4; break; - case "4.1": h264Level = H264Level.LEVEL_4_1; break; - case "4.2": h264Level = H264Level.LEVEL_4_2; break; - case "5": h264Level = H264Level.LEVEL_5; break; - case "5.1": h264Level = H264Level.LEVEL_5_1; break; - } - - LogUtil.info("Codec used: " + h264Level); - - h264.setProfileLevel(h264profile, h264Level); - ns.videoStreamSettings = h264; - } - - ns.publish(e.stream); - camerasPublishing[e.stream] = ns; - } - - public function stopBroadcasting(stream:String):void{ - trace("Closing netstream for webcam publishing"); - if (camerasPublishing[stream] != null) { - var ns:NetStream = camerasPublishing[stream]; - ns.attachCamera(null); - ns.close(); - ns = null; - delete camerasPublishing[stream]; - } - } - - public function stopAllBroadcasting():void { - for each (var ns:NetStream in camerasPublishing) - { - ns.attachCamera(null); - ns.close(); - ns = null; - } - camerasPublishing = new Object(); - } - - public function disconnect():void { - trace("VideoProxy:: disconnecting from Video application"); - stopAllBroadcasting(); - // Close publish NetConnection - if (nc != null) nc.close(); - // Close play NetConnections - for (var k:Object in playConnectionDict) { - var connection:NetConnection = playConnectionDict[k]; - connection.close(); - } - // Reset dictionaries - playConnectionDict = new Dictionary(); - streamNamePrefixDict = new Dictionary(); - urlStreamsDict = new Dictionary(); - streamUrlDict = new Dictionary(); - } - - public function onBWCheck(... rest):Number { - return 0; - } - - public function onBWDone(... rest):void { - var p_bw:Number; - if (rest.length > 0) p_bw = rest[0]; - // your application should do something here - // when the bandwidth check is complete - trace("bandwidth = " + p_bw + " Kbps."); - } - - - } -} +/** +* 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.modules.videoconf.business +{ + import com.asfusion.mate.events.Dispatcher; + + import flash.events.AsyncErrorEvent; + import flash.events.IOErrorEvent; + import flash.events.NetStatusEvent; + import flash.events.SecurityErrorEvent; + import flash.media.H264Level; + import flash.media.H264Profile; + import flash.media.H264VideoStreamSettings; + import flash.net.NetConnection; + import flash.net.NetStream; + import flash.system.Capabilities; + import flash.utils.Dictionary; + + import mx.collections.ArrayCollection; + + import org.bigbluebutton.common.LogUtil; + import org.bigbluebutton.core.BBB; + import org.bigbluebutton.core.UsersUtil; + import org.bigbluebutton.core.managers.UserManager; + import org.bigbluebutton.modules.videoconf.events.ConnectedEvent; + import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent; + import org.bigbluebutton.modules.videoconf.model.VideoConfOptions; + import org.bigbluebutton.modules.videoconf.events.PlayConnectionReady; + import org.bigbluebutton.modules.videoconf.services.messaging.MessageSender; + import org.bigbluebutton.modules.videoconf.services.messaging.MessageReceiver; + import org.bigbluebutton.modules.videoconf.events.PlayConnectionClosedEvent; + + + public class VideoProxy + { + public var videoOptions:VideoConfOptions; + + // NetConnection used for stream publishing + private var nc:NetConnection; + // NetStream used for stream publishing + private var ns:NetStream; + private var _url:String; + private var camerasPublishing:Object = new Object(); + private var connected:Boolean = false; + + // Message sender to request stream path + private var msgSender:MessageSender; + // Message receiver to receive the stream path + private var msgReceiver:MessageReceiver; + + // Dictionary<url,NetConnection> used for stream playing + private var playConnectionDict:Dictionary; + // Dictionary<url,Array<streamName>> used to keep track of streams using a URL + private var urlStreamsDict:Dictionary; + // Dictionary<streamName,streamNamePrefix> used for stream playing + private var streamNamePrefixDict:Dictionary; + // Dictionary<streamName,url> + private var streamUrlDict:Dictionary; + + private function parseOptions():void { + videoOptions = new VideoConfOptions(); + videoOptions.parseOptions(); + } + + public function VideoProxy(url:String) + { + _url = url; + parseOptions(); + nc = new NetConnection(); + nc.proxyType = "best"; + nc.client = this; + nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError); + nc.addEventListener(IOErrorEvent.IO_ERROR, onIOError); + nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); + nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError); + playConnectionDict = new Dictionary(); + urlStreamsDict = new Dictionary(); + streamNamePrefixDict = new Dictionary(); + streamUrlDict = new Dictionary(); + msgReceiver = new MessageReceiver(this); + msgSender = new MessageSender(); + } + + public function connect():void { + nc.connect(_url, UsersUtil.getInternalMeetingID(), UsersUtil.getMyUserID()); + playConnectionDict[_url] = nc; + urlStreamsDict[_url] = new Array(); + } + + private function onAsyncError(event:AsyncErrorEvent):void{ + } + + private function onIOError(event:NetStatusEvent):void{ + } + + private function onConnectedToVideoApp():void{ + var dispatcher:Dispatcher = new Dispatcher(); + dispatcher.dispatchEvent(new ConnectedEvent(ConnectedEvent.VIDEO_CONNECTED)); + } + + private function onNetStatus(event:NetStatusEvent):void{ + switch(event.info.code){ + case "NetConnection.Connect.Success": + connected = true; + //ns = new NetStream(nc); + onConnectedToVideoApp(); + break; + default: + LogUtil.debug("[" + event.info.code + "] for [" + _url + "]"); + connected = false; + break; + } + } + + private function onSecurityError(event:NetStatusEvent):void{ + } + + public function get publishConnection():NetConnection{ + return this.nc; + } + + private function onPlayNetStatus(event:NetStatusEvent):void { + var url:String = event.target.uri; + var streams:Array = urlStreamsDict[url]; + var dispatcher:Dispatcher = new Dispatcher(); + var prefix:String; + var stream:String; + switch(event.info.code){ + case "NetConnection.Connect.Success": + // Notify streams from this connection + var conn:NetConnection = playConnectionDict[url]; + for each (stream in streams) { + prefix = streamNamePrefixDict[stream]; + dispatcher.dispatchEvent(new PlayConnectionReady(stream, conn, prefix)); + } + break; + case "NetConnection.Connect.Failed": + case "NetConnection.Connect.Closed": + trace("[" + event.info.code + "] for a play connection at [" + url + "]"); + trace("Affected streams: ["+streams+"]"); + for each (stream in streams) { + prefix = streamNamePrefixDict[stream]; + delete streamNamePrefixDict[stream]; + delete streamUrlDict[stream]; + dispatcher.dispatchEvent(new PlayConnectionClosedEvent(stream, prefix)); + } + delete playConnectionDict[url]; + delete urlStreamsDict[url]; + break; + default: + LogUtil.debug("[" + event.info.code + "] for a play connection at [" + url + "]"); + break; + } + } + + public function createPlayConnectionFor(streamName:String):void { + LogUtil.debug("VideoProxy::createPlayConnectionFor:: Requesting path for stream [" + streamName + "]"); + // Check if a connection already exists + if(!streamUrlDict[streamName]) { + trace("VideoProxy::createPlayConnectionFor:: Requesting path for stream [" + streamName + "]"); + // Ask red5 the path to stream + msgSender.getStreamPath(streamName); + } + else { + trace("VideoProxy::createPlayConnectionFor:: Found connection for stream [" + streamName + "]"); + } + } + + public function handleStreamPathReceived(streamName:String, connectionPath:String):void { + trace("VideoProxy::handleStreamPathReceived:: Path for stream [" + streamName + "]: [" + connectionPath + "]"); + + var newUrl:String; + var streamPrefix:String; + + // Check whether the is through proxy servers or not + if(connectionPath == "") { + newUrl = _url; + streamPrefix = ""; + } + else { + var ipRegex:RegExp = /([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/; + var serverIp:String = connectionPath.split("/")[0]; + newUrl = _url.replace(ipRegex, serverIp); + streamPrefix = connectionPath.replace(serverIp, ""); + } + + if(streamPrefix != "") + streamPrefix = streamPrefix + "/"; + + // Store URL for this stream + streamUrlDict[streamName] = newUrl; + + // Set current streamPrefix to use the current path + streamNamePrefixDict[streamName] = streamPrefix; + + if(urlStreamsDict[newUrl] == null) { + urlStreamsDict[newUrl] = new Array(); + urlStreamsDict[streamPrefix+streamName] = urlStreamsDict[newUrl]; + } + urlStreamsDict[newUrl].push(streamName); + + // If connection with this URL does not exist + if(!playConnectionDict[newUrl]){ + // Create new NetConnection and store it + var connection:NetConnection = new NetConnection(); + connection.client = this; + connection.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError); + connection.addEventListener(IOErrorEvent.IO_ERROR, onIOError); + connection.addEventListener(NetStatusEvent.NET_STATUS, onPlayNetStatus); + connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError); + connection.connect(newUrl, UsersUtil.getInternalMeetingID(), UsersUtil.getMyUserID()); + trace("VideoProxy::handleStreamPathReceived:: Creating NetConnection for [" + newUrl + "]"); + playConnectionDict[newUrl] = connection; + } + else { + if(playConnectionDict[newUrl].connected) { + // Connection is ready, send event + var dispatcher:Dispatcher = new Dispatcher(); + dispatcher.dispatchEvent(new PlayConnectionReady(streamName, playConnectionDict[newUrl], streamPrefix)); + } + trace("VideoProxy::handleStreamPathReceived:: Found NetConnection for [" + newUrl + "]"); + } + } + + public function getConnectionForStream(stream:String):NetConnection { + var url:String = streamUrlDict[stream]; + return playConnectionDict[url]; + } + + public function getPrefixForStream(stream:String):String { + if(streamNamePrefixDict[stream]) + return streamNamePrefixDict[stream]; + else + return ""; + } + + public function closePlayConnectionFor(streamName:String):void { + var temp:Array = streamName.split("/"); + var stream:String = temp[temp.length-1]; + var streamUrl:String = streamUrlDict[stream]; + + // Remove the url entry for this stream + delete streamUrlDict[stream]; + + // Check if the connection should be closed + var streams:Array = urlStreamsDict[streamUrl]; + if(streams != null) { + streams = streams.filter(function(item:*, index:int, array:Array):Boolean { return item != stream }); + urlStreamsDict[streamUrl] = streams; + } + // Do not close publish connection, no matter what + if(playConnectionDict[streamUrl] == nc) + return; + if(streams == null || streams.length <= 0) { + trace("VideoProxy:: closePlayConnectionFor:: Closing connection with: [" + streamUrl + "]"); + // No one else is using this NetConnection + var connection:NetConnection = playConnectionDict[streamUrl]; + if(connection != null) connection.close(); + delete playConnectionDict[streamUrl]; + delete urlStreamsDict[streamUrl]; + } + else { + trace("VideoProxy:: closePlayConnectionFor:: Connection with: [" + streamUrl + "] has [" + streams.length + "] streams"); + } + } + + public function startPublishing(e:StartBroadcastEvent):void{ + var ns:NetStream = new NetStream(nc); + ns.addEventListener( NetStatusEvent.NET_STATUS, onNetStatus ); + ns.addEventListener( IOErrorEvent.IO_ERROR, onIOError ); + ns.addEventListener( AsyncErrorEvent.ASYNC_ERROR, onAsyncError ); + ns.client = this; + ns.attachCamera(e.camera); +// Uncomment if you want to build support for H264. But you need at least FP 11. (ralam july 23, 2011) +// if (Capabilities.version.search("11,0") != -1) { + if ((BBB.getFlashPlayerVersion() >= 11) && e.videoProfile.enableH264) { +// if (BBB.getFlashPlayerVersion() >= 11) { + LogUtil.info("Using H264 codec for video."); + var h264:H264VideoStreamSettings = new H264VideoStreamSettings(); + var h264profile:String = H264Profile.MAIN; + if (e.videoProfile.h264Profile != "main") { + h264profile = H264Profile.BASELINE; + } + var h264Level:String = H264Level.LEVEL_4_1; + switch (e.videoProfile.h264Level) { + case "1": h264Level = H264Level.LEVEL_1; break; + case "1.1": h264Level = H264Level.LEVEL_1_1; break; + case "1.2": h264Level = H264Level.LEVEL_1_2; break; + case "1.3": h264Level = H264Level.LEVEL_1_3; break; + case "1b": h264Level = H264Level.LEVEL_1B; break; + case "2": h264Level = H264Level.LEVEL_2; break; + case "2.1": h264Level = H264Level.LEVEL_2_1; break; + case "2.2": h264Level = H264Level.LEVEL_2_2; break; + case "3": h264Level = H264Level.LEVEL_3; break; + case "3.1": h264Level = H264Level.LEVEL_3_1; break; + case "3.2": h264Level = H264Level.LEVEL_3_2; break; + case "4": h264Level = H264Level.LEVEL_4; break; + case "4.1": h264Level = H264Level.LEVEL_4_1; break; + case "4.2": h264Level = H264Level.LEVEL_4_2; break; + case "5": h264Level = H264Level.LEVEL_5; break; + case "5.1": h264Level = H264Level.LEVEL_5_1; break; + } + + LogUtil.info("Codec used: " + h264Level); + + h264.setProfileLevel(h264profile, h264Level); + ns.videoStreamSettings = h264; + } + + ns.publish(e.stream); + camerasPublishing[e.stream] = ns; + } + + public function stopBroadcasting(stream:String):void{ + trace("Closing netstream for webcam publishing"); + if (camerasPublishing[stream] != null) { + var ns:NetStream = camerasPublishing[stream]; + ns.attachCamera(null); + ns.close(); + ns = null; + delete camerasPublishing[stream]; + } + } + + public function stopAllBroadcasting():void { + for each (var ns:NetStream in camerasPublishing) + { + ns.attachCamera(null); + ns.close(); + ns = null; + } + camerasPublishing = new Object(); + } + + public function disconnect():void { + trace("VideoProxy:: disconnecting from Video application"); + stopAllBroadcasting(); + // Close publish NetConnection + if (nc != null) nc.close(); + // Close play NetConnections + for (var k:Object in playConnectionDict) { + var connection:NetConnection = playConnectionDict[k]; + connection.close(); + } + // Reset dictionaries + playConnectionDict = new Dictionary(); + streamNamePrefixDict = new Dictionary(); + urlStreamsDict = new Dictionary(); + streamUrlDict = new Dictionary(); + } + + public function onBWCheck(... rest):Number { + return 0; + } + + public function onBWDone(... rest):void { + var p_bw:Number; + if (rest.length > 0) p_bw = rest[0]; + // your application should do something here + // when the bandwidth check is complete + trace("bandwidth = " + p_bw + " Kbps."); + } + + + } +} diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/maps/VideoEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/maps/VideoEventMap.mxml index 3e5f8d31ea..62f23acc6c 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/maps/VideoEventMap.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/maps/VideoEventMap.mxml @@ -1,144 +1,144 @@ -<?xml version="1.0" encoding="utf-8"?> - -<!-- - -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/>. - ---> - -<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.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; - import org.bigbluebutton.modules.videoconf.events.PlayConnectionReady; - import org.bigbluebutton.modules.videoconf.events.PlayConnectionClosedEvent; - ]]> - </mx:Script> - - <EventHandlers type="{VideoModuleStartEvent.START}"> - <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/> - <MethodInvoker generator="{VideoEventMapDelegate}" method="start" arguments="{event.uri}"/> - <EventAnnouncer generator="{ConnectAppEvent}" type="{ConnectAppEvent.CONNECT_VIDEO_APP}" /> - </EventHandlers> - - <EventHandlers type="{VideoModuleStopEvent.STOP}"> - <MethodInvoker generator="{VideoEventMapDelegate}" method="stopModule"/> - </EventHandlers> - - <EventHandlers type="{BBBEvent.CAMERA_SETTING}" > - <MethodInvoker generator="{VideoEventMapDelegate}" method="handleCameraSetting" arguments="{event}"/> - </EventHandlers> - - <EventHandlers type="{ConnectAppEvent.CONNECT_VIDEO_APP}"> - <MethodInvoker generator="{VideoEventMapDelegate}" method="connectToVideoApp" /> - </EventHandlers> - - <EventHandlers type="{ShareCameraRequestEvent.SHARE_CAMERA_REQUEST}"> - <MethodInvoker generator="{VideoEventMapDelegate}" method="handleShareCameraRequestEvent" arguments="{event}"/> - </EventHandlers> - - <EventHandlers type="{StopShareCameraRequestEvent.STOP_SHARE_CAMERA_REQUEST}"> - <MethodInvoker generator="{VideoEventMapDelegate}" method="handleStopShareCameraRequestEvent" arguments="{event}"/> - </EventHandlers> - - <EventHandlers type="{StopShareCameraRequestEvent.STOP_SHARE_ALL_CAMERA_REQUEST}"> - <MethodInvoker generator="{VideoEventMapDelegate}" method="handleStopAllShareCameraRequestEvent" arguments="{event}"/> - </EventHandlers> - - <EventHandlers type="{StartBroadcastEvent.START_BROADCAST}" > - <MethodInvoker generator="{VideoEventMapDelegate}" method="startPublishing" arguments="{event}" /> - </EventHandlers> - - <EventHandlers type="{StopBroadcastEvent.STOP_BROADCASTING}" > - <MethodInvoker generator="{VideoEventMapDelegate}" method="stopPublishing" arguments="{event}" /> - </EventHandlers> - - <EventHandlers type="{StreamStartedEvent.STREAM_STARTED}"> - <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/> - <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.userID, event.stream]}" /> - </EventHandlers> - - <EventHandlers type="{ViewCameraEvent.VIEW_CAMERA_EVENT}"> - <MethodInvoker generator="{VideoEventMapDelegate}" method="viewCamera" arguments="{[event.userID, event.stream, event.viewedName]}" /> - </EventHandlers> - - <EventHandlers type="{UserJoinedEvent.JOINED}"> - <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/> - <MethodInvoker generator="{VideoEventMapDelegate}" method="handleUserJoinedEvent" arguments="{event}" /> - </EventHandlers> - - <EventHandlers type="{UserLeftEvent.LEFT}"> - <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/> - <MethodInvoker generator="{VideoEventMapDelegate}" method="handleUserLeftEvent" arguments="{event}" /> - </EventHandlers> - - <EventHandlers type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}" > - <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/> - <MethodInvoker generator="{VideoEventMapDelegate}" method="switchToPresenter" arguments="{event}"/> - </EventHandlers> - - <EventHandlers type="{MadePresenterEvent.SWITCH_TO_VIEWER_MODE}"> - <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/> - <MethodInvoker generator="{VideoEventMapDelegate}" method="switchToViewer" arguments="{event}"/> - </EventHandlers> - - <EventHandlers type="{ConnectedEvent.VIDEO_CONNECTED}"> - <MethodInvoker generator="{VideoEventMapDelegate}" method="connectedToVideoApp" /> - </EventHandlers> - - <EventHandlers type="{ClosePublishWindowEvent.CLOSE_PUBLISH_WINDOW}"> - <MethodInvoker generator="{VideoEventMapDelegate}" method="handleClosePublishWindowEvent" arguments="{event}"/> - </EventHandlers> - - <EventHandlers type="{StoppedViewingWebcamEvent.STOPPED_VIEWING_WEBCAM}"> - <MethodInvoker generator="{VideoEventMapDelegate}" method="handleStoppedViewingWebcamEvent" arguments="{[event.webcamUserID, event.streamName]}"/> - </EventHandlers> - - <EventHandlers type="{BBBEvent.CAM_SETTINGS_CLOSED}"> - <MethodInvoker generator="{VideoEventMapDelegate}" method="handleCamSettingsClosedEvent" arguments="{event}"/> - </EventHandlers> - - <EventHandlers type="{PlayConnectionReady.PLAY_CONNECTION_READY}"> - <MethodInvoker generator="{VideoEventMapDelegate}" method="handlePlayConnectionReady" arguments="{event}" /> - </EventHandlers> - - <EventHandlers type="{PlayConnectionClosedEvent.PLAY_CONNECTION_CLOSED_EVENT}"> - <MethodInvoker generator="{VideoEventMapDelegate}" method="handlePlayConnectionClosed" arguments="{[event.streamName, event.prefix]}" /> - </EventHandlers> - <!-- ~~~~~~~~~~~~~~~~~~ INJECTORS ~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> - -</EventMap> +<?xml version="1.0" encoding="utf-8"?> + +<!-- + +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/>. + +--> + +<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.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; + import org.bigbluebutton.modules.videoconf.events.PlayConnectionReady; + import org.bigbluebutton.modules.videoconf.events.PlayConnectionClosedEvent; + ]]> + </mx:Script> + + <EventHandlers type="{VideoModuleStartEvent.START}"> + <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/> + <MethodInvoker generator="{VideoEventMapDelegate}" method="start" arguments="{event.uri}"/> + <EventAnnouncer generator="{ConnectAppEvent}" type="{ConnectAppEvent.CONNECT_VIDEO_APP}" /> + </EventHandlers> + + <EventHandlers type="{VideoModuleStopEvent.STOP}"> + <MethodInvoker generator="{VideoEventMapDelegate}" method="stopModule"/> + </EventHandlers> + + <EventHandlers type="{BBBEvent.CAMERA_SETTING}" > + <MethodInvoker generator="{VideoEventMapDelegate}" method="handleCameraSetting" arguments="{event}"/> + </EventHandlers> + + <EventHandlers type="{ConnectAppEvent.CONNECT_VIDEO_APP}"> + <MethodInvoker generator="{VideoEventMapDelegate}" method="connectToVideoApp" /> + </EventHandlers> + + <EventHandlers type="{ShareCameraRequestEvent.SHARE_CAMERA_REQUEST}"> + <MethodInvoker generator="{VideoEventMapDelegate}" method="handleShareCameraRequestEvent" arguments="{event}"/> + </EventHandlers> + + <EventHandlers type="{StopShareCameraRequestEvent.STOP_SHARE_CAMERA_REQUEST}"> + <MethodInvoker generator="{VideoEventMapDelegate}" method="handleStopShareCameraRequestEvent" arguments="{event}"/> + </EventHandlers> + + <EventHandlers type="{StopShareCameraRequestEvent.STOP_SHARE_ALL_CAMERA_REQUEST}"> + <MethodInvoker generator="{VideoEventMapDelegate}" method="handleStopAllShareCameraRequestEvent" arguments="{event}"/> + </EventHandlers> + + <EventHandlers type="{StartBroadcastEvent.START_BROADCAST}" > + <MethodInvoker generator="{VideoEventMapDelegate}" method="startPublishing" arguments="{event}" /> + </EventHandlers> + + <EventHandlers type="{StopBroadcastEvent.STOP_BROADCASTING}" > + <MethodInvoker generator="{VideoEventMapDelegate}" method="stopPublishing" arguments="{event}" /> + </EventHandlers> + + <EventHandlers type="{StreamStartedEvent.STREAM_STARTED}"> + <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/> + <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.userID, event.stream]}" /> + </EventHandlers> + + <EventHandlers type="{ViewCameraEvent.VIEW_CAMERA_EVENT}"> + <MethodInvoker generator="{VideoEventMapDelegate}" method="viewCamera" arguments="{[event.userID, event.stream, event.viewedName]}" /> + </EventHandlers> + + <EventHandlers type="{UserJoinedEvent.JOINED}"> + <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/> + <MethodInvoker generator="{VideoEventMapDelegate}" method="handleUserJoinedEvent" arguments="{event}" /> + </EventHandlers> + + <EventHandlers type="{UserLeftEvent.LEFT}"> + <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/> + <MethodInvoker generator="{VideoEventMapDelegate}" method="handleUserLeftEvent" arguments="{event}" /> + </EventHandlers> + + <EventHandlers type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}" > + <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/> + <MethodInvoker generator="{VideoEventMapDelegate}" method="switchToPresenter" arguments="{event}"/> + </EventHandlers> + + <EventHandlers type="{MadePresenterEvent.SWITCH_TO_VIEWER_MODE}"> + <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/> + <MethodInvoker generator="{VideoEventMapDelegate}" method="switchToViewer" arguments="{event}"/> + </EventHandlers> + + <EventHandlers type="{ConnectedEvent.VIDEO_CONNECTED}"> + <MethodInvoker generator="{VideoEventMapDelegate}" method="connectedToVideoApp" /> + </EventHandlers> + + <EventHandlers type="{ClosePublishWindowEvent.CLOSE_PUBLISH_WINDOW}"> + <MethodInvoker generator="{VideoEventMapDelegate}" method="handleClosePublishWindowEvent" arguments="{event}"/> + </EventHandlers> + + <EventHandlers type="{StoppedViewingWebcamEvent.STOPPED_VIEWING_WEBCAM}"> + <MethodInvoker generator="{VideoEventMapDelegate}" method="handleStoppedViewingWebcamEvent" arguments="{[event.webcamUserID, event.streamName]}"/> + </EventHandlers> + + <EventHandlers type="{BBBEvent.CAM_SETTINGS_CLOSED}"> + <MethodInvoker generator="{VideoEventMapDelegate}" method="handleCamSettingsClosedEvent" arguments="{event}"/> + </EventHandlers> + + <EventHandlers type="{PlayConnectionReady.PLAY_CONNECTION_READY}"> + <MethodInvoker generator="{VideoEventMapDelegate}" method="handlePlayConnectionReady" arguments="{event}" /> + </EventHandlers> + + <EventHandlers type="{PlayConnectionClosedEvent.PLAY_CONNECTION_CLOSED_EVENT}"> + <MethodInvoker generator="{VideoEventMapDelegate}" method="handlePlayConnectionClosed" arguments="{[event.streamName, event.prefix]}" /> + </EventHandlers> + <!-- ~~~~~~~~~~~~~~~~~~ INJECTORS ~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> + +</EventMap> diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/model/VideoConfOptions.as b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/model/VideoConfOptions.as index 2998091b91..52873d7eb6 100755 --- a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/model/VideoConfOptions.as +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/model/VideoConfOptions.as @@ -79,7 +79,8 @@ package org.bigbluebutton.modules.videoconf.model [Bindable] public var glowBlurSize:Number = 30.0; - [Bindable] + + [Bindable] public var priorityRatio:Number = 2/3; public function VideoConfOptions() { @@ -165,7 +166,7 @@ package org.bigbluebutton.modules.videoconf.model glowBlurSize = Number(vxml.@glowBlurSize.toString()); } if (vxml.@priorityRatio != undefined) { - priorityRatio = Number(vxml.@priorityRatio.toString()); + priorityRatio = Number(vxml.@priorityRatio.toString()); } } } diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/AvatarWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/AvatarWindow.mxml index 5e547d63b8..4214254a5f 100644 --- a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/AvatarWindow.mxml +++ b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/AvatarWindow.mxml @@ -36,39 +36,37 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. <mate:Listener type="{BBBEvent.USER_VOICE_MUTED}" method="handleUserVoiceMutedEvent" /> <mate:Listener type="{EventConstants.USER_TALKING}" method="handleUserTalkingEvent" /> - <mate:Listener type="{SwitchedPresenterEvent.SWITCHED_PRESENTER}" method="handleSwitchedPresenterEvent" /> - <mate:Listener type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}" method="handleMadePresenterEvent" /> - <mate:Listener type="{BBBEvent.USER_VOICE_JOINED}" method="handleNewRoleEvent" /> - <mate:Listener type="{BBBEvent.USER_VOICE_LEFT}" method="handleNewRoleEvent" /> + <mate:Listener type="{SwitchedPresenterEvent.SWITCHED_PRESENTER}" method="handleSwitchedPresenterEvent" /> + <mate:Listener type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}" method="handleMadePresenterEvent" /> + <mate:Listener type="{BBBEvent.USER_VOICE_JOINED}" method="handleNewRoleEvent" /> + <mate:Listener type="{BBBEvent.USER_VOICE_LEFT}" method="handleNewRoleEvent" /> <mate:Listener type="{CloseAllWindowsEvent.CLOSE_ALL_WINDOWS}" method="closeWindow" /> <mx:Script> <![CDATA[ - import flexlib.mdi.events.MDIWindowEvent; + import flexlib.mdi.events.MDIWindowEvent; - import mx.core.UIComponent; - import mx.events.ResizeEvent; - - import org.bigbluebutton.common.Images; - import org.bigbluebutton.common.LogUtil; - import org.bigbluebutton.common.Role; - import org.bigbluebutton.common.events.CloseWindowEvent; - import org.bigbluebutton.common.events.LocaleChangeEvent; - import org.bigbluebutton.core.EventConstants; - import org.bigbluebutton.core.UsersUtil; - import org.bigbluebutton.core.events.CoreEvent; - import org.bigbluebutton.core.events.SwitchedLayoutEvent; - import org.bigbluebutton.core.managers.UserManager; - import org.bigbluebutton.main.events.BBBEvent; - import org.bigbluebutton.main.events.MadePresenterEvent; - import org.bigbluebutton.main.events.SwitchedPresenterEvent; - import org.bigbluebutton.main.views.MainCanvas; - import org.bigbluebutton.modules.videoconf.business.TalkingButtonOverlay; - import org.bigbluebutton.modules.videoconf.events.CloseAllWindowsEvent; - import org.bigbluebutton.modules.videoconf.events.OpenVideoWindowEvent; - import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent; - import org.bigbluebutton.modules.videoconf.model.VideoConfOptions; - import org.bigbluebutton.util.i18n.ResourceUtil; + import mx.core.UIComponent; + import mx.events.ResizeEvent; + import org.bigbluebutton.common.Images; + import org.bigbluebutton.common.LogUtil; + import org.bigbluebutton.common.Role; + import org.bigbluebutton.common.events.CloseWindowEvent; + import org.bigbluebutton.common.events.LocaleChangeEvent; + import org.bigbluebutton.core.EventConstants; + import org.bigbluebutton.core.UsersUtil; + import org.bigbluebutton.core.events.CoreEvent; + import org.bigbluebutton.core.managers.UserManager; + import org.bigbluebutton.main.events.BBBEvent; + import org.bigbluebutton.main.events.MadePresenterEvent; + import org.bigbluebutton.main.events.SwitchedPresenterEvent; + import org.bigbluebutton.main.views.MainCanvas; + import org.bigbluebutton.modules.videoconf.business.TalkingButtonOverlay; + import org.bigbluebutton.modules.videoconf.events.CloseAllWindowsEvent; + import org.bigbluebutton.modules.videoconf.events.OpenVideoWindowEvent; + import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent; + import org.bigbluebutton.modules.videoconf.model.VideoConfOptions; + import org.bigbluebutton.util.i18n.ResourceUtil; [Bindable] private var defaultWidth:Number = 320; [Bindable] private var defaultHeight:Number = 240; diff --git a/bigbluebutton-config/bigbluebutton-release b/bigbluebutton-config/bigbluebutton-release index 3356e7cc65..ef39c792a3 100644 --- a/bigbluebutton-config/bigbluebutton-release +++ b/bigbluebutton-config/bigbluebutton-release @@ -1 +1 @@ -BIGBLUEBUTTON_RELEASE=0.9.0-RC +BIGBLUEBUTTON_RELEASE=0.9.0 diff --git a/bigbluebutton-config/web/default.pdf b/bigbluebutton-config/web/default.pdf old mode 100644 new mode 100755 diff --git a/bigbluebutton-html5/app/client/globals.coffee b/bigbluebutton-html5/app/client/globals.coffee index a81f92b2eb..766906ff0b 100755 --- a/bigbluebutton-html5/app/client/globals.coffee +++ b/bigbluebutton-html5/app/client/globals.coffee @@ -61,14 +61,6 @@ currentPresentation = Meteor.Presentations.findOne({"presentation.current": true}) currentPresentation?.presentation?.name -# helper to determine whether user has joined any type of audio -Handlebars.registerHelper "amIInAudio", -> - BBB.amIInAudio() - -# helper to determine whether the user is in the listen only audio stream -Handlebars.registerHelper "amIListenOnlyAudio", -> - BBB.amIListenOnlyAudio() - Handlebars.registerHelper "colourToHex", (value) => @window.colourToHex(value) @@ -112,7 +104,7 @@ Handlebars.registerHelper "getUsersInMeeting", -> raised.concat lowered Handlebars.registerHelper "getWhiteboardTitle", -> - (getPresentationFilename() or "Loading presentaion...") + "Presentation: " + (getPresentationFilename() or "Loading...") Handlebars.registerHelper "isCurrentUser", (userId) -> userId is null or userId is BBB.getCurrentUser()?.userId @@ -124,6 +116,9 @@ Handlebars.registerHelper "isCurrentUserRaisingHand", -> user = BBB.getCurrentUser() user?.user?.raise_hand +Handlebars.registerHelper "isCurrentUserSharingAudio", -> + BBB.amISharingAudio() + Handlebars.registerHelper "isCurrentUserSharingVideo", -> BBB.amISharingVideo() @@ -133,15 +128,16 @@ Handlebars.registerHelper "isCurrentUserTalking", -> Handlebars.registerHelper "isDisconnected", -> return !Meteor.status().connected -Handlebars.registerHelper "isUserInAudio", (userId) -> - BBB.isUserInAudio(userId) - -Handlebars.registerHelper "isUserListenOnlyAudio", (userId) -> - BBB.isUserListenOnlyAudio(userId) +Handlebars.registerHelper "isUserListenOnly", (userId) -> + user = Meteor.Users.findOne({userId:userId}) + return user?.user?.listenOnly Handlebars.registerHelper "isUserMuted", (userId) -> BBB.isUserMuted(userId) +Handlebars.registerHelper "isUserSharingAudio", (userId) -> + BBB.isUserSharingAudio(userId) + Handlebars.registerHelper "isUserSharingVideo", (userId) -> BBB.isUserSharingWebcam(userId) @@ -188,11 +184,6 @@ Handlebars.registerHelper "visibility", (section) -> str = str.replace http, "<a href='event:$1'><u>$1</u></a>" str = str.replace www, "$1<a href='event:http://$2'><u>$2</u></a>" -@introToAudio = (event, {isListenOnly} = {}) -> - isListenOnly ?= true - joinVoiceCall event, isListenOnly: isListenOnly - displayWebRTCNotification() - # check the chat history of the user and add tabs for the private chats @populateChatTabs = (msg) -> myUserId = getInSession "userId" @@ -262,45 +253,16 @@ Handlebars.registerHelper "visibility", (section) -> setInSession "display_usersList", !getInSession "display_usersList" setTimeout(redrawWhiteboard, 0) -# Periodically check the status of the WebRTC call, when a call has been established attempt to hangup, -# retry if a call is in progress, send the leave voice conference message to BBB -@exitVoiceCall = (event) -> - # To be called when the hangup is initiated - hangupCallback = -> - console.log "Exiting Voice Conference" - - # Checks periodically until a call is established so we can successfully end the call - # clean state - getInSession("triedHangup", false) - # function to initiate call - (checkToHangupCall = (context) -> - # if an attempt to hang up the call is made when the current session is not yet finished, the request has no effect - # keep track in the session if we haven't tried a hangup - if BBB.getCallStatus() isnt null and !getInSession("triedHangup") - console.log "Attempting to hangup on WebRTC call" - if BBB.amIListenOnlyAudio() # notify BBB-apps we are leaving the call call if we are listen only - Meteor.call('listenOnlyRequestToggle', getInSession("meetingId"), getInSession("userId"), getInSession("authToken"), false) - BBB.leaveVoiceConference hangupCallback - getInSession("triedHangup", true) # we have hung up, prevent retries - else - console.log "RETRYING hangup on WebRTC call in #{Meteor.config.app.WebRTCHangupRetryInterval} ms" - setTimeout checkToHangupCall, Meteor.config.app.WebRTCHangupRetryInterval # try again periodically - )(@) # automatically run function - return false - -# close the daudio UI, then join the conference. If listen only send the request to the server -@joinVoiceCall = (event, {isListenOnly} = {}) -> - $('#joinAudioDialog').dialog('close') - isListenOnly ?= true - - # create voice call params - joinCallback = (message) -> - console.log "Beginning WebRTC Conference Call" - - if isListenOnly - Meteor.call('listenOnlyRequestToggle', getInSession("meetingId"), getInSession("userId"), getInSession("authToken"), true) - BBB.joinVoiceConference joinCallback, isListenOnly # make the call #TODO should we apply role permissions to this action? - +@toggleVoiceCall = (event) -> + if BBB.amISharingAudio() + hangupCallback = -> + console.log "left voice conference" + BBB.leaveVoiceConference hangupCallback #TODO should we apply role permissions to this action? + else + # create voice call params + joinCallback = (message) -> + console.log "started webrtc_call" + BBB.joinVoiceConference joinCallback # make the call #TODO should we apply role permissions to this action? return false @toggleWhiteBoard = -> diff --git a/bigbluebutton-html5/app/client/lib/bbb_api_bridge.coffee b/bigbluebutton-html5/app/client/lib/bbb_api_bridge.coffee old mode 100755 new mode 100644 index 26aa86c2ca..18747f6a82 --- a/bigbluebutton-html5/app/client/lib/bbb_api_bridge.coffee +++ b/bigbluebutton-html5/app/client/lib/bbb_api_bridge.coffee @@ -57,48 +57,17 @@ https://github.com/bigbluebutton/bigbluebutton/blob/master/bigbluebutton-client/ BBB.isUserSharingWebcam = (userId, callback) -> BBB.getUser(userId)?.user?.webcam_stream?.length isnt 0 - # returns whether the user has joined any type of audio - BBB.amIInAudio = (callback) -> - user = BBB.getCurrentUser() - user?.user?.listenOnly or user?.user?.voiceUser?.joined - - # returns true if the user has joined the listen only audio stream - BBB.amIListenOnlyAudio = (callback) -> - BBB.isUserListenOnlyAudio BBB.getCurrentUser()?.userId - - # returns whether the user has joined the voice conference and is sharing audio through a microphone - BBB.amISharingAudio = (callback) -> - BBB.isUserSharingAudio BBB.getCurrentUser()?.userId - - # returns whether the user is currently talking BBB.amITalking = (callback) -> BBB.isUserTalking BBB.getCurrentUser()?.userId - BBB.isUserInAudio = (userId, callback) -> - user = BBB.getUser(userId) - user?.user?.listenOnly or user?.user?.voiceUser?.joined - - BBB.isUserListenOnlyAudio = (userId, callback) -> - BBB.getUser(userId)?.user?.listenOnly - - BBB.isUserSharingAudio = (userId, callback) -> - BBB.getUser(userId)?.user?.voiceUser?.joined - BBB.isUserTalking = (userId, callback) -> BBB.getUser(userId)?.user?.voiceUser?.talking - # returns true if the current user is marked as locked - BBB.amILocked = () -> - return BBB.getCurrentUser()?.user.locked - - # check whether the user is locked AND the current lock settings for the room - # includes locking the microphone of viewers (listenOnly is still alowed) - BBB.isMyMicLocked = () -> - lockedMicForRoom = Meteor.Meetings.findOne()?.roomLockSettings.disableMic - # note that voiceUser.locked is not used in BigBlueButton at this stage (April 2015) - - return lockedMicForRoom and BBB.amILocked() + BBB.amISharingAudio = (callback) -> + BBB.isUserSharingAudio BBB.getCurrentUser()?.userId + BBB.isUserSharingAudio = (userId) -> + BBB.getUser(userId)?.user?.voiceUser?.joined ### Raise user's hand. @@ -218,12 +187,9 @@ https://github.com/bigbluebutton/bigbluebutton/blob/master/bigbluebutton-client/ ### Join the voice conference. - isListenOnly: signifies whether the user joining the conference audio requests to join the listen only stream ### - BBB.joinVoiceConference = (callback, isListenOnly) -> - if BBB.isMyMicLocked() - callIntoConference(BBB.getMyVoiceBridge(), callback, true) #true because we force isListenOnly mode - callIntoConference(BBB.getMyVoiceBridge(), callback, isListenOnly) + BBB.joinVoiceConference = (callback) -> + callIntoConference(BBB.getMyVoiceBridge(), callback) ### Leave the voice conference. @@ -231,12 +197,6 @@ https://github.com/bigbluebutton/bigbluebutton/blob/master/bigbluebutton-client/ BBB.leaveVoiceConference = (callback) -> webrtc_hangup callback # sign out of call - ### - Get a hold of the object containing the call information - ### - BBB.getCallStatus = -> - getCallStatus() - ### Share user's webcam. @@ -380,7 +340,7 @@ https://github.com/bigbluebutton/bigbluebutton/blob/master/bigbluebutton-client/ listeners = {} ### - 3rd-party apps should use this method to register to listen for events. + 3rd-party apps should user this method to register to listen for events. ### BBB.listen = (eventName, handler) -> diff --git a/bigbluebutton-html5/app/client/main.coffee b/bigbluebutton-html5/app/client/main.coffee index 0bb3207287..cec262d87a 100755 --- a/bigbluebutton-html5/app/client/main.coffee +++ b/bigbluebutton-html5/app/client/main.coffee @@ -7,84 +7,6 @@ safariIconPath = 'M16.154,5.135c-0.504,0-1,0.031-1.488,0.089l-0.036-0.18c-0.021- # RaphaelJS "Internet Explorer" icon ieIconPath = 'M27.998,2.266c-2.12-1.91-6.925,0.382-9.575,1.93c-0.76-0.12-1.557-0.185-2.388-0.185c-3.349,0-6.052,0.985-8.106,2.843c-2.336,2.139-3.631,4.94-3.631,8.177c0,0.028,0.001,0.056,0.001,0.084c3.287-5.15,8.342-7.79,9.682-8.487c0.212-0.099,0.338,0.155,0.141,0.253c-0.015,0.042-0.015,0,0,0c-2.254,1.35-6.434,5.259-9.146,10.886l-0.003-0.007c-1.717,3.547-3.167,8.529-0.267,10.358c2.197,1.382,6.13-0.248,9.295-2.318c0.764,0.108,1.567,0.165,2.415,0.165c5.84,0,9.937-3.223,11.399-7.924l-8.022-0.014c-0.337,1.661-1.464,2.548-3.223,2.548c-2.21,0-3.729-1.211-3.828-4.012l15.228-0.014c0.028-0.578-0.042-0.985-0.042-1.436c0-5.251-3.143-9.355-8.255-10.663c2.081-1.294,5.974-3.209,7.848-1.681c1.407,1.14,0.633,3.533,0.295,4.518c-0.056,0.254,0.24,0.296,0.296,0.057C28.814,5.573,29.026,3.194,27.998,2.266zM13.272,25.676c-2.469,1.475-5.873,2.539-7.539,1.289c-1.243-0.935-0.696-3.468,0.398-5.938c0.664,0.992,1.495,1.886,2.473,2.63C9.926,24.651,11.479,25.324,13.272,25.676zM12.714,13.046c0.042-2.435,1.787-3.49,3.617-3.49c1.928,0,3.49,1.112,3.49,3.49H12.714z' -@displayWebRTCNotification = -> - if getInSession('webrtc_notification_is_displayed') is false # prevents the notification from displaying until the previous one is hidden - if !isWebRTCAvailable() # verifies if the browser supports WebRTC - $('.notification').addClass('webrtc-support-notification') - setInSession 'webrtc_notification_is_displayed', true - pp = new Raphael('browser-icon-container', 35, 35) - if getBrowserName() is 'Safari' - pp.path(safariIconPath).attr({fill: "#000", stroke: "none"}) - $('#notification-text').html("Sorry,<br/>Safari doesn't support WebRTC") - else if getBrowserName() is 'IE' - pp.path(ieIconPath).attr({fill: "#000", stroke: "none"}) - $('#notification-text').html("Sorry,<br/>IE doesn't support WebRTC") - else - pp.path(settingsIconPath).attr({fill: "#000", stroke: "none"}) - $('.notification.ui-widget-content p').css('font-size', '11px') # to make sure the text fits the dialog box - $('#notification-text').html("Sorry,<br/>your browser doesn't support WebRTC") - $('#notification').dialog('open') - setTimeout () -> # waits 2 sec, then hides the notification - $('#notification').dialog('close') - $('.joinAudioButton').blur() - setTimeout () -> # waits 0.5 sec (time to hide the notification), then removes the icons - pp.remove() - $('.notification').removeClass('webrtc-support-notification') - setInSession 'webrtc_notification_is_displayed', false - , 500 - , 2000 - else - if !BBB.amIInAudio() - Tracker.autorun (comp) -> - if BBB.amIInAudio() # display notification when you are in audio - $('#notification').addClass('joined-audio-notification') - $("#browser-icon-container").remove() # remove the space taken up by the unused icon - setInSession 'webrtc_notification_is_displayed', true - - if BBB.amIListenOnlyAudio() # notify the type of audio joined - $('#notification-text').html("You've joined the Listen Only Audio") - else - $('#notification-text').html("You've joined the audio") - - $('#notification').dialog('open') - setTimeout () -> - $('#notification').dialog('close') # close the entire notification - $('.joinAudioButton').blur() - setTimeout () -> - setInSession 'webrtc_notification_is_displayed', false - , 500 - , 3000 - comp.stop() - -# this method gets called from either mobile or desktop UI -# this method will adjust the UI to compensate for the new audio button -displayAudioSelectionMenu = ({isMobile} = {}) -> - isMobile ?= false - $('.joinAudioButton').blur() - - if isMobile - toggleSlidingMenu() - $('.navbarTitle').css('width', '55%') - - # pop open the dialog allowing users to choose the audio options - if isLandscapeMobile() - $('.joinAudio-dialog').addClass('landscape-mobile-joinAudio-dialog') - else - $('.joinAudio-dialog').addClass('desktop-joinAudio-dialog') - - $("#joinAudioDialog").dialog("open") - - -# helper function to reuse some code for the handling of audio join -onAudioJoinHelper = () -> - # if the microphone is locked (lock settings), the viewer is only - # allowed to join the audio as listenOnly. - if BBB.isMyMicLocked() - introToAudio(null, isListenOnly: true) - else - displayAudioSelectionMenu(isMobile: isMobile()) - - # Helper to load javascript libraries from the BBB server loadLib = (libname) -> successCallback = -> @@ -97,6 +19,8 @@ loadLib = (libname) -> # These settings can just be stored locally in session, created at start up Meteor.startup -> + + # Load SIP libraries before the application starts loadLib('sip.js') loadLib('bbb_webrtc_bridge_sip.js') @@ -121,8 +45,55 @@ Template.footer.helpers foot = "(c) #{info.copyrightYear} BigBlueButton Inc. [build #{info.bbbServerVersion} - #{info.dateOfBuild}] - For more information visit #{info.link}" Template.header.events - "click .joinAudioButton": (event) -> - onAudioJoinHelper() + "click .audioFeedIcon": (event) -> + if getInSession('webrtc_notification_is_displayed') is false # prevents the notification from displaying until the previous one is hidden + if !isWebRTCAvailable() # verifies if the browser supports WebRTC + $('.notification').addClass('webrtc-support-notification') + setInSession 'webrtc_notification_is_displayed', true + pp = new Raphael('browser-icon-container', 35, 35) + if getBrowserName() is 'Safari' + pp.path(safariIconPath).attr({fill: "#000", stroke: "none"}) + $('#notification-text').html("Sorry,<br/>Safari doesn't support WebRTC") + else if getBrowserName() is 'IE' + pp.path(ieIconPath).attr({fill: "#000", stroke: "none"}) + $('#notification-text').html("Sorry,<br/>IE doesn't support WebRTC") + else + pp.path(settingsIconPath).attr({fill: "#000", stroke: "none"}) + $('.notification.ui-widget-content p').css('font-size', '11px') # to make sure the text fits the dialog box + $('#notification-text').html("Sorry,<br/>your browser doesn't support WebRTC") + $('#notification').dialog('open') + setTimeout () -> # waits 2 sec, then hides the notification + $('#notification').dialog('close') + $('.audioFeedIcon').blur() + setTimeout () -> # waits 0.5 sec (time to hide the notification), then removes the icons + pp.remove() + $('.notification').removeClass('webrtc-support-notification') + setInSession 'webrtc_notification_is_displayed', false + , 500 + , 2000 + else + if !BBB.amISharingAudio() + Tracker.autorun (comp) -> + if BBB.amISharingAudio() + $('.notification').addClass('joined-audio-notification') + setInSession 'webrtc_notification_is_displayed', true + $('#notification-text').html("You've joined the audio") + $('#notification').dialog('open') + setTimeout () -> + $('#notification').dialog('close') + $('.audioFeedIcon').blur() + setTimeout () -> + $('.notification').removeClass('joined-audio-notification') + setInSession 'webrtc_notification_is_displayed', false + , 500 + , 2000 + comp.stop() + $('.audioFeedIcon').blur() + toggleVoiceCall @ + if BBB.amISharingAudio() + $('.navbarTitle').css('width', $('#navbar').width() - 358.4) + else + $('.navbarTitle').css('width', $('#navbar').width() - 409.6) "click .chatBarIcon": (event) -> $(".tooltip").hide() @@ -143,9 +114,6 @@ Template.header.events $(".tooltip").hide() toggleNavbar() - "click .leaveAudioButton": (event) -> - exitVoiceCall event - "click .lowerHand": (event) -> $(".tooltip").hide() Meteor.call('userLowerHand', getInSession("meetingId"), getInSession("userId"), getInSession("userId"), getInSession("authToken")) @@ -155,10 +123,11 @@ Template.header.events toggleMic @ "click .raiseHand": (event) -> + #Meteor.log.info "navbar raise own hand from client" + console.log "navbar raise own hand from client" $(".tooltip").hide() Meteor.call('userRaiseHand', getInSession("meetingId"), getInSession("userId"), getInSession("userId"), getInSession("authToken")) - - # "click .settingsIcon": (event) -> + # "click .settingsIcon": (event) -> # alert "settings" "click .signOutIcon": (event) -> @@ -168,10 +137,11 @@ Template.header.events else $('.logout-dialog').addClass('desktop-logout-dialog') $("#dialog").dialog("open") - "click .hideNavbarIcon": (event) -> $(".tooltip").hide() toggleNavbar() + # "click .settingsIcon": (event) -> + # alert "settings" "click .usersListIcon": (event) -> $(".tooltip").hide() @@ -194,8 +164,14 @@ Template.header.events $("#navbarMinimizedButton").addClass("navbarMinimizedButtonLarge") Template.slidingMenu.events - 'click .joinAudioButton': (event) -> - onAudioJoinHelper() + 'click .audioFeedIcon': (event) -> + $('.audioFeedIcon').blur() + toggleSlidingMenu() + toggleVoiceCall @ + if BBB.amISharingAudio() + $('.navbarTitle').css('width', '70%') + else + $('.navbarTitle').css('width', '55%') 'click .chatBarIcon': (event) -> $('.tooltip').hide() @@ -228,46 +204,11 @@ Template.slidingMenu.events toggleSlidingMenu() $('.collapseButton').blur() - "click .leaveAudioButton": (event) -> - exitVoiceCall event - toggleSlidingMenu() - Template.main.helpers - setTitle: -> - document.title = "BigBlueButton #{window.getMeetingName() ? 'HTML5'}" + setTitle: -> + document.title = "BigBlueButton #{window.getMeetingName() ? 'HTML5'}" Template.main.rendered = -> - # the initialization code for the dialog presenting the user with microphone+listen only options - $("#joinAudioDialog").dialog( - modal: true - draggable: false - resizable: false - autoOpen: false - dialogClass: 'no-close logout-dialog joinAudioDialog' - buttons: [ - { - text: 'Cancel' - click: () -> - $(this).dialog("close") - $(".tooltip").hide() - class: 'btn btn-xs btn-default joinAudioDialogButton' - } - ] - open: (event, ui) -> - $('.ui-widget-overlay').bind 'click', () -> - if isMobile() - $("#joinAudioDialog").dialog('close') - position: { my: "center", at: "center", of: window } - ) - - # jQuery click events are handled here. Meteor click handlers don't get called. - # we pass in a named boolean parameter the whether we wish to join audio as listen only or not - $("#microphone").click -> - introToAudio @, isListenOnly: false - - $("#listen_only").click -> - introToAudio @, isListenOnly: true - $("#dialog").dialog( modal: true draggable: false @@ -316,20 +257,16 @@ Template.main.rendered = -> position: my: 'left top' at: 'left bottom' - of: '.joinAudioButton' + of: '.audioFeedIcon' ) $(window).resize( -> $('#dialog').dialog('close') - $('#joinAudioDialog').dialog('close') ) $('#shield').click () -> toggleSlidingMenu() - if Meteor.config.app.autoJoinAudio - onAudioJoinHelper() - Template.makeButton.rendered = -> $('button[rel=tooltip]').tooltip() diff --git a/bigbluebutton-html5/app/client/main.html b/bigbluebutton-html5/app/client/main.html index c9ca307b9b..aa58282011 100755 --- a/bigbluebutton-html5/app/client/main.html +++ b/bigbluebutton-html5/app/client/main.html @@ -1,7 +1,7 @@ <template name="footer"> - <div id="footer" class="myFooter gradientBar navbar-default"> - {{{getFooterString}}} - </div> + <div id="footer" class="myFooter gradientBar navbar-default"> + {{{getFooterString}}} + </div> </template> <template name="header"> @@ -9,7 +9,7 @@ <div id="navbar" class="myNavbar gradientBar navbar navbar-default navbar-fixed-top" role="navigation"> <div class="navbarUserButtons navbarSection"> <div id="collapseButtonSection"> - {{#if isPortraitMobile}} + {{#if isMobile}} <button class="navbar-toggle btn navbarButton collapseSlidingMenuButton"> <div class="push-menu-icon"> <span class="icon-bar"></span> @@ -36,9 +36,9 @@ <!-- display/hide whiteboard toggle --> {{#if getInSession "display_whiteboard"}} - {{> makeButton btn_class="navbarIconToggleActive whiteboardIcon navbarButton collapseSectionButton" i_class="ion-easel" rel="tooltip" data_placement="bottom" title="Hide Whiteboard"}} + {{> makeButton btn_class="navbarIconToggleActive whiteboardIcon navbarButton collapseSectionButton" i_class="glyphicon glyphicon-pencil" rel="tooltip" data_placement="bottom" title="Hide Whiteboard"}} {{else}} - {{> makeButton btn_class="whiteboardIcon navbarButton collapseSectionButton" i_class="ion-easel" rel="tooltip" data_placement="bottom" title="Show Whiteboard"}} + {{> makeButton btn_class="whiteboardIcon navbarButton collapseSectionButton" i_class="glyphicon glyphicon-pencil" rel="tooltip" data_placement="bottom" title="Show Whiteboard"}} {{/if}} <!-- display/hide chat bar toggle --> @@ -56,26 +56,20 @@ {{/if}} --> </div> <div class='audioControllersSection'> - <!-- We are in a form of audio --> - {{#if amIInAudio}} + <!-- Join/hang up audio call --> + {{#if isCurrentUserSharingAudio}} <div class='hiddenNavbarSection'> - <!-- display the button for leaving audio --> {{> makeButton btn_class="navbarIconToggleActive audioFeedIcon navbarButton audioButton leaveAudioButton" i_class="ion-volume-mute" sharingAudio=true rel="tooltip" data_placement="bottom" title="Leave Audio Call"}} </div> - {{#unless amIListenOnlyAudio}} - {{#if isCurrentUserMuted}} - <!-- if you are muted the button representing your status will show volume off --> - {{> makeButton btn_class="muteIcon navbarButton audioButton" i_class="glyphicon glyphicon-volume-off" sharingAudio=true rel="tooltip" data_placement="bottom" title="Unmute"}} + {{#if isCurrentUserMuted}} + {{> makeButton btn_class="muteIcon navbarButton audioButton" i_class="glyphicon glyphicon-volume-off" sharingAudio=true rel="tooltip" data_placement="bottom" title="Unmute"}} + {{else}} + {{#if isCurrentUserTalking}} + {{> makeButton btn_class="navbarIconToggleActive muteIcon navbarButton audioButton" i_class="glyphicon glyphicon-volume-up" sharingAudio=true rel="tooltip" data_placement="bottom" title="Mute"}} {{else}} - {{#if isCurrentUserTalking}} - <!-- you are talking. Display a high volume/volume up representing voice activity --> - {{> makeButton btn_class="navbarIconToggleActive muteIcon navbarButton audioButton" i_class="glyphicon glyphicon-volume-up" sharingAudio=true rel="tooltip" data_placement="bottom" title="Mute"}} - {{else}} - <!-- you are not talking. Display low volume/volume down representing no voice activity --> - {{> makeButton btn_class="navbarIconToggleActive muteIcon navbarButton audioButton" i_class="glyphicon glyphicon-volume-down" sharingAudio=true rel="tooltip" data_placement="bottom" title="Mute"}} - {{/if}} + {{> makeButton btn_class="navbarIconToggleActive muteIcon navbarButton audioButton" i_class="glyphicon glyphicon-volume-down" sharingAudio=true rel="tooltip" data_placement="bottom" title="Mute"}} {{/if}} - {{/unless}} + {{/if}} {{else}} <div class='hiddenNavbarSection'> {{> makeButton btn_class="audioFeedIcon navbarButton audioButton joinAudioButton" i_class="glyphicon glyphicon-headphones" sharingAudio=false rel="tooltip" data_placement="bottom" title="Join Audio Call"}} @@ -96,6 +90,7 @@ <div class="navbarTitle navbarSection"><span>{{getMeetingName}}</span></div> <div class="navbarSettingsButtons navbarSection"> <!-- {{> makeButton id="userId" btn_class="settingsIcon navbarButton" i_class="glyphicon glyphicon-cog" rel="tooltip" data_placement="bottom" title="Settings"}} --> + <!-- {{> makeButton btn_class="hideNavbarIcon navbarButton" i_class="glyphicon glyphicon-chevron-up" rel="tooltip" data_placement="bottom" title="Hide Navbar"}} --> {{> makeButton btn_class="signOutIcon navbarButton" i_class="glyphicon glyphicon-log-out" rel="tooltip" data_placement="bottom" title="Logout"}} </div> </div> @@ -104,83 +99,56 @@ {{> makeButton id="navbarMinimizedButton" btn_class="hideNavbarIcon navbarMinimizedButtonSmall" i_class="glyphicon glyphicon-chevron-down" rel="tooltip" data_placement="bottom" title="Display Navbar"}} {{/if}} </template> -<!-- dialog that presents user with audio options - contains microphone and listen only with icons --> -<template name="joinAudioDialog"> - <div id="joinAudioDialog" title="How do you want to join the audio?"> - <hr class="joinAudioDialogHr"/> - <div style="float:left; border-right: 2px solid darkgrey; width: 50%; height: 100%"> - <i class="icon ion-mic-a joinAudioDialogIcon"></i> - <br/> - <button id="microphone" class="joinAudioDialogButton">Microphone</button> - </div> - <div style="float:left; width: 50%"> - <i class="icon ion-volume-high joinAudioDialogIcon"></i> - <br/> - <button id="listen_only" class="joinAudioDialogButton">Listen Only</button> - </div> - <br style="clear:both;"/><br/> - <hr style="margin: 10px; border: 1px solid darkgrey;" /> - </div> -</template> <template name="main"> - {{setTitle}} - <body> - <div id="dialog" title="Confirm Logout"> +{{setTitle}} +<body> + <div id="dialog" title="Confirm Logout"> <p>Are you sure you want to log out?</p> - </div> - {{> joinAudioDialog}} - <div id="notification"> + </div> + <div id="notification"> <div id="browser-icon-container"></div> <p id="notification-text"></p> - </div> - - <div id="main" class="mainContainer row-fluid"> - {{#if isDisconnected}} - {{>status}} - {{else}} - <div>{{> header}}</div> - {{> whiteboard id="whiteboard" title=getWhiteboardTitle name="whiteboard"}} - {{> chatbar id="chat" title="Chat" name="chatbar"}} - {{> usersList id="users" name="usersList"}} - <audio id="remote-media" autoplay="autoplay"></audio> - {{> footer}} - {{/if}} - <div id='shield'></div> - </div> - {{#if isPortraitMobile}} - {{> slidingMenu}} + </div> + <div id="main" class="mainContainer row-fluid"> + {{#if isDisconnected}} + {{>status}} + {{else}} + <div>{{> header}}</div> + {{> whiteboard id="whiteboard" title=getWhiteboardTitle name="whiteboard"}} + {{> chatbar id="chat" title="Chat" name="chatbar"}} + {{> usersList id="users" name="usersList"}} + <audio id="remote-media" autoplay="autoplay"></audio> + {{> footer}} {{/if}} - </body> + <div id='shield'></div> + </div> + {{#if isMobile}} + {{> slidingMenu}} + {{/if}} +</body> </template> <template name="recordingStatus"> - <!-- Recording status of the meeting --> - {{#with getCurrentMeeting}} - {{#if intendedForRecording}} - {{#if currentlyBeingRecorded}} - <button class="recordingStatus recordingStatusTrue" rel="tooltip" data-placement="bottom" title="This Meeting is Being Recorded"><span class="glyphicon glyphicon-record"></span> Recording</button> - {{else}} - <button class="recordingStatus recordingStatusFalse" rel="tooltip" data-placement="bottom" title="This Meeting is Not Currently Being Recorded"><span class="glyphicon glyphicon-record"></span></button> - {{/if}} - {{/if}} - {{/with}} + <!-- Recording status of the meeting --> + {{#with getCurrentMeeting}} + {{#if intendedForRecording}} + {{#if currentlyBeingRecorded}} + <button class="recordingStatus recordingStatusTrue" rel="tooltip" data-placement="bottom" title="This Meeting is Being Recorded"><span class="glyphicon glyphicon-record"></span> Recording</button> + {{else}} + <button class="recordingStatus recordingStatusFalse" rel="tooltip" data-placement="bottom" title="This Meeting is Not Currently Being Recorded"><span class="glyphicon glyphicon-record"></span></button> + {{/if}} + {{/if}} + {{/with}} </template> <template name='slidingMenu'> <div class="sliding-menu" id="sliding-menu"> <div class="slideSection"> - {{#if getInSession "display_usersList"}} - {{> makeButton btn_class="navbarIconToggleActive usersListIcon slideButton" i_class="glyphicon glyphicon-user" rel="tooltip" data_placement="right" title="Hide List of Users"}} - {{else}} - {{> makeButton btn_class="usersListIcon slideButton" i_class="glyphicon glyphicon-user" rel="tooltip" data_placement="right" title="Show List of Users"}} - {{/if}} - {{#if getInSession "display_whiteboard"}} - {{> makeButton btn_class="navbarIconToggleActive whiteboardIcon slideButton" i_class="ion-easel" rel="tooltip" data_placement="right" title="Hide Whiteboard"}} + {{> makeButton btn_class="navbarIconToggleActive whiteboardIcon slideButton" i_class="glyphicon glyphicon-pencil" rel="tooltip" data_placement="right" title="Hide Whiteboard"}} {{else}} - {{> makeButton btn_class="whiteboardIcon slideButton" i_class="ion-easel" rel="tooltip" data_placement="right" title="Show Whiteboard"}} + {{> makeButton btn_class="whiteboardIcon slideButton" i_class="glyphicon glyphicon-pencil" rel="tooltip" data_placement="right" title="Show Whiteboard"}} {{/if}} {{#if getInSession "display_chatbar"}} @@ -189,10 +157,16 @@ {{> makeButton btn_class="chatBarIcon slideButton" i_class="glyphicon glyphicon-comment" rel="tooltip" data_placement="right" title="Show Message Pane"}} {{/if}} - {{#if amIInAudio}} - {{> makeButton btn_class="navbarIconToggleActive audioFeedIcon slideButton audioButton leaveAudioButton" i_class="ion-volume-mute" sharingAudio=true rel="tooltip" data_placement="bottom" title="Leave Audio Call"}} + {{#if getInSession "display_usersList"}} + {{> makeButton btn_class="navbarIconToggleActive usersListIcon slideButton" i_class="glyphicon glyphicon-user" rel="tooltip" data_placement="right" title="Hide List of Users"}} + {{else}} + {{> makeButton btn_class="usersListIcon slideButton" i_class="glyphicon glyphicon-user" rel="tooltip" data_placement="right" title="Show List of Users"}} + {{/if}} + + {{#if isCurrentUserSharingAudio}} + {{> makeButton btn_class="navbarIconToggleActive audioFeedIcon slideButton" i_class="ion-volume-mute" sharingAudio=true rel="tooltip" data_placement="right" title="Leave Audio Call"}} {{else}} - {{> makeButton btn_class="audioFeedIcon slideButton audioButton joinAudioButton" i_class="glyphicon glyphicon-headphones" sharingAudio=false rel="tooltip" data_placement="bottom" title="Join Audio Call"}} + {{> makeButton btn_class="audioFeedIcon slideButton" i_class="glyphicon glyphicon-headphones" sharingAudio=false rel="tooltip" data_placement="right" title="Join Audio Call"}} {{/if}} {{#if isCurrentUserRaisingHand}} diff --git a/bigbluebutton-html5/app/client/stylesheets/chat.less b/bigbluebutton-html5/app/client/stylesheets/chat.less index 1407d1b95c..1ee07825ec 100755 --- a/bigbluebutton-html5/app/client/stylesheets/chat.less +++ b/bigbluebutton-html5/app/client/stylesheets/chat.less @@ -1,9 +1,9 @@ @import "variables"; .active { - border: .2vh solid !important; + border: .2vh solid extract(@azure, 2) !important; @media @mobile-portrait-with-keyboard, @mobile-portrait { - border-left: .1vh solid !important; + border-left: .1vh solid extract(@azure, 2) !important; } } @@ -76,18 +76,6 @@ .chatNameSelectorPrivate { .chatNameSelector; width:90%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - @media @landscape { - height: 20px; - } - @media @desktop-portrait { - height: 25px; - } - @media @mobile-portrait, @mobile-portrait-with-keyboard { - font-size: 4vw; - } } .chatNameSelectorPublic { @@ -96,6 +84,12 @@ width:100%; } +.chatOptionsText { + @media @mobile-portrait, @mobile-portrait-with-keyboard { + font-size: 5vw; + } +} + .close:hover { background-color: red; } @@ -119,12 +113,6 @@ padding: 5px; } - -.disabledChat { - background-color: grey; - width: 100% !important; -} - .dropdown { float: left; @media @desktop-portrait, @mobile-portrait, @mobile-portrait-with-keyboard { @@ -140,15 +128,13 @@ } } -#fontSizeTable { - /* Static font sizes are used everywhere in this control. This is the maximum amount of space required */ - height: 64px; - #displayButtons { - text-align:center; - width:84px; +#fontSizeControl { + @media @mobile-portrait, @mobile-portrait-with-keyboard { + font-size:7vw; } - #displayLabel { - width: 154px; + .fontSizeLabel { + height:30px; + text-align:center; } } @@ -156,6 +142,13 @@ background: extract(@yellow, 2) !important; } +#increaseFontSize, #decreaseFontSize { + @media @mobile-portrait, @mobile-portrait-with-keyboard { + height: 100px; + width: 100px; + } +} + #MoreChatsDrop { float: right; } @@ -292,7 +285,7 @@ &:hover { background-color: #ddd; - border: 1px solid; + border: 1px solid extract(@azure, 2); border-bottom: none; } } diff --git a/bigbluebutton-html5/app/client/stylesheets/style.less b/bigbluebutton-html5/app/client/stylesheets/style.less index 7920a4ac22..9a86b20aa9 100755 --- a/bigbluebutton-html5/app/client/stylesheets/style.less +++ b/bigbluebutton-html5/app/client/stylesheets/style.less @@ -41,10 +41,6 @@ body { overflow-x: hidden; } -.heading { - margin-left:5px -} - .mainContainer { height: 95%; } @@ -54,7 +50,6 @@ body { color: black; padding-top: 13px; text-align: center; - background-color: #EEEEEE; @media @landscape { position:fixed; bottom:0; @@ -70,13 +65,13 @@ body { font-size: 2vw; } - /*the footer should be visible only at the very bottom of a portrait page*/ + // the footer should be visible only at the very bottom of a portrait page @media @desktop-portrait, @mobile-portrait { order: 4; -webkit-order: 4; } @media @mobile-portrait-with-keyboard { - display: none; /*hide when typing*/ + display: none; //hide when typing } } @@ -88,6 +83,8 @@ body { } .btn { .linear-gradient(rgb(72,76,85), rgb(65,68,77)); + border-left: 1px solid extract(@darkGrey, 2); + border-right: 1px solid extract(@darkGrey, 4); &.navbarIconToggleActive { background: extract(@darkGrey, 3); border-bottom: 4px solid extract(@azure, 1); @@ -217,7 +214,7 @@ body { display: block; float: left; &:hover { - background: extract(@darkGrey, 4); + background: extract(@darkGrey, 3); } } @media @landscape { @@ -226,7 +223,7 @@ body { } .navbarSettingsButtons .btn:hover { - background: extract(@darkGrey, 4); + background: extract(@darkGrey, 3); } .panel-footer { @@ -323,6 +320,77 @@ body { } } +/* Custom alert box */ + +/* Logout menu's properties on mobile devices in landscape orientation */ +.landscape-mobile-logout-dialog { + @media @landscape { + .ui-widget-header { + font-size: 100% !important; + } + width: 55% !important; /* overriding "width: auto;" */ + font-size: 3vh !important; /* overriding "font-size: 11px;" */ + .ui-dialog-content { + height: 30% !important; /* overriding "height: auto;" */ + } + .ui-dialog-buttonset { + width: 100%; + font-size: 4vh; + button { + width: 40%; + margin-left: 5% !important; + margin-right: 5% !important; + } + } + height: 32% !important; + } +} + +/* Logout menu's properties on desktop */ +.desktop-logout-dialog { + @media @desktop-portrait, @landscape { + .ui-dialog-content { + height: 36px !important; /* overriding "height: auto;" */ + } + } +} + +.no-close .ui-dialog-titlebar-close { + display: none; /* no close button */ +} + +.logout-dialog.ui-dialog { + .ui-widget-header { + color: extract(@white, 1); + font-weight: bold; + background: extract(@darkGrey, 3); + @media @desktop-portrait, @landscape { + font-size: 12px; + } + } + .ui-dialog-content { + font-weight: bold; + text-align: center; + @media @desktop-portrait, @landscape { + min-height: 0px !important; /* overriding "min-height: 47px;"*/ + } + } + @media @mobile-portrait-with-keyboard, @mobile-portrait { + width: 100% !important; + } +} + +.logout-dialog.ui-widget-content { + background: extract(@white, 3); + border: 5px solid extract(@darkGrey, 3); + @media @desktop-portrait, @landscape { + font-size: 11px; + } + @media @mobile-portrait-with-keyboard, @mobile-portrait { + font-size: 280%; + } +} + .ui-widget-overlay { z-index: 1031; } @@ -378,7 +446,7 @@ body { } } -.glyphicon, .ion-android-hand, .ion-easel { +.glyphicon, .ion-android-hand { @media @mobile-portrait-with-keyboard, @mobile-portrait { font-size: 35px; } @@ -395,7 +463,7 @@ body { .narrowedNavbarTitle { @media @desktop-portrait { - width: calc(~'100% - 410px') !important; + width: calc(~'100% - 358.4px') !important; } } @@ -466,6 +534,8 @@ body { } .btn { .linear-gradient(rgb(72,76,85), rgb(65,68,77)); + border-left: 1px solid extract(@darkGrey, 2); + border-right: 1px solid extract(@darkGrey, 4); &.navbarIconToggleActive { background: extract(@darkGrey, 3); border-bottom: 4px solid extract(@azure, 1); @@ -511,11 +581,12 @@ body { background: grey; &.webrtc-support-notification { - width: 500px !important; + width: 300px !important; height: 50px !important; } &.joined-audio-notification { - width: 500px !important; + width: 200px !important; + height: 32px !important; #browser-icon-container { display: none; } @@ -528,6 +599,7 @@ body { &.ui-widget-content p { color: black; font-size: 14px; + height: 35px; margin: 0; padding: 1px; } @@ -557,103 +629,3 @@ body { .invisible { display: none; } - -/* Custom alert box */ -/* Logout menu's properties on mobile devices in landscape orientation */ -.landscape-mobile-logout-dialog { - @media @landscape { - .ui-widget-header { - font-size: 100% !important; - } - width: 55% !important; /* overriding "width: auto;" */ - font-size: 3vh !important; /* overriding "font-size: 11px;" */ - .ui-dialog-content { - height: 30% !important; /* overriding "height: auto;" */ - } - .ui-dialog-buttonset { - width: 100%; - font-size: 4vh; - button { - width: 40%; - margin-left: 5% !important; - margin-right: 5% !important; - } - } - height: 32% !important; - } -} - -/* Logout menu's properties on desktop */ -.desktop-logout-dialog { - @media @desktop-portrait, @landscape { - .ui-dialog-content { - height: 36px !important; /* overriding "height: auto;" */ - } - } -} - -.no-close .ui-dialog-titlebar-close { - display: none; /* no close button */ -} - -.logout-dialog.ui-dialog { - .ui-widget-header { - color: extract(@white, 1); - font-weight: bold; - background: extract(@darkGrey, 3); - @media @desktop-portrait, @landscape { - font-size: 12px; - } - } - .ui-dialog-content { - font-weight: bold; - text-align: center; - @media @desktop-portrait, @landscape { - min-height: 0px !important; /* overriding "min-height: 47px;"*/ - } - } - @media @mobile-portrait-with-keyboard, @mobile-portrait { - width: 100% !important; - } -} - -.logout-dialog.ui-widget-content { - background: extract(@white, 3); - border: 5px solid extract(@darkGrey, 3); - @media @desktop-portrait, @landscape { - font-size: 11px; - } - @media @mobile-portrait-with-keyboard, @mobile-portrait { - font-size: 280%; - } -} - -.joinAudioDialog { - min-width: 500px; - width: 25% !important; -} -#joinAudioDialog { - background-color: rgb(239, 239, 239); - display: none; -} -.joinAudioDialogButton { - background: -webkit-linear-gradient(rgb(255,255,255), rgb(225,226,229)); /* For Safari 5.1 to 6.0 */ - background: -o-linear-gradient(rgb(255,255,255), rgb(225,226,229)); /* For Opera 11.1 to 12.0 */ - background: -moz-linear-gradient(rgb(255,255,255), rgb(225,226,229)); /* For Firefox 3.6 to 15 */ - background: linear-gradient(rgb(255,255,255), rgb(225,226,229)); /* Standard syntax (must be last) */ - border-radius: 5px; - color: rgb(94,95,99); - font-weight: bold; - padding: 10px; -} -.joinAudioDialogHr { - border: 1px solid darkgrey; - margin: 10px; - margin-bottom:5px; -} -.joinAudioDialogIcon { - font-size: 100px; -} -.ui-dialog-titlebar { - text-align: center; -} diff --git a/bigbluebutton-html5/app/client/stylesheets/users.less b/bigbluebutton-html5/app/client/stylesheets/users.less index 9095fb7eef..874b7f5634 100755 --- a/bigbluebutton-html5/app/client/stylesheets/users.less +++ b/bigbluebutton-html5/app/client/stylesheets/users.less @@ -2,9 +2,6 @@ #content { margin-top: 10px; - &:first-child { - margin-top: 0px; - } overflow: hidden; width: 100%; @media @mobile-portrait, @mobile-portrait-with-keyboard { diff --git a/bigbluebutton-html5/app/client/views/chat/chat_bar.coffee b/bigbluebutton-html5/app/client/views/chat/chat_bar.coffee index eb766d6510..625df4acf8 100755 --- a/bigbluebutton-html5/app/client/views/chat/chat_bar.coffee +++ b/bigbluebutton-html5/app/client/views/chat/chat_bar.coffee @@ -65,24 +65,6 @@ Handlebars.registerHelper "grabChatTabs", -> setInSession 'chatTabs', initTabs getInSession('chatTabs')[0..3] -# true if the lock settings limit public chat and the current user is locked -Handlebars.registerHelper "publicChatDisabled", -> - userIsLocked = Meteor.Users.findOne({userId:getInSession 'userId'})?.user.locked - publicChatIsDisabled = Meteor.Meetings.findOne({})?.roomLockSettings.disablePubChat - presenter = Meteor.Users.findOne({userId:getInSession 'userId'})?.user.presenter - return userIsLocked and publicChatIsDisabled and !presenter - -# true if the lock settings limit private chat and the current user is locked -Handlebars.registerHelper "privateChatDisabled", -> - userIsLocked = Meteor.Users.findOne({userId:getInSession 'userId'})?.user.locked - privateChatIsDisabled = Meteor.Meetings.findOne({})?.roomLockSettings.disablePrivChat - presenter = Meteor.Users.findOne({userId:getInSession 'userId'})?.user.presenter - return userIsLocked and privateChatIsDisabled and !presenter - -# return whether the user's chat pane is open in Private chat (vs Public chat or Options) -Handlebars.registerHelper "inPrivateChat", -> - return !((getInSession 'inChatWith') in ['PUBLIC_CHAT', 'OPTIONS']) - @sendMessage = -> message = linkify $('#newMessageInput').val() # get the message from the input box unless (message?.length > 0 and (/\S/.test(message))) # check the message has content and it is not whitespace diff --git a/bigbluebutton-html5/app/client/views/chat/chat_bar.html b/bigbluebutton-html5/app/client/views/chat/chat_bar.html index 691352fb23..c99e4d0427 100755 --- a/bigbluebutton-html5/app/client/views/chat/chat_bar.html +++ b/bigbluebutton-html5/app/client/views/chat/chat_bar.html @@ -1,90 +1,76 @@ <template name="chatbar"> - <div id="{{id}}" {{visibility name}} class="component"> - <h3 class="title gradientBar"> - <span class="glyphicon glyphicon-comment heading"></span> - {{> extraConversations}} - </h3> - {{>tabButtons}} <!-- Display public/options tabs, and private chat tabs --> - {{#if getInSession "display_chatPane"}} - <div id="chatbody"> - <ul class="chat" {{messageFontSize}}> - {{#each getCombinedMessagesForChat}} - {{#if message}} - <li>{{> message}}</li> + <div id="{{id}}" {{visibility name}} class="component"> + <h3 class="title gradientBar"> + <span class="glyphicon glyphicon-comment"></span> + {{title}} + {{> extraConversations}} + </h3> + {{>tabButtons}} <!-- Display public/options tabs, and private chat tabs --> + {{#if getInSession "display_chatPane"}} + <div id="chatbody"> + <ul class="chat" {{messageFontSize}}> + {{#each getCombinedMessagesForChat}} + {{#if message}} + <li>{{> message}}</li> + {{/if}} + {{/each}} + {{#unless userExists}}<li>The user has left</li>{{/unless}} + </ul> + </div> + {{#if userExists}} + <div class="panel-footer">{{> chatInput}}</div> {{/if}} - {{/each}} - {{#unless userExists}}<li>The user has left</li>{{/unless}} - </ul> - </div> - {{#if userExists}} - <div class="panel-footer">{{> chatInput}}</div> - {{/if}} - {{else}} - {{> optionsBar}} - {{/if}} - </div> + {{else}} + {{> optionsBar}} + {{/if}} + </div> </template> <template name="chatInput"> - <div id="chatInput" class="chat-input-wrapper"> - {{#if inPrivateChat}} - {{#if privateChatDisabled}} - <textarea id="newMessageInput" class="disabledChat" placeholder="Private chat is temporarily locked (disabled)" rel="tooltip" data-placement="top" title="Private chat is temporarily locked" disabled></textarea> - {{else}} - <textarea id="newMessageInput" placeholder="Write a message..." rel="tooltip" data-placement="top" title="Write a new message"></textarea> - <button type="submit" id="sendMessageButton" class="btn" rel="tooltip" data-placement="top"> - Send - </button> - {{/if}} - {{else}} - {{#if publicChatDisabled}} - <textarea id="newMessageInput" class="disabledChat" placeholder="Public chat is temporarily locked (disabled)" rel="tooltip" data-placement="top" title="Public chat is temporarily locked" disabled></textarea> - {{else}} - <textarea id="newMessageInput" placeholder="Write a message..." rel="tooltip" data-placement="top" title="Write a new message"></textarea> - <button type="submit" id="sendMessageButton" class="btn" rel="tooltip" data-placement="top"> - Send - </button> - {{/if}} - {{/if}} - </div> + <div id="chatInput" class="chat-input-wrapper"> + <textarea id="newMessageInput" placeholder="Write a message..." rel="tooltip" data-placement="top" title="Write a new message"></textarea> + <button type="submit" id="sendMessageButton" class="btn" rel="tooltip" data-placement="top" title="Click to send your message"> + Send + </button> + </div> </template> <template name="chatOptions"> - <p>Chat Options:</p> - {{> optionsFontSize}} + <p>Chat Options:</p> + {{> optionsFontSize}} </template> <template name="extraConversations"> - {{#if tooManyConversations}} - <div id="MoreChatsDrop" class="btn-group"> - <button type="button" id="MoreChatsbutton" class="btn btn-default dropdown-toggle" data-toggle="dropdown">More Chats<span class="caret"></span></button> - <ul class="dropdown-menu extraConversationScrollableMenu" role="menu"> - {{#each getExtraConversations}} - <li class="extraConversation" id="{{safeName name}}"><a href="#">{{safeName name}}</a></li> - {{/each}} - </ul> - </div> - {{/if}} + {{#if tooManyConversations}} + <div id="MoreChatsDrop" class="btn-group"> + <button type="button" id="MoreChatsbutton" class="btn btn-default dropdown-toggle" data-toggle="dropdown">More Chats<span class="caret"></span></button> + <ul class="dropdown-menu extraConversationScrollableMenu" role="menu"> + {{#each getExtraConversations}} + <li class="extraConversation" id="{{safeName name}}"><a href="#">{{safeName name}}</a></li> + {{/each}} + </ul> + </div> + {{/if}} </template> <!-- Displays and styles an individual message in the chat --> <template name="message"> - <span style="float:left;"> - {{#if message.from_username}} - <span class="userNameEntry" rel="tooltip" data-placement="bottom" title="{{message.from_username}}"> - {{message.from_username}} - </span> - {{/if}} - </span> - <span style="float:right;"> - {{#if message.from_time}} - <span {{messageFontSize}}>{{toClockTime message.from_time}}</span> - <span {{messageFontSize}} class="glyphicon glyphicon-time"></span> - {{/if}} - </span> - <br/> - <div style="color:{{colourToHex message.from_color}}">{{{sanitizeAndFormat message.message}}}</div> - {{autoscroll}} + <span style="float:left;"> + {{#if message.from_username}} + <span class="userNameEntry" rel="tooltip" data-placement="bottom" title="{{message.from_username}}"> + {{message.from_username}} + </span> + {{/if}} + </span> + <span style="float:right;"> + {{#if message.from_time}} + <span {{messageFontSize}}>{{toClockTime message.from_time}}</span> + <span {{messageFontSize}} class="glyphicon glyphicon-time"></span> + {{/if}} + </span> + <br/> + <div style="color:{{colourToHex message.from_color}}">{{{sanitizeAndFormat message.message}}}</div> + {{autoscroll}} </template> <!-- Displays the list of options available --> @@ -110,16 +96,12 @@ </template> <template name="optionsFontSize"> - <span class="chatOptionsText" >Chat Message Font Size: </span><br/> - <table id="fontSizeTable"> - <tr> - <td id="displayButtons"> - <button id="decreaseFontSize" class="glyphicon glyphicon-minus"></button> - <button id="increaseFontSize" class="glyphicon glyphicon-plus"></button> - </td > - <td id="displayLabel"><label class="fontSizeLabel" {{messageFontSize}} >Size({{getInSession "messageFontSize"}})</label></td> - </tr> - </table> + <div id="fontSizeControl"> + <span class="chatOptionsText" >Chat Message Font Size: </span><br> + <button id="decreaseFontSize" class="glyphicon glyphicon-minus" ></button> + <label class="fontSizeLabel" {{messageFontSize}} >Size({{getInSession "messageFontSize"}})</label> + <button id="increaseFontSize" class="glyphicon glyphicon-plus"></button> + </div> </template> <!-- Display buttons on the chat tab, public, options, and all the private chat tabs --> diff --git a/bigbluebutton-html5/app/client/views/users/user_item.coffee b/bigbluebutton-html5/app/client/views/users/user_item.coffee index d9e7779ea6..24f33884fe 100755 --- a/bigbluebutton-html5/app/client/views/users/user_item.coffee +++ b/bigbluebutton-html5/app/client/views/users/user_item.coffee @@ -9,16 +9,3 @@ Template.displayUserIcons.events # the userId of the person who is lowering the hand console.log "lower hand- client click handler" Meteor.call('userLowerHand', getInSession("meetingId"), @userId, getInSession("userId"), getInSession("authToken")) - -Template.displayUserIcons.helpers - userLockedIconApplicable: (userId) -> - # the lock settings affect the user (and requiire a lock icon) if - # the user is set to be locked and there is a relevant lock in place - locked = BBB.getUser(userId)?.user.locked - settings = Meteor.Meetings.findOne()?.roomLockSettings - lockInAction = settings.disablePrivChat or - settings.disableCam or - settings.disableMic or - settings.lockedLayout or - settings.disablePubChat - return locked and lockInAction diff --git a/bigbluebutton-html5/app/client/views/users/user_item.html b/bigbluebutton-html5/app/client/views/users/user_item.html index 18df7410fd..14efb5fcd9 100755 --- a/bigbluebutton-html5/app/client/views/users/user_item.html +++ b/bigbluebutton-html5/app/client/views/users/user_item.html @@ -1,39 +1,36 @@ + + <template name="displayUserIcons"> {{#if isUserSharingVideo userId}} <span class="userListSettingIcon glyphicon glyphicon-facetime-video" rel="tooltip" data-placement="bottom" title="{{user.name}} is sharing their webcam"></span> {{/if}} - {{#if isUserInAudio userId}} - <!-- if the user is listen only, only display the one icon --> - {{#if isUserListenOnlyAudio userId}} - <span class="userListSettingIcon glyphicon glyphicon-headphones" title="Listening only"></span> - {{else}} - {{#if isCurrentUser userId}} - {{#if isUserMuted userId}} - <span class="muteIcon userListSettingIcon glyphicon glyphicon-volume-off" rel="tooltip" data-placement="bottom" title="Unmute yourself"></span> + {{#if isUserSharingAudio userId}} + {{#if isCurrentUser userId}} + {{#if isUserMuted userId}} + <span class="muteIcon userListSettingIcon glyphicon glyphicon-volume-off" rel="tooltip" data-placement="bottom" title="Unmute yourself"></span> + {{else}} + {{#if isCurrentUserTalking}} + <span class="muteIcon userListSettingIcon glyphicon glyphicon-volume-up" rel="tooltip" data-placement="bottom" title="is talking"></span> {{else}} - {{#if isCurrentUserTalking}} - <span class="muteIcon userListSettingIcon glyphicon glyphicon-volume-up" rel="tooltip" data-placement="bottom" title="is talking"></span> - {{else}} - <span class="muteIcon userListSettingIcon glyphicon glyphicon-volume-down" rel="tooltip" data-placement="bottom" title="is not talking"></span> - {{/if}} + <span class="muteIcon userListSettingIcon glyphicon glyphicon-volume-down" rel="tooltip" data-placement="bottom" title="is not talking"></span> {{/if}} + {{/if}} + {{else}} + {{#if isUserMuted userId}} + <span class="userListSettingIcon glyphicon glyphicon-volume-off" rel="tooltip" data-placement="bottom" title="{{user.name}} is muted"></span> {{else}} - {{#if isUserMuted userId}} - <span class="userListSettingIcon glyphicon glyphicon-volume-off" rel="tooltip" data-placement="bottom" title="{{user.name}} is muted"></span> + {{#if isUserTalking userId}} + <span class="userListSettingIcon glyphicon glyphicon-volume-up" rel="tooltip" data-placement="bottom" title="{{user.name}} is talking"></span> {{else}} - {{#if isUserTalking userId}} - <span class="userListSettingIcon glyphicon glyphicon-volume-up" rel="tooltip" data-placement="bottom" title="{{user.name}} is talking"></span> - {{else}} - <span class="userListSettingIcon glyphicon glyphicon-volume-down" rel="tooltip" data-placement="bottom" title="{{user.name}} is not talking"></span> - {{/if}} + <span class="userListSettingIcon glyphicon glyphicon-volume-down" rel="tooltip" data-placement="bottom" title="{{user.name}} is not talking"></span> {{/if}} {{/if}} {{/if}} {{/if}} - {{#if userLockedIconApplicable userId}} - <span class="userListSettingIcon glyphicon ion-locked" rel="tooltip" data-placement="bottom" title="The viewer is locked"></span> + {{#if isUserListenOnly userId}} + <span class="userListSettingIcon glyphicon glyphicon-headphones" title="Listening only"></span> {{/if}} {{#if user.presenter}} diff --git a/bigbluebutton-html5/app/client/views/users/user_list.coffee b/bigbluebutton-html5/app/client/views/users/user_list.coffee index c6484a6b63..96d0fbcb2c 100755 --- a/bigbluebutton-html5/app/client/views/users/user_list.coffee +++ b/bigbluebutton-html5/app/client/views/users/user_list.coffee @@ -1,6 +1,3 @@ Template.usersList.helpers - getInfoNumberOfUsers: -> - numberUsers = Meteor.Users.find().count() - if numberUsers > 8 - return "Users: #{numberUsers}" - # do not display the label if there are just a few users + getMeetingSize: -> # Retreieve the number of users in the chat, or "error" string + return Meteor.Users.find().count() diff --git a/bigbluebutton-html5/app/client/views/users/users_list.html b/bigbluebutton-html5/app/client/views/users/users_list.html index b245379dcb..4c9ec13d95 100755 --- a/bigbluebutton-html5/app/client/views/users/users_list.html +++ b/bigbluebutton-html5/app/client/views/users/users_list.html @@ -1,6 +1,6 @@ <template name="usersList"> <div id="{{id}}" {{visibility name}} class="component"> - <h3 class="title gradientBar"><span class="glyphicon glyphicon-user heading"></span> {{getInfoNumberOfUsers}} </h3> + <h3 class="title gradientBar"><span class="glyphicon glyphicon-user"></span> Participants: {{getMeetingSize}} User(s)</h3> <div id="user-contents"> <div class="userlist ScrollableWindowY"> diff --git a/bigbluebutton-html5/app/client/views/whiteboard/whiteboard.html b/bigbluebutton-html5/app/client/views/whiteboard/whiteboard.html index 7288c5f721..56f6213dd7 100755 --- a/bigbluebutton-html5/app/client/views/whiteboard/whiteboard.html +++ b/bigbluebutton-html5/app/client/views/whiteboard/whiteboard.html @@ -4,7 +4,7 @@ {{#if isMobileChromeOrFirefox}} {{> makeButton btn_class="fullscreenWhiteboardButton" i_class="glyphicon glyphicon-fullscreen"}} {{/if}} - <span class="ion-easel heading"></span> + <span class="glyphicon glyphicon-pencil"></span> {{title}} </h3> {{#each getCurrentSlide}} diff --git a/bigbluebutton-html5/app/config.coffee b/bigbluebutton-html5/app/config.coffee index cc606108e8..84bfbf1028 100755 --- a/bigbluebutton-html5/app/config.coffee +++ b/bigbluebutton-html5/app/config.coffee @@ -14,8 +14,6 @@ config.defaultWelcomeMessageFooter = "This server is running a build of <a href= config.maxUsernameLength = 30 config.maxChatLength = 140 -config.lockOnJoin = true - ## Application configurations config.app = {} @@ -23,11 +21,6 @@ config.app = {} config.app.mobileFont = 24 config.app.desktopFont = 12 -# Will offer the user to join the audio when entering the meeting -config.app.autoJoinAudio = false -# The amount of time the client will wait before making another call to successfully hangup the WebRTC conference call -config.app.WebRTCHangupRetryInterval = 2000 - # Configs for redis config.redis = {} config.redis.host = "127.0.0.1" diff --git a/bigbluebutton-html5/app/lib/router.coffee b/bigbluebutton-html5/app/lib/router.coffee old mode 100755 new mode 100644 diff --git a/bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.ttf b/bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.ttf old mode 100755 new mode 100644 index c4e4632486d863337c1c73478ddb3c20726c55a0..f8fcf261a6b2501cb5ede90e5f3d371452c64156 GIT binary patch delta 41416 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 F{{xk+r)dBH delta 90427 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 diff --git a/bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.woff b/bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.woff old mode 100755 new mode 100644 index 5f3a14e0a5ca6d20cc4fac708979e807b0d51bc3..9f808a3cdddbe92050fc02ac0e9251c17d40687d GIT binary patch literal 48380 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 WM$HDDJr4F@C~lyDh^9hLf&4FrLCJFf literal 67904 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%0AjtaE3L?b-A8{e$5;po!K>rWi&$<6F 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 E0LEz`i~s-t diff --git a/bigbluebutton-html5/app/server/collection_methods/meetings.coffee b/bigbluebutton-html5/app/server/collection_methods/meetings.coffee index 00d2acc142..348d08bd74 100755 --- a/bigbluebutton-html5/app/server/collection_methods/meetings.coffee +++ b/bigbluebutton-html5/app/server/collection_methods/meetings.coffee @@ -2,27 +2,17 @@ # Private methods on server # -------------------------------------------------------------------------------------------- @addMeetingToCollection = (meetingId, name, intendedForRecording, voiceConf, duration) -> - #check if the meeting is already in the collection - unless Meteor.Meetings.findOne({meetingId: meetingId})? - entry = - meetingId: meetingId - meetingName: name - intendedForRecording: intendedForRecording - currentlyBeingRecorded: false # defaut value - voiceConf: voiceConf - duration: duration - roomLockSettings: - # by default the lock settings will be disabled on meeting create - disablePrivChat: false - disableCam: false - disableMic: false - lockOnJoin: Meteor.config.lockOnJoin - lockedLayout: false - disablePubChat: false - - id = Meteor.Meetings.insert(entry) - Meteor.log.info "added meeting _id=[#{id}]:meetingId=[#{meetingId}]:name=[#{name}]:duration=[#{duration}]:voiceConf=[#{voiceConf}] - roomLockSettings:[#{JSON.stringify entry.roomLockSettings}]." + #check if the meeting is already in the collection + unless Meteor.Meetings.findOne({meetingId: meetingId})? + currentlyBeingRecorded = false # defaut value + id = Meteor.Meetings.insert( + meetingId: meetingId, + meetingName: name, + intendedForRecording: intendedForRecording, + currentlyBeingRecorded: currentlyBeingRecorded, + voiceConf: voiceConf, + duration: duration) + Meteor.log.info "added meeting _id=[#{id}]:meetingId=[#{meetingId}]:name=[#{name}]:duration=[#{duration}]:voiceConf=[#{voiceConf}]." @clearMeetingsCollection = (meetingId) -> @@ -32,7 +22,6 @@ Meteor.Meetings.remove({}, Meteor.log.info "cleared Meetings Collection (all meetings)!") -#clean up upon a meeting's end @removeMeetingFromCollection = (meetingId) -> if Meteor.Meetings.findOne({meetingId: meetingId})? Meteor.log.info "end of meeting #{meetingId}. Clear the meeting data from all collections" diff --git a/bigbluebutton-html5/app/server/collection_methods/users.coffee b/bigbluebutton-html5/app/server/collection_methods/users.coffee index 8b431dddb3..3b3980a09d 100755 --- a/bigbluebutton-html5/app/server/collection_methods/users.coffee +++ b/bigbluebutton-html5/app/server/collection_methods/users.coffee @@ -6,49 +6,6 @@ # immediately, since they do not require permission for things such as muting themsevles. # -------------------------------------------------------------------------------------------- Meteor.methods - # meetingId: the meetingId of the meeting the user is in - # toSetUserId: the userId of the user joining - # requesterUserId: the userId of the requester - # requesterToken: the authToken of the requester - listenOnlyRequestToggle: (meetingId, userId, authToken, isJoining) -> - voiceConf = Meteor.Meetings.findOne({meetingId:meetingId})?.voiceConf - username = Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.name - if isJoining - if isAllowedTo('joinListenOnly', meetingId, userId, authToken) - message = - payload: - userid: userId - meeting_id: meetingId - voice_conf: voiceConf - name: username - header: - timestamp: new Date().getTime() - name: "user_connected_to_global_audio" - version: "0.0.1" - - Meteor.log.info "publishing a user listenOnly toggleRequest #{isJoining} request for #{userId}" - - publish Meteor.config.redis.channels.toBBBApps.meeting, message - - else - if isAllowedTo('leaveListenOnly', meetingId, userId, authToken) - message = - payload: - userid: userId - meeting_id: meetingId - voice_conf: voiceConf - name: username - header: - timestamp: new Date().getTime() - name: "user_disconnected_from_global_audio" - version: "0.0.1" - - Meteor.log.info "publishing a user listenOnly toggleRequest #{isJoining} request for #{userId}" - - publish Meteor.config.redis.channels.toBBBApps.meeting, message - - return - # meetingId: the meetingId of the meeting the user[s] is in # toMuteUserId: the userId of the user to be [un]muted # requesterUserId: the userId of the requester @@ -160,6 +117,7 @@ Meteor.methods Meteor.log.info "marking user [#{userId}] as offline in meeting[#{meetingId}]" Meteor.Users.update({'meetingId': meetingId, 'userId': userId}, {$set:{'user.connection_status':'offline'}}) + # Corresponds to a valid action on the HTML clientside # After authorization, publish a user_leaving_request in redis # params: meetingid, userid as defined in BBB-App @@ -192,8 +150,8 @@ Meteor.methods Meteor.Users.update({meetingId: meetingId ,userId: voiceUserObject.web_userid}, {$set: {'user.voiceUser.locked':voiceUserObject.locked}}) # locked if voiceUserObject.muted? Meteor.Users.update({meetingId: meetingId ,userId: voiceUserObject.web_userid}, {$set: {'user.voiceUser.muted':voiceUserObject.muted}}) # muted - if voiceUserObject.listen_only? - Meteor.Users.update({meetingId: meetingId ,userId: voiceUserObject.web_userid}, {$set: {'user.listenOnly':voiceUserObject.listen_only}}) # listenOnly + if voiceUserObject.listenOnly? + Meteor.Users.update({meetingId: meetingId ,userId: voiceUserObject.web_userid}, {$set: {'user.listenOnly':voiceUserObject.listenOnly}}) # muted else Meteor.log.error "ERROR! did not find such voiceUser!" @@ -204,7 +162,7 @@ Meteor.methods # the collection already contains an entry for this user because # we added a dummy user on register_user_message (to save authToken) if u? - Meteor.log.info "UPDATING USER #{user.userid}, authToken=#{u.authToken}, locked=#{user.locked}" + Meteor.log.info "UPDATING USER #{user.userid}, authToken=#{u.authToken}" Meteor.Users.update({userId:user.userid, meetingId: meetingId}, {$set:{ user: userid: user.userid @@ -308,36 +266,6 @@ Meteor.methods Meteor.log.info "added user dummy html5 user with: userid=[#{userId}], id=[#{id}] Users.size is now #{Meteor.Users.find({meetingId: meetingId}).count()}" - -# when new lock settings including disableMic are set, -# all viewers that are in the audio bridge with a mic should be muted and locked -@handleLockingMic = (meetingId, newSettings) -> - # send mute requests for the viewer users joined with mic - for u in Meteor.Users.find({ - meetingId:meetingId - 'user.role':'VIEWER' - 'user.listenOnly':false - 'user.locked':true - 'user.voiceUser.joined':true - 'user.voiceUser.muted':false})?.fetch() - Meteor.log.error u.user.name # - Meteor.call('muteUser', meetingId, u.userId, u.userId, u.authToken, true) #true for muted - -# change the locked status of a user (lock settings) -@setUserLockedStatus = (meetingId, userId, isLocked) -> - if Meteor.Users.findOne({userId:userId, meetingId: meetingId})? - Meteor.Users.update({userId:userId, meetingId: meetingId}, {$set:{'user.locked': isLocked}}) - - # if the user is sharing audio, he should be muted upon locking involving disableMic - u = Meteor.Users.findOne({meetingId:meetingId, userId:userId}) - if u.user.role is 'VIEWER' and !u.user.listenOnly and u.user.voiceUser.joined and !u.user.voiceUser.muted and isLocked - Meteor.call('muteUser', meetingId, u.userId, u.userId, u.authToken, true) #true for muted - - Meteor.log.info "setting user locked status for userid:[#{userId}] from [#{meetingId}] locked=#{isLocked}" - else - Meteor.log.error "(unsuccessful-no such user) setting user locked status for userid:[#{userId}] from [#{meetingId}] locked=#{isLocked}" - - # called on server start and on meeting end @clearUsersCollection = (meetingId) -> if meetingId? diff --git a/bigbluebutton-html5/app/server/redispubsub.coffee b/bigbluebutton-html5/app/server/redispubsub.coffee index 3d81454bb1..21ae697e00 100755 --- a/bigbluebutton-html5/app/server/redispubsub.coffee +++ b/bigbluebutton-html5/app/server/redispubsub.coffee @@ -1,4 +1,8 @@ Meteor.methods + # + # I dont know if this is okay to be server side. We need to call it from the router, but I don't know if any harm can be caused + # by the client calling this + # # Construct and send a message to bbb-web to validate the user validateAuthToken: (meetingId, userId, authToken) -> @@ -56,45 +60,29 @@ class Meteor.RedisPubSub correlationId = message.payload?.reply_to or message.header?.reply_to meetingId = message.payload?.meeting_id - # just because it's common. we handle it anyway - notLoggedEventTypes = [ + ignoredEventTypes = [ "keep_alive_reply" "page_resized_message" "presentation_page_resized_message" - "presentation_cursor_updated_message" - "get_presentation_info_reply" - # "get_users_reply" - "get_chat_history_reply" - "get_all_meetings_reply" - "presentation_shared_message" - "presentation_conversion_done_message" - "presentation_conversion_progress_message" - "presentation_page_generated_message" - "presentation_page_changed_message" + "presentation_cursor_updated_message" # just because it's common. we handle it anyway ] if message?.header? and message?.payload? - unless message.header.name in notLoggedEventTypes + unless message.header.name in ignoredEventTypes Meteor.log.info "eventType= #{message.header.name} ", message: jsonMsg # handle voice events if message.header.name in ['user_left_voice_message', 'user_joined_voice_message', 'user_voice_talking_message', 'user_voice_muted_message'] - if message.payload.user? - updateVoiceUser meetingId, - 'web_userid': message.payload.user.voiceUser.web_userid - 'listen_only': message.payload.listen_only - 'talking': message.payload.user.voiceUser.talking - 'joined': message.payload.user.voiceUser.joined - 'locked': message.payload.user.voiceUser.locked - 'muted': message.payload.user.voiceUser.muted + voiceUser = message.payload.user?.voiceUser + updateVoiceUser meetingId, voiceUser return # listen only if message.header.name is 'user_listening_only' - updateVoiceUser meetingId, {'web_userid': message.payload.userid, 'listen_only': message.payload.listen_only} + updateVoiceUser meetingId, {'web_userid': message.payload.userid, 'listenOnly': message.payload.listen_only} # most likely we don't need to ensure that the user's voiceUser's {talking, joined, muted, locked} are false by default #TODO? - return + return if message.header.name is "get_all_meetings_reply" Meteor.log.info "Let's store some data for the running meetings so that when an HTML5 client joins everything is ready!" @@ -287,37 +275,6 @@ class Meteor.RedisPubSub Meteor.Meetings.update({meetingId: meetingId, intendedForRecording: intendedForRecording}, {$set: {currentlyBeingRecorded: currentlyBeingRecorded}}) return - # -------------------------------------------------- - # lock settings ------------------------------------ - if message.header.name is "eject_voice_user_message" - console.log "\n111111111" - return - - if message.header.name is "new_permission_settings" - oldSettings = Meteor.Meetings.findOne({meetingId:meetingId})?.roomLockSettings - newSettings = message.payload - - # if the disableMic setting was turned on - if !oldSettings?.disableMic and newSettings.disableMic - handleLockingMic(meetingId, newSettings) - - # substitute with the new lock settings - Meteor.Meetings.update({meetingId: meetingId}, {$set: { - 'roomLockSettings.disablePrivChat': message.payload.disablePrivChat - 'roomLockSettings.disableCam': message.payload.disableCam - 'roomLockSettings.disableMic': message.payload.disableMic - 'roomLockSettings.lockOnJoin': message.payload.lockOnJoin - 'roomLockSettings.lockedLayout': message.payload.lockedLayout - 'roomLockSettings.disablePubChat': message.payload.disablePubChat - }}) - return - - if message.header.name is "user_locked_message" or message.header.name is "user_unlocked_message" - userId = message.payload.userid - isLocked = message.payload.locked - setUserLockedStatus(meetingId, userId, isLocked) - return - if message.header.name in ["meeting_ended_message", "meeting_destroyed_event", "end_and_kick_all_message", "disconnect_all_users_message"] if Meteor.Meetings.findOne({meetingId: meetingId})? @@ -335,9 +292,9 @@ class Meteor.RedisPubSub # message should be an object @publish = (channel, message) -> - # Meteor.log.info "Publishing", - # channel: channel - # message: message + Meteor.log.info "Publishing", + channel: channel + message: message if Meteor.redisPubSub? Meteor.redisPubSub.pubClient.publish channel, JSON.stringify(message), (err, res) -> diff --git a/bigbluebutton-html5/app/server/user_permissions.coffee b/bigbluebutton-html5/app/server/user_permissions.coffee old mode 100755 new mode 100644 index ce3962ad81..43a422767c --- a/bigbluebutton-html5/app/server/user_permissions.coffee +++ b/bigbluebutton-html5/app/server/user_permissions.coffee @@ -1,16 +1,8 @@ presenter = null -# holds the values for whether the moderator user is allowed to perform an action (true) -# or false if not allowed. Some actions have dynamic values depending on the current lock settings +#for the time being moderators have the same permissions that viewers do moderator = - # audio listen only - joinListenOnly: true - leaveListenOnly: true - - # join audio with mic cannot be controlled on the server side as it is - # a client side only functionality - # raising/lowering hand raiseOwnHand : true lowerOwnHand : true @@ -26,29 +18,18 @@ moderator = subscribeChat: true #chat - chatPublic: true - chatPrivate: true - - -# holds the values for whether the viewer user is allowed to perform an action (true) -# or false if not allowed. Some actions have dynamic values depending on the current lock settings -viewer = (meetingId, userId) -> + chatPublic: true #should make this dynamically modifiable later on + chatPrivate: true #should make this dynamically modifiable later on - # listen only - joinListenOnly: true - leaveListenOnly: true - - # join audio with mic cannot be controlled on the server side as it is - # a client side only functionality +viewer = # raising/lowering hand raiseOwnHand : true lowerOwnHand : true # muting muteSelf : true - unmuteSelf : !(Meteor.Meetings.findOne({meetingId:meetingId})?.roomLockSettings.disableMic) or - !(Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.locked) + unmuteSelf : true logoutSelf : true @@ -57,18 +38,11 @@ viewer = (meetingId, userId) -> subscribeChat: true #chat - chatPublic: !(Meteor.Meetings.findOne({meetingId:meetingId})?.roomLockSettings.disablePubChat) or - !(Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.locked) or - Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.presenter - chatPrivate: !(Meteor.Meetings.findOne({meetingId:meetingId})?.roomLockSettings.disablePrivChat) or - !(Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.locked) or - Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.presenter - - + chatPublic: true #should make this dynamically modifiable later on + chatPrivate: true #should make this dynamically modifiable later on -# carries out the decision making for actions affecting users. For the list of -# actions and the default value - see 'viewer' and 'moderator' in the beginning of the file @isAllowedTo = (action, meetingId, userId, authToken) -> + # Disclaimer:the current version of the HTML5 client represents only VIEWER users validated = Meteor.Users.findOne({meetingId:meetingId, userId: userId})?.validated Meteor.log.info "in isAllowedTo: action-#{action}, userId=#{userId}, authToken=#{authToken} validated:#{validated}" @@ -78,7 +52,7 @@ viewer = (meetingId, userId) -> if user? and authToken is user.authToken # check if the user is who he claims to be if user.validated and user.clientType is "HTML5" if user.user?.role is 'VIEWER' or user.user?.role is 'MODERATOR' or user.user?.role is undefined - return viewer(meetingId, userId)[action] or false + return viewer[action] or false else Meteor.log.warn "UNSUCCESSFULL ATTEMPT FROM userid=#{userId} to perform:#{action}" return false diff --git a/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy b/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy index 791e6f6c79..021c97785e 100644 --- a/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy +++ b/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy @@ -1,183 +1,183 @@ -/** -* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ -* -* Copyright (c) 2014 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.web.services - -import java.util.concurrent.*; -import java.lang.InterruptedException -import org.bigbluebutton.presentation.DocumentConversionService -import org.bigbluebutton.presentation.UploadedPresentation - -class PresentationService { - - static transactional = false - DocumentConversionService documentConversionService - def presentationDir - def testConferenceMock - def testRoomMock - def testPresentationName - def testUploadedPresentation - def defaultUploadedPresentation - def presentationBaseUrl - - def deletePresentation = {conf, room, filename -> - def directory = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + filename) - deleteDirectory(directory) - } - - def deleteDirectory = {directory -> - log.debug "delete = ${directory}" - /** - * Go through each directory and check if it's not empty. - * We need to delete files inside a directory before a - * directory can be deleted. - **/ - File[] files = directory.listFiles(); - for (int i = 0; i < files.length; i++) { - if (files[i].isDirectory()) { - deleteDirectory(files[i]) - } else { - files[i].delete() - } - } - // Now that the directory is empty. Delete it. - directory.delete() - } - - def listPresentations = {conf, room -> - def presentationsList = [] - def directory = roomDirectory(conf, room) - log.debug "directory ${directory.absolutePath}" - if( directory.exists() ){ - directory.eachFile(){ file-> - System.out.println(file.name) - if( file.isDirectory() ) - presentationsList.add( file.name ) - } - } - return presentationsList - } - - def getPresentationDir = { - return presentationDir - } - - def processUploadedPresentation = {uploadedPres -> - // Run conversion on another thread. - Timer t = new Timer(uploadedPres.getName(), false) - - t.runAfter(1000) { - try { - documentConversionService.processDocument(uploadedPres) - } finally { - t.cancel() - } - } - } - - def showSlide(String conf, String room, String presentationName, String id) { - new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + "slide-${id}.swf") - } - - def showPngImage(String conf, String room, String presentationName, String id) { - new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + "pngs" + File.separatorChar + "slide${id}.png") - } - - def showPresentation = {conf, room, filename -> - new File(roomDirectory(conf, room).absolutePath + File.separatorChar + filename + File.separatorChar + "slides.swf") - } - - def showThumbnail = {conf, room, presentationName, thumb -> - println "Show thumbnails request for $presentationName $thumb" - def thumbFile = roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + - "thumbnails" + File.separatorChar + "thumb-${thumb}.png" - log.debug "showing $thumbFile" - - new File(thumbFile) - } - - def showTextfile = {conf, room, presentationName, textfile -> - println "Show textfiles request for $presentationName $textfile" - def txt = roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + - "textfiles" + File.separatorChar + "slide-${textfile}.txt" - log.debug "showing $txt" - - new File(txt) - } - - def numberOfThumbnails = {conf, room, name -> - def thumbDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "thumbnails") - thumbDir.listFiles().length - } - - def numberOfPngs = {conf, room, name -> - def PngsDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "pngs") - PngsDir.listFiles().length - } - - def numberOfTextfiles = {conf, room, name -> - log.debug roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "textfiles" - def textfilesDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "textfiles") - textfilesDir.listFiles().length - } - - def roomDirectory = {conf, room -> - return new File(presentationDir + File.separatorChar + conf + File.separatorChar + room) - } - - def testConversionProcess() { - File presDir = new File(roomDirectory(testConferenceMock, testRoomMock).absolutePath + File.separatorChar + testPresentationName) - - if (presDir.exists()) { - File pres = new File(presDir.getAbsolutePath() + File.separatorChar + testUploadedPresentation) - if (pres.exists()) { - UploadedPresentation uploadedPres = new UploadedPresentation(testConferenceMock, testRoomMock, testPresentationName); - uploadedPres.setUploadedFile(pres); - // Run conversion on another thread. - new Timer().runAfter(1000) - { - documentConversionService.processDocument(uploadedPres) - } - } else { - log.error "${pres.absolutePath} does NOT exist" - } - } else { - log.error "${presDir.absolutePath} does NOT exist." - } - - } - - def getFile = {conf, room, presentationName -> - println "download request for $presentationName" - def fileDirectory = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + -"download") - //list the files of the download directory ; it must have only 1 file to download - def list = fileDirectory.listFiles() - //new File(pdfFile) - list[0] - } -} - -/*** Helper classes **/ -import java.io.FilenameFilter; -import java.io.File; -class PngFilter implements FilenameFilter { - public boolean accept(File dir, String name) { - return (name.endsWith(".png")); - } -} +/** +* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ +* +* Copyright (c) 2014 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.web.services + +import java.util.concurrent.*; +import java.lang.InterruptedException +import org.bigbluebutton.presentation.DocumentConversionService +import org.bigbluebutton.presentation.UploadedPresentation + +class PresentationService { + + static transactional = false + DocumentConversionService documentConversionService + def presentationDir + def testConferenceMock + def testRoomMock + def testPresentationName + def testUploadedPresentation + def defaultUploadedPresentation + def presentationBaseUrl + + def deletePresentation = {conf, room, filename -> + def directory = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + filename) + deleteDirectory(directory) + } + + def deleteDirectory = {directory -> + log.debug "delete = ${directory}" + /** + * Go through each directory and check if it's not empty. + * We need to delete files inside a directory before a + * directory can be deleted. + **/ + File[] files = directory.listFiles(); + for (int i = 0; i < files.length; i++) { + if (files[i].isDirectory()) { + deleteDirectory(files[i]) + } else { + files[i].delete() + } + } + // Now that the directory is empty. Delete it. + directory.delete() + } + + def listPresentations = {conf, room -> + def presentationsList = [] + def directory = roomDirectory(conf, room) + log.debug "directory ${directory.absolutePath}" + if( directory.exists() ){ + directory.eachFile(){ file-> + System.out.println(file.name) + if( file.isDirectory() ) + presentationsList.add( file.name ) + } + } + return presentationsList + } + + def getPresentationDir = { + return presentationDir + } + + def processUploadedPresentation = {uploadedPres -> + // Run conversion on another thread. + Timer t = new Timer(uploadedPres.getName(), false) + + t.runAfter(1000) { + try { + documentConversionService.processDocument(uploadedPres) + } finally { + t.cancel() + } + } + } + + def showSlide(String conf, String room, String presentationName, String id) { + new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + "slide-${id}.swf") + } + + def showPngImage(String conf, String room, String presentationName, String id) { + new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + "pngs" + File.separatorChar + "slide${id}.png") + } + + def showPresentation = {conf, room, filename -> + new File(roomDirectory(conf, room).absolutePath + File.separatorChar + filename + File.separatorChar + "slides.swf") + } + + def showThumbnail = {conf, room, presentationName, thumb -> + println "Show thumbnails request for $presentationName $thumb" + def thumbFile = roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + + "thumbnails" + File.separatorChar + "thumb-${thumb}.png" + log.debug "showing $thumbFile" + + new File(thumbFile) + } + + def showTextfile = {conf, room, presentationName, textfile -> + println "Show textfiles request for $presentationName $textfile" + def txt = roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + + "textfiles" + File.separatorChar + "slide-${textfile}.txt" + log.debug "showing $txt" + + new File(txt) + } + + def numberOfThumbnails = {conf, room, name -> + def thumbDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "thumbnails") + thumbDir.listFiles().length + } + + def numberOfPngs = {conf, room, name -> + def PngsDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "pngs") + PngsDir.listFiles().length + } + + def numberOfTextfiles = {conf, room, name -> + log.debug roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "textfiles" + def textfilesDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "textfiles") + textfilesDir.listFiles().length + } + + def roomDirectory = {conf, room -> + return new File(presentationDir + File.separatorChar + conf + File.separatorChar + room) + } + + def testConversionProcess() { + File presDir = new File(roomDirectory(testConferenceMock, testRoomMock).absolutePath + File.separatorChar + testPresentationName) + + if (presDir.exists()) { + File pres = new File(presDir.getAbsolutePath() + File.separatorChar + testUploadedPresentation) + if (pres.exists()) { + UploadedPresentation uploadedPres = new UploadedPresentation(testConferenceMock, testRoomMock, testPresentationName); + uploadedPres.setUploadedFile(pres); + // Run conversion on another thread. + new Timer().runAfter(1000) + { + documentConversionService.processDocument(uploadedPres) + } + } else { + log.error "${pres.absolutePath} does NOT exist" + } + } else { + log.error "${presDir.absolutePath} does NOT exist." + } + + } + + def getFile = {conf, room, presentationName -> + println "download request for $presentationName" + def fileDirectory = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + +"download") + //list the files of the download directory ; it must have only 1 file to download + def list = fileDirectory.listFiles() + //new File(pdfFile) + list[0] + } +} + +/*** Helper classes **/ +import java.io.FilenameFilter; +import java.io.File; +class PngFilter implements FilenameFilter { + public boolean accept(File dir, String name) { + return (name.endsWith(".png")); + } +} diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MeetingMessageHandler.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MeetingMessageHandler.java index df6037d137..596d20747b 100755 --- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MeetingMessageHandler.java +++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MeetingMessageHandler.java @@ -181,7 +181,7 @@ public class MeetingMessageHandler implements MessageHandler { listener.handle(new UserRoleChanged(meetingId, userid, role)); } } - } + } } } } diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingConstants.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingConstants.java index 33cc69c1dd..1cc4570828 100755 --- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingConstants.java +++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingConstants.java @@ -53,6 +53,7 @@ public class MessagingConstants { public static final String USER_SHARE_WEBCAM_EVENT = "user_shared_webcam_message"; public static final String USER_UNSHARE_WEBCAM_EVENT = "user_unshared_webcam_message"; public static final String USER_ROLE_CHANGE_EVENT = "user_role_changed_message"; + public static final String SEND_POLLS_EVENT = "SendPollsEvent"; public static final String KEEP_ALIVE_REPLY = "keep_alive_reply"; -- GitLab