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