From fb247007c6abe4adef10d317f87a0596351ff7c4 Mon Sep 17 00:00:00 2001 From: th-aslam Date: Thu, 23 Jul 2026 15:40:16 -0700 Subject: [PATCH] feat: make the p2p H.264 high profile stripping configurable. --- modules/RTC/MockClasses.ts | 13 +++++ modules/RTC/TPCUtils.spec.ts | 54 +++++++++++++++++++++ modules/RTC/TPCUtils.ts | 10 +++- service/RTC/StandardVideoQualitySettings.ts | 5 +- 4 files changed, 80 insertions(+), 2 deletions(-) diff --git a/modules/RTC/MockClasses.ts b/modules/RTC/MockClasses.ts index e8c1715281..b2d9a96bba 100644 --- a/modules/RTC/MockClasses.ts +++ b/modules/RTC/MockClasses.ts @@ -132,6 +132,10 @@ export class MockPeerConnection { * @internal */ _midsWithSentTrack: Set; + /** + * {@link TraceablePeerConnection.codecSettings}. + */ + codecSettings?: { codecList: string[]; mediaType: MediaType; }; /** * Constructor. * @@ -195,6 +199,15 @@ export class MockPeerConnection { return false; } + /** + * {@link TraceablePeerConnection.usesCodecSelectionAPI}. + * + * @returns {boolean} + */ + usesCodecSelectionAPI(): boolean { + return false; + } + /** * Returns the list of the codecs negotiated. * @returns {Array} diff --git a/modules/RTC/TPCUtils.spec.ts b/modules/RTC/TPCUtils.spec.ts index b28d437d10..17353dbe53 100644 --- a/modules/RTC/TPCUtils.spec.ts +++ b/modules/RTC/TPCUtils.spec.ts @@ -1,4 +1,6 @@ /* eslint-disable max-len */ +import transform from 'sdp-transform'; + import { CodecMimeType } from '../../service/RTC/CodecMimeType'; import { MediaType } from '../../service/RTC/MediaType'; import { SIM_LAYERS } from '../../service/RTC/StandardVideoQualitySettings'; @@ -208,6 +210,58 @@ describe('TPCUtils', () => { }); }); + describe('mungeCodecOrder()', () => { + const sdpStr = [ + 'v=0', + 'o=- 814997227879783433 5 IN IP4 127.0.0.1', + 's=-', + 't=0 0', + 'm=video 9 RTP/SAVPF 100 102 96', + 'c=IN IP4 0.0.0.0', + 'a=rtpmap:100 H264/90000', + 'a=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f', + 'a=rtpmap:102 H264/90000', + 'a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640028', + 'a=rtpmap:96 VP8/90000', + 'a=mid:0', + '' + ].join('\r\n'); + + const createTpcUtils = (videoQuality = {}) => { + const pc = new MockPeerConnection('1', true, false /* simulcast */); + + pc.codecSettings = { + codecList: [ CodecMimeType.H264, CodecMimeType.VP8 ], + mediaType: MediaType.VIDEO + }; + + return new TPCUtils(pc, { + isP2P: true, + videoQuality + }); + }; + + it('strips the high profile H.264 payload types on p2p by default', () => { + const tpcUtils = createTpcUtils(); + const mungedSdp = tpcUtils.mungeCodecOrder(transform.parse(sdpStr)); + const mLine = mungedSdp.media.find(m => m.type === 'video'); + + expect(mLine.rtp.some(pt => pt.payload === 100)).toBe(true); + expect(mLine.rtp.some(pt => pt.payload === 102)).toBe(false); + expect(mLine.fmtp.some(f => f.payload === 102)).toBe(false); + }); + + it('keeps the high profile H.264 payload types when videoQuality.h264.stripHighProfile is disabled', () => { + const tpcUtils = createTpcUtils({ h264: { stripHighProfile: false } }); + const mungedSdp = tpcUtils.mungeCodecOrder(transform.parse(sdpStr)); + const mLine = mungedSdp.media.find(m => m.type === 'video'); + + expect(mLine.rtp.some(pt => pt.payload === 100)).toBe(true); + expect(mLine.rtp.some(pt => pt.payload === 102)).toBe(true); + expect(mLine.fmtp.some(f => f.payload === 102)).toBe(true); + }); + }); + describe('Test encodings when default settings are used for', () => { let pc, tpcUtils; let activeState, height, maxBitrates, scalabilityModes, scaleFactor; diff --git a/modules/RTC/TPCUtils.ts b/modules/RTC/TPCUtils.ts index 2e4683dc28..668479902b 100644 --- a/modules/RTC/TPCUtils.ts +++ b/modules/RTC/TPCUtils.ts @@ -30,6 +30,7 @@ export interface ICodecConfig { [key: string]: number; }; scalabilityModeEnabled?: boolean; + stripHighProfile?: boolean; useKSVC?: boolean; useSimulcast?: boolean; } @@ -92,6 +93,9 @@ export class TPCUtils { continue; // eslint-disable-line no-continue } + typeof codecConfig.stripHighProfile !== 'undefined' + && (this.codecSettings[codec].stripHighProfile = codecConfig.stripHighProfile); + const scalabilityModeEnabled = this.codecSettings[codec].scalabilityModeEnabled && (typeof codecConfig.scalabilityModeEnabled === 'undefined' || codecConfig.scalabilityModeEnabled); @@ -837,7 +841,11 @@ export class TPCUtils { // 2. There are multiple VP9 payload types generated by the browser, more payload types are added // if the endpoint doesn't have a local video source. Therefore, strip all the high profile codec // variants for VP9 so that only one payload type for VP9 is negotiated between the peers. - if (codec === CodecMimeType.H264 || codec === CodecMimeType.VP9) { + // The H.264 strip can be disabled through config.js (videoQuality.h264.stripHighProfile=false) + // for deployments that want to negotiate Main/High profile, e.g. for hardware encoders that do + // not support the baseline profiles. + if ((codec === CodecMimeType.H264 && this.codecSettings[codec].stripHighProfile) + || codec === CodecMimeType.VP9) { SDPUtil.stripCodec(mLine, codec, true /* high profile */); } diff --git a/service/RTC/StandardVideoQualitySettings.ts b/service/RTC/StandardVideoQualitySettings.ts index e463311e87..8e009e1c48 100644 --- a/service/RTC/StandardVideoQualitySettings.ts +++ b/service/RTC/StandardVideoQualitySettings.ts @@ -70,7 +70,10 @@ export const STANDARD_CODEC_SETTINGS = { standard: 800000, ultraHd: 8000000, }, - scalabilityModeEnabled: browser.supportsScalabilityModeAPI() + scalabilityModeEnabled: browser.supportsScalabilityModeAPI(), + + // Whether the Main/High profile H.264 payload types are stripped from the SDP on p2p connections. + stripHighProfile: true }, vp8: { maxBitratesVideo: {