Source: lib/util/stats.js

  1. /*! @license
  2. * Shaka Player
  3. * Copyright 2016 Google LLC
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. goog.provide('shaka.util.Stats');
  7. goog.require('shaka.util.StateHistory');
  8. goog.require('shaka.util.SwitchHistory');
  9. /**
  10. * This class tracks all the various components (some optional) that are used to
  11. * populate |shaka.extern.Stats| which is passed to the app.
  12. *
  13. * @final
  14. */
  15. shaka.util.Stats = class {
  16. constructor() {
  17. /** @private {number} */
  18. this.width_ = NaN;
  19. /** @private {number} */
  20. this.height_ = NaN;
  21. /** @private {string} */
  22. this.currentCodecs_ = '';
  23. /** @private {number} */
  24. this.totalDroppedFrames_ = NaN;
  25. /** @private {number} */
  26. this.totalDecodedFrames_ = NaN;
  27. /** @private {number} */
  28. this.totalCorruptedFrames_ = NaN;
  29. /** @private {number} */
  30. this.totalStallsDetected_ = NaN;
  31. /** @private {number} */
  32. this.totalGapsJumped_ = NaN;
  33. /** @private {number} */
  34. this.completionPercent_ = NaN;
  35. /** @private {number} */
  36. this.loadLatencySeconds_ = NaN;
  37. /** @private {number} */
  38. this.manifestTimeSeconds_ = NaN;
  39. /** @private {number} */
  40. this.drmTimeSeconds_ = NaN;
  41. /** @private {number} */
  42. this.licenseTimeSeconds_ = NaN;
  43. /** @private {number} */
  44. this.liveLatencySeconds_ = NaN;
  45. /** @private {number} */
  46. this.maxSegmentDurationSeconds_ = NaN;
  47. /** @private {number} */
  48. this.currentStreamBandwidth_ = NaN;
  49. /** @private {number} */
  50. this.bandwidthEstimate_ = NaN;
  51. /** @private {number} */
  52. this.manifestSizeBytes_ = NaN;
  53. /** @private {number} */
  54. this.bytesDownloaded_ = NaN;
  55. /** @private {number} */
  56. this.nonFatalErrorCount_ = 0;
  57. /** @private {number} */
  58. this.manifestPeriodCount_ = NaN;
  59. /** @private {number} */
  60. this.manifestGapCount_ = NaN;
  61. /** @private {!shaka.util.StateHistory} */
  62. this.stateHistory_ = new shaka.util.StateHistory();
  63. /** @private {!shaka.util.SwitchHistory} */
  64. this.switchHistory_ = new shaka.util.SwitchHistory();
  65. }
  66. /**
  67. * Update the ratio of dropped frames to total frames. This will replace the
  68. * previous values.
  69. *
  70. * @param {number} dropped
  71. * @param {number} decoded
  72. */
  73. setDroppedFrames(dropped, decoded) {
  74. this.totalDroppedFrames_ = dropped;
  75. this.totalDecodedFrames_ = decoded;
  76. }
  77. /**
  78. * Update corrupted frames. This will replace the previous values.
  79. *
  80. * @param {number} corrupted
  81. */
  82. setCorruptedFrames(corrupted) {
  83. this.totalCorruptedFrames_ = corrupted;
  84. }
  85. /**
  86. * Update number of stalls detected. This will replace the previous value.
  87. *
  88. * @param {number} stallsDetected
  89. */
  90. setStallsDetected(stallsDetected) {
  91. this.totalStallsDetected_ = stallsDetected;
  92. }
  93. /**
  94. * Update number of playback gaps jumped over. This will replace the previous
  95. * value.
  96. *
  97. * @param {number} gapsJumped
  98. */
  99. setGapsJumped(gapsJumped) {
  100. this.totalGapsJumped_ = gapsJumped;
  101. }
  102. /**
  103. * Set the width and height of the video we are currently playing.
  104. *
  105. * @param {number} width
  106. * @param {number} height
  107. */
  108. setResolution(width, height) {
  109. this.width_ = width;
  110. this.height_ = height;
  111. }
  112. /**
  113. * Set the codecs that we are currently playing.
  114. *
  115. * @param {string} codecs
  116. */
  117. setCodecs(codecs) {
  118. this.currentCodecs_ = codecs;
  119. }
  120. /**
  121. * Record the time it took between the user signalling "I want to play this"
  122. * to "I am now seeing this".
  123. *
  124. * @param {number} seconds
  125. */
  126. setLoadLatency(seconds) {
  127. this.loadLatencySeconds_ = seconds;
  128. }
  129. /**
  130. * Record the time it took to download and parse the manifest.
  131. *
  132. * @param {number} seconds
  133. */
  134. setManifestTime(seconds) {
  135. this.manifestTimeSeconds_ = seconds;
  136. }
  137. /**
  138. * Record the current completion percent. This is the "high water mark", so it
  139. * will store the highest provided completion percent.
  140. *
  141. * @param {number} percent
  142. */
  143. setCompletionPercent(percent) {
  144. if (isNaN(this.completionPercent_)) {
  145. this.completionPercent_ = percent;
  146. } else {
  147. this.completionPercent_ = Math.max(this.completionPercent_, percent);
  148. }
  149. }
  150. /**
  151. * Record the time it took to download the first drm key.
  152. *
  153. * @param {number} seconds
  154. */
  155. setDrmTime(seconds) {
  156. this.drmTimeSeconds_ = seconds;
  157. }
  158. /**
  159. * Record the cumulative time spent on license requests during this session.
  160. *
  161. * @param {number} seconds
  162. */
  163. setLicenseTime(seconds) {
  164. this.licenseTimeSeconds_ = seconds;
  165. }
  166. /**
  167. * Record the latency in live streams.
  168. *
  169. * @param {number} seconds
  170. */
  171. setLiveLatency(seconds) {
  172. this.liveLatencySeconds_ = seconds;
  173. }
  174. /**
  175. * Record the presentation's max segment duration.
  176. *
  177. * @param {number} seconds
  178. */
  179. setMaxSegmentDuration(seconds) {
  180. this.maxSegmentDurationSeconds_ = seconds;
  181. }
  182. /**
  183. * @param {number} bandwidth
  184. */
  185. setCurrentStreamBandwidth(bandwidth) {
  186. this.currentStreamBandwidth_ = bandwidth;
  187. }
  188. /**
  189. * @param {number} bandwidth
  190. */
  191. setBandwidthEstimate(bandwidth) {
  192. this.bandwidthEstimate_ = bandwidth;
  193. }
  194. /**
  195. * @param {number} size
  196. */
  197. setManifestSize(size) {
  198. this.manifestSizeBytes_ = size;
  199. }
  200. /**
  201. * @param {number} bytesDownloaded
  202. */
  203. addBytesDownloaded(bytesDownloaded) {
  204. if (isNaN(this.bytesDownloaded_)) {
  205. this.bytesDownloaded_ = bytesDownloaded;
  206. } else {
  207. this.bytesDownloaded_ += bytesDownloaded;
  208. }
  209. }
  210. /** */
  211. addNonFatalError() {
  212. this.nonFatalErrorCount_++;
  213. }
  214. /**
  215. * @param {number} count
  216. */
  217. setManifestPeriodCount(count) {
  218. this.manifestPeriodCount_ = count;
  219. }
  220. /**
  221. * @param {number} count
  222. */
  223. setManifestGapCount(count) {
  224. this.manifestGapCount_ = count;
  225. }
  226. /**
  227. * @return {!shaka.util.StateHistory}
  228. */
  229. getStateHistory() {
  230. return this.stateHistory_;
  231. }
  232. /**
  233. * @return {!shaka.util.SwitchHistory}
  234. */
  235. getSwitchHistory() {
  236. return this.switchHistory_;
  237. }
  238. /**
  239. * Create a stats blob that we can pass up to the app. This blob will not
  240. * reference any internal data.
  241. *
  242. * @return {shaka.extern.Stats}
  243. */
  244. getBlob() {
  245. return {
  246. width: this.width_,
  247. height: this.height_,
  248. currentCodecs: this.currentCodecs_,
  249. streamBandwidth: this.currentStreamBandwidth_,
  250. decodedFrames: this.totalDecodedFrames_,
  251. droppedFrames: this.totalDroppedFrames_,
  252. corruptedFrames: this.totalCorruptedFrames_,
  253. stallsDetected: this.totalStallsDetected_,
  254. gapsJumped: this.totalGapsJumped_,
  255. estimatedBandwidth: this.bandwidthEstimate_,
  256. completionPercent: this.completionPercent_,
  257. loadLatency: this.loadLatencySeconds_,
  258. manifestTimeSeconds: this.manifestTimeSeconds_,
  259. drmTimeSeconds: this.drmTimeSeconds_,
  260. playTime: this.stateHistory_.getTimeSpentIn('playing'),
  261. pauseTime: this.stateHistory_.getTimeSpentIn('paused'),
  262. bufferingTime: this.stateHistory_.getTimeSpentIn('buffering'),
  263. licenseTime: this.licenseTimeSeconds_,
  264. liveLatency: this.liveLatencySeconds_,
  265. maxSegmentDuration: this.maxSegmentDurationSeconds_,
  266. manifestSizeBytes: this.manifestSizeBytes_,
  267. bytesDownloaded: this.bytesDownloaded_,
  268. nonFatalErrorCount: this.nonFatalErrorCount_,
  269. manifestPeriodCount: this.manifestPeriodCount_,
  270. manifestGapCount: this.manifestGapCount_,
  271. stateHistory: this.stateHistory_.getCopy(),
  272. switchHistory: this.switchHistory_.getCopy(),
  273. };
  274. }
  275. /**
  276. * Create an empty stats blob. This resembles the stats when we are not
  277. * playing any content.
  278. *
  279. * @return {shaka.extern.Stats}
  280. */
  281. static getEmptyBlob() {
  282. return {
  283. width: NaN,
  284. height: NaN,
  285. currentCodecs: '',
  286. streamBandwidth: NaN,
  287. decodedFrames: NaN,
  288. droppedFrames: NaN,
  289. corruptedFrames: NaN,
  290. stallsDetected: NaN,
  291. gapsJumped: NaN,
  292. estimatedBandwidth: NaN,
  293. completionPercent: NaN,
  294. loadLatency: NaN,
  295. manifestTimeSeconds: NaN,
  296. drmTimeSeconds: NaN,
  297. playTime: NaN,
  298. pauseTime: NaN,
  299. bufferingTime: NaN,
  300. licenseTime: NaN,
  301. liveLatency: NaN,
  302. maxSegmentDuration: NaN,
  303. manifestSizeBytes: NaN,
  304. bytesDownloaded: NaN,
  305. nonFatalErrorCount: NaN,
  306. manifestPeriodCount: NaN,
  307. manifestGapCount: NaN,
  308. switchHistory: [],
  309. stateHistory: [],
  310. };
  311. }
  312. };