浏览代码

fix(unified-plan): Use the new sdp-interop module for Unified plan

Switch to using ontrack for remote tracks, re-use mids/transceivers when remote sources are removed and added.
master
Jaya Allamsetty 5 年前
父节点
当前提交
190a9e44d0

+ 37
- 2
modules/RTC/TPCUtils.js 查看文件

@@ -49,6 +49,40 @@ export class TPCUtils {
49 49
         ];
50 50
     }
51 51
 
52
+    /**
53
+     * Ensures that the ssrcs associated with a FID ssrc-group appear in the correct order, i.e.,
54
+     * the primary ssrc first and the secondary rtx ssrc later. This is important for unified
55
+     * plan since we have only one FID group per media description.
56
+     * @param {Object} description the webRTC session description instance for the remote
57
+     * description.
58
+     * @private
59
+     */
60
+    _ensureCorrectOrderOfSsrcs(description) {
61
+        const parsedSdp = transform.parse(description.sdp);
62
+
63
+        parsedSdp.media.forEach(mLine => {
64
+            if (mLine.type === 'audio') {
65
+                return;
66
+            }
67
+            if (!mLine.ssrcGroups || !mLine.ssrcGroups.length) {
68
+                return;
69
+            }
70
+            let reorderedSsrcs = [];
71
+
72
+            mLine.ssrcGroups[0].ssrcs.split(' ').forEach(ssrc => {
73
+                const sources = mLine.ssrcs.filter(source => source.id.toString() === ssrc);
74
+
75
+                reorderedSsrcs = reorderedSsrcs.concat(sources);
76
+            });
77
+            mLine.ssrcs = reorderedSsrcs;
78
+        });
79
+
80
+        return new RTCSessionDescription({
81
+            type: description.type,
82
+            sdp: transform.write(parsedSdp)
83
+        });
84
+    }
85
+
52 86
     /**
53 87
      * Obtains stream encodings that need to be configured on the given track.
54 88
      * @param {JitsiLocalTrack} localTrack
@@ -176,7 +210,7 @@ export class TPCUtils {
176 210
 
177 211
             return false;
178 212
         }
179
-        logger.info(`Adding ${localTrack} on ${this.pc}`);
213
+        logger.debug(`Adding ${localTrack} on ${this.pc}`);
180 214
 
181 215
         // If the client starts with audio/video muted setting, the transceiver direction
182 216
         // will be set to 'recvonly'. Use addStream here so that a MSID is generated for the stream.
@@ -218,7 +252,7 @@ export class TPCUtils {
218 252
             return false;
219 253
         }
220 254
 
221
-        logger.info(`Removing ${localTrack} on ${this.pc}`);
255
+        logger.debug(`Removing ${localTrack} on ${this.pc}`);
222 256
         transceiver.sender.replaceTrack(null)
223 257
             .then(() => {
224 258
                 this.pc.localTracks.delete(localTrack.rtcId);
@@ -252,6 +286,7 @@ export class TPCUtils {
252 286
             if (!transceiver) {
253 287
                 return Promise.reject(new Error('replace track failed'));
254 288
             }
289
+            logger.debug(`Replacing ${oldTrack} with ${newTrack} on ${this.pc}`);
255 290
 
256 291
             return transceiver.sender.replaceTrack(track)
257 292
                 .then(() => {

+ 107
- 191
modules/RTC/TraceablePeerConnection.js 查看文件

@@ -1,6 +1,7 @@
1 1
 /* global __filename, RTCSessionDescription */
2 2
 
3 3
 import { getLogger } from 'jitsi-meet-logger';
4
+import { Interop } from '@jitsi/sdp-interop';
4 5
 import transform from 'sdp-transform';
5 6
 
6 7
 import * as GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';
@@ -220,7 +221,6 @@ export default function TraceablePeerConnection(
220 221
      * 300 values, i.e. 5 minutes; set to 0 to disable
221 222
      */
222 223
     this.maxstats = options.maxstats;
223
-    const Interop = require('@jitsi/sdp-interop').Interop;
224 224
 
225 225
     this.interop = new Interop();
226 226
     const Simulcast = require('@jitsi/sdp-simulcast');
@@ -267,10 +267,23 @@ export default function TraceablePeerConnection(
267 267
             this.onicecandidate(event);
268 268
         }
269 269
     };
