summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webrtc/RTCStats-helper.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--testing/web-platform/tests/webrtc/RTCStats-helper.js1076
1 files changed, 1076 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webrtc/RTCStats-helper.js b/testing/web-platform/tests/webrtc/RTCStats-helper.js
new file mode 100644
index 0000000000..e504550c0c
--- /dev/null
+++ b/testing/web-platform/tests/webrtc/RTCStats-helper.js
@@ -0,0 +1,1076 @@
+'use strict';
+
+// Test is based on the following editor draft:
+// webrtc-pc 20171130
+// webrtc-stats 20171122
+
+// This file depends on dictionary-helper.js which should
+// be loaded from the main HTML file.
+
+/*
+ [webrtc-stats]
+ 6.1. RTCStatsType enum
+ enum RTCStatsType {
+ "codec",
+ "inbound-rtp",
+ "outbound-rtp",
+ "remote-inbound-rtp",
+ "remote-outbound-rtp",
+ "csrc",
+ "peer-connection",
+ "data-channel",
+ "stream",
+ "track",
+ "transport",
+ "candidate-pair",
+ "local-candidate",
+ "remote-candidate",
+ "certificate",
+ "ice-server"
+ };
+ */
+const statsValidatorTable = {
+ 'codec': validateCodecStats,
+ 'inbound-rtp': validateInboundRtpStreamStats,
+ 'outbound-rtp': validateOutboundRtpStreamStats,
+ 'remote-inbound-rtp': validateRemoteInboundRtpStreamStats,
+ 'remote-outbound-rtp': validateRemoteOutboundRtpStreamStats,
+ 'media-source': validateMediaSourceStats,
+ 'csrc': validateContributingSourceStats,
+ 'peer-connection': validatePeerConnectionStats,
+ 'data-channel': validateDataChannelStats,
+ 'transceiver': validateTransceiverStats,
+ 'sender': validateSenderStats,
+ 'receiver': validateReceiverStats,
+ 'transport': validateTransportStats,
+ 'candidate-pair': validateIceCandidatePairStats,
+ 'local-candidate': validateIceCandidateStats,
+ 'remote-candidate': validateIceCandidateStats,
+ 'certificate': validateCertificateStats,
+ 'ice-server': validateIceServerStats
+};
+
+// Validate that the stats objects in a stats report
+// follows the respective definitions.
+// Stats objects with unknown type are ignored and
+// only basic validation is done.
+function validateStatsReport(statsReport) {
+ for(const [id, stats] of statsReport.entries()) {
+ assert_equals(stats.id, id,
+ 'expect stats.id to be the same as the key in statsReport');
+
+ const validator = statsValidatorTable[stats.type];
+ if(validator) {
+ validator(statsReport, stats);
+ } else {
+ validateRtcStats(statsReport, stats);
+ }
+ }
+}
+
+// Assert that the stats report have stats objects of
+// given types
+function assert_stats_report_has_stats(statsReport, statsTypes) {
+ const hasTypes = new Set([...statsReport.values()]
+ .map(stats => stats.type));
+
+ for(const type of statsTypes) {
+ assert_true(hasTypes.has(type),
+ `Expect statsReport to contain stats object of type ${type}`);
+ }
+}
+
+function findStatsFromReport(statsReport, predicate, message) {
+ for (const stats of statsReport.values()) {
+ if (predicate(stats)) {
+ return stats;
+ }
+ }
+
+ assert_unreached(message || 'none of stats in statsReport satisfy given condition')
+}
+
+// Get stats object of type that is expected to be
+// found in the statsReport
+function getRequiredStats(statsReport, type) {
+ for(const stats of statsReport.values()) {
+ if(stats.type === type) {
+ return stats;
+ }
+ }
+
+ assert_unreached(`required stats of type ${type} is not found in stats report`);
+}
+
+// Get stats object by the stats ID.
+// This is used to retreive other stats objects
+// linked to a stats object
+function getStatsById(statsReport, statsId) {
+ assert_true(statsReport.has(statsId),
+ `Expect stats report to have stats object with id ${statsId}`);
+
+ return statsReport.get(statsId);
+}
+
+// Validate an ID field in a stats object by making sure
+// that the linked stats object is found in the stats report
+// and have the type field value same as expected type
+// It doesn't validate the other fields of the linked stats
+// as validateStatsReport already does all validations
+function validateIdField(statsReport, stats, field, type) {
+ assert_string_field(stats, field);
+ const linkedStats = getStatsById(statsReport, stats[field]);
+ assert_equals(linkedStats.type, type,
+ `Expect linked stats object to have type ${type}`);
+}
+
+function validateOptionalIdField(statsReport, stats, field, type) {
+ if(stats[field] !== undefined) {
+ validateIdField(statsReport, stats, field, type);
+ }
+}
+
+/*
+ [webrtc-pc]
+ 8.4. RTCStats Dictionary
+ dictionary RTCStats {
+ required DOMHighResTimeStamp timestamp;
+ required RTCStatsType type;
+ required DOMString id;
+ };
+ */
+function validateRtcStats(statsReport, stats) {
+ assert_number_field(stats, 'timestamp');
+ assert_string_field(stats, 'type');
+ assert_string_field(stats, 'id');
+}
+
+/*
+ [webrtc-stats]
+ 7.1. RTCRtpStreamStats dictionary
+ dictionary RTCRtpStreamStats : RTCStats {
+ unsigned long ssrc;
+ DOMString kind;
+ DOMString transportId;
+ DOMString codecId;
+ };
+
+ kind of type DOMString
+ Either "audio" or "video".
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCRtpStreamStats, with attributes ssrc, kind, transportId, codecId
+ */
+function validateRtpStreamStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ assert_unsigned_int_field(stats, 'ssrc');
+ assert_string_field(stats, 'kind');
+ assert_enum_field(stats, 'kind', ['audio', 'video'])
+
+ validateIdField(statsReport, stats, 'transportId', 'transport');
+ validateIdField(statsReport, stats, 'codecId', 'codec');
+
+}
+
+/*
+ [webrtc-stats]
+ 7.2. RTCCodecStats dictionary
+ dictionary RTCCodecStats : RTCStats {
+ required unsigned long payloadType;
+ RTCCodecType codecType;
+ required DOMString transportId;
+ required DOMString mimeType;
+ unsigned long clockRate;
+ unsigned long channels;
+ DOMString sdpFmtpLine;
+ };
+
+ enum RTCCodecType {
+ "encode",
+ "decode",
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCCodecStats, with attributes payloadType, codecType, mimeType, clockRate, channels, sdpFmtpLine
+ */
+
+function validateCodecStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ assert_unsigned_int_field(stats, 'payloadType');
+ assert_optional_enum_field(stats, 'codecType', ['encode', 'decode']);
+
+ validateOptionalIdField(statsReport, stats, 'transportId', 'transport');
+
+ assert_string_field(stats, 'mimeType');
+ assert_unsigned_int_field(stats, 'clockRate');
+ if (stats.kind === 'audio') {
+ assert_unsigned_int_field(stats, 'channels');
+ }
+ assert_string_field(stats, 'sdpFmtpLine');
+}
+
+/*
+ [webrtc-stats]
+ 7.3. RTCReceivedRtpStreamStats dictionary
+ dictionary RTCReceivedRtpStreamStats : RTCRtpStreamStats {
+ unsigned long long packetsReceived;
+ long long packetsLost;
+ double jitter;
+ unsigned long long packetsDiscarded;
+ unsigned long long packetsRepaired;
+ unsigned long long burstPacketsLost;
+ unsigned long long burstPacketsDiscarded;
+ unsigned long burstLossCount;
+ unsigned long burstDiscardCount;
+ double burstLossRate;
+ double burstDiscardRate;
+ double gapLossRate;
+ double gapDiscardRate;
+ unsigned long framesDropped;
+ unsigned long partialFramesLost;
+ unsigned long fullFramesLost;
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCReceivedRtpStreamStats, with all required attributes from its
+ inherited dictionaries, and also attributes packetsReceived,
+ packetsLost, jitter, packetsDiscarded, framesDropped
+ */
+function validateReceivedRtpStreamStats(statsReport, stats) {
+ validateRtpStreamStats(statsReport, stats);
+
+ assert_unsigned_int_field(stats, 'packetsReceived');
+ assert_unsigned_int_field(stats, 'packetsLost');
+
+ assert_number_field(stats, 'jitter');
+
+ assert_unsigned_int_field(stats, 'packetsDiscarded');
+ assert_unsigned_int_field(stats, 'framesDropped');
+
+ assert_optional_unsigned_int_field(stats, 'packetsRepaired');
+ assert_optional_unsigned_int_field(stats, 'burstPacketsLost');
+ assert_optional_unsigned_int_field(stats, 'burstPacketsDiscarded');
+ assert_optional_unsigned_int_field(stats, 'burstLossCount');
+ assert_optional_unsigned_int_field(stats, 'burstDiscardCount');
+
+ assert_optional_number_field(stats, 'burstLossRate');
+ assert_optional_number_field(stats, 'burstDiscardRate');
+ assert_optional_number_field(stats, 'gapLossRate');
+ assert_optional_number_field(stats, 'gapDiscardRate');
+
+ assert_optional_unsigned_int_field(stats, 'partialFramesLost');
+ assert_optional_unsigned_int_field(stats, 'fullFramesLost');
+}
+
+/*
+ [webrtc-stats]
+ 7.4. RTCInboundRtpStreamStats dictionary
+ dictionary RTCInboundRtpStreamStats : RTCReceivedRtpStreamStats {
+ DOMString trackId;
+ DOMString receiverId;
+ DOMString remoteId;
+ unsigned long framesDecoded;
+ unsigned long keyFramesDecoded;
+ unsigned long frameWidth;
+ unsigned long frameHeight;
+ unsigned long frameBitDepth;
+ double framesPerSecond;
+ unsigned long long qpSum;
+ double totalDecodeTime;
+ double totalInterFrameDelay;
+ double totalSquaredInterFrameDelay;
+ boolean voiceActivityFlag;
+ DOMHighResTimeStamp lastPacketReceivedTimestamp;
+ double averageRtcpInterval;
+ unsigned long long headerBytesReceived;
+ unsigned long long fecPacketsReceived;
+ unsigned long long fecPacketsDiscarded;
+ unsigned long long bytesReceived;
+ unsigned long long packetsFailedDecryption;
+ unsigned long long packetsDuplicated;
+ record<USVString, unsigned long long> perDscpPacketsReceived;
+ unsigned long nackCount;
+ unsigned long firCount;
+ unsigned long pliCount;
+ unsigned long sliCount;
+ DOMHighResTimeStamp estimatedPlayoutTimestamp;
+ double jitterBufferDelay;
+ unsigned long long jitterBufferEmittedCount;
+ unsigned long long totalSamplesReceived;
+ unsigned long long samplesDecodedWithSilk;
+ unsigned long long samplesDecodedWithCelt;
+ unsigned long long concealedSamples;
+ unsigned long long silentConcealedSamples;
+ unsigned long long concealmentEvents;
+ unsigned long long insertedSamplesForDeceleration;
+ unsigned long long removedSamplesForAcceleration;
+ double audioLevel;
+ double totalAudioEnergy;
+ double totalSamplesDuration;
+ unsigned long framesReceived;
+ DOMString decoderImplementation;
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCInboundRtpStreamStats, with all required attributes from its inherited
+ dictionaries, and also attributes receiverId, remoteId, framesDecoded, nackCount, framesReceived, bytesReceived, totalAudioEnergy, totalSampleDuration
+ */
+function validateInboundRtpStreamStats(statsReport, stats) {
+ validateReceivedRtpStreamStats(statsReport, stats);
+ validateOptionalIdField(statsReport, stats, 'trackId', 'track');
+ validateIdField(statsReport, stats, 'receiverId', 'receiver');
+ validateIdField(statsReport, stats, 'remoteId', 'remote-outbound-rtp');
+ assert_unsigned_int_field(stats, 'framesDecoded');
+ assert_optional_unsigned_int_field(stats, 'keyFramesDecoded');
+ assert_optional_unsigned_int_field(stats, 'frameWidth');
+ assert_optional_unsigned_int_field(stats, 'frameHeight');
+ assert_optional_unsigned_int_field(stats, 'frameBitDepth');
+ assert_optional_number_field(stats, 'framesPerSecond');
+ assert_optional_unsigned_int_field(stats, 'qpSum');
+ assert_optional_number_field(stats, 'totalDecodeTime');
+ assert_optional_number_field(stats, 'totalInterFrameDelay');
+ assert_optional_number_field(stats, 'totalSquaredInterFrameDelay');
+
+ assert_optional_boolean_field(stats, 'voiceActivityFlag');
+
+ assert_optional_number_field(stats, 'lastPacketReceivedTimeStamp');
+ assert_optional_number_field(stats, 'averageRtcpInterval');
+
+ assert_optional_unsigned_int_field(stats, 'fecPacketsReceived');
+ assert_optional_unsigned_int_field(stats, 'fecPacketsDiscarded');
+ assert_unsigned_int_field(stats, 'bytesReceived');
+ assert_optional_unsigned_int_field(stats, 'packetsFailedDecryption');
+ assert_optional_unsigned_int_field(stats, 'packetsDuplicated');
+
+ assert_optional_dict_field(stats, 'perDscpPacketsReceived');
+ if (stats['perDscpPacketsReceived']) {
+ Object.keys(stats['perDscpPacketsReceived'])
+ .forEach(k =>
+ assert_equals(typeof k, 'string', 'Expect keys of perDscpPacketsReceived to be strings')
+ );
+ Object.values(stats['perDscpPacketsReceived'])
+ .forEach(v =>
+ assert_true(Number.isInteger(v) && (v >= 0), 'Expect values of perDscpPacketsReceived to be strings')
+ );
+ }
+
+ assert_unsigned_int_field(stats, 'nackCount');
+
+ assert_optional_unsigned_int_field(stats, 'firCount');
+ assert_optional_unsigned_int_field(stats, 'pliCount');
+ assert_optional_unsigned_int_field(stats, 'sliCount');
+
+ assert_optional_number_field(stats, 'estimatedPlayoutTimestamp');
+ assert_optional_number_field(stats, 'jitterBufferDelay');
+ assert_optional_unsigned_int_field(stats, 'jitterBufferEmittedCount');
+ assert_optional_unsigned_int_field(stats, 'totalSamplesReceived');
+ assert_optional_unsigned_int_field(stats, 'samplesDecodedWithSilk');
+ assert_optional_unsigned_int_field(stats, 'samplesDecodedWithCelt');
+ assert_optional_unsigned_int_field(stats, 'concealedSamples');
+ assert_optional_unsigned_int_field(stats, 'silentConcealedSamples');
+ assert_optional_unsigned_int_field(stats, 'concealmentEvents');
+ assert_optional_unsigned_int_field(stats, 'insertedSamplesForDeceleration');
+ assert_optional_unsigned_int_field(stats, 'removedSamplesForAcceleration');
+ assert_optional_number_field(stats, 'audioLevel');
+ assert_optional_number_field(stats, 'totalAudioEnergy');
+ assert_optional_number_field(stats, 'totalSamplesDuration');
+ assert_unsigned_int_field(stats, 'framesReceived');
+ assert_optional_string_field(stats, 'decoderImplementation');
+ assert_optional_boolean_field(stats, 'powerEfficientDecoder');
+}
+
+/*
+ [webrtc-stats]
+ 7.5. RTCRemoteInboundRtpStreamStats dictionary
+ dictionary RTCRemoteInboundRtpStreamStats : RTCReceivedRtpStreamStats {
+ DOMString localId;
+ double roundTripTime;
+ double totalRoundTripTime;
+ double fractionLost;
+ unsigned long long reportsReceived;
+ unsigned long long roundTripTimeMeasurements;
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCRemoteInboundRtpStreamStats, with all required attributes from its
+ inherited dictionaries, and also attributes localId, roundTripTime
+ */
+function validateRemoteInboundRtpStreamStats(statsReport, stats) {
+ validateReceivedRtpStreamStats(statsReport, stats);
+
+ validateIdField(statsReport, stats, 'localId', 'outbound-rtp');
+ assert_number_field(stats, 'roundTripTime');
+ assert_optional_number_field(stats, 'totalRoundTripTime');
+ assert_optional_number_field(stats, 'fractionLost');
+ assert_optional_unsigned_int_field(stats, 'reportsReceived');
+ assert_optional_unsigned_int_field(stats, 'roundTripTimeMeasurements');
+}
+
+/*
+ [webrtc-stats]
+ 7.6. RTCSentRtpStreamStats dictionary
+ dictionary RTCSentRtpStreamStats : RTCRtpStreamStats {
+ unsigned long packetsSent;
+ unsigned long long bytesSent;
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCSentRtpStreamStats, with all required attributes from its inherited
+ dictionaries, and also attributes packetsSent, bytesSent
+ */
+function validateSentRtpStreamStats(statsReport, stats) {
+ validateRtpStreamStats(statsReport, stats);
+
+ assert_unsigned_int_field(stats, 'packetsSent');
+ assert_unsigned_int_field(stats, 'bytesSent');
+}
+
+/*
+ [webrtc-stats]
+ 7.7. RTCOutboundRtpStreamStats dictionary
+ dictionary RTCOutboundRtpStreamStats : RTCSentRtpStreamStats {
+ DOMString mediaSourceId;
+ DOMString senderId;
+ DOMString remoteId;
+ DOMString rid;
+ DOMHighResTimeStamp lastPacketSentTimestamp;
+ unsigned long long headerBytesSent;
+ unsigned long packetsDiscardedOnSend;
+ unsigned long long bytesDiscardedOnSend;
+ unsigned long fecPacketsSent;
+ unsigned long long retransmittedPacketsSent;
+ unsigned long long retransmittedBytesSent;
+ double targetBitrate;
+ unsigned long long totalEncodedBytesTarget;
+ unsigned long frameWidth;
+ unsigned long frameHeight;
+ unsigned long frameBitDepth;
+ double framesPerSecond;
+ unsigned long framesSent;
+ unsigned long hugeFramesSent;
+ unsigned long framesEncoded;
+ unsigned long keyFramesEncoded;
+ unsigned long framesDiscardedOnSend;
+ unsigned long long qpSum;
+ unsigned long long totalSamplesSent;
+ unsigned long long samplesEncodedWithSilk;
+ unsigned long long samplesEncodedWithCelt;
+ boolean voiceActivityFlag;
+ double totalEncodeTime;
+ double totalPacketSendDelay;
+ double averageRtcpInterval;
+ RTCQualityLimitationReason qualityLimitationReason;
+ record<DOMString, double> qualityLimitationDurations;
+ unsigned long qualityLimitationResolutionChanges;
+ record<USVString, unsigned long long> perDscpPacketsSent;
+ unsigned long nackCount;
+ unsigned long firCount;
+ unsigned long pliCount;
+ unsigned long sliCount;
+ DOMString encoderImplementation;
+ };
+ Obsolete members:
+ partial dictionary RTCOutboundStreamStats {
+ DOMString trackId;
+ };
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCOutboundRtpStreamStats, with all required attributes from its
+ inherited dictionaries, and also attributes senderId, remoteId, framesEncoded, nackCount, framesSent
+ */
+function validateOutboundRtpStreamStats(statsReport, stats) {
+ validateSentRtpStreamStats(statsReport, stats)
+
+ validateOptionalIdField(statsReport, stats, 'mediaSourceId', 'media-source');
+ validateIdField(statsReport, stats, 'senderId', 'sender');
+ validateIdField(statsReport, stats, 'remoteId', 'remote-inbound-rtp');
+
+ assert_optional_string_field(stats, 'rid');
+
+ assert_optional_number_field(stats, 'lastPacketSentTimestamp');
+ assert_optional_unsigned_int_field(stats, 'headerBytesSent');
+ assert_optional_unsigned_int_field(stats, 'packetsDiscardedOnSend');
+ assert_optional_unsigned_int_field(stats, 'bytesDiscardedOnSend');
+ assert_optional_unsigned_int_field(stats, 'fecPacketsSent');
+ assert_optional_unsigned_int_field(stats, 'retransmittedPacketsSent');
+ assert_optional_unsigned_int_field(stats, 'retransmittedBytesSent');
+ assert_optional_number_field(stats, 'targetBitrate');
+ assert_optional_unsigned_int_field(stats, 'totalEncodedBytesTarget');
+ if (stats['kind'] === 'video') {
+ assert_optional_unsigned_int_field(stats, 'frameWidth');
+ assert_optional_unsigned_int_field(stats, 'frameHeight');
+ assert_optional_unsigned_int_field(stats, 'frameBitDepth');
+ assert_optional_number_field(stats, 'framesPerSecond');
+ assert_unsigned_int_field(stats, 'framesSent');
+ assert_optional_unsigned_int_field(stats, 'hugeFramesSent');
+ assert_unsigned_int_field(stats, 'framesEncoded');
+ assert_optional_unsigned_int_field(stats, 'keyFramesEncoded');
+ assert_optional_unsigned_int_field(stats, 'framesDiscardedOnSend');
+ assert_optional_unsigned_int_field(stats, 'qpSum');
+ } else if (stats['kind'] === 'audio') {
+ assert_optional_unsigned_int_field(stats, 'totalSamplesSent');
+ assert_optional_unsigned_int_field(stats, 'samplesEncodedWithSilk');
+ assert_optional_unsigned_int_field(stats, 'samplesEncodedWithCelt');
+ assert_optional_boolean_field(stats, 'voiceActivityFlag');
+ }
+ assert_optional_number_field(stats, 'totalEncodeTime');
+ assert_optional_number_field(stats, 'totalPacketSendDelay');
+ assert_optional_number_field(stats, 'averageRTCPInterval');
+
+ if (stats['kind'] === 'video') {
+ assert_optional_enum_field(stats, 'qualityLimitationReason', ['none', 'cpu', 'bandwidth', 'other']);
+
+ assert_optional_dict_field(stats, 'qualityLimitationDurations');
+ if (stats['qualityLimitationDurations']) {
+ Object.keys(stats['qualityLimitationDurations'])
+ .forEach(k =>
+ assert_equals(typeof k, 'string', 'Expect keys of qualityLimitationDurations to be strings')
+ );
+ Object.values(stats['qualityLimitationDurations'])
+ .forEach(v =>
+ assert_equals(typeof num, 'number', 'Expect values of qualityLimitationDurations to be numbers')
+ );
+ }
+
+ assert_optional_unsigned_int_field(stats, 'qualityLimitationResolutionChanges');
+ }
+ assert_unsigned_int_field(stats, 'nackCount');
+ assert_optional_dict_field(stats, 'perDscpPacketsSent');
+ if (stats['perDscpPacketsSent']) {
+ Object.keys(stats['perDscpPacketsSent'])
+ .forEach(k =>
+ assert_equals(typeof k, 'string', 'Expect keys of perDscpPacketsSent to be strings')
+ );
+ Object.values(stats['perDscpPacketsSent'])
+ .forEach(v =>
+ assert_true(Number.isInteger(v) && (v >= 0), 'Expect values of perDscpPacketsSent to be strings')
+ );
+ }
+
+ assert_optional_unsigned_int_field(stats, 'firCount');
+ assert_optional_unsigned_int_field(stats, 'pliCount');
+ assert_optional_unsigned_int_field(stats, 'sliCount');
+ assert_optional_string_field(stats, 'encoderImplementation');
+ assert_optional_boolean_field(stats, 'powerEfficientEncoder');
+ assert_optional_string_field(stats, 'scalabilityMode');
+ // Obsolete stats
+ validateOptionalIdField(statsReport, stats, 'trackId', 'track');
+}
+
+/*
+ [webrtc-stats]
+ 7.8. RTCRemoteOutboundRtpStreamStats dictionary
+ dictionary RTCRemoteOutboundRtpStreamStats : RTCSentRtpStreamStats {
+ DOMString localId;
+ DOMHighResTimeStamp remoteTimestamp;
+ unsigned long long reportsSent;
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCRemoteOutboundRtpStreamStats, with all required attributes from its
+ inherited dictionaries, and also attributes localId, remoteTimestamp
+ */
+function validateRemoteOutboundRtpStreamStats(statsReport, stats) {
+ validateSentRtpStreamStats(statsReport, stats);
+
+ validateIdField(statsReport, stats, 'localId', 'inbound-rtp');
+ assert_number_field(stats, 'remoteTimeStamp');
+ assert_optional_unsigned_int_field(stats, 'reportsSent');
+}
+
+/*
+ [webrtc-stats]
+ 7.11 RTCMediaSourceStats dictionary
+ dictionary RTCMediaSourceStats : RTCStats {
+ DOMString trackIdentifier;
+ DOMString kind;
+ };
+
+ dictionary RTCAudioSourceStats : RTCMediaSourceStats {
+ double audioLevel;
+ double totalAudioEnergy;
+ double totalSamplesDuration;
+ double echoReturnLoss;
+ double echoReturnLossEnhancement;
+ };
+
+ dictionary RTCVideoSourceStats : RTCMediaSourceStats {
+ unsigned long width;
+ unsigned long height;
+ unsigned long bitDepth;
+ unsigned long frames;
+ // see https://github.com/w3c/webrtc-stats/issues/540
+ double framesPerSecond;
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ RTCMediaSourceStats with attributes trackIdentifier, kind
+ RTCAudioSourceStats, with all required attributes from its inherited dictionaries and totalAudioEnergy, totalSamplesDuration
+ RTCVideoSourceStats, with all required attributes from its inherited dictionaries and width, height, framesPerSecond
+*/
+function validateMediaSourceStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+ assert_string_field(stats, 'trackIdentifier');
+ assert_enum_field(stats, 'kind', ['audio', 'video']);
+
+ if (stats.kind === 'audio') {
+ assert_optional_number_field(stats, 'audioLevel');
+ assert_number_field(stats, 'totalAudioEnergy');
+ assert_number_field(stats, 'totalSamplesDuration');
+ assert_optional_number_field(stats, 'echoReturnLoss');
+ assert_optional_number_field(stats, 'echoReturnLossEnhancement');
+ } else if (stats.kind === 'video') {
+ assert_unsigned_int_field(stats, 'width');
+ assert_unsigned_int_field(stats, 'height');
+ assert_optional_unsigned_int_field(stats, 'bitDpeth');
+ assert_optional_unsigned_int_field(stats, 'frames');
+ assert_number_field(stats, 'framesPerSecond');
+ }
+}
+
+/*
+ [webrtc-stats]
+ 7.9. RTCRTPContributingSourceStats
+ dictionary RTCRTPContributingSourceStats : RTCStats {
+ unsigned long contributorSsrc;
+ DOMString inboundRtpStreamId;
+ unsigned long packetsContributedTo;
+ double audioLevel;
+ };
+ */
+function validateContributingSourceStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ assert_optional_unsigned_int_field(stats, 'contributorSsrc');
+
+ validateOptionalIdField(statsReport, stats, 'inboundRtpStreamId', 'inbound-rtp');
+ assert_optional_unsigned_int_field(stats, 'packetsContributedTo');
+ assert_optional_number_field(stats, 'audioLevel');
+}
+
+/*
+ [webrtc-stats]
+ 7.10. RTCPeerConnectionStats dictionary
+ dictionary RTCPeerConnectionStats : RTCStats {
+ unsigned long dataChannelsOpened;
+ unsigned long dataChannelsClosed;
+ unsigned long dataChannelsRequested;
+ unsigned long dataChannelsAccepted;
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCPeerConnectionStats, with attributes dataChannelsOpened, dataChannelsClosed
+ */
+function validatePeerConnectionStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ assert_unsigned_int_field(stats, 'dataChannelsOpened');
+ assert_unsigned_int_field(stats, 'dataChannelsClosed');
+ assert_optional_unsigned_int_field(stats, 'dataChannelsRequested');
+ assert_optional_unsigned_int_field(stats, 'dataChannelsAccepted');
+}
+
+/* [webrtc-stats]
+ 7.16 RTCRtpTransceiverStats dictionary
+ dictionary RTCRtpTransceiverStats {
+ DOMString senderId;
+ DOMString receiverId;
+ DOMString mid;
+ };
+*/
+function validateTransceiverStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+ validateOptionalIdField(statsReport, stats, 'senderId', 'sender');
+ validateOptionalIdField(statsReport, stats, 'receiverId', 'sender');
+ assert_optional_string_field(stats, 'mid');
+}
+
+/*
+ [webrtc-stats]
+ dictionary RTCMediaHandlerStats : RTCStats {
+ DOMString trackIdentifier;
+ boolean remoteSource;
+ boolean ended;
+ DOMString kind;
+ RTCPriorityType priority;
+ };
+ dictionary RTCVideoHandlerStats : RTCMediaHandlerStats {
+ };
+ dictionary RTCAudioHandlerStats : RTCMediaHandlerStats {
+ };
+ Used from validateSenderStats and validateReceiverStats
+
+ [webrtc-priority]
+ enum RTCPriorityType {
+ "very-low",
+ "low",
+ "medium",
+ "high"
+ };
+
+ [webrtc-pc]
+ MTI:
+ RTCMediaHandlerStats with attributes trackIdentifier
+ RTCAudioHandlerStats, with all required attributes from its inherited dictionaries
+ RTCVideoHandlerStats, with all required attributes from its inherited dictionaries
+
+*/
+function validateMediaHandlerStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+ assert_string_field(stats, 'trackIdentifier');
+ assert_optional_boolean_field(stats, 'remoteSource');
+ assert_optional_boolean_field(stats, 'ended');
+ assert_optional_string_field(stats, 'kind');
+ assert_enum_field(stats, 'priority', ['very-low', 'low', 'medium', 'high']);
+}
+
+/*
+ [webrtc-stats]
+ dictionary RTCAudioSenderStats : RTCAudioHandlerStats {
+ DOMString mediaSourceId;
+ };
+ dictionary RTCVideoSenderStats : RTCVideoHandlerStats {
+ DOMString mediaSourceId;
+ };
+
+ [webrtc-pc]
+ MTI:
+ RTCVideoSenderStats, with all required attributes from its inherited dictionaries
+*/
+function validateSenderStats(statsReport, stats) {
+ validateMediaHandlerStats(statsReport, stats);
+ validateOptionalIdField(statsReport, stats, 'mediaSourceId', 'media-source');
+}
+
+/*
+ [webrtc-stats]
+ dictionary RTCAudioReceiverStats : RTCAudioHandlerStats {
+ };
+ dictionary RTCVideoReceiverStats : RTCVideoHandlerStats {
+ };
+
+ [webrtc-pc]
+ MTI:
+ RTCVideoReceiverStats, with all required attributes from its inherited dictionaries
+*/
+function validateReceiverStats(statsReport, stats) {
+ validateMediaHandlerStats(statsReport, stats);
+}
+
+
+/*
+ [webrtc-stats]
+ 7.13. RTCDataChannelStats dictionary
+ dictionary RTCDataChannelStats : RTCStats {
+ DOMString label;
+ DOMString protocol;
+ // see https://github.com/w3c/webrtc-stats/issues/541
+ unsigned short dataChannelIdentifier;
+ DOMString transportId;
+ RTCDataChannelState state;
+ unsigned long messagesSent;
+ unsigned long long bytesSent;
+ unsigned long messagesReceived;
+ unsigned long long bytesReceived;
+ };
+
+ [webrtc-pc]
+ 6.2. RTCDataChannel
+ enum RTCDataChannelState {
+ "connecting",
+ "open",
+ "closing",
+ "closed"
+ };
+
+ 8.6. Mandatory To Implement Stats
+ - RTCDataChannelStats, with attributes label, protocol, datachannelIdentifier, state,
+ messagesSent, bytesSent, messagesReceived, bytesReceived
+ */
+function validateDataChannelStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ assert_string_field(stats, 'label');
+ assert_string_field(stats, 'protocol');
+ assert_unsigned_int_field(stats, 'dataChannelIdentifier');
+
+ validateOptionalIdField(statsReport, stats, 'transportId', 'transport');
+
+ assert_enum_field(stats, 'state',
+ ['connecting', 'open', 'closing', 'closed']);
+
+ assert_unsigned_int_field(stats, 'messagesSent');
+ assert_unsigned_int_field(stats, 'bytesSent');
+ assert_unsigned_int_field(stats, 'messagesReceived');
+ assert_unsigned_int_field(stats, 'bytesReceived');
+}
+
+/*
+ [webrtc-stats]
+ 7.14. RTCTransportStats dictionary
+ dictionary RTCTransportStats : RTCStats {
+ unsigned long long packetsSent;
+ unsigned long long packetsReceived;
+ unsigned long long bytesSent;
+ unsigned long long bytesReceived;
+ DOMString rtcpTransportStatsId;
+ RTCIceRole iceRole;
+ RTCDtlsTransportState dtlsState;
+ DOMString selectedCandidatePairId;
+ DOMString localCertificateId;
+ DOMString remoteCertificateId;
+ DOMString tlsVersion;
+ DOMString dtlsCipher;
+ DOMString srtpCipher;
+ DOMString tlsGroup;
+ unsigned long selectedCandidatePairChanges;
+ };
+
+ [webrtc-pc]
+ 5.5. RTCDtlsTransportState Enum
+ enum RTCDtlsTransportState {
+ "new",
+ "connecting",
+ "connected",
+ "closed",
+ "failed"
+ };
+
+ 5.6. RTCIceRole Enum
+ enum RTCIceRole {
+ "unknown",
+ "controlling",
+ "controlled"
+ };
+
+ 8.6. Mandatory To Implement Stats
+ - RTCTransportStats, with attributes bytesSent, bytesReceived,
+ selectedCandidatePairId, localCertificateId,
+ remoteCertificateId
+ */
+function validateTransportStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ assert_optional_unsigned_int_field(stats, 'packetsSent');
+ assert_optional_unsigned_int_field(stats, 'packetsReceived');
+ assert_unsigned_int_field(stats, 'bytesSent');
+ assert_unsigned_int_field(stats, 'bytesReceived');
+
+ validateOptionalIdField(statsReport, stats, 'rtcpTransportStatsId',
+ 'transport');
+
+ assert_optional_enum_field(stats, 'iceRole',
+ ['unknown', 'controlling', 'controlled']);
+
+ assert_optional_enum_field(stats, 'dtlsState',
+ ['new', 'connecting', 'connected', 'closed', 'failed']);
+
+ validateIdField(statsReport, stats, 'selectedCandidatePairId', 'candidate-pair');
+ validateIdField(statsReport, stats, 'localCertificateId', 'certificate');
+ validateIdField(statsReport, stats, 'remoteCertificateId', 'certificate');
+ assert_optional_string_field(stats, 'tlsVersion');
+ assert_optional_string_field(stats, 'dtlsCipher');
+ assert_optional_string_field(stats, 'srtpCipher');
+ assert_optional_string_field(stats, 'tlsGroup');
+ assert_optional_unsigned_int_field(stats, 'selectedCandidatePairChanges');
+}
+
+/*
+ [webrtc-stats]
+ 7.15. RTCIceCandidateStats dictionary
+ dictionary RTCIceCandidateStats : RTCStats {
+ required DOMString transportId;
+ DOMString? address;
+ long port;
+ DOMString protocol;
+ RTCIceCandidateType candidateType;
+ long priority;
+ DOMString url;
+ DOMString relayProtocol;
+ };
+
+ [webrtc-pc]
+ 4.8.1.3. RTCIceCandidateType Enum
+ enum RTCIceCandidateType {
+ "host",
+ "srflx",
+ "prflx",
+ "relay"
+ };
+
+ 8.6. Mandatory To Implement Stats
+ - RTCIceCandidateStats, with attributes address, port, protocol, candidateType, url
+ */
+function validateIceCandidateStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ validateIdField(statsReport, stats, 'transportId', 'transport');
+ // The address is mandatory to implement, but is allowed to be null
+ // when hidden for privacy reasons.
+ if (stats.address != null) {
+ // Departure from strict spec reading:
+ // This field is populated in a racy manner in Chrome.
+ // We allow it to be present or not present for the time being.
+ // TODO(https://bugs.chromium.org/1092721): Become consistent.
+ assert_optional_string_field(stats, 'address');
+ }
+ assert_unsigned_int_field(stats, 'port');
+ assert_string_field(stats, 'protocol');
+
+ assert_enum_field(stats, 'candidateType',
+ ['host', 'srflx', 'prflx', 'relay']);
+
+ assert_optional_int_field(stats, 'priority');
+ // The url field is mandatory for local candidates gathered from
+ // a STUN or TURN server, and MUST NOT be present otherwise.
+ // TODO(hta): Improve checking.
+ assert_optional_string_field(stats, 'url');
+ assert_optional_string_field(stats, 'relayProtocol');
+}
+
+/*
+ [webrtc-stats]
+ 7.16. RTCIceCandidatePairStats dictionary
+ dictionary RTCIceCandidatePairStats : RTCStats {
+ DOMString transportId;
+ DOMString localCandidateId;
+ DOMString remoteCandidateId;
+ RTCStatsIceCandidatePairState state;
+ boolean nominated;
+ unsigned long packetsSent;
+ unsigned long packetsReceived;
+ unsigned long long bytesSent;
+ unsigned long long bytesReceived;
+ DOMHighResTimeStamp lastPacketSentTimestamp;
+ DOMHighResTimeStamp lastPacketReceivedTimestamp;
+ DOMHighResTimeStamp firstRequestTimestamp;
+ DOMHighResTimeStamp lastRequestTimestamp;
+ DOMHighResTimeStamp lastResponseTimestamp;
+ double totalRoundTripTime;
+ double currentRoundTripTime;
+ double availableOutgoingBitrate;
+ double availableIncomingBitrate;
+ unsigned long circuitBreakerTriggerCount;
+ unsigned long long requestsReceived;
+ unsigned long long requestsSent;
+ unsigned long long responsesReceived;
+ unsigned long long responsesSent;
+ unsigned long long retransmissionsReceived;
+ unsigned long long retransmissionsSent;
+ unsigned long long consentRequestsSent;
+ DOMHighResTimeStamp consentExpiredTimestamp;
+ unsigned long packetsDiscardedOnSend;
+ unsigned long long bytesDiscardedOnSend; };
+
+ enum RTCStatsIceCandidatePairState {
+ "frozen",
+ "waiting",
+ "in-progress",
+ "failed",
+ "succeeded"
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCIceCandidatePairStats, with attributes transportId, localCandidateId,
+ remoteCandidateId, state, nominated, bytesSent, bytesReceived, totalRoundTripTime, currentRoundTripTime
+ // not including priority per https://github.com/w3c/webrtc-pc/issues/2457
+ */
+function validateIceCandidatePairStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ validateIdField(statsReport, stats, 'transportId', 'transport');
+ validateIdField(statsReport, stats, 'localCandidateId', 'local-candidate');
+ validateIdField(statsReport, stats, 'remoteCandidateId', 'remote-candidate');
+
+ assert_enum_field(stats, 'state',
+ ['frozen', 'waiting', 'in-progress', 'failed', 'succeeded']);
+
+ assert_boolean_field(stats, 'nominated');
+ assert_optional_unsigned_int_field(stats, 'packetsSent');
+ assert_optional_unsigned_int_field(stats, 'packetsReceived');
+ assert_unsigned_int_field(stats, 'bytesSent');
+ assert_unsigned_int_field(stats, 'bytesReceived');
+
+ assert_optional_number_field(stats, 'lastPacketSentTimestamp');
+ assert_optional_number_field(stats, 'lastPacketReceivedTimestamp');
+ assert_optional_number_field(stats, 'firstRequestTimestamp');
+ assert_optional_number_field(stats, 'lastRequestTimestamp');
+ assert_optional_number_field(stats, 'lastResponseTimestamp');
+
+ assert_number_field(stats, 'totalRoundTripTime');
+ assert_number_field(stats, 'currentRoundTripTime');
+
+ assert_optional_number_field(stats, 'availableOutgoingBitrate');
+ assert_optional_number_field(stats, 'availableIncomingBitrate');
+
+ assert_optional_unsigned_int_field(stats, 'circuitBreakerTriggerCount');
+ assert_optional_unsigned_int_field(stats, 'requestsReceived');
+ assert_optional_unsigned_int_field(stats, 'requestsSent');
+ assert_optional_unsigned_int_field(stats, 'responsesReceived');
+ assert_optional_unsigned_int_field(stats, 'responsesSent');
+ assert_optional_unsigned_int_field(stats, 'retransmissionsReceived');
+ assert_optional_unsigned_int_field(stats, 'retransmissionsSent');
+ assert_optional_unsigned_int_field(stats, 'consentRequestsSent');
+ assert_optional_number_field(stats, 'consentExpiredTimestamp');
+ assert_optional_unsigned_int_field(stats, 'packetsDiscardedOnSend');
+ assert_optional_unsigned_int_field(stats, 'bytesDiscardedOnSend');
+}
+
+/*
+ [webrtc-stats]
+ 7.17. RTCCertificateStats dictionary
+ dictionary RTCCertificateStats : RTCStats {
+ DOMString fingerprint;
+ DOMString fingerprintAlgorithm;
+ DOMString base64Certificate;
+ DOMString issuerCertificateId;
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCCertificateStats, with attributes fingerprint, fingerprintAlgorithm,
+ base64Certificate, issuerCertificateId
+ */
+function validateCertificateStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ assert_string_field(stats, 'fingerprint');
+ assert_string_field(stats, 'fingerprintAlgorithm');
+ assert_string_field(stats, 'base64Certificate');
+ assert_optional_string_field(stats, 'issuerCertificateId');
+}
+
+/*
+ [webrtc-stats]
+ 7.30. RTCIceServerStats dictionary
+ dictionary RTCIceServerStats : RTCStats {
+ DOMString url;
+ long port;
+ DOMString protocol;
+ unsigned long totalRequestsSent;
+ unsigned long totalResponsesReceived;
+ double totalRoundTripTime;
+ };
+*/
+function validateIceServerStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ assert_optional_string_field(stats, 'url');
+ assert_optional_int_field(stats, 'port');
+ assert_optional_string_field(stats, 'protocol');
+ assert_optional_unsigned_int_field(stats, 'totalRequestsSent');
+ assert_optional_unsigned_int_field(stats, 'totalResponsesReceived');
+ assert_optional_number_field(stats, 'totalRoundTripTime');
+}