Browse Source

ref(TPC) Pass the transform object along for SDP munging.

release-8443
Jaya Allamsetty 10 months ago
parent
commit
07f037e12e
2 changed files with 110 additions and 123 deletions
  1. 97
    62
      modules/RTC/TPCUtils.js
  2. 13
    61
      modules/RTC/TraceablePeerConnection.js

+ 97
- 62
modules/RTC/TPCUtils.js View File

7
 import { MediaType } from '../../service/RTC/MediaType';
7
 import { MediaType } from '../../service/RTC/MediaType';
8
 import {
8
 import {
9
     SIM_LAYERS,
9
     SIM_LAYERS,
10
+    SSRC_GROUP_SEMANTICS,
10
     STANDARD_CODEC_SETTINGS,
11
     STANDARD_CODEC_SETTINGS,
11
     VIDEO_QUALITY_LEVELS,
12
     VIDEO_QUALITY_LEVELS,
12
     VIDEO_QUALITY_SETTINGS
13
     VIDEO_QUALITY_SETTINGS
438
     }
439
     }
439
 
440
 
440
     /**
441
     /**
441
-     * Ensures that the ssrcs associated with a FID ssrc-group appear in the correct order, i.e.,
442
-     * the primary ssrc first and the secondary rtx ssrc later. This is important for unified
443
-     * plan since we have only one FID group per media description.
444
-     * @param {Object} description the webRTC session description instance for the remote
445
-     * description.
446
-     * @private
442
+     * Ensures that the ssrcs associated with a FID ssrc-group appear in the correct order, i.e., the primary ssrc
443
+     * first and the secondary rtx ssrc later. This is important for unified plan since we have only one FID group per
444
+     * media description.
445
+     * @param {Object} description the webRTC session description instance for the remote description.
446
+     * @returns {Object} the modified webRTC session description instance.
447
      */
447
      */
448
     ensureCorrectOrderOfSsrcs(description) {
448
     ensureCorrectOrderOfSsrcs(description) {
449
         const parsedSdp = transform.parse(description.sdp);
449
         const parsedSdp = transform.parse(description.sdp);
493
         if (this.pc.usesCodecSelectionAPI() && rtpSender) {
493
         if (this.pc.usesCodecSelectionAPI() && rtpSender) {
494
             const { codecs } = rtpSender.getParameters();
494
             const { codecs } = rtpSender.getParameters();
495
 
495
 
496
-            return codecs[0].mimeType.split('/')[1].toLowerCase();
496
+            if (codecs?.length) {
497
+                return codecs[0].mimeType.split('/')[1].toLowerCase();
498
+            }
497
         }
499
         }
498
 
500
 
499
         const sdp = this.pc.remoteDescription?.sdp;
501
         const sdp = this.pc.remoteDescription?.sdp;
500
-        const defaultCodec = CodecMimeType.VP8;
501
 
502
 
502
         if (!sdp) {
503
         if (!sdp) {
503
-            return defaultCodec;
504
+            return CodecMimeType.VP8;
504
         }
505
         }
505
         const parsedSdp = transform.parse(sdp);
506
         const parsedSdp = transform.parse(sdp);
506
         const mLine = parsedSdp.media
507
         const mLine = parsedSdp.media
512
             return Object.values(CodecMimeType).find(value => value === codec.toLowerCase());
513
             return Object.values(CodecMimeType).find(value => value === codec.toLowerCase());
513
         }
514
         }
514
 
515
 
515
-        return defaultCodec;
516
+        return CodecMimeType.VP8;
516
     }
517
     }
517
 
518
 
518
     /**
519
     /**
519
      * Returns the codecs in the current order of preference as configured on the peerconnection.
520
      * Returns the codecs in the current order of preference as configured on the peerconnection.
520
      *
521
      *
521
-     * @param {RTCSessionDescription} - The local description to be used.
522
+     * @param {string} - The local SDP to be used.
522
      * @returns {Array}
523
      * @returns {Array}
523
      */
524
      */
524
-    getConfiguredVideoCodecs(description) {
525
-        const currentSdp = description?.sdp ?? this.pc.localDescription?.sdp;
525
+    getConfiguredVideoCodecs(sdp) {
526
+        const currentSdp = sdp ?? this.pc.localDescription?.sdp;
526
 
527
 
527
         if (!currentSdp) {
528
         if (!currentSdp) {
528
             return [];
529
             return [];
574
         } ];
575
         } ];
575
     }
