Browse Source

Implement the functionality that allows users to start the conversation muted.

master
hristoterezov 10 years ago
parent
commit
cc1ad1bc13

+ 2
- 0
config.js View File

32
     enableWelcomePage: true,
32
     enableWelcomePage: true,
33
     enableSimulcast: false, // blocks FF support
33
     enableSimulcast: false, // blocks FF support
34
     logStats: false, // Enable logging of PeerConnection stats via the focus
34
     logStats: false, // Enable logging of PeerConnection stats via the focus
35
+    startVideoMuted: false,
36
+    startAudioMuted: false,
35
     /*noticeMessage: 'Service update is scheduled for 16th March 2015. ' +
37
     /*noticeMessage: 'Service update is scheduled for 16th March 2015. ' +
36
     'During that time service will not be available. ' +
38
     'During that time service will not be available. ' +
37
     'Apologise for inconvenience.'*/
39
     'Apologise for inconvenience.'*/

+ 2
- 2
index.html View File

10
     <meta itemprop="description" content="Join a WebRTC video conference powered by the Jitsi Videobridge"/>
10
     <meta itemprop="description" content="Join a WebRTC video conference powered by the Jitsi Videobridge"/>
11
     <meta itemprop="image" content="/images/jitsilogo.png"/>
11
     <meta itemprop="image" content="/images/jitsilogo.png"/>
12
     <script src="libs/jquery-2.1.1.min.js"></script>
12
     <script src="libs/jquery-2.1.1.min.js"></script>
13
-    <script src="config.js?v=6"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
13
+    <script src="config.js?v=7"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
14
     <script src="libs/strophe/strophe.min.js?v=1"></script>
14
     <script src="libs/strophe/strophe.min.js?v=1"></script>
15
     <script src="libs/strophe/strophe.disco.min.js?v=1"></script>
15
     <script src="libs/strophe/strophe.disco.min.js?v=1"></script>
16
     <script src="libs/strophe/strophe.caps.jsonly.min.js?v=1"></script>
16
     <script src="libs/strophe/strophe.caps.jsonly.min.js?v=1"></script>
19
     <script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
19
     <script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
20
     <script src="libs/toastr.js?v=1"></script><!-- notifications lib -->
20
     <script src="libs/toastr.js?v=1"></script><!-- notifications lib -->
21
     <script src="interface_config.js?v=5"></script>
21
     <script src="interface_config.js?v=5"></script>
22
-    <script src="libs/app.bundle.js?v=57"></script>
22
+    <script src="libs/app.bundle.js?v=58"></script>
23
     <script src="analytics.js?v=1"></script><!-- google analytics plugin -->
23
     <script src="analytics.js?v=1"></script><!-- google analytics plugin -->
24
     <link rel="stylesheet" href="css/font.css?v=7"/>
24
     <link rel="stylesheet" href="css/font.css?v=7"/>
25
     <link rel="stylesheet" href="css/toastr.css?v=1">
25
     <link rel="stylesheet" href="css/toastr.css?v=1">

+ 2
- 2
lang/main.json View File

123
         "focus": "Conference focus",
123
         "focus": "Conference focus",
124
         "focusFail": "__component__ not available - retry in __ms__ sec",
124
         "focusFail": "__component__ not available - retry in __ms__ sec",
125
         "grantedTo": "Moderator rights granted to __to__!",
125
         "grantedTo": "Moderator rights granted to __to__!",
126
-        "grantedToUnknown": "Moderator rights granted to $t(somebody)!"
127
-
126
+        "grantedToUnknown": "Moderator rights granted to $t(somebody)!",
127
+        "muted": "You have started the conversation muted."
128
     },
128
     },
