|
|
@@ -564,46 +564,37 @@ const SDPUtil = {
|
|
564
|
564
|
},
|
|
565
|
565
|
|
|
566
|
566
|
/**
|
|
567
|
|
- * Sets the given codecName as the preferred codec by
|
|
568
|
|
- * moving it to the beginning of the payload types
|
|
569
|
|
- * list (modifies the given mline in place). If there
|
|
570
|
|
- * are multiple options within the same codec (multiple h264
|
|
571
|
|
- * profiles, for instance), this will prefer the first one
|
|
572
|
|
- * that is found.
|
|
573
|
|
- * @param {object} videoMLine the video mline object from
|
|
574
|
|
- * an sdp as parsed by transform.parse
|
|
|
567
|
+ * Sets the given codecName as the preferred codec by moving it to the beginning
|
|
|
568
|
+ * of the payload types list (modifies the given mline in place). All instances
|
|
|
569
|
+ * of the codec are moved up.
|
|
|
570
|
+ * @param {object} mLine the mline object from an sdp as parsed by transform.parse
|
|
575
|
571
|
* @param {string} codecName the name of the preferred codec
|
|
576
|
572
|
*/
|
|
577
|
|
- preferVideoCodec(videoMLine, codecName) {
|
|
578
|
|
- let payloadType = null;
|
|
579
|
|
-
|
|
580
|
|
- if (!videoMLine || !codecName) {
|
|
|
573
|
+ preferCodec(mline, codecName) {
|
|
|
574
|
+ if (!mline || !codecName) {
|
|
581
|
575
|
return;
|
|
582
|
576
|
}
|
|
583
|
577
|
|
|
584
|
|
- for (let i = 0; i < videoMLine.rtp.length; ++i) {
|
|
585
|
|
- const rtp = videoMLine.rtp[i];
|
|
|
578
|
+ const matchingPayloadTypes = mline.rtp
|
|
|
579
|
+ .filter(rtp => rtp.codec && rtp.codec.toLowerCase() === codecName.toLowerCase())
|
|
|
580
|
+ .map(rtp => rtp.payload);
|
|
586
|
581
|
|
|
587
|
|
- if (rtp.codec
|
|
588
|
|
- && rtp.codec.toLowerCase() === codecName.toLowerCase()) {
|
|
589
|
|
- payloadType = rtp.payload;
|
|
590
|
|
- break;
|
|
591
|
|
- }
|
|
592
|
|
- }
|
|
593
|
|
- if (payloadType) {
|
|
594
|
|
- // Call toString() on payloads to get around an issue within
|
|
595
|
|
- // SDPTransform that sets payloads as a number, instead of a string,
|
|
596
|
|
- // when there is only one payload.
|
|
|
582
|
+ if (matchingPayloadTypes) {
|
|
|
583
|
+ // Call toString() on payloads to get around an issue within SDPTransform that sets
|
|
|
584
|
+ // payloads as a number, instead of a string, when there is only one payload.
|
|
597
|
585
|
const payloadTypes
|
|
598
|
|
- = videoMLine.payloads
|
|
599
|
|
- .toString()
|
|
600
|
|
- .split(' ')
|
|
601
|
|
- .map(p => parseInt(p, 10));
|
|
602
|
|
- const payloadIndex = payloadTypes.indexOf(payloadType);
|
|
|
586
|
+ = mline.payloads
|
|
|
587
|
+ .toString()
|
|
|
588
|
+ .split(' ')
|
|
|
589
|
+ .map(p => parseInt(p, 10));
|
|
|
590
|
+
|
|
|
591
|
+ for (const pt of matchingPayloadTypes.reverse()) {
|
|
|
592
|
+ const payloadIndex = payloadTypes.indexOf(pt);
|
|
603
|
593
|
|
|
604
|
|
- payloadTypes.splice(payloadIndex, 1);
|
|
605
|
|
- payloadTypes.unshift(payloadType);
|
|
606
|
|
- videoMLine.payloads = payloadTypes.join(' ');
|
|
|
594
|
+ payloadTypes.splice(payloadIndex, 1);
|
|
|
595
|
+ payloadTypes.unshift(pt);
|
|
|
596
|
+ }
|
|
|
597
|
+ mline.payloads = payloadTypes.join(' ');
|
|
607
|
598
|
}
|
|
608
|
599
|
},
|
|
609
|
600
|
|
|
|
@@ -612,29 +603,41 @@ const SDPUtil = {
|
|
612
|
603
|
* types are also stripped. If the resulting mline would have no codecs,
|
|
613
|
604
|
* it's disabled.
|
|
614
|
605
|
*
|
|
615
|
|
- * @param {object} videoMLine the video mline object from an sdp as parsed
|
|
616
|
|
- * by transform.parse.
|
|
|
606
|
+ * @param {object} mLine the mline object from an sdp as parsed by transform.parse.
|
|
617
|
607
|
* @param {string} codecName the name of the codec which will be stripped.
|
|
618
|
608
|
*/
|
|
619
|
|
- stripVideoCodec(videoMLine, codecName) {
|
|
620
|
|
- if (!videoMLine || !codecName) {
|
|
|
609
|
+ stripCodec(mLine, codecName, highProfile = false) {
|
|
|
610
|
+ if (!mLine || !codecName) {
|
|
621
|
611
|
return;
|
|
622
|
612
|
}
|
|
623
|
613
|
|
|
624
|
|
- const removePts = [];
|
|
|
614
|
+ const h264Pts = [];
|
|
|
615
|
+ let removePts = [];
|
|
|
616
|
+ const stripH264HighCodec = codecName.toLowerCase() === 'h264' && highProfile;
|
|
625
|
617
|
|
|
626
|
|
- for (const rtp of videoMLine.rtp) {
|
|
|
618
|
+ for (const rtp of mLine.rtp) {
|
|
627
|
619
|
if (rtp.codec
|
|
628
|
620
|
&& rtp.codec.toLowerCase() === codecName.toLowerCase()) {
|
|
629
|
|
- removePts.push(rtp.payload);
|
|
|
621
|
+ if (stripH264HighCodec) {
|
|
|
622
|
+ h264Pts.push(rtp.payload);
|
|
|
623
|
+ } else {
|
|
|
624
|
+ removePts.push(rtp.payload);
|
|
|
625
|
+ }
|
|
630
|
626
|
}
|
|
631
|
627
|
}
|
|
632
|
628
|
|
|
|
629
|
+ // high profile H264 codecs have 64 as the first two bytes of the profile-level-id.
|
|
|
630
|
+ if (stripH264HighCodec) {
|
|
|
631
|
+ removePts = mLine.fmtp
|
|
|
632
|
+ .filter(item => h264Pts.indexOf(item.payload) > -1 && item.config.includes('profile-level-id=64'))
|
|
|
633
|
+ .map(item => item.payload);
|
|
|
634
|
+ }
|
|
|
635
|
+
|
|
633
|
636
|
if (removePts.length > 0) {
|
|
634
|
637
|
// We also need to remove the payload types that are related to RTX
|
|
635
|
638
|
// for the codecs we want to disable.
|
|
636
|
639
|
const rtxApts = removePts.map(item => `apt=${item}`);
|
|
637
|
|
- const rtxPts = videoMLine.fmtp.filter(
|
|
|
640
|
+ const rtxPts = mLine.fmtp.filter(
|
|
638
|
641
|
item => rtxApts.indexOf(item.config) !== -1);
|
|
639
|
642
|
|
|
640
|
643
|
removePts.push(...rtxPts.map(item => item.payload));
|
|
|
@@ -642,27 +645,27 @@ const SDPUtil = {
|
|
642
|
645
|
// Call toString() on payloads to get around an issue within
|
|
643
|
646
|
// SDPTransform that sets payloads as a number, instead of a string,
|
|
644
|
647
|
// when there is only one payload.
|
|
645
|
|
- const allPts = videoMLine.payloads
|
|
|
648
|
+ const allPts = mLine.payloads
|
|
646
|
649
|
.toString()
|
|
647
|
650
|
.split(' ')
|
|
648
|
651
|
.map(Number);
|
|
649
|
652
|
const keepPts = allPts.filter(pt => removePts.indexOf(pt) === -1);
|
|
650
|
653
|
|
|
651
|
654
|
if (keepPts.length === 0) {
|
|
652
|
|
- // There are no other video codecs, disable the stream.
|
|
653
|
|
- videoMLine.port = 0;
|
|
654
|
|
- videoMLine.direction = 'inactive';
|
|
655
|
|
- videoMLine.payloads = '*';
|
|
|
655
|
+ // There are no other codecs, disable the stream.
|
|
|
656
|
+ mLine.port = 0;
|
|
|
657
|
+ mLine.direction = 'inactive';
|
|
|
658
|
+ mLine.payloads = '*';
|
|
656
|
659
|
} else {
|
|
657
|
|
- videoMLine.payloads = keepPts.join(' ');
|
|
|
660
|
+ mLine.payloads = keepPts.join(' ');
|
|
658
|
661
|
}
|
|
659
|
662
|
|
|
660
|
|
- videoMLine.rtp = videoMLine.rtp.filter(
|
|
|
663
|
+ mLine.rtp = mLine.rtp.filter(
|
|
661
|
664
|
item => keepPts.indexOf(item.payload) !== -1);
|
|
662
|
|
- videoMLine.fmtp = videoMLine.fmtp.filter(
|
|
|
665
|
+ mLine.fmtp = mLine.fmtp.filter(
|
|
663
|
666
|
item => keepPts.indexOf(item.payload) !== -1);
|
|
664
|
|
- if (videoMLine.rtcpFb) {
|
|
665
|
|
- videoMLine.rtcpFb = videoMLine.rtcpFb.filter(
|
|
|
667
|
+ if (mLine.rtcpFb) {
|
|
|
668
|
+ mLine.rtcpFb = mLine.rtcpFb.filter(
|
|
666
|
669
|
item => keepPts.indexOf(item.payload) !== -1);
|
|
667
|
670
|
}
|
|
668
|
671
|
}
|