576
     }
576
 
577
 
578
+    /**
579
+     * Injects a 'SIM' ssrc-group line for simulcast into the given session description object to make Jicofo happy.
580
+     * This is needed only for Firefox since it does not generate it when simulcast is enabled.
581
+     *
582
+     * @param desc A session description object (with 'type' and 'sdp' fields)
583
+     * @return A session description object with its sdp field modified to contain an inject ssrc-group for simulcast.
584
+     */
585
+    injectSsrcGroupForUnifiedSimulcast(desc) {
586
+        const sdp = transform.parse(desc.sdp);
587
+        const video = sdp.media.find(mline => mline.type === 'video');
588
+
589
+        // Check if the browser supports RTX, add only the primary ssrcs to the SIM group if that is the case.
590
+        video.ssrcGroups = video.ssrcGroups || [];
591
+        const fidGroups = video.ssrcGroups.filter(group => group.semantics === SSRC_GROUP_SEMANTICS.FID);
592
+
593
+        if (video.simulcast || video.simulcast_03) {
594
+            const ssrcs = [];
595
+
596
+            if (fidGroups && fidGroups.length) {
597
+                fidGroups.forEach(group => {
598
+                    ssrcs.push(group.ssrcs.split(' ')[0]);
599
+                });
600
+            } else {
601
+                video.ssrcs.forEach(ssrc => {
602
+                    if (ssrc.attribute === 'msid') {
603
+                        ssrcs.push(ssrc.id);
604
+                    }
605
+                });
606
+            }
607
+            if (video.ssrcGroups.find(group => group.semantics === SSRC_GROUP_SEMANTICS.SIM)) {
608
+                // Group already exists, no need to do anything
609
+                return desc;
610
+            }
611
+
612
+            // Add a SIM group for every 3 FID groups.
613
+            for (let i = 0; i < ssrcs.length; i += 3) {
614
+                const simSsrcs = ssrcs.slice(i, i + 3);
615
+
616
+                video.ssrcGroups.push({
617
+                    semantics: SSRC_GROUP_SEMANTICS.SIM,
618
+                    ssrcs: simSsrcs.join(' ')
619
+                });
620
+            }
621
+        }
622
+
623
+        return {
624
+            type: desc.type,
625
+            sdp: transform.write(sdp)
626
+        };
627
+    }
628
+
577
     /**
629
     /**
578
      * Takes in a *unified plan* offer and inserts the appropriate parameters for adding simulcast receive support.
630
      * Takes in a *unified plan* offer and inserts the appropriate parameters for adding simulcast receive support.
579
      * @param {Object} desc - A session description object
631
      * @param {Object} desc - A session description object
659
     /**
711
     /**
660
      * Munges the session description to ensure that the codec order is as per the preferred codec settings.
712
      * Munges the session description to ensure that the codec order is as per the preferred codec settings.
661
      *
713
      *
662
-     * @param {RTCSessionDescription} description - the local/remote description to be munged.
663
-     * @returns {RTCSessionDescription} - the munged local/remote description.
714
+     * @param {transform.SessionDescription} parsedSdp that needs to be munged
715
+     * @returns {transform.SessionDescription} the munged SDP.
664
      */
716
      */
