Browse Source

Adds mute and kick functoinality avaialable for the focus of the conference.

master
yanas 11 years ago
parent
commit
56424df0a0

+ 160
- 16
app.js View File

15
  */
15
  */
16
 var ssrc2videoType = {};
16
 var ssrc2videoType = {};
17
 var videoSrcToSsrc = {};
17
 var videoSrcToSsrc = {};
18
+var mutedAudios = {};
18
 
19
 
19
 var localVideoSrc = null;
20
 var localVideoSrc = null;
20
 var flipXLocalVideo = true;
21
 var flipXLocalVideo = true;
35
 
36
 
36
 /* window.onbeforeunload = closePageWarning; */
37
 /* window.onbeforeunload = closePageWarning; */
37
 
38
 
39
+var preMuted = false;
40
+
38
 function init() {
41
 function init() {
39
     RTC = setupRTC();
42
     RTC = setupRTC();
40
     if (RTC === null) {
43
     if (RTC === null) {
179
     RTC.attachMediaStream($('#localAudio'), stream);
182
     RTC.attachMediaStream($('#localAudio'), stream);
180
     document.getElementById('localAudio').autoplay = true;
183
     document.getElementById('localAudio').autoplay = true;
181
     document.getElementById('localAudio').volume = 0;
184
     document.getElementById('localAudio').volume = 0;
185
+    if (preMuted) {
186
+        toggleAudio();
187
+        preMuted = false;
188
+    }
182
 }
189
 }
183
 
190
 
184
 function change_local_video(stream, flipX) {
191
 function change_local_video(stream, flipX) {
485
     }
492
     }
486
 });
493
 });
487
 
494
 
488
-$(document).bind('callterminated.jingle', function (event, sid, reason) {
489
-    // FIXME
495
+$(document).bind('callterminated.jingle', function (event, sid, jid, reason) {
496
+    // Leave the room if my call has been remotely terminated.
497
+    if (connection.emuc.joined && focus == null && reason === 'kick') {
498
+        connection.emuc.doLeave();
499
+        openMessageDialog(  "Session Terminated",
500
+                            "Ouch! You have been kicked out of the meet!");
501
+    }
490
 });
502
 });
491
 
503
 
492
 $(document).bind('setLocalDescription.jingle', function (event, sid) {
504
 $(document).bind('setLocalDescription.jingle', function (event, sid) {
579
 });
591
 });
580
 
592
 
581
 $(document).bind('left.muc', function (event, jid) {
593
 $(document).bind('left.muc', function (event, jid) {
582
-    console.log('left', jid);
594
+    console.log('left.muc', jid);
595
+    // Need to call this with a slight delay, otherwise the element couldn't be
596
+    // found for some reason.
597
+    window.setTimeout(function () {
598
+        var container = document.getElementById(
599
+                'participant_' + Strophe.getResourceFromJid(jid));
600
+        if (container) {
601
+            // hide here, wait for video to close before removing
602
+            $(container).hide();
603
+            resizeThumbnails();
604
+        }
605
+    }, 10);
606
+
583
     connection.jingle.terminateByJid(jid);
607
     connection.jingle.terminateByJid(jid);
584
-    var container = document.getElementById('participant_' + Strophe.getResourceFromJid(jid));
585
-    if (container) {
586
-        // hide here, wait for video to close before removing
587
-        $(container).hide();
588
-        resizeThumbnails();
589
-    }
590
-    if (focus === null && connection.emuc.myroomjid === connection.emuc.list_members[0]) {
608
+
609
+    if (focus == null
610
+            && jid !== connection.emuc.myroomjid
611
+            && connection.emuc.myroomjid === connection.emuc.list_members[0]
612
+            && connection.emuc.list_members.length > 1) {
591
         console.log('welcome to our new focus... myself');
613
         console.log('welcome to our new focus... myself');
592
         focus = new ColibriFocus(connection, config.hosts.bridge);
614
         focus = new ColibriFocus(connection, config.hosts.bridge);
593
         if (Object.keys(connection.emuc.members).length > 0) {
615
         if (Object.keys(connection.emuc.members).length > 0) {
603
         focus = new ColibriFocus(connection, config.hosts.bridge);
625
         focus = new ColibriFocus(connection, config.hosts.bridge);
604
     }
626
     }
605
     if (connection.emuc.getPrezi(jid)) {
627
     if (connection.emuc.getPrezi(jid)) {
606
-        $(document).trigger('presentationremoved.muc', [jid, connection.emuc.getPrezi(jid)]);
628
+        $(document).trigger('presentationremoved.muc',
629
+                            [jid, connection.emuc.getPrezi(jid)]);
607
     }
630
     }
608
 });
631
 });
609
 
632
 
686
         videoSpanId = 'participant_' + Strophe.getResourceFromJid(jid);
709
         videoSpanId = 'participant_' + Strophe.getResourceFromJid(jid);
687
     }
710
     }
