浏览代码

Changes video mute/unmute implementation. JitsiLocalTrack objects store information about the SSRCs. On video mute / unmute operation no jingle packets are sent anymore.

master
hristoterezov 9 年前
父节点
当前提交
5928488dc7

+ 31
- 5
JitsiConference.js 查看文件

@@ -286,6 +286,17 @@ JitsiConference.prototype.addTrack = function (track) {
286 286
             }
287 287
         });
288 288
     }
289
+
290
+    track.ssrcHandler = function (conference, ssrcMap) {
291
+        if(ssrcMap[this.getMSID()]){
292
+            this._setSSRC(ssrcMap[this.getMSID()]);
293
+            conference.room.removeListener(XMPPEvents.SENDRECV_STREAMS_CHANGED,
294
+                this.ssrcHandler);
295
+        }
296
+    }.bind(track, this);
297
+    this.room.addListener(XMPPEvents.SENDRECV_STREAMS_CHANGED,
298
+        track.ssrcHandler);
299
+
289 300
     return new Promise(function (resolve) {
290 301
         this.room.addStream(track.getOriginalStream(), function () {
291 302
             this.rtc.addLocalStream(track);
@@ -309,6 +320,8 @@ JitsiConference.prototype.addTrack = function (track) {
309 320
                                    track.stopHandler);
310 321
             track.addEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,
311 322
                                    track.audioLevelHandler);
323
+            //FIXME: This dependacy is not necessary. This is quick fix.
324
+            track._setConference(this);
312 325
             this.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, track);
313 326
             resolve(track);
314 327
         }.bind(this));
@@ -354,13 +367,24 @@ JitsiConference.prototype.removeTrack = function (track) {
354 367
     }
355 368
     return new Promise(function (resolve) {
356 369
         this.room.removeStream(track.getOriginalStream(), function(){
370
+            track._setSSRC(null);
371
+            //FIXME: This dependacy is not necessary. This is quick fix.
372
+            track._setConference(this);
357 373
             this.rtc.removeLocalStream(track);
358
-            track.removeEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, track.muteHandler);
359
-            track.removeEventListener(JitsiTrackEvents.TRACK_STOPPED, track.stopHandler);
360
-            track.removeEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, track.audioLevelHandler);
374
+            track.removeEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED,
375
+                track.muteHandler);
376
+            track.removeEventListener(JitsiTrackEvents.TRACK_STOPPED,
377
+                track.stopHandler);
378
+            track.removeEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,
379
+                track.audioLevelHandler);
380
+            this.room.removeListener(XMPPEvents.SENDRECV_STREAMS_CHANGED,
381
+                track.ssrcHandler);
361 382
             this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);
362 383
             resolve();
363
-        }.bind(this));
384
+        }.bind(this), {
385
+            mtype: track.getType(),
386
+            type: "remove",
387
+            ssrc: track.ssrc});
364 388
     }.bind(this));
365 389
 };
366 390
 
@@ -1053,7 +1077,9 @@ function setupListeners(conference) {
1053 1077
         }
1054 1078
 
1055 1079
         if (updated) {
1056
-            conference.eventEmitter.emit(JitsiConferenceEvents.AVAILABLE_DEVICES_CHANGED, from, availableDevices);
1080
+            conference.eventEmitter.emit(
1081
+                JitsiConferenceEvents.AVAILABLE_DEVICES_CHANGED,
1082
+                from, availableDevices);
1057 1083
         }
1058 1084
     });
1059 1085
 

+ 33
- 7
modules/RTC/JitsiLocalTrack.js 查看文件

@@ -15,7 +15,9 @@ function JitsiLocalTrack(stream, videoType,
15 15
     this.resolution = resolution;
16 16
     this.deviceId = deviceId;
17 17
     this.startMuted = false;
18
-    var self = this;
18
+    this.ssrc = null;
19
+    //FIXME: This dependacy is not necessary.
20
+    this.conference = null;
19 21
     JitsiTrack.call(this, null, stream,
20 22
         function () {
21 23
             if(!this.dontFireRemoveEvent)
@@ -23,7 +25,6 @@ function JitsiLocalTrack(stream, videoType,
23 25
                     JitsiTrackEvents.TRACK_STOPPED);
24 26
             this.dontFireRemoveEvent = false;
25 27
         }.bind(this));
26
-
27 28
 }
28 29
 
29 30
 JitsiLocalTrack.prototype = Object.create(JitsiTrack.prototype);
@@ -61,7 +62,8 @@ JitsiLocalTrack.prototype._setMute = function (mute) {
61 62
     } else {
62 63
         if (mute) {
63 64
             this.dontFireRemoveEvent = true;
64
-            this.rtc.room.removeStream(this.stream, function () {});
65
+            this.rtc.room.removeStream(this.stream, function () {},
66
+                {mtype: this.type, type: "mute", ssrc: this.ssrc});
65 67
             RTCUtils.stopMediaStream(this.stream);
66 68
             if(isAudio)
67 69
                 this.rtc.room.setAudioMute(mute);
@@ -103,7 +105,7 @@ JitsiLocalTrack.prototype._setMute = function (mute) {
103 105
                                     self.containers[i], self.stream);
104 106
                     }
105 107
 
106
-                    self.rtc.room.addStream(stream.stream,
108
+                    self.rtc.room.addStream(self.stream,
107 109
                         function () {
108 110
                             if(isAudio)
109 111
                                 self.rtc.room.setAudioMute(mute);
@@ -111,7 +113,11 @@ JitsiLocalTrack.prototype._setMute = function (mute) {
111 113
                                 self.rtc.room.setVideoMute(mute);
112 114
                             self.eventEmitter.emit(
113 115
                                 JitsiTrackEvents.TRACK_MUTE_CHANGED);
114
-                        });
116
+                        }, {
117
+                            mtype: self.type,
118
+                            type: "unmute",
119
+                            ssrc: self.ssrc,
120
+                            msid: self.getMSID()});
115 121
                 });
116 122
         }
117 123
     }
