Sfoglia il codice sorgente

Adds mute indication when someone is muted.

j8
yanas 11 anni fa
parent
commit
f8070b621a
4 ha cambiato i file con 195 aggiunte e 24 eliminazioni
  1. 106
    10
      app.js
  2. 41
    3
      css/videolayout_default.css
  3. 5
    6
      index.html
  4. 43
    5
      muc.js

+ 106
- 10
app.js Vedi File

@@ -223,7 +223,7 @@ $(document).bind('remotestreamadded.jingle', function (event, data, sid) {
223 223
         var sess = connection.jingle.sessions[sid];
224 224
         if (data.stream.id === 'mixedmslabel') return;
225 225
         var videoTracks = data.stream.getVideoTracks();
226
-        console.log("waiting..", videoTracks, selector[0]);
226
+//        console.log("waiting..", videoTracks, selector[0]);
227 227
 
228 228
         if (videoTracks.length === 0 || selector[0].currentTime > 0) {
229 229
             RTC.attachMediaStream(selector, data.stream); // FIXME: why do i have to do this for FF?
@@ -673,6 +673,32 @@ $(document).bind('passwordrequired.muc', function (event, jid) {
673 673
             });
674 674
 });
675 675
 
676
+$(document).bind('audiomuted.muc', function (event, jid, isMuted) {
677
+    var videoSpanId = null;
678
+    if (jid === connection.emuc.myroomjid) {
679
+        videoSpanId = 'localVideoContainer';
680
+    } else {
681
+        ensurePeerContainerExists(jid);
682
+        videoSpanId = 'participant_' + Strophe.getResourceFromJid(jid);
683
+    }
684
+
685
+    if (videoSpanId)
686
+        showAudioIndicator(videoSpanId, isMuted);
687
+});
688
+
689
+$(document).bind('videomuted.muc', function (event, jid, isMuted) {
690
+    var videoSpanId = null;
691
+    if (jid === connection.emuc.myroomjid) {
692
+        videoSpanId = 'localVideoContainer';
693
+    } else {
694
+        ensurePeerContainerExists(jid);
695
+        videoSpanId = 'participant_' + Strophe.getResourceFromJid(jid);
696
+    }
697
+
698
+    if (videoSpanId)
699
+        showAudioIndicator(videoSpanId, isMuted);
700
+});
701
+
676 702
 /**
677 703
  * Updates the large video with the given new video source.
678 704
  */
@@ -744,11 +770,11 @@ function isVideoSrcDesktop(videoSrc){
744 770
 function setLargeVideoVisible(isVisible) {
745 771
     if (isVisible) {
746 772
         $('#largeVideo').css({visibility:'visible'});
747
-        $('#watermark').css({visibility:'visible'});
773
+        $('.watermark').css({visibility:'visible'});
748 774
     }
749 775
     else {
750 776
         $('#largeVideo').css({visibility:'hidden'});
751
-        $('#watermark').css({visibility:'hidden'});
777
+        $('.watermark').css({visibility:'hidden'});
752 778
     }
753 779
 }
754 780
 
@@ -757,35 +783,49 @@ function getConferenceHandler() {
757 783
 }
758 784
 
759 785
 function toggleVideo() {
760
-    if (!(connection && connection.jingle.localVideo)) return;
786
+    if (!(connection && connection.jingle.localVideo))
787
+        return;
761 788
 
762 789
     var sess = getConferenceHandler();
763 790
     if (sess) {
764 791
         sess.toggleVideoMute(
765 792
             function(isMuted){
766 793
                 if(isMuted) {
767
-                    $('#video').removeClass("fa fa-video-camera fa-lg");
768
-                    $('#video').addClass("fa fa-video-camera no-fa-video-camera fa-lg");
794
+                    $('#video').removeClass("icon-camera");
795
+                    $('#video').addClass("icon-camera icon-camera-disabled");
769 796
                 } else {
770
-                    $('#video').removeClass("fa fa-video-camera no-fa-video-camera fa-lg");
771
-                    $('#video').addClass("fa fa-video-camera fa-lg");
797
+                    $('#video').removeClass("icon-camera icon-camera-disabled");
798
+                    $('#video').addClass("icon-camera");
772 799
                 }
773 800
             }
774 801
         );
775 802
     }
803
+
776 804
     var sess = focus || activecall;
777 805
     if (!sess) {
778 806
         return;
779 807
     }
808
+
780 809
     sess.pendingop = ismuted ? 'unmute' : 'mute';
810
+//    connection.emuc.addVideoInfoToPresence(!ismuted);
811
+//    connection.emuc.sendPresence();
812
+
781 813
     sess.modifySources();
782 814
 }
783 815
 
816
+/**
817
+ * Mutes / unmutes audio for the local participant.
818
+ */
784 819
 function toggleAudio() {
785
-    if (!(connection && connection.jingle.localAudio)) return;
820
+    if (!(connection && connection.jingle.localAudio))
821
+        return;
786 822
     var localAudio = connection.jingle.localAudio;
787 823
     for (var idx = 0; idx < localAudio.getAudioTracks().length; idx++) {
788
-        localAudio.getAudioTracks()[idx].enabled = !localAudio.getAudioTracks()[idx].enabled;
824
+        var audioEnabled = localAudio.getAudioTracks()[idx].enabled;
825
+
826
+        localAudio.getAudioTracks()[idx].enabled = !audioEnabled;
827
+        connection.emuc.addAudioInfoToPresence(audioEnabled); //isMuted is the opposite of audioEnabled
828
+        connection.emuc.sendPresence();
789 829
     }
790 830
 }
791 831
 
@@ -1561,6 +1601,62 @@ function createEditDisplayNameButton() {
1561 1601
     return editButton;
1562 1602
 }
1563 1603
 
1604
+/**
1605
+ * Shows audio muted indicator over small videos.
1606
+ */
1607
+function showAudioIndicator(videoSpanId, isMuted) {
1608
+    var audioMutedSpan = $('#' + videoSpanId + '>span.audioMuted');
1609
+
1610
+    if (isMuted === 'false') {
1611
+        if (audioMutedSpan.length > 0) {
1612
+            audioMutedSpan.remove();
1613
+        }
1614
+    }
1615
+    else {
1616
+        var videoMutedSpan = $('#' + videoSpanId + '>span.videoMuted');
1617
+
1618
+        audioMutedSpan = document.createElement('span');
1619
+        audioMutedSpan.className = 'audioMuted';
1620
+        if (videoMutedSpan) {
1621
+            audioMutedSpan.right = '30px';
1622
+        }
1623
+        $('#' + videoSpanId)[0].appendChild(audioMutedSpan);
1624
+
1625
+        var mutedIndicator = document.createElement('i');
1626
+        mutedIndicator.className = 'icon-mic-disabled';
1627
+        mutedIndicator.title = "Participant is muted";
1628
+        audioMutedSpan.appendChild(mutedIndicator);
1629
+    }
1630
+}
1631
+
1632
+/**
1633
+ * Shows video muted indicator over small videos.
1634
+ */
1635
+function showVideoIndicator(videoSpanId, isMuted) {
1636
+    var videoMutedSpan = $('#' + videoSpanId + '>span.videoMuted');
1637
+
1638
+    if (isMuted === 'false') {
1639
+        if (videoMutedSpan.length > 0) {
1640
+            videoMutedSpan.remove();
1641
+        }
1642
+    }
1643
+    else {
1644
+        var audioMutedSpan = $('#' + videoSpanId + '>span.audioMuted');
1645
+
1646
+        videoMutedSpan = document.createElement('span');
1647
+        videoMutedSpan.className = 'videoMuted';
1648
+        if (audioMutedSpan) {
1649
+            videoMutedSpan.right = '30px';
1650
+        }
1651
+        $('#' + videoSpanId)[0].appendChild(videoMutedSpan);
1652
+
1653
+        var mutedIndicator = document.createElement('i');
1654
+        mutedIndicator.className = 'icon-camera-disabled';
1655
+        mutedIndicator.title = "Participant has stopped the camera.";
1656
+        videoMutedSpan.appendChild(mutedIndicator);
1657
+    }
1658
+}
1659
+
1564 1660
 /**
1565 1661
  * Resizes and repositions videos in full screen mode.
1566 1662
  */

+ 41
- 3
css/videolayout_default.css Vedi File

@@ -178,6 +178,34 @@
178 178
     z-index: 2;
179 179
 }
180 180
 
181
+.videocontainer>span.audioMuted {
182
+    display: inline-block;
183
+    position: absolute;
184
+    color: #FFFFFF;
185
+    top: 0;
186
+    right: 0;
187
+    padding: 8px 5px;
188
+    width: 25px;
189
+    font-size: 8pt;
190
+    text-shadow: 0px 1px 0px rgba(255,255,255,.3), 0px -1px 0px rgba(0,0,0,.7);
191
+    border: 0px;
192
+    z-index: 3;
193
+}
194
+
195
+.videocontainer>span.videoMuted {
196
+    display: inline-block;
197
+    position: absolute;
198
+    color: #FFFFFF;
199
+    top: 0;
200
+    right: 0;
201
+    padding: 8px 5px;
202
+    width: 25px;
203
+    font-size: 8pt;
204
+    text-shadow: 0px 1px 0px rgba(255,255,255,.3), 0px -1px 0px rgba(0,0,0,.7);
205
+    border: 0px;
206
+    z-index: 3;
207
+}
208
+
181 209
 #reloadPresentation {
182 210
     display: none;
183 211
     position: absolute;
@@ -220,15 +248,25 @@
220 248
     border-bottom-right-radius: 12px;
221 249
 }