688
 
711
 
712
+    if (focus) {
713
+        mutedAudios[jid] = isMuted;
714
+        updateRemoteVideoMenu(jid, isMuted);
715
+    }
716
+
689
     if (videoSpanId)
717
     if (videoSpanId)
690
         showAudioIndicator(videoSpanId, isMuted);
718
         showAudioIndicator(videoSpanId, isMuted);
691
 });
719
 });
700
     }
728
     }
701
 
729
 
702
     if (videoSpanId)
730
     if (videoSpanId)
703
-        showAudioIndicator(videoSpanId, isMuted);
731
+        showVideoIndicator(videoSpanId, isMuted);
704
 });
732
 });
705
 
733
 
706
 /**
734
 /**
821
  * Mutes / unmutes audio for the local participant.
849
  * Mutes / unmutes audio for the local participant.
822
  */
850
  */
823
 function toggleAudio() {
851
 function toggleAudio() {
824
-    if (!(connection && connection.jingle.localAudio))
852
+    if (!(connection && connection.jingle.localAudio)) {
853
+        preMuted = true;
825
         return;
854
         return;
855
+    }
856
+
826
     var localAudio = connection.jingle.localAudio;
857
     var localAudio = connection.jingle.localAudio;
827
     for (var idx = 0; idx < localAudio.getAudioTracks().length; idx++) {
858
     for (var idx = 0; idx < localAudio.getAudioTracks().length; idx++) {
828
         var audioEnabled = localAudio.getAudioTracks()[idx].enabled;
859
         var audioEnabled = localAudio.getAudioTracks()[idx].enabled;
831
         connection.emuc.addAudioInfoToPresence(audioEnabled); //isMuted is the opposite of audioEnabled
862
         connection.emuc.addAudioInfoToPresence(audioEnabled); //isMuted is the opposite of audioEnabled
832
         connection.emuc.sendPresence();
863
         connection.emuc.sendPresence();
833
     }
864
     }
865
+
866
+    buttonClick("#mute", "icon-microphone icon-mic-disabled");
834
 }
867
 }
835
 
868
 
836
 /**
869
 /**
1167
     $(id).toggleClass(classname); // add the class to the clicked element
1200
     $(id).toggleClass(classname); // add the class to the clicked element
1168
 }
1201
 }
1169
 
1202
 
1203
+/**
1204
+ * Shows a message to the user.
1205
+ *
1206
+ * @param titleString the title of the message
1207
+ * @param messageString the text of the message
1208
+ */
1209
+function openMessageDialog(titleString, messageString) {
1210
+    console.log("OPEN MESSAGE DIALOG");
1211
+    $.prompt(messageString,
1212
+        {
1213
+            title: titleString,
1214
+            persistent: false
1215
+        }
1216
+    );
1217
+}
1218
+
1170
 /**
1219
 /**
1171
  * Opens the lock room dialog.
1220
  * Opens the lock room dialog.
1172
  */