129
     "dialog": {
129
     "dialog": {
130
         "kickMessage": "Ouch! You have been kicked out of the meet!",
130
         "kickMessage": "Ouch! You have been kicked out of the meet!",

+ 272
- 120
libs/app.bundle.js View File

1
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.APP = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
1
+!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.APP=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2
 /* jshint -W117 */
2
 /* jshint -W117 */
3
 /* application specific logic */
3
 /* application specific logic */
4
 
4
 
578
 var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
578
 var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
579
 
579
 
580
 
580
 
581
-function LocalStream(stream, type, eventEmitter, videoType)
581
+function LocalStream(stream, type, eventEmitter, videoType, isGUMStream)
582
 {
582
 {
583
     this.stream = stream;
583
     this.stream = stream;
584
     this.eventEmitter = eventEmitter;
584
     this.eventEmitter = eventEmitter;
585
     this.type = type;
585
     this.type = type;
586
     this.videoType = videoType;
586
     this.videoType = videoType;
587
+    this.isGUMStream = true;
588
+    if(isGUMStream === false)
589
+        this.isGUMStream = isGUMStream;
587
     var self = this;
590
     var self = this;
588
     if(type == "audio")
591
     if(type == "audio")
589
     {
592
     {
614
 }
617
 }
615
 
618
 
616
 LocalStream.prototype.isAudioStream = function () {
619
 LocalStream.prototype.isAudioStream = function () {
617
-    return (this.stream.getAudioTracks() && this.stream.getAudioTracks().length > 0);
618
-};
619
-
620
-LocalStream.prototype.mute = function()
621
-{
622
-    var ismuted = false;
623
-    var tracks = this.getTracks();
624
-
625
-    for (var idx = 0; idx < tracks.length; idx++) {
626
-        ismuted = !tracks[idx].enabled;
627
-        tracks[idx].enabled = ismuted;
628
-    }
629
-    return ismuted;
620
+    return this.type === "audio";
630
 };
621
 };
631
 
622
 
632
 LocalStream.prototype.setMute = function(mute)
623
 LocalStream.prototype.setMute = function(mute)
633
 {
624
 {
634
 
625
 
635
-    if(window.location.protocol != "https:" ||
636
-        this.isAudioStream() || this.videoType === "screen")
626
+    if((window.location.protocol != "https:" && this.isGUMStream) ||
627
+        (this.isAudioStream() && this.isGUMStream) || this.videoType === "screen")
637
     {
628
     {
638
         var tracks = this.getTracks();
629
         var tracks = this.getTracks();
639
 
630
 
649
         }
640
         }
650
         else
641
         else
651
         {
642
         {
652
-            APP.RTC.rtcUtils.obtainAudioAndVideoPermissions(["video"],
643
+            var self = this;
644
+            APP.RTC.rtcUtils.obtainAudioAndVideoPermissions(
645
+                (this.isAudioStream() ? ["audio"] : ["video"]),
653
                 function (stream) {
646
                 function (stream) {
654
-                    APP.RTC.changeLocalVideo(stream, false, function () {});
647
+                    if(self.isAudioStream())
648
+                    {
649
+                        APP.RTC.changeLocalAudio(stream, function () {});
650
+                    }
651
+                    else
652
+                    {
653
+                        APP.RTC.changeLocalVideo(stream, false, function () {});
654
+                    }
655
                 });
655
                 });
656
         }
656
         }
657
     }
657
     }
760
 
760
 
761
 var eventEmitter = new EventEmitter();
761
 var eventEmitter = new EventEmitter();
762
 
762
 
763
+
764
+function getMediaStreamUsage()
765
+{
766
+    var result = {
767
+        audio: 1,
768
+        video: 1
769
+    };
770
+    if( config.startAudioMuted === true)
771
+        result.audio = 0;
772
+    if( config.startVideoMuted === true)
773
+        result.video = 0;
774
+
775
+    /** There are some issues with the desktop sharing
776
+     * when this property is enabled.
777
+
778
+     if(result.audio > 0 && result.video > 0)
779
+        return result;
780
+     var isSecureConnection = window.location.protocol == "https:";
781
+
782
+    if(config.disableEarlyMediaPermissionRequests || !isSecureConnection)
783
+    {
784
+        if(result.audio === 0)
785
+            result.audio = -1;
786
+        if(result.video === 0)
787
+            result.video = -1;
788
+    }**/
789
+
790
+    return result;
791
+}
792
+
763
 var RTC = {
793
 var RTC = {
764
     rtcUtils: null,
794
     rtcUtils: null,
765
     devices: {
795
     devices: {
766
-        audio: false,
767
-        video: false
796
+        audio: true,
797
+        video: true
768
     },
798
     },
769
     localStreams: [],
799
     localStreams: [],
770
     remoteStreams: {},
800
     remoteStreams: {},
782
 
812
 
783
         eventEmitter.removeListener(eventType, listener);
813
         eventEmitter.removeListener(eventType, listener);
784
     },
814
     },
785
-    createLocalStream: function (stream, type, change, videoType) {
815
+    createLocalStream: function (stream, type, change, videoType, isMuted, isGUMStream) {
786
 
816
 
787
-        var localStream =  new LocalStream(stream, type, eventEmitter, videoType);
817
+        var localStream =  new LocalStream(stream, type, eventEmitter, videoType, isGUMStream);
788
         //in firefox we have only one stream object
818
         //in firefox we have only one stream object
789
         if(this.localStreams.length == 0 ||
819
         if(this.localStreams.length == 0 ||
790
             this.localStreams[0].getOriginalStream() != stream)
820
             this.localStreams[0].getOriginalStream() != stream)
791
             this.localStreams.push(localStream);
821
             this.localStreams.push(localStream);
822
+        if(isMuted === true)
823
+            localStream.setMute(false);
792
 
824
 
793
         if(type == "audio")
825
         if(type == "audio")
794
         {
826
         {
802
         if(change)
834
         if(change)
803
             eventType = StreamEventTypes.EVENT_TYPE_LOCAL_CHANGED;
835
             eventType = StreamEventTypes.EVENT_TYPE_LOCAL_CHANGED;
804
 
836
 
805
-        eventEmitter.emit(eventType, localStream);
837
+        eventEmitter.emit(eventType, localStream, isMuted);
806
         return localStream;
838
         return localStream;
807
     },
839
     },
808
     removeLocalStream: function (stream) {
840
     removeLocalStream: function (stream) {
886
         APP.UI.addListener(UIEvents.PINNED_ENDPOINT,
918
         APP.UI.addListener(UIEvents.PINNED_ENDPOINT,
887
             DataChannels.handlePinnedEndpointEvent);
919
             DataChannels.handlePinnedEndpointEvent);
888
         this.rtcUtils = new RTCUtils(this);
920
         this.rtcUtils = new RTCUtils(this);
889
-        this.rtcUtils.obtainAudioAndVideoPermissions();
921
+        this.rtcUtils.obtainAudioAndVideoPermissions(
922
+            null, null, getMediaStreamUsage());
890
     },
923
     },
891
     muteRemoteVideoStream: function (jid, value) {
924
     muteRemoteVideoStream: function (jid, value) {
892
         var stream;
925
         var stream;
927
                 callback();
960
                 callback();
928
             };
961
             };
929
         }
962
         }
930
-        var videoStream = this.rtcUtils.createVideoStream(stream);
963
+        var videoStream = this.rtcUtils.createStream(stream, true);
931
         this.localVideo = this.createLocalStream(videoStream, "video", true, type);
964
         this.localVideo = this.createLocalStream(videoStream, "video", true, type);
932
         // Stop the stream to trigger onended event for old stream
965
         // Stop the stream to trigger onended event for old stream
933
         oldStream.stop();
966
         oldStream.stop();
934
         APP.xmpp.switchStreams(videoStream, oldStream,localCallback);
967
         APP.xmpp.switchStreams(videoStream, oldStream,localCallback);
935
     },
968
     },
969
+    changeLocalAudio: function (stream, callback) {
970
+        var oldStream = this.localAudio.getOriginalStream();
971
+        var newStream = this.rtcUtils.createStream(stream);
972
+        this.localAudio = this.createLocalStream(newStream, "audio", true);
973
+        // Stop the stream to trigger onended event for old stream
974
+        oldStream.stop();
975
+        APP.xmpp.switchStreams(newStream, oldStream, callback, true);
976
+    },
936
     /**
977
     /**
937
      * Checks if video identified by given src is desktop stream.
978
      * Checks if video identified by given src is desktop stream.
938
      * @param videoSrc eg.
979
      * @param videoSrc eg.
967
         {
1008
         {
968
             APP.xmpp.sendVideoInfoPresence(mute);
1009
             APP.xmpp.sendVideoInfoPresence(mute);
969
             if(callback)
1010
             if(callback)
970
-                callback();
1011
+                callback(mute);
971
         }
1012
         }
972
         else
1013
         else
973
         {
1014
         {
1138
                 //
1179
                 //
1139
                 // https://groups.google.com/forum/#!topic/mozilla.dev.media/pKOiioXonJg
1180
                 // https://groups.google.com/forum/#!topic/mozilla.dev.media/pKOiioXonJg
1140
                 // https://github.com/webrtc/samples/issues/302
1181
                 // https://github.com/webrtc/samples/issues/302
1182
+                if(!element[0])
1183
+                    return;
1141
                 element[0].mozSrcObject = stream;
1184
                 element[0].mozSrcObject = stream;
1142
                 element[0].play();
1185
                 element[0].play();
1143
             };
1186
             };
1150
                 return tracks[0].id.replace(/[\{,\}]/g,"");
1193
                 return tracks[0].id.replace(/[\{,\}]/g,"");
1151
             };
1194
             };
1152
             this.getVideoSrc = function (element) {
1195
             this.getVideoSrc = function (element) {
1196
+                if(!element)
1197
+                    return null;
1153
                 return element.mozSrcObject;
1198
                 return element.mozSrcObject;
1154
             };
1199
             };
1155
             this.setVideoSrc = function (element, src) {
1200
             this.setVideoSrc = function (element, src) {
1156
-                element.mozSrcObject = src;
1201
+                if(element)
1202
+                    element.mozSrcObject = src;
1157
             };
1203
             };
1158
             RTCSessionDescription = mozRTCSessionDescription;
1204
             RTCSessionDescription = mozRTCSessionDescription;
1159
             RTCIceCandidate = mozRTCIceCandidate;
1205
             RTCIceCandidate = mozRTCIceCandidate;
1176
             return stream.id.replace(/[\{,\}]/g,"");
1222
             return stream.id.replace(/[\{,\}]/g,"");
1177
         };
1223
         };
1178
         this.getVideoSrc = function (element) {
1224
         this.getVideoSrc = function (element) {
1225
+            if(!element)
1226
+                return null;
1179
             return element.getAttribute("src");
1227
             return element.getAttribute("src");
1180
         };
1228
         };
1181
         this.setVideoSrc = function (element, src) {
1229
         this.setVideoSrc = function (element, src) {
1182
-            element.setAttribute("src", src);
1230
+            if(element)
1231
+                element.setAttribute("src", src);
1183
         };
1232
         };
1184
         // DTLS should now be enabled by default but..
1233
         // DTLS should now be enabled by default but..
1185
         this.pc_constraints = {'optional': [{'DtlsSrtpKeyAgreement': 'true'}]};
1234
         this.pc_constraints = {'optional': [{'DtlsSrtpKeyAgreement': 'true'}]};
1286
  * We ask for audio and video combined stream in order to get permissions and
1335
  * We ask for audio and video combined stream in order to get permissions and
1287
  * not to ask twice.
1336
  * not to ask twice.
1288
  */
1337
  */
1289
-RTCUtils.prototype.obtainAudioAndVideoPermissions = function(devices, callback) {
1338
+RTCUtils.prototype.obtainAudioAndVideoPermissions = function(devices, callback, usageOptions) {
1290
     var self = this;
1339
     var self = this;
1291
     // Get AV
1340
     // Get AV
1292
 
1341
 
1342
+    var successCallback = function (stream) {
1343
+        if(callback)
1344
+            callback(stream, usageOptions);
1345
+        else
1346
+            self.successCallback(stream, usageOptions);
1347
+    };
1348
+
1293
     if(!devices)
1349
     if(!devices)
1294
         devices = ['audio', 'video'];
1350
         devices = ['audio', 'video'];
1295
 
1351
 
1352
+    var newDevices = [];
1353
+
1354
+
1355
+    if(usageOptions)
1356
+        for(var i = 0; i < devices.length; i++)
1357
+        {
1358
+            var device = devices[i];
1359
+            if(usageOptions[device] !== -1)
1360
+                newDevices.push(device);
1361
+        }
1362
+    else
1363
+        newDevices = devices;
1364
+
1365
+    if(newDevices.length === 0)
1366
+    {
1367
+        successCallback();
1368
+        return;
1369
+    }
1370
+
1296
     this.getUserMediaWithConstraints(
1371
     this.getUserMediaWithConstraints(
1297
-        devices,
1372
+        newDevices,
1298
         function (stream) {
1373
         function (stream) {
1299
-            if(callback)
1300
-                callback(stream);
1301
-            else
1302
-                self.successCallback(stream);
1374
+            successCallback(stream);
1303
         },
1375
         },
1304
         function (error) {
1376
         function (error) {
1305
             self.errorCallback(error);
1377
             self.errorCallback(error);
1307
         config.resolution || '360');
1379
         config.resolution || '360');
1308
 }
1380
 }
1309
 
1381
 
1310
-RTCUtils.prototype.successCallback = function (stream) {
1382
+RTCUtils.prototype.successCallback = function (stream, usageOptions) {
1311
     if(stream)
1383
     if(stream)
1312
         console.log('got', stream, stream.getAudioTracks().length,
1384
         console.log('got', stream, stream.getAudioTracks().length,
1313
             stream.getVideoTracks().length);
1385
             stream.getVideoTracks().length);
1314
-    this.handleLocalStream(stream);
1386
+    this.handleLocalStream(stream, usageOptions);
1315
 };
1387
 };
1316
 
1388
 
1317
 RTCUtils.prototype.errorCallback = function (error) {
1389
 RTCUtils.prototype.errorCallback = function (error) {
1349
 
1421
 
1350
 }
1422
 }
1351
 
1423
 
1352
-RTCUtils.prototype.handleLocalStream = function(stream)
1424
+RTCUtils.prototype.handleLocalStream = function(stream, usageOptions)
1353
 {
1425
 {
1354
     if(window.webkitMediaStream)
1426
     if(window.webkitMediaStream)
1355
     {
1427
     {
1369
             }
1441
             }
1370
         }
1442
         }
1371
 
1443
 
1372
-        this.service.createLocalStream(audioStream, "audio");
1444
+        var audioMuted = (usageOptions && usageOptions.audio != 1),
1445
+            videoMuted = (usageOptions && usageOptions.video != 1);
1446
+
1447
+        var audioGUM = (!usageOptions || usageOptions.audio != -1),
1448
+            videoGUM = (!usageOptions || usageOptions.video != -1);
1449
+
1373
 
1450
 
1374
-        this.service.createLocalStream(videoStream, "video");
1451
+        this.service.createLocalStream(audioStream, "audio", null, null,
1452
+            audioMuted, audioGUM);
1453
+
1454
+        this.service.createLocalStream(videoStream, "video", null, null,
1455
+            videoMuted, videoGUM);
1375
     }
1456
     }
1376
     else
1457
     else
1377
     {//firefox
1458
     {//firefox
1380
 
1461
 
1381
 };
1462
 };
1382
 
1463
 
1383
-RTCUtils.prototype.createVideoStream = function(stream)
1464
+RTCUtils.prototype.createStream = function(stream, isVideo)
1384
 {
1465
 {
1385
-    var videoStream = null;
1466
+    var newStream = null;
1386
     if(window.webkitMediaStream)
1467
     if(window.webkitMediaStream)
1387
     {
1468
     {
1388
-        videoStream = new webkitMediaStream();
1389
-        if(stream)
1469
+        newStream = new webkitMediaStream();
1470
+        if(newStream)
1390
         {
1471
         {
1391
-            var videoTracks = stream.getVideoTracks();
1472
+            var tracks = (isVideo? stream.getVideoTracks() : stream.getAudioTracks());
1392
 
1473
 
1393
-            for (i = 0; i < videoTracks.length; i++) {
1394
-                videoStream.addTrack(videoTracks[i]);
1474
+            for (i = 0; i < tracks.length; i++) {
1475
+                newStream.addTrack(tracks[i]);
1395
             }
1476
             }
1396
         }
1477
         }
1397
 
1478
 
1398
     }
1479
     }
1399
     else
1480
     else
1400
-        videoStream = stream;
1481
+        newStream = stream;
1401
 
1482
 
1402
-    return videoStream;
1483
+    return newStream;
1403
 };
1484
 };
1404
 
1485
 
1405
 module.exports = RTCUtils;
1486
 module.exports = RTCUtils;
1439
 var roomName = null;
1520
 var roomName = null;
1440
 
1521
 
1441
 
1522
 
1523
+function notifyForInitialMute()
1524
+{
1525
+    if(config.startAudioMuted || config.startVideoMuted)
1526
+    {
1527
+        messageHandler.notify(null, "notify.me", "connected", "notify.muted");
1528
+    }
1529
+}
1530
+
1442
 function setupPrezi()
1531
 function setupPrezi()
1443
 {
1532
 {
1444
     $("#reloadPresentationLink").click(function()
1533
     $("#reloadPresentationLink").click(function()
1461
     BottomToolbar.init();
1550
     BottomToolbar.init();
1462
 }
1551
 }
1463
 
1552
 
1464
-function streamHandler(stream) {
1553
+function streamHandler(stream, isMuted) {
1465
     switch (stream.type)
1554
     switch (stream.type)
1466
     {
1555
     {
1467
         case "audio":
1556
         case "audio":
1468
-            VideoLayout.changeLocalAudio(stream);
1557
+            VideoLayout.changeLocalAudio(stream, isMuted);
1469
             break;
1558
             break;
1470
         case "video":
1559
         case "video":
1471
-            VideoLayout.changeLocalVideo(stream);
1560
+            VideoLayout.changeLocalVideo(stream, isMuted);
1472
             break;
1561
             break;
1473
         case "stream":
1562
         case "stream":
1474
-            VideoLayout.changeLocalStream(stream);
1563
+            VideoLayout.changeLocalStream(stream, isMuted);
1475
             break;
1564
             break;
1476
     }
1565
     }
1477
 }
1566
 }
1788
 
1877
 
1789
     SettingsMenu.init();
1878
     SettingsMenu.init();
1790
 
1879
 
1880
+    notifyForInitialMute();
1881
+
1791
 };
1882
 };
1792
 
1883
 
1793
 function chatAddError(errorMessage, originalText)
1884
 function chatAddError(errorMessage, originalText)
1821
 
1912
 
1822
     if (displayName)
1913
     if (displayName)
1823
         onDisplayNameChanged('localVideoContainer', displayName);
1914
         onDisplayNameChanged('localVideoContainer', displayName);
1915
+
1916
+
1917
+    VideoLayout.mucJoined();
1824
 }
1918
 }
