Skip to content

Commit 1b190d6

Browse files
authored
feat: send inbound-rtp metrics via DataChannel to pion (#156)
1 parent a93c6d1 commit 1b190d6

File tree

1 file changed

+51
-0
lines changed

1 file changed

+51
-0
lines changed

src/modules/StreamingClient.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import {
2323
} from '../lib/ClientMetrics';
2424

2525
const SUCCESS_METRIC_POLLING_TIMEOUT_MS = 15000; // After this time we will stop polling for the first frame and consider the session a failure.
26+
const STATS_COLLECTION_INTERVAL_MS = 5000;
27+
2628
export class StreamingClient {
2729
private publicEventEmitter: PublicEventEmitter;
2830
private internalEventEmitter: InternalEventEmitter;
@@ -44,6 +46,7 @@ export class StreamingClient {
4446
private successMetricFired = false;
4547
private showPeerConnectionStatsReport: boolean = false;
4648
private peerConnectionStatsReportOutputFormat: 'console' | 'json' = 'console';
49+
private statsCollectionInterval: ReturnType<typeof setInterval> | null = null;
4750

4851
constructor(
4952
sessionId: string,
@@ -116,6 +119,47 @@ export class StreamingClient {
116119
});
117120
}
118121

122+
private startStatsCollection() {
123+
if (this.statsCollectionInterval) {
124+
return;
125+
}
126+
127+
// Send stats every STATS_COLLECTION_INTERVAL_MS seconds
128+
this.statsCollectionInterval = setInterval(async () => {
129+
if (
130+
!this.peerConnection ||
131+
!this.dataChannel ||
132+
this.dataChannel.readyState !== 'open'
133+
) {
134+
return;
135+
}
136+
137+
try {
138+
const stats = await this.peerConnection.getStats();
139+
this.sendClientSideMetrics(stats);
140+
} catch (error) {
141+
console.error('Failed to collect and send stats:', error);
142+
}
143+
}, STATS_COLLECTION_INTERVAL_MS);
144+
}
145+
146+
private sendClientSideMetrics(stats: RTCStatsReport) {
147+
stats.forEach((report: RTCStats) => {
148+
// Process inbound-rtp stats for both video and audio
149+
if (report.type === 'inbound-rtp') {
150+
const metrics = {
151+
message_type: 'remote_rtp_stats',
152+
data: report,
153+
};
154+
155+
// Send the metrics via data channel
156+
if (this.dataChannel && this.dataChannel.readyState === 'open') {
157+
this.dataChannel.send(JSON.stringify(metrics));
158+
}
159+
}
160+
});
161+
}
162+
119163
private startSuccessMetricPolling() {
120164
if (this.successMetricPoller || this.successMetricFired) {
121165
return;
@@ -418,6 +462,8 @@ export class StreamingClient {
418462
this.peerConnection?.iceConnectionState === 'completed'
419463
) {
420464
this.publicEventEmitter.emit(AnamEvent.CONNECTION_ESTABLISHED);
465+
// Start collecting stats every 5 seconds
466+
this.startStatsCollection();
421467
}
422468
}
423469

@@ -610,6 +656,11 @@ export class StreamingClient {
610656
}
611657
}
612658
}
659+
// stop stats collection
660+
if (this.statsCollectionInterval) {
661+
clearInterval(this.statsCollectionInterval);
662+
this.statsCollectionInterval = null;
663+
}
613664
// reset video frame polling
614665
if (this.successMetricPoller) {
615666
clearInterval(this.successMetricPoller);

0 commit comments

Comments
 (0)