1221
  */
1448
         return;
1497
         return;
1449
     }
1498
     }
1450
 
1499
 
1451
-    var container = addRemoteVideoContainer(videoSpanId);
1500
+    var container = addRemoteVideoContainer(peerJid, videoSpanId);
1452
 
1501
 
1453
     var nickfield = document.createElement('span');
1502
     var nickfield = document.createElement('span');
1454
     nickfield.className = "nick";
1503
     nickfield.className = "nick";
1457
     resizeThumbnails();
1506
     resizeThumbnails();
1458
 }
1507
 }
1459
 
1508
 
1460
-function addRemoteVideoContainer(id) {
1509
+function addRemoteVideoContainer(peerJid, spanId) {
1461
     var container = document.createElement('span');
1510
     var container = document.createElement('span');
1462
-    container.id = id;
1511
+    container.id = spanId;
1463
     container.className = 'videocontainer';
1512
     container.className = 'videocontainer';
1464
     var remotes = document.getElementById('remoteVideos');
1513
     var remotes = document.getElementById('remoteVideos');
1514
+
1515
+    if (focus)
1516
+        addRemoteVideoMenu(peerJid, container);
1517
+
1465
     remotes.appendChild(container);
1518
     remotes.appendChild(container);
1466
     return container;
1519
     return container;
1467
 }
1520
 }
1476
     parentElement.appendChild(focusIndicator);
1529
     parentElement.appendChild(focusIndicator);
1477
 }
1530
 }
1478
 
1531
 