1825
 
1919
 
1826
 function initEtherpad(name) {
1920
 function initEtherpad(name) {
2121
 /**
2215
 /**
2122
  * Sets muted audio state for the local participant.
2216
  * Sets muted audio state for the local participant.
2123
  */
2217
  */
2124
-UI.setAudioMuted = function (mute) {
2125
-
2126
-    if(!APP.xmpp.setAudioMute(mute, function () {
2218
+UI.setAudioMuted = function (mute, earlyMute) {
2219
+    var audioMute = null;
2220
+    if(earlyMute)
2221
+        audioMute = function (mute, cb) {
2222
+            return APP.xmpp.sendAudioInfoPresence(mute, cb);
2223
+        };
2224
+    else
2225
+        audioMute = function (mute, cb) {
2226
+            return APP.xmpp.setAudioMute(mute, cb);
2227
+        }
2228
+    if(!audioMute(mute, function () {
2127
         VideoLayout.showLocalAudioIndicator(mute);
2229
         VideoLayout.showLocalAudioIndicator(mute);
2128
 
2230
 
2129
         UIUtil.buttonClick("#mute", "icon-microphone icon-mic-disabled");
2231
         UIUtil.buttonClick("#mute", "icon-microphone icon-mic-disabled");
2171
     }
2273
     }
2172
 }
2274
 }
2173
 
2275
 
2276
+
2277
+UI.setVideoMute = setVideoMute;
2278
+
2174
 module.exports = UI;
2279
 module.exports = UI;
2175
 
2280
 
2176
 
2281
 
2929
         }
3034
         }
2930
     }
3035
     }
2931
 
3036
 
3037
+    if(jid && jid == APP.xmpp.myJid())
3038
+    {
3039
+        var localVideo = APP.RTC.localVideo;
3040
+        return (!localVideo || localVideo.isMuted());
3041
+    }
3042
+
2932
     if (!APP.RTC.remoteStreams[jid] || !APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) {
3043
     if (!APP.RTC.remoteStreams[jid] || !APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) {
2933
         return null;
3044
         return null;
2934
     }
3045
     }
3028
             } else {
3139
             } else {
3029
                 if (video && video.length > 0) {
3140
                 if (video && video.length > 0) {
3030
                     setVisibility(video, !show);
3141
                     setVisibility(video, !show);
3031
-                    setVisibility(avatar, show);
3032
                 }
3142
                 }
3143
+                setVisibility(avatar, show);
3144
+
3033
             }
3145
             }
3034
         }
3146
         }
3035
     },
3147
     },
7261
             || (lastNEndpointsCache && lastNEndpointsCache.indexOf(resource) !== -1);
7373
             || (lastNEndpointsCache && lastNEndpointsCache.indexOf(resource) !== -1);
7262
     };
7374
     };
7263
 
7375
 
7264
-    my.changeLocalStream = function (stream) {
7265
-        VideoLayout.changeLocalVideo(stream);
7376
+    my.changeLocalStream = function (stream, isMuted) {
7377
+        VideoLayout.changeLocalVideo(stream, isMuted);
7266
     };
7378
     };
7267
 
7379
 
7268
-    my.changeLocalAudio = function(stream) {
7380
+    my.changeLocalAudio = function(stream, isMuted) {
7381
+        if(isMuted)
7382
+            APP.UI.setAudioMuted(true, true);
7269
         APP.RTC.attachMediaStream($('#localAudio'), stream.getOriginalStream());
7383
         APP.RTC.attachMediaStream($('#localAudio'), stream.getOriginalStream());
7270
         document.getElementById('localAudio').autoplay = true;
7384
         document.getElementById('localAudio').autoplay = true;
7271
         document.getElementById('localAudio').volume = 0;
7385
         document.getElementById('localAudio').volume = 0;
7272
-        if (preMuted) {
7273
-            if(!APP.UI.setAudioMuted(true))
7274
-            {
7275
-                preMuted = mute;
7276
-            }
7277
-            preMuted = false;
7278
-        }
7279
     };
7386
     };
7280
 
7387
 
7281
-    my.changeLocalVideo = function(stream) {
7282
-        var flipX = true;
7283
-        if(stream.videoType == "screen")
7284
-            flipX = false;
7285
-        var localVideo = document.createElement('video');
7286
-        localVideo.id = 'localVideo_' +
7287
-            APP.RTC.getStreamID(stream.getOriginalStream());
7288
-        localVideo.autoplay = true;
7289
-        localVideo.volume = 0; // is it required if audio is separated ?
7290
-        localVideo.oncontextmenu = function () { return false; };
7291
-
7292
-        var localVideoContainer = document.getElementById('localVideoWrapper');
7293
-        localVideoContainer.appendChild(localVideo);
7294
-
7388
+    my.changeLocalVideo = function(stream, isMuted) {
7295
         // Set default display name.
7389
         // Set default display name.
7296
         setDisplayName('localVideoContainer');
7390
         setDisplayName('localVideoContainer');
7297
 
7391
 
7302
 
7396
 
7303
         AudioLevels.updateAudioLevelCanvas(null, VideoLayout);
7397
         AudioLevels.updateAudioLevelCanvas(null, VideoLayout);
7304
 
7398
 
7305
-        var localVideoSelector = $('#' + localVideo.id);
7399
+        var localVideo = null;
7306
 
7400
 
7307
         function localVideoClick(event) {
7401
         function localVideoClick(event) {
7308
             event.stopPropagation();
7402
             event.stopPropagation();
7311
                 false,
7405
                 false,
7312
                 APP.xmpp.myResource());
7406
                 APP.xmpp.myResource());
7313
         }
7407
         }
7314
-        // Add click handler to both video and video wrapper elements in case
7315
-        // there's no video.
7316
-        localVideoSelector.click(localVideoClick);
7408
+
7317
         $('#localVideoContainer').click(localVideoClick);
7409
         $('#localVideoContainer').click(localVideoClick);
7318
 
7410
 
7319
         // Add hover handler
7411
         // Add hover handler
7323
             },
7415
             },
7324
             function() {
7416
             function() {
7325
                 if (!VideoLayout.isLargeVideoVisible()
7417
                 if (!VideoLayout.isLargeVideoVisible()
7326
-                        || APP.RTC.getVideoSrc(localVideo) !== APP.RTC.getVideoSrc($('#largeVideo')[0]))
7418
+                    || APP.RTC.getVideoSrc(localVideo) !== APP.RTC.getVideoSrc($('#largeVideo')[0]))
7327
                     VideoLayout.showDisplayName('localVideoContainer', false);
7419
                     VideoLayout.showDisplayName('localVideoContainer', false);
7328
             }
7420
             }
