Skip to content

Commit e64c9a8

Browse files
chore: add audio level and access to call stats on media-signaling lib (RocketChat#37160)
1 parent 1b85a9e commit e64c9a8

4 files changed

Lines changed: 94 additions & 1 deletion

File tree

packages/media-signaling/src/definition/call/IClientMediaCall.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ export interface IClientMediaCall {
7777
busy: boolean;
7878

7979
contact: CallContact;
80+
audioLevel: number;
81+
localAudioLevel: number;
8082

8183
emitter: Emitter<CallEvents>;
8284

@@ -90,4 +92,6 @@ export interface IClientMediaCall {
9092
transfer(callee: { type: CallActorType; id: string }): void;
9193

9294
sendDTMF(dtmf: string, duration?: number): void;
95+
96+
getStats(selector?: MediaStreamTrack | null): Promise<RTCStatsReport | null>;
9397
}

packages/media-signaling/src/definition/services/webrtc/IWebRTCProcessor.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ export interface IWebRTCProcessor extends IServiceProcessor<WebRTCInternalStateM
1919

2020
muted: boolean;
2121
held: boolean;
22-
2322
setMuted(muted: boolean): void;
2423
setHeld(held: boolean): void;
2524
stop(): void;
@@ -31,6 +30,11 @@ export interface IWebRTCProcessor extends IServiceProcessor<WebRTCInternalStateM
3130
setRemoteAnswer(params: { sdp: RTCSessionDescriptionInit }): Promise<void>;
3231

3332
getRemoteMediaStream(): MediaStream;
33+
34+
audioLevel: number;
35+
localAudioLevel: number;
36+
37+
getStats(selector?: MediaStreamTrack | null): Promise<RTCStatsReport | null>;
3438
}
3539

3640
export type WebRTCProcessorConfig = {

packages/media-signaling/src/lib/Call.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,14 @@ export class ClientMediaCall implements IClientMediaCall {
157157

158158
private pendingAnswerRequest: ServerMediaSignalRemoteSDP | null;
159159

160+
public get audioLevel(): number {
161+
return this.webrtcProcessor?.audioLevel || 0;
162+
}
163+
164+
public get localAudioLevel(): number {
165+
return this.webrtcProcessor?.localAudioLevel || 0;
166+
}
167+
160168
constructor(
161169
private readonly config: IClientMediaCallConfig,
162170
callId: string,
@@ -641,6 +649,10 @@ export class ClientMediaCall implements IClientMediaCall {
641649
});
642650
}
643651

652+
public async getStats(selector?: MediaStreamTrack | null): Promise<RTCStatsReport | null> {
653+
return this.webrtcProcessor?.getStats(selector) ?? null;
654+
}
655+
644656
private changeState(newState: CallState): void {
645657
if (newState === this._state) {
646658
return;

packages/media-signaling/src/lib/services/webrtc/Processor.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,28 @@ export class MediaCallWebRTCProcessor implements IWebRTCProcessor {
4949

5050
private addedEmptyTransceiver = false;
5151

52+
private _audioLevelTracker: ReturnType<typeof setInterval> | null;
53+
54+
private _audioLevel: number;
55+
56+
public get audioLevel(): number {
57+
return this._audioLevel;
58+
}
59+
60+
private _localAudioLevel: number;
61+
62+
public get localAudioLevel(): number {
63+
return this._localAudioLevel;
64+
}
65+
5266
constructor(private readonly config: WebRTCProcessorConfig) {
5367
this.localMediaStream = new MediaStream();
5468
this.remoteMediaStream = new MediaStream();
5569
this.iceGatheringWaiters = new Set();
5670
this.inputTrack = config.inputTrack;
71+
this._audioLevel = 0;
72+
this._localAudioLevel = 0;
73+
this._audioLevelTracker = null;
5774

5875
this.peer = new RTCPeerConnection(config.rtc);
5976

@@ -62,6 +79,8 @@ export class MediaCallWebRTCProcessor implements IWebRTCProcessor {
6279

6380
this.emitter = new Emitter();
6481
this.registerPeerEvents();
82+
83+
this.registerAudioLevelTracker();
6584
}
6685

6786
public getRemoteMediaStream() {
@@ -138,6 +157,7 @@ export class MediaCallWebRTCProcessor implements IWebRTCProcessor {
138157
// Stop only the remote stream; the track of the local stream may still be in use by another call so it's up to the session to stop it.
139158
this.remoteStream.stopAudio();
140159
this.unregisterPeerEvents();
160+
this.unregisterAudioLevelTracker();
141161

142162
this.peer.close();
143163
}
@@ -214,6 +234,14 @@ export class MediaCallWebRTCProcessor implements IWebRTCProcessor {
214234
}
215235
}
216236

237+
public async getStats(selector?: MediaStreamTrack | null): Promise<RTCStatsReport | null> {
238+
if (this.stopped) {
239+
return null;
240+
}
241+
242+
return this.peer.getStats(selector);
243+
}
244+
217245
private changeInternalState(stateName: keyof WebRTCInternalStateMap): void {
218246
this.config.logger?.debug('MediaCallWebRTCProcessor.changeInternalState', stateName);
219247
this.emitter.emit('internalStateChange', stateName);
@@ -303,6 +331,51 @@ export class MediaCallWebRTCProcessor implements IWebRTCProcessor {
303331
}
304332
}
305333

334+
private registerAudioLevelTracker() {
335+
if (this._audioLevelTracker) {
336+
this.unregisterAudioLevelTracker();
337+
}
338+
339+
this._audioLevelTracker = setInterval(() => {
340+
this.getStats()
341+
.then((stats) => {
342+
if (!stats) {
343+
return;
344+
}
345+
346+
stats.forEach((report) => {
347+
if (report.kind !== 'audio') {
348+
return;
349+
}
350+
351+
switch (report.type) {
352+
case 'inbound-rtp':
353+
this._audioLevel = report.audioLevel ?? 0;
354+
break;
355+
case 'media-source':
356+
this._localAudioLevel = report.audioLevel ?? 0;
357+
break;
358+
}
359+
});
360+
})
361+
.catch(() => {
362+
this._audioLevel = 0;
363+
this._localAudioLevel = 0;
364+
});
365+
}, 50);
366+
}
367+
368+
private unregisterAudioLevelTracker() {
369+
if (!this._audioLevelTracker) {
370+
return;
371+
}
372+
373+
clearInterval(this._audioLevelTracker);
374+
this._audioLevelTracker = null;
375+
this._audioLevel = 0;
376+
this._localAudioLevel = 0;
377+
}
378+
306379
private restartIce() {
307380
this.config.logger?.debug('MediaCallWebRTCProcessor.restartIce');
308381
this.startNewNegotiation();

0 commit comments

Comments
 (0)