1532
+function addRemoteVideoMenu(jid, parentElement) {
1533
+    var spanElement = document.createElement('span');
1534
+    spanElement.className = 'remotevideomenu';
1535
+
1536
+    parentElement.appendChild(spanElement);
1537
+
1538
+    var menuElement = document.createElement('i');
1539
+    menuElement.className = 'fa fa-angle-down';
1540
+    menuElement.title = 'Remote user controls';
1541
+    spanElement.appendChild(menuElement);
1542
+
1543
+//    <ul class="popupmenu">
1544
+//    <li><a href="#">Mute</a></li>
1545
+//    <li><a href="#">Eject</a></li>
1546
+//    </ul>
1547
+    var popupmenuElement = document.createElement('ul');
1548
+    popupmenuElement.className = 'popupmenu';
1549
+    popupmenuElement.id = 'remote_popupmenu_' + Strophe.getResourceFromJid(jid);
1550
+    spanElement.appendChild(popupmenuElement);
1551
+
1552
+    var muteMenuItem = document.createElement('li');
1553
+    var muteLinkItem = document.createElement('a');
1554
+
1555
+    var mutedIndicator = "<i class='icon-mic-disabled'></i>";
1556
+
1557
+    if (!mutedAudios[jid]) {
1558
+        muteLinkItem.innerHTML = mutedIndicator + 'Mute';
1559
+        muteLinkItem.className = 'mutelink';
1560
+    }
1561
+    else {
1562
+        muteLinkItem.innerHTML = mutedIndicator + ' Muted';
1563
+        muteLinkItem.className = 'mutelink disabled';
1564
+    }
1565
+
1566
+    muteLinkItem.onclick = function(){
1567
+        if ($(this).attr('disabled') != undefined) {
1568
+            event.preventDefault();
1569
+        }
1570
+        var isMute = !mutedAudios[jid];
1571
+        connection.moderate.setMute(jid, isMute);
1572
+        popupmenuElement.setAttribute('style', 'display:none;');
1573
+
1574
+        if (isMute) {
1575
+            this.innerHTML = mutedIndicator + ' Muted';
1576
+            this.className = 'mutelink disabled';
1577
+        }
1578
+        else {
1579
+            this.innerHTML = mutedIndicator + ' Mute';
1580
+            this.className = 'mutelink';
1581
+        }
1582
+    };
1583
+
1584
+    muteMenuItem.appendChild(muteLinkItem);
1585
+    popupmenuElement.appendChild(muteMenuItem);
1586
+
1587
+    var ejectIndicator = "<i class='fa fa-eject'></i>";
1588
+
1589
+    var ejectMenuItem = document.createElement('li');
1590
+    var ejectLinkItem = document.createElement('a');
1591
+    ejectLinkItem.innerHTML = ejectIndicator + ' Kick out';
1592
+    ejectLinkItem.onclick = function(){
1593
+        connection.moderate.eject(jid);
1594
+        popupmenuElement.setAttribute('style', 'display:none;');
1595
+    };
1596
+
1597
+    ejectMenuItem.appendChild(ejectLinkItem);
1598
+    popupmenuElement.appendChild(ejectMenuItem);
1599
+}
1600
+
1601
+function updateRemoteVideoMenu(jid, isMuted) {
1602
+    var muteMenuItem
1603
+        = $('#remote_popupmenu_'
1604
+                + Strophe.getResourceFromJid(jid)
1605
+                + '>li>a.mutelink');
1606
+
1607
+    var mutedIndicator = "<i class='icon-mic-disabled'></i>";
1608
+
1609
+    if (muteMenuItem.length) {
1610
+        var muteLink = muteMenuItem.get(0);
1611
+
1612
+        if (isMuted === 'true') {
1613
+            muteLink.innerHTML = mutedIndicator + ' Muted';
1614
+            muteLink.className = 'mutelink disabled';
1615
+        }
1616
+        else {
1617
+            muteLink.innerHTML = mutedIndicator + ' Mute';
1618
+            muteLink.className = 'mutelink';
1619
+        }
1620
+    }
1621
+}
1622
+
1479
 /**
1623
 /**
1480
  * Toggles the application in and out of full screen mode
1624
  * Toggles the application in and out of full screen mode
1481
  * (a.k.a. presentation mode in Chrome).
1625
  * (a.k.a. presentation mode in Chrome).

+ 0
- 1
css/main.css View File

205
 }
205
 }
206
 
206
 
207
 button, input, select, textarea {
207
 button, input, select, textarea {
208
-    font-size: 100%;
209
     margin: 0;
208
     margin: 0;
210
     vertical-align: baseline;
209
     vertical-align: baseline;
211
 }
210
 }

+ 56
- 0
css/popup_menu.css View File

1
+/*Initialize*/
2
+ul.popupmenu {
3
+    display:none;
4
+    position: absolute;
5
+    padding:0;
6
+    margin: 0;
7
+    bottom: 20px;
8
+    padding-bottom: 5px;
9
+    padding-top: 5px;
10
+    right: 10px;
11
+    left: 0px;
12
+    width: 100px;
13
+    background-color: rgba(0,0,0,1);
14
+    -webkit-box-shadow: 0 0 2px #000000, 0 0 10px #000000;
15
+    border-radius:8px;
16
+}
17
+
18
+ul.popupmenu:after {
19
+    content: url('../images/popupPointer.png');
20
+    display: block;
21
+    position: absolute;
22
+    bottom: -9px;
23
+    left: 13px;
24
+}
25
+
26
+ul.popupmenu li {
27
+    list-style-type: none;
28
+    text-align: left;
29
+}
30
+
31
+ul.popupmenu li:hover {
32
+    background-color: rgba(82, 82, 82, .7);
33
+    border-radius:2px;
34
+}
35
+
36
+/*Link Appearance*/
37
+ul.popupmenu li a {
38
+    text-decoration: none;
39
+    color: #fff;
40
+    padding: 5px;
41
+    display: inline-block;
42
+    font-size: 9pt;
43
+}
44
+
45
+ul.popupmenu li a i {
46
+    width: 12px;
47
+}
48
+
49
+span.remotevideomenu:hover ul.popupmenu {
50
+    display:block !important;
51
+}
52
+
53
+a.disabled {
54
+    color: gray !important;
55
+    pointer-events: none;
56
+}

