Parcourir la source

Feat: Remove ssrcs on leave

* fix(TPC): Configure degradation preference in RTCRtpSendParameters.
Properly configure degradation preference on RTCRtpSendParameters instead of RTCRtpEncodingParameters. Fixes https://github.com/jitsi/lib-jitsi-meet/issues/1510.

* feat(JingleSessionPC): Remove ssrcs from remote desc when a user leaves.
Remove the ssrcs (associated with remote sources) from the remote desc along with the removal of the remote tracks when an endpoint leaves the call. The source-remove signaling message from Jicofo will no longer be needed in this case and can be dropped.
release-8443
Jaya Allamsetty il y a 4 ans
Parent
révision
928d6683a0
Aucun compte lié à l'adresse e-mail de l'auteur
4 fichiers modifiés avec 129 ajouts et 46 suppressions
  1. 27
    11
      JitsiConference.js
  2. 0
    23
      modules/RTC/RTC.js
  3. 54
    12
      modules/RTC/TraceablePeerConnection.js
  4. 48
    0
      modules/xmpp/JingleSessionPC.js

+ 27
- 11
JitsiConference.js Voir le fichier

@@ -1668,20 +1668,36 @@ JitsiConference.prototype.onMemberLeft = function(jid) {
1668 1668
 
1669 1669
     delete this.participants[id];
1670 1670
 
1671
-    const removedTracks = this.rtc.removeRemoteTracks(id);
1671
+    // Remove the ssrcs from the remote description.
1672
+    const mediaSessions = this._getMediaSessions();
1673
+    const removePromises = [];
1672 1674
 
1673
-    removedTracks.forEach(
1674
-        track =>
1675
-            this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track));
1676
-
1677
-    // there can be no participant in case the member that left is focus
1678
-    if (participant) {
1679
-        this.eventEmitter.emit(
1680
-            JitsiConferenceEvents.USER_LEFT, id, participant);
1675
+    for (const session of mediaSessions) {
1676
+        removePromises.push(session.removeRemoteStreamsOnLeave(id));
1681 1677
     }
1682 1678
 
1683
-    this._maybeStartOrStopP2P(true /* triggered by user left event */);
1684
-    this._maybeClearSITimeout();
1679
+    Promise.allSettled(removePromises)
1680
+        .then(results => {
1681
+            let removedTracks = [];
1682
+
1683
+            results.map(result => result.value).forEach(value => {
1684
+                if (value) {
1685
+                    removedTracks = removedTracks.concat(value);
1686
+                }
1687
+            });
1688
+
1689
+            removedTracks.forEach(track => {
1690
+                this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);
1691
+            });
1692
+
1693
+            // There can be no participant in case the member that left is focus.
1694
+            if (participant) {
1695
+                this.eventEmitter.emit(JitsiConferenceEvents.USER_LEFT, id, participant);
1696
+            }
1697
+
1698
+            this._maybeStartOrStopP2P(true /* triggered by user left event */);
1699
+            this._maybeClearSITimeout();
1700
+        });
1685 1701
 };
1686 1702
 
1687 1703
 /**

+ 0
- 23
modules/RTC/RTC.js Voir le fichier

@@ -648,29 +648,6 @@ export default class RTC extends Listenable {
648 648
         this.localTracks.splice(pos, 1);
649 649
     }
650 650
 
651
-    /**
652
-     * Removes all JitsiRemoteTracks associated with given MUC nickname
653
-     * (resource part of the JID). Returns array of removed tracks.
654
-     *
655
-     * @param {string} Owner The resource part of the MUC JID.
656
-     * @returns {JitsiRemoteTrack[]}
657
-     */
658
-    removeRemoteTracks(owner) {
659
-        let removedTracks = [];
660
-
661
-        for (const tpc of this.peerConnections.values()) {
662
-            const pcRemovedTracks = tpc.removeRemoteTracks(owner);
663
-
664
-            removedTracks = removedTracks.concat(pcRemovedTracks);
665
-        }
666
-
667
-        logger.debug(
668
-            `Removed remote tracks for ${owner}`
669
-                + ` count: ${removedTracks.length}`);
670
-
671
-        return removedTracks;
672
-    }
673
-
674 651
     /**
675 652
      *
676 653
      */

+ 54
- 12
modules/RTC/TraceablePeerConnection.js Voir le fichier

@@ -630,6 +630,50 @@ TraceablePeerConnection.prototype.getRemoteTracks = function(
630 630
     return remoteTracks;
631 631
 };
632 632
 
