Przeglądaj źródła

fix(TPC) add muted tracks to TPC but not to the RTCPeerConnection.

Fixes https://github.com/jitsi/jitsi-meet/issues/9988.
tags/v0.0.2
Jaya Allamsetty 4 lat temu
rodzic
commit
e566291864
No account linked to committer's email address

+ 23
- 142
modules/RTC/TPCUtils.js Wyświetl plik

80
         ];
80
         ];
81
     }
81
     }
82
 
82
 
83
-    /**
84
-     * Returns the transceiver associated with a given RTCRtpSender/RTCRtpReceiver.
85
-     *
86
-     * @param {string} mediaType - type of track associated with the transceiver 'audio' or 'video'.
87
-     * @param {JitsiLocalTrack} localTrack - local track to be used for lookup.
88
-     * @returns {RTCRtpTransceiver}
89
-     */
90
-    _findTransceiver(mediaType, localTrack = null) {
91
-        let transceiver = null;
92
-
93
-        // Check if the local track has been removed from the peerconnection already.
94
-        const trackRemoved = !localTrack
95
-            || (localTrack
96
-                && browser.doesVideoMuteByStreamRemove()
97
-                && localTrack.isVideoTrack()
98
-                && localTrack.isMuted());
99
-
100
-        if (trackRemoved) {
101
-            transceiver = this.pc.peerconnection.getTransceivers()
102
-                .find(t => t.receiver?.track?.kind === mediaType);
103
-        } else if (localTrack) {
104
-            transceiver = this.pc.peerconnection.getTransceivers()
105
-                .find(t => t.sender?.track?.id === localTrack.getTrackId());
106
-        }
107
-
108
-        return transceiver;
109
-    }
110
-
111
     /**
83
     /**
112
      * Obtains stream encodings that need to be configured on the given track based
84
      * Obtains stream encodings that need to be configured on the given track based
113
      * on the track media type and the simulcast setting.
85
      * on the track media type and the simulcast setting.
169
         });
141
         });
170
     }
142
     }
171
 
143
 
144
+    /**
145
+     * Returns the transceiver associated with a given RTCRtpSender/RTCRtpReceiver.
146
+     *
147
+     * @param {string} mediaType - type of track associated with the transceiver 'audio' or 'video'.
148
+     * @param {JitsiLocalTrack} localTrack - local track to be used for lookup.
149
+     * @returns {RTCRtpTransceiver}
150
+     */
151
+    findTransceiver(mediaType, localTrack = null) {
152
+        const transceiver = localTrack?.track && localTrack.getOriginalStream()
153
+            ? this.pc.peerconnection.getTransceivers().find(t => t.sender?.track?.id === localTrack.getTrackId())
154
+            : this.pc.peerconnection.getTransceivers().find(t => t.receiver?.track?.kind === mediaType);
155
+
156
+        return transceiver;
157
+    }
158
+
172
     /**
159
     /**
173
      * Takes in a *unified plan* offer and inserts the appropriate
160
      * Takes in a *unified plan* offer and inserts the appropriate
174
      * parameters for adding simulcast receive support.
161
      * parameters for adding simulcast receive support.
271
         }
258
         }
272
     }
259
     }
273
 
260
 
274
-    /**
275
-     * Adds a track on the RTCRtpSender as part of the unmute operation.
276
-     * @param {JitsiLocalTrack} localTrack - track to be unmuted.
277
-     * @returns {Promise<void>} - resolved when done.
278
-     */
279
-    addTrackUnmute(localTrack) {
280
-        const mediaType = localTrack.getType();
281
-        const track = localTrack.getTrack();
282
-        const transceiver = this._findTransceiver(mediaType);
283
-
284
-        if (!transceiver) {
285
-            return Promise.reject(new Error(`RTCRtpTransceiver for ${mediaType} not found`));
286
-        }
287
-        logger.debug(`${this.pc} Adding ${localTrack}`);
288
-
289
-        return transceiver.sender.replaceTrack(track);
290
-    }
291
-
292
     /**
261
     /**
293
      * Returns the calculated active state of the simulcast encodings based on the frame height requested for the send
262
      * Returns the calculated active state of the simulcast encodings based on the frame height requested for the send
294
      * stream. All the encodings that have a resolution lower than the frame height requested will be enabled.
263
      * stream. All the encodings that have a resolution lower than the frame height requested will be enabled.
368
         return encodingsBitrates;
337
         return encodingsBitrates;
369
     }
338
     }
370
 
339
 
371
-    /**
372
-     * Removes the track from the RTCRtpSender as part of the mute operation.
373
-     * @param {JitsiLocalTrack} localTrack - track to be removed.
374
-     * @returns {Promise<void>} - resolved when done.
375
-     */
376
-    removeTrackMute(localTrack) {
377
-        const mediaType = localTrack.getType();
378
-        const transceiver = this._findTransceiver(mediaType, localTrack);
379
-
380
-        if (!transceiver) {
381
-            return Promise.reject(new Error(`RTCRtpTransceiver for ${mediaType} not found`));
382
-        }
383
-
384
-        logger.debug(`${this.pc} Removing ${localTrack}`);
385
-
386
-        return transceiver.sender.replaceTrack(null);
387
-    }
388
-
389
     /**
340
     /**
390
      * Replaces the existing track on a RTCRtpSender with the given track.
341
      * Replaces the existing track on a RTCRtpSender with the given track.
391
      * @param {JitsiLocalTrack} oldTrack - existing track on the sender that needs to be removed.
342
      * @param {JitsiLocalTrack} oldTrack - existing track on the sender that needs to be removed.
393
      * @returns {Promise<void>} - resolved when done.
344
      * @returns {Promise<void>} - resolved when done.
394
      */