7329
         );
7421
         );
7330
-        // Add stream ended handler
7331
-        stream.getOriginalStream().onended = function () {
7332
-            localVideoContainer.removeChild(localVideo);
7333
-            VideoLayout.updateRemovedVideo(APP.RTC.getVideoSrc(localVideo));
7334
-        };
7422
+
7423
+        if(isMuted)
7424
+        {
7425
+            APP.UI.setVideoMute(true);
7426
+            return;
7427
+        }
7428
+        var flipX = true;
7429
+        if(stream.videoType == "screen")
7430
+            flipX = false;
7431
+        var localVideo = document.createElement('video');
7432
+        localVideo.id = 'localVideo_' +
7433
+            APP.RTC.getStreamID(stream.getOriginalStream());
7434
+        localVideo.autoplay = true;
7435
+        localVideo.volume = 0; // is it required if audio is separated ?
7436
+        localVideo.oncontextmenu = function () { return false; };
7437
+
7438
+        var localVideoContainer = document.getElementById('localVideoWrapper');
7439
+        localVideoContainer.appendChild(localVideo);
7440
+
7441
+        var localVideoSelector = $('#' + localVideo.id);
7442
+
7443
+        // Add click handler to both video and video wrapper elements in case
7444
+        // there's no video.
7445
+        localVideoSelector.click(localVideoClick);
7446
+
7335
         // Flip video x axis if needed
7447
         // Flip video x axis if needed
7336
         flipXLocalVideo = flipX;
7448
         flipXLocalVideo = flipX;
7337
         if (flipX) {
7449
         if (flipX) {
7338
             localVideoSelector.addClass("flipVideoX");
7450
             localVideoSelector.addClass("flipVideoX");
7339
         }
7451
         }
7452
+
7340
         // Attach WebRTC stream
7453
         // Attach WebRTC stream
7341
         var videoStream = APP.simulcast.getLocalVideoStream();
7454
         var videoStream = APP.simulcast.getLocalVideoStream();
7342
         APP.RTC.attachMediaStream(localVideoSelector, videoStream);
7455
         APP.RTC.attachMediaStream(localVideoSelector, videoStream);
7343
 
7456
 
7457
+        // Add stream ended handler
7458
+        stream.getOriginalStream().onended = function () {
7459
+            localVideoContainer.removeChild(localVideo);
7460
+            VideoLayout.updateRemovedVideo(APP.RTC.getVideoSrc(localVideo));
7461
+        };
7462
+
7463
+
7344
         localVideoSrc = APP.RTC.getVideoSrc(localVideo);
7464
         localVideoSrc = APP.RTC.getVideoSrc(localVideo);
7345
 
7465
 
7346
         var myResourceJid = APP.xmpp.myResource();
7466
         var myResourceJid = APP.xmpp.myResource();
7350
 
7470
 
7351
     };
7471
     };
7352
 
7472
 
7473
+    my.mucJoined = function () {
7474
+        var myResourceJid = APP.xmpp.myResource();
7475
+
7476
+        if(!largeVideoState.userResourceJid)
7477
+            VideoLayout.updateLargeVideo(localVideoSrc, 0,
7478
+                myResourceJid, true);
7479
+    };
7480
+
7353
     /**
7481
     /**
7354
      * Adds or removes icons for not available camera and microphone.
7482
      * Adds or removes icons for not available camera and microphone.
7355
      * @param resourceJid the jid of user
7483
      * @param resourceJid the jid of user
7417
                 }
7545
                 }
7418
             }
7546
             }
7419
 
7547
 
7548
+            var src = null, volume = null;
7420
             // mute if localvideo
7549
             // mute if localvideo
7421
             if (pick) {
7550
             if (pick) {
7422
                 var container = pick.parentNode;
7551
                 var container = pick.parentNode;
7423
-                var jid = null;
7424
-                if(container)
7425
-                {
7426
-                    if(container.id == "localVideoWrapper")
7427
-                    {
7428
-                        jid = APP.xmpp.myResource();
7429
-                    }
7430
-                    else
7431
-                    {
7432
-                        jid = VideoLayout.getPeerContainerResourceJid(container);
7433
-                    }
7434
-                }
7435
-
7436
-                VideoLayout.updateLargeVideo(APP.RTC.getVideoSrc(pick), pick.volume, jid);
7552
+                src = APP.RTC.getVideoSrc(pick);
7553
+                volume = pick.volume;
7437
             } else {
7554
             } else {
7438
                 console.warn("Failed to elect large video");
7555
                 console.warn("Failed to elect large video");
7556
+                container = $('#remoteVideos>span[id!="mixedstream"]:visible:last').get(0);
7557
+
7558
+            }
7559
+
7560
+            var jid = null;
7561
+            if(container)
7562
+            {
7563
+                if(container.id == "localVideoWrapper")
7564
+                {
7565
+                    jid = APP.xmpp.myResource();
7566
+                }
7567
+                else
7568
+                {
7569
+                    jid = VideoLayout.getPeerContainerResourceJid(container);
7570
+                }
7439
             }
7571
             }
7572
+            else
7573
+                return;
7574
+
7575
+            VideoLayout.updateLargeVideo(src, volume, jid);
7440
         }
7576
         }
7441
     };
7577
     };
7442
     
7578
     
7485
     /**
7621
     /**
7486
      * Updates the large video with the given new video source.
7622
      * Updates the large video with the given new video source.
7487
      */
7623
      */
7488
-    my.updateLargeVideo = function(newSrc, vol, resourceJid) {
7489
-        console.log('hover in', newSrc);
7490
-
7491
-        if (APP.RTC.getVideoSrc($('#largeVideo')[0]) !== newSrc) {
7624
+    my.updateLargeVideo = function(newSrc, vol, resourceJid, forceUpdate) {
7625
+        console.log('hover in', newSrc, resourceJid);
7492
 
7626
 
7627
+        if (APP.RTC.getVideoSrc($('#largeVideo')[0]) !== newSrc || forceUpdate) {
7493
             $('#activeSpeaker').css('visibility', 'hidden');
7628
             $('#activeSpeaker').css('visibility', 'hidden');
7494
             // Due to the simulcast the localVideoSrc may have changed when the
7629
             // Due to the simulcast the localVideoSrc may have changed when the
7495
             // fadeOut event triggers. In that case the getJidFromVideoSrc and
7630
             // fadeOut event triggers. In that case the getJidFromVideoSrc and
7527
                 largeVideoState.updateInProgress = true;
7662
                 largeVideoState.updateInProgress = true;
7528
 
7663
 
7529
                 var doUpdate = function () {
7664
                 var doUpdate = function () {
7530
-
7531
                     Avatar.updateActiveSpeakerAvatarSrc(
7665
                     Avatar.updateActiveSpeakerAvatarSrc(
7532
                         APP.xmpp.findJidFromResource(
7666
                         APP.xmpp.findJidFromResource(
7533
                             largeVideoState.userResourceJid));
7667
                             largeVideoState.userResourceJid));
8372
                 if (videoSpan.classList.contains("dominantspeaker"))
8506
                 if (videoSpan.classList.contains("dominantspeaker"))
8373
                     videoSpan.classList.remove("dominantspeaker");
8507
                     videoSpan.classList.remove("dominantspeaker");
8374
             }
8508
             }
8375
-
8376
-            Avatar.showUserAvatar(
8377
-                APP.xmpp.findJidFromResource(resourceJid));
8378
         }
8509
         }
8510
+        Avatar.showUserAvatar(
8511
+            APP.xmpp.findJidFromResource(resourceJid));
8379
     };
8512
     };
8380
 
8513
 
8381
     /**
8514
     /**
13436
  * @param oldStream old video stream of this session.
13569
  * @param oldStream old video stream of this session.
13437
  * @param success_callback callback executed after successful stream switch.
13570
  * @param success_callback callback executed after successful stream switch.
13438
  */
13571
  */
13439
-JingleSession.prototype.switchStreams = function (new_stream, oldStream, success_callback) {
13572
+JingleSession.prototype.switchStreams = function (new_stream, oldStream, success_callback, isAudio) {
13440
 
13573
 
13441
     var self = this;
13574
     var self = this;
13442
 
13575
 
13451
             self.peerconnection.addStream(new_stream);
13584
             self.peerconnection.addStream(new_stream);
13452
     }
13585
     }
13453
 
13586
 
13454
-    APP.RTC.switchVideoStreams(new_stream, oldStream);
13587
+    if(!isAudio)
13588
+        APP.RTC.switchVideoStreams(new_stream, oldStream);
13455
 
13589
 
13456
     // Conference is not active
13590
     // Conference is not active
