@gcorevideo/player 2.22.16 → 2.22.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/assets/clappr-nerd-stats/clappr-nerd-stats.ejs +76 -78
  2. package/assets/clappr-nerd-stats/clappr-nerd-stats.scss +10 -7
  3. package/dist/core.js +10 -14
  4. package/dist/index.css +1441 -1440
  5. package/dist/index.js +589 -522
  6. package/dist/player.d.ts +216 -159
  7. package/dist/plugins/index.css +1204 -1203
  8. package/dist/plugins/index.js +581 -506
  9. package/docs/api/player.clapprstats.exportmetrics.md +1 -1
  10. package/docs/api/player.clapprstats.md +5 -15
  11. package/docs/api/player.clapprstatssettings.md +13 -0
  12. package/docs/api/player.clips.destroy.md +18 -0
  13. package/docs/api/player.clips.disable.md +18 -0
  14. package/docs/api/player.clips.enable.md +18 -0
  15. package/docs/api/player.clips.md +170 -0
  16. package/docs/api/player.clips.render.md +18 -0
  17. package/docs/api/player.clips.supportedversion.md +16 -0
  18. package/docs/api/player.clips.version.md +14 -0
  19. package/docs/api/player.clipspluginsettings.md +2 -2
  20. package/docs/api/player.clipspluginsettings.text.md +1 -1
  21. package/docs/api/player.md +27 -18
  22. package/docs/api/player.mediacontrol.md +1 -1
  23. package/docs/api/{player.mediacontrol.getelement.md → player.mediacontrol.mount.md} +20 -7
  24. package/docs/api/player.mediacontrolleftelement.md +1 -1
  25. package/docs/api/{player.clapprnerdstats._constructor_.md → player.nerdstats._constructor_.md} +3 -3
  26. package/docs/api/{player.clapprnerdstats.md → player.nerdstats.md} +5 -5
  27. package/docs/api/player.qualitylevel.height.md +1 -1
  28. package/docs/api/player.qualitylevel.level.md +1 -1
  29. package/docs/api/player.qualitylevel.md +4 -4
  30. package/docs/api/player.qualitylevel.width.md +1 -1
  31. package/docs/api/player.timeposition.current.md +1 -1
  32. package/docs/api/player.timeposition.md +2 -2
  33. package/docs/api/player.timeposition.total.md +1 -1
  34. package/docs/api/player.timeprogress.md +6 -4
  35. package/docs/api/player.timevalue.md +1 -1
  36. package/lib/index.plugins.d.ts +2 -1
  37. package/lib/index.plugins.d.ts.map +1 -1
  38. package/lib/index.plugins.js +2 -1
  39. package/lib/playback/dash-playback/DashPlayback.d.ts +0 -1
  40. package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
  41. package/lib/playback/dash-playback/DashPlayback.js +9 -12
  42. package/lib/playback/hls-playback/HlsPlayback.d.ts +1 -1
  43. package/lib/playback/hls-playback/HlsPlayback.d.ts.map +1 -1
  44. package/lib/playback/hls-playback/HlsPlayback.js +0 -1
  45. package/lib/playback.types.d.ts +24 -12
  46. package/lib/playback.types.d.ts.map +1 -1
  47. package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.d.ts +4 -0
  48. package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.d.ts.map +1 -1
  49. package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.js +20 -23
  50. package/lib/plugins/clappr-nerd-stats/NerdStats.d.ts +86 -0
  51. package/lib/plugins/clappr-nerd-stats/NerdStats.d.ts.map +1 -0
  52. package/lib/plugins/clappr-nerd-stats/NerdStats.js +390 -0
  53. package/lib/plugins/clappr-nerd-stats/formatter.d.ts +5 -0
  54. package/lib/plugins/clappr-nerd-stats/formatter.d.ts.map +1 -1
  55. package/lib/plugins/clappr-nerd-stats/formatter.js +56 -24
  56. package/lib/plugins/clappr-nerd-stats/speedtest/index.d.ts +2 -2
  57. package/lib/plugins/clappr-nerd-stats/speedtest/index.d.ts.map +1 -1
  58. package/lib/plugins/clappr-nerd-stats/speedtest/types.d.ts +1 -1
  59. package/lib/plugins/clappr-nerd-stats/speedtest/types.d.ts.map +1 -1
  60. package/lib/plugins/clappr-nerd-stats/types.d.ts +3 -0
  61. package/lib/plugins/clappr-nerd-stats/types.d.ts.map +1 -1
  62. package/lib/plugins/clappr-nerd-stats/utils.d.ts +7 -0
  63. package/lib/plugins/clappr-nerd-stats/utils.d.ts.map +1 -0
  64. package/lib/plugins/clappr-nerd-stats/utils.js +67 -0
  65. package/lib/plugins/clappr-stats/ClapprStats.d.ts +27 -32
  66. package/lib/plugins/clappr-stats/ClapprStats.d.ts.map +1 -1
  67. package/lib/plugins/clappr-stats/ClapprStats.js +94 -202
  68. package/lib/plugins/clappr-stats/types.d.ts +65 -25
  69. package/lib/plugins/clappr-stats/types.d.ts.map +1 -1
  70. package/lib/plugins/clappr-stats/types.js +37 -2
  71. package/lib/plugins/clappr-stats/utils.d.ts +1 -1
  72. package/lib/plugins/clappr-stats/utils.d.ts.map +1 -1
  73. package/lib/plugins/clappr-stats/utils.js +1 -3
  74. package/lib/plugins/seek-time/SeekTime.d.ts +1 -1
  75. package/lib/plugins/seek-time/SeekTime.d.ts.map +1 -1
  76. package/lib/plugins/seek-time/SeekTime.js +3 -4
  77. package/lib/testUtils.d.ts +2 -1
  78. package/lib/testUtils.d.ts.map +1 -1
  79. package/lib/testUtils.js +3 -2
  80. package/package.json +1 -1
  81. package/src/index.plugins.ts +2 -1
  82. package/src/playback/dash-playback/DashPlayback.ts +10 -15
  83. package/src/playback/hls-playback/HlsPlayback.ts +2 -4
  84. package/src/playback.types.ts +25 -11
  85. package/src/plugins/clappr-nerd-stats/NerdStats.ts +503 -0
  86. package/src/plugins/clappr-nerd-stats/formatter.ts +91 -47
  87. package/src/plugins/clappr-nerd-stats/speedtest/index.ts +2 -2
  88. package/src/plugins/clappr-nerd-stats/speedtest/types.ts +1 -1
  89. package/src/plugins/clappr-nerd-stats/types.ts +43 -3
  90. package/src/plugins/clappr-nerd-stats/utils.ts +75 -0
  91. package/src/plugins/clappr-stats/ClapprStats.ts +242 -306
  92. package/src/plugins/clappr-stats/__tests__/ClapprStats.test.ts +133 -0
  93. package/src/plugins/clappr-stats/types.ts +93 -47
  94. package/src/plugins/clappr-stats/utils.ts +4 -6
  95. package/src/plugins/error-screen/__tests__/ErrorScreen.test.ts +3 -4
  96. package/src/plugins/seek-time/SeekTime.ts +4 -5
  97. package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +1 -0
  98. package/src/testUtils.ts +3 -2
  99. package/temp/player.api.json +311 -159
  100. package/tsconfig.tsbuildinfo +1 -1
  101. package/docs/api/player.clapprstats.setupdatemetrics.md +0 -56
  102. package/docs/api/player.clipsplugin.gettext.md +0 -58
  103. package/docs/api/player.clipsplugin.md +0 -59
  104. package/src/plugins/clappr-nerd-stats/ClapprNerdStats.ts +0 -435
