type MediaKind = "audio" | "video" ; interface StatsItem { [ key ] : number ; } export const extractCandidatePairs = ( stats ) => { const candidatePairs = [ ... stats . values ( ) ] . filter ( ( stat ) => stat . type === "candidate-pair" ) ; const selectedPairs = candidatePairs . filter ( ( stat ) => { if ( "selected" in stat ) return stat . selected && stat . nominated ; return stat . nominated ; } ) ; return selectedPairs . map ( ( { localCandidateId , remoteCandidateId } ) => { const localReport = stats . get ( localCandidateId ) ; const remoteReport = stats . get ( remoteCandidateId ) ; if ( ! localReport ) { console . warn ( "localCandidate not found!" ) ; } if ( ! remoteReport ) { console . warn ( "remoteCandidate not found!" ) ; } return { localCandidate : localReport ? { address : localReport . address || localReport . ip , port : localReport . port , protocol : localReport . protocol , type : localReport . candidateType , } : { } , remoteCandidate : remoteReport ? { address : remoteReport . address || remoteReport . ip , port : remoteReport . port , protocol : remoteReport . protocol , type : remoteReport . candidateType , } : { } , } ; } ) ; } ; export const extractOutboundRtps = ( stats ) => { const outboundRtps = [ ... stats . values ( ) ] . filter ( ( stat ) => stat . type === "outbound-rtp" ) ; if ( outboundRtps . length > 2 ) { console . warn ( "outbound-rtp reports are found more than 2!" ) ; } const outbounds = { video : { bytesSent : 0 , packetsSent : 0 , } , audio : { bytesSent : 0 , packetsSent : 0 , } , } ; for ( const stat of outboundRtps ) { const kind = stat . kind || stat . mediaType ; if ( kind !== "audio" && kind !== "video" ) { console . warn ( `unknown outbound rtp kind: ${ kind } found!` ) ; continue ; } outbounds [ kind ] . bytesSent += stat . bytesSent ; outbounds [ kind ] . packetsSent += stat . packetsSent ; } return { audioOutbounds : outbounds . audio , videoOutbounds : outbounds . video , } ; } ; export const extractInboundRtps = ( stats ) => { const inboundRtps = [ ... stats . values ( ) ] . filter ( ( stat ) => stat . type === "inbound-rtp" ) ; const videoInbounds = { size : 0 , bytesReceived : 0 , packetsReceived : 0 , packetsLost : 0 , nackCount : 0 , firCount : 0 , pliCount : 0 , items : [ ] as StatsItem [ ] , } ; const audioInbounds = { size : 0 , bytesReceived : 0 , packetsReceived : 0 , packetsLost : 0 , items : [ ] as StatsItem [ ] , } ; for ( const stat of inboundRtps ) { const item = { bytesReceived : stat . bytesReceived , packetsReceived : stat . packetsReceived , packetsLost : stat . packetsLost , ssrc : stat . ssrc , } ; const kind = stat . kind || stat . mediaType ; if ( kind !== "audio" && kind !== "video" ) { console . warn ( `unknown outbound rtp kind: ${ kind } found!` ) ; continue ; } if ( kind === "video" ) { item . nackCount = stat . nackCount || 0 ; item . firCount = stat . firCount || 0 ; item . pliCount = stat . pliCount || 0 ; videoInbounds . items . push ( item ) ; } if ( kind === "audio" ) { audioInbounds . items . push ( item ) ; } } for ( const item of videoInbounds . items ) { videoInbounds . size += 1 ; videoInbounds . bytesReceived += item . bytesReceived ; videoInbounds . packetsReceived += item . packetsReceived ; videoInbounds . packetsLost += item . packetsLost ; videoInbounds . nackCount += item . nackCount ; videoInbounds . firCount += item . firCount ; videoInbounds . pliCount += item . pliCount ; } for ( const item of audioInbounds . items ) { audioInbounds . size += 1 ; audioInbounds . bytesReceived += item . bytesReceived ; audioInbounds . packetsReceived += item . packetsReceived ; audioInbounds . packetsLost += item . packetsLost ; } return { videoInbounds , audioInbounds , } ; } ;