@@ -122,10 +128,11 @@ JitsiLocalTrack.prototype._setMute = function (mute) {
122 128
  * NOTE: Works for local tracks only.
123 129
  */
124 130
 JitsiLocalTrack.prototype.stop = function () {
131
+    if(this.conference){
132
+        this.conference.removeTrack(this);
133
+    }
125 134
     if(!this.stream)
126 135
         return;
127
-    if(this.rtc)
128
-        this.rtc.room.removeStream(this.stream, function () {});
129 136
     RTCUtils.stopMediaStream(this.stream);
130 137
     this.detach();
131 138
 }
@@ -163,6 +170,25 @@ JitsiLocalTrack.prototype._setRTC = function (rtc) {
163 170
     this.rtc = rtc;
164 171
 };
165 172
 
173
+/**
174
+ * Updates the SSRC associated with the MediaStream in JitsiLocalTrack object.
175
+ * @ssrc the new ssrc
176
+ */
177
+JitsiLocalTrack.prototype._setSSRC = function (ssrc) {
178
+    this.ssrc = ssrc;
179
+}
180
+
181
+
182
+//FIXME: This dependacy is not necessary. This is quick fix.
183
+/**
184
+ * Sets the JitsiConference object associated with the track. This is temp
185
+ * solution.
186
+ * @param conference the JitsiConference object
187
+ */
188
+JitsiLocalTrack.prototype._setConference = function(conference) {
189
+    this.conference = conference;
190
+}
191
+
166 192
 /**
167 193
  * Gets the SSRC of this local track if it's available already or <tt>null</tt>
168 194
  * otherwise. That's because we don't know the SSRC until local description is

+ 20
- 8
modules/RTC/JitsiTrack.js 查看文件

@@ -77,23 +77,24 @@ function JitsiTrack(rtc, stream, streamInactiveHandler, jitsiTrackType)
77 77
     this.stream = stream;
78 78
     this.eventEmitter = new EventEmitter();
79 79
     this.audioLevel = -1;
80
-    this.type = jitsiTrackType || (this.stream.getVideoTracks().length > 0)?
81
-        JitsiTrack.VIDEO : JitsiTrack.AUDIO;
80
+    this.type = jitsiTrackType || ((this.stream.getVideoTracks().length > 0)?
81
+        JitsiTrack.VIDEO : JitsiTrack.AUDIO);
82 82
     if(this.type == JitsiTrack.AUDIO) {
83 83
         this._getTracks = function () {
84
-            return this.stream.getAudioTracks();
84
+            return this.stream? this.stream.getAudioTracks() : [];
85 85
         }.bind(this);
86 86
     } else {
87 87
         this._getTracks = function () {
88
-            return this.stream.getVideoTracks();
88
+            return this.stream? this.stream.getVideoTracks() : [];
89 89
         }.bind(this);
90 90
     }
91
-    if (RTCBrowserType.isFirefox() && this.stream) {
92
-        implementOnEndedHandling(this);
93
-    }
94 91
 
95
-    if(stream)
92
+    if(stream) {
93
+        if (RTCBrowserType.isFirefox()) {
94
+            implementOnEndedHandling(this);
95
+        }
96 96
         addMediaStreamInactiveHandler(stream, streamInactiveHandler);
97
+    }
97 98
 }
98 99
 
99 100
 /**
@@ -310,4 +311,15 @@ JitsiTrack.prototype.setAudioLevel = function (audioLevel) {
310 311
     }
311 312
  }
312 313
 
314
+/**
315
+ * Returns the msid of the stream attached to the JitsiTrack object or null if
316
+ * no stream is attached.
317
+ */
318
+JitsiTrack.prototype.getMSID = function () {
319
+    var tracks, track;
320
+    return (!this.stream || !this.stream.id || !(tracks = this._getTracks()) ||
321
+        !tracks.length || !(track = tracks[0]) || !track.id)?
322
+            null : this.stream.id + " " + track.id;
323
+}
324
+
313 325
 module.exports = JitsiTrack;

+ 4
- 15
modules/xmpp/ChatRoom.js 查看文件

@@ -562,29 +562,18 @@ ChatRoom.prototype.setJingleSession = function(session){
562 562
 };
563 563
 
564 564
 
565
-ChatRoom.prototype.removeStream = function (stream, callback) {
565
+ChatRoom.prototype.removeStream = function (stream, callback, ssrcInfo) {
566 566
     if(!this.session) {
567 567
         callback();
568 568
         return;
569 569
     }
570
-    this.session.removeStream(stream, callback);
570
+    this.session.removeStream(stream, callback, ssrcInfo);
571 571
 };
572 572
 
573
-ChatRoom.prototype.switchStreams = function (stream, oldStream, callback, isAudio) {
573
+ChatRoom.prototype.addStream = function (stream, callback, ssrcInfo) {
574 574
     if(this.session) {
575 575
         // FIXME: will block switchInProgress on true value in case of exception
576
-        this.session.switchStreams(stream, oldStream, callback, isAudio);
577
-    } else {
578
-        // We are done immediately
579
-        logger.warn("No conference handler or conference not started yet");
580
-        callback();
581
-    }
582
-};
583
-
584
-ChatRoom.prototype.addStream = function (stream, callback) {
585
-    if(this.session) {
586
-        // FIXME: will block switchInProgress on true value in case of exception
587
-        this.session.addStream(stream, callback);
576
+        this.session.addStream(stream, callback, ssrcInfo);
588 577
     } else {
589 578
         // We are done immediately
590 579
         logger.warn("No conference handler or conference not started yet");

+ 164
- 185
modules/xmpp/JingleSessionPC.js 查看文件

@@ -21,7 +21,6 @@ function JingleSessionPC(me, sid, connection, service) {
21 21
     this.state = null;
22 22
     this.localSDP = null;
23 23
     this.remoteSDP = null;
24
-    this.relayedStreams = [];
25 24
 
26 25
     this.usetrickle = true;
27 26
     this.usepranswer = false; // early transport warmup -- mind you, this might fail. depends on webrtc issue 1718
@@ -37,8 +36,8 @@ function JingleSessionPC(me, sid, connection, service) {
37 36
     this.addssrc = [];
38 37
     this.removessrc = [];
39 38
     this.pendingop = null;
40
-    this.switchstreams = false;
41
-    this.addingStreams = false;
39
+    this.modifyingLocalStreams = false;
40
+    this.modifiedSSRCs = {};
42 41
 
43 42
     /**
44 43
      * A map that stores SSRCs of local streams
@@ -182,10 +181,6 @@ JingleSessionPC.prototype.doInitialize = function () {
182 181
     this.peerconnection.onnegotiationneeded = function (event) {
183 182
         self.room.eventEmitter.emit(XMPPEvents.PEERCONNECTION_READY, self);
184 183
     };
185
-
186
-    this.relayedStreams.forEach(function(stream) {
187
-        self.peerconnection.addStream(stream);
188
-    });
189 184
 };
190 185
 
191 186
 function onIceConnectionStateChange(sid, session) {
@@ -461,81 +456,6 @@ JingleSessionPC.prototype.sendIceCandidates = function (candidates) {
461 456
         10000);
462 457
 };
463 458
 
464
-
465
-JingleSessionPC.prototype.sendOffer = function () {
466
-    //logger.log('sendOffer...');
467
-    var self = this;
468
-    this.peerconnection.createOffer(function (sdp) {
469
-            self.createdOffer(sdp);
470
-        },
471
-        function (e) {
472
-            logger.error('createOffer failed', e);
473
-        },
474
-        this.media_constraints
475
-    );
476
-};
477
-
478
-// FIXME createdOffer is never used in jitsi-meet
479
-JingleSessionPC.prototype.createdOffer = function (sdp) {
480
-    //logger.log('createdOffer', sdp);
481
-    var self = this;
482
-    this.localSDP = new SDP(sdp.sdp);
483
-    //this.localSDP.mangle();
484
-    var sendJingle = function () {
485
-        var init = $iq({to: this.peerjid,
486
-            type: 'set'})
487
-            .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
488
-                action: 'session-initiate',
489
-                initiator: this.initiator,
490
-                sid: this.sid});
491
-        self.localSDP.toJingle(
492
-            init,
493
-            this.initiator == this.me ? 'initiator' : 'responder');
494
-
495
-        self.connection.sendIQ(init,
496
-            function () {
497
-                var ack = {};
498
-                ack.source = 'offer';
499
-                $(document).trigger('ack.jingle', [self.sid, ack]);
500
-            },
501
-            function (stanza) {
502
-                self.state = 'error';
503
-                self.peerconnection.close();
504
-                var error = ($(stanza).find('error').length) ? {
505
-                    code: $(stanza).find('error').attr('code'),
506
-                    reason: $(stanza).find('error :first')[0].tagName,
507
-                }:{};
508
-                error.source = 'offer';
509
-                JingleSessionPC.onJingleError(self.sid, error);
510
-            },
511
-            10000);
512
-    }
513
-    sdp.sdp = this.localSDP.raw;
514
-    this.peerconnection.setLocalDescription(sdp,
515
-        function () {
516
-            if(self.usetrickle)
517
-            {
518
-                sendJingle();
519
-            }
520
-            self.setLocalDescription();
521
-            //logger.log('setLocalDescription success');
522
-        },
523
-        function (e) {
524
-            logger.error('setLocalDescription failed', e);
525
-            self.room.eventEmitter.emit(XMPPEvents.CONFERENCE_SETUP_FAILED);
526
-        }
527
-    );
528
-    var cands = SDPUtil.find_lines(this.localSDP.raw, 'a=candidate:');
529
-    for (var i = 0; i < cands.length; i++) {
530
-        var cand = SDPUtil.parse_icecandidate(cands[i]);
531
-        if (cand.type == 'srflx') {
532
-            this.hadstuncandidate = true;
533
-        } else if (cand.type == 'relay') {
534
-            this.hadturncandidate = true;
535
-        }
536
-    }
537
-};
538
-
539 459
 JingleSessionPC.prototype.readSsrcInfo = function (contents) {
540 460
     var self = this;
541 461
     $(contents).each(function (idx, content) {
@@ -1032,7 +952,7 @@ JingleSessionPC.prototype._modifySources = function (successCallback, queueCallb
1032 952
 
1033 953
     if (this.peerconnection.signalingState == 'closed') return;
1034 954
     if (!(this.addssrc.length || this.removessrc.length || this.pendingop !== null
1035
-        || this.switchstreams || this.addingStreams)){
955
+        || this.modifyingLocalStreams)){
1036 956
         // There is nothing to do since scheduled job might have been executed by another succeeding call
1037 957
         this.setLocalDescription();
1038 958
         if(successCallback){
@@ -1043,8 +963,7 @@ JingleSessionPC.prototype._modifySources = function (successCallback, queueCallb
1043 963
     }
1044 964
 
1045 965
     // Reset switch streams flags
1046
-    this.switchstreams = false;
1047
-    this.addingStreams = false;
966
+    this.modifyingLocalStreams = false;
1048 967
 
1049 968
     var sdp = new SDP(this.peerconnection.remoteDescription.sdp);
1050 969
 
@@ -1128,91 +1047,12 @@ JingleSessionPC.prototype._modifySources = function (successCallback, queueCallb
1128 1047
     );
1129 1048
 };
1130 1049
 
1131
-
1132
-/**
1133
- * Switches video streams.
1134
- * @param newStream new stream that will be used as video of this session.
1135
- * @param oldStream old video stream of this session.
1136
- * @param successCallback callback executed after successful stream switch.
1137
- * @param isAudio whether the streams are audio (if true) or video (if false).
1138
- */
1139
-JingleSessionPC.prototype.switchStreams =
1140
-    function (newStream, oldStream, successCallback, isAudio) {
1141
-    var self = this;
1142
-    var sender, newTrack;
1143
-    var senderKind = isAudio ? 'audio' : 'video';
1144
-    // Remember SDP to figure out added/removed SSRCs
1145
-    var oldSdp = null;
1146
-
1147
-    if (self.peerconnection) {
1148
-        if (self.peerconnection.localDescription) {
1149
-            oldSdp = new SDP(self.peerconnection.localDescription.sdp);
1150
-        }
1151
-        if (RTCBrowserType.getBrowserType() ===
1152
-                RTCBrowserType.RTC_BROWSER_FIREFOX) {
1153
-            // On Firefox we don't replace MediaStreams as this messes up the
1154
-            // m-lines (which can't be removed in Plan Unified) and brings a lot
1155
-            // of complications. Instead, we use the RTPSender and replace just
1156
-            // the track.
1157
-
1158
-            // Find the right sender (for audio or video)
1159
-            self.peerconnection.peerconnection.getSenders().some(function (s) {
1160
-                if (s.track && s.track.kind === senderKind) {
1161
-                    sender = s;
1162
-                    return true;
1163
-                }
1164
-            });
1165
-
1166
-            if (sender) {
1167
-                // We assume that our streams have a single track, either audio
1168
-                // or video.
1169
-                newTrack = isAudio ? newStream.getAudioTracks()[0] :
1170
-                    newStream.getVideoTracks()[0];
1171
-                sender.replaceTrack(newTrack)
1172
-                    .then(function() {
1173
-                        console.log("Replaced a track, isAudio=" + isAudio);
1174
-                    })
1175
-                    .catch(function(err) {
1176
-                        console.log("Failed to replace a track: " + err);
1177
-                    });
1178
-            } else {
1179
-                console.log("Cannot switch tracks: no RTPSender.");
1180
-            }
1181
-        } else {
1182
-            self.peerconnection.removeStream(oldStream, true);
1183
-            if (newStream) {
1184
-                self.peerconnection.addStream(newStream);
1185
-            }
1186
-        }
1187
-    }
1188
-
1189
-    // Conference is not active
1190
-    if (!oldSdp) {
1191
-        successCallback();
1192
-        return;
1193
-    }
1194
-
1195
-    self.switchstreams = true;
1196
-    self.modifySourcesQueue.push(function() {
1197
-        logger.log('modify sources done');
1198
-
1199
-        successCallback();
1200
-
1201
-        var newSdp = new SDP(self.peerconnection.localDescription.sdp);
1202
-        logger.log("SDPs", oldSdp, newSdp);
1203
-        self.notifyMySSRCUpdate(oldSdp, newSdp);
1204
-    });
1205
-};
1206
-
1207 1050
 /**
1208 1051
  * Adds streams.
1209 1052
  * @param stream new stream that will be added.
1210 1053
  * @param success_callback callback executed after successful stream addition.
1211 1054
  */
1212
-JingleSessionPC.prototype.addStream = function (stream, callback) {
1213
-
1214
-    var self = this;
1215
-
1055
+JingleSessionPC.prototype.addStream = function (stream, callback, ssrcInfo) {
1216 1056
     // Remember SDP to figure out added/removed SSRCs
1217 1057
     var oldSdp = null;
1218 1058
     if(this.peerconnection) {
@@ -1220,7 +1060,7 @@ JingleSessionPC.prototype.addStream = function (stream, callback) {
1220 1060
             oldSdp = new SDP(this.peerconnection.localDescription.sdp);
1221 1061
         }
1222 1062
         if(stream)
1223
-            this.peerconnection.addStream(stream);
1063
+            this.peerconnection.addStream(stream, ssrcInfo);
1224 1064
     }
1225 1065
 
1226 1066
     // Conference is not active
@@ -1229,12 +1069,17 @@ JingleSessionPC.prototype.addStream = function (stream, callback) {
1229 1069
         return;
1230 1070
     }
1231 1071
 
1232
-    this.addingStreams = true;
1072
+    this.modifyingLocalStreams = true;
1073
+    var self = this;
1233 1074
     this.modifySourcesQueue.push(function() {
1234 1075
         logger.log('modify sources done');
1235 1076
 
1236 1077
         callback();
1237
-
1078
+        if(ssrcInfo) { //available only on video unmute
1079
+            self.modifiedSSRCs[ssrcInfo.type] =
1080
+                self.modifiedSSRCs[ssrcInfo.type] || [];
1081
+            self.modifiedSSRCs[ssrcInfo.type].push(ssrcInfo);
1082
+        }
1238 1083
         var newSdp = new SDP(self.peerconnection.localDescription.sdp);
1239 1084
         logger.log("SDPs", oldSdp, newSdp);
1240 1085
         self.notifyMySSRCUpdate(oldSdp, newSdp);
@@ -1246,10 +1091,7 @@ JingleSessionPC.prototype.addStream = function (stream, callback) {
1246 1091
  * @param stream stream that will be removed.
1247 1092
  * @param success_callback callback executed after successful stream addition.
1248 1093
  */
1249
-JingleSessionPC.prototype.removeStream = function (stream, callback) {
1250
-
1251
-    var self = this;
1252
-
1094
+JingleSessionPC.prototype.removeStream = function (stream, callback, ssrcInfo) {
1253 1095
     // Remember SDP to figure out added/removed SSRCs
1254 1096
     var oldSdp = null;
1255 1097
     if(this.peerconnection) {
@@ -1258,10 +1100,12 @@ JingleSessionPC.prototype.removeStream = function (stream, callback) {
1258 1100
         }
1259 1101
         if (RTCBrowserType.getBrowserType() ===
1260 1102
                 RTCBrowserType.RTC_BROWSER_FIREFOX) {
1103
+            if(!stream)//There is nothing to be changed
1104
+                return;
1261 1105
             var sender = null;
1262 1106
             // On Firefox we don't replace MediaStreams as this messes up the
1263 1107
             // m-lines (which can't be removed in Plan Unified) and brings a lot
1264
-            // of complications. Instead, we use the RTPSender and replace just
1108
+            // of complications. Instead, we use the RTPSender and remove just
1265 1109
             // the track.
1266 1110
             var track = null;
1267 1111
             if(stream.getAudioTracks() && stream.getAudioTracks().length) {
@@ -1272,7 +1116,7 @@ JingleSessionPC.prototype.removeStream = function (stream, callback) {
1272 1116
             }
1273 1117
 
1274 1118
             if(!track) {
1275
-                console.log("Cannot switch tracks: no tracks.");
1119
+                logger.log("Cannot remove tracks: no tracks.");
1276 1120
                 return;
1277 1121
             }
1278 1122
 
@@ -1286,17 +1130,15 @@ JingleSessionPC.prototype.removeStream = function (stream, callback) {
1286 1130
 
1287 1131
             if (sender) {
1288 1132
                 self.peerconnection.peerconnection.removeTrack(sender);
1289
-                    // .then(function() {
1290
-                    //     console.log("Replaced a track, isAudio=" + isAudio);
1291
-                    // })
1292
-                    // .catch(function(err) {
1293
-                    //     console.log("Failed to replace a track: " + err);
1294
-                    // });
1295 1133
             } else {
1296
-                console.log("Cannot switch tracks: no RTPSender.");
1134
+                logger.log("Cannot remove tracks: no RTPSender.");
1297 1135
             }
1298 1136
         } else if(stream)
1299
-            this.peerconnection.removeStream(stream);
1137
+            this.peerconnection.removeStream(stream, false, ssrcInfo);
1138
+        // else
1139
+        // NOTE: If there is no stream and the browser is not FF we still need to do
1140
+        // some transformation in order to send remove-source for the muted
1141
+        // streams. That's why we aren't calling return here.
1300 1142
     }
1301 1143
 
1302 1144
     // Conference is not active
@@ -1305,13 +1147,19 @@ JingleSessionPC.prototype.removeStream = function (stream, callback) {
1305 1147
         return;
1306 1148
     }
1307 1149
 
1308
-    this.addingStreams = true;
1150
+    this.modifyingLocalStreams = true;
1151
+    var self = this;
1309 1152
     this.modifySourcesQueue.push(function() {
1310 1153
         logger.log('modify sources done');
1311 1154
 
1312 1155
         callback();
1313 1156
 
1314 1157
         var newSdp = new SDP(self.peerconnection.localDescription.sdp);
1158
+        if(ssrcInfo) {
1159
+            self.modifiedSSRCs[ssrcInfo.type] =
1160
+                self.modifiedSSRCs[ssrcInfo.type] || [];
1161
+            self.modifiedSSRCs[ssrcInfo.type].push(ssrcInfo);
1162
+        }
1315 1163
         logger.log("SDPs", oldSdp, newSdp);
1316 1164
         self.notifyMySSRCUpdate(oldSdp, newSdp);
1317 1165
     });
@@ -1340,7 +1188,8 @@ JingleSessionPC.prototype.notifyMySSRCUpdate = function (old_sdp, new_sdp) {
1340 1188
             sid: this.sid
1341 1189
         }
1342 1190
     );
1343
-    var removed = sdpDiffer.toJingle(remove);
1191
+    sdpDiffer.toJingle(remove);
1192
+    var removed = this.fixJingle(remove);
1344 1193
 
1345 1194
     if (removed && remove) {
1346 1195
         logger.info("Sending source-remove", remove);
@@ -1366,7 +1215,9 @@ JingleSessionPC.prototype.notifyMySSRCUpdate = function (old_sdp, new_sdp) {
1366 1215
             sid: this.sid
1367 1216
         }
1368 1217
     );
1369
-    var added = sdpDiffer.toJingle(add);
1218
+
1219
+    sdpDiffer.toJingle(add);
1220
+    var added = this.fixJingle(add);
1370 1221
 
1371 1222
     if (added && add) {
1372 1223
         logger.info("Sending source-add", add);
@@ -1563,4 +1414,132 @@ JingleSessionPC.prototype.getIceConnectionState = function () {
1563 1414
     return this.peerconnection.iceConnectionState;
1564 1415
 }
1565 1416
 
1417
+
1418
+/**
1419
+ * Fixes the outgoing jingle packets by removing the nodes related to the
1420
+ * muted/unmuted streams, handles removing of muted stream, etc.
1421
+ * @param jingle the jingle packet that is going to be sent
1422
+ * @returns {boolean} true if the jingle has to be sent and false otherwise.
1423
+ */
1424
+JingleSessionPC.prototype.fixJingle = function(jingle) {
1425
+    var action = $(jingle.nodeTree).find("jingle").attr("action");
1426
+    switch (action) {
1427
+        case "source-add":
1428
+            this.fixSourceAddJingle(jingle);
1429
+            break;
1430
+        case "source-remove":
1431
+            this.fixSourceRemoveJingle(jingle);
1432
+            break;
1433
+        default:
1434
+            logger.error("Unknown jingle action!");
1435
+            return false;
1436
+    }
1437
+
1438
+    var sources = $(jingle.tree()).find(">jingle>content>description>source");
1439
+    return sources && sources.length > 0;
1440
+}
1441
+
1442
+/**
1443
+ * Fixes the outgoing jingle packets with action source-add by removing the
1444
+ * nodes related to the unmuted streams
1445
+ * @param jingle the jingle packet that is going to be sent
1446
+ * @returns {boolean} true if the jingle has to be sent and false otherwise.
1447
+ */
1448
+JingleSessionPC.prototype.fixSourceAddJingle = function (jingle) {
1449
+    var ssrcs = this.modifiedSSRCs["unmute"];
1450
+    this.modifiedSSRCs["unmute"] = [];
1451
+    if(ssrcs && ssrcs.length) {
1452
+        ssrcs.forEach(function (ssrcObj) {
1453
+            var desc = $(jingle.tree()).find(">jingle>content[name=\"" +
1454
+                ssrcObj.mtype + "\"]>description");
1455
+            if(!desc || !desc.length)
1456
+                return;
1457
+            ssrcObj.ssrc.ssrcs.forEach(function (ssrc) {
1458
+                var sourceNode = desc.find(">source[ssrc=\"" +
1459
+                    ssrc + "\"]");
1460
+                sourceNode.remove();
1461
+            });
1462
+            ssrcObj.ssrc.groups.forEach(function (group) {
1463
+                var groupNode = desc.find(">ssrc-group[semantics=\"" +
1464
+                    group.group.semantics + "\"]:has(source[ssrc=\"" +
1465
+                    group.primarySSRC +
1466
+                     "\"])");
1467
+                groupNode.remove();
1468
+            });
1469
+        });
1470
+    }
1471
+}
1472
+
1473
+/**
1474
+ * Fixes the outgoing jingle packets with action source-remove by removing the
1475
+ * nodes related to the muted streams, handles removing of muted stream
1476
+ * @param jingle the jingle packet that is going to be sent
1477
+ * @returns {boolean} true if the jingle has to be sent and false otherwise.
1478
+ */
1479
+JingleSessionPC.prototype.fixSourceRemoveJingle = function(jingle) {
1480
+    var ssrcs = this.modifiedSSRCs["mute"];
1481
+    this.modifiedSSRCs["mute"] = [];
1482
+    if(ssrcs && ssrcs.length)
1483
+        ssrcs.forEach(function (ssrcObj) {
1484
+            ssrcObj.ssrc.ssrcs.forEach(function (ssrc) {
1485
+                var sourceNode = $(jingle.tree()).find(">jingle>content[name=\"" +
1486
+                    ssrcObj.mtype + "\"]>description>source[ssrc=\"" +
1487
+                    ssrc + "\"]");
1488
+                sourceNode.remove();
1489
+            });
1490
+            ssrcObj.ssrc.groups.forEach(function (group) {
1491
+                var groupNode = $(jingle.tree()).find(">jingle>content[name=\"" +
1492
+                    ssrcObj.mtype + "\"]>description>ssrc-group[semantics=\"" +
1493
+                    group.group.semantics + "\"]:has(source[ssrc=\"" + group.primarySSRC +
1494
+                     "\"])");
1495
+                groupNode.remove();
1496
+            });
1497
+        });
1498
+
1499
+    ssrcs = this.modifiedSSRCs["remove"];
1500
+    this.modifiedSSRCs["remove"] = [];
1501
+    if(ssrcs && ssrcs.length)
1502
+        ssrcs.forEach(function (ssrcObj) {
1503
+            var content = $(jingle.tree()).find(">jingle>content[name=\"" +
1504
+                ssrcObj.mtype + "\"]");
1505
+
1506
+            if(!content || !content.length) {
1507
+                $(jingle.tree()).find(">jingle").append(
1508
+                    "<content name=\"" + ssrcObj.mtype + "\"></content>");
1509
+                content = $(jingle.tree()).find(">jingle>content[name=\"" +
1510
+                    ssrcObj.mtype + "\"]");
1511
+            }
1512
+
1513
+            var desc = content.find(">description");
1514
+            if(!desc || !desc.length) {
1515
+                content.append("<description " +
1516
+                    "xmlns=\"urn:xmpp:jingle:apps:rtp:1\" media=\"" +
1517
+                    ssrcObj.mtype + "\"></description>");
1518
+                desc = content.find(">description");
1519
+            }
1520
+
1521
+            ssrcObj.ssrc.ssrcs.forEach(function (ssrc) {
1522
+                var sourceNode = desc.find(">source[ssrc=\"" +ssrc + "\"]");
1523
+                if(!sourceNode || !sourceNode.length) {
1524
+                    //Maybe we have to include cname, msid, etc here?
1525
+                    desc.append("<source " +
1526
+                        "xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\" ssrc=\"" +
1527
+                        ssrc + "\"></source>");
1528
+                }
1529
+            });
1530
+            ssrcObj.ssrc.groups.forEach(function (group) {
1531
+                var groupNode = desc.find(">ssrc-group[semantics=\"" +
1532
+                    group.group.semantics + "\"]:has(source[ssrc=\"" + group.primarySSRC +
1533
+                     "\"])");
1534
+                if(!groupNode || !groupNode.length) {
1535
+                    desc.append("<ssrc-group semantics=\"" +
1536
+                        group.group.semantics +
1537
+                        "\" xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"><source ssrc=\"" +
1538
+                        group.group.ssrcs.split(" ").join("\"/><source ssrc=\"") + "\"/>" +
1539
+                        "</ssrc-group>");
1540
+                }
1541
+            });
1542
+        });
1543
+}
1544
+
1566 1545
 module.exports = JingleSessionPC;

+ 182
- 59
modules/xmpp/TraceablePeerConnection.js 查看文件

@@ -3,10 +3,15 @@ var RTC = require('../RTC/RTC');
3 3
 var logger = require("jitsi-meet-logger").getLogger(__filename);
4 4
 var RTCBrowserType = require("../RTC/RTCBrowserType.js");
5 5
 var XMPPEvents = require("../../service/xmpp/XMPPEvents");
6
+var transform = require('sdp-transform');
6 7
 
7 8
 function TraceablePeerConnection(ice_config, constraints, session) {
8 9
     var self = this;
9 10
     this.session = session;
11
+    this.replaceSSRCs = {
12
+        "audio": [],
13
+        "video": []
14
+    };
10 15
     this.recvOnlySSRCs = {};
11 16
     var RTCPeerConnectionType = null;
12 17
     if (RTCBrowserType.isFirefox()) {
@@ -144,14 +149,13 @@ var dumpSDP = function(description) {
144 149
  * @param desc the SDP that will be modified.
145 150
  * @returns the modified SDP.
146 151
  */
147
-TraceablePeerConnection.prototype.insertRecvOnlySSRC = function (desc) {
152
+TraceablePeerConnection.prototype.ssrcReplacement = function (desc) {
148 153
     if (typeof desc !== 'object' || desc === null ||
149 154
         typeof desc.sdp !== 'string') {
150 155
         console.warn('An empty description was passed as an argument.');
151 156
         return desc;
152 157
     }
153 158
 
154
-    var transform = require('sdp-transform');
155 159
     var RandomUtil = require('../util/RandomUtil');
156 160
 
157 161
     var session = transform.parse(desc.sdp);
@@ -162,12 +166,107 @@ TraceablePeerConnection.prototype.insertRecvOnlySSRC = function (desc) {
162 166
 
163 167
     var modded = false;
164 168
     session.media.forEach(function (bLine) {
165
-        if (bLine.direction != 'recvonly')
166
-        {
169
+        if(!this.replaceSSRCs[bLine.type])
167 170
             return;
168
-        }
169 171
 
170 172
         modded = true;
173
+        var SSRCs = this.replaceSSRCs[bLine.type].splice(0,1);
174
+        //FIXME: The code expects that we have only SIM group or we
175
+        // don't have any groups and we have only one SSRC per
176
+        // stream. If we add another groups (FID, etc) this code
177
+        // must be changed.
178
+        while(SSRCs &&
179
+            SSRCs.length){
180
+            var ssrcOperation = SSRCs[0];
181
+            switch(ssrcOperation.type) {
182
+                case "mute":
183
+                //FIXME: If we want to support multiple streams we have to add
184
+                // recv-only ssrcs for the
185
+                // muted streams on every change until the stream is unmuted
186
+                // or removed. Otherwise the recv-only streams won't be included
187
+                // in the SDP
188
+                    if(!bLine.ssrcs)
189
+                        bLine.ssrcs = [];
190
+                    var groups = ssrcOperation.ssrc.groups;
191
+                    var ssrc = null;
192
+                    if(groups && groups.length) {
193
+                        ssrc = groups[0].primarySSRC;
194
+                    } else if(ssrcOperation.ssrc.ssrcs &&
195
+                        ssrcOperation.ssrc.ssrcs.length) {
196
+                        ssrc = ssrcOperation.ssrc.ssrcs[0];
197
+                    } else {
198
+                        logger.error("SSRC replacement error!");
199
+                        break;
200
+                    }
201
+                    bLine.ssrcs.push({
202
+                        id: ssrc,
203
+                        attribute: 'cname',
204
+                        value: ['recvonly-', ssrc].join('')
205
+                    })
206
+                    break;
207
+                case "unmute":
208
+                    if(!ssrcOperation.ssrc || !ssrcOperation.ssrc.ssrcs ||
209
+                        !ssrcOperation.ssrc.ssrcs.length)
210
+                        break;
211
+                    var ssrcMap = {};
212
+                    var ssrcLastIdx = ssrcOperation.ssrc.ssrcs.length - 1;
213
+                    for(var i = 0; i < bLine.ssrcs.length; i++) {
214
+                        var ssrc = bLine.ssrcs[i];
215
+                        if (ssrc.attribute !== 'msid' &&
216
+                            ssrc.value !== ssrcOperation.msid) {
217
+                            continue;
218
+                        }
219
+                        ssrcMap[ssrc.id] =
220
+                            ssrcOperation.ssrc.ssrcs[ssrcLastIdx];
221
+                        ssrcLastIdx--;
222
+                        if(ssrcLastIdx < 0)
223
+                            break;
224
+                    }
225
+                    var groups = ssrcOperation.ssrc.groups;
226
+                    if (typeof bLine.ssrcGroups !== 'undefined' &&
227
+                        Array.isArray(bLine.ssrcGroups) && groups &&
228
+                        groups.length) {
229
+                        bLine.ssrcGroups.forEach(function (group) {
230
+                            if(!group.ssrcs)
231
+                                return;
232
+                            var currentSSRCs = group.ssrcs.split(" ");
233
+                            var newGroup = null;
234
+                            for(var i = 0; i < groups.length; i++) {
235
+                                newGroup = groups[i].group;
236
+                                var newSSRCs = newGroup.ssrcs.split(" ");
237
+                                if(newGroup.semantics !== group.semantics)
238
+                                    continue;
239
+                                var wrongGroup = false;
240
+                                for(var j = 0; j < currentSSRCs.length; j++) {
241
+                                    if(newGroup.ssrcs.indexOf(
242
+                                        ssrcMap[currentSSRCs[j]]) === -1){
243
+                                        wrongGroup = true;
244
+                                        break;
245
+                                    }
246
+                                }
247
+                                if(!wrongGroup) {
248
+                                    for(j = 0; j < newSSRCs.length; j++) {
249
+                                        ssrcMap[currentSSRCs[j]] = newSSRCs[j];
250
+                                    }
251
+                                    break;
252
+                                }
253
+                            }
254
+
255
+                            group.ssrcs = newGroup.ssrcs;
256
+                        });
257
+                    }
258
+                    bLine.ssrcs.forEach(function (ssrc) {
259
+                        if(ssrcMap[ssrc.id]) {
260
+                            ssrc.id = ssrcMap[ssrc.id];
261
+                        }
262
+                    });
263
+                    break;
264
+                default:
265
+                break;
266
+            }
267
+            SSRCs = this.replaceSSRCs[bLine.type].splice(0,1);
268
+        }
269
+
171 270
         if (!Array.isArray(bLine.ssrcs) || bLine.ssrcs.length === 0)
172 271
         {
173 272
             var ssrc = this.recvOnlySSRCs[bLine.type]
@@ -187,6 +286,60 @@ TraceablePeerConnection.prototype.insertRecvOnlySSRC = function (desc) {
187 286
     });
188 287
 };
189 288
 
289
+/**
290
+ * Returns map with keys msid and values ssrc.
291
+ * @param desc the SDP that will be modified.
292
+ */
293
+function extractSSRCMap(desc) {
294
+    if (typeof desc !== 'object' || desc === null ||
295
+        typeof desc.sdp !== 'string') {
296
+        console.warn('An empty description was passed as an argument.');
297
+        return desc;
298
+    }
299
+
300
+    var ssrcList = {};
301
+    var ssrcGroups = {};
302
+    var session = transform.parse(desc.sdp);
303
+    if (!Array.isArray(session.media))
304
+    {
305
+        return;
306
+    }
307
+
308
+    session.media.forEach(function (bLine) {
309
+        if (!Array.isArray(bLine.ssrcs))
310
+        {
311
+            return;
312
+        }
313
+
314
+        if (typeof bLine.ssrcGroups !== 'undefined' &&
315
+            Array.isArray(bLine.ssrcGroups)) {
316
+            bLine.ssrcGroups.forEach(function (group) {
317
+                if (typeof group.semantics !== 'undefined' &&
318
+                    typeof group.ssrcs !== 'undefined') {
319
+                    var primarySSRC = Number(group.ssrcs.split(' ')[0]);
320
+                    ssrcGroups[primarySSRC] = ssrcGroups[primarySSRC] || [];
321
+                    ssrcGroups[primarySSRC].push(group);
322
+                }
323
+            });
324
+        }
325
+        bLine.ssrcs.forEach(function (ssrc) {
326
+            if(ssrc.attribute !== 'msid')
327
+                return;
328
+            ssrcList[ssrc.value] = ssrcList[ssrc.value] ||
329
+                {groups: [], ssrcs: []};
330
+            ssrcList[ssrc.value].ssrcs.push(ssrc.id);
331
+            if(ssrcGroups[ssrc.id]){
332
+                ssrcGroups[ssrc.id].forEach(function (group) {
333
+                    ssrcList[ssrc.value].groups.push(
334
+                        {primarySSRC: ssrc.id, group: group});
335
+                });
336
+            }
337
+        });
338
+    });
339
+
340
+    return ssrcList;
341
+}
342
+
190 343
 /**
191 344
  * Takes a SessionDescription object and returns a "normalized" version.
192 345
  * Currently it only takes care of ordering the a=ssrc lines.
@@ -201,8 +354,8 @@ var normalizePlanB = function(desc) {
201 354
     var transform = require('sdp-transform');
202 355
     var session = transform.parse(desc.sdp);
203 356
 
204
-    if (typeof session !== 'undefined' && typeof session.media !== 'undefined' &&
205
-        Array.isArray(session.media)) {
357
+    if (typeof session !== 'undefined' &&
358
+        typeof session.media !== 'undefined' && Array.isArray(session.media)) {
206 359
         session.media.forEach(function (mLine) {
207 360
 
208 361
             // Chrome appears to be picky about the order in which a=ssrc lines
@@ -215,7 +368,8 @@ var normalizePlanB = function(desc) {
215 368
             var firstSsrcs = [];
216 369
             var newSsrcLines = [];
217 370
 
218
-            if (typeof mLine.ssrcGroups !== 'undefined' && Array.isArray(mLine.ssrcGroups)) {
371
+            if (typeof mLine.ssrcGroups !== 'undefined' &&
372
+                Array.isArray(mLine.ssrcGroups)) {
219 373
                 mLine.ssrcGroups.forEach(function (group) {
220 374
                     if (typeof group.semantics !== 'undefined' &&
221 375
                         group.semantics === 'FID') {
@@ -296,11 +450,13 @@ Object.keys(getters).forEach(function (prop) {
296 450
     );
297 451
 });
298 452
 
299
-TraceablePeerConnection.prototype.addStream = function (stream) {
453
+TraceablePeerConnection.prototype.addStream = function (stream, ssrcInfo) {
300 454
     this.trace('addStream', stream.id);
301 455
     try
302 456
     {
303 457
         this.peerconnection.addStream(stream);
458
+        if(ssrcInfo && this.replaceSSRCs[ssrcInfo.mtype])
459
+            this.replaceSSRCs[ssrcInfo.mtype].push(ssrcInfo);
304 460
     }
305 461
     catch (e)
306 462
     {
@@ -308,7 +464,8 @@ TraceablePeerConnection.prototype.addStream = function (stream) {
308 464
     }
309 465
 };
310 466
 
311
-TraceablePeerConnection.prototype.removeStream = function (stream, stopStreams) {
467
+TraceablePeerConnection.prototype.removeStream = function (stream, stopStreams,
468
+ssrcInfo) {
312 469
     this.trace('removeStream', stream.id);
313 470
     if(stopStreams) {
314 471
         RTC.stopMediaStream(stream);
@@ -316,8 +473,11 @@ TraceablePeerConnection.prototype.removeStream = function (stream, stopStreams)
316 473
 
317 474
     try {
318 475
         // FF doesn't support this yet.
319
-        if (this.peerconnection.removeStream)
476
+        if (this.peerconnection.removeStream) {
320 477
             this.peerconnection.removeStream(stream);
478
+            if(ssrcInfo && this.replaceSSRCs[ssrcInfo.mtype])
479
+                this.replaceSSRCs[ssrcInfo.mtype].push(ssrcInfo);
480
+        }
321 481
     } catch (e) {
322 482
         logger.error(e);
323 483
     }
@@ -399,47 +559,6 @@ TraceablePeerConnection.prototype.close = function () {
399 559
     this.peerconnection.close();
400 560
 };
401 561
 
402
-TraceablePeerConnection.prototype.createOffer
403
-        = function (successCallback, failureCallback, constraints) {
404
-    var self = this;
405
-    this.trace('createOffer', JSON.stringify(constraints, null, ' '));
406
-    this.peerconnection.createOffer(
407
-        function (offer) {
408
-            self.trace('createOfferOnSuccess::preTransform', dumpSDP(offer));
409
-            // NOTE this is not tested because in meet the focus generates the
410
-            // offer.
411
-
412
-            // if we're running on FF, transform to Plan B first.
413
-            if (RTCBrowserType.usesUnifiedPlan()) {
414
-                offer = self.interop.toPlanB(offer);
415
-                self.trace('createOfferOnSuccess::postTransform (Plan B)', dumpSDP(offer));
416
-            }
417
-
418
-            if (RTCBrowserType.isChrome())
419
-            {
420
-                offer = self.insertRecvOnlySSRC(offer);
421
-                self.trace('createAnswerOnSuccess::mungeLocalVideoSSRC',
422
-                    dumpSDP(offer));
423
-            }
424
-
425
-            if (!self.session.room.options.disableSimulcast
426
-                 && self.simulcast.isSupported()) {
427
-                offer = self.simulcast.mungeLocalDescription(offer);
428
-                self.trace('createOfferOnSuccess::postTransform (simulcast)',
429
-                    dumpSDP(offer));
430
-            }
431
-            successCallback(offer);
432
-        },
433
-        function(err) {
434
-            self.trace('createOfferOnFailure', err);
435
-            self.eventEmitter.emit(XMPPEvents.CREATE_OFFER_FAILED, err,
436
-                self.peerconnection);
437
-            failureCallback(err);
438
-        },
439
-        constraints
440
-    );
441
-};
442
-
443 562
 TraceablePeerConnection.prototype.createAnswer
444 563
         = function (successCallback, failureCallback, constraints) {
445 564
     var self = this;
@@ -454,19 +573,23 @@ TraceablePeerConnection.prototype.createAnswer
454 573
                     dumpSDP(answer));
455 574
             }
456 575
 
457
-            if (RTCBrowserType.isChrome())
458
-            {
459
-                answer = self.insertRecvOnlySSRC(answer);
460
-                self.trace('createAnswerOnSuccess::mungeLocalVideoSSRC',
461
-                    dumpSDP(answer));
462
-            }
463
-
464 576
             if (!self.session.room.options.disableSimulcast
465 577
                 && self.simulcast.isSupported()) {
466 578
                 answer = self.simulcast.mungeLocalDescription(answer);
467 579
                 self.trace('createAnswerOnSuccess::postTransform (simulcast)',
468 580
                     dumpSDP(answer));
469 581
             }
582
+
583
+            if (!RTCBrowserType.isFirefox())
584
+            {
585
+                answer = self.ssrcReplacement(answer);
586
+                self.trace('createAnswerOnSuccess::mungeLocalVideoSSRC',
587
+                    dumpSDP(answer));
588
+            }
589
+
590
+            self.eventEmitter.emit(XMPPEvents.SENDRECV_STREAMS_CHANGED,
591
+                extractSSRCMap(answer));
592
+
470 593
             successCallback(answer);
471 594
         },
472 595
         function(err) {

+ 0
- 19
modules/xmpp/xmpp.js 查看文件

@@ -33,24 +33,6 @@ function initStrophePlugins(XMPP) {
33 33
     require("./strophe.logger")();
34 34
 }
35 35
 
36
-//!!!!!!!!!! FIXME: ...
37
-///**
38
-// * If given <tt>localStream</tt> is video one this method will advertise it's
39
-// * video type in MUC presence.
40
-// * @param localStream new or modified <tt>LocalStream</tt>.
41
-// */
42
-//function broadcastLocalVideoType(localStream) {
43
-//    if (localStream.videoType)
44
-//        XMPP.addToPresence('videoType', localStream.videoType);
45
-//}
46
-//
47
-//function registerListeners() {
48
-//    RTC.addStreamListener(
49
-//        broadcastLocalVideoType,
50
-//        StreamEventTypes.EVENT_TYPE_LOCAL_CHANGED
51
-//    );
52
-//}
53
-
54 36
 function XMPP(options) {
55 37
     this.eventEmitter = new EventEmitter();
56 38
     this.connection = null;
@@ -59,7 +41,6 @@ function XMPP(options) {
59 41
     this.forceMuted = false;
60 42
     this.options = options;
61 43
     initStrophePlugins(this);
62
-//    registerListeners();
63 44
 
64 45
     this.connection = createConnection(options.bosh);
65 46
 

+ 1
- 1
package.json 查看文件

@@ -19,7 +19,7 @@
19 19
     "pako": "*",
20 20
     "sdp-interop": "0.1.11",
21 21
     "sdp-transform": "1.5.*",
22
-    "sdp-simulcast": "0.1.4",
22
+    "sdp-simulcast": "0.1.5",
23 23
     "async": "0.9.0",
24 24
     "retry": "0.6.1",
25 25
     "jssha": "1.5.0",

+ 5
- 1
service/xmpp/XMPPEvents.js 查看文件

@@ -112,6 +112,10 @@ var XMPPEvents = {
112 112
     /**
113 113
      * Indicates error while adding ice candidate.
114 114
      */
115
-    ADD_ICE_CANDIDATE_FAILED: "xmpp.add_ice_candidate_failed"
115
+    ADD_ICE_CANDIDATE_FAILED: "xmpp.add_ice_candidate_failed",
116
+    /**
117
+     * Indicates that the local sendrecv streams in local SDP are changed.
118
+     */
119
+    SENDRECV_STREAMS_CHANGED: "xmpp.sendrecv_streams_changed"
116 120
 };
117 121
 module.exports = XMPPEvents;

正在加载...
取消
保存