@@ -1,469 +1,405 @@
1
- import { Container, ContainerPlugin, Events as CoreEvents, Log } from '@clappr/core';
2
- import type { QualityLevel, TimePosition, TimeProgress } from '../../playback.types.js';
3
- import assert from 'assert';
4
-
5
- import { CLAPPR_VERSION } from '../../build.js';
6
- import { TimerId } from '../../utils/types.js';
7
- import type { Metrics, MetricsUpdateFn } from './types.js';
8
- import { ClapprStatsEvents } from './types.js';
9
- import { newMetrics } from './utils.js';
10
-
11
- type StatsTimer = keyof Metrics['timers'];
12
-
13
- type UriToMeasureBandwidth = {
14
- url: string;
15
- start: number;
16
- end: number;
17
- expired: boolean;
18
- timeout: number;
19
- timer: TimerId | null;
20
- }
1
+ import { Container, ContainerPlugin, Events as CoreEvents } from '@clappr/core'
2
+
3
+ import type {
4
+ QualityLevel,
5
+ TimePosition,
6
+ TimeProgress,
7
+ } from '../../playback.types.js'
21
8
 
22
- // TODO: fix
23
- const updateMetrics = () => {};
9
+ import { CLAPPR_VERSION } from '../../build.js'
10
+ import { TimerId } from '../../utils/types.js'
11
+ import type { Metrics } from './types.js'
12
+ import { ClapprStatsEvents, Chronograph, Counter } from './types.js'
13
+ import { newMetrics } from './utils.js'
14
+
15
+ export type ClapprStatsSettings = {
16
+ /**
17
+ * The interval in milliseconds of periodic measurements.
18
+ * The plugin will emit a {@link ClapprStatsEvents.REPORT} event with the collected metrics at the specified interval.
19
+ */
20
+ runEach?: number
21
+ }
24
22
 
