11import type {
22 AggregatedStatsReport ,
3+ AudioAggregatedStats ,
34 BaseStats ,
45 ParticipantsStatsReport ,
56 RTCCodecStats ,
@@ -158,20 +159,32 @@ export const createStatsReporter = ({
158159 publisher ? getRawStatsForTrack ( 'publisher' ) : undefined ,
159160 ] ) ;
160161
161- const process = ( report : RTCStatsReport , kind : PeerConnectionKind ) =>
162- aggregate ( transform ( report , { kind, trackKind : 'video' , publisher } ) ) ;
162+ const process = ( report : RTCStatsReport , kind : PeerConnectionKind ) => {
163+ const videoStats = aggregate (
164+ transform ( report , { kind, trackKind : 'video' , publisher } ) ,
165+ ) ;
166+ const audioStats = aggregateAudio (
167+ transform ( report , { kind, trackKind : 'audio' , publisher } ) ,
168+ ) ;
169+ return {
170+ videoStats,
171+ audioStats,
172+ } ;
173+ } ;
163174
164- const subscriberStats = subscriberRawStats
175+ const subscriberResult = subscriberRawStats
165176 ? process ( subscriberRawStats , 'subscriber' )
166- : getEmptyStats ( ) ;
167- const publisherStats = publisherRawStats
177+ : { videoStats : getEmptyVideoStats ( ) , audioStats : getEmptyAudioStats ( ) } ;
178+ const publisherResult = publisherRawStats
168179 ? process ( publisherRawStats , 'publisher' )
169- : getEmptyStats ( ) ;
180+ : { videoStats : getEmptyVideoStats ( ) , audioStats : getEmptyAudioStats ( ) } ;
170181
171182 state . setCallStatsReport ( {
172183 datacenter,
173- publisherStats,
174- subscriberStats,
184+ publisherStats : publisherResult . videoStats ,
185+ publisherAudioStats : publisherResult . audioStats ,
186+ subscriberStats : subscriberResult . videoStats ,
187+ subscriberAudioStats : subscriberResult . audioStats ,
175188 subscriberRawStats,
176189 publisherRawStats,
177190 participants : participantStats ,
@@ -266,6 +279,11 @@ const transform = (
266279 }
267280
268281 let trackType : TrackType | undefined ;
282+ let audioLevel : number | undefined ;
283+ let concealedSamples : number | undefined ;
284+ let concealmentEvents : number | undefined ;
285+ let packetsReceived : number | undefined ;
286+ let packetsLost : number | undefined ;
269287 if ( kind === 'publisher' && publisher ) {
270288 const firefox = isFirefox ( ) ;
271289 const mediaSource = stats . find (
@@ -276,7 +294,23 @@ const transform = (
276294 ) as RTCMediaSourceStats | undefined ;
277295 if ( mediaSource ) {
278296 trackType = publisher . getTrackType ( mediaSource . trackIdentifier ) ;
297+ if (
298+ trackKind === 'audio' &&
299+ typeof mediaSource . audioLevel === 'number'
300+ ) {
301+ audioLevel = mediaSource . audioLevel ;
302+ }
303+ }
304+ } else if ( kind === 'subscriber' && trackKind === 'audio' ) {
305+ const inboundStats = rtcStreamStats as RTCInboundRtpStreamStats ;
306+ const inboundLevel = inboundStats . audioLevel ;
307+ if ( typeof inboundLevel === 'number' ) {
308+ audioLevel = inboundLevel ;
279309 }
310+ concealedSamples = inboundStats . concealedSamples ;
311+ concealmentEvents = inboundStats . concealmentEvents ;
312+ packetsReceived = inboundStats . packetsReceived ;
313+ packetsLost = inboundStats . packetsLost ;
280314 }
281315
282316 return {
@@ -294,6 +328,11 @@ const transform = (
294328 rid : rtcStreamStats . rid ,
295329 ssrc : rtcStreamStats . ssrc ,
296330 trackType,
331+ audioLevel,
332+ concealedSamples,
333+ concealmentEvents,
334+ packetsReceived,
335+ packetsLost,
297336 } ;
298337 } ) ;
299338
@@ -304,7 +343,7 @@ const transform = (
304343 } ;
305344} ;
306345
307- const getEmptyStats = ( stats ?: StatsReport ) : AggregatedStatsReport => {
346+ const getEmptyVideoStats = ( stats ?: StatsReport ) : AggregatedStatsReport => {
308347 return {
309348 rawReport : stats ?? { streams : [ ] , timestamp : Date . now ( ) } ,
310349 totalBytesSent : 0 ,
@@ -321,13 +360,29 @@ const getEmptyStats = (stats?: StatsReport): AggregatedStatsReport => {
321360 } ;
322361} ;
323362
363+ const getEmptyAudioStats = ( ) : AudioAggregatedStats => {
364+ return {
365+ totalBytesSent : 0 ,
366+ totalBytesReceived : 0 ,
367+ averageJitterInMs : 0 ,
368+ averageRoundTripTimeInMs : 0 ,
369+ codec : '' ,
370+ codecPerTrackType : { } ,
371+ timestamp : Date . now ( ) ,
372+ totalConcealedSamples : 0 ,
373+ totalConcealmentEvents : 0 ,
374+ totalPacketsReceived : 0 ,
375+ totalPacketsLost : 0 ,
376+ } ;
377+ } ;
378+
324379/**
325380 * Aggregates generic stats.
326381 *
327382 * @param stats the stats to aggregate.
328383 */
329384const aggregate = ( stats : StatsReport ) : AggregatedStatsReport => {
330- const aggregatedStats = getEmptyStats ( stats ) ;
385+ const aggregatedStats = getEmptyVideoStats ( stats ) ;
331386
332387 let maxArea = - 1 ;
333388 const area = ( w : number , h : number ) => w * h ;
@@ -386,3 +441,49 @@ const aggregate = (stats: StatsReport): AggregatedStatsReport => {
386441
387442 return report ;
388443} ;
444+
445+ /**
446+ * Aggregates audio stats from a stats report.
447+ *
448+ * @param stats the stats report containing audio streams.
449+ * @returns aggregated audio stats.
450+ */
451+ const aggregateAudio = ( stats : StatsReport ) : AudioAggregatedStats => {
452+ const streams = stats . streams ;
453+
454+ const audioStats = getEmptyAudioStats ( ) ;
455+
456+ const report = streams . reduce ( ( acc , stream ) => {
457+ acc . totalBytesSent += stream . bytesSent || 0 ;
458+ acc . totalBytesReceived += stream . bytesReceived || 0 ;
459+ acc . averageJitterInMs += stream . jitter || 0 ;
460+ acc . averageRoundTripTimeInMs += stream . currentRoundTripTime || 0 ;
461+ acc . totalConcealedSamples += stream . concealedSamples || 0 ;
462+ acc . totalConcealmentEvents += stream . concealmentEvents || 0 ;
463+ acc . totalPacketsReceived += stream . packetsReceived || 0 ;
464+ acc . totalPacketsLost += stream . packetsLost || 0 ;
465+
466+ return acc ;
467+ } , audioStats ) ;
468+
469+ if ( streams . length > 0 ) {
470+ report . averageJitterInMs = Math . round (
471+ ( report . averageJitterInMs / streams . length ) * 1000 ,
472+ ) ;
473+ report . averageRoundTripTimeInMs = Math . round (
474+ ( report . averageRoundTripTimeInMs / streams . length ) * 1000 ,
475+ ) ;
476+ report . codec = streams [ 0 ] . codec || '' ;
477+ report . codecPerTrackType = streams . reduce (
478+ ( acc , stream ) => {
479+ if ( stream . trackType ) {
480+ acc [ stream . trackType ] = stream . codec || '' ;
481+ }
482+ return acc ;
483+ } ,
484+ { } as Record < TrackType , string > ,
485+ ) ;
486+ }
487+
488+ return report ;
489+ } ;
0 commit comments