665
-    mungeCodecOrder(description) {
717
+    mungeCodecOrder(parsedSdp) {
666
         const codecSettings = this.pc.codecSettings;
718
         const codecSettings = this.pc.codecSettings;
667
 
719
 
668
         if (!codecSettings) {
720
         if (!codecSettings) {
669
-            return description;
721
+            return parsedSdp;
670
         }
722
         }
671
 
723
 
724
+        const mungedSdp = parsedSdp;
672
         const { isP2P } = this.options;
725
         const { isP2P } = this.options;
673
-        const parsedSdp = transform.parse(description.sdp);
674
-        const mLines = parsedSdp.media.filter(m => m.type === codecSettings.mediaType);
675
-
676
-        if (!mLines.length) {
677
-            return description;
678
-        }
726
+        const mLines = mungedSdp.media.filter(m => m.type === codecSettings.mediaType);
679
 
727
 
680
         for (const mLine of mLines) {
728
         for (const mLine of mLines) {
681
-            const currentCodecs = this.getConfiguredVideoCodecs(description);
729
+            const currentCodecs = this.getConfiguredVideoCodecs(transform.write(parsedSdp));
682
 
730
 
683
             for (const codec of currentCodecs) {
731
             for (const codec of currentCodecs) {
684
                 if (isP2P) {
732
                 if (isP2P) {
707
             }
755
             }
708
         }
756
         }
709
 
757
 
710
-        return {
711
-            type: description.type,
712
-            sdp: transform.write(parsedSdp)
713
-        };
758
+        return mungedSdp;
714
     }
759
     }
715
 
760
 
716
     /**
761
     /**
717
      * Munges the stereo flag as well as the opusMaxAverageBitrate in the SDP, based on values set through config.js,
762
      * Munges the stereo flag as well as the opusMaxAverageBitrate in the SDP, based on values set through config.js,
718
      * if present.
763
      * if present.
719
      *
764
      *
720
-     * @param {RTCSessionDescription} description that needs to be munged.
721
-     * @returns {RTCSessionDescription} the munged description.
765
+     * @param {transform.SessionDescription} parsedSdp that needs to be munged.
766
+     * @returns {transform.SessionDescription} the munged SDP.
722
      */
767
      */
723
-    mungeOpus(description) {
768
+    mungeOpus(parsedSdp) {
724
         const { audioQuality } = this.options;
769
         const { audioQuality } = this.options;
725
 
770
 
726
         if (!audioQuality?.enableOpusDtx && !audioQuality?.stereo && !audioQuality?.opusMaxAverageBitrate) {
771
         if (!audioQuality?.enableOpusDtx && !audioQuality?.stereo && !audioQuality?.opusMaxAverageBitrate) {
727
-            return description;
772
+            return parsedSdp;
728
         }
773
         }
729
 
774
 
730
-        const parsedSdp = transform.parse(description.sdp);
731
-        const mLines = parsedSdp.media.filter(m => m.type === MediaType.AUDIO);
775
+        const mungedSdp = parsedSdp;
776
+        const mLines = mungedSdp.media.filter(m => m.type === MediaType.AUDIO);
732
 
777
 
733
         for (const mLine of mLines) {
778
         for (const mLine of mLines) {
734
             const { payload } = mLine.rtp.find(protocol => protocol.codec === CodecMimeType.OPUS);
779
             const { payload } = mLine.rtp.find(protocol => protocol.codec === CodecMimeType.OPUS);
780
             fmtpOpus.config = mungedConfig.trim();
825
             fmtpOpus.config = mungedConfig.trim();
781
         }
826
         }
782
 
827
 
783
-        return {
784
-            type: description.type,
785
-            sdp: transform.write(parsedSdp)
786
-        };
828
+        return mungedSdp;
787
     }
829
     }
788
 
830
 
789
     /**
831
     /**
790
-     * Munges the session description by setting the max bitrates on the video m-lines when VP9 K-SVC codec is in use.
832
+     * Munges the session SDP by setting the max bitrates on the video m-lines when VP9 K-SVC codec is in use.
791
      *
833
      *
792
-     * @param {RTCSessionDescription} description - The local/remote description that needs to be munged.
834
+     * @param {transform.SessionDescription} parsedSdp that needs to be munged.
793
      * @param {boolean} isLocalSdp - Whether the max bitrate (via b=AS line in SDP) is set on local SDP.
835
      * @param {boolean} isLocalSdp - Whether the max bitrate (via b=AS line in SDP) is set on local SDP.
794
-     * @returns {RTCSessionDescription} - The munged local/remote description.
836
+     * @returns {transform.SessionDescription} The munged SDP.
795
      */
837
      */
796
-    setMaxBitrates(description, isLocalSdp = false) {
838
+    setMaxBitrates(parsedSdp, isLocalSdp = false) {
797
         const pcCodecSettings = this.pc.codecSettings;
839
         const pcCodecSettings = this.pc.codecSettings;
798
 
840
 
799
         if (!pcCodecSettings) {
841
         if (!pcCodecSettings) {
800
-            return description;
842
+            return parsedSdp;
801
         }
843
         }
802
-        const parsedSdp = transform.parse(description.sdp);
803
 
844
 
804
         // Find all the m-lines associated with the local sources.
845
         // Find all the m-lines associated with the local sources.
846
+        const mungedSdp = parsedSdp;
805
         const direction = isLocalSdp ? MediaDirection.RECVONLY : MediaDirection.SENDONLY;
847
         const direction = isLocalSdp ? MediaDirection.RECVONLY : MediaDirection.SENDONLY;
806
-        const mLines = parsedSdp.media.filter(m => m.type === MediaType.VIDEO && m.direction !== direction);
848
+        const mLines = mungedSdp.media.filter(m => m.type === MediaType.VIDEO && m.direction !== direction);
807
         const currentCodec = pcCodecSettings.codecList[0];
849
         const currentCodec = pcCodecSettings.codecList[0];
808
         const codecScalabilityModeSettings = this.codecSettings[currentCodec];
850
         const codecScalabilityModeSettings = this.codecSettings[currentCodec];
809
 
851
 
846
             }
888
             }
847
         }
889
         }