25
23
  /**
26
- * `PLUGIN` that collects useful statistics about playback performance.
24
+ * `PLUGIN` that measures data about playback, which can be useful for analyzing performance and UX.
27
25
  * @beta
28
26
  * @remarks
29
27
  * This plugin does not render anything and is supposed to be extended or used together with other plugins that actually render something.
28
+ *
29
+ * Configuration options - {@link ClapprStatsSettings}
30
+ *
31
+ * Events - {@link ClapprStatsEvents}
30
32
  */
31
33
  export class ClapprStats extends ContainerPlugin {
32
- private bwMeasureCount = 0;
33
-
34
- private intervalId: TimerId | null = null;
35
-
36
- private lastDecodedFramesCount = 0;
37
-
38
- private metrics: Metrics = newMetrics();
39
-
40
- private completion: {
41
- watch: number[];
42
- calls: number[];
43
- };
34
+ private timerId: TimerId | null = null
44
35
 
45
- private _onReport: (metrics: Metrics) => void;
36
+ private lastDecodedFramesCount = 0
46
37
 
47
- private runBandwidthTestEvery: number;
38
+ private metrics: Metrics = newMetrics()
48
39
 
49
- private runEach: number;
50
-
51
- private timers: Record<StatsTimer, number> = {
52
- startup: 0,
53
- watch: 0,
54
- pause: 0,
55
- buffering: 0,
56
- session: 0,
57
- latency: 0,
58
- };
59
-
60
- private updateFn: MetricsUpdateFn = updateMetrics;
61
-
62
- private urisToMeasureBandwidth: UriToMeasureBandwidth[];
40
+ private timers: Record<Chronograph, number> = {
41
+ [Chronograph.Startup]: 0,
42
+ [Chronograph.Watch]: 0,
43
+ [Chronograph.Pause]: 0,
44
+ [Chronograph.Buffering]: 0,
45
+ [Chronograph.Session]: 0,
46
+ }
63
47
 
64
- private uriToMeasureLatency: string | undefined;
48
+ private runEach: number
65
49
 
66
50
  /**
67
51
  * @internal
68
52
  */
69
53
  get name() {
70
- return 'clappr_stats';
54
+ return 'clappr_stats'
71
55
  }
72
56
 
73
57
  /**
74
58
  * @internal
75
59
  */
76
60
  get supportedVersion() {
77
- return { min: CLAPPR_VERSION };
61
+ return { min: CLAPPR_VERSION }
78
62
  }
79
63
 
80
- private get _playbackName() {
81
- return String(this.container.playback.name || '');
64
+ private get playbackName() {
65
+ return String(this.container.playback.name || '')
82
66
  }
83
67
 
84
- private get _playbackType() {
85
- return this.container.getPlaybackType();
68
+ private get playbackType() {
69
+ return this.container.getPlaybackType()
86
70
  }
87
71
 
88
- private _now() {
89
- const hasPerformanceSupport = window.performance && typeof (window.performance.now) === 'function';
72
+ private now() {
73
+ const hasPerformanceSupport =
74
+ window.performance && typeof window.performance.now === 'function'
90
75
 
91
- return (hasPerformanceSupport) ? window.performance.now() : new Date().getTime();
76
+ return hasPerformanceSupport
77
+ ? window.performance.now()
78
+ : new Date().getTime()
92
79
  }
93
80
 
94
- private _inc(counter: keyof Metrics['counters']) {
95
- this.metrics.counters[counter] += 1;
81
+ private inc(counter: Counter) {
82
+ this.metrics.counters[counter] += 1
96
83
  }
97
84
 
98
85
  // _timerHasStarted(timer) {
99
86
  // return this[`_start${timer}`] !== undefined;
100
87
  // }
101
88
 
102
- private start(timer: StatsTimer) {
89
+ private start(timer: Chronograph) {
103
90
  // this[`_start${timer}`] = this._now();
104
- this.timers[timer] = this._now();
91
+ this.timers[timer] = this.now()
105
92
  }
106
93
 
107
- private _stop(timer: StatsTimer) {
94
+ private stop(timer: Chronograph) {
108
95
  // this._metrics.timers[timer] += this._now() - this[`_start${timer}`];
109
- this.metrics.timers[timer] += this._now() - this.timers[timer];
110
- }
111
-
112
- /**
113
- * Registers a callback to receive the metrics.
114
- * @param updateMetricsFn - The callback to receive the metrics
115
- */
116
- setUpdateMetrics(updateMetricsFn: MetricsUpdateFn) {
117
- // TODO use events instead
118
- this.updateFn = updateMetricsFn;
119
- }
120
-
121
- private _defaultReport(metrics: Metrics) {
122
- this.updateFn(metrics);
96
+ this.metrics.chrono[timer] += this.now() - this.timers[timer]
123
97
  }
124
98
 
125
99
  constructor(container: Container) {
126
- super(container);
127
- this.runEach = container.options.clapprStats?.runEach ?? 5000;
128
- this._onReport = container.options.clapprStats?.onReport ?? this._defaultReport;
129
- this.uriToMeasureLatency = container.options.clapprStats?.uriToMeasureLatency;
130
- this.urisToMeasureBandwidth = container.options.clapprStats?.urisToMeasureBandwidth;
131
- this.runBandwidthTestEvery = container.options.clapprStats?.runBandwidthTestEvery ?? 10;
132
-
133
- this.completion = {
134
- watch: container.options.clapprStats?.onCompletion ?? [],
135
- calls: []
136
- };
100
+ super(container)
101
+ this.runEach = container.options.clapprStats?.runEach ?? 5000
137
102
  }
138
103
 
139
104
  /**
140
105
  * @internal
141
106
  */
142
107
  override bindEvents() {
143
- this.listenTo(this.container, CoreEvents.CONTAINER_BITRATE, this.onBitrate);
144
- this.listenTo(this.container, CoreEvents.CONTAINER_STOP, this.stopReporting);
145
- this.listenTo(this.container, CoreEvents.CONTAINER_ENDED, this.stopReporting);
146
- this.listenToOnce(this.container.playback, CoreEvents.PLAYBACK_PLAY_INTENT, this.startTimers);
147
- this.listenToOnce(this.container, CoreEvents.CONTAINER_PLAY, this.onFirstPlaying);
148
- this.listenTo(this.container, CoreEvents.CONTAINER_PLAY, this.onPlay);
149
- this.listenTo(this.container, CoreEvents.CONTAINER_PAUSE, this.onPause);
150
- this.listenToOnce(this.container, CoreEvents.CONTAINER_STATE_BUFFERING, this.onBuffering);
151
- this.listenTo(this.container, CoreEvents.CONTAINER_SEEK, this.onSeek);
152
- this.listenTo(this.container, CoreEvents.CONTAINER_ERROR, () => this._inc('error'));
153
- this.listenTo(this.container, CoreEvents.CONTAINER_FULLSCREEN, () => this._inc('fullscreen'));
154
- this.listenTo(this.container, CoreEvents.CONTAINER_PLAYBACKDVRSTATECHANGED, (dvrInUse: boolean) => {
155
- dvrInUse && this._inc('dvrUsage');
156
- });
157
- this.listenTo(this.container.playback, CoreEvents.PLAYBACK_PROGRESS, this.onProgress);
158
- this.listenTo(this.container.playback, CoreEvents.PLAYBACK_TIMEUPDATE, this.onTimeUpdate);
108
+ this.listenTo(this.container, CoreEvents.CONTAINER_BITRATE, this.onBitrate)
109
+ this.listenTo(this.container, CoreEvents.CONTAINER_STOP, this.stopReporting)
110
+ this.listenTo(
111
+ this.container,
112
+ CoreEvents.CONTAINER_ENDED,
113
+ this.stopReporting,
114
+ )
115
+ this.listenToOnce(
116
+ this.container.playback,
117
+ CoreEvents.PLAYBACK_PLAY_INTENT,
118
+ this.startTimers,
119
+ )
120
+ this.listenToOnce(
121
+ this.container,
122
+ CoreEvents.CONTAINER_PLAY,
123
+ this.onFirstPlaying,
124
+ )
125
+ this.listenTo(this.container, CoreEvents.CONTAINER_PLAY, this.onPlay)
126
+ this.listenTo(this.container, CoreEvents.CONTAINER_PAUSE, this.onPause)
127
+ this.listenToOnce(
128
+ this.container,
129
+ CoreEvents.CONTAINER_STATE_BUFFERING,
130
+ this.onBuffering,
131
+ )
132
+ this.listenTo(this.container, CoreEvents.CONTAINER_SEEK, this.onSeek)
133
+ this.listenTo(this.container, CoreEvents.CONTAINER_ERROR, () =>
134
+ this.inc(Counter.Error),
135
+ )
136
+ this.listenTo(this.container, CoreEvents.CONTAINER_FULLSCREEN, () =>
137
+ this.inc(Counter.Fullscreen),
138
+ )
139
+ this.listenTo(
140
+ this.container,
141
+ CoreEvents.CONTAINER_PLAYBACKDVRSTATECHANGED,
142
+ (dvrInUse: boolean) => {
143
+ dvrInUse && this.inc(Counter.DvrUsage)
144
+ },
145
+ )
146
+ this.listenTo(
147
+ this.container.playback,
148
+ CoreEvents.PLAYBACK_PROGRESS,
149
+ this.onProgress,
150
+ )
151
+ this.listenTo(
152
+ this.container.playback,
153
+ CoreEvents.PLAYBACK_TIMEUPDATE,
154
+ this.onTimeUpdate,
155
+ )
159
156
  }
160
157
 
161
158
  /**
162
159
  * @internal
163
160
  */
164
161
  override destroy() {
165
- this.stopReporting();
166
- super.destroy();
162
+ this.stopReporting()
163
+ super.destroy()
167
164
  }
168
165
 
169
166
  /**
170
167
  * Returns the collected metrics.
171
- * @returns Currently collected metrics
168
+ * @returns Measurements collected so far
172
169
  */
173
170
  exportMetrics() {
174
- return structuredClone(this.metrics);
171
+ return structuredClone(this.metrics)
175
172
  }
176
173
 
177
174
  private onBitrate(newBitrate: QualityLevel) {
178
- const bitrate = newBitrate.bitrate;
179
- const now = this._now();
175
+ const bitrate = newBitrate.bitrate
176
+ const now = this.now()
180
177
 
181
178
  if (this.metrics.extra.bitratesHistory.length > 0) {
182
- const beforeLast = this.metrics.extra.bitratesHistory[this.metrics.extra.bitratesHistory.length - 1];
183
-
184
- beforeLast.end = now;
185
- beforeLast.time = now - beforeLast.start;
179
+ const last =
180
+ this.metrics.extra.bitratesHistory[
181
+ this.metrics.extra.bitratesHistory.length - 1
182
+ ]
183
+ last.end = now
184
+ last.time = now - last.start
186
185
  }
187
186
 
188
- this.metrics.extra.bitratesHistory.push({ start: this._now(), bitrate: bitrate });
187
+ this.metrics.extra.bitratesHistory.push({ start: this.now(), bitrate })
189
188
 
190
- this._inc('changeLevel');
189
+ this.inc(Counter.ChangeLevel)
191
190
  }
192
191
 
193
192
  private stopReporting() {
194
- this._buildReport();
193
+ this.buildReport()
195
194
 
196
- if (this.intervalId !== null) {
197
- clearInterval(this.intervalId);
198
- this.intervalId = null;
195
+ if (this.timerId !== null) {
196
+ clearInterval(this.timerId)
197
+ this.timerId = null
199
198
  }
200
- this._newMetrics();
201
-
202
- // TODO
203
- // @ts-ignore
204
- this.stopListening();
205
- this.bindEvents();
206
199
  }
207
200
 
208
201
  private startTimers() {
209
- this.intervalId = setInterval(this._buildReport.bind(this), this.runEach);
210
- this.start('session');
211
- this.start('startup');
202
+ this.timerId = setInterval(this.buildReport.bind(this), this.runEach)
203
+ this.start(Chronograph.Session)
204
+ this.start(Chronograph.Startup)
212
205
  }
213
206
 
214
207
  private onFirstPlaying() {
215
- this.listenTo(this.container, CoreEvents.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
208
+ this.listenTo(
209
+ this.container,
210
+ CoreEvents.CONTAINER_TIMEUPDATE,
211
+ this.onContainerUpdateWhilePlaying,
212
+ )
216
213
 
217
- this.start('watch');
218
- this._stop('startup');
214
+ this.start(Chronograph.Watch)
215
+ this.stop(Chronograph.Startup)
219
216
  }
220
217
 
221
218
  private playAfterPause() {
222
- this.listenTo(this.container, CoreEvents.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
223
- this._stop('pause');
224
- this.start('watch');
219
+ this.listenTo(
220
+ this.container,
221
+ CoreEvents.CONTAINER_TIMEUPDATE,
222
+ this.onContainerUpdateWhilePlaying,
223
+ )
224
+ this.stop(Chronograph.Pause)
225
+ this.start(Chronograph.Watch)
225
226
  }
226
227
 
227
228
  private onPlay() {
228
- this._inc('play');
229
+ this.inc(Counter.Play)
229
230
  }
230
231
 
231
232
  private onPause() {
232
- this._stop('watch');
233
- this.start('pause');
234
- this._inc('pause');
235
- this.listenToOnce(this.container, CoreEvents.CONTAINER_PLAY, this.playAfterPause);
236
- this.stopListening(this.container, CoreEvents.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
233
+ this.stop(Chronograph.Watch)
234
+ this.start(Chronograph.Pause)
235
+ this.inc(Counter.Pause)
236
+ this.listenToOnce(
237
+ this.container,
238
+ CoreEvents.CONTAINER_PLAY,
239
+ this.playAfterPause,
240
+ )
241
+ this.stopListening(
242
+ this.container,
243
+ CoreEvents.CONTAINER_TIMEUPDATE,
244
+ this.onContainerUpdateWhilePlaying,
245
+ )
237
246
  }
238
247
 
239
248
  private onSeek(e: number) {
240
- this._inc('seek');
241
- this.metrics.extra.watchHistory.push([e * 1000, e * 1000]);
249
+ this.inc(Counter.Seek)
250
+ this.metrics.extra.watchHistory.push([e * 1000, e * 1000])
242
251
  }
243
252
 
244
253
  private onTimeUpdate(e: TimePosition) {
245
254
  const current = e.current * 1000,
246
255
  total = e.total * 1000,
247
- l = this.metrics.extra.watchHistory.length;
256
+ l = this.metrics.extra.watchHistory.length
248
257
 
249
- this.metrics.extra.duration = total;
250
- this.metrics.extra.currentTime = current;
251
- this.metrics.extra.watchedPercentage = (current / total) * 100;
258
+ this.metrics.extra.duration = total
259
+ this.metrics.extra.currentTime = current
260
+ // TODO what if it's a live stream?
261
+ this.metrics.extra.watchedPercentage = (current / total) * 100
252
262
 
253
263
  if (l === 0) {
254
- this.metrics.extra.watchHistory.push([current, current]);
264
+ this.metrics.extra.watchHistory.push([current, current])
255
265
  } else {
256
- this.metrics.extra.watchHistory[l - 1][1] = current;
266
+ this.metrics.extra.watchHistory[l - 1][1] = current
257
267
  }
258
268
 
259
269
  if (this.metrics.extra.bitratesHistory.length > 0) {
260
- const lastBitrate = this.metrics.extra.bitratesHistory[this.metrics.extra.bitratesHistory.length - 1];
270
+ const lastBitrate =
271
+ this.metrics.extra.bitratesHistory[
272
+ this.metrics.extra.bitratesHistory.length - 1
273
+ ]
261
274
 
262
275
  if (!lastBitrate.end) {
263
- lastBitrate.time = this._now() - lastBitrate.start;
276
+ lastBitrate.time = this.now() - lastBitrate.start
264
277
  }
265
278
  }
266
279
 
267
- this._onCompletion();
280
+ this.onCompletion()
268
281
  }
269
282
 
270
283
  private onContainerUpdateWhilePlaying() {
271
284
  if (this.container.playback.isPlaying()) {
272
- this._stop('watch');
273
- this.start('watch');
285
+ this.stop(Chronograph.Watch)
286
+ this.start(Chronograph.Watch)
274
287
  }
275
288
  }
276
289
 
277
290
  private onBuffering() {
278
- this._inc('buffering');
279
- this.start('buffering');
280
- this.listenToOnce(this.container, CoreEvents.CONTAINER_STATE_BUFFERFULL, this.onBufferfull);
291
+ this.inc(Counter.Buffering)
292
+ this.start(Chronograph.Buffering)
293
+ this.listenToOnce(
294
+ this.container,
295
+ CoreEvents.CONTAINER_STATE_BUFFERFULL,
296
+ this.onBufferfull,
297
+ )
281
298
  }
282
299
 
283
300
  private onBufferfull() {
284
- this._stop('buffering');
285
- this.listenToOnce(this.container, CoreEvents.CONTAINER_STATE_BUFFERING, this.onBuffering);
301
+ this.stop(Chronograph.Buffering)
302
+ this.listenToOnce(
303
+ this.container,
304
+ CoreEvents.CONTAINER_STATE_BUFFERING,
305
+ this.onBuffering,
306
+ )
286
307
  }
287
308
 
288
309
  private onProgress(progress: TimeProgress) {
289
- this.metrics.extra.buffersize = progress.current * 1000;
290
- }
291
-
292
- private _newMetrics() {
293
- this.metrics = newMetrics();
310
+ this.metrics.extra.buffersize = progress.current * 1000
294
311
  }
295
312
 
296
- private _onCompletion() {
297
- const currentPercentage = this.metrics.extra.watchedPercentage;
298
- const allPercentages = this.completion.watch;
299
- const isCalled = this.completion.calls.indexOf(currentPercentage) !== -1;
300
-
301
- if (allPercentages.indexOf(currentPercentage) !== -1 && !isCalled) {
302
- Log.info(this.name + ' PERCENTAGE_EVENT: ' + currentPercentage);
303
- this.completion.calls.push(currentPercentage);
304
- this.trigger(ClapprStatsEvents.PERCENTAGE_EVENT, currentPercentage);
305
- }
313
+ private onCompletion() {
314
+ // Decide if this is needed
315
+ // const currentPercentage = this.metrics.extra.watchedPercentage;
316
+ // this.trigger(ClapprStatsEvents.PERCENTAGE, currentPercentage);
306
317
  }
307
318
 
308
- private _buildReport() {
309
- this._stop('session');
310
- this.start('session');
311
-
312
- this.metrics.extra.playbackName = this._playbackName;
313
- this.metrics.extra.playbackType = this._playbackType;
319
+ private buildReport() {
320
+ this.stop(Chronograph.Session)
321
+ this.start(Chronograph.Session)
314
322
 
315
- this._calculateBitrates();
316
- this._calculatePercentages();
317
- this._fetchFPS();
318
- this._measureLatency();
319
- this._measureBandwidth();
323
+ this.metrics.extra.playbackName = this.playbackName
324
+ this.metrics.extra.playbackType = this.playbackType
320
325
 
321
- this._onReport(this.metrics);
322
- this.trigger(ClapprStatsEvents.REPORT_EVENT, structuredClone(this.metrics));
326
+ this.calcBitrates()
327
+ this.calcBufferingPercentage()
328
+ // TODO calc FPS properly, e.g., on TIMEUPDATE event
329
+ this.fetchFPS()
330
+ this.trigger(ClapprStatsEvents.REPORT, structuredClone(this.metrics))
323
331
  }
324
332
 
325
- private _fetchFPS() {
333
+ private fetchFPS() {
334
+ // TODO check if the playback and media sources support video, then use the common method
326
335
  // flashls ??? - hls.droppedFramesl hls.stream.bufferLength (seconds)
327
336
  // hls ??? (use the same?)
328
337
  const fetchFPS = {
329
- 'html5_video': this._html5FetchFPS,
330
- 'hls': this._html5FetchFPS,
331
- 'dash_shaka_playback': this._html5FetchFPS
332
- };
338
+ html5_video: this.html5FetchFPS,
339
+ hls: this.html5FetchFPS,
340
+ dash: this.html5FetchFPS,
341
+ }
333
342
 
334
- if (this._playbackName in fetchFPS) {
335
- fetchFPS[this._playbackName as keyof typeof fetchFPS].call(this);
343
+ if (this.playbackName in fetchFPS) {
344
+ fetchFPS[this.playbackName as keyof typeof fetchFPS].call(this)
336
345
  }
337
346
  }
338
347
 
339
- private _calculateBitrates() {
340
- const { bitratesHistory } = this.metrics.extra;
348
+ // TODO sort out
349
+ private calcBitrates() {
350
+ const { bitratesHistory } = this.metrics.extra
341
351
 
342
352
  if (bitratesHistory.length === 0) {
343
- return;
353
+ return
344
354
  }
345
355
 
346
- let totalTime = 0;
347
- let weightedTotal = 0;
356
+ let totalTime = 0
357
+ let weightedTotal = 0
348
358
 
349
359
  for (const { bitrate, time = 0 } of bitratesHistory) {
350
- totalTime += time;
351
- weightedTotal += bitrate * time;
360
+ totalTime += time
361
+ weightedTotal += bitrate * time
352
362
  }
353
- this.metrics.extra.bitrateWeightedMean = weightedTotal / totalTime;
363
+ this.metrics.extra.bitrateWeightedMean = weightedTotal / totalTime
354
364
 
355
- this.metrics.extra.bitrateMostUsed = bitratesHistory.reduce((mostUsed, current) =>
356
- (current.time || 0) > (mostUsed.time || 0) ? current : mostUsed,
365
+ this.metrics.extra.bitrateMostUsed = bitratesHistory.reduce(
366
+ (mostUsed, current) =>
367
+ (current.time || 0) > (mostUsed.time || 0) ? current : mostUsed,
357
368
  { time: 0, bitrate: 0, start: 0, end: 0 },
358
- ).bitrate;
369
+ ).bitrate
359
370
  }
360
371
 
361
- private _calculatePercentages() {
372
+ private calcBufferingPercentage() {
362
373
  if (this.metrics.extra.duration > 0) {
363
- this.metrics.extra.bufferingPercentage = (this.metrics.timers.buffering / this.metrics.extra.duration) * 100;
374
+ this.metrics.extra.bufferingPercentage =
375
+ (this.metrics.chrono.buffering / this.metrics.extra.duration) * 100
364
376
  }
365
377
  }
366
378
 
367
- private _html5FetchFPS() {
368
- const videoTag = this.container.playback.el;
379
+ private html5FetchFPS() {
380
+ const videoTag = this.container.playback.el
369
381
 
370
- const getFirstValidValue = (...args: any[]) => args.find(val => val !== undefined);
382
+ const getFirstValidValue = (...args: any[]) =>
383
+ args.find((val) => val !== undefined)
371
384
 
372
- const decodedFrames = getFirstValidValue(videoTag.webkitDecodedFrameCount, videoTag.mozDecodedFrames, 0);
385
+ const decodedFrames = getFirstValidValue(
386
+ videoTag.webkitDecodedFrameCount,
387
+ videoTag.mozDecodedFrames,
388
+ 0,
389
+ )
373
390
  const droppedFrames = getFirstValidValue(
374
391
  videoTag.webkitDroppedFrameCount,
375
- videoTag.mozParsedFrames && videoTag.mozDecodedFrames ? videoTag.mozParsedFrames - videoTag.mozDecodedFrames : 0,
376
- 0
377
- );
378
- const decodedFramesLastTime = decodedFrames - (this.lastDecodedFramesCount || 0);
379
-
380
- this.metrics.counters.decodedFrames = decodedFrames;
381
- this.metrics.counters.droppedFrames = droppedFrames;
382
- this.metrics.counters.fps = decodedFramesLastTime / (this.runEach / 1000);
383
-
384
- this.lastDecodedFramesCount = decodedFrames;
385
- }
386
-
387
- // originally from https://www.smashingmagazine.com/2011/11/analyzing-network-characteristics-using-javascript-and-the-dom-part-1/
388
- private _measureLatency() {
389
- if (this.uriToMeasureLatency) {
390
- const t: number[] = [];
391
- const n = 2;
392
- let rtt;
393
- const ld = () => {
394
- t.push(this._now());
395
- if (t.length > n) {
396
- done();
397
- } else {
398
- const img = new Image;
399
-
400
- img.onload = ld;
401
- img.src = this.uriToMeasureLatency + '?' + Math.random()
402
- + '=' + this._now();
403
- }
404
- };
405
- const done = () => {
406
- rtt = t[2] - t[1];
407
- this.metrics.timers.latency = rtt;
408
- };
409
-
410
- ld();
411
- }
412
- }
392
+ videoTag.mozParsedFrames && videoTag.mozDecodedFrames
393
+ ? videoTag.mozParsedFrames - videoTag.mozDecodedFrames
394
+ : 0,
395
+ 0,
396
+ )
397
+ const delta = decodedFrames - (this.lastDecodedFramesCount || 0)
413
398
 
414
- // originally from https://www.smashingmagazine.com/2011/11/analyzing-network-characteristics-using-javascript-and-the-dom-part-1/
415
- private _measureBandwidth() {
416
- if (this.urisToMeasureBandwidth && (this.bwMeasureCount % this.runBandwidthTestEvery === 0)) {
417
- let i = 0;
418
-
419
- const ld = (e?: ProgressEvent) => {
420
- if (i > 0) {
421
- const prev = this.urisToMeasureBandwidth[i - 1];
422
- prev.end = this._now();
423
- if (prev.timer !== null) {
424
- clearTimeout(prev.timer);
425
- }
426
- }
427
- if (i >= this.urisToMeasureBandwidth.length || (i > 0 && this.urisToMeasureBandwidth[i - 1].expired)) {
428
- assert(e, 'incorrect invocation in _measureBandwidth');
429
- done(e);
430
- } else {
431
- const xhr = new XMLHttpRequest();
432
-
433
- xhr.open('GET', this.urisToMeasureBandwidth[i].url, true);
434
- xhr.responseType = 'arraybuffer';
435
- xhr.onload = xhr.onabort = ld;
436
- this.urisToMeasureBandwidth[i].start = this._now();
437
- this.urisToMeasureBandwidth[i].timer = setTimeout((j) => {
438
- this.urisToMeasureBandwidth[j].expired = true;
439
- xhr.abort();
440
- }, this.urisToMeasureBandwidth[i].timeout, i);
441
- xhr.send();
442
- }
443
- i++;
444
- };
445
-
446
- const done = (e: ProgressEvent) => {
447
- const timeSpent = (this.urisToMeasureBandwidth[i - 1].end - this.urisToMeasureBandwidth[i - 1].start) / 1000;
448
- const bandwidthBps = (e.loaded * 8) / timeSpent;
449
-
450
- this.metrics.extra.bandwidth = bandwidthBps;
451
- this.urisToMeasureBandwidth.forEach((x) => {
452
- x.start = 0;
453
- x.end = 0;
454
- x.expired = false;
455
- if (x.timer !== null) {
456
- clearTimeout(x.timer);
457
- x.timer = null;
458
- }
459
- });
460
- };
461
-
462
- ld();
463
- }
464
- this.bwMeasureCount++;
399
+ this.metrics.counters.decodedFrames = decodedFrames
400
+ this.metrics.counters.droppedFrames = droppedFrames
401
+ this.metrics.counters.fps = delta / (this.runEach / 1000) // TODO use time delta instead of runEach
402
+
403
+ this.lastDecodedFramesCount = decodedFrames
465
404
  }
466
405
  }
467
-
468
- // ClapprStats.REPORT_EVENT = 'clappr:stats:report';
469
- // ClapprStats.PERCENTAGE_EVENT = 'clappr:stats:percentage';