13457
     if(!oldSdp || !self.peerconnection) {
13591
     if(!oldSdp || !self.peerconnection) {
15877
         initPresenceMap: function (myroomjid) {
16011
         initPresenceMap: function (myroomjid) {
15878
             this.presMap['to'] = myroomjid;
16012
             this.presMap['to'] = myroomjid;
15879
             this.presMap['xns'] = 'http://jabber.org/protocol/muc';
16013
             this.presMap['xns'] = 'http://jabber.org/protocol/muc';
16014
+            if(APP.RTC.localAudio.isMuted())
16015
+            {
16016
+                this.addAudioInfoToPresence(true);
16017
+            }
16018
+
16019
+            if(APP.RTC.localVideo.isMuted())
16020
+            {
16021
+                this.addVideoInfoToPresence(true);
16022
+            }
15880
         },
16023
         },
15881
         doJoin: function (jid, password) {
16024
         doJoin: function (jid, password) {
15882
             this.myroomjid = jid;
16025
             this.myroomjid = jid;
17328
     isExternalAuthEnabled: function () {
17471
     isExternalAuthEnabled: function () {
17329
         return Moderator.isExternalAuthEnabled();
17472
         return Moderator.isExternalAuthEnabled();
17330
     },
17473
     },
17331
-    switchStreams: function (stream, oldStream, callback) {
17474
+    switchStreams: function (stream, oldStream, callback, isAudio) {
17332
         if (connection && connection.jingle.activecall) {
17475
         if (connection && connection.jingle.activecall) {
17333
             // FIXME: will block switchInProgress on true value in case of exception
17476
             // FIXME: will block switchInProgress on true value in case of exception
17334
-            connection.jingle.activecall.switchStreams(stream, oldStream, callback);
17477
+            connection.jingle.activecall.switchStreams(stream, oldStream, callback, isAudio);
17335
         } else {
17478
         } else {
17336
             // We are done immediately
17479
             // We are done immediately
17337
             console.warn("No conference handler or conference not started yet");
17480
             console.warn("No conference handler or conference not started yet");
17339
         }
17482
         }
17340
     },
17483
     },
17341
     sendVideoInfoPresence: function (mute) {
17484
     sendVideoInfoPresence: function (mute) {
17485
+        if(!connection)
17486
+            return;
17342
         connection.emuc.addVideoInfoToPresence(mute);
17487
         connection.emuc.addVideoInfoToPresence(mute);
17343
         connection.emuc.sendPresence();
17488
         connection.emuc.sendPresence();
17344
     },
17489
     },
17382
         // It is not clear what is the right way to handle multiple tracks.
17527
         // It is not clear what is the right way to handle multiple tracks.
17383
         // So at least make sure that they are all muted or all unmuted and
17528
         // So at least make sure that they are all muted or all unmuted and
17384
         // that we send presence just once.
17529
         // that we send presence just once.
17385
-        APP.RTC.localAudio.mute();
17530
+        APP.RTC.localAudio.setMute(!mute);
17386
         // isMuted is the opposite of audioEnabled
17531
         // isMuted is the opposite of audioEnabled
17387
-        connection.emuc.addAudioInfoToPresence(mute);
17388
-        connection.emuc.sendPresence();
17532
+        this.sendAudioInfoPresence(mute, callback);
17533
+        return true;
17534
+    },
17535
+    sendAudioInfoPresence: function(mute, callback)
17536
+    {
17537
+        if(connection) {
17538
+            connection.emuc.addAudioInfoToPresence(mute);
17539
+            connection.emuc.sendPresence();
17540
+        }
17389
         callback();
17541
         callback();
17390
         return true;
17542
         return true;
17391
     },
17543
     },

+ 18
- 18
modules/RTC/LocalStream.js View File

1
 var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
1
 var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
2
 
2
 
3
 
3
 
4
-function LocalStream(stream, type, eventEmitter, videoType)
4
+function LocalStream(stream, type, eventEmitter, videoType, isGUMStream)
5
 {
5
 {
6
     this.stream = stream;
6
     this.stream = stream;
7
     this.eventEmitter = eventEmitter;
7
     this.eventEmitter = eventEmitter;
8
     this.type = type;
8
     this.type = type;
9
     this.videoType = videoType;
9
     this.videoType = videoType;
10
+    this.isGUMStream = true;
11
+    if(isGUMStream === false)
12
+        this.isGUMStream = isGUMStream;
10
     var self = this;
13
     var self = this;
11
     if(type == "audio")
14
     if(type == "audio")
12
     {
15
     {
37
 }
40
 }
38
 
41
 
39
 LocalStream.prototype.isAudioStream = function () {
42
 LocalStream.prototype.isAudioStream = function () {
40
-    return (this.stream.getAudioTracks() && this.stream.getAudioTracks().length > 0);
41
-};
42
-
43
-LocalStream.prototype.mute = function()
44
-{
45
-    var ismuted = false;
46
-    var tracks = this.getTracks();
47
-
48
-    for (var idx = 0; idx < tracks.length; idx++) {
49
-        ismuted = !tracks[idx].enabled;
50
-        tracks[idx].enabled = ismuted;
51
-    }
52
-    return ismuted;
43
+    return this.type === "audio";
53
 };
44
 };
54
 
45
 
55
 LocalStream.prototype.setMute = function(mute)
46
 LocalStream.prototype.setMute = function(mute)
56
 {
47
 {
57
 
48
 
58
-    if(window.location.protocol != "https:" ||
59
-        this.isAudioStream() || this.videoType === "screen")
49
+    if((window.location.protocol != "https:" && this.isGUMStream) ||
50
+        (this.isAudioStream() && this.isGUMStream) || this.videoType === "screen")
60
     {
51
     {
61
         var tracks = this.getTracks();
52
         var tracks = this.getTracks();
62
 
53
 
72
         }
63
         }
73
         else
64
         else
74
         {
65
         {
75
-            APP.RTC.rtcUtils.obtainAudioAndVideoPermissions(["video"],
66
+            var self = this;
67
+            APP.RTC.rtcUtils.obtainAudioAndVideoPermissions(
68
+                (this.isAudioStream() ? ["audio"] : ["video"]),
76
                 function (stream) {
69
                 function (stream) {
77
-                    APP.RTC.changeLocalVideo(stream, false, function () {});
70
+                    if(self.isAudioStream())
71
+                    {
72
+                        APP.RTC.changeLocalAudio(stream, function () {});
73
+                    }
74
+                    else
75
+                    {
76
+                        APP.RTC.changeLocalVideo(stream, false, function () {});
77
+                    }
78
                 });
78
                 });
79
         }
79
         }
80
     }
80
     }

+ 49
- 8
modules/RTC/RTC.js View File

13
 
13
 
14
 var eventEmitter = new EventEmitter();
14
 var eventEmitter = new EventEmitter();
15
 
15
 
16
+
17
+function getMediaStreamUsage()
18
+{
19
+    var result = {
20
+        audio: 1,
21
+        video: 1
22
+    };
23
+    if( config.startAudioMuted === true)
24
+        result.audio = 0;
25
+    if( config.startVideoMuted === true)
26
+        result.video = 0;
27
+
28
+    /** There are some issues with the desktop sharing
29
+     * when this property is enabled.
30
+
31
+     if(result.audio > 0 && result.video > 0)
32
+        return result;
33
+     var isSecureConnection = window.location.protocol == "https:";
34
+
35
+    if(config.disableEarlyMediaPermissionRequests || !isSecureConnection)
36
+    {
37
+        if(result.audio === 0)
38
+            result.audio = -1;
39
+        if(result.video === 0)
40
+            result.video = -1;
41
+    }**/
42
+
43
+    return result;
44
+}
45
+
16
 var RTC = {
46
 var RTC = {
17
     rtcUtils: null,
47
     rtcUtils: null,
18
     devices: {
48
     devices: {
19
-        audio: false,
20
-        video: false
49
+        audio: true,
50
+        video: true
21
     },
51
     },
22
     localStreams: [],
52
     localStreams: [],
23
     remoteStreams: {},
53
     remoteStreams: {},
35
 
65
 
36
         eventEmitter.removeListener(eventType, listener);
66
         eventEmitter.removeListener(eventType, listener);
37
     },
67
     },
38
-    createLocalStream: function (stream, type, change, videoType) {
68
+    createLocalStream: function (stream, type, change, videoType, isMuted, isGUMStream) {
39
 
69
 
40
-        var localStream =  new LocalStream(stream, type, eventEmitter, videoType);
70
+        var localStream =  new LocalStream(stream, type, eventEmitter, videoType, isGUMStream);
41
         //in firefox we have only one stream object
71
         //in firefox we have only one stream object
42
         if(this.localStreams.length == 0 ||
72
         if(this.localStreams.length == 0 ||
43
             this.localStreams[0].getOriginalStream() != stream)
73
             this.localStreams[0].getOriginalStream() != stream)
44
             this.localStreams.push(localStream);
74
             this.localStreams.push(localStream);
75
+        if(isMuted === true)
76
+            localStream.setMute(false);
45
 
77
 
46
         if(type == "audio")
78
         if(type == "audio")
47
         {
79
         {
55
         if(change)
87
         if(change)
56
             eventType = StreamEventTypes.EVENT_TYPE_LOCAL_CHANGED;
88
             eventType = StreamEventTypes.EVENT_TYPE_LOCAL_CHANGED;
57
 
89
 
58
-        eventEmitter.emit(eventType, localStream);
90
+        eventEmitter.emit(eventType, localStream, isMuted);
59
         return localStream;
91
         return localStream;
60
     },
92
     },
61
     removeLocalStream: function (stream) {
93
     removeLocalStream: function (stream) {
139
         APP.UI.addListener(UIEvents.PINNED_ENDPOINT,
171
         APP.UI.addListener(UIEvents.PINNED_ENDPOINT,
140
             DataChannels.handlePinnedEndpointEvent);
172
             DataChannels.handlePinnedEndpointEvent);
141
         this.rtcUtils = new RTCUtils(this);
173
         this.rtcUtils = new RTCUtils(this);
142
-        this.rtcUtils.obtainAudioAndVideoPermissions();
174
+        this.rtcUtils.obtainAudioAndVideoPermissions(
175
+            null, null, getMediaStreamUsage());
143
     },
176
     },
144
     muteRemoteVideoStream: function (jid, value) {
177
     muteRemoteVideoStream: function (jid, value) {
145
         var stream;
178
         var stream;
180
                 callback();
213
                 callback();
181
             };
214
             };
182
         }
215
         }
183
-        var videoStream = this.rtcUtils.createVideoStream(stream);
216
+        var videoStream = this.rtcUtils.createStream(stream, true);
184
         this.localVideo = this.createLocalStream(videoStream, "video", true, type);
217
         this.localVideo = this.createLocalStream(videoStream, "video", true, type);
185
         // Stop the stream to trigger onended event for old stream
218
         // Stop the stream to trigger onended event for old stream
186
         oldStream.stop();
219
         oldStream.stop();
187
         APP.xmpp.switchStreams(videoStream, oldStream,localCallback);
220
         APP.xmpp.switchStreams(videoStream, oldStream,localCallback);
188
     },
221
     },
222
+    changeLocalAudio: function (stream, callback) {
223
+        var oldStream = this.localAudio.getOriginalStream();
224
+        var newStream = this.rtcUtils.createStream(stream);
225
+        this.localAudio = this.createLocalStream(newStream, "audio", true);
226
+        // Stop the stream to trigger onended event for old stream
227
+        oldStream.stop();
228
+        APP.xmpp.switchStreams(newStream, oldStream, callback, true);
229
+    },
189
     /**
230
     /**
190
      * Checks if video identified by given src is desktop stream.
231
      * Checks if video identified by given src is desktop stream.
191
      * @param videoSrc eg.
232
      * @param videoSrc eg.
220
         {
261
         {
221
             APP.xmpp.sendVideoInfoPresence(mute);
262
             APP.xmpp.sendVideoInfoPresence(mute);
222
             if(callback)
263
             if(callback)
223
-                callback();
264
+                callback(mute);
224
         }
265
         }
225
         else
266
         else
226
         {
267
         {

+ 62
- 22
modules/RTC/RTCUtils.js View File

144
                 //
144
                 //
145
                 // https://groups.google.com/forum/#!topic/mozilla.dev.media/pKOiioXonJg
145
                 // https://groups.google.com/forum/#!topic/mozilla.dev.media/pKOiioXonJg
146
                 // https://github.com/webrtc/samples/issues/302
146
                 // https://github.com/webrtc/samples/issues/302
147
+                if(!element[0])
148
+                    return;
147
                 element[0].mozSrcObject = stream;
149
                 element[0].mozSrcObject = stream;
148
                 element[0].play();
150
                 element[0].play();
149
             };
151
             };
156
                 return tracks[0].id.replace(/[\{,\}]/g,"");
158
                 return tracks[0].id.replace(/[\{,\}]/g,"");
157
             };
159
             };
158
             this.getVideoSrc = function (element) {
160
             this.getVideoSrc = function (element) {
161
+                if(!element)
162
+                    return null;
159
                 return element.mozSrcObject;
163
                 return element.mozSrcObject;
160
             };
164
             };
161
             this.setVideoSrc = function (element, src) {
165
             this.setVideoSrc = function (element, src) {
162
-                element.mozSrcObject = src;
166
+                if(element)
167
+                    element.mozSrcObject = src;
163
             };
168
             };
164
             RTCSessionDescription = mozRTCSessionDescription;
169
             RTCSessionDescription = mozRTCSessionDescription;
165
             RTCIceCandidate = mozRTCIceCandidate;
170
             RTCIceCandidate = mozRTCIceCandidate;
182
             return stream.id.replace(/[\{,\}]/g,"");
187
             return stream.id.replace(/[\{,\}]/g,"");
183
         };
188
         };
184
         this.getVideoSrc = function (element) {
189
         this.getVideoSrc = function (element) {
190
+            if(!element)
191
+                return null;
185
             return element.getAttribute("src");
192
             return element.getAttribute("src");
186
         };
193
         };
187
         this.setVideoSrc = function (element, src) {
194
         this.setVideoSrc = function (element, src) {
188
-            element.setAttribute("src", src);
195
+            if(element)
196
+                element.setAttribute("src", src);
189
         };
197
         };
190
         // DTLS should now be enabled by default but..
198
         // DTLS should now be enabled by default but..
191
         this.pc_constraints = {'optional': [{'DtlsSrtpKeyAgreement': 'true'}]};
199
         this.pc_constraints = {'optional': [{'DtlsSrtpKeyAgreement': 'true'}]};
292
  * We ask for audio and video combined stream in order to get permissions and
300
  * We ask for audio and video combined stream in order to get permissions and
293
  * not to ask twice.
301
  * not to ask twice.
294
  */
302
  */
295
-RTCUtils.prototype.obtainAudioAndVideoPermissions = function(devices, callback) {
303
+RTCUtils.prototype.obtainAudioAndVideoPermissions = function(devices, callback, usageOptions) {
296
     var self = this;
304
     var self = this;
297
     // Get AV
305
     // Get AV
298
 
306
 
307
+    var successCallback = function (stream) {
308
+        if(callback)
309
+            callback(stream, usageOptions);
310
+        else
311
+            self.successCallback(stream, usageOptions);
312
+    };
313
+
299
     if(!devices)
314
     if(!devices)
300
         devices = ['audio', 'video'];
315
         devices = ['audio', 'video'];
301
 
316
 
317
+    var newDevices = [];
318
+
319
+
320
+    if(usageOptions)
321
+        for(var i = 0; i < devices.length; i++)
322
+        {
323
+            var device = devices[i];
324
+            if(usageOptions[device] !== -1)
325
+                newDevices.push(device);
326
+        }
327
+    else
328
+        newDevices = devices;
329
+
330
+    if(newDevices.length === 0)
331
+    {
332
+        successCallback();
333
+        return;
334
+    }
335
+
302
     this.getUserMediaWithConstraints(
336
     this.getUserMediaWithConstraints(
303
-        devices,
337
+        newDevices,
304
         function (stream) {
338
         function (stream) {
305
-            if(callback)
306
-                callback(stream);
307
-            else
308
-                self.successCallback(stream);
339
+            successCallback(stream);
309
         },
340
         },
310
         function (error) {
341
         function (error) {
311
             self.errorCallback(error);
342
             self.errorCallback(error);
313
         config.resolution || '360');
344
         config.resolution || '360');
314
 }
345
 }
315
 
346
 
316
-RTCUtils.prototype.successCallback = function (stream) {
347
+RTCUtils.prototype.successCallback = function (stream, usageOptions) {
317
     if(stream)
348
     if(stream)
318
         console.log('got', stream, stream.getAudioTracks().length,
349
         console.log('got', stream, stream.getAudioTracks().length,
319
             stream.getVideoTracks().length);
350
             stream.getVideoTracks().length);
320
-    this.handleLocalStream(stream);
351
+    this.handleLocalStream(stream, usageOptions);
321
 };
352
 };
322
 
353
 
323
 RTCUtils.prototype.errorCallback = function (error) {
354
 RTCUtils.prototype.errorCallback = function (error) {
355
 
386
 
356
 }
387
 }
357
 
388
 
358
-RTCUtils.prototype.handleLocalStream = function(stream)
389
+RTCUtils.prototype.handleLocalStream = function(stream, usageOptions)
359
 {
390
 {
360
     if(window.webkitMediaStream)
391
     if(window.webkitMediaStream)
361
     {
392
     {
375
             }
406
             }
376
         }
407
         }
377
 
408
 
378
-        this.service.createLocalStream(audioStream, "audio");
409
+        var audioMuted = (usageOptions && usageOptions.audio != 1),
410
+            videoMuted = (usageOptions && usageOptions.video != 1);
411
+
412
+        var audioGUM = (!usageOptions || usageOptions.audio != -1),
413
+            videoGUM = (!usageOptions || usageOptions.video != -1);
414
+
379
 
415
 
380
-        this.service.createLocalStream(videoStream, "video");
416
+        this.service.createLocalStream(audioStream, "audio", null, null,
417
+            audioMuted, audioGUM);
418
+
419
+        this.service.createLocalStream(videoStream, "video", null, null,
420
+            videoMuted, videoGUM);
381
     }
421
     }
382
     else
422
     else
383
     {//firefox
423
     {//firefox
386
 
426
 
387
 };
427
 };
388
 
428
 
389
-RTCUtils.prototype.createVideoStream = function(stream)
429
+RTCUtils.prototype.createStream = function(stream, isVideo)
390
 {
430
 {
391
-    var videoStream = null;
431
+    var newStream = null;
392
     if(window.webkitMediaStream)
432
     if(window.webkitMediaStream)
393
     {
433
     {
394
-        videoStream = new webkitMediaStream();
395
-        if(stream)
434
+        newStream = new webkitMediaStream();
435
+        if(newStream)
396
         {
436
         {
397
-            var videoTracks = stream.getVideoTracks();
437
+            var tracks = (isVideo? stream.getVideoTracks() : stream.getAudioTracks());
398
 
438
 
399
-            for (i = 0; i < videoTracks.length; i++) {
400
-                videoStream.addTrack(videoTracks[i]);
439
+            for (i = 0; i < tracks.length; i++) {
440
+                newStream.addTrack(tracks[i]);
401
             }
441
             }
402
         }
442
         }
403
 
443
 
404
     }
444
     }
405
     else
445
     else
406
-        videoStream = stream;
446
+        newStream = stream;
407
 
447
 
408
-    return videoStream;
448
+    return newStream;
409
 };
449
 };
410
 
450
 
411
 module.exports = RTCUtils;
451
 module.exports = RTCUtils;

+ 31
- 7
modules/UI/UI.js View File

32
 var roomName = null;
32
 var roomName = null;
33
 
33
 
34
 
34
 
35
+function notifyForInitialMute()
36
+{
37
+    if(config.startAudioMuted || config.startVideoMuted)
38
+    {
39
+        messageHandler.notify(null, "notify.me", "connected", "notify.muted");
40
+    }
41
+}
42
+
35
 function setupPrezi()
43
 function setupPrezi()
36
 {
44
 {
37
     $("#reloadPresentationLink").click(function()
45
     $("#reloadPresentationLink").click(function()
54
     BottomToolbar.init();
62
     BottomToolbar.init();
55
 }
63
 }
56
 
64
 
57
-function streamHandler(stream) {
65
+function streamHandler(stream, isMuted) {
58
     switch (stream.type)
66
     switch (stream.type)
59
     {
67
     {
60
         case "audio":
68
         case "audio":
61
-            VideoLayout.changeLocalAudio(stream);
69
+            VideoLayout.changeLocalAudio(stream, isMuted);
62
             break;
70
             break;
63
         case "video":
71
         case "video":
64
-            VideoLayout.changeLocalVideo(stream);
72
+            VideoLayout.changeLocalVideo(stream, isMuted);
65
             break;
73
             break;
66
         case "stream":
74
         case "stream":
67
-            VideoLayout.changeLocalStream(stream);
75
+            VideoLayout.changeLocalStream(stream, isMuted);
68
             break;
76
             break;
69
     }
77
     }
70
 }
78
 }
381
 
389
 
382
     SettingsMenu.init();
390
     SettingsMenu.init();
383
 
391
 
392
+    notifyForInitialMute();
393
+
384
 };
394
 };
385
 
395
 
386
 function chatAddError(errorMessage, originalText)
396
 function chatAddError(errorMessage, originalText)
414
 
424
 
415
     if (displayName)
425
     if (displayName)
416
         onDisplayNameChanged('localVideoContainer', displayName);
426
         onDisplayNameChanged('localVideoContainer', displayName);
427
+
428
+
429
+    VideoLayout.mucJoined();
417
 }
430
 }
