@gcorevideo/player 2.22.16 → 2.22.17
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.
- package/dist/core.js +6 -8
- package/dist/index.css +1338 -1338
- package/dist/index.js +361 -439
- package/dist/player.d.ts +216 -159
- package/dist/plugins/index.css +1463 -1463
- package/dist/plugins/index.js +354 -427
- package/docs/api/player.clapprstats.exportmetrics.md +1 -1
- package/docs/api/player.clapprstats.md +5 -15
- package/docs/api/player.clapprstatssettings.md +13 -0
- package/docs/api/player.clips.destroy.md +18 -0
- package/docs/api/player.clips.disable.md +18 -0
- package/docs/api/player.clips.enable.md +18 -0
- package/docs/api/player.clips.md +170 -0
- package/docs/api/player.clips.render.md +18 -0
- package/docs/api/player.clips.supportedversion.md +16 -0
- package/docs/api/player.clips.version.md +14 -0
- package/docs/api/player.clipspluginsettings.md +2 -2
- package/docs/api/player.clipspluginsettings.text.md +1 -1
- package/docs/api/player.md +27 -18
- package/docs/api/player.mediacontrol.md +1 -1
- package/docs/api/{player.mediacontrol.getelement.md → player.mediacontrol.mount.md} +20 -7
- package/docs/api/player.mediacontrolleftelement.md +1 -1
- package/docs/api/{player.clapprnerdstats._constructor_.md → player.nerdstats._constructor_.md} +3 -3
- package/docs/api/{player.clapprnerdstats.md → player.nerdstats.md} +5 -5
- package/docs/api/player.qualitylevel.height.md +1 -1
- package/docs/api/player.qualitylevel.level.md +1 -1
- package/docs/api/player.qualitylevel.md +4 -4
- package/docs/api/player.qualitylevel.width.md +1 -1
- package/docs/api/player.timeposition.current.md +1 -1
- package/docs/api/player.timeposition.md +2 -2
- package/docs/api/player.timeposition.total.md +1 -1
- package/docs/api/player.timeprogress.md +6 -4
- package/docs/api/player.timevalue.md +1 -1
- package/lib/index.plugins.d.ts +2 -1
- package/lib/index.plugins.d.ts.map +1 -1
- package/lib/index.plugins.js +2 -1
- package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
- package/lib/playback/dash-playback/DashPlayback.js +5 -7
- package/lib/playback.types.d.ts +22 -9
- package/lib/playback.types.d.ts.map +1 -1
- package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.d.ts +4 -0
- package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.d.ts.map +1 -1
- package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.js +20 -23
- package/lib/plugins/clappr-nerd-stats/NerdStats.d.ts +83 -0
- package/lib/plugins/clappr-nerd-stats/NerdStats.d.ts.map +1 -0
- package/lib/plugins/clappr-nerd-stats/NerdStats.js +339 -0
- package/lib/plugins/clappr-stats/ClapprStats.d.ts +27 -32
- package/lib/plugins/clappr-stats/ClapprStats.d.ts.map +1 -1
- package/lib/plugins/clappr-stats/ClapprStats.js +94 -202
- package/lib/plugins/clappr-stats/types.d.ts +65 -24
- package/lib/plugins/clappr-stats/types.d.ts.map +1 -1
- package/lib/plugins/clappr-stats/types.js +37 -2
- package/lib/plugins/clappr-stats/utils.d.ts.map +1 -1
- package/lib/plugins/clappr-stats/utils.js +1 -2
- package/lib/testUtils.d.ts +2 -1
- package/lib/testUtils.d.ts.map +1 -1
- package/lib/testUtils.js +3 -2
- package/package.json +1 -1
- package/src/index.plugins.ts +2 -1
- package/src/playback/dash-playback/DashPlayback.ts +5 -8
- package/src/playback.types.ts +23 -8
- package/src/plugins/clappr-nerd-stats/{ClapprNerdStats.ts → NerdStats.ts} +25 -30
- package/src/plugins/clappr-stats/ClapprStats.ts +242 -306
- package/src/plugins/clappr-stats/__tests__/ClapprStats.test.ts +133 -0
- package/src/plugins/clappr-stats/types.ts +72 -25
- package/src/plugins/clappr-stats/utils.ts +1 -2
- package/src/plugins/error-screen/__tests__/ErrorScreen.test.ts +3 -4
- package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +1 -0
- package/src/testUtils.ts +3 -2
- package/temp/player.api.json +311 -159
- package/tsconfig.tsbuildinfo +1 -1
- package/docs/api/player.clapprstats.setupdatemetrics.md +0 -56
- package/docs/api/player.clipsplugin.gettext.md +0 -58
- package/docs/api/player.clipsplugin.md +0 -59
|
@@ -1,36 +1,29 @@
|
|
|
1
|
-
import { ContainerPlugin, Events as CoreEvents
|
|
2
|
-
import assert from 'assert';
|
|
1
|
+
import { ContainerPlugin, Events as CoreEvents } from '@clappr/core';
|
|
3
2
|
import { CLAPPR_VERSION } from '../../build.js';
|
|
4
|
-
import { ClapprStatsEvents } from './types.js';
|
|
3
|
+
import { ClapprStatsEvents, Chronograph, Counter } from './types.js';
|
|
5
4
|
import { newMetrics } from './utils.js';
|
|
6
|
-
// TODO: fix
|
|
7
|
-
const updateMetrics = () => { };
|
|
8
5
|
/**
|
|
9
|
-
* `PLUGIN` that
|
|
6
|
+
* `PLUGIN` that measures data about playback, which can be useful for analyzing performance and UX.
|
|
10
7
|
* @beta
|
|
11
8
|
* @remarks
|
|
12
9
|
* This plugin does not render anything and is supposed to be extended or used together with other plugins that actually render something.
|
|
10
|
+
*
|
|
11
|
+
* Configuration options - {@link ClapprStatsSettings}
|
|
12
|
+
*
|
|
13
|
+
* Events - {@link ClapprStatsEvents}
|
|
13
14
|
*/
|
|
14
15
|
export class ClapprStats extends ContainerPlugin {
|
|
15
|
-
|
|
16
|
-
intervalId = null;
|
|
16
|
+
timerId = null;
|
|
17
17
|
lastDecodedFramesCount = 0;
|
|
18
18
|
metrics = newMetrics();
|
|
19
|
-
completion;
|
|
20
|
-
_onReport;
|
|
21
|
-
runBandwidthTestEvery;
|
|
22
|
-
runEach;
|
|
23
19
|
timers = {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
latency: 0,
|
|
20
|
+
[Chronograph.Startup]: 0,
|
|
21
|
+
[Chronograph.Watch]: 0,
|
|
22
|
+
[Chronograph.Pause]: 0,
|
|
23
|
+
[Chronograph.Buffering]: 0,
|
|
24
|
+
[Chronograph.Session]: 0,
|
|
30
25
|
};
|
|
31
|
-
|
|
32
|
-
urisToMeasureBandwidth;
|
|
33
|
-
uriToMeasureLatency;
|
|
26
|
+
runEach;
|
|
34
27
|
/**
|
|
35
28
|
* @internal
|
|
36
29
|
*/
|
|
@@ -43,17 +36,19 @@ export class ClapprStats extends ContainerPlugin {
|
|
|
43
36
|
get supportedVersion() {
|
|
44
37
|
return { min: CLAPPR_VERSION };
|
|
45
38
|
}
|
|
46
|
-
get
|
|
39
|
+
get playbackName() {
|
|
47
40
|
return String(this.container.playback.name || '');
|
|
48
41
|
}
|
|
49
|
-
get
|
|
42
|
+
get playbackType() {
|
|
50
43
|
return this.container.getPlaybackType();
|
|
51
44
|
}
|
|
52
|
-
|
|
53
|
-
const hasPerformanceSupport = window.performance && typeof
|
|
54
|
-
return
|
|
45
|
+
now() {
|
|
46
|
+
const hasPerformanceSupport = window.performance && typeof window.performance.now === 'function';
|
|
47
|
+
return hasPerformanceSupport
|
|
48
|
+
? window.performance.now()
|
|
49
|
+
: new Date().getTime();
|
|
55
50
|
}
|
|
56
|
-
|
|
51
|
+
inc(counter) {
|
|
57
52
|
this.metrics.counters[counter] += 1;
|
|
58
53
|
}
|
|
59
54
|
// _timerHasStarted(timer) {
|
|
@@ -61,34 +56,15 @@ export class ClapprStats extends ContainerPlugin {
|
|
|
61
56
|
// }
|
|
62
57
|
start(timer) {
|
|
63
58
|
// this[`_start${timer}`] = this._now();
|
|
64
|
-
this.timers[timer] = this.
|
|
59
|
+
this.timers[timer] = this.now();
|
|
65
60
|
}
|
|
66
|
-
|
|
61
|
+
stop(timer) {
|
|
67
62
|
// this._metrics.timers[timer] += this._now() - this[`_start${timer}`];
|
|
68
|
-
this.metrics.
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Registers a callback to receive the metrics.
|
|
72
|
-
* @param updateMetricsFn - The callback to receive the metrics
|
|
73
|
-
*/
|
|
74
|
-
setUpdateMetrics(updateMetricsFn) {
|
|
75
|
-
// TODO use events instead
|
|
76
|
-
this.updateFn = updateMetricsFn;
|
|
77
|
-
}
|
|
78
|
-
_defaultReport(metrics) {
|
|
79
|
-
this.updateFn(metrics);
|
|
63
|
+
this.metrics.chrono[timer] += this.now() - this.timers[timer];
|
|
80
64
|
}
|
|
81
65
|
constructor(container) {
|
|
82
66
|
super(container);
|
|
83
67
|
this.runEach = container.options.clapprStats?.runEach ?? 5000;
|
|
84
|
-
this._onReport = container.options.clapprStats?.onReport ?? this._defaultReport;
|
|
85
|
-
this.uriToMeasureLatency = container.options.clapprStats?.uriToMeasureLatency;
|
|
86
|
-
this.urisToMeasureBandwidth = container.options.clapprStats?.urisToMeasureBandwidth;
|
|
87
|
-
this.runBandwidthTestEvery = container.options.clapprStats?.runBandwidthTestEvery ?? 10;
|
|
88
|
-
this.completion = {
|
|
89
|
-
watch: container.options.clapprStats?.onCompletion ?? [],
|
|
90
|
-
calls: []
|
|
91
|
-
};
|
|
92
68
|
}
|
|
93
69
|
/**
|
|
94
70
|
* @internal
|
|
@@ -103,10 +79,10 @@ export class ClapprStats extends ContainerPlugin {
|
|
|
103
79
|
this.listenTo(this.container, CoreEvents.CONTAINER_PAUSE, this.onPause);
|
|
104
80
|
this.listenToOnce(this.container, CoreEvents.CONTAINER_STATE_BUFFERING, this.onBuffering);
|
|
105
81
|
this.listenTo(this.container, CoreEvents.CONTAINER_SEEK, this.onSeek);
|
|
106
|
-
this.listenTo(this.container, CoreEvents.CONTAINER_ERROR, () => this.
|
|
107
|
-
this.listenTo(this.container, CoreEvents.CONTAINER_FULLSCREEN, () => this.
|
|
82
|
+
this.listenTo(this.container, CoreEvents.CONTAINER_ERROR, () => this.inc(Counter.Error));
|
|
83
|
+
this.listenTo(this.container, CoreEvents.CONTAINER_FULLSCREEN, () => this.inc(Counter.Fullscreen));
|
|
108
84
|
this.listenTo(this.container, CoreEvents.CONTAINER_PLAYBACKDVRSTATECHANGED, (dvrInUse) => {
|
|
109
|
-
dvrInUse && this.
|
|
85
|
+
dvrInUse && this.inc(Counter.DvrUsage);
|
|
110
86
|
});
|
|
111
87
|
this.listenTo(this.container.playback, CoreEvents.PLAYBACK_PROGRESS, this.onProgress);
|
|
112
88
|
this.listenTo(this.container.playback, CoreEvents.PLAYBACK_TIMEUPDATE, this.onTimeUpdate);
|
|
@@ -120,67 +96,63 @@ export class ClapprStats extends ContainerPlugin {
|
|
|
120
96
|
}
|
|
121
97
|
/**
|
|
122
98
|
* Returns the collected metrics.
|
|
123
|
-
* @returns
|
|
99
|
+
* @returns Measurements collected so far
|
|
124
100
|
*/
|
|
125
101
|
exportMetrics() {
|
|
126
102
|
return structuredClone(this.metrics);
|
|
127
103
|
}
|
|
128
104
|
onBitrate(newBitrate) {
|
|
129
105
|
const bitrate = newBitrate.bitrate;
|
|
130
|
-
const now = this.
|
|
106
|
+
const now = this.now();
|
|
131
107
|
if (this.metrics.extra.bitratesHistory.length > 0) {
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
108
|
+
const last = this.metrics.extra.bitratesHistory[this.metrics.extra.bitratesHistory.length - 1];
|
|
109
|
+
last.end = now;
|
|
110
|
+
last.time = now - last.start;
|
|
135
111
|
}
|
|
136
|
-
this.metrics.extra.bitratesHistory.push({ start: this.
|
|
137
|
-
this.
|
|
112
|
+
this.metrics.extra.bitratesHistory.push({ start: this.now(), bitrate });
|
|
113
|
+
this.inc(Counter.ChangeLevel);
|
|
138
114
|
}
|
|
139
115
|
stopReporting() {
|
|
140
|
-
this.
|
|
141
|
-
if (this.
|
|
142
|
-
clearInterval(this.
|
|
143
|
-
this.
|
|
116
|
+
this.buildReport();
|
|
117
|
+
if (this.timerId !== null) {
|
|
118
|
+
clearInterval(this.timerId);
|
|
119
|
+
this.timerId = null;
|
|
144
120
|
}
|
|
145
|
-
this._newMetrics();
|
|
146
|
-
// TODO
|
|
147
|
-
// @ts-ignore
|
|
148
|
-
this.stopListening();
|
|
149
|
-
this.bindEvents();
|
|
150
121
|
}
|
|
151
122
|
startTimers() {
|
|
152
|
-
this.
|
|
153
|
-
this.start(
|
|
154
|
-
this.start(
|
|
123
|
+
this.timerId = setInterval(this.buildReport.bind(this), this.runEach);
|
|
124
|
+
this.start(Chronograph.Session);
|
|
125
|
+
this.start(Chronograph.Startup);
|
|
155
126
|
}
|
|
156
127
|
onFirstPlaying() {
|
|
157
128
|
this.listenTo(this.container, CoreEvents.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
|
|
158
|
-
this.start(
|
|
159
|
-
this.
|
|
129
|
+
this.start(Chronograph.Watch);
|
|
130
|
+
this.stop(Chronograph.Startup);
|
|
160
131
|
}
|
|
161
132
|
playAfterPause() {
|
|
162
133
|
this.listenTo(this.container, CoreEvents.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
|
|
163
|
-
this.
|
|
164
|
-
this.start(
|
|
134
|
+
this.stop(Chronograph.Pause);
|
|
135
|
+
this.start(Chronograph.Watch);
|
|
165
136
|
}
|
|
166
137
|
onPlay() {
|
|
167
|
-
this.
|
|
138
|
+
this.inc(Counter.Play);
|
|
168
139
|
}
|
|
169
140
|
onPause() {
|
|
170
|
-
this.
|
|
171
|
-
this.start(
|
|
172
|
-
this.
|
|
141
|
+
this.stop(Chronograph.Watch);
|
|
142
|
+
this.start(Chronograph.Pause);
|
|
143
|
+
this.inc(Counter.Pause);
|
|
173
144
|
this.listenToOnce(this.container, CoreEvents.CONTAINER_PLAY, this.playAfterPause);
|
|
174
145
|
this.stopListening(this.container, CoreEvents.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
|
|
175
146
|
}
|
|
176
147
|
onSeek(e) {
|
|
177
|
-
this.
|
|
148
|
+
this.inc(Counter.Seek);
|
|
178
149
|
this.metrics.extra.watchHistory.push([e * 1000, e * 1000]);
|
|
179
150
|
}
|
|
180
151
|
onTimeUpdate(e) {
|
|
181
152
|
const current = e.current * 1000, total = e.total * 1000, l = this.metrics.extra.watchHistory.length;
|
|
182
153
|
this.metrics.extra.duration = total;
|
|
183
154
|
this.metrics.extra.currentTime = current;
|
|
155
|
+
// TODO what if it's a live stream?
|
|
184
156
|
this.metrics.extra.watchedPercentage = (current / total) * 100;
|
|
185
157
|
if (l === 0) {
|
|
186
158
|
this.metrics.extra.watchHistory.push([current, current]);
|
|
@@ -191,68 +163,60 @@ export class ClapprStats extends ContainerPlugin {
|
|
|
191
163
|
if (this.metrics.extra.bitratesHistory.length > 0) {
|
|
192
164
|
const lastBitrate = this.metrics.extra.bitratesHistory[this.metrics.extra.bitratesHistory.length - 1];
|
|
193
165
|
if (!lastBitrate.end) {
|
|
194
|
-
lastBitrate.time = this.
|
|
166
|
+
lastBitrate.time = this.now() - lastBitrate.start;
|
|
195
167
|
}
|
|
196
168
|
}
|
|
197
|
-
this.
|
|
169
|
+
this.onCompletion();
|
|
198
170
|
}
|
|
199
171
|
onContainerUpdateWhilePlaying() {
|
|
200
172
|
if (this.container.playback.isPlaying()) {
|
|
201
|
-
this.
|
|
202
|
-
this.start(
|
|
173
|
+
this.stop(Chronograph.Watch);
|
|
174
|
+
this.start(Chronograph.Watch);
|
|
203
175
|
}
|
|
204
176
|
}
|
|
205
177
|
onBuffering() {
|
|
206
|
-
this.
|
|
207
|
-
this.start(
|
|
178
|
+
this.inc(Counter.Buffering);
|
|
179
|
+
this.start(Chronograph.Buffering);
|
|
208
180
|
this.listenToOnce(this.container, CoreEvents.CONTAINER_STATE_BUFFERFULL, this.onBufferfull);
|
|
209
181
|
}
|
|
210
182
|
onBufferfull() {
|
|
211
|
-
this.
|
|
183
|
+
this.stop(Chronograph.Buffering);
|
|
212
184
|
this.listenToOnce(this.container, CoreEvents.CONTAINER_STATE_BUFFERING, this.onBuffering);
|
|
213
185
|
}
|
|
214
186
|
onProgress(progress) {
|
|
215
187
|
this.metrics.extra.buffersize = progress.current * 1000;
|
|
216
188
|
}
|
|
217
|
-
|
|
218
|
-
this
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
this.
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
this._calculateBitrates();
|
|
236
|
-
this._calculatePercentages();
|
|
237
|
-
this._fetchFPS();
|
|
238
|
-
this._measureLatency();
|
|
239
|
-
this._measureBandwidth();
|
|
240
|
-
this._onReport(this.metrics);
|
|
241
|
-
this.trigger(ClapprStatsEvents.REPORT_EVENT, structuredClone(this.metrics));
|
|
242
|
-
}
|
|
243
|
-
_fetchFPS() {
|
|
189
|
+
onCompletion() {
|
|
190
|
+
// Decide if this is needed
|
|
191
|
+
// const currentPercentage = this.metrics.extra.watchedPercentage;
|
|
192
|
+
// this.trigger(ClapprStatsEvents.PERCENTAGE, currentPercentage);
|
|
193
|
+
}
|
|
194
|
+
buildReport() {
|
|
195
|
+
this.stop(Chronograph.Session);
|
|
196
|
+
this.start(Chronograph.Session);
|
|
197
|
+
this.metrics.extra.playbackName = this.playbackName;
|
|
198
|
+
this.metrics.extra.playbackType = this.playbackType;
|
|
199
|
+
this.calcBitrates();
|
|
200
|
+
this.calcBufferingPercentage();
|
|
201
|
+
// TODO calc FPS properly, e.g., on TIMEUPDATE event
|
|
202
|
+
this.fetchFPS();
|
|
203
|
+
this.trigger(ClapprStatsEvents.REPORT, structuredClone(this.metrics));
|
|
204
|
+
}
|
|
205
|
+
fetchFPS() {
|
|
206
|
+
// TODO check if the playback and media sources support video, then use the common method
|
|
244
207
|
// flashls ??? - hls.droppedFramesl hls.stream.bufferLength (seconds)
|
|
245
208
|
// hls ??? (use the same?)
|
|
246
209
|
const fetchFPS = {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
210
|
+
html5_video: this.html5FetchFPS,
|
|
211
|
+
hls: this.html5FetchFPS,
|
|
212
|
+
dash: this.html5FetchFPS,
|
|
250
213
|
};
|
|
251
|
-
if (this.
|
|
252
|
-
fetchFPS[this.
|
|
214
|
+
if (this.playbackName in fetchFPS) {
|
|
215
|
+
fetchFPS[this.playbackName].call(this);
|
|
253
216
|
}
|
|
254
217
|
}
|
|
255
|
-
|
|
218
|
+
// TODO sort out
|
|
219
|
+
calcBitrates() {
|
|
256
220
|
const { bitratesHistory } = this.metrics.extra;
|
|
257
221
|
if (bitratesHistory.length === 0) {
|
|
258
222
|
return;
|
|
@@ -266,95 +230,23 @@ export class ClapprStats extends ContainerPlugin {
|
|
|
266
230
|
this.metrics.extra.bitrateWeightedMean = weightedTotal / totalTime;
|
|
267
231
|
this.metrics.extra.bitrateMostUsed = bitratesHistory.reduce((mostUsed, current) => (current.time || 0) > (mostUsed.time || 0) ? current : mostUsed, { time: 0, bitrate: 0, start: 0, end: 0 }).bitrate;
|
|
268
232
|
}
|
|
269
|
-
|
|
233
|
+
calcBufferingPercentage() {
|
|
270
234
|
if (this.metrics.extra.duration > 0) {
|
|
271
|
-
this.metrics.extra.bufferingPercentage =
|
|
235
|
+
this.metrics.extra.bufferingPercentage =
|
|
236
|
+
(this.metrics.chrono.buffering / this.metrics.extra.duration) * 100;
|
|
272
237
|
}
|
|
273
238
|
}
|
|
274
|
-
|
|
239
|
+
html5FetchFPS() {
|
|
275
240
|
const videoTag = this.container.playback.el;
|
|
276
|
-
const getFirstValidValue = (...args) => args.find(val => val !== undefined);
|
|
241
|
+
const getFirstValidValue = (...args) => args.find((val) => val !== undefined);
|
|
277
242
|
const decodedFrames = getFirstValidValue(videoTag.webkitDecodedFrameCount, videoTag.mozDecodedFrames, 0);
|
|
278
|
-
const droppedFrames = getFirstValidValue(videoTag.webkitDroppedFrameCount, videoTag.mozParsedFrames && videoTag.mozDecodedFrames
|
|
279
|
-
|
|
243
|
+
const droppedFrames = getFirstValidValue(videoTag.webkitDroppedFrameCount, videoTag.mozParsedFrames && videoTag.mozDecodedFrames
|
|
244
|
+
? videoTag.mozParsedFrames - videoTag.mozDecodedFrames
|
|
245
|
+
: 0, 0);
|
|
246
|
+
const delta = decodedFrames - (this.lastDecodedFramesCount || 0);
|
|
280
247
|
this.metrics.counters.decodedFrames = decodedFrames;
|
|
281
248
|
this.metrics.counters.droppedFrames = droppedFrames;
|
|
282
|
-
this.metrics.counters.fps =
|
|
249
|
+
this.metrics.counters.fps = delta / (this.runEach / 1000); // TODO use time delta instead of runEach
|
|
283
250
|
this.lastDecodedFramesCount = decodedFrames;
|
|
284
251
|
}
|
|
285
|
-
// originally from https://www.smashingmagazine.com/2011/11/analyzing-network-characteristics-using-javascript-and-the-dom-part-1/
|
|
286
|
-
_measureLatency() {
|
|
287
|
-
if (this.uriToMeasureLatency) {
|
|
288
|
-
const t = [];
|
|
289
|
-
const n = 2;
|
|
290
|
-
let rtt;
|
|
291
|
-
const ld = () => {
|
|
292
|
-
t.push(this._now());
|
|
293
|
-
if (t.length > n) {
|
|
294
|
-
done();
|
|
295
|
-
}
|
|
296
|
-
else {
|
|
297
|
-
const img = new Image;
|
|
298
|
-
img.onload = ld;
|
|
299
|
-
img.src = this.uriToMeasureLatency + '?' + Math.random()
|
|
300
|
-
+ '=' + this._now();
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
const done = () => {
|
|
304
|
-
rtt = t[2] - t[1];
|
|
305
|
-
this.metrics.timers.latency = rtt;
|
|
306
|
-
};
|
|
307
|
-
ld();
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
// originally from https://www.smashingmagazine.com/2011/11/analyzing-network-characteristics-using-javascript-and-the-dom-part-1/
|
|
311
|
-
_measureBandwidth() {
|
|
312
|
-
if (this.urisToMeasureBandwidth && (this.bwMeasureCount % this.runBandwidthTestEvery === 0)) {
|
|
313
|
-
let i = 0;
|
|
314
|
-
const ld = (e) => {
|
|
315
|
-
if (i > 0) {
|
|
316
|
-
const prev = this.urisToMeasureBandwidth[i - 1];
|
|
317
|
-
prev.end = this._now();
|
|
318
|
-
if (prev.timer !== null) {
|
|
319
|
-
clearTimeout(prev.timer);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
if (i >= this.urisToMeasureBandwidth.length || (i > 0 && this.urisToMeasureBandwidth[i - 1].expired)) {
|
|
323
|
-
assert(e, 'incorrect invocation in _measureBandwidth');
|
|
324
|
-
done(e);
|
|
325
|
-
}
|
|
326
|
-
else {
|
|
327
|
-
const xhr = new XMLHttpRequest();
|
|
328
|
-
xhr.open('GET', this.urisToMeasureBandwidth[i].url, true);
|
|
329
|
-
xhr.responseType = 'arraybuffer';
|
|
330
|
-
xhr.onload = xhr.onabort = ld;
|
|
331
|
-
this.urisToMeasureBandwidth[i].start = this._now();
|
|
332
|
-
this.urisToMeasureBandwidth[i].timer = setTimeout((j) => {
|
|
333
|
-
this.urisToMeasureBandwidth[j].expired = true;
|
|
334
|
-
xhr.abort();
|
|
335
|
-
}, this.urisToMeasureBandwidth[i].timeout, i);
|
|
336
|
-
xhr.send();
|
|
337
|
-
}
|
|
338
|
-
i++;
|
|
339
|
-
};
|
|
340
|
-
const done = (e) => {
|
|
341
|
-
const timeSpent = (this.urisToMeasureBandwidth[i - 1].end - this.urisToMeasureBandwidth[i - 1].start) / 1000;
|
|
342
|
-
const bandwidthBps = (e.loaded * 8) / timeSpent;
|
|
343
|
-
this.metrics.extra.bandwidth = bandwidthBps;
|
|
344
|
-
this.urisToMeasureBandwidth.forEach((x) => {
|
|
345
|
-
x.start = 0;
|
|
346
|
-
x.end = 0;
|
|
347
|
-
x.expired = false;
|
|
348
|
-
if (x.timer !== null) {
|
|
349
|
-
clearTimeout(x.timer);
|
|
350
|
-
x.timer = null;
|
|
351
|
-
}
|
|
352
|
-
});
|
|
353
|
-
};
|
|
354
|
-
ld();
|
|
355
|
-
}
|
|
356
|
-
this.bwMeasureCount++;
|
|
357
|
-
}
|
|
358
252
|
}
|
|
359
|
-
// ClapprStats.REPORT_EVENT = 'clappr:stats:report';
|
|
360
|
-
// ClapprStats.PERCENTAGE_EVENT = 'clappr:stats:percentage';
|
|
@@ -1,27 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @beta
|
|
3
|
+
*/
|
|
4
|
+
export declare enum Chronograph {
|
|
5
|
+
Startup = "startup",
|
|
6
|
+
Watch = "watch",
|
|
7
|
+
Pause = "pause",
|
|
8
|
+
Buffering = "buffering",
|
|
9
|
+
Session = "session"
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* @beta
|
|
13
|
+
*/
|
|
14
|
+
export declare enum Counter {
|
|
15
|
+
Play = "play",
|
|
16
|
+
Pause = "pause",
|
|
17
|
+
Error = "error",
|
|
18
|
+
Buffering = "buffering",
|
|
19
|
+
DecodedFrames = "decodedFrames",
|
|
20
|
+
DroppedFrames = "droppedFrames",
|
|
21
|
+
Fps = "fps",
|
|
22
|
+
ChangeLevel = "changeLevel",
|
|
23
|
+
Seek = "seek",
|
|
24
|
+
Fullscreen = "fullscreen",
|
|
25
|
+
DvrUsage = "dvrUsage"
|
|
26
|
+
}
|
|
1
27
|
/**
|
|
2
28
|
* @beta
|
|
3
29
|
*/
|
|
4
30
|
export type Metrics = {
|
|
31
|
+
/**
|
|
32
|
+
* Events count counters
|
|
33
|
+
*/
|
|
5
34
|
counters: {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
35
|
+
/**
|
|
36
|
+
*
|
|
37
|
+
*/
|
|
38
|
+
[Counter.Play]: number;
|
|
39
|
+
[Counter.Pause]: number;
|
|
40
|
+
[Counter.Error]: number;
|
|
41
|
+
[Counter.Buffering]: number;
|
|
42
|
+
[Counter.DecodedFrames]: number;
|
|
43
|
+
[Counter.DroppedFrames]: number;
|
|
44
|
+
[Counter.Fps]: number;
|
|
45
|
+
[Counter.ChangeLevel]: number;
|
|
46
|
+
[Counter.Seek]: number;
|
|
47
|
+
[Counter.Fullscreen]: number;
|
|
48
|
+
[Counter.DvrUsage]: number;
|
|
17
49
|
};
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Time measurements - accumulated duration of time-based activities
|
|
52
|
+
*/
|
|
53
|
+
chrono: {
|
|
54
|
+
/**
|
|
55
|
+
* Time spent in the startup phase
|
|
56
|
+
*/
|
|
57
|
+
[Chronograph.Startup]: number;
|
|
58
|
+
/**
|
|
59
|
+
* Total time spent in the watch phase
|
|
60
|
+
*/
|
|
61
|
+
[Chronograph.Watch]: number;
|
|
62
|
+
/**
|
|
63
|
+
*
|
|
64
|
+
*/
|
|
65
|
+
[Chronograph.Pause]: number;
|
|
66
|
+
[Chronograph.Buffering]: number;
|
|
67
|
+
[Chronograph.Session]: number;
|
|
25
68
|
};
|
|
26
69
|
extra: {
|
|
27
70
|
playbackName: string;
|
|
@@ -48,15 +91,13 @@ export type BitrateTrackRecord = {
|
|
|
48
91
|
time?: number;
|
|
49
92
|
bitrate: number;
|
|
50
93
|
};
|
|
51
|
-
/**
|
|
52
|
-
* @beta
|
|
53
|
-
*/
|
|
54
|
-
export type MetricsUpdateFn = (metrics: Metrics) => void;
|
|
55
94
|
/**
|
|
56
95
|
* @beta
|
|
57
96
|
*/
|
|
58
97
|
export declare enum ClapprStatsEvents {
|
|
59
|
-
|
|
60
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Emitted periodically with current measurements.
|
|
100
|
+
*/
|
|
101
|
+
REPORT = "clappr:stats:report"
|
|
61
102
|
}
|
|
62
103
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/plugins/clappr-stats/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/plugins/clappr-stats/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,oBAAY,WAAW;IACrB,OAAO,YAAY;IACnB,KAAK,UAAU;IACf,KAAK,UAAU;IACf,SAAS,cAAc;IACvB,OAAO,YAAY;CAEpB;AAED;;GAEG;AACH,oBAAY,OAAO;IACjB,IAAI,SAAS;IACb,KAAK,UAAU;IACf,KAAK,UAAU;IACf,SAAS,cAAc;IACvB,aAAa,kBAAkB;IAC/B,aAAa,kBAAkB;IAC/B,GAAG,QAAQ;IACX,WAAW,gBAAgB;IAC3B,IAAI,SAAS;IACb,UAAU,eAAe;IACzB,QAAQ,aAAa;CACtB;AAED;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG;IACpB;;OAEG;IACH,QAAQ,EAAE;QACR;;WAEG;QACH,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QACvB,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QACxB,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QACxB,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAC5B,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAChC,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAChC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QACtB,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QACvB,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAC7B,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;KAC5B,CAAC;IACF;;OAEG;IACH,MAAM,EAAE;QACN;;WAEG;QACH,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAC9B;;WAEG;QACH,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAC5B;;WAEG;QACH,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAC5B,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAChC,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;KAE/B,CAAC;IACF,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;QACrB,eAAe,EAAE,kBAAkB,EAAE,CAAC;QACtC,mBAAmB,EAAE,MAAM,CAAC;QAC5B,eAAe,EAAE,MAAM,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QACtC,iBAAiB,EAAE,MAAM,CAAC;QAC1B,mBAAmB,EAAE,MAAM,CAAC;QAC5B,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB,CAAA;AAED;;GAEG;AACH,oBAAY,iBAAiB;IAC3B;;OAEG;IACH,MAAM,wBAAwB;CAK/B"}
|
|
@@ -1,8 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @beta
|
|
3
|
+
*/
|
|
4
|
+
export var Chronograph;
|
|
5
|
+
(function (Chronograph) {
|
|
6
|
+
Chronograph["Startup"] = "startup";
|
|
7
|
+
Chronograph["Watch"] = "watch";
|
|
8
|
+
Chronograph["Pause"] = "pause";
|
|
9
|
+
Chronograph["Buffering"] = "buffering";
|
|
10
|
+
Chronograph["Session"] = "session";
|
|
11
|
+
// Latency = 'latency',
|
|
12
|
+
})(Chronograph || (Chronograph = {}));
|
|
13
|
+
/**
|
|
14
|
+
* @beta
|
|
15
|
+
*/
|
|
16
|
+
export var Counter;
|
|
17
|
+
(function (Counter) {
|
|
18
|
+
Counter["Play"] = "play";
|
|
19
|
+
Counter["Pause"] = "pause";
|
|
20
|
+
Counter["Error"] = "error";
|
|
21
|
+
Counter["Buffering"] = "buffering";
|
|
22
|
+
Counter["DecodedFrames"] = "decodedFrames";
|
|
23
|
+
Counter["DroppedFrames"] = "droppedFrames";
|
|
24
|
+
Counter["Fps"] = "fps";
|
|
25
|
+
Counter["ChangeLevel"] = "changeLevel";
|
|
26
|
+
Counter["Seek"] = "seek";
|
|
27
|
+
Counter["Fullscreen"] = "fullscreen";
|
|
28
|
+
Counter["DvrUsage"] = "dvrUsage";
|
|
29
|
+
})(Counter || (Counter = {}));
|
|
1
30
|
/**
|
|
2
31
|
* @beta
|
|
3
32
|
*/
|
|
4
33
|
export var ClapprStatsEvents;
|
|
5
34
|
(function (ClapprStatsEvents) {
|
|
6
|
-
|
|
7
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Emitted periodically with current measurements.
|
|
37
|
+
*/
|
|
38
|
+
ClapprStatsEvents["REPORT"] = "clappr:stats:report";
|
|
39
|
+
/**
|
|
40
|
+
* Emitted when the playback reaches a certain percentage of the total duration.
|
|
41
|
+
*/
|
|
42
|
+
// PERCENTAGE = 'clappr:stats:percentage',
|
|
8
43
|
})(ClapprStatsEvents || (ClapprStatsEvents = {}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/plugins/clappr-stats/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC,wBAAgB,UAAU,IAAI,OAAO,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/plugins/clappr-stats/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC,wBAAgB,UAAU,IAAI,OAAO,CAsCpC"}
|
package/lib/testUtils.d.ts
CHANGED
|
@@ -94,9 +94,10 @@ export declare function createMockPlayback(name?: string): Events<string | symbo
|
|
|
94
94
|
switchAudioTrack: import("vitest").Mock<(...args: any[]) => any>;
|
|
95
95
|
trigger: <T extends string | symbol>(event: T, ...args: any[]) => boolean;
|
|
96
96
|
};
|
|
97
|
-
export declare function createMockContainer(playback?: any): Events<string | symbol, any> & {
|
|
97
|
+
export declare function createMockContainer(options?: Record<string, unknown>, playback?: any): Events<string | symbol, any> & {
|
|
98
98
|
el: any;
|
|
99
99
|
playback: any;
|
|
100
|
+
options: Record<string, unknown>;
|
|
100
101
|
$el: any;
|
|
101
102
|
getDuration: import("vitest").Mock<(...args: any[]) => any>;
|
|
102
103
|
getPlugin: import("vitest").Mock<(...args: any[]) => any>;
|
package/lib/testUtils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,YAAY,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,MAAM,MAAM,eAAe,CAAA;AAElC;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,MAAM;IAErC,SAAS,CAAC,OAAO,EAAE,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,GAAG;IAClB,SAAS,CAAC,WAAW,CAAC,EAAE,GAAG;gBAFjB,OAAO,EAAE,GAAG,EACb,IAAI,EAAE,GAAG,EACR,WAAW,CAAC,EAAE,GAAG,YAAA;IAK7B,IAAI,IAAI,WAEP;IAED,OAAO;IAEP,IAAI;IAEJ,KAAK;IAEL,IAAI;IAEJ,OAAO;IAEP,IAAI;IAEJ,cAAc;IAEd,WAAW;IAIX,QAAQ;IAER,OAAO;IAEP,eAAe;IAIf,kBAAkB;IAIlB,cAAc;IAId,qBAAqB;IAIrB,IAAI;IAEJ,MAAM;IAEN,MAAM;IAEN,SAAS;IAET,eAAe;IAIf,WAAW;IAIX,QAAQ;IAIR,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;CAGtC;AAED,wBAAgB,cAAc,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,
|
|
1
|
+
{"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,YAAY,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,MAAM,MAAM,eAAe,CAAA;AAElC;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,MAAM;IAErC,SAAS,CAAC,OAAO,EAAE,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,GAAG;IAClB,SAAS,CAAC,WAAW,CAAC,EAAE,GAAG;gBAFjB,OAAO,EAAE,GAAG,EACb,IAAI,EAAE,GAAG,EACR,WAAW,CAAC,EAAE,GAAG,YAAA;IAK7B,IAAI,IAAI,WAEP;IAED,OAAO;IAEP,IAAI;IAEJ,KAAK;IAEL,IAAI;IAEJ,OAAO;IAEP,IAAI;IAEJ,cAAc;IAEd,WAAW;IAIX,QAAQ;IAER,OAAO;IAEP,eAAe;IAIf,kBAAkB;IAIlB,cAAc;IAId,qBAAqB;IAIrB,IAAI;IAEJ,MAAM;IAEN,MAAM;IAEN,SAAS;IAET,eAAe;IAIf,WAAW;IAIX,QAAQ;IAIR,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;CAGtC;AAED,wBAAgB,cAAc,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,GAAkC;;;;;;;;;;;;;;;;EAqB9C;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkC/C;AAED,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAAE,QAAQ,GAAE,GAA0B;;;;;;;;;;;;;;;EAmB9G;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAc/C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,GAAG,OAY7C"}
|
package/lib/testUtils.js
CHANGED
|
@@ -60,7 +60,7 @@ export class _MockPlayback extends Events {
|
|
|
60
60
|
this.emit(event, ...args);
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
-
export function createMockCore(options = {}, container = createMockContainer()) {
|
|
63
|
+
export function createMockCore(options = {}, container = createMockContainer(options)) {
|
|
64
64
|
const el = document.createElement('div');
|
|
65
65
|
const emitter = new Events();
|
|
66
66
|
return Object.assign(emitter, {
|
|
@@ -128,12 +128,13 @@ export function createMockPlayback(name = 'mock') {
|
|
|
128
128
|
trigger: emitter.emit,
|
|
129
129
|
});
|
|
130
130
|
}
|
|
131
|
-
export function createMockContainer(playback = createMockPlayback()) {
|
|
131
|
+
export function createMockContainer(options = {}, playback = createMockPlayback()) {
|
|
132
132
|
const el = playback.el;
|
|
133
133
|
const emitter = new Events();
|
|
134
134
|
return Object.assign(emitter, {
|
|
135
135
|
el,
|
|
136
136
|
playback,
|
|
137
|
+
options,
|
|
137
138
|
$el: $(el),
|
|
138
139
|
getDuration: vi.fn().mockReturnValue(0),
|
|
139
140
|
getPlugin: vi.fn(),
|