diff options
Diffstat (limited to 'testing/web-platform/tests/webrtc/RTCStats-helper.js')
-rw-r--r-- | testing/web-platform/tests/webrtc/RTCStats-helper.js | 1076 |
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'); +} |