222 250
 
223
-#watermark {
251
+.watermark {
224 252
     display: block;
225 253
     position: absolute;
226
-    left: 15;
227 254
     top: 15;
228 255
     width: 20%;
229 256
     height: 10%;
230
-    background-image:url(../images/watermark.png);
231 257
     background-size: contain;
232 258
     background-repeat: no-repeat;
233 259
     z-index: 2;
234 260
 }
261
+
262
+#leftwatermark {
263
+    left: 15;
264
+    background-image:url(../images/watermark.png);
265
+    background-position: center left;
266
+}
267
+
268
+#rightwatermark {
269
+    right: 15;
270
+    background-image:url(../images/rightwatermark.png);
271
+    background-position: center right;
272
+}

+ 5
- 6
index.html Vedi File

@@ -20,10 +20,10 @@
20 20
     <script src="libs/colibri/colibri.session.js?v=1"></script>
21 21
     <script src="//code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
22 22
     <script src="config.js"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
23
-    <script src="muc.js?v=9"></script><!-- simple MUC library -->
23
+    <script src="muc.js?v=10"></script><!-- simple MUC library -->
24 24
     <script src="estos_log.js?v=2"></script><!-- simple stanza logger -->
25 25
     <script src="desktopsharing.js?v=1"></script><!-- desktop sharing -->