848
 
890
 
849
-        return {
850
-            type: description.type,
851
-            sdp: transform.write(parsedSdp)
852
-        };
891
+        return mungedSdp;
853
     }
892
     }
854
 
893
 
855
     /**
894
     /**
856
      * Checks if the AV1 Dependency descriptors are negotiated on the bridge peerconnection and removes them from the
895
      * Checks if the AV1 Dependency descriptors are negotiated on the bridge peerconnection and removes them from the
857
-     * description when codec selected is VP8 or VP9.
896
+     * SDP when codec selected is VP8 or VP9.
858
      *
897
      *
859
-     * @param {RTCSessionDescription} description that needs to be munged.
860
-     * @returns {RTCSessionDescription} the munged description.
898
+     * @param {transform.SessionDescription} parsedSdp that needs to be munged.
899
+     * @returns {string} the munged SDP.
861
      */
900
      */
862
-    updateAv1DdHeaders(description) {
863
-        const parsedSdp = transform.parse(description.sdp);
864
-        const mLines = parsedSdp.media.filter(m => m.type === MediaType.VIDEO);
865
-
866
-        if (!mLines.length || !browser.supportsDDExtHeaders()) {
867
-            return description;
901
+    updateAv1DdHeaders(parsedSdp) {
902
+        if (!this.supportsDDHeaderExt) {
903
+            return parsedSdp;
868
         }
904
         }
905
+        const mungedSdp = parsedSdp;
906
+        const mLines = mungedSdp.media.filter(m => m.type === MediaType.VIDEO);
869
 
907
 
870
         mLines.forEach((mLine, idx) => {
908
         mLines.forEach((mLine, idx) => {
871
             const senderMids = Array.from(this.pc.localTrackTransceiverMids.values());
909
             const senderMids = Array.from(this.pc.localTrackTransceiverMids.values());
896
             }
934
             }
897
         });
935
         });
898
 
936
 
899
-        return {
900
-            type: description.type,
901
-            sdp: transform.write(parsedSdp)
902
-        };
937
+        return mungedSdp;
903
     }
938
     }
904
 }
939
 }

+ 13
- 61
modules/RTC/TraceablePeerConnection.js View File

1187
     return ssrcInfo && ssrcInfo.ssrcs[0];
1187
     return ssrcInfo && ssrcInfo.ssrcs[0];
1188
 };
1188
 };
1189
 
1189
 
1190
-/**
1191
- * When doing unified plan simulcast, we'll have a set of ssrcs but no ssrc-groups on Firefox. Unfortunately, Jicofo
1192
- * will complain if it sees ssrcs with matching msids but no ssrc-group, so a ssrc-group line is injected to make
1193
- * Jicofo happy.
1194
- *
1195
- * @param desc A session description object (with 'type' and 'sdp' fields)
1196
- * @return A session description object with its sdp field modified to contain an inject ssrc-group for simulcast.
1197
- */
1198
-TraceablePeerConnection.prototype._injectSsrcGroupForUnifiedSimulcast = function(desc) {
1199
-    const sdp = transform.parse(desc.sdp);
1200
-    const video = sdp.media.find(mline => mline.type === 'video');
1201
-
1202
-    // Check if the browser supports RTX, add only the primary ssrcs to the SIM group if that is the case.
1203
-    video.ssrcGroups = video.ssrcGroups || [];
1204
-    const fidGroups = video.ssrcGroups.filter(group => group.semantics === SSRC_GROUP_SEMANTICS.FID);
1205
-
1206
-    if (video.simulcast || video.simulcast_03) {
1207
-        const ssrcs = [];
1208
-
1209
-        if (fidGroups && fidGroups.length) {
1210
-            fidGroups.forEach(group => {
1211
-                ssrcs.push(group.ssrcs.split(' ')[0]);
1212
-            });
1213
-        } else {
1214
-            video.ssrcs.forEach(ssrc => {
1215
-                if (ssrc.attribute === 'msid') {
1216
-                    ssrcs.push(ssrc.id);
1217
-                }
1218
-            });
1219
-        }
1220
-        if (video.ssrcGroups.find(group => group.semantics === SSRC_GROUP_SEMANTICS.SIM)) {
1221
-            // Group already exists, no need to do anything
1222
-            return desc;
1223
-        }
1224
-
1225
-        // Add a SIM group for every 3 FID groups.
1226
-        for (let i = 0; i < ssrcs.length; i += 3) {
1227
-            const simSsrcs = ssrcs.slice(i, i + 3);
1228
-
1229
-            video.ssrcGroups.push({
1230
-                semantics: SSRC_GROUP_SEMANTICS.SIM,
1231
-                ssrcs: simSsrcs.join(' ')
1232
-            });
1233
-        }
1234
-    }
1235
-
1236
-    return {
1237
-        type: desc.type,
1238
-        sdp: transform.write(sdp)
1239
-    };
1240
-};
1241
-
1242
 /* eslint-disable-next-line vars-on-top */