+ 5
- 5
css/videolayout_default.css View File

16
     left: 0;
16
     left: 0;
17
     right: 0;
17
     right: 0;
18
     width:auto;
18
     width:auto;
19
-    overflow: hidden;
20
     border:1px solid transparent;
19
     border:1px solid transparent;
21
-    z-index: 2;
20
+    z-index: 5;
22
 }
21
 }
23
 
22
 
24
 .videocontainer {
23
 .videocontainer {
41
     content:"";
40
     content:"";
42
     cursor: pointer;
41
     cursor: pointer;
43
     cursor: hand;
42
     cursor: hand;
44
-    transform:scale(1.08, 1.08);
45
-    -webkit-transform:scale(1.08, 1.08);
43
+    /* transform:scale(1.08, 1.08);
44
+    -webkit-transform:scale(1.08, 1.08); */
46
     transition-duration: 0.5s;
45
     transition-duration: 0.5s;
47
     -webkit-transition-duration: 0.5s;
46
     -webkit-transition-duration: 0.5s;
48
     -webkit-animation-name: greyPulse;
47
     -webkit-animation-name: greyPulse;
107
     display: none;
106
     display: none;
108
 }
107
 }
109
 
108
 
110
-#remoteVideos .videocontainer>span.focusindicator {
109
+#remoteVideos .videocontainer>span.focusindicator,
110
+#remoteVideos .videocontainer>span.remotevideomenu {
111
     display: inline-block;
111
     display: inline-block;
112
     position: absolute;
112
     position: absolute;
113
     color: #FFFFFF;
113
     color: #FFFFFF;

BIN
images/popupPointer.png View File


+ 3
- 1
index.html View File

31
     <script src="prezi.js?v=2"></script><!-- prezi plugin -->
31
     <script src="prezi.js?v=2"></script><!-- prezi plugin -->
32
     <script src="smileys.js?v=1"></script><!-- smiley images -->
32
     <script src="smileys.js?v=1"></script><!-- smiley images -->
33
     <script src="replacement.js?v=5"></script><!-- link and smiley replacement -->
33
     <script src="replacement.js?v=5"></script><!-- link and smiley replacement -->
34
+    <script src="moderatemuc.js?v=1"></script><!-- moderator plugin -->
34
     <script src="analytics.js?v=1"></script><!-- google analytics plugin -->
35
     <script src="analytics.js?v=1"></script><!-- google analytics plugin -->
35
     <link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
36
     <link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
36
     <link rel="stylesheet" href="css/font.css"/>
37
     <link rel="stylesheet" href="css/font.css"/>
38
     <link rel="stylesheet" type="text/css" media="screen" href="css/videolayout_default.css?v=4" id="videolayout_default"/>
39
     <link rel="stylesheet" type="text/css" media="screen" href="css/videolayout_default.css?v=4" id="videolayout_default"/>
39
     <link rel="stylesheet" href="css/jquery-impromptu.css?v=4">
40
     <link rel="stylesheet" href="css/jquery-impromptu.css?v=4">
40
     <link rel="stylesheet" href="css/modaldialog.css?v=3">
41
     <link rel="stylesheet" href="css/modaldialog.css?v=3">
42
+    <link rel="stylesheet" href="css/popup_menu.css?v=1">
41
     <!--
43
     <!--
42
         Link used for inline installation of chrome desktop streaming extension,
44
         Link used for inline installation of chrome desktop streaming extension,
43
         is updated automatically from the code with the value defined in config.js -->
45
         is updated automatically from the code with the value defined in config.js -->
49
   <body>
51
   <body>
50
     <div id="header">
52
     <div id="header">
51
         <span id="toolbar">
53
         <span id="toolbar">