418
 
431
 
419
 function initEtherpad(name) {
432
 function initEtherpad(name) {
714
 /**
727
 /**
715
  * Sets muted audio state for the local participant.
728
  * Sets muted audio state for the local participant.
716
  */
729
  */
717
-UI.setAudioMuted = function (mute) {
718
-
719
-    if(!APP.xmpp.setAudioMute(mute, function () {
730
+UI.setAudioMuted = function (mute, earlyMute) {
731
+    var audioMute = null;
732
+    if(earlyMute)
733
+        audioMute = function (mute, cb) {
734
+            return APP.xmpp.sendAudioInfoPresence(mute, cb);
735
+        };
736
+    else
737
+        audioMute = function (mute, cb) {
738
+            return APP.xmpp.setAudioMute(mute, cb);
739
+        }
740
+    if(!audioMute(mute, function () {
720
         VideoLayout.showLocalAudioIndicator(mute);
741
         VideoLayout.showLocalAudioIndicator(mute);
721
 
742
 
722
         UIUtil.buttonClick("#mute", "icon-microphone icon-mic-disabled");
743
         UIUtil.buttonClick("#mute", "icon-microphone icon-mic-disabled");
764
     }
785
     }
765
 }
786
 }
766
 
787
 
788
+
789
+UI.setVideoMute = setVideoMute;
790
+
767
 module.exports = UI;
791
 module.exports = UI;
768
 
792
 

+ 8
- 1
modules/UI/avatar/Avatar.js View File

20
         }
20
         }
21
     }
21
     }
22
 
22
 
23
+    if(jid && jid == APP.xmpp.myJid())
24
+    {
25
+        var localVideo = APP.RTC.localVideo;
26
+        return (!localVideo || localVideo.isMuted());
27
+    }
28
+
23
     if (!APP.RTC.remoteStreams[jid] || !APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) {
29
     if (!APP.RTC.remoteStreams[jid] || !APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) {
24
         return null;
30
         return null;
25
     }
31
     }
119
             } else {
125
             } else {
120
                 if (video && video.length > 0) {
126
                 if (video && video.length > 0) {
121
                     setVisibility(video, !show);
127
                     setVisibility(video, !show);
122
-                    setVisibility(avatar, show);
123
                 }
128
                 }
129
+                setVisibility(avatar, show);
130
+
124
             }
131
             }
