PageRenderTime 66ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/chrome/test/data/webrtc/peerconnection_getstats.js

http://github.com/chromium/chromium
JavaScript | 753 lines | 479 code | 47 blank | 227 comment | 44 complexity | 891e804ade0df0600e91776fe0aa06df MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, BSD-2-Clause, LGPL-2.1, MPL-2.0, 0BSD, EPL-1.0, MPL-2.0-no-copyleft-exception, GPL-2.0, BitTorrent-1.0, CPL-1.0, LGPL-3.0, Unlicense, BSD-3-Clause, CC0-1.0, JSON, MIT, GPL-3.0, CC-BY-SA-3.0, AGPL-1.0
  1. /**
  2. * Copyright 2016 The Chromium Authors. All rights reserved.
  3. * Use of this source code is governed by a BSD-style license that can be
  4. * found in the LICENSE file.
  5. */
  6. /**
  7. * Constructs an RTCStats dictionary by merging the parent RTCStats object with
  8. * the dictionary of RTCStats members defined for this dictionary.
  9. */
  10. function RTCStats(parent, membersObject) {
  11. if (parent != null)
  12. Object.assign(this, parent);
  13. Object.assign(this, membersObject);
  14. }
  15. const Presence = {
  16. MANDATORY: true,
  17. OPTIONAL: false,
  18. };
  19. /**
  20. * According to spec, multiple stats dictionaries can have the same
  21. * "RTCStats.type". For example, "track" refers to any of
  22. * RTCSenderVideoTrackAttachmentStats, RTCSenderAudioTrackAttachmentStats,
  23. * RTCReceiverVideoTrackAttachmentStats and
  24. * RTCReceiverAudioTrackAttachmentStats. Inspection is needed to determine which
  25. * dictionary applies to the object; for simplicity, this class merges all of
  26. * the associated dictionaries into a single dictionary.
  27. */
  28. class MergedRTCStats {
  29. constructor(presence, type, stats) {
  30. this.presence_ = presence;
  31. this.type_ = type;
  32. this.stats_ = stats;
  33. }
  34. presence() {
  35. return this.presence_;
  36. }
  37. type() {
  38. return this.type_;
  39. }
  40. stats() {
  41. return this.stats_;
  42. }
  43. merge(presence, stats) {
  44. if (presence)
  45. this.presence_ = true;
  46. Object.assign(this.stats_, stats);
  47. }
  48. }
  49. /**
  50. * Maps "RTCStats.type" values to MergedRTCStats. These are descriptions of
  51. * whitelisted (allowed to be exposed to the web) RTCStats-derived dictionaries,
  52. * see RTCStats definitions below.
  53. * @private
  54. */
  55. const gStatsWhitelist = new Map();
  56. function addRTCStatsToWhitelist(presence, type, stats) {
  57. mergedStats = gStatsWhitelist.get(type);
  58. if (!mergedStats) {
  59. gStatsWhitelist.set(type, new MergedRTCStats(presence, type, stats));
  60. } else {
  61. mergedStats.merge(presence, stats);
  62. }
  63. }
  64. /**
  65. * RTCRtpStreamStats
  66. * https://w3c.github.io/webrtc-stats/#streamstats-dict*
  67. * @private
  68. */
  69. let kRTCRtpStreamStats = new RTCStats(null, {
  70. ssrc: 'number',
  71. isRemote: 'boolean', // Obsolete, type reveals if "remote-" or not.
  72. kind: 'string',
  73. mediaType: 'string', // Obsolete, replaced by |kind|.
  74. transportId: 'string',
  75. codecId: 'string',
  76. });
  77. /**
  78. * RTCReceivedRtpStreamStats
  79. * https://w3c.github.io/webrtc-stats/#dom-rtcreceivedrtpstreamstats
  80. * @private
  81. */
  82. let kRTCReceivedRtpStreamStats = new RTCStats(kRTCRtpStreamStats, {
  83. packetsReceived: 'number',
  84. packetsLost: 'number',
  85. jitter: 'number',
  86. packetsDiscarded: 'number',
  87. packetsRepaired: 'number',
  88. burstPacketsLost: 'number',
  89. burstPacketsDiscarded: 'number',
  90. burstLossCount: 'number',
  91. burstDiscardCount: 'number',
  92. burstLossRate: 'number',
  93. burstDiscardRate: 'number',
  94. gapLossRate: 'number',
  95. gapDiscardRate: 'number',
  96. });
  97. /*
  98. * RTCInboundRTPStreamStats
  99. * https://w3c.github.io/webrtc-stats/#inboundrtpstats-dict*
  100. * @private
  101. */
  102. let kRTCInboundRtpStreamStats = new RTCStats(kRTCReceivedRtpStreamStats, {
  103. trackId: 'string',
  104. receiverId: 'string',
  105. remoteId: 'string',
  106. framesDecoded: 'number',
  107. keyFramesDecoded: 'number',
  108. frameBitDepth: 'number',
  109. qpSum: 'number',
  110. totalDecodeTime: 'number',
  111. totalInterFrameDelay: 'number',
  112. totalSquaredInterFrameDelay: 'number',
  113. lastPacketReceivedTimestamp: 'number',
  114. averageRtcpInterval: 'number',
  115. fecPacketsReceived: 'number',
  116. fecPacketsDiscarded: 'number',
  117. bytesReceived: 'number',
  118. headerBytesReceived: 'number',
  119. packetsFailedDecryption: 'number',
  120. packetsDuplicated: 'number',
  121. perDscpPacketsReceived: 'object',
  122. nackCount: 'number',
  123. firCount: 'number',
  124. pliCount: 'number',
  125. sliCount: 'number',
  126. estimatedPlayoutTimestamp: 'number',
  127. fractionLost: 'number', // Obsolete, moved to RTCRemoteInboundRtpStreamStats.
  128. decoderImplementation: 'string',
  129. });
  130. addRTCStatsToWhitelist(
  131. Presence.MANDATORY, 'inbound-rtp', kRTCInboundRtpStreamStats);
  132. /*
  133. * RTCRemoteInboundRtpStreamStats
  134. * https://w3c.github.io/webrtc-stats/#remoteinboundrtpstats-dict*
  135. * @private
  136. */
  137. let kRTCRemoteInboundRtpStreamStats =
  138. new RTCStats(kRTCReceivedRtpStreamStats, {
  139. localId: 'string',
  140. roundTripTime: 'number',
  141. fractionLost: 'number',
  142. });
  143. // TODO(https://crbug.com/967382): Update the browser_tests to wait for the
  144. // existence of remote-inbound-rtp as well (these are created later than
  145. // outbound-rtp). When this is done, change presence to MANDATORY.
  146. addRTCStatsToWhitelist(
  147. Presence.OPTIONAL, 'remote-inbound-rtp', kRTCRemoteInboundRtpStreamStats);
  148. /**
  149. * RTCSentRtpStreamStats
  150. * https://w3c.github.io/webrtc-stats/#dom-rtcsentrtpstreamstats
  151. * @private
  152. */
  153. let kRTCSentRtpStreamStats = new RTCStats(kRTCRtpStreamStats, {
  154. packetsSent: 'number',
  155. packetsDiscardedOnSend: 'number',
  156. fecPacketsSent: 'number',
  157. bytesSent: 'number',
  158. bytesDiscardedOnSend: 'number',
  159. });
  160. /*
  161. * RTCOutboundRtpStreamStats
  162. * https://w3c.github.io/webrtc-stats/#outboundrtpstats-dict*
  163. * @private
  164. */
  165. let kRTCOutboundRtpStreamStats = new RTCStats(kRTCSentRtpStreamStats, {
  166. trackId: 'string',
  167. mediaSourceId: 'string',
  168. senderId: 'string',
  169. remoteId: 'string',
  170. lastPacketSentTimestamp: 'number',
  171. retransmittedPacketsSent: 'number',
  172. retransmittedBytesSent: 'number',
  173. headerBytesSent: 'number',
  174. targetBitrate: 'number',
  175. totalEncodedBytesTarget: 'number',
  176. frameBitDepth: 'number',
  177. framesEncoded: 'number',
  178. keyFramesEncoded: 'number',
  179. qpSum: 'number',
  180. totalEncodeTime: 'number',
  181. totalPacketSendDelay: 'number',
  182. averageRtcpInterval: 'number',
  183. qualityLimitationReason: 'string',
  184. qualityLimitationDurations: 'object',
  185. qualityLimitationResolutionChanges: 'number',
  186. perDscpPacketsSent: 'object',
  187. nackCount: 'number',
  188. firCount: 'number',
  189. pliCount: 'number',
  190. sliCount: 'number',
  191. encoderImplementation: 'string',
  192. rid: 'string',
  193. frameWidth: 'number',
  194. frameHeight: 'number',
  195. framesPerSecond: 'number',
  196. framesSent: 'number',
  197. hugeFramesSent: 'number',
  198. });
  199. addRTCStatsToWhitelist(
  200. Presence.MANDATORY, 'outbound-rtp', kRTCOutboundRtpStreamStats);
  201. /*
  202. * RTCRemoteOutboundRtpStreamStats
  203. * https://w3c.github.io/webrtc-stats/#dom-rtcremoteoutboundrtpstreamstats
  204. * @private
  205. */
  206. let kRTCRemoteOutboundRtpStreamStats = new RTCStats(kRTCSentRtpStreamStats, {
  207. localId: 'string',
  208. remoteTimestamp: 'number',
  209. });
  210. // TODO(hbos): When remote-outbound-rtp is implemented, make presence MANDATORY.
  211. addRTCStatsToWhitelist(
  212. Presence.OPTIONAL, 'remote-outbound-rtp', kRTCRemoteOutboundRtpStreamStats);
  213. /**
  214. * RTCMediaSourceStats
  215. * https://w3c.github.io/webrtc-stats/#dom-rtcmediasourcestats
  216. * @private
  217. */
  218. const kRTCMediaSourceStats = new RTCStats(null, {
  219. trackIdentifier: 'string',
  220. kind: 'string',
  221. });
  222. /**
  223. * RTCAudioSourceStats
  224. * https://w3c.github.io/webrtc-stats/#dom-rtcaudiosourcestats
  225. * @private
  226. */
  227. const kRTCAudioSourceStats = new RTCStats(kRTCMediaSourceStats, {
  228. audioLevel: 'number',
  229. totalAudioEnergy: 'number',
  230. totalSamplesDuration: 'number',
  231. });
  232. addRTCStatsToWhitelist(
  233. Presence.MANDATORY, 'media-source', kRTCAudioSourceStats);
  234. /**
  235. * RTCVideoSourceStats
  236. * https://w3c.github.io/webrtc-stats/#dom-rtcvideosourcestats
  237. * @private
  238. */
  239. const kRTCVideoSourceStats = new RTCStats(kRTCMediaSourceStats, {
  240. width: 'number',
  241. height: 'number',
  242. bitDepth: 'number',
  243. frames: 'number',
  244. framesPerSecond: 'number',
  245. });
  246. addRTCStatsToWhitelist(
  247. Presence.MANDATORY, 'media-source', kRTCVideoSourceStats);
  248. /*
  249. * RTCRtpContributingSourceStats
  250. * https://w3c.github.io/webrtc-stats/#dom-rtcrtpcontributingsourcestats
  251. * @private
  252. */
  253. let kRTCRtpContributingSourceStats = new RTCStats(null, {
  254. contributorSsrc: 'number',
  255. inboundRtpStreamId: 'string',
  256. packetsContributedTo: 'number',
  257. audioLevel: 'number',
  258. });
  259. // TODO(hbos): When csrc is implemented, make presence MANDATORY.
  260. addRTCStatsToWhitelist(
  261. Presence.OPTIONAL, 'csrc', kRTCRtpContributingSourceStats);
  262. /*
  263. * RTCCodecStats
  264. * https://w3c.github.io/webrtc-stats/#codec-dict*
  265. * @private
  266. */
  267. let kRTCCodecStats = new RTCStats(null, {
  268. payloadType: 'number',
  269. mimeType: 'string',
  270. // TODO(hbos): As soon as |codec| has been renamed |mimeType| in the webrtc
  271. // repo, remove this line. https://bugs.webrtc.org/7061
  272. codec: 'string',
  273. clockRate: 'number',
  274. channels: 'number',
  275. sdpFmtpLine: 'string',
  276. implementation: 'string',
  277. });
  278. addRTCStatsToWhitelist(Presence.MANDATORY, 'codec', kRTCCodecStats);
  279. /*
  280. * RTCPeerConnectionStats
  281. * https://w3c.github.io/webrtc-stats/#pcstats-dict*
  282. * @private
  283. */
  284. let kRTCPeerConnectionStats = new RTCStats(null, {
  285. dataChannelsOpened: 'number',
  286. dataChannelsClosed: 'number',
  287. dataChannelsRequested: 'number',
  288. dataChannelsAccepted: 'number',
  289. });
  290. addRTCStatsToWhitelist(
  291. Presence.MANDATORY, 'peer-connection', kRTCPeerConnectionStats);
  292. /*
  293. * RTCMediaStreamStats
  294. * https://w3c.github.io/webrtc-stats/#msstats-dict*
  295. * @private
  296. */
  297. let kRTCMediaStreamStats = new RTCStats(null, {
  298. streamIdentifier: 'string',
  299. trackIds: 'sequence_string',
  300. });
  301. addRTCStatsToWhitelist(Presence.MANDATORY, 'stream', kRTCMediaStreamStats);
  302. /**
  303. * RTCMediaHandlerStats
  304. * https://w3c.github.io/webrtc-stats/#mststats-dict*
  305. * @private
  306. */
  307. let kRTCMediaHandlerStats = new RTCStats(null, {
  308. trackIdentifier: 'string',
  309. remoteSource: 'boolean',
  310. ended: 'boolean',
  311. kind: 'string',
  312. priority: 'string',
  313. detached: 'boolean', // Obsolete, detached stats should fire "onstatsended".
  314. });
  315. /*
  316. * RTCVideoHandlerStats
  317. * https://w3c.github.io/webrtc-stats/#dom-rtcvideohandlerstats
  318. * @private
  319. */
  320. let kRTCVideoHandlerStats = new RTCStats(kRTCMediaHandlerStats, {
  321. frameWidth: 'number',
  322. frameHeight: 'number',
  323. framesPerSecond: 'number',
  324. });
  325. /*
  326. * RTCVideoSenderStats
  327. * https://w3c.github.io/webrtc-stats/#dom-rtcvideosenderstats
  328. * @private
  329. */
  330. let kRTCVideoSenderStats = new RTCStats(kRTCVideoHandlerStats, {
  331. mediaSourceId: 'string',
  332. framesCaptured: 'number',
  333. framesSent: 'number',
  334. hugeFramesSent: 'number',
  335. });
  336. // TODO(hbos): When sender is implemented, make presence MANDATORY.
  337. addRTCStatsToWhitelist(Presence.OPTIONAL, 'sender', kRTCVideoSenderStats);
  338. /*
  339. * RTCSenderVideoTrackAttachmentStats
  340. * https://w3c.github.io/webrtc-stats/#dom-rtcsendervideotrackattachmentstats
  341. * @private
  342. */
  343. let kRTCSenderVideoTrackAttachmentStats = new RTCStats(kRTCVideoSenderStats, {
  344. });
  345. addRTCStatsToWhitelist(
  346. Presence.MANDATORY, 'track', kRTCSenderVideoTrackAttachmentStats);
  347. /*
  348. * RTCVideoReceiverStats
  349. * https://w3c.github.io/webrtc-stats/#dom-rtcvideoreceiverstats
  350. * @private
  351. */
  352. let kRTCVideoReceiverStats = new RTCStats(kRTCVideoHandlerStats, {
  353. estimatedPlayoutTimestamp: 'number',
  354. jitterBufferDelay: 'number',
  355. jitterBufferEmittedCount: 'number',
  356. framesReceived: 'number',
  357. framesDecoded: 'number',
  358. framesDropped: 'number',
  359. partialFramesLost: 'number',
  360. fullFramesLost: 'number',
  361. });
  362. // TODO(hbos): When receiver is implemented, make presence MANDATORY.
  363. addRTCStatsToWhitelist(
  364. Presence.OPTIONAL, 'receiver', kRTCVideoReceiverStats);
  365. /*
  366. * RTCReceiverVideoTrackAttachmentStats
  367. * https://github.com/w3c/webrtc-stats/issues/424
  368. * @private
  369. */
  370. let kRTCReceiverVideoTrackAttachmentStats =
  371. new RTCStats(kRTCVideoReceiverStats, {
  372. });
  373. addRTCStatsToWhitelist(
  374. Presence.MANDATORY, 'track', kRTCReceiverVideoTrackAttachmentStats);
  375. /*
  376. * RTCAudioHandlerStats
  377. * https://w3c.github.io/webrtc-stats/#dom-rtcaudiohandlerstats
  378. * @private
  379. */
  380. let kRTCAudioHandlerStats = new RTCStats(kRTCMediaHandlerStats, {
  381. audioLevel: 'number',
  382. totalAudioEnergy: 'number',
  383. voiceActivityFlag: 'boolean',
  384. totalSamplesDuration: 'number',
  385. });
  386. /*
  387. * RTCAudioSenderStats
  388. * https://w3c.github.io/webrtc-stats/#dom-rtcaudiosenderstats
  389. * @private
  390. */
  391. let kRTCAudioSenderStats = new RTCStats(kRTCAudioHandlerStats, {
  392. mediaSourceId: 'string',
  393. echoReturnLoss: 'number',
  394. echoReturnLossEnhancement: 'number',
  395. totalSamplesSent: 'number',
  396. });
  397. // TODO(hbos): When sender is implemented, make presence MANDATORY.
  398. addRTCStatsToWhitelist(Presence.OPTIONAL, 'sender', kRTCAudioSenderStats);
  399. /*
  400. * RTCSenderAudioTrackAttachmentStats
  401. * https://w3c.github.io/webrtc-stats/#dom-rtcsenderaudiotrackattachmentstats
  402. * @private
  403. */
  404. let kRTCSenderAudioTrackAttachmentStats = new RTCStats(kRTCAudioSenderStats, {
  405. });
  406. addRTCStatsToWhitelist(
  407. Presence.MANDATORY, 'track', kRTCSenderAudioTrackAttachmentStats);
  408. /*
  409. * RTCAudioReceiverStats
  410. * https://w3c.github.io/webrtc-stats/#dom-rtcaudioreceiverstats
  411. * @private
  412. */
  413. let kRTCAudioReceiverStats = new RTCStats(kRTCAudioHandlerStats, {
  414. estimatedPlayoutTimestamp: 'number',
  415. jitterBufferDelay: 'number',
  416. jitterBufferEmittedCount: 'number',
  417. totalSamplesReceived: 'number',
  418. concealedSamples: 'number',
  419. silentConcealedSamples: 'number',
  420. concealmentEvents: 'number',
  421. insertedSamplesForDeceleration: 'number',
  422. removedSamplesForAcceleration: 'number',
  423. });
  424. // TODO(hbos): When receiver is implemented, make presence MANDATORY.
  425. addRTCStatsToWhitelist(
  426. Presence.OPTIONAL, 'receiver', kRTCAudioReceiverStats);
  427. /*
  428. * RTCReceiverAudioTrackAttachmentStats
  429. * https://github.com/w3c/webrtc-stats/issues/424
  430. * @private
  431. */
  432. let kRTCReceiverAudioTrackAttachmentStats =
  433. new RTCStats(kRTCAudioReceiverStats, {
  434. });
  435. addRTCStatsToWhitelist(
  436. Presence.MANDATORY, 'track', kRTCReceiverAudioTrackAttachmentStats);
  437. /*
  438. * RTCDataChannelStats
  439. * https://w3c.github.io/webrtc-stats/#dcstats-dict*
  440. * @private
  441. */
  442. let kRTCDataChannelStats = new RTCStats(null, {
  443. label: 'string',
  444. protocol: 'string',
  445. datachannelid: 'number',
  446. state: 'string',
  447. messagesSent: 'number',
  448. bytesSent: 'number',
  449. messagesReceived: 'number',
  450. bytesReceived: 'number',
  451. });
  452. addRTCStatsToWhitelist(
  453. Presence.MANDATORY, 'data-channel', kRTCDataChannelStats);
  454. /*
  455. * RTCTransportStats
  456. * https://w3c.github.io/webrtc-stats/#transportstats-dict*
  457. * @private
  458. */
  459. let kRTCTransportStats = new RTCStats(null, {
  460. bytesSent: 'number',
  461. bytesReceived: 'number',
  462. rtcpTransportStatsId: 'string',
  463. dtlsState: 'string',
  464. selectedCandidatePairId: 'string',
  465. localCertificateId: 'string',
  466. remoteCertificateId: 'string',
  467. tlsVersion: 'string',
  468. dtlsCipher: 'string',
  469. srtpCipher: 'string',
  470. selectedCandidatePairChanges: 'number',
  471. });
  472. addRTCStatsToWhitelist(Presence.MANDATORY, 'transport', kRTCTransportStats);
  473. /*
  474. * RTCIceCandidateStats
  475. * https://w3c.github.io/webrtc-stats/#icecandidate-dict*
  476. * @private
  477. */
  478. let kRTCIceCandidateStats = new RTCStats(null, {
  479. transportId: 'string',
  480. isRemote: 'boolean',
  481. networkType: 'string',
  482. ip: 'string',
  483. port: 'number',
  484. protocol: 'string',
  485. relayProtocol: 'string',
  486. candidateType: 'string',
  487. priority: 'number',
  488. url: 'string',
  489. deleted: 'boolean',
  490. });
  491. addRTCStatsToWhitelist(
  492. Presence.MANDATORY, 'local-candidate', kRTCIceCandidateStats);
  493. addRTCStatsToWhitelist(
  494. Presence.MANDATORY, 'remote-candidate', kRTCIceCandidateStats);
  495. /*
  496. * RTCIceCandidatePairStats
  497. * https://w3c.github.io/webrtc-stats/#candidatepair-dict*
  498. * @private
  499. */
  500. let kRTCIceCandidatePairStats = new RTCStats(null, {
  501. transportId: 'string',
  502. localCandidateId: 'string',
  503. remoteCandidateId: 'string',
  504. state: 'string',
  505. priority: 'number',
  506. nominated: 'boolean',
  507. writable: 'boolean',
  508. readable: 'boolean',
  509. bytesSent: 'number',
  510. bytesReceived: 'number',
  511. totalRoundTripTime: 'number',
  512. currentRoundTripTime: 'number',
  513. availableOutgoingBitrate: 'number',
  514. availableIncomingBitrate: 'number',
  515. requestsReceived: 'number',
  516. requestsSent: 'number',
  517. responsesReceived: 'number',
  518. responsesSent: 'number',
  519. retransmissionsReceived: 'number',
  520. retransmissionsSent: 'number',
  521. consentRequestsReceived: 'number',
  522. consentRequestsSent: 'number',
  523. consentResponsesReceived: 'number',
  524. consentResponsesSent: 'number',
  525. });
  526. addRTCStatsToWhitelist(
  527. Presence.MANDATORY, 'candidate-pair', kRTCIceCandidatePairStats);
  528. /*
  529. * RTCCertificateStats
  530. * https://w3c.github.io/webrtc-stats/#certificatestats-dict*
  531. * @private
  532. */
  533. let kRTCCertificateStats = new RTCStats(null, {
  534. fingerprint: 'string',
  535. fingerprintAlgorithm: 'string',
  536. base64Certificate: 'string',
  537. issuerCertificateId: 'string',
  538. });
  539. addRTCStatsToWhitelist(Presence.MANDATORY, 'certificate', kRTCCertificateStats);
  540. // Public interface to tests. These are expected to be called with
  541. // ExecuteJavascript invocations from the browser tests and will return answers
  542. // through the DOM automation controller.
  543. /**
  544. * Verifies that the promise-based |RTCPeerConnection.getStats| returns stats,
  545. * makes sure that all returned stats have the base RTCStats-members and that
  546. * all stats are allowed by the whitelist.
  547. *
  548. * Returns "ok-" followed by JSON-stringified array of "RTCStats.type" values
  549. * to the test, these being the different types of stats that was returned by
  550. * this call to getStats.
  551. */
  552. function verifyStatsGeneratedPromise() {
  553. peerConnection_().getStats()
  554. .then(function(report) {
  555. if (report == null || report.size == 0)
  556. throw new failTest('report is null or empty.');
  557. let statsTypes = new Set();
  558. let ids = new Set();
  559. for (let stats of report.values()) {
  560. verifyStatsIsWhitelisted_(stats);
  561. statsTypes.add(stats.type);
  562. if (ids.has(stats.id))
  563. throw failTest('stats.id is not a unique identifier.');
  564. ids.add(stats.id);
  565. }
  566. returnToTest('ok-' + JSON.stringify(Array.from(statsTypes.values())));
  567. },
  568. function(e) {
  569. throw failTest('Promise was rejected: ' + e);
  570. });
  571. }
  572. /**
  573. * Gets the result of the promise-based |RTCPeerConnection.getStats| as a
  574. * dictionary of RTCStats-dictionaries.
  575. *
  576. * Returns "ok-" followed by a JSON-stringified dictionary of dictionaries to
  577. * the test.
  578. */
  579. function getStatsReportDictionary() {
  580. peerConnection_().getStats()
  581. .then(function(report) {
  582. if (report == null || report.size == 0)
  583. throw new failTest('report is null or empty.');
  584. let reportDictionary = {};
  585. for (let stats of report.values()) {
  586. reportDictionary[stats.id] = stats;
  587. }
  588. returnToTest('ok-' + JSON.stringify(reportDictionary));
  589. },
  590. function(e) {
  591. throw failTest('Promise was rejected: ' + e);
  592. });
  593. }
  594. /**
  595. * Measures the performance of the promise-based |RTCPeerConnection.getStats|
  596. * and returns the time it took in milliseconds as a double
  597. * (DOMHighResTimeStamp, accurate to one thousandth of a millisecond).
  598. * Verifies that all stats types of the whitelist were contained in the result.
  599. *
  600. * Returns "ok-" followed by a double on success.
  601. */
  602. function measureGetStatsPerformance() {
  603. let t0 = performance.now();
  604. peerConnection_().getStats()
  605. .then(function(report) {
  606. let t1 = performance.now();
  607. for (let stats of report.values()) {
  608. verifyStatsIsWhitelisted_(stats);
  609. }
  610. for (let mandatoryType of mandatoryStatsTypes()) {
  611. let mandatoryTypeExists = false;
  612. for (let stats of report.values()) {
  613. if (stats.type == mandatoryType) {
  614. mandatoryTypeExists = true;
  615. break;
  616. }
  617. }
  618. if (!mandatoryTypeExists) {
  619. returnToTest('Missing mandatory type: ' + mandatoryType);
  620. }
  621. }
  622. returnToTest('ok-' + (t1 - t0));
  623. },
  624. function(e) {
  625. throw failTest('Promise was rejected: ' + e);
  626. });
  627. }
  628. /**
  629. * Returns a complete list of mandatory "RTCStats.type" values from the
  630. * whitelist as a JSON-stringified array of strings to the test.
  631. */
  632. function getMandatoryStatsTypes() {
  633. returnToTest(JSON.stringify(Array.from(mandatoryStatsTypes())));
  634. }
  635. // Internals.
  636. /** Gets a set of all mandatory stats types. */
  637. function mandatoryStatsTypes() {
  638. const mandatoryTypes = new Set();
  639. for (let whitelistedStats of gStatsWhitelist.values()) {
  640. if (whitelistedStats.presence() == Presence.MANDATORY)
  641. mandatoryTypes.add(whitelistedStats.type());
  642. }
  643. return mandatoryTypes;
  644. }
  645. /**
  646. * Checks if |stats| correctly maps to a a whitelisted RTCStats-derived
  647. * dictionary, throwing |failTest| if it doesn't. See |gStatsWhitelist|.
  648. *
  649. * The "RTCStats.type" must map to a known dictionary description. Every member
  650. * is optional, but if present it must be present in the whitelisted dictionary
  651. * description and its type must match.
  652. * @private
  653. */
  654. function verifyStatsIsWhitelisted_(stats) {
  655. if (stats == null)
  656. throw failTest('stats is null or undefined: ' + stats);
  657. if (typeof(stats.id) !== 'string')
  658. throw failTest('stats.id is not a string:' + stats.id);
  659. if (typeof(stats.timestamp) !== 'number' || !isFinite(stats.timestamp) ||
  660. stats.timestamp <= 0) {
  661. throw failTest('stats.timestamp is not a positive finite number: ' +
  662. stats.timestamp);
  663. }
  664. if (typeof(stats.type) !== 'string')
  665. throw failTest('stats.type is not a string: ' + stats.type);
  666. let whitelistedStats = gStatsWhitelist.get(stats.type);
  667. if (whitelistedStats == null)
  668. throw failTest('stats.type is not a whitelisted type: ' + stats.type);
  669. whitelistedStats = whitelistedStats.stats();
  670. for (let propertyName in stats) {
  671. if (propertyName === 'id' || propertyName === 'timestamp' ||
  672. propertyName === 'type') {
  673. continue;
  674. }
  675. if (!whitelistedStats.hasOwnProperty(propertyName)) {
  676. throw failTest(
  677. stats.type + '.' + propertyName + ' is not a whitelisted ' +
  678. 'member: ' + stats[propertyName]);
  679. }
  680. if (whitelistedStats[propertyName] === 'any')
  681. continue;
  682. if (!whitelistedStats[propertyName].startsWith('sequence_')) {
  683. if (typeof(stats[propertyName]) !== whitelistedStats[propertyName]) {
  684. throw failTest('stats.' + propertyName + ' should have a different ' +
  685. 'type according to the whitelist: ' + stats[propertyName] + ' vs ' +
  686. whitelistedStats[propertyName]);
  687. }
  688. } else {
  689. if (!Array.isArray(stats[propertyName])) {
  690. throw failTest('stats.' + propertyName + ' should have a different ' +
  691. 'type according to the whitelist (should be an array): ' +
  692. JSON.stringify(stats[propertyName]) + ' vs ' +
  693. whitelistedStats[propertyName]);
  694. }
  695. let elementType = whitelistedStats[propertyName].substring(9);
  696. for (let element in stats[propertyName]) {
  697. if (typeof(element) !== elementType) {
  698. throw failTest('stats.' + propertyName + ' should have a different ' +
  699. 'type according to the whitelist (an element of the array has ' +
  700. 'the incorrect type): ' + JSON.stringify(stats[propertyName]) +
  701. ' vs ' + whitelistedStats[propertyName]);
  702. }
  703. }
  704. }
  705. }
  706. }