52
-            <a class="button" onclick='buttonClick("#mute", "icon-microphone icon-mic-disabled");toggleAudio();'>
54
+            <a class="button" onclick='toggleAudio();'>
53
                 <i id="mute" title="Mute / unmute" class="icon-microphone"></i></a>
55
                 <i id="mute" title="Mute / unmute" class="icon-microphone"></i></a>
54
             <div class="header_button_separator"></div>
56
             <div class="header_button_separator"></div>
55
             <a class="button" onclick='buttonClick("#video", "icon-camera icon-camera-disabled");toggleVideo();'>
57
             <a class="button" onclick='buttonClick("#video", "icon-camera icon-camera-disabled");toggleVideo();'>

+ 43
- 0
libs/colibri/colibri.focus.js View File

848
     delete this.remotessrc[session.peerjid];
848
     delete this.remotessrc[session.peerjid];
849
     this.modifySources();
849
     this.modifySources();
850
 };
850
 };
851
+
852
+ColibriFocus.prototype.sendTerminate = function (session, reason, text) {
853
+    var term = $iq({to: session.peerjid, type: 'set'})
854
+        .c('jingle',
855
+            {xmlns: 'urn:xmpp:jingle:1',
856
+            action: 'session-terminate',
857
+            initiator: session.me,
858
+            sid: session.sid})
859
+        .c('reason')
860
+        .c(reason || 'success');
861
+
862
+    if (text) {
863
+        term.up().c('text').t(text);
864
+    }
865
+
866
+    this.connection.sendIQ(term,
867
+        function () {
868
+            if (!session)
869
+                return;
870
+
871
+            if (session.peerconnection) {
872
+                session.peerconnection.close();
873
+                session.peerconnection = null;
874
+            }
875
+
876
+            session.terminate();
877
+            var ack = {};
878
+            ack.source = 'terminate';
879
+            $(document).trigger('ack.jingle', [session.sid, ack]);
880
+        },
881
+        function (stanza) {
882
+            var error = ($(stanza).find('error').length) ? {
883
+                code: $(stanza).find('error').attr('code'),
884
+                reason: $(stanza).find('error :first')[0].tagName,
885
+            }:{};
886
+            $(document).trigger('ack.jingle', [self.sid, error]);
887
+        },
888
+        10000);
889
+    if (this.statsinterval !== null) {
890
+        window.clearInterval(this.statsinterval);
891
+        this.statsinterval = null;
892
+    }
893
+};

+ 1
- 1
libs/colibri/colibri.session.js View File

90
 };
90
 };
91
 
91
 
92
 ColibriSession.prototype.sendTerminate = function (reason, text) {
92
 ColibriSession.prototype.sendTerminate = function (reason, text) {
93
-    console.log('ColibriSession.sendTerminate');
93
+    this.colibri.sendTerminate(this, reason, text);
94
 };
94
 };

+ 29
- 3
libs/strophe/strophe.jingle.js View File

112
                 $(document).trigger('callaccepted.jingle', [sess.sid]);
112
                 $(document).trigger('callaccepted.jingle', [sess.sid]);
113
                 break;
113
                 break;
114
             case 'session-terminate':
114
             case 'session-terminate':
115
-                console.log('terminating...');
115
+                // If this is not the focus sending the terminate, we have
116
+                // nothing more to do here.
117
+                if (Object.keys(this.sessions).length < 1
118
+                    || !(this.sessions[Object.keys(this.sessions)[0]]
119
+                        instanceof JingleSession))
120
+                {
121
+                    break;
122
+                }
123
+                console.log('terminating...', sess.sid);
116
                 sess.terminate();
124
                 sess.terminate();
117
                 this.terminate(sess.sid);
125
                 this.terminate(sess.sid);
