UNPKG

infobip-rtc

Version:

Infobip RTC JavaScript SDK - Infobip WebRTC API Implementation

202 lines 10.1 kB
import { CallStats } from "../CallStats"; import { AudioRemoteMediaStats } from "./audio/AudioRemoteMediaStats"; import { VideoRemoteMediaStats } from "./video/VideoRemoteMediaStats"; import { VideoLocalMediaStats } from "./video/VideoLocalMediaStats"; import { SelectedCandidatePair } from "../transport/SelectedCandidatePair"; import { IceCandidate } from "../transport/IceCandidate"; import { AudioLocalMediaStats } from "./audio/AudioLocalMediaStats"; import { ExtractedStats } from "./ExtractedStats"; export class MediaStatsAdapter { static extract(rtcStatsReport, isVideo) { let callStats = new CallStats(isVideo); let selectedCandidatePair = null; const extractedRemoteStats = new Map(); const extractedLocalStats = new Map(); rtcStatsReport.forEach((statsReport) => { if (statsReport.type === "transport" && statsReport.dtlsState === "connected") { selectedCandidatePair = rtcStatsReport.get(statsReport.selectedCandidatePairId); } else if (statsReport.type === "inbound-rtp") { const inboundRtp = statsReport; const stats = MediaStatsAdapter.extractInboundRTPStats(inboundRtp); MediaStatsAdapter.populateCodec(inboundRtp, rtcStatsReport, stats); extractedRemoteStats.set(statsReport.id, stats); } else if (statsReport.type === "outbound-rtp") { const outboundRtp = statsReport; const stats = MediaStatsAdapter.extractOutboundRTPStats(outboundRtp); MediaStatsAdapter.populateCodec(outboundRtp, rtcStatsReport, stats); extractedLocalStats.set(stats.id, stats); } else if (statsReport.type === "remote-inbound-rtp") { MediaStatsAdapter.extractRTTIfMissing(callStats, statsReport); } }); if (!selectedCandidatePair) { selectedCandidatePair = MediaStatsAdapter.getSelectedCandidatePair(rtcStatsReport); } if (selectedCandidatePair) { MediaStatsAdapter.extractTransportMetrics(callStats, selectedCandidatePair); } return new ExtractedStats(callStats, extractedRemoteStats, extractedLocalStats); } static populateCodec(statsReport, rtcStatsReport, stats) { const codecId = statsReport.codecId; const codecStatsReport = !codecId ? MediaStatsAdapter.extractCodecStatsReport(rtcStatsReport) : rtcStatsReport.get(codecId); if (!codecStatsReport) { return; } if (stats.video) { stats.codec = MediaStatsAdapter.extractVideoCodec(codecStatsReport); } else { stats.codec = MediaStatsAdapter.extractAudioCodec(codecStatsReport); } } static extractSelectedCandidatePair(rtcStatsReport) { let selectedCandidatePair = null; rtcStatsReport.forEach((statsReport) => { if (statsReport.type === "transport" && statsReport.selectedCandidatePairId) { selectedCandidatePair = rtcStatsReport.get(statsReport.selectedCandidatePairId); } }); if (!selectedCandidatePair) { selectedCandidatePair = MediaStatsAdapter.getSelectedCandidatePair(rtcStatsReport); } if (!selectedCandidatePair) { return null; } let localCandidate = rtcStatsReport.get(selectedCandidatePair.localCandidateId); let remoteCandidate = rtcStatsReport.get(selectedCandidatePair.remoteCandidateId); let local = new IceCandidate(localCandidate); let remote = new IceCandidate(remoteCandidate); return new SelectedCandidatePair(local, remote); } static getSelectedCandidatePair(stats) { let selectedCandidatePair = null; stats.forEach((statsReport) => { if (statsReport.type === 'candidate-pair' && statsReport.selected) { selectedCandidatePair = statsReport; } }); return selectedCandidatePair; } static extractInboundRTPStats(statsReport) { let stats; if (statsReport.kind === "audio") { stats = MediaStatsAdapter.extractAudioRemoteMediaStats(statsReport); MediaStatsAdapter.extractCommonRemoteMediaStats(stats, statsReport); } else { stats = MediaStatsAdapter.extractVideoRemoteMediaStats(statsReport); MediaStatsAdapter.extractCommonRemoteMediaStats(stats, statsReport); } return stats; } static extractOutboundRTPStats(statsReport) { let stats; if (statsReport.kind === "audio") { stats = new AudioLocalMediaStats(statsReport.id); MediaStatsAdapter.extractCommonLocalMediaStats(stats, statsReport); } else { stats = MediaStatsAdapter.extractVideoLocalMediaStats(statsReport); MediaStatsAdapter.extractCommonLocalMediaStats(stats, statsReport); } return stats; } static extractCommonRemoteMediaStats(remoteMediaStats, statsReport) { remoteMediaStats.packetsReceived = statsReport.packetsReceived; remoteMediaStats.packetsLost = statsReport.packetsLost; remoteMediaStats.bytesReceived = statsReport.bytesReceived; MediaStatsAdapter.extractAverageJitterBufferDelay(remoteMediaStats, statsReport); } static extractCommonLocalMediaStats(localMediaStats, statsReport) { localMediaStats.bytesSent = statsReport.bytesSent; localMediaStats.packetsSent = statsReport.packetsSent; localMediaStats.retransmittedBytesSent = statsReport.retransmittedBytesSent; localMediaStats.retransmittedPacketsSent = statsReport.retransmittedPacketsSent; } static extractAudioRemoteMediaStats(statsReport) { const audioRemoteMediaStats = new AudioRemoteMediaStats(statsReport.id); audioRemoteMediaStats.jitter = statsReport.jitter * 1000; audioRemoteMediaStats.concealedSamples = statsReport.concealedSamples; audioRemoteMediaStats.concealmentEvents = statsReport.concealmentEvents; return audioRemoteMediaStats; } static extractVideoRemoteMediaStats(statsReport) { const videoRemoteMediaStats = new VideoRemoteMediaStats(statsReport.id); videoRemoteMediaStats.frameWidth = statsReport.frameWidth; videoRemoteMediaStats.frameHeight = statsReport.frameHeight; videoRemoteMediaStats.framesReceived = statsReport.framesReceived; videoRemoteMediaStats.framesDropped = statsReport.framesDropped; videoRemoteMediaStats.framesDecoded = statsReport.framesDecoded; videoRemoteMediaStats.keyFramesDecoded = statsReport.keyFramesDecoded; videoRemoteMediaStats.nackCount = statsReport.nackCount; videoRemoteMediaStats.firCount = statsReport.firCount; videoRemoteMediaStats.pliCount = statsReport.pliCount; videoRemoteMediaStats.qpSum = statsReport.qpSum; if (videoRemoteMediaStats.framesDecoded > 0) { videoRemoteMediaStats.averageQP = Math.round(videoRemoteMediaStats.qpSum / videoRemoteMediaStats.framesDecoded); } return videoRemoteMediaStats; } static extractVideoLocalMediaStats(statsReport) { const videoLocalMediaStats = new VideoLocalMediaStats(statsReport.id); videoLocalMediaStats.frameWidth = statsReport.frameWidth; videoLocalMediaStats.frameHeight = statsReport.frameHeight; videoLocalMediaStats.framesSent = statsReport.framesSent; videoLocalMediaStats.framesEncoded = statsReport.framesEncoded; videoLocalMediaStats.keyFramesEncoded = statsReport.keyFramesEncoded; videoLocalMediaStats.nackCount = statsReport.nackCount; videoLocalMediaStats.firCount = statsReport.firCount; videoLocalMediaStats.pliCount = statsReport.pliCount; videoLocalMediaStats.qpSum = statsReport.qpSum; if (videoLocalMediaStats.framesEncoded > 0) { videoLocalMediaStats.averageQP = Math.round(videoLocalMediaStats.qpSum / videoLocalMediaStats.framesEncoded); } videoLocalMediaStats.qualityLimitationReason = statsReport.qualityLimitationReason; return videoLocalMediaStats; } static extractAverageJitterBufferDelay(remoteMediaStats, statsReport) { remoteMediaStats.jitterBufferDelay = statsReport.jitterBufferDelay; remoteMediaStats.jitterBufferEmittedCount = statsReport.jitterBufferEmittedCount; if (remoteMediaStats.jitterBufferEmittedCount > 0) { remoteMediaStats.averageJitterBufferDelay = Math.round(remoteMediaStats.jitterBufferDelay / remoteMediaStats.jitterBufferEmittedCount); } return remoteMediaStats; } static extractTransportMetrics(callStats, statsReport) { callStats.bytesReceived = statsReport.bytesReceived; callStats.bytesSent = statsReport.bytesSent; callStats.availableOutgoingBitrate = statsReport.availableOutgoingBitrate; if (statsReport.currentRoundTripTime) { callStats.currentRoundTripTime = statsReport.currentRoundTripTime * 1000; } } static extractRTTIfMissing(callStats, statsReport) { if (!callStats.currentRoundTripTime) { callStats.currentRoundTripTime = statsReport.roundTripTime * 1000; } } static extractCodecStatsReport(rtcStatsReport) { return Array.from(rtcStatsReport.values()).find((statsReport) => { return statsReport.type === "codec"; }); } static extractAudioCodec(codecStatsReport) { let codec = codecStatsReport.mimeType; if (codec) { return codec.toLowerCase().replace("audio/", ""); } return null; } static extractVideoCodec(codecStatsReport) { let codec = codecStatsReport.mimeType; if (codec) { return codec.toLowerCase().replace("video/", ""); } return null; } } //# sourceMappingURL=MediaStatsAdapter.js.map