125
         }
132
         }
126
     },
133
     },

+ 77
- 56
modules/UI/videolayout/VideoLayout.js View File

550
             || (lastNEndpointsCache && lastNEndpointsCache.indexOf(resource) !== -1);
550
             || (lastNEndpointsCache && lastNEndpointsCache.indexOf(resource) !== -1);
551
     };
551
     };
552
 
552
 
553
-    my.changeLocalStream = function (stream) {
554
-        VideoLayout.changeLocalVideo(stream);
553
+    my.changeLocalStream = function (stream, isMuted) {
554
+        VideoLayout.changeLocalVideo(stream, isMuted);
555
     };
555
     };
556
 
556
 
557
-    my.changeLocalAudio = function(stream) {
557
+    my.changeLocalAudio = function(stream, isMuted) {
558
+        if(isMuted)
559
+            APP.UI.setAudioMuted(true, true);
558
         APP.RTC.attachMediaStream($('#localAudio'), stream.getOriginalStream());
560
         APP.RTC.attachMediaStream($('#localAudio'), stream.getOriginalStream());
559
         document.getElementById('localAudio').autoplay = true;
561
         document.getElementById('localAudio').autoplay = true;
560
         document.getElementById('localAudio').volume = 0;
562
         document.getElementById('localAudio').volume = 0;
561
-        if (preMuted) {
562
-            if(!APP.UI.setAudioMuted(true))
563
-            {
564
-                preMuted = mute;
565
-            }
566
-            preMuted = false;
567
-        }
568
     };
563
     };
569
 
564
 
570
-    my.changeLocalVideo = function(stream) {
571
-        var flipX = true;
572
-        if(stream.videoType == "screen")
573
-            flipX = false;
574
-        var localVideo = document.createElement('video');
575
-        localVideo.id = 'localVideo_' +
576
-            APP.RTC.getStreamID(stream.getOriginalStream());
577
-        localVideo.autoplay = true;
578
-        localVideo.volume = 0; // is it required if audio is separated ?
579
-        localVideo.oncontextmenu = function () { return false; };
580
-
581
-        var localVideoContainer = document.getElementById('localVideoWrapper');
582
-        localVideoContainer.appendChild(localVideo);
583
-
565
+    my.changeLocalVideo = function(stream, isMuted) {
584
         // Set default display name.
566
         // Set default display name.
585
         setDisplayName('localVideoContainer');
567
         setDisplayName('localVideoContainer');
586
 
568
 
591
 
573
 
592
         AudioLevels.updateAudioLevelCanvas(null, VideoLayout);
574
         AudioLevels.updateAudioLevelCanvas(null, VideoLayout);
593
 
575
 
594
-        var localVideoSelector = $('#' + localVideo.id);
576
+        var localVideo = null;
595
 
577
 
596
         function localVideoClick(event) {
578
         function localVideoClick(event) {
597
             event.stopPropagation();
579
             event.stopPropagation();
600
                 false,
582
                 false,
601
                 APP.xmpp.myResource());
583
                 APP.xmpp.myResource());
602
         }
584
         }
603
-        // Add click handler to both video and video wrapper elements in case
604
-        // there's no video.
605
-        localVideoSelector.click(localVideoClick);
585
+
606
         $('#localVideoContainer').click(localVideoClick);
586
         $('#localVideoContainer').click(localVideoClick);
607
 
587
 
608
         // Add hover handler
588
         // Add hover handler
612
             },
592
             },
613
             function() {
593
             function() {
614
                 if (!VideoLayout.isLargeVideoVisible()
594
                 if (!VideoLayout.isLargeVideoVisible()
615
-                        || APP.RTC.getVideoSrc(localVideo) !== APP.RTC.getVideoSrc($('#largeVideo')[0]))
595
+                    || APP.RTC.getVideoSrc(localVideo) !== APP.RTC.getVideoSrc($('#largeVideo')[0]))
616
                     VideoLayout.showDisplayName('localVideoContainer', false);
596
                     VideoLayout.showDisplayName('localVideoContainer', false);
617
             }
597
             }
618
         );
598
         );
619
-        // Add stream ended handler
620
-        stream.getOriginalStream().onended = function () {
621
-            localVideoContainer.removeChild(localVideo);
622
-            VideoLayout.updateRemovedVideo(APP.RTC.getVideoSrc(localVideo));
623
-        };
599
+
600
+        if(isMuted)
601
+        {
602
+            APP.UI.setVideoMute(true);
603
+            return;
604
+        }
605
+        var flipX = true;
606
+        if(stream.videoType == "screen")
607
+            flipX = false;
608
+        var localVideo = document.createElement('video');
609
+        localVideo.id = 'localVideo_' +
610
+            APP.RTC.getStreamID(stream.getOriginalStream());
611
+        localVideo.autoplay = true;
612
+        localVideo.volume = 0; // is it required if audio is separated ?
613
+        localVideo.oncontextmenu = function () { return false; };
614
+
615
+        var localVideoContainer = document.getElementById('localVideoWrapper');
616
+        localVideoContainer.appendChild(localVideo);
617
+
618
+        var localVideoSelector = $('#' + localVideo.id);
619
+
620
+        // Add click handler to both video and video wrapper elements in case
621
+        // there's no video.
622
+        localVideoSelector.click(localVideoClick);
623
+
624
         // Flip video x axis if needed
624
         // Flip video x axis if needed
625
         flipXLocalVideo = flipX;
625
         flipXLocalVideo = flipX;
626
         if (flipX) {
626
         if (flipX) {
627
             localVideoSelector.addClass("flipVideoX");
627
             localVideoSelector.addClass("flipVideoX");
628
         }
628
         }
629
+
629
         // Attach WebRTC stream
630
         // Attach WebRTC stream
630
         var videoStream = APP.simulcast.getLocalVideoStream();
631
         var videoStream = APP.simulcast.getLocalVideoStream();
631
         APP.RTC.attachMediaStream(localVideoSelector, videoStream);
632
         APP.RTC.attachMediaStream(localVideoSelector, videoStream);