118
                 if ($(iq).find('>jingle>reason').length) {
126
                 if ($(iq).find('>jingle>reason').length) {
119
                     $(document).trigger('callterminated.jingle', [
127
                     $(document).trigger('callterminated.jingle', [
120
                         sess.sid,
128
                         sess.sid,
129
+                        sess.peerjid,
121
                         $(iq).find('>jingle>reason>:first')[0].tagName,
130
                         $(iq).find('>jingle>reason>:first')[0].tagName,
122
                         $(iq).find('>jingle>reason>text').text()
131
                         $(iq).find('>jingle>reason>text').text()
123
                     ]);
132
                     ]);
124
                 } else {
133
                 } else {
125
-                    $(document).trigger('callterminated.jingle', [sess.sid]);
134
+                    $(document).trigger('callterminated.jingle',
135
+                                        [sess.sid, sess.peerjid]);
126
                 }
136
                 }
127
                 break;
137
                 break;
128
             case 'transport-info':
138
             case 'transport-info':
192
             delete this.sessions[sid];
202
             delete this.sessions[sid];
193
         }
203
         }
194
     },
204
     },
205
+    // Used to terminate a session when an unavailable presence is received.
195
     terminateByJid: function (jid) {
206
     terminateByJid: function (jid) {
196
         if (this.jid2session.hasOwnProperty(jid)) {
207
         if (this.jid2session.hasOwnProperty(jid)) {
197
             var sess = this.jid2session[jid];
208
             var sess = this.jid2session[jid];
200
                 console.log('peer went away silently', jid);
211
                 console.log('peer went away silently', jid);
201
                 delete this.sessions[sess.sid];
212
                 delete this.sessions[sess.sid];
202
                 delete this.jid2session[jid];
213
                 delete this.jid2session[jid];
203
-                $(document).trigger('callterminated.jingle', [sess.sid, 'gone']);
214
+                $(document).trigger('callterminated.jingle',
215
+                                    [sess.sid, jid], 'gone');
216
+            }
217
+        }
218
+    },
219
+    terminateRemoteByJid: function (jid, reason) {
220
+        if (this.jid2session.hasOwnProperty(jid)) {
221
+            var sess = this.jid2session[jid];
222
+            if (sess) {
223
+                sess.sendTerminate(reason || (!sess.active()) ? 'kick' : null);
224
+                sess.terminate();
225
+                console.log('terminate peer with jid', sess.sid, jid);
226
+                delete this.sessions[sess.sid];
227
+                delete this.jid2session[jid];
228
+                $(document).trigger('callterminated.jingle',
229
+                                    [sess.sid, jid, 'kicked']);
204
             }
230
             }
205
         }
231
         }
206
     },
232
     },

+ 50
- 0
moderatemuc.js View File

1
+/**
2
+ * Moderate connection plugin.
3
+ */
4
+Strophe.addConnectionPlugin('moderate', {
5
+    connection: null,
6
+    roomjid: null,
7
+    myroomjid: null,
8
+    members: {},
9
+    list_members: [], // so we can elect a new focus
10
+    presMap: {},
11
+    preziMap: {},
12
+    joined: false,
13
+    isOwner: false,
14
+    init: function (conn) {
15
+        this.connection = conn;
16
+
17
+        this.connection.addHandler( this.onMute.bind(this),
18
+                                    'http://jitsi.org/jitmeet/audio',
19
+                                    'iq',
20
+                                    'set',
21
+                                    null,
22
+                                    null);
23
+    },
24
+    setMute: function(jid, mute) {
25
+        var iq = $iq({to: jid, type: 'set'})
26
+                    .c('mute', {xmlns: 'http://jitsi.org/jitmeet/audio'})
27
+                    .t(mute.toString())
28
+                    .up();
29
+
30
+        this.connection.sendIQ(
31
+                iq,
32
+                function (result) {
33
+                    console.log('set mute', result);
34
+                },
35
+                function (error) {
36
+                    console.log('set mute error', error);
37
+                });
38
+    },
39
+    onMute: function(iq) {
40
+        var mute = $(iq).find('mute');
41
+        if (mute.length) {
42
+            toggleAudio();
43
+        }
44
+        return true;
45
+    },
46
+    eject: function(jid) {
47
+        connection.jingle.terminateRemoteByJid(jid, 'kick');
48
+        connection.emuc.kick(jid);
49
+    }
50
+});

