|
@@ -7,6 +7,7 @@ import { MediaDirection } from '../../service/RTC/MediaDirection';
|
7
|
7
|
import { MediaType } from '../../service/RTC/MediaType';
|
8
|
8
|
import {
|
9
|
9
|
SIM_LAYERS,
|
|
10
|
+ SSRC_GROUP_SEMANTICS,
|
10
|
11
|
STANDARD_CODEC_SETTINGS,
|
11
|
12
|
VIDEO_QUALITY_LEVELS,
|
12
|
13
|
VIDEO_QUALITY_SETTINGS
|
|
@@ -438,12 +439,11 @@ export class TPCUtils {
|
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
|
448
|
ensureCorrectOrderOfSsrcs(description) {
|
449
|
449
|
const parsedSdp = transform.parse(description.sdp);
|
|
@@ -493,14 +493,15 @@ export class TPCUtils {
|
493
|
493
|
if (this.pc.usesCodecSelectionAPI() && rtpSender) {
|
494
|
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
|
501
|
const sdp = this.pc.remoteDescription?.sdp;
|
500
|
|
- const defaultCodec = CodecMimeType.VP8;
|
501
|
502
|
|
502
|
503
|
if (!sdp) {
|
503
|
|
- return defaultCodec;
|
|
504
|
+ return CodecMimeType.VP8;
|
504
|
505
|
}
|
505
|
506
|
const parsedSdp = transform.parse(sdp);
|
506
|
507
|
const mLine = parsedSdp.media
|
|
@@ -512,17 +513,17 @@ export class TPCUtils {
|
512
|
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
|
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
|
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
|
528
|
if (!currentSdp) {
|
528
|
529
|
return [];
|
|
@@ -574,6 +575,57 @@ export class TPCUtils {
|
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
|
630
|
* Takes in a *unified plan* offer and inserts the appropriate parameters for adding simulcast receive support.
|
579
|
631
|
* @param {Object} desc - A session description object
|
|
@@ -659,26 +711,22 @@ export class TPCUtils {
|
659
|
711
|
/**
|
660
|
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
|
718
|
const codecSettings = this.pc.codecSettings;
|
667
|
719
|
|
668
|
720
|
if (!codecSettings) {
|
669
|
|
- return description;
|
|
721
|
+ return parsedSdp;
|
670
|
722
|
}
|
671
|
723
|
|
|
724
|
+ const mungedSdp = parsedSdp;
|
672
|
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
|
728
|
for (const mLine of mLines) {
|
681
|
|
- const currentCodecs = this.getConfiguredVideoCodecs(description);
|
|
729
|
+ const currentCodecs = this.getConfiguredVideoCodecs(transform.write(parsedSdp));
|
682
|
730
|
|
683
|
731
|
for (const codec of currentCodecs) {
|
684
|
732
|
if (isP2P) {
|
|
@@ -707,28 +755,25 @@ export class TPCUtils {
|
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
|
762
|
* Munges the stereo flag as well as the opusMaxAverageBitrate in the SDP, based on values set through config.js,
|
718
|
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
|
769
|
const { audioQuality } = this.options;
|
725
|
770
|
|
726
|
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
|
778
|
for (const mLine of mLines) {
|
734
|
779
|
const { payload } = mLine.rtp.find(protocol => protocol.codec === CodecMimeType.OPUS);
|
|
@@ -780,30 +825,27 @@ export class TPCUtils {
|
780
|
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
|
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
|
839
|
const pcCodecSettings = this.pc.codecSettings;
|
798
|
840
|
|
799
|
841
|
if (!pcCodecSettings) {
|
800
|
|
- return description;
|
|
842
|
+ return parsedSdp;
|
801
|
843
|
}
|
802
|
|
- const parsedSdp = transform.parse(description.sdp);
|
803
|
844
|
|
804
|
845
|
// Find all the m-lines associated with the local sources.
|
|
846
|
+ const mungedSdp = parsedSdp;
|
805
|
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
|
849
|
const currentCodec = pcCodecSettings.codecList[0];
|
808
|
850
|
const codecScalabilityModeSettings = this.codecSettings[currentCodec];
|
809
|
851
|
|
|
@@ -846,26 +888,22 @@ export class TPCUtils {
|
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
|
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
|
908
|
mLines.forEach((mLine, idx) => {
|
871
|
909
|
const senderMids = Array.from(this.pc.localTrackTransceiverMids.values());
|
|
@@ -896,9 +934,6 @@ export class TPCUtils {
|
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
|
}
|