633
+/**
634
+ * Parses the remote description and returns the sdp lines of the sources associated with a remote participant.
635
+ *
636
+ * @param {string} id Endpoint id of the remote participant.
637
+ * @returns {Array<string>} The sdp lines that have the ssrc information.
638
+ */
639
+TraceablePeerConnection.prototype.getRemoteSourceInfoByParticipant = function(id) {
640
+    const removeSsrcInfo = [];
641
+    const remoteTracks = this.getRemoteTracks(id);
642
+
643
+    if (!remoteTracks?.length) {
644
+        return removeSsrcInfo;
645
+    }
646
+    const primarySsrcs = remoteTracks.map(track => track.getSSRC());
647
+    const sdp = new SDP(this.remoteDescription.sdp);
648
+
649
+    for (const media of sdp.media) {
650
+        primarySsrcs.forEach((ssrc, idx) => {
651
+            let lines = '';
652
+            let ssrcLines = SDPUtil.findLines(media, `a=ssrc:${ssrc}`);
653
+
654
+            if (ssrcLines.length) {
655
+                if (!removeSsrcInfo[idx]) {
656
+                    removeSsrcInfo[idx] = '';
657
+                }
658
+
659
+                // Check if there are any FID groups are present for the primary ssrc.
660
+                const fidLines = SDPUtil.findLines(media, `a=ssrc-group:FID ${ssrc}`);
661
+
662
+                if (fidLines.length) {
663
+                    const secondarySsrc = fidLines[0].split(' ')[2];
664
+
665
+                    lines += `${fidLines[0]}\r\n`;
666
+                    ssrcLines = ssrcLines.concat(SDPUtil.findLines(media, `a=ssrc:${secondarySsrc}`));
667
+                }
668
+                removeSsrcInfo[idx] += `${ssrcLines.join('\r\n')}\r\n`;
669
+            }
670
+            removeSsrcInfo[idx] += lines;
671
+        });
672
+    }
673
+
674
+    return removeSsrcInfo;
675
+};
676
+
633 677
 /**
634 678
  * Tries to find {@link JitsiTrack} for given SSRC number. It will search both
635 679
  * local and remote tracks bound to this instance.
@@ -2128,20 +2172,18 @@ TraceablePeerConnection.prototype.setSenderVideoDegradationPreference = function
2128 2172
         return Promise.resolve();
2129 2173
     }
2130 2174
     const parameters = videoSender.getParameters();
2175
+    const preference = localVideoTrack.videoType === VideoType.CAMERA
2176
+        ? DEGRADATION_PREFERENCE_CAMERA
2177
+        : this.options.capScreenshareBitrate && browser.usesPlanB()
2131 2178
 
2132
-    if (!parameters.encodings || !parameters.encodings.length) {
2133
-        return Promise.resolve();
2134
-    }
2135
-    for (const encoding in parameters.encodings) {
2136
-        if (parameters.encodings.hasOwnProperty(encoding)) {
2137
-            const preference = localVideoTrack.videoType === VideoType.CAMERA
2138
-                ? DEGRADATION_PREFERENCE_CAMERA
2139
-                : DEGRADATION_PREFERENCE_DESKTOP;
2179
+            // Prefer resolution for low fps share.
2180
+            ? DEGRADATION_PREFERENCE_DESKTOP
2140 2181
 
2141
-            logger.info(`Setting video sender degradation preference on ${this} to ${preference}`);
2142
-            parameters.encodings[encoding].degradationPreference = preference;
2143
-        }
2144
-    }
2182
+            // Prefer frame-rate for high fps share.
2183
+            : DEGRADATION_PREFERENCE_CAMERA;
2184
+
2185
+    logger.info(`Setting a degradation preference of ${preference} on local video track`);
2186
+    parameters.degradationPreference = preference;
2145 2187
     this.tpcUtils.updateEncodingsResolution(parameters);
2146 2188
 
2147 2189
     return videoSender.setParameters(parameters);

+ 48
- 0
modules/xmpp/JingleSessionPC.js Voir le fichier

@@ -1662,6 +1662,54 @@ export default class JingleSessionPC extends JingleSession {
1662 1662
         this._addOrRemoveRemoteStream(false /* remove */, elem);
1663 1663
     }
1664 1664
 
1665
+    /**
1666
+     * Handles the deletion of the remote tracks and SSRCs associated with a remote endpoint.
1667
+     *
1668
+     * @param {string} id Endpoint id of the participant that has left the call.
1669
+     * @returns {Promise<JitsiRemoteTrack>} Promise that resolves with the tracks that are removed or error if the
1670
+     * operation fails.
1671
+     */
1672
+    removeRemoteStreamsOnLeave(id) {
1673
+        let remoteTracks = [];
1674
+
1675
+        const workFunction = finishCallback => {
1676
+            const removeSsrcInfo = this.peerconnection.getRemoteSourceInfoByParticipant(id);
1677
+
1678
+            if (!removeSsrcInfo.length) {
1679
+                logger.debug(`No remote SSRCs for participant: ${id} found.`);
1680
+                finishCallback();
1681
+            }
1682
+            const oldLocalSdp = new SDP(this.peerconnection.localDescription.sdp);
1683
+            const newRemoteSdp = this._processRemoteRemoveSource(removeSsrcInfo);
1684
+
1685
+            remoteTracks = this.peerconnection.removeRemoteTracks(id);
1686
+            this._renegotiate(newRemoteSdp.raw)
1687
+                .then(() => {
1688
+                    const newLocalSDP = new SDP(this.peerconnection.localDescription.sdp);
1689
+
1690
+                    this.notifyMySSRCUpdate(oldLocalSdp, newLocalSDP);
1691
+                    finishCallback();
1692
+                })
1693
+                .catch(err => finishCallback(err));
1694
+        };
1695
+
1696
+        return new Promise((resolve, reject) => {
1697
+            logger.debug(`Queued removeRemoteStreamsOnLeave task for participant ${id} on ${this}`);
1698
+
1699
+            this.modificationQueue.push(
1700
+                workFunction,
1701
+                error => {
1702
+                    if (error) {
1703
+                        logger.error(`removeRemoteStreamsOnLeave error on ${this}:`, error);
1704
+                        reject(error);
1705
+                    } else {
1706
+                        logger.info(`removeRemoteStreamsOnLeave done on ${this}!`);
1707
+                        resolve(remoteTracks);
1708
+                    }
1709
+                });
1710
+        });
1711
+    }
1712
+
1665 1713
     /**
1666 1714
      * Handles either Jingle 'source-add' or 'source-remove' message for this
1667 1715
      * Jingle session.

Chargement…
Annuler
Enregistrer