+ 37
- 4
muc.js View File

36
         }
36
         }
37
         this.sendPresence();
37
         this.sendPresence();
38
     },
38
     },
39
+    doLeave: function() {
40
+        console.log("DO LEAVE", this.myroomjid);
41
+        var pres = $pres({to: this.myroomjid, type: 'unavailable' });
42
+        this.presMap.length = 0;
43
+        this.connection.send(pres);
44
+    },
39
     onPresence: function (pres) {
45
     onPresence: function (pres) {
40
         var from = pres.getAttribute('from');
46
         var from = pres.getAttribute('from');
41
         var type = pres.getAttribute('type');
47
         var type = pres.getAttribute('type');
125
     },
131
     },
126
     onPresenceUnavailable: function (pres) {
132
     onPresenceUnavailable: function (pres) {
127
         var from = pres.getAttribute('from');
133
         var from = pres.getAttribute('from');
128
-        delete this.members[from];
129
-        this.list_members.splice(this.list_members.indexOf(from), 1);
130
-        $(document).trigger('left.muc', [from]);
134
+        // Status code 110 indicates that this notification is "self-presence".
135
+        if (!$(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]>status[code="110"]').length) {
136
+            delete this.members[from];
137
+            this.list_members.splice(this.list_members.indexOf(from), 1);
138
+            $(document).trigger('left.muc', [from]);
139
+        }
140
+        // If the status code is 110 this means we're leaving and we would like
141
+        // to remove everyone else from our view, so we trigger the event.
142
+        else if (this.list_members.length > 1) {
143
+            for (var i = 0; i < this.list_members.length; i++) {
144
+                var member = this.list_members[i];
145
+                delete this.members[i];
146
+                this.list_members.splice(i, 1);
147
+                $(document).trigger('left.muc', member);
148
+            }
149
+        }
131
         return true;
150
         return true;
132
     },
151
     },
133
     onPresenceError: function (pres) {
152
     onPresenceError: function (pres) {
188
             }
207
             }
189
         );
208
         );
190
     },
209
     },
210
+    kick: function (jid) {
211
+        var kickIQ = $iq({to: this.roomjid, type: 'set'})
212
+            .c('query', {xmlns: 'http://jabber.org/protocol/muc#admin'})
213
+            .c('item', {nick: Strophe.getResourceFromJid(jid), role: 'none'})
214
+            .c('reason').t('You have been kicked.').up().up().up();
215
+
216
+        this.connection.sendIQ(
217
+                kickIQ,
218
+                function (result) {
219
+                    console.log('Kick participant with jid: ' + jid, result);
220
+                },
221
+                function (error) {
222
+                    console.log('Kick participant error: ', error);
223
+                });
224
+    },
191
     sendPresence: function () {
225
     sendPresence: function () {
192
         var pres = $pres({to: this.presMap['to'] });
226
         var pres = $pres({to: this.presMap['to'] });
193
         pres.c('x', {xmlns: this.presMap['xns']});
227
         pres.c('x', {xmlns: this.presMap['xns']});
210
         }
244
         }
211
 
245
 
212
         if (this.presMap['videons']) {
246
         if (this.presMap['videons']) {
213
-            console.log("SEND VIDEO MUTED", this.presMap['videomuted']);
214
             pres.c('videomuted', {xmlns: this.presMap['videons']})
247
             pres.c('videomuted', {xmlns: this.presMap['videons']})
215
                 .t(this.presMap['videomuted']).up();
248
                 .t(this.presMap['videomuted']).up();
216
         }
249
         }

Loading…
Cancel
Save