import parsers from './index';
import logger from '../../../../logger';
import { TAGS } from '../../../../constants';
import messages from '../../../../messages';
/**
* @typedef videoStats - The Peer connection video streaming statistics.
* @property {JSON} videoStats.sending The Peer connection sending video streaming statistics.
* @property {Number} videoStats.sending.ssrc The Peer connection sending video streaming RTP packets SSRC.
* @property {Number} videoStats.sending.bytes The Peer connection current sending video streaming bytes.
* Note that value is in bytes so you have to convert that to bits for displaying for an example kbps.
* @property {Number} videoStats.sending.totalBytes The Peer connection total sending video streaming bytes.
* Note that value is in bytes so you have to convert that to bits for displaying for an example kbps.
* @property {Number} videoStats.sending.packets The Peer connection current sending video streaming packets.
* @property {Number} videoStats.sending.totalPackets The Peer connection total sending video streaming packets.
* @property {Number} videoStats.sending.roundTripTime The Peer connection sending video streaming Round-trip delay time.
* Defined as <code>0</code> if it's not present in original raw statistics before parsing.
* @property {Number} videoStats.sending.jitter <blockquote class="info">
* This property has been deprecated and would be removed in future releases
* as it should not be in <code>sending</code> property.
* </blockquote> The Peer connection sending video streaming RTP packets jitter in seconds.
* Defined as <code>0</code> if it's not present in original raw statistics before parsing.
* @property {Number} [videoStats.sending.qpSum] - The Peer connection sending video streaming sum of the QP values of frames passed.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.sending.frames] - The Peer connection sending video streaming frames.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.sending.frameWidth] - The Peer connection sending video streaming frame width.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.sending.frameHeight] - The Peer connection sending video streaming frame height.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.sending.hugeFramesSent] - The Peer connection sending video streaming number
* of huge frames sent by this RTP stream. Huge frames, by definition, are frames that have an encoded size at least 2.5 times the average size of the frames.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.sending.framesPerSecond] - The Peer connection sending video streaming fps.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.sending.framesEncoded] - The Peer connection sending video streaming frames encoded.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.sending.nacks] - The Peer connection current sending video streaming nacks.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.sending.totalNacks] - The Peer connection total sending video streaming nacks.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.sending.plis] - The Peer connection current sending video streaming plis.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.sending.totalPlis] - The Peer connection total sending video streaming plis.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.sending.firs] - The Peer connection current sending video streaming firs.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.sending.totalFirs] - The Peer connection total sending video streaming firs.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {JSON} [videoStats.sending.codec] - The Peer connection sending video streaming selected codec information.
* Defined as <code>null</code> if local session description is not available before parsing.
* @property {String} videoStats.sending.codec.name The Peer connection sending video streaming selected codec name.
* @property {Number} videoStats.sending.codec.payloadType The Peer connection sending video streaming selected codec payload type.
* @property {String} [videoStats.sending.codec.implementation] - The Peer connection sending video streaming selected codec implementation.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.sending.codec.channels] - The Peer connection sending video streaming selected codec channels (2 for stereo).
* Defined as <code>null</code> if it's not available in original raw statistics before parsing,
* and this is usually present in <code>statistics.audio</code> property.
* @property {Number} [videoStats.sending.codec.clockRate] - The Peer connection sending video streaming selected codec media sampling rate.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {String} [videoStats.sending.codec.params] - The Peer connection sending video streaming selected codec parameters.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {JSON} videoStats.receiving The Peer connection receiving video streaming statistics.
* @property {Number} videoStats.receiving.ssrc The Peer connection receiving video streaming RTP packets SSRC.
* @property {Number} videoStats.receiving.bytes The Peer connection current receiving video streaming bytes.
* Note that value is in bytes so you have to convert that to bits for displaying for an example kbps.
* @property {Number} videoStats.receiving.totalBytes The Peer connection total receiving video streaming bytes.
* Note that value is in bytes so you have to convert that to bits for displaying for an example kbps.
* @property {Number} videoStats.receiving.packets The Peer connection current receiving video streaming packets.
* @property {Number} videoStats.receiving.totalPackets The Peer connection total receiving video streaming packets.
* @property {Number} videoStats.receiving.packetsLost The Peer connection current receiving video streaming packets lost.
* @property {Number} videoStats.receiving.totalPacketsLost The Peer connection total receiving video streaming packets lost.
* @property {Number} [videoStats.receiving.frames] - The Peer connection receiving video streaming frames.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.receiving.frameWidth] - The Peer connection sending video streaming frame width.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.receiving.frameHeight] - The Peer connection sending video streaming frame height.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.receiving.framesDecoded] - The Peer connection receiving video streaming frames decoded.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.receiving.framesDroped] - The Peer connection receiving video streaming frames dropped.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.receiving.nacks] - The Peer connection current receiving video streaming nacks.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.receiving.totalNacks] - The Peer connection total receiving video streaming nacks.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.receiving.plis] - The Peer connection current receiving video streaming plis.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.receiving.totalPlis] - The Peer connection total receiving video streaming plis.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.receiving.firs] - The Peer connection current receiving video streaming firs.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.receiving.totalFirs] - The Peer connection total receiving video streaming firs.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {JSON} [videoStats.receiving.codec] - The Peer connection receiving video streaming selected codec information.
* Defined as <code>null</code> if remote session description is not available before parsing.
* Note that if the value is polyfilled, the value may not be accurate since the remote Peer can override the selected codec.
* The value is derived from the remote session description.
* @property {String} videoStats.receiving.codec.name The Peer connection receiving video streaming selected codec name.
* @property {Number} videoStats.receiving.codec.payloadType The Peer connection receiving video streaming selected codec payload type.
* @property {String} [videoStats.receiving.codec.implementation] - The Peer connection receiving video streaming selected codec implementation.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {Number} [videoStats.receiving.codec.channels] - The Peer connection receiving video streaming selected codec channels (2 for stereo).
* Defined as <code>null</code> if it's not available in original raw statistics before parsing,
* and this is usually present in <code>statistics.audio</code> property.
* @property {Number} [videoStats.receiving.codec.clockRate] - The Peer connection receiving video streaming selected codec media sampling rate.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
* @property {String} [videoStats.receiving.codec.params] - The Peer connection receiving video streaming selected codec parameters.
* Defined as <code>null</code> if it's not available in original raw statistics before parsing.
*/
const parseReceiving = (output, value, prevStats) => {
const parsedStats = output.video.receiving;
parsedStats.bytes = parsedStats.bytes || 0;
if (value.bytesReceived) {
const bytesReceived = parseInt(value.bytesReceived || '0', 10);
parsedStats.totalBytes = bytesReceived;
parsedStats.bytes += parsers.tabulateStats(prevStats, value, 'bytesReceived');
}
if (value.packetsReceived) {
const packetsReceived = parseInt(value.packetsReceived || '0', 10);
parsedStats.totalPackets = packetsReceived;
parsedStats.packets = parsers.tabulateStats(prevStats, value, 'packetsReceived');
}
if (Number.isInteger(value.packetsLost)) {
const packetsLost = parseInt(value.packetsLost || '0', 10);
parsedStats.totalPacketsLost = packetsLost;
parsedStats.packetsLost = parsers.tabulateStats(prevStats, value, 'packetsLost');
}
if (Number.isInteger(value.firCount)) {
const firsSent = parseInt(value.firCount || '0', 10);
parsedStats.totalFirs = firsSent;
parsedStats.firs = parsers.tabulateStats(prevStats, value, 'firCount');
}
if (Number.isInteger(value.nackCount)) {
const nacksSent = parseInt(value.nackCount || '0', 10);
parsedStats.totalNacks = nacksSent;
parsedStats.nacks = parsers.tabulateStats(prevStats, value, 'nackCount');
}
if (value.pliCount || Number.isInteger(value.pliCount)) {
const plisSent = parseInt(value.pliCount || '0', 10);
parsedStats.totalPlis = plisSent;
parsedStats.plis = parsers.tabulateStats(prevStats, value, 'pliCount');
}
parsedStats.ssrc = value.ssrc;
parsedStats.qpSum = parseInt(value.qpSum || '0', 10);
parsedStats.decoderImplementation = value.decoderImplementation;
const { trackId } = value;
const videoReceiver = output.raw[trackId];
if (videoReceiver) {
parsedStats.framesDropped = parseFloat(videoReceiver.framesDropped || '0');
parsedStats.frames = parseInt(videoReceiver.framesReceived || '0', 10);
parsedStats.framesDecoded = parseInt(videoReceiver.framesDecoded || '0', 10);
parsedStats.frameWidth = parseInt(videoReceiver.frameWidth || '0', 10);
parsedStats.frameHeight = parseInt(videoReceiver.frameHeight || '0', 10);
}
};
const parseSending = (output, value, prevStats) => {
const parsedStats = output.video.sending;
parsedStats.bytes = parsedStats.bytes || 0;
if (value.bytesSent) {
const bytesSent = parseInt(value.bytesSent || '0', 10);
parsedStats.totalBytes = bytesSent;
parsedStats.bytes += parsers.tabulateStats(prevStats, value, 'bytesSent');
}
if (value.packetsSent) {
const packetsSent = parseInt(value.packetsSent || '0', 10);
parsedStats.totalPackets = packetsSent;
parsedStats.packets = parsers.tabulateStats(prevStats, value, 'packetsSent');
}
if (Number.isInteger(value.firCount)) {
const firsReceived = parseInt(value.firCount || '0', 10);
parsedStats.totalFirs = firsReceived;
parsedStats.firs = parsers.tabulateStats(prevStats, value, 'firCount');
}
if (Number.isInteger(value.nackCount)) {
const nacksReceived = parseInt(value.nackCount || '0', 10);
parsedStats.totalNacks = nacksReceived;
parsedStats.nacks = parsers.tabulateStats(prevStats, value, 'nackCount');
}
if (Number.isInteger(value.pliCount)) {
const plisReceived = parseInt(value.pliCount || '0', 10);
parsedStats.totalPlis = plisReceived;
parsedStats.plis = parsers.tabulateStats(prevStats, value, 'pliCount');
}
if (value.jitter) {
parsedStats.jitter = parseInt(value.jitter || '0', 10);
}
if (value.roundTripTime) {
parsedStats.roundTripTime = parseInt(value.roundTripTime || '0', 10);
}
if (Number.isInteger(value.framesEncoded)) {
parsedStats.framesEncoded = parseInt(value.framesEncoded || '0', 10);
}
parsedStats.ssrc = value.ssrc;
parsedStats.qpSum = parseInt(value.qpSum || '0', 10);
const { trackId, mediaSourceId } = value;
const videoSender = output.raw[trackId];
if (videoSender) {
parsedStats.frameWidth = parseInt(videoSender.frameWidth || '0', 10);
parsedStats.frameHeight = parseInt(videoSender.frameHeight || '0', 10);
parsedStats.frames = parseInt(videoSender.framesSent || '0', 10);
parsedStats.hugeFramesSent = parseInt(videoSender.hugeFramesSent || '0', 10);
}
const videoSource = output.raw[mediaSourceId];
if (videoSource) {
parsedStats.framesPerSecond = parseInt(videoSource.framesPerSecond || '0', 10);
}
};
/**
* Function that parses the raw stats from the RTCInboundRtpStreamStats and RTCOutboundRtpStreamStats dictionary.
* @param {SkylinkState} state - The room state.
* @param {Object} output - Stats output object that stores the parsed stats values.
* @param {String} type - Stats dictionary identifier.
* @param {RTCPeerConnection} value - Stats value.
* @param {String} peerId - The peer Id.
* @param {String} direction - The direction of the media flow, i.e. sending or receiving
* @memberOf PeerConnectionStatisticsParsers
*/
const parseVideo = (state, output, type, value, peerId, direction) => {
const { peerStats } = state;
const prevStats = peerStats[peerId][value.id];
switch (direction) {
case 'receiving':
parseReceiving(output, value, prevStats);
break;
case 'sending':
parseSending(output, value, prevStats);
break;
default:
logger.log.DEBUG([peerId, TAGS.STATS_MODULE, null, messages.STATS_MODULE.ERRORS.PARSE_FAILED]);
}
};
export default parseVideo;