Skip to content

Commit

Permalink
Enable DTX on audio tracks in calls (#2482)
Browse files Browse the repository at this point in the history
This greatly reduces the amount of bandwidth used when transmitting
silence.
  • Loading branch information
robintown authored Jun 29, 2022
1 parent f553854 commit e7493fd
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 7 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
],
"dependencies": {
"@babel/runtime": "^7.12.5",
"@types/sdp-transform": "^2.4.5",
"another-json": "^0.2.0",
"browser-request": "^0.3.3",
"bs58": "^4.0.1",
Expand All @@ -63,6 +64,7 @@
"p-retry": "^4.5.0",
"qs": "^6.9.6",
"request": "^2.88.2",
"sdp-transform": "^2.14.1",
"unhomoglyph": "^1.0.6"
},
"devDependencies": {
Expand Down
64 changes: 57 additions & 7 deletions src/webrtc/call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ limitations under the License.
* @module webrtc/call
*/

import { parse as parseSdp, write as writeSdp } from "sdp-transform";

import { logger } from '../logger';
import * as utils from '../utils';
import { MatrixEvent } from '../models/event';
Expand Down Expand Up @@ -171,6 +173,11 @@ export enum CallErrorCode {
*/
CreateAnswer = 'create_answer',

/**
* An offer could not be created
*/
CreateOffer = 'create_offer',

/**
* Error code used when we fail to send the answer
* for some reason other than there being unknown devices
Expand Down Expand Up @@ -1438,6 +1445,31 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
}
}

// Enables DTX (discontinuous transmission) on the given session to reduce
// bandwidth when transmitting silence
private enableDtx(description: RTCSessionDescriptionInit): void {
// The only way to enable DTX at this time is through SDP munging
const sdp = parseSdp(description.sdp);
sdp.media.forEach(media => {
if (media.type === "audio") {
media.fmtp.forEach(fmtp => fmtp.config += ";usedtx=1");
}
});
description.sdp = writeSdp(sdp);
}

private async createOffer(): Promise<RTCSessionDescriptionInit> {
const offer = await this.peerConn.createOffer();
this.enableDtx(offer);
return offer;
}

private async createAnswer(): Promise<RTCSessionDescriptionInit> {
const answer = await this.peerConn.createAnswer();
this.enableDtx(answer);
return answer;
}

private async gotCallFeedsForAnswer(callFeeds: CallFeed[]): Promise<void> {
if (this.callHasEnded()) return;

Expand All @@ -1449,18 +1481,18 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap

this.setState(CallState.CreateAnswer);

let myAnswer;
let answer: RTCSessionDescriptionInit;
try {
this.getRidOfRTXCodecs();
myAnswer = await this.peerConn.createAnswer();
answer = await this.createAnswer();
} catch (err) {
logger.debug(`Call ${this.callId} Failed to create answer: `, err);
this.terminate(CallParty.Local, CallErrorCode.CreateAnswer, true);
return;
}

try {
await this.peerConn.setLocalDescription(myAnswer);
await this.peerConn.setLocalDescription(answer);
this.setState(CallState.Connecting);

// Allow a short time for initial candidates to be gathered
Expand Down Expand Up @@ -1672,8 +1704,17 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
await this.peerConn.setRemoteDescription(description);

if (description.type === 'offer') {
this.getRidOfRTXCodecs();
await this.peerConn.setLocalDescription();
let answer: RTCSessionDescriptionInit;
try {
this.getRidOfRTXCodecs();
answer = await this.createAnswer();
} catch (err) {
logger.debug(`Call ${this.callId} Failed to create answer: `, err);
this.terminate(CallParty.Local, CallErrorCode.CreateAnswer, true);
return;
}

await this.peerConn.setLocalDescription(answer);

this.sendVoipEvent(EventType.CallNegotiate, {
description: this.peerConn.localDescription,
Expand Down Expand Up @@ -1741,7 +1782,6 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
private async wrappedGotLocalOffer(): Promise<void> {
this.makingOffer = true;
try {
this.getRidOfRTXCodecs();
await this.gotLocalOffer();
} catch (e) {
this.getLocalOfferFailed(e);
Expand All @@ -1760,8 +1800,18 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
return;
}

let offer: RTCSessionDescriptionInit;
try {
this.getRidOfRTXCodecs();
offer = await this.createOffer();
} catch (err) {
logger.debug(`Call ${this.callId} Failed to create offer: `, err);
this.terminate(CallParty.Local, CallErrorCode.CreateOffer, true);
return;
}

try {
await this.peerConn.setLocalDescription();
await this.peerConn.setLocalDescription(offer);
} catch (err) {
logger.debug(`Call ${this.callId} Error setting local description!`, err);
this.terminate(CallParty.Local, CallErrorCode.SetLocalDescription, true);
Expand Down
10 changes: 10 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1608,6 +1608,11 @@
resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d"
integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==

"@types/sdp-transform@^2.4.5":
version "2.4.5"
resolved "https://registry.yarnpkg.com/@types/sdp-transform/-/sdp-transform-2.4.5.tgz#3167961e0a1a5265545e278627aa37c606003f53"
integrity sha512-GVO0gnmbyO3Oxm2HdPsYUNcyihZE3GyCY8ysMYHuQGfLhGZq89Nm4lSzULWTzZoyHtg+VO/IdrnxZHPnPSGnAg==

"@types/stack-utils@^2.0.0":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
Expand Down Expand Up @@ -5874,6 +5879,11 @@ safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==

sdp-transform@^2.14.1:
version "2.14.1"
resolved "https://registry.yarnpkg.com/sdp-transform/-/sdp-transform-2.14.1.tgz#2bb443583d478dee217df4caa284c46b870d5827"
integrity sha512-RjZyX3nVwJyCuTo5tGPx+PZWkDMCg7oOLpSlhjDdZfwUoNqG1mM8nyj31IGHyaPWXhjbP7cdK3qZ2bmkJ1GzRw==

[email protected]:
version "7.0.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
Expand Down

0 comments on commit e7493fd

Please sign in to comment.