Browse Source

Merge pull request #593 from jitsi/custom-role-recorder-view

Add custom-role to presence and special view for Recorders
j8
hristoterezov 9 years ago
parent
commit
a8aa62b075

+ 58
- 54
conference.js View File

21
 
21
 
22
 let room, connection, localAudio, localVideo, roomLocker;
22
 let room, connection, localAudio, localVideo, roomLocker;
23
 
23
 
24
-/**
25
- * Known custom conference commands.
26
- */
27
-const Commands = {
28
-    CONNECTION_QUALITY: "stats",
29
-    EMAIL: "email",
30
-    ETHERPAD: "etherpad",
31
-    SHARED_VIDEO: "shared-video"
32
-};
33
-
34
 import {VIDEO_CONTAINER_TYPE} from "./modules/UI/videolayout/LargeVideo";
24
 import {VIDEO_CONTAINER_TYPE} from "./modules/UI/videolayout/LargeVideo";
35
 
25
 
36
 /**
26
 /**
52
 
42
 
53
 /**
43
 /**
54
  * Share email with other users.
44
  * Share email with other users.
45
+ * @param emailCommand the email command
55
  * @param {string} email new email
46
  * @param {string} email new email
56
  */
47
  */
57
-function sendEmail (email) {
58
-    room.sendCommand(Commands.EMAIL, {
48
+function sendEmail (emailCommand, email) {
49
+    room.sendCommand(emailCommand, {
59
         value: email,
50
         value: email,
60
         attributes: {
51
         attributes: {
61
             id: room.myUserId()
52
             id: room.myUserId()
507
     getLogs () {
498
     getLogs () {
508
         return room.getLogs();
499
         return room.getLogs();
509
     },
500
     },
510
-    _createRoom (localTracks) {
511
-        room = connection.initJitsiConference(APP.conference.roomName,
512
-            this._getConferenceOptions());
513
-        this.localId = room.myUserId();
514
-        localTracks.forEach((track) => {
515
-            if (track.isAudioTrack()) {
516
-                this.useAudioStream(track);
517
-            } else if (track.isVideoTrack()) {
518
-                this.useVideoStream(track);
519
-            }
520
-        });
521
-        roomLocker = createRoomLocker(room);
522
-        this._room = room; // FIXME do not use this
523
-
524
-        let email = APP.settings.getEmail();
525
-        email && sendEmail(email);
526
-
527
-        let nick = APP.settings.getDisplayName();
528
-        if (config.useNicks && !nick) {
529
-            nick = APP.UI.askForNickname();
530
-            APP.settings.setDisplayName(nick);
531
-        }
532
-        nick && room.setDisplayName(nick);
533
-
534
-        this._setupListeners();
535
-    },
536
 
501
 
537
     /**
502
     /**
538
      * Exposes a Command(s) API on this instance. It is necessitated by (1) the
503
      * Exposes a Command(s) API on this instance. It is necessitated by (1) the
544
      * API of this instance.
509
      * API of this instance.
545
      */
510
      */
546
     commands: {
511
     commands: {
512
+        /**
513
+         * Known custom conference commands.
514
+         */
515
+        defaults: {
516
+            CONNECTION_QUALITY: "stats",
517
+            EMAIL: "email",
518
+            ETHERPAD: "etherpad",
519
+            SHARED_VIDEO: "shared-video",
520
+            CUSTOM_ROLE: "custom-role"
521
+        },
547
         /**
522
         /**
548
          * Receives notifications from other participants about commands aka
523
          * Receives notifications from other participants about commands aka
549
          * custom events (sent by sendCommand or sendCommandOnce methods).
524
          * custom events (sent by sendCommand or sendCommandOnce methods).
550
          * @param command {String} the name of the command
525
          * @param command {String} the name of the command
551
          * @param handler {Function} handler for the command
526
          * @param handler {Function} handler for the command
552
          */
527
          */
553
-        addCommandListener () {
528
+            addCommandListener () {
554
             room.addCommandListener.apply(room, arguments);
529
             room.addCommandListener.apply(room, arguments);
555
         },
530
         },
556
         /**
531
         /**
557
          * Removes command.
532
          * Removes command.
558
          * @param name {String} the name of the command.
533
          * @param name {String} the name of the command.
559
          */
534
          */
560
-        removeCommand () {
535
+            removeCommand () {
561
             room.removeCommand.apply(room, arguments);
536
             room.removeCommand.apply(room, arguments);
562
         },
537
         },
563
         /**
538
         /**
565
          * @param name {String} the name of the command.
540
          * @param name {String} the name of the command.
566
          * @param values {Object} with keys and values that will be sent.
541
          * @param values {Object} with keys and values that will be sent.
567
          */
542
          */
568
-        sendCommand () {
543
+            sendCommand () {
569
             room.sendCommand.apply(room, arguments);
544
             room.sendCommand.apply(room, arguments);
570
         },
545
         },
571
         /**
546
         /**
573
          * @param name {String} the name of the command.
548
          * @param name {String} the name of the command.
574
          * @param values {Object} with keys and values that will be sent.
549
          * @param values {Object} with keys and values that will be sent.
575
          */
550
          */
576
-        sendCommandOnce () {
551
+            sendCommandOnce () {
577
             room.sendCommandOnce.apply(room, arguments);
552
             room.sendCommandOnce.apply(room, arguments);
578
-        },
553
+        }
554
+    },
555
+
556
+    _createRoom (localTracks) {
557
+        room = connection.initJitsiConference(APP.conference.roomName,
558
+            this._getConferenceOptions());
559
+        this.localId = room.myUserId();
560
+        localTracks.forEach((track) => {
561
+            if (track.isAudioTrack()) {
562
+                this.useAudioStream(track);
563
+            } else if (track.isVideoTrack()) {
564
+                this.useVideoStream(track);
565
+            }
566
+        });
567
+        roomLocker = createRoomLocker(room);
568
+        this._room = room; // FIXME do not use this
569
+
570
+        let email = APP.settings.getEmail();
571
+        email && sendEmail(this.commands.defaults.EMAIL, email);
572
+
573
+        let nick = APP.settings.getDisplayName();
574
+        if (config.useNicks && !nick) {
575
+            nick = APP.UI.askForNickname();
576
+            APP.settings.setDisplayName(nick);
577
+        }
578
+        nick && room.setDisplayName(nick);
579
+
580
+        this._setupListeners();
579
     },
581
     },
580
 
582
 
581
     _getConferenceOptions() {
583
     _getConferenceOptions() {
916
                 APP.UI.updateLocalStats(percent, stats);
918
                 APP.UI.updateLocalStats(percent, stats);
917
 
919
 
918
                 // send local stats to other users
920
                 // send local stats to other users
919
-                room.sendCommandOnce(Commands.CONNECTION_QUALITY, {
921
+                room.sendCommandOnce(this.commands.defaults.CONNECTION_QUALITY,
922
+                {
920
                     children: ConnectionQuality.convertToMUCStats(stats),
923
                     children: ConnectionQuality.convertToMUCStats(stats),
921
                     attributes: {
924
                     attributes: {
922
                         xmlns: 'http://jitsi.org/jitmeet/stats'
925
                         xmlns: 'http://jitsi.org/jitmeet/stats'
926
         );
929
         );
927
 
930
 
928
         // listen to remote stats
931
         // listen to remote stats
929
-        room.addCommandListener(Commands.CONNECTION_QUALITY,(values, from) => {
930
-            ConnectionQuality.updateRemoteStats(from, values);
932
+        room.addCommandListener(this.commands.defaults.CONNECTION_QUALITY,
933
+            (values, from) => {
934
+                ConnectionQuality.updateRemoteStats(from, values);
931
         });
935
         });
932
 
936
 
933
         ConnectionQuality.addListener(CQEvents.REMOTESTATS_UPDATED,
937
         ConnectionQuality.addListener(CQEvents.REMOTESTATS_UPDATED,
935
                 APP.UI.updateRemoteStats(id, percent, stats);
939
                 APP.UI.updateRemoteStats(id, percent, stats);
936
             });
940
             });
937
 
941
 
938
-        room.addCommandListener(Commands.ETHERPAD, ({value}) => {
942
+        room.addCommandListener(this.commands.defaults.ETHERPAD, ({value}) => {
939
             APP.UI.initEtherpad(value);
943
             APP.UI.initEtherpad(value);
940
         });
944
         });
941
 
945
 
948
 
952
 
949
             APP.settings.setEmail(email);
953
             APP.settings.setEmail(email);
950
             APP.UI.setUserAvatar(room.myUserId(), email);
954
             APP.UI.setUserAvatar(room.myUserId(), email);
951
-            sendEmail(email);
955
+            sendEmail(this.commands.defaults.EMAIL, email);
952
         });
956
         });
953
-        room.addCommandListener(Commands.EMAIL, (data) => {
957
+        room.addCommandListener(this.commands.defaults.EMAIL, (data) => {
954
             APP.UI.setUserAvatar(data.attributes.id, data.value);
958
             APP.UI.setUserAvatar(data.attributes.id, data.value);
955
         });
959
         });
956
 
960
 
1095
             // send start and stop commands once, and remove any updates
1099
             // send start and stop commands once, and remove any updates
1096
             // that had left
1100
             // that had left
1097
             if (state === 'stop' || state === 'start' || state === 'playing') {
1101
             if (state === 'stop' || state === 'start' || state === 'playing') {
1098
-                room.removeCommand(Commands.SHARED_VIDEO);
1099
-                room.sendCommandOnce(Commands.SHARED_VIDEO, {
1102
+                room.removeCommand(this.commands.defaults.SHARED_VIDEO);
1103
+                room.sendCommandOnce(this.commands.defaults.SHARED_VIDEO, {
1100
                     value: url,
1104
                     value: url,
1101
                     attributes: {
1105
                     attributes: {
1102
                         state: state,
1106
                         state: state,
1108
             else {
1112
             else {
1109
                 // in case of paused, in order to allow late users to join
1113
                 // in case of paused, in order to allow late users to join
1110
                 // paused
1114
                 // paused
1111
-                room.removeCommand(Commands.SHARED_VIDEO);
1112
-                room.sendCommand(Commands.SHARED_VIDEO, {
1115
+                room.removeCommand(this.commands.defaults.SHARED_VIDEO);
1116
+                room.sendCommand(this.commands.defaults.SHARED_VIDEO, {
1113
                     value: url,
1117
                     value: url,
1114
                     attributes: {
1118
                     attributes: {
1115
                         state: state,
1119
                         state: state,
1120
             }
1124
             }
1121
         });
1125
         });
1122
         room.addCommandListener(
1126
         room.addCommandListener(
1123
-            Commands.SHARED_VIDEO, ({value, attributes}, id) => {
1127
+            this.commands.defaults.SHARED_VIDEO, ({value, attributes}, id) => {
1124
 
1128
 
1125
                 if (attributes.state === 'stop') {
1129
                 if (attributes.state === 'stop') {
1126
                     APP.UI.stopSharedVideo(id, attributes);
1130
                     APP.UI.stopSharedVideo(id, attributes);

+ 30
- 2
modules/UI/Feedback.js View File

69
     $('#feedbackButtonDiv').toggleClass("hidden");
69
     $('#feedbackButtonDiv').toggleClass("hidden");
70
 }
70
 }
71
 
71
 
72
+/**
73
+ * Shows / hides the feedback button.
74
+ * @param {show} set to {true} to show the feedback button or to  {false}
75
+ * to hide it
76
+ * @private
77
+ */
78
+function _showFeedbackButton (show) {
79
+    var feedbackButton = $("#feedbackButtonDiv");
80
+
81
+    if (show)
82
+        feedbackButton.css("display", "block");
83
+    else
84
+        feedbackButton.css("display", "none");
85
+}
86
+
72
 /**
87
 /**
73
  * Defines all methods in connection to the Feedback window.
88
  * Defines all methods in connection to the Feedback window.
74
  *
89
  *
85
      * @param emitter the EventEmitter to associate with the Feedback.
100
      * @param emitter the EventEmitter to associate with the Feedback.
86
      */
101
      */
87
     init: function (emitter) {
102
     init: function (emitter) {
103
+        // Initialise to enabled.
104
+        this.enabled = true;
105
+
88
         // CallStats is the way we send feedback, so we don't have to initialise
106
         // CallStats is the way we send feedback, so we don't have to initialise
89
         // if callstats isn't enabled.
107
         // if callstats isn't enabled.
90
         if (!APP.conference.isCallstatsEnabled())
108
         if (!APP.conference.isCallstatsEnabled())
91
             return;
109
             return;
92
-        $("#feedbackButtonDiv").css("display", "block");
110
+
111
+        _showFeedbackButton(true);
93
         $("#feedbackButton").click(function (event) {
112
         $("#feedbackButton").click(function (event) {
94
             Feedback.openFeedbackWindow();
113
             Feedback.openFeedbackWindow();
95
         });
114
         });
100
             _toggleFeedbackIcon();
119
             _toggleFeedbackIcon();
101
         });
120
         });
102
     },
121
     },
122
+    /**
123
+     * Enables/ disabled the feedback feature.
124
+     */
125
+    enableFeedback: function (enable) {
126
+        if (this.enabled !== enable)
127
+            _showFeedbackButton(enable);
128
+        this.enabled = enable;
129
+    },
130
+
103
     /**
131
     /**
104
      * Indicates if the feedback functionality is enabled.
132
      * Indicates if the feedback functionality is enabled.
105
      *
133
      *
106
      * @return true if the feedback functionality is enabled, false otherwise.
134
      * @return true if the feedback functionality is enabled, false otherwise.
107
      */
135
      */
108
     isEnabled: function() {
136
     isEnabled: function() {
109
-        return APP.conference.isCallstatsEnabled();
137
+        return this.enabled && APP.conference.isCallstatsEnabled();
110
     },
138
     },
111
     /**
139
     /**
112
      * Opens the feedback window.
140
      * Opens the feedback window.

+ 13
- 4
modules/UI/UI.js View File

29
 var Feedback = require("./Feedback");
29
 var Feedback = require("./Feedback");
30
 
30
 
31
 import FollowMe from "../FollowMe";
31
 import FollowMe from "../FollowMe";
32
+import Recorder from "../recorder/Recorder";
33
+
32
 
34
 
33
 var eventEmitter = new EventEmitter();
35
 var eventEmitter = new EventEmitter();
34
 UI.eventEmitter = eventEmitter;
36
 UI.eventEmitter = eventEmitter;
42
  * Prompt user for nickname.
44
  * Prompt user for nickname.
43
  */
45
  */
44
 function promptDisplayName() {
46
 function promptDisplayName() {
45
-    let nickRequiredMsg = APP.translation.translateString("dialog.displayNameRequired");
47
+    let nickRequiredMsg
48
+        = APP.translation.translateString("dialog.displayNameRequired");
46
     let defaultNickMsg = APP.translation.translateString(
49
     let defaultNickMsg = APP.translation.translateString(
47
         "defaultNickname", {name: "Jane Pink"}
50
         "defaultNickname", {name: "Jane Pink"}
48
     );
51
     );
110
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API
113
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API
111
  */
114
  */
112
 function toggleFullScreen () {
115
 function toggleFullScreen () {
113
-    let isNotFullScreen = !document.fullscreenElement &&    // alternative standard method
114
-
116
+                            // alternative standard method
117
+    let isNotFullScreen = !document.fullscreenElement &&
115
             !document.mozFullScreenElement && // current working methods
118
             !document.mozFullScreenElement && // current working methods
116
         !document.webkitFullscreenElement &&
119
         !document.webkitFullscreenElement &&
117
         !document.msFullscreenElement;
120
         !document.msFullscreenElement;
124
         } else if (document.documentElement.mozRequestFullScreen) {
127
         } else if (document.documentElement.mozRequestFullScreen) {
125
             document.documentElement.mozRequestFullScreen();
128
             document.documentElement.mozRequestFullScreen();
126
         } else if (document.documentElement.webkitRequestFullscreen) {
129
         } else if (document.documentElement.webkitRequestFullscreen) {
127
-            document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
130
+            document.documentElement
131
+                .webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
128
         }
132
         }
129
     } else {
133
     } else {
130
         if (document.exitFullscreen) {
134
         if (document.exitFullscreen) {
238
     //if local role changes buttons state will be again updated
242
     //if local role changes buttons state will be again updated
239
     UI.updateLocalRole(false);
243
     UI.updateLocalRole(false);
240
 
244
 
245
+    // Initialise the recorder handler. We're doing this explicitly before
246
+    // calling showToolbar, because the recorder may want to disable all
247
+    // toolbars.
248
+    new Recorder(APP.conference, UI);
249
+
241
     // Once we've joined the muc show the toolbar
250
     // Once we've joined the muc show the toolbar
242
     ToolbarToggler.showToolbar();
251
     ToolbarToggler.showToolbar();
243
 
252
 

+ 39
- 2
modules/UI/recording/Recording.js View File

133
     });
133
     });
134
 }
134
 }
135
 
135
 
136
+/**
137
+ * Shows a prompt dialog to the user when they have toggled off the recording.
138
+ *
139
+ * @param recordingType the recording type
140
+ * @returns {Promise}
141
+ * @private
142
+ */
136
 function _showStopRecordingPrompt (recordingType) {
143
 function _showStopRecordingPrompt (recordingType) {
137
     var title;
144
     var title;
138
     var message;
145
     var message;
167
     });
174
     });
168
 }
175
 }
169
 
176
 
177
+/**
178
+ * Moves the element given by {selector} to the top right corner of the screen.
179
+ * @param selector the selector for the element to move
180
+ * @param move {true} to move the element, {false} to move it back to its intial
181
+ * position
182
+ */
170
 function moveToCorner(selector, move) {
183
 function moveToCorner(selector, move) {
171
     let moveToCornerClass = "moveToCorner";
184
     let moveToCornerClass = "moveToCorner";
172
 
185
 
176
         selector.removeClass(moveToCornerClass);
189
         selector.removeClass(moveToCornerClass);
177
 }
190
 }
178
 
191
 
192
+/**
193
+ * The status of the recorder.
194
+ * FIXME: Those constants should come from the library.
195
+ * @type {{ON: string, OFF: string, AVAILABLE: string,
196
+ * UNAVAILABLE: string, PENDING: string}}
197
+ */
179
 var Status = {
198
 var Status = {
180
     ON: "on",
199
     ON: "on",
181
     OFF: "off",
200
     OFF: "off",
184
     PENDING: "pending"
203
     PENDING: "pending"
185
 };
204
 };
186
 
205
 
206
+/**
207
+ * Manages the recording user interface and user experience.
208
+ * @type {{init, initRecordingButton, showRecordingButton, updateRecordingState,
209
+ * setRecordingButtonState, checkAutoRecord}}
210
+ */
187
 var Recording = {
211
 var Recording = {
188
     /**
212
     /**
189
      * Initializes the recording UI.
213
      * Initializes the recording UI.
196
         this.initRecordingButton(recordingType);
220
         this.initRecordingButton(recordingType);
197
     },
221
     },
198
 
222
 
223
+    /**
224
+     * Initialise the recording button.
225
+     */
199
     initRecordingButton(recordingType) {
226
     initRecordingButton(recordingType) {
200
         let selector = $('#toolbar_button_record');
227
         let selector = $('#toolbar_button_record');
201
 
228
 
261
         });
288
         });
262
     },
289
     },
263
 
290
 
264
-    // Shows or hides the 'recording' button.
291
+    /**
292
+     * Shows or hides the 'recording' button.
293
+     * @param show {true} to show the recording button, {false} to hide it
294
+     */
265
     showRecordingButton (show) {
295
     showRecordingButton (show) {
266
         if (_isRecordingButtonEnabled() && show) {
296
         if (_isRecordingButtonEnabled() && show) {
267
             $('#toolbar_button_record').css({display: "inline-block"});
297
             $('#toolbar_button_record').css({display: "inline-block"});
270
         }
300
         }
271
     },
301
     },
272
 
302
 
303
+    /**
304
+     * Updates the recording state UI.
305
+     * @param recordingState gives us the current recording state
306
+     */
273
     updateRecordingState(recordingState) {
307
     updateRecordingState(recordingState) {
274
         // I'm the recorder, so I don't want to see any UI related to states.
308
         // I'm the recorder, so I don't want to see any UI related to states.
275
         if (config.iAmRecorder)
309
         if (config.iAmRecorder)
282
         this.setRecordingButtonState(recordingState);
316
         this.setRecordingButtonState(recordingState);
283
     },
317
     },
284
 
318
 
285
-    // Sets the state of the recording button
319
+    /**
320
+     * Sets the state of the recording button.
321
+     * @param recordingState gives us the current recording state
322
+     */
286
     setRecordingButtonState (recordingState) {
323
     setRecordingButtonState (recordingState) {
287
         let buttonSelector = $('#toolbar_button_record');
324
         let buttonSelector = $('#toolbar_button_record');
288
         let labelSelector = $('#recordingLabel');
325
         let labelSelector = $('#recordingLabel');

+ 20
- 1
modules/UI/toolbars/BottomToolbar.js View File

12
 const BottomToolbar = {
12
 const BottomToolbar = {
13
     init () {
13
     init () {
14
         this.toolbar = $('#bottomToolbar');
14
         this.toolbar = $('#bottomToolbar');
15
-    },
16
 
15
 
16
+        // The bottom toolbar is enabled by default.
17
+        this.enabled = true;
18
+    },
19
+    /**
20
+     * Enables / disables the bottom toolbar.
21
+     * @param {e} set to {true} to enable the bottom toolbar or {false}
22
+     * to disable it
23
+     */
24
+    enable (e) {
25
+        this.enabled = e;
26
+        if (!e && this.isVisible())
27
+            this.hide(false);
28
+    },
29
+    /**
30
+     * Indicates if the bottom toolbar is currently enabled.
31
+     * @return {this.enabled}
32
+     */
33
+    isEnabled() {
34
+        return this.enabled;
35
+    },
17
     setupListeners (emitter) {
36
     setupListeners (emitter) {
18
         UIUtil.hideDisabledButtons(defaultBottomToolbarButtons);
37
         UIUtil.hideDisabledButtons(defaultBottomToolbarButtons);
19
 
38
 

+ 71
- 5
modules/UI/toolbars/Toolbar.js View File

171
 const Toolbar = {
171
 const Toolbar = {
172
     init (eventEmitter) {
172
     init (eventEmitter) {
173
         emitter = eventEmitter;
173
         emitter = eventEmitter;
174
+        // The toolbar is enabled by default.
175
+        this.enabled = true;
176
+        this.toolbarSelector = $("#header");
174
 
177
 
175
         UIUtil.hideDisabledButtons(defaultToolbarButtons);
178
         UIUtil.hideDisabledButtons(defaultToolbarButtons);
176
 
179
 
178
             buttonId => $(`#${buttonId}`).click(buttonHandlers[buttonId])
181
             buttonId => $(`#${buttonId}`).click(buttonHandlers[buttonId])
179
         );
182
         );
180
     },
183
     },
181
-
184
+    /**
185
+     * Enables / disables the toolbar.
186
+     * @param {e} set to {true} to enable the toolbar or {false}
187
+     * to disable it
188
+     */
189
+    enable (e) {
190
+        this.enabled = e;
191
+        if (!e && this.isVisible())
192
+            this.hide(false);
193
+    },
194
+    /**
195
+     * Indicates if the bottom toolbar is currently enabled.
196
+     * @return {this.enabled}
197
+     */
198
+    isEnabled() {
199
+        return this.enabled;
200
+    },
182
     /**
201
     /**
183
      * Updates the room invite url.
202
      * Updates the room invite url.
184
      */
203
      */
185
     updateRoomUrl (newRoomUrl) {
204
     updateRoomUrl (newRoomUrl) {
186
         roomUrl = newRoomUrl;
205
         roomUrl = newRoomUrl;
187
 
206
 
188
-        // If the invite dialog has been already opened we update the information.
207
+        // If the invite dialog has been already opened we update the
208
+        // information.
189
         let inviteLink = document.getElementById('inviteLinkRef');
209
         let inviteLink = document.getElementById('inviteLinkRef');
190
         if (inviteLink) {
210
         if (inviteLink) {
191
             inviteLink.value = roomUrl;
211
             inviteLink.value = roomUrl;
244
     // checks whether desktop sharing is enabled and whether
264
     // checks whether desktop sharing is enabled and whether
245
     // we have params to start automatically sharing
265
     // we have params to start automatically sharing
246
     checkAutoEnableDesktopSharing () {
266
     checkAutoEnableDesktopSharing () {
247
-        if (UIUtil.isButtonEnabled('desktop') && config.autoEnableDesktopSharing) {
267
+        if (UIUtil.isButtonEnabled('desktop')
268
+            && config.autoEnableDesktopSharing) {
248
             emitter.emit(UIEvents.TOGGLE_SCREENSHARING);
269
             emitter.emit(UIEvents.TOGGLE_SCREENSHARING);
249
         }
270
         }
250
     },
271
     },
251
 
272
 
252
     // Shows or hides SIP calls button
273
     // Shows or hides SIP calls button
253
     showSipCallButton (show) {
274
     showSipCallButton (show) {
254
-        if (APP.conference.sipGatewayEnabled() && UIUtil.isButtonEnabled('sip') && show) {
275
+        if (APP.conference.sipGatewayEnabled()
276
+            && UIUtil.isButtonEnabled('sip') && show) {
255
             $('#toolbar_button_sip').css({display: "inline-block"});
277
             $('#toolbar_button_sip').css({display: "inline-block"});
256
         } else {
278
         } else {
257
             $('#toolbar_button_sip').css({display: "none"});
279
             $('#toolbar_button_sip').css({display: "none"});
331
      * @param {boolean} muted if icon should look like muted or not
353
      * @param {boolean} muted if icon should look like muted or not
332
      */
354
      */
333
     markAudioIconAsMuted (muted) {
355
     markAudioIconAsMuted (muted) {
334
-        $('#toolbar_button_mute').toggleClass("icon-microphone", !muted).toggleClass("icon-mic-disabled", muted);
356
+        $('#toolbar_button_mute').toggleClass("icon-microphone",
357
+            !muted).toggleClass("icon-mic-disabled", muted);
358
+    },
359
+
360
+    /**
361
+     * Indicates if the toolbar is currently hovered.
362
+     * @return {true} if the toolbar is currently hovered, {false} otherwise
363
+     */
364
+    isHovered() {
365
+        this.toolbarSelector.find('*').each(function () {
366
+            let id = $(this).attr('id');
367
+            if ($(`#${id}:hover`).length > 0) {
368
+                return true;
369
+            }
370
+        });
371
+        if ($("#bottomToolbar:hover").length > 0) {
372
+            return true;
373
+        }
374
+        return false;
375
+    },
376
+
377
+    /**
378
+     * Returns true if this toolbar is currently visible, or false otherwise.
379
+     * @return <tt>true</tt> if currently visible, <tt>false</tt> - otherwise
380
+     */
381
+    isVisible() {
382
+        return this.toolbarSelector.is(":visible");
383
+    },
384
+
385
+    /**
386
+     * Hides the toolbar with animation or not depending on the animate
387
+     * parameter.
388
+     */
389
+    hide() {
390
+        this.toolbarSelector.hide(
391
+            "slide", { direction: "up", duration: 300});
392
+    },
393
+
394
+    /**
395
+     * Shows the toolbar with animation or not depending on the animate
396
+     * parameter.
397
+     */
398
+    show() {
399
+        this.toolbarSelector.show(
400
+            "slide", { direction: "up", duration: 300});
335
     }
401
     }
336
 };
402
 };
337
 
403
 

+ 19
- 29
modules/UI/toolbars/ToolbarToggler.js View File

2
 
2
 
3
 import UIUtil from '../util/UIUtil';
3
 import UIUtil from '../util/UIUtil';
4
 import BottomToolbar from './BottomToolbar';
4
 import BottomToolbar from './BottomToolbar';
5
+import Toolbar from './Toolbar';
5
 import FilmStrip from '../videolayout/FilmStrip.js';
6
 import FilmStrip from '../videolayout/FilmStrip.js';
6
 
7
 
7
 let toolbarTimeoutObject;
8
 let toolbarTimeoutObject;
16
     }
17
     }
17
 }
18
 }
18
 
19
 
19
-function isToolbarVisible () {
20
-    return $('#header').is(':visible');
21
-}
22
-
23
 /**
20
 /**
24
  * Hides the toolbar.
21
  * Hides the toolbar.
25
  */
22
  */
28
         return;
25
         return;
29
     }
26
     }
30
 
27
 
31
-    let header = $("#header");
32
-    let isToolbarHover = false;
33
-    header.find('*').each(function () {
34
-        let id = $(this).attr('id');
35
-        if ($(`#${id}:hover`).length > 0) {
36
-            isToolbarHover = true;
37
-        }
38
-    });
39
-    if ($("#bottomToolbar:hover").length > 0) {
40
-        isToolbarHover = true;
41
-    }
42
-
43
     clearTimeout(toolbarTimeoutObject);
28
     clearTimeout(toolbarTimeoutObject);
44
     toolbarTimeoutObject = null;
29
     toolbarTimeoutObject = null;
45
 
30
 
46
-    if (isToolbarHover) {
31
+    if (Toolbar.isHovered()) {
47
         toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
32
         toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
48
     } else {
33
     } else {
49
-        header.hide("slide", { direction: "up", duration: 300});
34
+        Toolbar.hide();
50
         $('#subject').animate({top: "-=40"}, 300);
35
         $('#subject').animate({top: "-=40"}, 300);
51
         if (!FilmStrip.isFilmStripVisible()) {
36
         if (!FilmStrip.isFilmStripVisible()) {
52
             BottomToolbar.hide(true);
37
             BottomToolbar.hide(true);
59
      * Shows the main toolbar.
44
      * Shows the main toolbar.
60
      */
45
      */
61
     showToolbar () {
46
     showToolbar () {
62
-        // if we are a recorder we do not want to show the toolbar
63
-        if (interfaceConfig.filmStripOnly || config.iAmRecorder) {
47
+        if (interfaceConfig.filmStripOnly) {
64
             return;
48
             return;
65
         }
49
         }
66
-        let header = $("#header");
67
-        if (!header.is(':visible') || !BottomToolbar.isVisible()) {
68
-            header.show("slide", { direction: "up", duration: 300});
50
+
51
+        var updateTimeout = false;
52
+        if (Toolbar.isEnabled() && !Toolbar.isVisible()) {
53
+            Toolbar.show();
69
             $('#subject').animate({top: "+=40"}, 300);
54
             $('#subject').animate({top: "+=40"}, 300);
70
-            if (!BottomToolbar.isVisible()) {
71
-                BottomToolbar.show(true);
72
-            }
55
+            updateTimeout = true;
56
+        }
73
 
57
 
58
+        if (BottomToolbar.isEnabled() && !BottomToolbar.isVisible()) {
59
+            BottomToolbar.show(true);
60
+            updateTimeout = true;
61
+        }
62
+
63
+        if (updateTimeout) {
74
             if (toolbarTimeoutObject) {
64
             if (toolbarTimeoutObject) {
75
                 clearTimeout(toolbarTimeoutObject);
65
                 clearTimeout(toolbarTimeoutObject);
76
                 toolbarTimeoutObject = null;
66
                 toolbarTimeoutObject = null;
89
      * @param isDock indicates what operation to perform
79
      * @param isDock indicates what operation to perform
90
      */
80
      */
91
     dockToolbar (isDock) {
81
     dockToolbar (isDock) {
92
-        if (interfaceConfig.filmStripOnly) {
82
+        if (interfaceConfig.filmStripOnly || !Toolbar.isEnabled()) {
93
             return;
83
             return;
94
         }
84
         }
95
 
85
 
96
         if (isDock) {
86
         if (isDock) {
97
             // First make sure the toolbar is shown.
87
             // First make sure the toolbar is shown.
98
-            if (!isToolbarVisible()) {
88
+            if (!Toolbar.isVisible()) {
99
                 this.showToolbar();
89
                 this.showToolbar();
100
             }
90
             }
101
 
91
 
103
             clearTimeout(toolbarTimeoutObject);
93
             clearTimeout(toolbarTimeoutObject);
104
             toolbarTimeoutObject = null;
94
             toolbarTimeoutObject = null;
105
         } else {
95
         } else {
106
-            if (isToolbarVisible()) {
96
+            if (Toolbar.isVisible()) {
107
                 toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
97
                 toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
108
             } else {
98
             } else {
109
                 this.showToolbar();
99
                 this.showToolbar();

+ 18
- 0
modules/UI/videolayout/SmallVideo.js View File

50
     }
50
     }
51
 };
51
 };
52
 
52
 
53
+/**
54
+ * Enables / disables the device availability icons for this small video.
55
+ * @param {enable} set to {true} to enable and {false} to disable
56
+ */
57
+SmallVideo.prototype.enableDeviceAvailabilityIcons = function (enable) {
58
+    if (typeof enable === "undefined")
59
+        return;
60
+
61
+    this.deviceAvailabilityIconsEnabled = enable;
62
+};
63
+
64
+/**
65
+ * Sets the device "non" availability icons.
66
+ * @param devices the devices, which will be checked for availability
67
+ */
53
 SmallVideo.prototype.setDeviceAvailabilityIcons = function (devices) {
68
 SmallVideo.prototype.setDeviceAvailabilityIcons = function (devices) {
69
+    if (!this.deviceAvailabilityIconsEnabled)
70
+        return;
71
+
54
     if(!this.container)
72
     if(!this.container)
55
         return;
73
         return;
56
 
74
 

+ 19
- 0
modules/UI/videolayout/VideoLayout.js View File

196
         video.setDeviceAvailabilityIcons(devices);
196
         video.setDeviceAvailabilityIcons(devices);
197
     },
197
     },
198
 
198
 
199
+    /**
200
+     * Enables/disables device availability icons for the given participant id.
201
+     * The default value is {true}.
202
+     * @param id the identifier of the participant
203
+     * @param enable {true} to enable device availability icons
204
+     */
205
+    enableDeviceAvailabilityIcons (id, enable) {
206
+        let video;
207
+        if (APP.conference.isLocalId(id)) {
208
+            video = localVideoThumbnail;
209
+        }
210
+        else if (remoteVideos[id]) {
211
+            video = remoteVideos[id];
212
+        }
213
+
214
+        if (video)
215
+            video.enableDeviceAvailabilityIcons(enable);
216
+    },
217
+
199
     /**
218
     /**
200
      * Checks if removed video is currently displayed and tries to display
219
      * Checks if removed video is currently displayed and tries to display
201
      * another one instead.
220
      * another one instead.

+ 100
- 0
modules/recorder/Recorder.js View File

1
+/* global config, APP */
2
+/*
3
+ * Copyright @ 2015 Atlassian Pty Ltd
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ *     http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+import VideoLayout from '../UI/videolayout/VideoLayout';
18
+import Feedback from '../UI/Feedback.js';
19
+import Toolbar from '../UI/toolbars/Toolbar';
20
+import BottomToolbar from '../UI/toolbars/BottomToolbar';
21
+
22
+const _RECORDER_CUSTOM_ROLE = "recorder-role";
23
+
24
+class Recorder {
25
+    /**
26
+     * Initializes a new {Recorder} instance.
27
+     *
28
+     * @param conference the {conference} which is to transport
29
+     * {Recorder}-related information between participants
30
+     * @param UI the {UI} which is the source (model/state) to be sent to
31
+     * remote participants if the local participant is the moderator or the
32
+     * destination (model/state) to receive from the remote moderator if the
33
+     * local participant is not the moderator
34
+     */
35
+    constructor (conference, UI) {
36
+        this._conference = conference;
37
+        this._UI = UI;
38
+
39
+        // If I am a recorder then I publish my recorder custom role to notify
40
+        // everyone.
41
+        if (config.iAmRecorder) {
42
+            VideoLayout.enableDeviceAvailabilityIcons(conference.localId, true);
43
+            this._publishMyRecorderRole();
44
+            Feedback.enableFeedback(false);
45
+            Toolbar.enable(false);
46
+            BottomToolbar.enable(false);
47
+        }
48
+
49
+        // Listen to "CUSTOM_ROLE" commands.
50
+        this._conference.commands.addCommandListener(
51
+            this._conference.commands.defaults.CUSTOM_ROLE,
52
+            this._onCustomRoleCommand.bind(this));
53
+    }
54
+
55
+    /**
56
+     * Publish the recorder custom role.
57
+     * @private
58
+     */
59
+    _publishMyRecorderRole () {
60
+        var conference = this._conference;
61
+
62
+        var commands = conference.commands;
63
+
64
+        commands.removeCommand(commands.defaults.CUSTOM_ROLE);
65
+        var self = this;
66
+        commands.sendCommandOnce(
67
+            commands.defaults.CUSTOM_ROLE,
68
+            {
69
+                attributes: {
70
+                    recorderRole: true
71
+                }
72
+            });
73
+    }
74
+
75
+    /**
76
+     * Notifies this instance about a &qout;Custom Role&qout; command (delivered
77
+     * by the Command(s) API of {this._conference}).
78
+     *
79
+     * @param attributes the attributes {Object} carried by the command
80
+     * @param id the identifier of the participant who issued the command. A
81
+     * notable idiosyncrasy of the Command(s) API to be mindful of here is that
82
+     * the command may be issued by the local participant.
83
+     */
84
+    _onCustomRoleCommand ({ attributes }, id) {
85
+        // We require to know who issued the command because (1) only a
86
+        // moderator is allowed to send commands and (2) a command MUST be
87
+        // issued by a defined commander.
88
+        if (typeof id === 'undefined'
89
+            || this._conference.isLocalId(id)
90
+            || !attributes.recorderRole)
91
+            return;
92
+
93
+        var isRecorder = (attributes.recorderRole == 'true');
94
+
95
+        if (isRecorder)
96
+            VideoLayout.enableDeviceAvailabilityIcons(id, isRecorder);
97
+    }
98
+}
99
+
100
+export default Recorder;

Loading…
Cancel
Save