632
 
633
 
634
+        // Add stream ended handler
635
+        stream.getOriginalStream().onended = function () {
636
+            localVideoContainer.removeChild(localVideo);
637
+            VideoLayout.updateRemovedVideo(APP.RTC.getVideoSrc(localVideo));
638
+        };
639
+
640
+
633
         localVideoSrc = APP.RTC.getVideoSrc(localVideo);
641
         localVideoSrc = APP.RTC.getVideoSrc(localVideo);
634
 
642
 
635
         var myResourceJid = APP.xmpp.myResource();
643
         var myResourceJid = APP.xmpp.myResource();
639
 
647
 
640
     };
648
     };
641
 
649
 
650
+    my.mucJoined = function () {
651
+        var myResourceJid = APP.xmpp.myResource();
652
+
653
+        if(!largeVideoState.userResourceJid)
654
+            VideoLayout.updateLargeVideo(localVideoSrc, 0,
655
+                myResourceJid, true);
656
+    };
657
+
642
     /**
658
     /**
643
      * Adds or removes icons for not available camera and microphone.
659
      * Adds or removes icons for not available camera and microphone.
644
      * @param resourceJid the jid of user
660
      * @param resourceJid the jid of user
706
                 }
722
                 }
707
             }
723
             }
708
 
724
 
725
+            var src = null, volume = null;
709
             // mute if localvideo
726
             // mute if localvideo
710
             if (pick) {
727
             if (pick) {
711
                 var container = pick.parentNode;
728
                 var container = pick.parentNode;
712
-                var jid = null;
713
-                if(container)
714
-                {
715
-                    if(container.id == "localVideoWrapper")
716
-                    {
717
-                        jid = APP.xmpp.myResource();
718
-                    }
719
-                    else
720
-                    {
721
-                        jid = VideoLayout.getPeerContainerResourceJid(container);
722
-                    }
723
-                }
724
-
725
-                VideoLayout.updateLargeVideo(APP.RTC.getVideoSrc(pick), pick.volume, jid);
729
+                src = APP.RTC.getVideoSrc(pick);
730
+                volume = pick.volume;
726
             } else {
731
             } else {
727
                 console.warn("Failed to elect large video");
732
                 console.warn("Failed to elect large video");
733
+                container = $('#remoteVideos>span[id!="mixedstream"]:visible:last').get(0);
734
+
728
             }
735
             }
736
+
737
+            var jid = null;
738
+            if(container)
739
+            {
740
+                if(container.id == "localVideoWrapper")
741
+                {
742
+                    jid = APP.xmpp.myResource();
743
+                }
744
+                else
745
+                {
746
+                    jid = VideoLayout.getPeerContainerResourceJid(container);
747
+                }
748
+            }
749
+            else
750
+                return;
751
+
752
+            VideoLayout.updateLargeVideo(src, volume, jid);
729
         }
753
         }
730
     };
754
     };
731
     
755
     
774
     /**
798
     /**
775
      * Updates the large video with the given new video source.
799
      * Updates the large video with the given new video source.
776
      */
800
      */
777
-    my.updateLargeVideo = function(newSrc, vol, resourceJid) {
778
-        console.log('hover in', newSrc);
779
-
780
-        if (APP.RTC.getVideoSrc($('#largeVideo')[0]) !== newSrc) {
801
+    my.updateLargeVideo = function(newSrc, vol, resourceJid, forceUpdate) {
802
+        console.log('hover in', newSrc, resourceJid);
781
 
803
 
804
+        if (APP.RTC.getVideoSrc($('#largeVideo')[0]) !== newSrc || forceUpdate) {
782
             $('#activeSpeaker').css('visibility', 'hidden');
805
             $('#activeSpeaker').css('visibility', 'hidden');
783
             // Due to the simulcast the localVideoSrc may have changed when the
806
             // Due to the simulcast the localVideoSrc may have changed when the
784
             // fadeOut event triggers. In that case the getJidFromVideoSrc and
807
             // fadeOut event triggers. In that case the getJidFromVideoSrc and
816
                 largeVideoState.updateInProgress = true;
839
                 largeVideoState.updateInProgress = true;
817
 
840
 
818
                 var doUpdate = function () {
841
                 var doUpdate = function () {
819
-
820
                     Avatar.updateActiveSpeakerAvatarSrc(
842
                     Avatar.updateActiveSpeakerAvatarSrc(
821
                         APP.xmpp.findJidFromResource(
843
                         APP.xmpp.findJidFromResource(
822
                             largeVideoState.userResourceJid));
844
                             largeVideoState.userResourceJid));
1661
                 if (videoSpan.classList.contains("dominantspeaker"))
1683
                 if (videoSpan.classList.contains("dominantspeaker"))
1662
                     videoSpan.classList.remove("dominantspeaker");
1684
                     videoSpan.classList.remove("dominantspeaker");
1663
             }
1685
             }
1664
-
1665
-            Avatar.showUserAvatar(
1666
-                APP.xmpp.findJidFromResource(resourceJid));
1667
         }
1686
         }
1687
+        Avatar.showUserAvatar(
1688
+            APP.xmpp.findJidFromResource(resourceJid));
1668
     };
1689
     };
1669
 
1690
 
1670
     /**
1691
     /**

+ 3
- 2
modules/xmpp/JingleSession.js View File

955
  * @param oldStream old video stream of this session.
955
  * @param oldStream old video stream of this session.
956
  * @param success_callback callback executed after successful stream switch.
956
  * @param success_callback callback executed after successful stream switch.
957
  */
957
  */
958
-JingleSession.prototype.switchStreams = function (new_stream, oldStream, success_callback) {
958
+JingleSession.prototype.switchStreams = function (new_stream, oldStream, success_callback, isAudio) {
959
 
959
 
960
     var self = this;
960
     var self = this;
961
 
961
 
970
             self.peerconnection.addStream(new_stream);
970
             self.peerconnection.addStream(new_stream);
971
     }
971
     }
972
 
972
 
973
-    APP.RTC.switchVideoStreams(new_stream, oldStream);
973
+    if(!isAudio)
974
+        APP.RTC.switchVideoStreams(new_stream, oldStream);
974
 
975
 
975
     // Conference is not active
976
     // Conference is not active
976
     if(!oldSdp || !self.peerconnection) {
977
     if(!oldSdp || !self.peerconnection) {

+ 9
- 0
modules/xmpp/strophe.emuc.js View File

28
         initPresenceMap: function (myroomjid) {
28
         initPresenceMap: function (myroomjid) {
29
             this.presMap['to'] = myroomjid;
29
             this.presMap['to'] = myroomjid;
30
             this.presMap['xns'] = 'http://jabber.org/protocol/muc';
30
             this.presMap['xns'] = 'http://jabber.org/protocol/muc';
31
+            if(APP.RTC.localAudio.isMuted())
32
+            {
33
+                this.addAudioInfoToPresence(true);
34
+            }
35
+
36
+            if(APP.RTC.localVideo.isMuted())
37
+            {
38
+                this.addVideoInfoToPresence(true);
39
+            }
31
         },
40
         },
32
         doJoin: function (jid, password) {
41
         doJoin: function (jid, password) {
33
             this.myroomjid = jid;
42
             this.myroomjid = jid;

+ 14
- 5
modules/xmpp/xmpp.js View File

261
     isExternalAuthEnabled: function () {
261
     isExternalAuthEnabled: function () {
262
         return Moderator.isExternalAuthEnabled();
262
         return Moderator.isExternalAuthEnabled();
263
     },
263
     },
264
-    switchStreams: function (stream, oldStream, callback) {
264
+    switchStreams: function (stream, oldStream, callback, isAudio) {
265
         if (connection && connection.jingle.activecall) {
265
         if (connection && connection.jingle.activecall) {
266
             // FIXME: will block switchInProgress on true value in case of exception
266
             // FIXME: will block switchInProgress on true value in case of exception
267
-            connection.jingle.activecall.switchStreams(stream, oldStream, callback);
267
+            connection.jingle.activecall.switchStreams(stream, oldStream, callback, isAudio);
268
         } else {
268
         } else {
269
             // We are done immediately
269
             // We are done immediately
270
             console.warn("No conference handler or conference not started yet");
270
             console.warn("No conference handler or conference not started yet");
272
         }
272
         }
273
     },
273
     },
274
     sendVideoInfoPresence: function (mute) {
274
     sendVideoInfoPresence: function (mute) {
275
+        if(!connection)
276
+            return;
275
         connection.emuc.addVideoInfoToPresence(mute);
277
         connection.emuc.addVideoInfoToPresence(mute);
276
         connection.emuc.sendPresence();
278
         connection.emuc.sendPresence();
277
     },
279
     },
315
         // It is not clear what is the right way to handle multiple tracks.
317
         // It is not clear what is the right way to handle multiple tracks.
316
         // So at least make sure that they are all muted or all unmuted and
318
         // So at least make sure that they are all muted or all unmuted and
317
         // that we send presence just once.
319
         // that we send presence just once.
318
-        APP.RTC.localAudio.mute();
320
+        APP.RTC.localAudio.setMute(!mute);
319
         // isMuted is the opposite of audioEnabled
321
         // isMuted is the opposite of audioEnabled
320
-        connection.emuc.addAudioInfoToPresence(mute);
321
-        connection.emuc.sendPresence();
322
+        this.sendAudioInfoPresence(mute, callback);
323
+        return true;
324
+    },
325
+    sendAudioInfoPresence: function(mute, callback)
326
+    {
327
+        if(connection) {
328
+            connection.emuc.addAudioInfoToPresence(mute);
329
+            connection.emuc.sendPresence();
330
+        }
322
         callback();
331
         callback();
323
         return true;
332
         return true;
324
     },
333
     },

Loading…
Cancel
Save