26
-    <script src="app.js?v=25"></script><!-- application logic -->
26
+    <script src="app.js?v=26"></script><!-- application logic -->
27 27
     <script src="chat.js?v=4"></script><!-- chat logic -->
28 28
     <script src="util.js?v=3"></script><!-- utility functions -->
29 29
     <script src="etherpad.js?v=7"></script><!-- etherpad plugin -->
@@ -33,7 +33,7 @@
33 33
     <link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
34 34
     <link rel="stylesheet" href="css/font.css"/>
35 35
     <link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=20"/>
36
-    <link rel="stylesheet" type="text/css" media="screen" href="css/videolayout_default.css?v=3" id="videolayout_default"/>
36
+    <link rel="stylesheet" type="text/css" media="screen" href="css/videolayout_default.css?v=4" id="videolayout_default"/>
37 37
     <link rel="stylesheet" href="css/jquery-impromptu.css?v=4">
38 38
     <link rel="stylesheet" href="css/modaldialog.css?v=3">
39 39
     <!--
@@ -46,8 +46,6 @@
46 46
   </head>
47 47
   <body>
48 48
     <div id="header">
49
-        <a href="http://jitsi.org" target="_blank"><div id="leftlogo"></div></a>
50
-        <a href="http://www.estos.com/" target="_blank"><div id="rightlogo"></div></a>
51 49
         <span id="toolbar">
52 50
             <a class="button" onclick='buttonClick("#mute", "icon-microphone icon-mic-disabled");toggleAudio();'>
53 51
                 <i id="mute" title="Mute / unmute" class="icon-microphone"></i></a>
@@ -91,7 +89,8 @@
91 89
         <div id="largeVideoContainer" class="videocontainer">
92 90
             <div id="presentation"></div>
93 91
             <div id="etherpad"></div>
94
-            <a href="http://jitsi.org" target="_new"><div id="watermark"></div></a>
92
+            <a href="http://jitsi.org" target="_new"><div class="watermark" id="leftwatermark"></div></a>
93
+            <!-- a href="http://jitsi.org" target="_new"><div class="watermark" id="rightwatermark"></div></a -->
95 94
             <video id="largeVideo" autoplay oncontextmenu="return false;"></video>
96 95
         </div>
97 96
         <div id="remoteVideos">

+ 43
- 5
muc.js Vedi File

