Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/handlers/ortc/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,12 @@ export function applyForcedRtpExtensions(
const uri = extenCap.uri as RtpHeaderExtensionUri;
const enabled: boolean | undefined = forcedRtpExtensions[uri];

if (enabled === true) {
// MID is mandatory when BUNDLE is used and cannot be disabled by this API.
// Some browsers may report it as stopped after negotiation, but reject the
// entire list if that direction is submitted again.
Comment on lines -78 to +80

@ibc ibc Oct 19, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an IA written PR. Which is the real evidence behind this IA predictable comment? It clearly looks like if you prompted to the IA agent some statement (what is said in the reported issue ticket) and it just generated a solution assuming that issue is true or normal behavior in some browsers. Is this a bug already reported in libwebrtc?

if (uri === 'urn:ietf:params:rtp-hdrext:sdes:mid') {
extenCap.direction = 'sendrecv';
} else if (enabled === true) {
extenCap.direction = 'sendrecv';
} else if (enabled === false) {
extenCap.direction = 'stopped';
Expand Down
38 changes: 38 additions & 0 deletions src/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { FakeMediaStreamTrack } from 'fake-mediastreamtrack';
import * as mediasoupClient from '../index';
import { UnsupportedError, InvalidStateError } from '../errors';
import * as utils from '../utils';
import { applyForcedRtpExtensions } from '../handlers/ortc/utils';
import type { RtpCapabilities } from '../RtpParameters';
import { FakeHandler } from '../handlers/FakeHandler';
import * as fakeParameters from './fakeParameters';
Expand Down Expand Up @@ -1762,3 +1763,40 @@ describe('detectDevice() and detectDeviceAsync() assign proper handler based on
);
}
});

describe('applyForcedRtpExtensions()', () => {
test('keeps the mandatory MID extension enabled when forcing another extension', () => {
const midUri = 'urn:ietf:params:rtp-hdrext:sdes:mid';
const absCaptureTimeUri =
'http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time';
const capabilities: RTCRtpHeaderExtensionCapability[] = [
{ uri: midUri, direction: 'stopped' },
{ uri: absCaptureTimeUri, direction: 'recvonly' },
];
let submittedCapabilities: RTCRtpHeaderExtensionCapability[] | undefined;
const transceiver = {
getHeaderExtensionsToNegotiate: () => capabilities,
setHeaderExtensionsToNegotiate: (
nextCapabilities: RTCRtpHeaderExtensionCapability[]
) => {
const midExtension = nextCapabilities.find(({ uri }) => uri === midUri);

if (midExtension?.direction !== 'sendrecv') {
throw new Error('Attempted to stop a mandatory extension.');
}

submittedCapabilities = nextCapabilities;
},
} as unknown as RTCRtpTransceiver;

expect(
applyForcedRtpExtensions(transceiver, {
[absCaptureTimeUri]: true,
})
).toBe(true);
expect(submittedCapabilities).toEqual([
{ uri: midUri, direction: 'sendrecv' },
{ uri: absCaptureTimeUri, direction: 'sendrecv' },
]);
});
});