in src/sdp/SDP.ts [719:787]
private sectionWithCodecPreferences(
section: string,
preferences: VideoCodecCapability[]
): string {
const payloadTypeToCodec: Map<string, VideoCodecCapability> = new Map();
const lines = SDP.splitLines(section);
// Process each line to map payload types to their respective codecs
lines.forEach(line => {
if (!line.startsWith('a=rtpmap:')) {
return;
}
const payloadMatch = /^a=rtpmap:(\d+)\s/.exec(line);
if (!payloadMatch) {
return;
}
const payloadTypeString: string = payloadMatch[1];
for (const preference of preferences) {
if (!line.includes(`${preference.codecName}/${preference.codecCapability.clockRate}`)) {
continue;
}
let codecMatches = false;
if (preference.codecCapability.sdpFmtpLine !== undefined) {
let hasVp9ProfileId = false;
for (const prospectiveFmtpLine of lines) {
if (preference.fmtpLineMatches(prospectiveFmtpLine, parseInt(payloadTypeString))) {
codecMatches = true;
break;
}
hasVp9ProfileId ||= prospectiveFmtpLine.startsWith(
`a=fmtp:${payloadTypeString} profile-id=`
);
}
if (preference.equals(VideoCodecCapability.vp9Profile0()) && !hasVp9ProfileId) {
codecMatches = true;
}
} else {
codecMatches = true;
}
if (codecMatches) {
payloadTypeToCodec.set(payloadTypeString, preference);
break;
}
}
});
const payloadTypesToRemove: Set<string> = new Set(payloadTypeToCodec.keys());
const mline = lines[0].split(' ').filter(text => !payloadTypesToRemove.has(text));
const orderedPreferedPayloadTypes = Array.from(payloadTypeToCodec.entries())
.sort(([_payloadType1, codec1], [_payloadType2, codec2]) => {
const priority1 = preferences.indexOf(codec1);
const priority2 = preferences.indexOf(codec2);
return priority1 - priority2;
})
.map(([payloadType, _]) => payloadType);
mline.splice(3, 0, ...orderedPreferedPayloadTypes);
lines[0] = mline.join(' ');
return lines.join(SDP.CRLF) + SDP.CRLF;
}