@@ -23,6 +23,8 @@ import {
2323} from '../lib/ClientMetrics' ;
2424
2525const 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+
2628export 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