270
-    this.peerconnection.onaddstream
271
-        = event => this._remoteStreamAdded(event.stream);
272
-    this.peerconnection.onremovestream
273
-        = event => this._remoteStreamRemoved(event.stream);
270
+
271
+    // Use stream events in plan-b and track events in unified plan.
272
+    if (browser.usesPlanB()) {
273
+        this.peerconnection.onaddstream
274
+            = event => this._remoteStreamAdded(event.stream);
275
+        this.peerconnection.onremovestream
276
+            = event => this._remoteStreamRemoved(event.stream);
277
+    } else {
278
+        this.peerconnection.ontrack = event => {
279
+            const stream = event.streams[0];
280
+
281
+            this._remoteTrackAdded(stream, event.track, event.transceiver);
282
+            stream.onremovetrack = evt => {
283
+                this._remoteTrackRemoved(stream, evt.track);
284
+            };
285
+        };
286
+    }
274 287
     this.onsignalingstatechange = null;
275 288
     this.peerconnection.onsignalingstatechange = event => {
276 289
         this.trace('onsignalingstatechange', this.signalingState);
@@ -421,16 +434,7 @@ TraceablePeerConnection.prototype._getDesiredMediaDirection = function(
421 434
  * <tt>false</tt> if it's turned off.
422 435
  */
423 436
 TraceablePeerConnection.prototype.isSimulcastOn = function() {
424
-    return !this.options.disableSimulcast
425
-        && browser.supportsSimulcast()
426
-
427
-        // Firefox has been added as supporting simulcast, but it is
428
-        // experimental so we only want to do it for firefox if the config
429
-        // option is set.  Unfortunately, browser::supportsSimulcast()
430
-        // doesn't have a reference to the config options, so we have
431
-        // to do it here
432
-        && (!browser.isFirefox()
433
-            || this.options.enableFirefoxSimulcast);
437
+    return !this.options.disableSimulcast;
434 438
 };
435 439
 
436 440
 /**
@@ -644,12 +648,21 @@ TraceablePeerConnection.prototype._remoteStreamAdded = function(stream) {
644 648
  * @param {MediaStream} stream the WebRTC MediaStream instance which is
645 649
  * the parent of the track
646 650
  * @param {MediaStreamTrack} track the WebRTC MediaStreamTrack added for remote
647
- * participant
651
+ * participant.
652
+ * @param {RTCRtpTransceiver} transceiver the WebRTC transceiver that is created
653
+ * for the remote participant in unified plan.
648 654
  */
649
-TraceablePeerConnection.prototype._remoteTrackAdded = function(stream, track) {
655
+TraceablePeerConnection.prototype._remoteTrackAdded = function(stream, track, transceiver = null) {
650 656
     const streamId = RTC.getStreamID(stream);
651 657
     const mediaType = track.kind;
652 658
 
659
+    if (!this.isP2P && !RTC.isUserStreamById(streamId)) {
660
+        logger.info(
661
+            `${this} ignored remote 'stream added' event for non-user stream`
662
+             + `id: ${streamId}`);
663
+
664
+        return;
665
+    }
653 666
     logger.info(`${this} remote track added:`, streamId, mediaType);
654 667
 
655 668
     // look up an associated JID for a stream id
@@ -663,9 +676,26 @@ TraceablePeerConnection.prototype._remoteTrackAdded = function(stream, track) {
663 676
         return;
664 677
     }
665 678
 
666
-    const remoteSDP = new SDP(this.remoteDescription.sdp);
667
-    const mediaLines
668
-        = remoteSDP.media.filter(mls => mls.startsWith(`m=${mediaType}`));
679
+    const remoteSDP = browser.usesPlanB()
680
+        ? new SDP(this.remoteDescription.sdp)
681
+        : new SDP(this.peerconnection.remoteDescription.sdp);
682
+    let mediaLines;
683
+
684
+    if (browser.usesUnifiedPlan()) {
685
+        if (transceiver && transceiver.mid) {
686
+            const mid = transceiver.mid;
687
+
688
+            mediaLines = remoteSDP.media.filter(mls => SDPUtil.findLine(mls, `a=mid:${mid}`));
689
+        } else {
690
+            mediaLines = remoteSDP.media.filter(mls => {
691
+                const msid = SDPUtil.findLine(mls, 'a=msid');
692
+
693
+                return typeof msid !== 'undefined' && streamId === msid.substring(7).split(' ')[0];
694
+            });
695
+        }
696
+    } else {
697
+        mediaLines = remoteSDP.media.filter(mls => mls.startsWith(`m=${mediaType}`));
698
+    }
669 699
 
670 700
     if (!mediaLines.length) {
671 701
         GlobalOnErrorHandler.callErrorHandler(
@@ -1321,24 +1351,24 @@ const getters = {
1321 1351
             desc = this._injectSsrcGroupForUnifiedSimulcast(desc);
1322 1352
             this.trace('getLocalDescription::postTransform (inject ssrc group)',
1323 1353
                 dumpSDP(desc));
1324
-        }
1354
+        } else {
1355
+            if (browser.doesVideoMuteByStreamRemove()) {
1356
+                desc = this.localSdpMunger.maybeAddMutedLocalVideoTracksToSDP(desc);
1357
+                logger.debug(
1358
+                    'getLocalDescription::postTransform (munge local SDP)', desc);
1359
+            }
1325 1360
 
1326
-        if (browser.doesVideoMuteByStreamRemove()) {
1327
-            desc = this.localSdpMunger.maybeAddMutedLocalVideoTracksToSDP(desc);
1328
-            logger.debug(
1329
-                'getLocalDescription::postTransform (munge local SDP)', desc);
1361
+            // What comes out of this getter will be signalled over Jingle to
1362
+            // the other peer, so we need to make sure the media direction is
1363
+            // 'sendrecv' because we won't change the direction later and don't want
1364
+            // the other peer to think we can't send or receive.
1365
+            //
1366
+            // Note that the description we set in chrome does have the accurate
1367
+            // direction (e.g. 'recvonly'), since that is technically what is
1368
+            // happening (check setLocalDescription impl).
1369
+            desc = enforceSendRecv(desc, this.options);
1330 1370
         }
1331 1371
 
1332
-        // What comes out of this getter will be signalled over Jingle to
1333
-        // the other peer, so we need to make sure the media direction is
1334
-        // 'sendrecv' because we won't change the direction later and don't want
1335
-        // the other peer to think we can't send or receive.
1336
-        //
1337
-        // Note that the description we set in chrome does have the accurate
1338
-        // direction (e.g. 'recvonly'), since that is technically what is
1339
-        // happening (check setLocalDescription impl).
1340
-        desc = enforceSendRecv(desc, this.options);
1341
-
1342 1372
         // See the method's doc for more info about this transformation.
1343 1373
         desc = this.localSdpMunger.transformStreamIdentifiers(desc);
1344 1374
 
@@ -1347,6 +1377,11 @@ const getters = {
1347 1377
     remoteDescription() {
1348 1378
         let desc = this.peerconnection.remoteDescription;
1349 1379
 
1380
+        if (!desc) {
1381
+            logger.debug('getRemoteDescription no remoteDescription found');
1382
+
1383
+            return {};
1384
+        }
1350 1385
         this.trace('getRemoteDescription::preTransform', dumpSDP(desc));
1351 1386
 
1352 1387
         // if we're running on FF, transform to Plan B first.
@@ -1356,7 +1391,7 @@ const getters = {
1356 1391
                 'getRemoteDescription::postTransform (Plan B)', dumpSDP(desc));
1357 1392
         }
1358 1393
 
1359
-        return desc || {};
1394
+        return desc;
1360 1395
     }
1361 1396
 };
1362 1397
 
@@ -1406,7 +1441,7 @@ TraceablePeerConnection.prototype.addTrack = function(track, isInitiator = false
1406 1441
     }
1407 1442
 
1408 1443
     // Muted video tracks do not have WebRTC stream
1409
-    if (browser.doesVideoMuteByStreamRemove()
1444
+    if (browser.usesPlanB() && browser.doesVideoMuteByStreamRemove()
1410 1445
             && track.isVideoTrack() && track.isMuted()) {
1411 1446
         const ssrcInfo = this.generateNewStreamSSRCInfo(track);
1412 1447
 
@@ -1793,12 +1828,12 @@ TraceablePeerConnection.prototype.setLocalDescription = function(description) {
1793 1828
             dumpSDP(localSdp));
1794 1829
     }
1795 1830
 
1796
-    localSdp = this._adjustLocalMediaDirection(localSdp);
1797
-
1798
-    localSdp = this._ensureSimulcastGroupIsLast(localSdp);
1831
+    if (browser.usesPlanB()) {
1832
+        localSdp = this._adjustLocalMediaDirection(localSdp);
1833
+        localSdp = this._ensureSimulcastGroupIsLast(localSdp);
1834
+    } else {
1799 1835
 
1800
-    // if we're using unified plan, transform to it first.
1801
-    if (browser.usesUnifiedPlan()) {
1836
+        // if we're using unified plan, transform to it first.
1802 1837
         localSdp = this.interop.toUnifiedPlan(localSdp);
1803 1838
         this.trace(
1804 1839
             'setLocalDescription::postTransform (Unified Plan)',
@@ -1889,7 +1924,7 @@ TraceablePeerConnection.prototype.setMaxBitRate = function(localTrack) {
1889 1924
                 if (!parameters.encodings || !parameters.encodings.length) {
1890 1925
                     return;
1891 1926
                 }
1892
-                logger.info('Setting max bitrate on video stream');
1927
+                logger.debug('Setting max bitrate on video stream');
1893 1928
                 for (const encoding in parameters.encodings) {
1894 1929
                     if (parameters.encodings.hasOwnProperty(encoding)) {
1895 1930
                         parameters.encodings[encoding].maxBitrate
@@ -1915,64 +1950,51 @@ TraceablePeerConnection.prototype.setMaxBitRate = function(localTrack) {
1915 1950
 TraceablePeerConnection.prototype.setRemoteDescription = function(description) {
1916 1951
     this.trace('setRemoteDescription::preTransform', dumpSDP(description));
1917 1952
 
1918
-    // TODO the focus should squeze or explode the remote simulcast
1919
-    // eslint-disable-next-line no-param-reassign
1920
-    description = this.simulcast.mungeRemoteDescription(description);
1921
-    this.trace(
1922
-        'setRemoteDescription::postTransform (simulcast)',
1923
-        dumpSDP(description));
1953
+    if (browser.usesPlanB()) {
1954
+        // TODO the focus should squeze or explode the remote simulcast
1955
+        // eslint-disable-next-line no-param-reassign
1956
+        description = this.simulcast.mungeRemoteDescription(description);
1957
+        this.trace(
1958
+            'setRemoteDescription::postTransform (simulcast)',
1959
+            dumpSDP(description));
1924 1960
 
1925
-    if (this.options.preferH264) {
1926
-        const parsedSdp = transform.parse(description.sdp);
1927
-        const videoMLine = parsedSdp.media.find(m => m.type === 'video');
1961
+        if (this.options.preferH264) {
1962
+            const parsedSdp = transform.parse(description.sdp);
1963
+            const videoMLine = parsedSdp.media.find(m => m.type === 'video');
1928 1964
 
1929
-        SDPUtil.preferVideoCodec(videoMLine, 'h264');
1965
+            SDPUtil.preferVideoCodec(videoMLine, 'h264');
1930 1966
 
1931
-        // eslint-disable-next-line no-param-reassign
1932
-        description = new RTCSessionDescription({
1933
-            type: description.type,
1934
-            sdp: transform.write(parsedSdp)
1935
-        });
1936
-    }
1967
+            // eslint-disable-next-line no-param-reassign
1968
+            description = new RTCSessionDescription({
1969
+                type: description.type,
1970
+                sdp: transform.write(parsedSdp)
1971
+            });
1972
+        }
1937 1973
 
1938
-    // If the browser uses unified plan, transform to it first
1939
-    if (browser.usesUnifiedPlan()) {
1940 1974
         // eslint-disable-next-line no-param-reassign
1941
-        description = new RTCSessionDescription({
1942
-            type: description.type,
1943
-            sdp: this.rtxModifier.stripRtx(description.sdp)
1944
-        });
1945
-
1946
-        this.trace(
1947
-            'setRemoteDescription::postTransform (stripRtx)',
1948
-            dumpSDP(description));
1975
+        description = normalizePlanB(description);
1976
+    } else {
1977
+        const currentDescription = this.peerconnection.remoteDescription;
1949 1978
 
1950 1979
         // eslint-disable-next-line no-param-reassign
1951
-        description = this.interop.toUnifiedPlan(description);
1980
+        description = this.interop.toUnifiedPlan(description, currentDescription);
1952 1981
         this.trace(
1953
-            'setRemoteDescription::postTransform (Plan A)',
1982
+            'setRemoteDescription::postTransform (Unified)',
1954 1983
             dumpSDP(description));
1955 1984
 
1956 1985
         if (this.isSimulcastOn()) {
1986
+            // eslint-disable-next-line no-param-reassign
1987
+            description = this.simulcast.mungeRemoteDescription(description);
1988
+
1957 1989
             // eslint-disable-next-line no-param-reassign
1958 1990
             description = this.tpcUtils._insertUnifiedPlanSimulcastReceive(description);
1959 1991
             this.trace(
1960 1992
                 'setRemoteDescription::postTransform (sim receive)',
1961 1993
                 dumpSDP(description));
1962
-        }
1963
-    } else {
1964
-        // Plan B
1965
-        // eslint-disable-next-line no-param-reassign
1966
-        description = normalizePlanB(description);
1967
-    }
1968 1994
 
1969
-    // Safari WebRTC errors when no supported video codec is found in the offer.
1970
-    // To prevent the error, inject H264 into the video mLine.
1971
-    if (browser.isSafariWithWebrtc() && !browser.isSafariWithVP8()) {
1972
-        logger.debug('Maybe injecting H264 into the remote description');
1973
-
1974
-        // eslint-disable-next-line no-param-reassign
1975
-        description = this._injectH264IfNotPresent(description);
1995
+            // eslint-disable-next-line no-param-reassign
1996
+            description = this.tpcUtils._ensureCorrectOrderOfSsrcs(description);
1997
+        }
1976 1998
     }
1977 1999
 
1978 2000
     return new Promise((resolve, reject) => {
@@ -1998,76 +2020,6 @@ TraceablePeerConnection.prototype.setRemoteDescription = function(description) {
1998 2020
     });
1999 2021
 };
2000 2022
 
2001
-/**
2002
- * Inserts an H264 payload into the description if not already present. This is
2003
- * need for Safari WebRTC, which errors when no supported video codec is found
2004
- * in the offer. Related bug reports:
2005
- * https://bugs.webkit.org/show_bug.cgi?id=173141
2006
- * https://bugs.chromium.org/p/webrtc/issues/detail?id=4957
2007
- *
2008
- * @param {RTCSessionDescription} description - An RTCSessionDescription
2009
- * to inject with an H264 payload.
2010
- * @private
2011
- * @returns {RTCSessionDescription}
2012
- */
2013
-TraceablePeerConnection.prototype._injectH264IfNotPresent = function(
2014
-        description) {
2015
-    const parsedSdp = transform.parse(description.sdp);
2016
-    const videoMLine = parsedSdp.media.find(m => m.type === 'video');
2017
-
2018
-    if (!videoMLine) {
2019
-        logger.debug('No videoMLine found, no need to inject H264.');
2020
-
2021
-        return description;
2022
-    }
2023
-
2024
-    if (videoMLine.rtp.some(rtp => rtp.codec.toLowerCase() === 'h264')) {
2025
-        logger.debug('H264 codec found in video mLine, no need to inject.');
2026
-
2027
-        return description;
2028
-    }
2029
-
2030
-    const { fmtp, payloads, rtp } = videoMLine;
2031
-    const payloadsArray = payloads.toString().split(' ');
2032
-    let dummyPayloadType;
2033
-
2034
-    for (let i = 127; i >= 96; i--) {
2035
-        if (!payloadsArray.includes(i)) {
2036
-            dummyPayloadType = i;
2037
-            payloadsArray.push(i);
2038
-            videoMLine.payloads = payloadsArray.join(' ');
2039
-            break;
2040
-        }
2041
-    }
2042
-
2043
-    if (typeof dummyPayloadType === 'undefined') {
2044
-        logger.error('Could not find valid payload type to inject.');
2045
-
2046
-        return description;
2047
-    }
2048
-
2049
-    rtp.push({
2050
-        codec: 'H264',
2051
-        payload: dummyPayloadType,
2052
-        rate: 90000
2053
-    });
2054
-
2055
-    fmtp.push({
2056
-        config: 'level-asymmetry-allowed=1;'
2057
-            + 'packetization-mode=1;'
2058
-            + 'profile-level-id=42e01f',
2059
-        payload: dummyPayloadType
2060
-    });
2061
-
2062
-    logger.debug(
2063
-        `Injecting H264 payload type ${dummyPayloadType} into video mLine.`);
2064
-
2065
-    return new RTCSessionDescription({
2066
-        type: description.type,
2067
-        sdp: transform.write(parsedSdp)
2068
-    });
2069
-};
2070
-
2071 2023
 /**
2072 2024
  * Enables/disables video media transmission on this peer connection. When
2073 2025
  * disabled the SDP video media direction in the local SDP will be adjusted to
@@ -2278,17 +2230,6 @@ const _fixAnswerRFC4145Setup = function(offer, answer) {
2278 2230
 };
2279 2231
 
2280 2232
 TraceablePeerConnection.prototype.createAnswer = function(constraints) {
2281
-    if (browser.isFirefox() && this.isSimulcastOn()) {
2282
-        const videoSender
2283
-            = this.peerconnection.getSenders().find(sender =>
2284
-                sender.track !== null && sender.track.kind === 'video');
2285
-        const simParams = {
2286
-            encodings: this.tpcUtils.simulcastEncodings
2287
-        };
2288
-
2289
-        videoSender.setParameters(simParams);
2290
-    }
2291
-
2292 2233
     return this._createOfferOrAnswer(false /* answer */, constraints);
2293 2234
 };
2294 2235
 
@@ -2319,32 +2260,7 @@ TraceablePeerConnection.prototype._createOfferOrAnswer = function(
2319 2260
             this.trace(
2320 2261
                 `create${logName}OnSuccess::preTransform`, dumpSDP(resultSdp));
2321 2262
 
2322
-            // if we're using unified plan, transform to Plan B.
2323
-            if (browser.usesUnifiedPlan()) {
2324
-                // eslint-disable-next-line no-param-reassign
2325
-                resultSdp = this.interop.toPlanB(resultSdp);
2326
-                this.trace(
2327
-                    `create${logName}OnSuccess::postTransform (Plan B)`,
2328
-                    dumpSDP(resultSdp));
2329
-                if (this.isSimulcastOn()) {
2330
-                    // eslint-disable-next-line no-param-reassign
2331
-                    resultSdp
2332
-                        = this._injectSsrcGroupForUnifiedSimulcast(resultSdp);
2333
-                    this.trace(
2334
-                        `create${logName}OnSuccess::postTransform`
2335
-                        + '(inject ssrc group)', dumpSDP(resultSdp));
2336
-                }
2337
-            }
2338
-
2339
-            /**
2340
-             * We don't keep ssrcs consitent for Firefox because rewriting
2341
-             *  the ssrcs between createAnswer and setLocalDescription breaks
2342
-             *  the caching in sdp-interop (sdp-interop must know about all
2343
-             *  ssrcs, and it updates its cache in toPlanB so if we rewrite them
2344
-             *  after that, when we try and go back to unified plan it will
2345
-             *  complain about unmapped ssrcs)
2346
-             */
2347
-            if (!browser.usesUnifiedPlan()) {
2263
+            if (browser.usesPlanB()) {
2348 2264
                 // If there are no local video tracks, then a "recvonly"
2349 2265
                 // SSRC needs to be generated
2350 2266
                 if (!this.hasAnyTracksOfType(MediaType.VIDEO)

+ 0
- 51
modules/RTC/TraceablePeerConnection.spec.js 查看文件

@@ -1,51 +0,0 @@
1
-import transform from 'sdp-transform';
2
-
3
-import { multiCodecVideoSdp, plainVideoSdp } from '../xmpp/SampleSdpStrings';
4
-
5
-import TraceablePeerConnection from './TraceablePeerConnection';
6
-
7
-describe('TraceablePeerConnection', () => {
8
-    describe('_injectH264IfNotPresent', () => {
9
-        // Store the method-in-test in a convenience variable.
10
-        const injectFunction
11
-            = TraceablePeerConnection.prototype._injectH264IfNotPresent;
12
-        const MockSessionDescription = function({ sdp }) {
13
-            this.sdp = sdp;
14
-        };
15
-        const originalSessionDescription = window.originalSessionDescription;
16
-
17
-        beforeEach(() => {
18
-            window.RTCSessionDescription = MockSessionDescription;
19
-        });
20
-
21
-        afterEach(() => {
22
-            window.RTCSessionDescription = originalSessionDescription;
23
-        });
24
-
25
-        it('adds h264', () => {
26
-            const sessionDescription = new MockSessionDescription({
27
-                sdp: transform.write(plainVideoSdp)
28
-            });
29
-            const { sdp } = injectFunction(sessionDescription);
30
-            const expectedH264Payload = [
31
-                'm=video 9 RTP/SAVPF 100 127',
32
-                'a=rtpmap:127 H264/90000',
33
-                'a=fmtp:127 level-asymmetry-allowed=1;'
34
-                    + 'packetization-mode=1;'
35
-                    + 'profile-level-id=42e01f'
36
-            ];
37
-
38
-            expectedH264Payload.forEach(h264Description =>
39
-                expect(sdp.indexOf(h264Description) > -1).toBe(true));
40
-        });
41
-
42
-        it('does not modify the description if H264 is present', () => {
43
-            const sessionDescription = new MockSessionDescription({
44
-                sdp: transform.write(multiCodecVideoSdp)
45
-            });
46
-            const result = injectFunction(sessionDescription);
47
-
48
-            expect(result).toEqual(sessionDescription);
49
-        });
50
-    });
51
-});

+ 1
- 10
modules/browser/BrowserCapabilities.js 查看文件

@@ -39,7 +39,7 @@ export default class BrowserCapabilities extends BrowserDetection {
39 39
      * otherwise.
40 40
      */
41 41
     supportsP2P() {
42
-        return !this.isFirefox();
42
+        return !this.usesUnifiedPlan();
43 43
     }
44 44
 
45 45
     /**
@@ -181,15 +181,6 @@ export default class BrowserCapabilities extends BrowserDetection {
181 181
         return !this.isFirefox() && !this.usesUnifiedPlan();
182 182
     }
183 183
 
184
-    /**
185
-     * Whether jitsi-meet supports simulcast on the current browser.
186
-     * @returns {boolean}
187
-     */
188
-    supportsSimulcast() {
189
-        return this.isChromiumBased() || this.isFirefox()
190
-            || this.isSafariWithVP8() || this.isReactNative();
191
-    }
192
-
193 184
     /**
194 185
      * Returns whether or not the current browser can support capturing video,
195 186
      * be it camera or desktop, and displaying received video.

+ 20
- 27
modules/xmpp/JingleSessionPC.js 查看文件

@@ -1597,16 +1597,31 @@ export default class JingleSessionPC extends JingleSession {
1597 1597
      *  in removeSsrcInfo
1598 1598
      */
1599 1599
     _processRemoteRemoveSource(removeSsrcInfo) {
1600
-        const remoteSdp = new SDP(this.peerconnection.remoteDescription.sdp);
1600
+        const remoteSdp = browser.usesPlanB()
1601
+            ? new SDP(this.peerconnection.remoteDescription.sdp)
1602
+            : new SDP(this.peerconnection.peerconnection.remoteDescription.sdp);
1601 1603
 
1602 1604
         removeSsrcInfo.forEach((lines, idx) => {
1603 1605
             // eslint-disable-next-line no-param-reassign
1604 1606
             lines = lines.split('\r\n');
1605 1607
             lines.pop(); // remove empty last element;
1606
-            lines.forEach(line => {
1607
-                remoteSdp.media[idx]
1608
-                    = remoteSdp.media[idx].replace(`${line}\r\n`, '');
1609
-            });
1608
+            if (browser.usesPlanB()) {
1609
+                lines.forEach(line => {
1610
+                    remoteSdp.media[idx]
1611
+                        = remoteSdp.media[idx].replace(`${line}\r\n`, '');
1612
+                });
1613
+            } else {
1614
+                lines.forEach(line => {
1615
+                    const mid = remoteSdp.media.findIndex(mLine => mLine.includes(line));
1616
+
1617
+                    if (mid > -1) {
1618
+                        remoteSdp.media[mid] = remoteSdp.media[mid].replace(`${line}\r\n`, '');
1619
+
1620
+                        // Change the direction to "inactive".
1621
+                        remoteSdp.media[mid] = remoteSdp.media[mid].replace('a=sendonly', 'a=inactive');
1622
+                    }
1623
+                });
1624
+            }
1610 1625
         });
1611 1626
         remoteSdp.raw = remoteSdp.session + remoteSdp.media.join('');
1612 1627
 
@@ -1701,28 +1716,6 @@ export default class JingleSessionPC extends JingleSession {
1701 1716
      * @private
1702 1717
      */
1703 1718
     _initiatorRenegotiate(remoteDescription) {
1704
-        if (this.peerconnection.signalingState === 'have-local-offer') {
1705
-            // Skip createOffer and setLocalDescription or FF will fail
1706
-            logger.debug(
1707
-                'Renegotiate: setting remote description');
1708
-
1709
-            /* eslint-disable arrow-body-style */
1710
-
1711
-            return this.peerconnection.setRemoteDescription(remoteDescription)
1712
-                .then(() => {
1713
-                    // In case when the answer is being set for the first time,
1714
-                    // full sRD/sLD cycle is required to have the local
1715
-                    // description updated and SSRCs synchronized correctly.
1716
-                    // Otherwise SSRCs for streams added after invite, but
1717
-                    // before the answer was accepted will not be detected.
1718
-                    // The reason for that is that renegotiate can not be called
1719
-                    // when adding tracks and they will not be reflected in
1720
-                    // the local SDP.
1721
-                    return this._initiatorRenegotiate(remoteDescription);
1722
-                });
1723
-            /* eslint-enable arrow-body-style */
1724
-        }
1725
-
1726 1719
         logger.debug('Renegotiate: creating offer');
1727 1720
 
1728 1721
         return this.peerconnection.createOffer(this.mediaConstraints)

+ 12
- 6
package-lock.json 查看文件

@@ -1305,17 +1305,18 @@
1305 1305
       }
1306 1306
     },
1307 1307
     "@jitsi/sdp-interop": {
1308
-      "version": "0.1.14",
1309
-      "resolved": "https://registry.npmjs.org/@jitsi/sdp-interop/-/sdp-interop-0.1.14.tgz",
1310
-      "integrity": "sha512-v60VAtBx9LO46c9In9oMNY+Ho5993UMOLHBg6VcrcyoVTIWIeqs/9YjjmrQ3Sf4I5aMRABNl7HTby/1lHcqFJw==",
1308
+      "version": "1.0.1",
1309
+      "resolved": "https://registry.npmjs.org/@jitsi/sdp-interop/-/sdp-interop-1.0.1.tgz",
1310
+      "integrity": "sha512-OJm8IYsJKCYJBlC0geRHm2VHi8ow2k/3wOZ7n0lEOBfV6RWghZQzQWHdT/qrkbXB2EHcm40Oy91a5Bfz2m6ydA==",
1311 1311
       "requires": {
1312
+        "lodash.clonedeep": "4.5.0",
1312 1313
         "sdp-transform": "2.3.0"
1313 1314
       }
1314 1315
     },
1315 1316
     "@jitsi/sdp-simulcast": {
1316
-      "version": "0.2.2",
1317
-      "resolved": "https://registry.npmjs.org/@jitsi/sdp-simulcast/-/sdp-simulcast-0.2.2.tgz",
1318
-      "integrity": "sha512-zQt9DRnG/wn7bQg3nat0+G2yptBtuZuQN0iG5LHy4/wedyzV7HjEE73Zod69i7boZlRgvdjyexoaiwisrj9knw==",
1317
+      "version": "0.3.0",
1318
+      "resolved": "https://registry.npmjs.org/@jitsi/sdp-simulcast/-/sdp-simulcast-0.3.0.tgz",
1319
+      "integrity": "sha512-lxHfIWgTvdVY7F7BOcC3OaFvyvLsQJVRBCQvfmz4/Pk21/FdCyeBW4gv9ogfxxisjarU8gPX7/up4Z3C17wuXw==",
1319 1320
       "requires": {
1320 1321
         "sdp-transform": "2.3.0"
1321 1322
       }
@@ -6644,6 +6645,11 @@
6644 6645
       "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
6645 6646
       "dev": true
6646 6647
     },
6648
+    "lodash.clonedeep": {
6649
+      "version": "4.5.0",
6650
+      "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
6651
+      "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
6652
+    },
6647 6653
     "lodash.cond": {
6648 6654
       "version": "4.5.2",
6649 6655
       "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz",

+ 2
- 2
package.json 查看文件

@@ -16,8 +16,8 @@
16 16
   "author": "",
17 17
   "readmeFilename": "README.md",
18 18
   "dependencies": {
19
-    "@jitsi/sdp-interop": "0.1.14",
20
-    "@jitsi/sdp-simulcast": "0.2.2",
19
+    "@jitsi/sdp-interop": "1.0.1",
20
+    "@jitsi/sdp-simulcast": "0.3.0",
21 21
     "async": "0.9.0",
22 22
     "current-executing-script": "0.1.3",
23 23
     "jitsi-meet-logger": "github:jitsi/jitsi-meet-logger#5ec92357570dc8f0b7ffc1528820721c84c6af8b",

正在加载...
取消
保存