Skip to content

Commit bdb91b3

Browse files
dbkrSimonBrandner
andauthored
Set max average bitrate on PTT calls (#2499)
* Set max average bitrate on PTT calls Via SDP munging. Also makes the SDP munging a bit more generic and codec-specific (we were previously adding usedtx to any codec that had an fmtp line already, which was probably not really the intention). * Make SDP munging for codecs that don't already have fmtp lines * Use sensible typescript syntax Co-authored-by: Šimon Brandner <[email protected]> Co-authored-by: Šimon Brandner <[email protected]>
1 parent 9a15094 commit bdb91b3

File tree

1 file changed

+58
-5
lines changed

1 file changed

+58
-5
lines changed

src/webrtc/call.ts

+58-5
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@ interface AssertedIdentity {
9393
displayName: string;
9494
}
9595

96+
// Used internally to specify modifications to codec parameters in SDP
97+
interface CodecParams {
98+
enableDtx?: boolean; // true to enable discontinuous transmission, false to disable, undefined to leave as-is
99+
maxAverageBitrate?: number; // sets the max average bitrate, or undefined to leave as-is
100+
}
101+
102+
type CodecParamMods = Record<string, CodecParams>;
103+
96104
export enum CallState {
97105
Fledgling = 'fledgling',
98106
InviteSent = 'invite_sent',
@@ -261,6 +269,18 @@ export function genCallID(): string {
261269
return Date.now().toString() + randomString(16);
262270
}
263271

272+
function getCodecParamMods(isPtt: boolean): CodecParamMods {
273+
const mods = {
274+
'opus': {
275+
enableDtx: true,
276+
},
277+
} as CodecParamMods;
278+
279+
if (isPtt) mods.opus.maxAverageBitrate = 12000;
280+
281+
return mods;
282+
}
283+
264284
export type CallEventHandlerMap = {
265285
[CallEvent.DataChannel]: (channel: RTCDataChannel) => void;
266286
[CallEvent.FeedsChanged]: (feeds: CallFeed[]) => void;
@@ -1456,26 +1476,59 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
14561476

14571477
// Enables DTX (discontinuous transmission) on the given session to reduce
14581478
// bandwidth when transmitting silence
1459-
private enableDtx(description: RTCSessionDescriptionInit): void {
1479+
private mungeSdp(description: RTCSessionDescriptionInit, mods: CodecParamMods): void {
14601480
// The only way to enable DTX at this time is through SDP munging
14611481
const sdp = parseSdp(description.sdp);
1482+
14621483
sdp.media.forEach(media => {
1463-
if (media.type === "audio") {
1464-
media.fmtp.forEach(fmtp => fmtp.config += ";usedtx=1");
1484+
const payloadTypeToCodecMap = new Map<number, string>();
1485+
const codecToPayloadTypeMap = new Map<string, number>();
1486+
for (const rtp of media.rtp) {
1487+
payloadTypeToCodecMap.set(rtp.payload, rtp.codec);
1488+
codecToPayloadTypeMap.set(rtp.codec, rtp.payload);
1489+
}
1490+
1491+
for (const [codec, params] of Object.entries(mods)) {
1492+
if (!codecToPayloadTypeMap.has(codec)) {
1493+
logger.info(`Ignoring SDP modifications for ${codec} as it's not present.`);
1494+
continue;
1495+
}
1496+
1497+
const extraconfig: string[] = [];
1498+
if (params.enableDtx !== undefined) {
1499+
extraconfig.push(`usedtx=${params.enableDtx ? '1' : '0'}`);
1500+
}
1501+
if (params.maxAverageBitrate !== undefined) {
1502+
extraconfig.push(`maxaveragebitrate=${params.maxAverageBitrate}`);
1503+
}
1504+
1505+
let found = false;
1506+
for (const fmtp of media.fmtp) {
1507+
if (payloadTypeToCodecMap.get(fmtp.payload) === codec) {
1508+
found = true;
1509+
fmtp.config += ";" + extraconfig.join(";");
1510+
}
1511+
}
1512+
if (!found) {
1513+
media.fmtp.push({
1514+
payload: codecToPayloadTypeMap.get(codec),
1515+
config: extraconfig.join(";"),
1516+
});
1517+
}
14651518
}
14661519
});
14671520
description.sdp = writeSdp(sdp);
14681521
}
14691522

14701523
private async createOffer(): Promise<RTCSessionDescriptionInit> {
14711524
const offer = await this.peerConn.createOffer();
1472-
this.enableDtx(offer);
1525+
this.mungeSdp(offer, getCodecParamMods(this.isPtt));
14731526
return offer;
14741527
}
14751528

14761529
private async createAnswer(): Promise<RTCSessionDescriptionInit> {
14771530
const answer = await this.peerConn.createAnswer();
1478-
this.enableDtx(answer);
1531+
this.mungeSdp(answer, getCodecParamMods(this.isPtt));
14791532
return answer;
14801533
}
14811534

0 commit comments

Comments
 (0)