1190
 /* eslint-disable-next-line vars-on-top */
1243
 const getters = {
1191
 const getters = {
1244
     signalingState() {
1192
     signalingState() {
1261
 
1209
 
1262
         this.trace('getLocalDescription::preTransform', dumpSDP(desc));
1210
         this.trace('getLocalDescription::preTransform', dumpSDP(desc));
1263
 
1211
 
1264
-        // For a jvb connection, transform the SDP to Plan B first.
1265
         if (!this.isP2P) {
1212
         if (!this.isP2P) {
1266
-            desc = this._injectSsrcGroupForUnifiedSimulcast(desc);
1213
+            desc = this.tpcUtils.injectSsrcGroupForUnifiedSimulcast(desc);
1267
             this.trace('getLocalDescription::postTransform (inject ssrc group)', dumpSDP(desc));
1214
             this.trace('getLocalDescription::postTransform (inject ssrc group)', dumpSDP(desc));
1268
         }
1215
         }
1269
 
1216
 
1457
  * @returns {Array}
1404
  * @returns {Array}
1458
  */
1405
  */
1459
 TraceablePeerConnection.prototype.getConfiguredVideoCodecs = function(description) {
1406
 TraceablePeerConnection.prototype.getConfiguredVideoCodecs = function(description) {
1460
-    return this.tpcUtils.getConfiguredVideoCodecs(description);
1407
+    return this.tpcUtils.getConfiguredVideoCodecs(description?.sdp);
1461
 };
1408
 };
1462
 
1409
 
1463
 /**
1410
 /**
2001
  * @returns {RTCSessionDescription} - The munged description.
1948
  * @returns {RTCSessionDescription} - The munged description.
2002
  */
1949
  */
2003
 TraceablePeerConnection.prototype._mungeDescription = function(description) {
1950
 TraceablePeerConnection.prototype._mungeDescription = function(description) {
2004
-    let mungedDescription = description;
2005
-
2006
     this.trace('RTCSessionDescription::preTransform', dumpSDP(description));
1951
     this.trace('RTCSessionDescription::preTransform', dumpSDP(description));
2007
-    mungedDescription = this.tpcUtils.mungeOpus(description);
2008
-    mungedDescription = this.tpcUtils.mungeCodecOrder(mungedDescription);
2009
-    mungedDescription = this.tpcUtils.setMaxBitrates(mungedDescription, true);
2010
-    mungedDescription = this.tpcUtils.updateAv1DdHeaders(mungedDescription);
1952
+    let mungedSdp = transform.parse(description.sdp);
1953
+
1954
+    mungedSdp = this.tpcUtils.mungeOpus(mungedSdp);
1955
+    mungedSdp = this.tpcUtils.mungeCodecOrder(mungedSdp);
1956
+    mungedSdp = this.tpcUtils.setMaxBitrates(mungedSdp, true);
1957
+    mungedSdp = this.tpcUtils.updateAv1DdHeaders(mungedSdp);
1958
+    const mungedDescription = {
1959
+        type: description.type,
1960
+        sdp: transform.write(mungedSdp)
1961
+    };
1962
+
2011
     this.trace('RTCSessionDescription::postTransform', dumpSDP(mungedDescription));
1963
     this.trace('RTCSessionDescription::postTransform', dumpSDP(mungedDescription));
2012
 
1964
 
2013
     return mungedDescription;
1965
     return mungedDescription;

Loading…
Cancel
Save