345
      */
395
     replaceTrack(oldTrack, newTrack) {
346
     replaceTrack(oldTrack, newTrack) {
396
-        if (oldTrack && newTrack) {
397
-            const mediaType = newTrack.getType();
398
-            const stream = newTrack.getOriginalStream();
399
-
400
-            // Ignore cases when the track is replaced while the device is in a muted state,like
401
-            // replacing camera when video muted or replacing mic when audio muted. These JitsiLocalTracks
402
-            // do not have a mediastream attached. Replace track will be called again when the device is
403
-            // unmuted and the track will be replaced on the peerconnection then.
404
-            if (!stream) {
405
-                this.pc.localTracks.delete(oldTrack.rtcId);
406
-                this.pc.localTracks.set(newTrack.rtcId, newTrack);
407
-
408
-                return Promise.resolve();
409
-            }
410
-
411
-            const transceiver = this._findTransceiver(mediaType, oldTrack);
412
-            const track = newTrack.getTrack();
347
+        const mediaType = newTrack?.getType() ?? oldTrack?.getType();
348
+        const transceiver = this.findTransceiver(mediaType, oldTrack);
349
+        const track = newTrack?.getTrack() ?? null;
413
 
350
 
414
-            if (!transceiver) {
415
-                return Promise.reject(new Error('replace track failed'));
416
-            }
417
-            logger.debug(`${this.pc} Replacing ${oldTrack} with ${newTrack}`);
418
-
419
-            return transceiver.sender.replaceTrack(track)
420
-                .then(() => {
421
-                    const ssrc = this.pc.localSSRCs.get(oldTrack.rtcId);
422
-
423
-                    this.pc.localTracks.delete(oldTrack.rtcId);
424
-                    this.pc.localSSRCs.delete(oldTrack.rtcId);
425
-                    this.pc._addedStreams = this.pc._addedStreams.filter(s => s !== stream);
426
-                    this.pc.localTracks.set(newTrack.rtcId, newTrack);
427
-
428
-                    this.pc._addedStreams.push(stream);
429
-                    this.pc.localSSRCs.set(newTrack.rtcId, ssrc);
430
-                });
431
-        } else if (oldTrack && !newTrack) {
432
-            return this.removeTrackMute(oldTrack)
433
-                .then(() => {
434
-                    const mediaType = oldTrack.getType();
435
-                    const transceiver = this._findTransceiver(mediaType);
436
-
437
-                    // Change the direction on the transceiver to 'recvonly' so that a 'removetrack'
438
-                    // is fired on the associated media stream on the remote peer.
439
-                    if (transceiver) {
440
-                        transceiver.direction = MediaDirection.RECVONLY;
441
-                    }
442
-
443
-                    // Remove the old track from the list of local tracks.
444
-                    this.pc.localTracks.delete(oldTrack.rtcId);
445
-                    this.pc.localSSRCs.delete(oldTrack.rtcId);
446
-                });
447
-        } else if (newTrack && !oldTrack) {
448
-            return this.addTrackUnmute(newTrack)
449
-                .then(() => {
450
-                    const mediaType = newTrack.getType();
451
-                    const transceiver = this._findTransceiver(mediaType, newTrack);
452
-
453
-                    // Change the direction on the transceiver back to 'sendrecv' so that a 'track'
454
-                    // event is fired on the remote peer.
455
-                    if (transceiver) {
456
-                        transceiver.direction = MediaDirection.SENDRECV;
457
-                    }
458
-
459
-                    // Avoid configuring the encodings on Chromium/Safari until simulcast is configured
460
-                    // for the newly added track using SDP munging which happens during the renegotiation.
461
-                    const promise = browser.usesSdpMungingForSimulcast()
462
-                        ? Promise.resolve()
463
-                        : this.setEncodings(newTrack);
464
-
465
-                    return promise
466
-                        .then(() => {
467
-                            // Add the new track to the list of local tracks.
468
-                            this.pc.localTracks.set(newTrack.rtcId, newTrack);
469
-                        });
470
-                });
351
+        if (!transceiver) {
352
+            return Promise.reject(new Error('replace track failed'));
471
         }
353
         }
354
+        logger.debug(`${this.pc} Replacing ${oldTrack} with ${newTrack}`);
472
 
355
 
473
-        logger.info(`${this.pc} TPCUtils.replaceTrack called with no new track and no old track`);
474
-
475
-        return Promise.resolve();
356
+        return transceiver.sender.replaceTrack(track);
476
     }
357
     }