@@ -72,6 +72,19 @@ Strophe.addConnectionPlugin('emuc', {
72 72
             $(document).trigger('presentationremoved.muc', [from, url]);
73 73
         }
74 74
 
75
+        // Parse audio info tag.
76
+        var audioMuted = $(pres).find('>audiomuted');
77
+        if (audioMuted.length) {
78
+            $(document).trigger('audiomuted.muc', [from, audioMuted.text()]);
79
+        }
80
+
81
+        // Parse video info tag.
82
+        var videoMuted = $(pres).find('>videomuted');
83
+        if (videoMuted.length) {
84
+            $(document).trigger('videomuted.muc', [from, videoMuted.text()]);
85
+        }
86
+
87
+        // Parse status.
75 88
         if ($(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]>status[code="201"]').length) {
76 89
             // http://xmpp.org/extensions/xep-0045.html#createroom-instant
77 90
             this.isOwner = true;
@@ -81,6 +94,7 @@ Strophe.addConnectionPlugin('emuc', {
81 94
             this.connection.send(create); // fire away
82 95
         }
83 96
 
97
+        // Parse roles.
84 98
         var member = {};
85 99
         member.show = $(pres).find('>show').text();
86 100
         member.status = $(pres).find('>status').text();
@@ -186,16 +200,31 @@ Strophe.addConnectionPlugin('emuc', {
186 200
 
187 201
         if (this.presMap['displayName']) {
188 202
             // XEP-0172
189
-            pres.c('nick', {xmlns: 'http://jabber.org/protocol/nick'}).t(this.presMap['displayName']).up();
203
+            pres.c('nick', {xmlns: 'http://jabber.org/protocol/nick'})
204
+                .t(this.presMap['displayName']).up();
205
+        }
206
+
207
+        if (this.presMap['audions']) {
208
+            pres.c('audiomuted', {xmlns: this.presMap['audions']})
209
+                .t(this.presMap['audiomuted']).up();
210
+        }
211
+
212
+        if (this.presMap['videons']) {
213
+            console.log("SEND VIDEO MUTED", this.presMap['videomuted']);
214
+            pres.c('videomuted', {xmlns: this.presMap['videons']})
215
+                .t(this.presMap['videomuted']).up();
190 216
         }
191 217
 
192 218
         if (this.presMap['prezins']) {
193
-            pres.c('prezi', {xmlns: this.presMap['prezins'], 'url': this.presMap['preziurl']}).
194
-                            c('current').t(this.presMap['prezicurrent']).up().up();
219
+            pres.c('prezi',
220
+                    {xmlns: this.presMap['prezins'],
221
+                    'url': this.presMap['preziurl']})
222
+                    .c('current').t(this.presMap['prezicurrent']).up().up();
195 223
         }
196 224
 
197 225
         if (this.presMap['etherpadns']) {
198
-            pres.c('etherpad', {xmlns: this.presMap['etherpadns']}).t(this.presMap['etherpadname']).up();
226
+            pres.c('etherpad', {xmlns: this.presMap['etherpadns']})
227
+                .t(this.presMap['etherpadname']).up();
199 228
         }
200 229
 
201 230
         if (this.presMap['medians'])
@@ -212,7 +241,8 @@ Strophe.addConnectionPlugin('emuc', {
212 241
                     pres.c('source',
213 242
                            {type: this.presMap['source' + i + '_type'],
214 243
                            ssrc: this.presMap['source' + i + '_ssrc'],
215
-                           direction: this.presMap['source'+ i + '_direction'] || 'sendrecv' }
244
+                           direction: this.presMap['source'+ i + '_direction']
245
+                                                    || 'sendrecv' }
216 246
                     ).up();
217 247
                 }
218 248
         }
@@ -257,5 +287,13 @@ Strophe.addConnectionPlugin('emuc', {
257 287
     addEtherpadToPresence: function(etherpadName) {
258 288
         this.presMap['etherpadns'] = 'http://jitsi.org/jitmeet/etherpad';
259 289
         this.presMap['etherpadname'] = etherpadName;
290
+    },
291
+    addAudioInfoToPresence: function(isMuted) {
292
+        this.presMap['audions'] = 'http://jitsi.org/jitmeet/audio';
293
+        this.presMap['audiomuted'] = isMuted.toString();
294
+    },
295
+    addVideoInfoToPresence: function(isMuted) {
296
+        this.presMap['videons'] = 'http://jitsi.org/jitmeet/video';
297
+        this.presMap['videomuted'] = isMuted.toString();
260 298
     }
261 299
 });

Loading…
Annulla
Salva