Просмотр исходного кода

Merge branch 'master' into callstats_fix

dev1
hristoterezov 9 лет назад
Родитель
Сommit
4f8a0143ef

+ 23
- 4
JitsiConference.js Просмотреть файл

@@ -351,6 +351,13 @@ JitsiConference.prototype.addTrack = function (track) {
351 351
                                    track.audioLevelHandler);
352 352
             //FIXME: This dependacy is not necessary. This is quick fix.
353 353
             track._setConference(this);
354
+
355
+            // send event for starting screen sharing
356
+            // FIXME: we assume we have only one screen sharing track
357
+            // if we change this we need to fix this check
358
+            if (track.isVideoTrack() && track.videoType === "desktop")
359
+                this.statistics.sendScreenSharingEvent(true);
360
+
354 361
             this.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, track);
355 362
             resolve(track);
356 363
         }.bind(this));
@@ -391,6 +398,7 @@ JitsiConference.prototype.removeTrack = function (track) {
391 398
     {
392 399
         throw new Error(JitsiTrackErrors.TRACK_IS_DISPOSED);
393 400
     }
401
+
394 402
     if(!this.room){
395 403
         if(this.rtc) {
396 404
             this.rtc.removeLocalStream(track);
@@ -410,6 +418,13 @@ JitsiConference.prototype.removeTrack = function (track) {
410 418
                 track.audioLevelHandler);
411 419
             this.room.removeListener(XMPPEvents.SENDRECV_STREAMS_CHANGED,
412 420
                 track.ssrcHandler);
421
+
422
+            // send event for stopping screen sharing
423
+            // FIXME: we assume we have only one screen sharing track
424
+            // if we change this we need to fix this check
425
+            if (track.isVideoTrack() && track.videoType === "desktop")
426
+                this.statistics.sendScreenSharingEvent(false);
427
+
413 428
             this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);
414 429
             resolve();
415 430
         }.bind(this), {
@@ -575,6 +590,10 @@ JitsiConference.prototype.onDisplayNameChanged = function (jid, displayName) {
575 590
     if (!participant) {
576 591
         return;
577 592
     }
593
+
594
+    if (participant._displayName === displayName)
595
+        return;
596
+
578 597
     participant._displayName = displayName;
579 598
     this.eventEmitter.emit(JitsiConferenceEvents.DISPLAY_NAME_CHANGED, id, displayName);
580 599
 };
@@ -826,10 +845,10 @@ JitsiConference.prototype.getLogs = function () {
826 845
 };
827 846
 
828 847
 /**
829
- * Returns measured performanceTimes.
848
+ * Returns measured connectionTimes.
830 849
  */
831
-JitsiConference.prototype.getPerformanceTimes = function () {
832
-    return this.room.performanceTimes;
850
+JitsiConference.prototype.getConnectionTimes = function () {
851
+    return this.room.connectionTimes;
833 852
 };
834 853
 
835 854
 /**
@@ -866,7 +885,7 @@ function setupListeners(conference) {
866 885
         if (conference.room.isFocus(jingleSession.peerjid)) {
867 886
             // Accept incoming call
868 887
             conference.room.setJingleSession(jingleSession);
869
-            conference.room.performanceTimes["session.initiate"] = now;
888
+            conference.room.connectionTimes["session.initiate"] = now;
870 889
             jingleSession.initialize(false /* initiator */, conference.room);
871 890
             conference.rtc.onIncommingCall(jingleSession);
872 891
             jingleSession.acceptOffer(jingleOffer, null,

+ 3
- 3
JitsiConnection.js Просмотреть файл

@@ -94,10 +94,10 @@ JitsiConnection.prototype.removeEventListener = function (event, listener) {
94 94
 }
95 95
 
96 96
 /**
97
- * Returns measured performanceTimes.
97
+ * Returns measured connectionTimes.
98 98
  */
99
-JitsiConnection.prototype.getPerformanceTimes = function () {
100
-    return this.xmpp.performanceTimes;
99
+JitsiConnection.prototype.getConnectionTimes = function () {
100
+    return this.xmpp.connectionTimes;
101 101
 };
102 102
 
103 103
 module.exports = JitsiConnection;

+ 3
- 1
JitsiTrackErrors.js Просмотреть файл

@@ -12,7 +12,9 @@ module.exports = {
12 12
             (error.constraintName == "minWidth" ||
13 13
             error.constraintName == "maxWidth" ||
14 14
             error.constraintName == "minHeight" ||
15
-            error.constraintName == "maxHeight") &&
15
+            error.constraintName == "maxHeight" ||
16
+            error.constraintName == "width" ||
17
+            error.constraintName == "height") &&
16 18
             devices.indexOf("video") !== -1) {
17 19
                 return this.UNSUPPORTED_RESOLUTION;
18 20
         } else if(typeof error === "object" && error.type === "jitsiError") {

+ 3
- 3
connection_optimization/external_connect.js Просмотреть файл

@@ -33,7 +33,7 @@ function createConnectionExternally(webserviceUrl, success_callback,
33 33
 
34 34
     xhttp.onreadystatechange = function() {
35 35
         if (xhttp.readyState == xhttp.DONE) {
36
-            var now = window.performanceTimes["external_connect.done"] =
36
+            var now = window.connectionTimes["external_connect.done"] =
37 37
                 window.performance.now();
38 38
             console.log("(TIME) external connect XHR done:\t", now);
39 39
             if (xhttp.status == HTTP_STATUS_OK) {
@@ -53,8 +53,8 @@ function createConnectionExternally(webserviceUrl, success_callback,
53 53
     xhttp.timeout = 3000;
54 54
 
55 55
     xhttp.open("GET", webserviceUrl, true);
56
-    window.performanceTimes = {};
57
-    var now = window.performanceTimes["external_connect.sending"] =
56
+    window.connectionTimes = {};
57
+    var now = window.connectionTimes["external_connect.sending"] =
58 58
         window.performance.now();
59 59
     console.log("(TIME) Sending external connect XHR:\t", now);
60 60
     xhttp.send();

+ 14
- 1
modules/statistics/CallStats.js Просмотреть файл

@@ -32,7 +32,9 @@ var fabricEvent = {
32 32
     videoResume:"videoResume",
33 33
     fabricUsageEvent:"fabricUsageEvent",
34 34
     fabricStats:"fabricStats",
35
-    fabricTerminated:"fabricTerminated"
35
+    fabricTerminated:"fabricTerminated",
36
+    screenShareStart:"screenShareStart",
37
+    screenShareStop:"screenShareStop"
36 38
 };
37 39
 
38 40
 var callStats = null;
@@ -209,6 +211,17 @@ CallStats.sendMuteEvent = _try_catch(function (mute, type, cs) {
209 211
     CallStats._reportEvent.call(cs, event);
210 212
 });
211 213
 
214
+/**
215
+ * Notifies CallStats for screen sharing events
216
+ * @param start {boolean} true for starting screen sharing and
217
+ * false for not stopping
218
+ */
219
+CallStats.sendScreenSharingEvent = _try_catch(function (start, cs) {
220
+
221
+    CallStats._reportEvent.call(cs,
222
+        start? fabricEvent.screenShareStart : fabricEvent.screenShareStop);
223
+});
224
+
212 225
 /**
213 226
  * Reports an error to callstats.
214 227
  *

+ 10
- 0
modules/statistics/statistics.js Просмотреть файл

@@ -193,6 +193,16 @@ Statistics.prototype.sendMuteEvent = function (muted, type) {
193 193
         CallStats.sendMuteEvent(muted, type, this.callstats);
194 194
 };
195 195
 
196
+/**
197
+ * Notifies CallStats for screen sharing events
198
+ * @param start {boolean} true for starting screen sharing and
199
+ * false for not stopping
200
+ */
201
+Statistics.prototype.sendScreenSharingEvent = function (start) {
202
+    if(this.callStatsIntegrationEnabled)
203
+        CallStats.sendScreenSharingEvent(start, this.callstats);
204
+};
205
+
196 206
 /**
197 207
  * Lets the underlying statistics module know where is given SSRC rendered by
198 208
  * providing renderer tag ID.

+ 6
- 6
modules/xmpp/ChatRoom.js Просмотреть файл

@@ -76,14 +76,14 @@ function ChatRoom(connection, jid, password, XMPP, options, settings) {
76 76
     this.bridgeIsDown = false;
77 77
     this.options = options || {};
78 78
     this.moderator = new Moderator(this.roomjid, this.xmpp, this.eventEmitter,
79
-        settings);
79
+        settings, {connection: this.xmpp.options, conference: this.options});
80 80
     this.initPresenceMap();
81 81
     this.session = null;
82 82
     var self = this;
83 83
     this.lastPresences = {};
84 84
     this.phoneNumber = null;
85 85
     this.phonePin = null;
86
-    this.performanceTimes = {};
86
+    this.connectionTimes = {};
87 87
 }
88 88
 
89 89
 ChatRoom.prototype.initPresenceMap = function () {
@@ -264,9 +264,9 @@ ChatRoom.prototype.onPresence = function (pres) {
264 264
         }
265 265
         if (!this.joined) {
266 266
             this.joined = true;
267
-            var now = this.performanceTimes["muc.joined"] =
267
+            var now = this.connectionTimes["muc.joined"] =
268 268
                 window.performance.now();
269
-            console.log("(TIME) MUC joined:\t", now);
269
+            logger.log("(TIME) MUC joined:\t", now);
270 270
             this.eventEmitter.emit(XMPPEvents.MUC_JOINED);
271 271
         }
272 272
     } else if (this.members[from] === undefined) {
@@ -655,7 +655,7 @@ ChatRoom.prototype.addAudioInfoToPresence = function (mute) {
655 655
     this.removeFromPresence("audiomuted");
656 656
     this.addToPresence("audiomuted",
657 657
         {attributes:
658
-        {"audions": "http://jitsi.org/jitmeet/audio"},
658
+        {"xmlns": "http://jitsi.org/jitmeet/audio"},
659 659
             value: mute.toString()});
660 660
 };
661 661
 
@@ -672,7 +672,7 @@ ChatRoom.prototype.addVideoInfoToPresence = function (mute) {
672 672
     this.removeFromPresence("videomuted");
673 673
     this.addToPresence("videomuted",
674 674
         {attributes:
675
-        {"videons": "http://jitsi.org/jitmeet/video"},
675
+        {"xmlns": "http://jitsi.org/jitmeet/video"},
676 676
             value: mute.toString()});
677 677
 };
678 678
 

+ 15
- 11
modules/xmpp/JingleSessionPC.js Просмотреть файл

@@ -152,11 +152,9 @@ JingleSessionPC.prototype.doInitialize = function () {
152 152
      */
153 153
     this.peerconnection.oniceconnectionstatechange = function (event) {
154 154
         if (!(self && self.peerconnection)) return;
155
-        self.room.performanceTimes["ice.state"] =
156
-            self.room.performanceTimes["ice.state"] || [];
157 155
         var now = window.performance.now();
158
-        self.room.performanceTimes["ice.state"].push(
159
-            {state: self.peerconnection.iceConnectionState, time: now});
156
+        self.room.connectionTimes["ice.state." +
157
+            self.peerconnection.iceConnectionState] = now;
160 158
         logger.log("(TIME) ICE " + self.peerconnection.iceConnectionState +
161 159
                     ":\t", now);
162 160
         self.updateModifySourcesQueue();
@@ -785,6 +783,7 @@ JingleSessionPC.prototype.removeSource = function (elem) {
785 783
                 lines += 'a=ssrc-group:' + semantics + ' ' + ssrcs.join(' ') + '\r\n';
786 784
             }
787 785
         });
786
+        var ssrcs = [];
788 787
         var tmp = $(content).find('source[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]'); // can handle both >source and >description>source
789 788
         tmp.each(function () {
790 789
             var ssrc = $(this).attr('ssrc');
@@ -793,18 +792,23 @@ JingleSessionPC.prototype.removeSource = function (elem) {
793 792
                 logger.error("Got remove stream request for my own ssrc: "+ssrc);
794 793
                 return;
795 794
             }
796
-            $(this).find('>parameter').each(function () {
797
-                lines += 'a=ssrc:' + ssrc + ' ' + $(this).attr('name');
798
-                if ($(this).attr('value') && $(this).attr('value').length)
799
-                    lines += ':' + $(this).attr('value');
800
-                lines += '\r\n';
801
-            });
795
+            ssrcs.push(ssrc);
802 796
         });
803 797
         sdp.media.forEach(function(media, idx) {
804 798
             if (!SDPUtil.find_line(media, 'a=mid:' + name))
805 799
                 return;
806
-            sdp.media[idx] += lines;
807 800
             if (!self.removessrc[idx]) self.removessrc[idx] = '';
801
+            ssrcs.forEach(function(ssrc) {
802
+                var ssrcLines = SDPUtil.find_lines(media, 'a=ssrc:' + ssrc);
803
+                if (ssrcLines.length)
804
+                    self.removessrc[idx] += ssrcLines.join("\r\n")+"\r\n";
805
+                // Clear any pending 'source-add' for this SSRC 
806
+                if (self.addssrc[idx]) {
807
+                    self.addssrc[idx]
808
+                        = self.addssrc[idx].replace(
809
+                            new RegExp('^a=ssrc:'+ssrc+' .*\r\n', 'gm'), '');
810
+                }
811
+            });
808 812
             self.removessrc[idx] += lines;
809 813
         });
810 814
         sdp.raw = sdp.session + sdp.media.join('');

+ 1
- 1
modules/xmpp/TraceablePeerConnection.js Просмотреть файл

@@ -400,7 +400,7 @@ var normalizePlanB = function(desc) {
400 400
                 for (i = 0; i<mLine.ssrcs.length; i++){
401 401
                     if (typeof mLine.ssrcs[i] === 'object'
402 402
                         && typeof mLine.ssrcs[i].id !== 'undefined'
403
-                        && !$.inArray(mLine.ssrcs[i].id, firstSsrcs)) {
403
+                        && firstSsrcs.indexOf(mLine.ssrcs[i].id) >= 0) {
404 404
                         newSsrcLines.push(mLine.ssrcs[i]);
405 405
                         delete mLine.ssrcs[i];
406 406
                     }

+ 41
- 30
modules/xmpp/moderator.js Просмотреть файл

@@ -21,7 +21,7 @@ function createExpBackoffTimer(step) {
21 21
     };
22 22
 }
23 23
 
24
-function Moderator(roomName, xmpp, emitter, settings) {
24
+function Moderator(roomName, xmpp, emitter, settings, options) {
25 25
     this.roomName = roomName;
26 26
     this.xmppService = xmpp;
27 27
     this.getNextTimeout = createExpBackoffTimer(1000);
@@ -29,11 +29,13 @@ function Moderator(roomName, xmpp, emitter, settings) {
29 29
     // External authentication stuff
30 30
     this.externalAuthEnabled = false;
31 31
     this.settings = settings;
32
+    this.options = options;
33
+
32 34
     // Sip gateway can be enabled by configuring Jigasi host in config.js or
33 35
     // it will be enabled automatically if focus detects the component through
34 36
     // service discovery.
35
-    this.sipGatewayEnabled = this.xmppService.options.hosts &&
36
-        this.xmppService.options.hosts.call_control !== undefined;
37
+    this.sipGatewayEnabled = this.options.connection.hosts &&
38
+        this.options.connection.hosts.call_control !== undefined;
37 39
 
38 40
     this.eventEmitter = emitter;
39 41
 
@@ -94,10 +96,10 @@ Moderator.prototype.getFocusUserJid =  function () {
94 96
 
95 97
 Moderator.prototype.getFocusComponent =  function () {
96 98
     // Get focus component address
97
-    var focusComponent = this.xmppService.options.hosts.focus;
99
+    var focusComponent = this.options.connection.hosts.focus;
98 100
     // If not specified use default:  'focus.domain'
99 101
     if (!focusComponent) {
100
-        focusComponent = 'focus.' + this.xmppService.options.hosts.domain;
102
+        focusComponent = 'focus.' + this.options.connection.hosts.domain;
101 103
     }
102 104
     return focusComponent;
103 105
 };
@@ -109,7 +111,6 @@ Moderator.prototype.createConferenceIq =  function () {
109 111
     // Session Id used for authentication
110 112
     var sessionId = this.settings.getSessionId();
111 113
     var machineUID = this.settings.getUserId();
112
-    var options = this.xmppService.options;
113 114
 
114 115
     logger.info(
115 116
             "Session ID: " + sessionId + " machine UID: " + machineUID);
@@ -123,75 +124,85 @@ Moderator.prototype.createConferenceIq =  function () {
123 124
     if (sessionId) {
124 125
         elem.attrs({ 'session-id': sessionId});
125 126
     }
126
-    if (options.hosts !== undefined && options.hosts.bridge !== undefined) {
127
+    if (this.options.connection.hosts !== undefined
128
+        && this.options.connection.hosts.bridge !== undefined) {
127 129
         elem.c(
128 130
             'property', {
129 131
                 name: 'bridge',
130
-                value: options.hosts.bridge
132
+                value: this.options.connection.hosts.bridge
131 133
             }).up();
132 134
     }
133
-    if (options.enforcedBridge !== undefined) {
135
+    if (this.options.connection.enforcedBridge !== undefined) {
134 136
         elem.c(
135 137
             'property', {
136 138
                 name: 'enforcedBridge',
137
-                value: options.enforcedBridge
139
+                value: this.options.connection.enforcedBridge
138 140
             }).up();
139 141
     }
140 142
     // Tell the focus we have Jigasi configured
141
-    if (options.hosts !== undefined &&
142
-        options.hosts.call_control !== undefined) {
143
+    if (this.options.connection.hosts !== undefined &&
144
+        this.options.connection.hosts.call_control !== undefined) {
143 145
         elem.c(
144 146
             'property', {
145 147
                 name: 'call_control',
146
-                value: options.hosts.call_control
148
+                value: this.options.connection.hosts.call_control
147 149
             }).up();
148 150
     }
149
-    if (options.channelLastN !== undefined) {
151
+    if (this.options.conference.channelLastN !== undefined) {
150 152
         elem.c(
151 153
             'property', {
152 154
                 name: 'channelLastN',
153
-                value: options.channelLastN
155
+                value: this.options.conference.channelLastN
154 156
             }).up();
155 157
     }
156
-    if (options.adaptiveLastN !== undefined) {
158
+    if (this.options.conference.adaptiveLastN !== undefined) {
157 159
         elem.c(
158 160
             'property', {
159 161
                 name: 'adaptiveLastN',
160
-                value: options.adaptiveLastN
162
+                value: this.options.conference.adaptiveLastN
161 163
             }).up();
162 164
     }
163
-    if (options.disableAdaptiveSimulcast !== undefined ||
164
-        options.disableSimulcast) {
165
+    if (this.options.conference.disableAdaptiveSimulcast !== undefined ||
166
+        this.options.conference.disableSimulcast) {
165 167
         // disableSimulcast implies disableAdaptiveSimulcast.
166
-        var value = options.disableSimulcast ? true :
167
-            options.disableAdaptiveSimulcast;
168
+        var value = this.options.conference.disableSimulcast ? true :
169
+            this.options.conference.disableAdaptiveSimulcast;
168 170
         elem.c(
169 171
             'property', {
170 172
                 name: 'disableAdaptiveSimulcast',
171 173
                 value: value
172 174
             }).up();
173 175
     }
174
-    if (options.openSctp !== undefined) {
176
+    // TODO: re-enable once rtx is stable
177
+    //if (this.options.conference.disableRtx !== undefined) {
178
+        elem.c(
179
+            'property', {
180
+                name: 'disableRtx',
181
+                //value: this.options.conference.disableRtx
182
+                value: true
183
+            }).up();
184
+    //}
185
+    if (this.options.conference.openSctp !== undefined) {
175 186
         elem.c(
176 187
             'property', {
177 188
                 name: 'openSctp',
178
-                value: options.openSctp
189
+                value: this.options.conference.openSctp
179 190
             }).up();
180 191
     }
181
-    if (options.startAudioMuted !== undefined)
192
+    if (this.options.conference.startAudioMuted !== undefined)
182 193
     {
183 194
         elem.c(
184 195
             'property', {
185 196
                 name: 'startAudioMuted',
186
-                value: options.startAudioMuted
197
+                value: this.options.conference.startAudioMuted
187 198
             }).up();
188 199
     }
189
-    if (options.startVideoMuted !== undefined)
200
+    if (this.options.conference.startVideoMuted !== undefined)
190 201
     {
191 202
         elem.c(
192 203
             'property', {
193 204
                 name: 'startVideoMuted',
194
-                value: options.startVideoMuted
205
+                value: this.options.conference.startVideoMuted
195 206
             }).up();
196 207
     }
197 208
 
@@ -263,7 +274,7 @@ Moderator.prototype.parseConfigOptions =  function (resultIq) {
263 274
  */
264 275
 Moderator.prototype.allocateConferenceFocus =  function (callback) {
265 276
     // Try to use focus user JID from the config
266
-    this.setFocusUserJid(this.xmppService.options.focusUserJid);
277
+    this.setFocusUserJid(this.options.connection.focusUserJid);
267 278
     // Send create conference IQ
268 279
     var self = this;
269 280
     this.connection.sendIQ(
@@ -272,7 +283,7 @@ Moderator.prototype.allocateConferenceFocus =  function (callback) {
272 283
             self._allocateConferenceFocusSuccess(result, callback);
273 284
         },
274 285
         function (error) {
275
-            self._allocateConferenceFocusError(error);
286
+            self._allocateConferenceFocusError(error, callback);
276 287
         });
277 288
     // XXX We're pressed for time here because we're beginning a complex and/or
278 289
     // lengthy conference-establishment process which supposedly involves
@@ -322,7 +333,7 @@ Moderator.prototype._allocateConferenceFocusError = function (error, callback) {
322 333
     if ($(error).find('>error>not-authorized').length) {
323 334
         logger.warn("Unauthorized to start the conference", error);
324 335
         var toDomain = Strophe.getDomainFromJid(error.getAttribute('to'));
325
-        if (toDomain !== self.xmppService.options.hosts.anonymousdomain) {
336
+        if (toDomain !== self.options.connection.hosts.anonymousdomain) {
326 337
             //FIXME "is external" should come either from the focus or config.js
327 338
             self.externalAuthEnabled = true;
328 339
         }

+ 1
- 1
modules/xmpp/strophe.jingle.js Просмотреть файл

@@ -95,7 +95,7 @@ module.exports = function(XMPP, eventEmitter) {
95 95
             switch (action) {
96 96
                 case 'session-initiate':
97 97
                     var now = window.performance.now();
98
-                    console.log("(TIME) received session-initiate:\t", now);
98
+                    logger.log("(TIME) received session-initiate:\t", now);
99 99
                     var startMuted = $(iq).find('jingle>startmuted');
100 100
                     if (startMuted && startMuted.length > 0) {
101 101
                         var audioMuted = startMuted.attr("audio");

+ 3
- 5
modules/xmpp/xmpp.js Просмотреть файл

@@ -37,7 +37,7 @@ function XMPP(options, token) {
37 37
     this.eventEmitter = new EventEmitter();
38 38
     this.connection = null;
39 39
     this.disconnectInProgress = false;
40
-    this.performanceTimes = {status: []};
40
+    this.connectionTimes = {};
41 41
     this.forceMuted = false;
42 42
     this.options = options;
43 43
     initStrophePlugins(this);
@@ -62,9 +62,7 @@ XMPP.prototype.getConnection = function () { return this.connection; };
62 62
  */
63 63
 XMPP.prototype.connectionHandler = function (password, status, msg) {
64 64
     var now = window.performance.now();
65
-    this.performanceTimes["status"].push(
66
-        {state: Strophe.getStatusString(status),
67
-        time: now});
65
+    this.connectionTimes[Strophe.getStatusString(status).toLowerCase()] = now;
68 66
     logger.log("(TIME) Strophe " + Strophe.getStatusString(status) +
69 67
         (msg ? "[" + msg + "]" : "") + ":\t", now);
70 68
     if (status === Strophe.Status.CONNECTED ||
@@ -171,7 +169,7 @@ XMPP.prototype._connect = function (jid, password) {
171 169
  * @param options {object} connecting options - rid, sid, jid and password.
172 170
  */
173 171
  XMPP.prototype.attach = function (options) {
174
-    var now = this.performanceTimes["attaching"] = window.performance.now();
172
+    var now = this.connectionTimes["attaching"] = window.performance.now();
175 173
     logger.log("(TIME) Strophe Attaching\t:" + now);
176 174
     this.connection.attach(options.jid, options.sid, parseInt(options.rid,10)+1,
177 175
         this.connectionHandler.bind(this, options.password));

+ 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.5",
22
+    "sdp-simulcast": "0.1.6",
23 23
     "async": "0.9.0",
24 24
     "retry": "0.6.1",
25 25
     "jssha": "1.5.0",

Загрузка…
Отмена
Сохранить