477
 
358
 
478
     /**
359
     /**
496
      */
377
      */
497
     setEncodings(track) {
378
     setEncodings(track) {
498
         const mediaType = track.getType();
379
         const mediaType = track.getType();
499
-        const transceiver = this._findTransceiver(mediaType, track);
380
+        const transceiver = this.findTransceiver(mediaType, track);
500
         const parameters = transceiver?.sender?.getParameters();
381
         const parameters = transceiver?.sender?.getParameters();
501
 
382
 
502
         // Resolve if the encodings are not available yet. This happens immediately after the track is added to the
383
         // Resolve if the encodings are not available yet. This happens immediately after the track is added to the

+ 53
- 16
modules/RTC/TraceablePeerConnection.js Wyświetl plik

1698
     }
1698
     }
1699
 
1699
 
1700
     this.localTracks.set(rtcId, track);
1700
     this.localTracks.set(rtcId, track);
1701
+    const webrtcStream = track.getOriginalStream();
1701
 
1702
 
1702
     if (this._usesUnifiedPlan) {
1703
     if (this._usesUnifiedPlan) {
1703
-        try {
1704
-            this.tpcUtils.addTrack(track, isInitiator);
1705
-        } catch (error) {
1706
-            logger.error(`${this} Adding track=${track} failed: ${error?.message}`);
1704
+        logger.debug(`${this} TPC.addTrack using unified plan`);
1705
+        if (webrtcStream) {
1706
+            try {
1707
+                this.tpcUtils.addTrack(track, isInitiator);
1708
+            } catch (error) {
1709
+                logger.error(`${this} Adding track=${track} failed: ${error?.message}`);
1707
 
1710
 
1708
-            return Promise.reject(error);
1711
+                return Promise.reject(error);
1712
+            }
1709
         }
1713
         }
1710
     } else {
1714
     } else {
1711
         // Use addStream API for the plan-b case.
1715
         // Use addStream API for the plan-b case.
1712
-        const webrtcStream = track.getOriginalStream();
1713
-
1714
         if (webrtcStream) {
1716
         if (webrtcStream) {
1715
             this._addStream(webrtcStream);
1717
             this._addStream(webrtcStream);
1716
 
1718
 
1753
 
1755
 
1754
     // On Firefox, the encodings have to be configured on the sender only after the transceiver is created.
1756
     // On Firefox, the encodings have to be configured on the sender only after the transceiver is created.
1755
     if (browser.isFirefox()) {
1757
     if (browser.isFirefox()) {
1756
-        promiseChain = promiseChain.then(() => this.tpcUtils.setEncodings(track));
1758
+        promiseChain = promiseChain.then(() => webrtcStream && this.tpcUtils.setEncodings(track));
1757
     }
1759
     }
1758
 
1760
 
1759
     return promiseChain;
1761
     return promiseChain;
1761
 
1763
 
1762
 /**
1764
 /**
1763
  * Adds local track as part of the unmute operation.
1765
  * Adds local track as part of the unmute operation.
1764
- * @param {JitsiLocalTrack} track the track to be added as part of the unmute
1765
- * operation
1766
+ * @param {JitsiLocalTrack} track the track to be added as part of the unmute operation.
1767
+ *
1766
  * @return {Promise<boolean>} Promise that resolves to true if the underlying PeerConnection's
1768
  * @return {Promise<boolean>} Promise that resolves to true if the underlying PeerConnection's
1767
  * state has changed and renegotiation is required, false if no renegotiation is needed or
1769
  * state has changed and renegotiation is required, false if no renegotiation is needed or
1768
  * Promise is rejected when something goes wrong.
1770
  * Promise is rejected when something goes wrong.
1769
  */
1771
  */
1770
 TraceablePeerConnection.prototype.addTrackUnmute = function(track) {
1772
 TraceablePeerConnection.prototype.addTrackUnmute = function(track) {
1773
+    logger.info(`${this} Adding track=${track} as unmute`);
1774
+
1771
     if (!this._assertTrackBelongs('addTrackUnmute', track)) {
1775
     if (!this._assertTrackBelongs('addTrackUnmute', track)) {
1772
         // Abort
1776
         // Abort
1777
+
1773
         return Promise.reject('Track not found on the peerconnection');
1778
         return Promise.reject('Track not found on the peerconnection');
1774
     }
1779
     }
1775
 
1780
 
1776
-    logger.info(`${this} Adding track=${track} as unmute`);
1777
     const webRtcStream = track.getOriginalStream();
1781
     const webRtcStream = track.getOriginalStream();
1778
 
1782
 
1779
     if (!webRtcStream) {
1783
     if (!webRtcStream) {
1783
     }
1787
     }
1784
 
1788
 
1785
     if (this._usesUnifiedPlan) {
1789
     if (this._usesUnifiedPlan) {
1786
-        return this.tpcUtils.addTrackUnmute(track);
1790
+        return this.tpcUtils.replaceTrack(null, track).then(() => this.isP2P);
1787
     }
1791
     }
1788
 
1792
 
1789
     this._addStream(webRtcStream);
1793
     this._addStream(webRtcStream);
1825
 TraceablePeerConnection.prototype._assertTrackBelongs = function(
1829
 TraceablePeerConnection.prototype._assertTrackBelongs = function(
1826
         methodName,
1830
         methodName,
1827
         localTrack) {
1831
         localTrack) {
1828
-    const doesBelong = this.localTracks.has(localTrack.rtcId);
1832
+    const doesBelong = this.localTracks.has(localTrack?.rtcId);
1829
 
1833
 
1830
     if (!doesBelong) {
1834
     if (!doesBelong) {
1831
         logger.error(`${this} ${methodName}: track=${localTrack} does not belong to pc`);
1835
         logger.error(`${this} ${methodName}: track=${localTrack} does not belong to pc`);
1979
  * Otherwise no renegotiation is needed.
1983
  * Otherwise no renegotiation is needed.
1980
  */
1984
  */
1981
 TraceablePeerConnection.prototype.replaceTrack = function(oldTrack, newTrack) {
1985
 TraceablePeerConnection.prototype.replaceTrack = function(oldTrack, newTrack) {
1986
+    if (!(oldTrack || newTrack)) {
1987
+        logger.info(`${this} replaceTrack called with no new track and no old track`);
1988
+
1989
+        return Promise.resolve();
1990
+    }
1991
+
1982
     if (this._usesUnifiedPlan) {
1992
     if (this._usesUnifiedPlan) {
1983
         logger.debug(`${this} TPC.replaceTrack using unified plan`);
1993
         logger.debug(`${this} TPC.replaceTrack using unified plan`);
1994
+        const stream = newTrack?.getOriginalStream();
1995
+        const promise = newTrack && !stream
1996
+
1997
+            // Ignore cases when the track is replaced while the device is in a muted state.
1998
+            // The track will be replaced again on the peerconnection when the user unmutes.
1999
+            ? Promise.resolve()
2000
+            : this.tpcUtils.replaceTrack(oldTrack, newTrack);
2001
+
2002
+        return promise
2003
+            .then(() => {
2004
+                oldTrack && this.localTracks.delete(oldTrack.rtcId);
2005
+                newTrack && this.localTracks.set(newTrack.rtcId, newTrack);
1984
 
2006
 
1985
-        // Renegotiate only in the case of P2P. We rely on 'negotiationeeded' to be fired for JVB.
1986
-        return this.tpcUtils.replaceTrack(oldTrack, newTrack).then(() => this.isP2P);
2007
+                const mediaType = newTrack?.getType() ?? oldTrack?.getType();
2008
+                const transceiver = this.tpcUtils.findTransceiver(mediaType, oldTrack);
2009
+
2010
+                if (transceiver) {
2011
+                    // Set the transceiver direction.
2012
+                    transceiver.direction = newTrack ? MediaDirection.SENDRECV : MediaDirection.RECVONLY;
2013
+                }
2014
+
2015
+                // Avoid configuring the encodings on Chromium/Safari until simulcast is configured
2016
+                // for the newly added track using SDP munging which happens during the renegotiation.
2017
+                const configureEncodingsPromise = browser.usesSdpMungingForSimulcast() || !newTrack
2018
+                    ? Promise.resolve()
2019
+                    : this.tpcUtils.setEncodings(newTrack);
2020
+
2021
+                // Renegotiate only in the case of P2P. We rely on 'negotiationeeded' to be fired for JVB.
2022
+                return configureEncodingsPromise.then(() => this.isP2P);
2023
+            });
1987
     }
2024
     }
1988
 
2025
 
1989
     logger.debug(`${this} TPC.replaceTrack using plan B`);
2026
     logger.debug(`${this} TPC.replaceTrack using plan B`);
2021
     }
2058
     }
2022
 
2059
 
2023
     if (this._usesUnifiedPlan) {
2060
     if (this._usesUnifiedPlan) {
2024
-        return this.tpcUtils.removeTrackMute(localTrack);
2061
+        return this.tpcUtils.replaceTrack(localTrack, null);
2025
     }
2062
     }
2026
 
2063
 
2027
     if (webRtcStream) {
2064
     if (webRtcStream) {

+ 7
- 5
modules/xmpp/JingleSessionPC.js Wyświetl plik

2278
                     if (shouldRenegotiate && oldLocalSDP && tpc.remoteDescription.sdp) {
2278
                     if (shouldRenegotiate && oldLocalSDP && tpc.remoteDescription.sdp) {
2279
                         this._renegotiate()
2279
                         this._renegotiate()
2280
                             .then(() => {
2280
                             .then(() => {
2281
-                                // The results are ignored, as this check failure is not
2282
-                                // enough to fail the whole operation. It will log
2283
-                                // an error inside.
2284
-                                this._verifyNoSSRCChanged(
2285
-                                    operationName, new SDP(oldLocalSDP));
2281
+                                // The results are ignored, as this check failure is not enough to fail the whole
2282
+                                // operation. It will log an error inside for plan-b.
2283
+                                !this.usesUnifiedPlan && this._verifyNoSSRCChanged(operationName, new SDP(oldLocalSDP));
2284
+                                const newLocalSdp = tpc.localDescription.sdp;
2285
+
2286
+                                // Signal the ssrc if an unmute operation results in a new ssrc being generated.
2287
+                                this.notifyMySSRCUpdate(new SDP(oldLocalSDP), new SDP(newLocalSdp));
2286
                                 finishedCallback();
2288
                                 finishedCallback();
2287
                             });
2289
                             });
2288
                     } else {
2290
                     } else {

Ładowanie…
Anuluj
Zapisz