@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
package/dist/index.js
CHANGED
|
@@ -13045,13 +13045,11 @@ class DashPlayback extends BasePlayback {
|
|
|
13045
13045
|
this.getPlaybackType() === Playback.LIVE);
|
|
13046
13046
|
}
|
|
13047
13047
|
_onProgress() {
|
|
13048
|
-
|
|
13049
|
-
|
|
13050
|
-
|
|
13051
|
-
|
|
13052
|
-
|
|
13053
|
-
buffer = this._dash.getDashMetrics().getCurrentBufferLevel('audio');
|
|
13054
|
-
}
|
|
13048
|
+
const buffer =
|
|
13049
|
+
// @ts-expect-error
|
|
13050
|
+
this._dash.getDashMetrics().getCurrentBufferLevel('video') ||
|
|
13051
|
+
// @ts-expect-error
|
|
13052
|
+
this._dash.getDashMetrics().getCurrentBufferLevel('audio');
|
|
13055
13053
|
const progress = {
|
|
13056
13054
|
start: this.getCurrentTime(),
|
|
13057
13055
|
current: this.getCurrentTime() + buffer,
|
|
@@ -43307,7 +43305,7 @@ class Player {
|
|
|
43307
43305
|
}
|
|
43308
43306
|
}
|
|
43309
43307
|
|
|
43310
|
-
var version$1 = "2.22.
|
|
43308
|
+
var version$1 = "2.22.17";
|
|
43311
43309
|
|
|
43312
43310
|
var packages = {
|
|
43313
43311
|
"node_modules/@clappr/core": {
|
|
@@ -43885,6 +43883,339 @@ class BottomGear extends UICorePlugin {
|
|
|
43885
43883
|
}
|
|
43886
43884
|
}
|
|
43887
43885
|
|
|
43886
|
+
/**
|
|
43887
|
+
* @beta
|
|
43888
|
+
*/
|
|
43889
|
+
var Chronograph;
|
|
43890
|
+
(function (Chronograph) {
|
|
43891
|
+
Chronograph["Startup"] = "startup";
|
|
43892
|
+
Chronograph["Watch"] = "watch";
|
|
43893
|
+
Chronograph["Pause"] = "pause";
|
|
43894
|
+
Chronograph["Buffering"] = "buffering";
|
|
43895
|
+
Chronograph["Session"] = "session";
|
|
43896
|
+
// Latency = 'latency',
|
|
43897
|
+
})(Chronograph || (Chronograph = {}));
|
|
43898
|
+
/**
|
|
43899
|
+
* @beta
|
|
43900
|
+
*/
|
|
43901
|
+
var Counter;
|
|
43902
|
+
(function (Counter) {
|
|
43903
|
+
Counter["Play"] = "play";
|
|
43904
|
+
Counter["Pause"] = "pause";
|
|
43905
|
+
Counter["Error"] = "error";
|
|
43906
|
+
Counter["Buffering"] = "buffering";
|
|
43907
|
+
Counter["DecodedFrames"] = "decodedFrames";
|
|
43908
|
+
Counter["DroppedFrames"] = "droppedFrames";
|
|
43909
|
+
Counter["Fps"] = "fps";
|
|
43910
|
+
Counter["ChangeLevel"] = "changeLevel";
|
|
43911
|
+
Counter["Seek"] = "seek";
|
|
43912
|
+
Counter["Fullscreen"] = "fullscreen";
|
|
43913
|
+
Counter["DvrUsage"] = "dvrUsage";
|
|
43914
|
+
})(Counter || (Counter = {}));
|
|
43915
|
+
/**
|
|
43916
|
+
* @beta
|
|
43917
|
+
*/
|
|
43918
|
+
var ClapprStatsEvents;
|
|
43919
|
+
(function (ClapprStatsEvents) {
|
|
43920
|
+
/**
|
|
43921
|
+
* Emitted periodically with current measurements.
|
|
43922
|
+
*/
|
|
43923
|
+
ClapprStatsEvents["REPORT"] = "clappr:stats:report";
|
|
43924
|
+
/**
|
|
43925
|
+
* Emitted when the playback reaches a certain percentage of the total duration.
|
|
43926
|
+
*/
|
|
43927
|
+
// PERCENTAGE = 'clappr:stats:percentage',
|
|
43928
|
+
})(ClapprStatsEvents || (ClapprStatsEvents = {}));
|
|
43929
|
+
|
|
43930
|
+
function newMetrics$1() {
|
|
43931
|
+
return {
|
|
43932
|
+
counters: {
|
|
43933
|
+
play: 0,
|
|
43934
|
+
pause: 0,
|
|
43935
|
+
error: 0,
|
|
43936
|
+
buffering: 0,
|
|
43937
|
+
decodedFrames: 0,
|
|
43938
|
+
droppedFrames: 0,
|
|
43939
|
+
fps: 0,
|
|
43940
|
+
changeLevel: 0,
|
|
43941
|
+
seek: 0,
|
|
43942
|
+
fullscreen: 0,
|
|
43943
|
+
dvrUsage: 0,
|
|
43944
|
+
},
|
|
43945
|
+
chrono: {
|
|
43946
|
+
startup: 0,
|
|
43947
|
+
watch: 0,
|
|
43948
|
+
pause: 0,
|
|
43949
|
+
buffering: 0,
|
|
43950
|
+
session: 0,
|
|
43951
|
+
},
|
|
43952
|
+
extra: {
|
|
43953
|
+
playbackName: '',
|
|
43954
|
+
playbackType: '',
|
|
43955
|
+
bitratesHistory: [],
|
|
43956
|
+
bitrateWeightedMean: 0,
|
|
43957
|
+
bitrateMostUsed: 0,
|
|
43958
|
+
buffersize: 0,
|
|
43959
|
+
watchHistory: [],
|
|
43960
|
+
watchedPercentage: 0,
|
|
43961
|
+
bufferingPercentage: 0,
|
|
43962
|
+
bandwidth: 0,
|
|
43963
|
+
duration: 0,
|
|
43964
|
+
currentTime: 0,
|
|
43965
|
+
},
|
|
43966
|
+
custom: {},
|
|
43967
|
+
};
|
|
43968
|
+
}
|
|
43969
|
+
|
|
43970
|
+
/**
|
|
43971
|
+
* `PLUGIN` that measures data about playback, which can be useful for analyzing performance and UX.
|
|
43972
|
+
* @beta
|
|
43973
|
+
* @remarks
|
|
43974
|
+
* This plugin does not render anything and is supposed to be extended or used together with other plugins that actually render something.
|
|
43975
|
+
*
|
|
43976
|
+
* Configuration options - {@link ClapprStatsSettings}
|
|
43977
|
+
*
|
|
43978
|
+
* Events - {@link ClapprStatsEvents}
|
|
43979
|
+
*/
|
|
43980
|
+
class ClapprStats extends ContainerPlugin {
|
|
43981
|
+
timerId = null;
|
|
43982
|
+
lastDecodedFramesCount = 0;
|
|
43983
|
+
metrics = newMetrics$1();
|
|
43984
|
+
timers = {
|
|
43985
|
+
[Chronograph.Startup]: 0,
|
|
43986
|
+
[Chronograph.Watch]: 0,
|
|
43987
|
+
[Chronograph.Pause]: 0,
|
|
43988
|
+
[Chronograph.Buffering]: 0,
|
|
43989
|
+
[Chronograph.Session]: 0,
|
|
43990
|
+
};
|
|
43991
|
+
runEach;
|
|
43992
|
+
/**
|
|
43993
|
+
* @internal
|
|
43994
|
+
*/
|
|
43995
|
+
get name() {
|
|
43996
|
+
return 'clappr_stats';
|
|
43997
|
+
}
|
|
43998
|
+
/**
|
|
43999
|
+
* @internal
|
|
44000
|
+
*/
|
|
44001
|
+
get supportedVersion() {
|
|
44002
|
+
return { min: CLAPPR_VERSION$1 };
|
|
44003
|
+
}
|
|
44004
|
+
get playbackName() {
|
|
44005
|
+
return String(this.container.playback.name || '');
|
|
44006
|
+
}
|
|
44007
|
+
get playbackType() {
|
|
44008
|
+
return this.container.getPlaybackType();
|
|
44009
|
+
}
|
|
44010
|
+
now() {
|
|
44011
|
+
const hasPerformanceSupport = window.performance && typeof window.performance.now === 'function';
|
|
44012
|
+
return hasPerformanceSupport
|
|
44013
|
+
? window.performance.now()
|
|
44014
|
+
: new Date().getTime();
|
|
44015
|
+
}
|
|
44016
|
+
inc(counter) {
|
|
44017
|
+
this.metrics.counters[counter] += 1;
|
|
44018
|
+
}
|
|
44019
|
+
// _timerHasStarted(timer) {
|
|
44020
|
+
// return this[`_start${timer}`] !== undefined;
|
|
44021
|
+
// }
|
|
44022
|
+
start(timer) {
|
|
44023
|
+
// this[`_start${timer}`] = this._now();
|
|
44024
|
+
this.timers[timer] = this.now();
|
|
44025
|
+
}
|
|
44026
|
+
stop(timer) {
|
|
44027
|
+
// this._metrics.timers[timer] += this._now() - this[`_start${timer}`];
|
|
44028
|
+
this.metrics.chrono[timer] += this.now() - this.timers[timer];
|
|
44029
|
+
}
|
|
44030
|
+
constructor(container) {
|
|
44031
|
+
super(container);
|
|
44032
|
+
this.runEach = container.options.clapprStats?.runEach ?? 5000;
|
|
44033
|
+
}
|
|
44034
|
+
/**
|
|
44035
|
+
* @internal
|
|
44036
|
+
*/
|
|
44037
|
+
bindEvents() {
|
|
44038
|
+
this.listenTo(this.container, Events$1.CONTAINER_BITRATE, this.onBitrate);
|
|
44039
|
+
this.listenTo(this.container, Events$1.CONTAINER_STOP, this.stopReporting);
|
|
44040
|
+
this.listenTo(this.container, Events$1.CONTAINER_ENDED, this.stopReporting);
|
|
44041
|
+
this.listenToOnce(this.container.playback, Events$1.PLAYBACK_PLAY_INTENT, this.startTimers);
|
|
44042
|
+
this.listenToOnce(this.container, Events$1.CONTAINER_PLAY, this.onFirstPlaying);
|
|
44043
|
+
this.listenTo(this.container, Events$1.CONTAINER_PLAY, this.onPlay);
|
|
44044
|
+
this.listenTo(this.container, Events$1.CONTAINER_PAUSE, this.onPause);
|
|
44045
|
+
this.listenToOnce(this.container, Events$1.CONTAINER_STATE_BUFFERING, this.onBuffering);
|
|
44046
|
+
this.listenTo(this.container, Events$1.CONTAINER_SEEK, this.onSeek);
|
|
44047
|
+
this.listenTo(this.container, Events$1.CONTAINER_ERROR, () => this.inc(Counter.Error));
|
|
44048
|
+
this.listenTo(this.container, Events$1.CONTAINER_FULLSCREEN, () => this.inc(Counter.Fullscreen));
|
|
44049
|
+
this.listenTo(this.container, Events$1.CONTAINER_PLAYBACKDVRSTATECHANGED, (dvrInUse) => {
|
|
44050
|
+
dvrInUse && this.inc(Counter.DvrUsage);
|
|
44051
|
+
});
|
|
44052
|
+
this.listenTo(this.container.playback, Events$1.PLAYBACK_PROGRESS, this.onProgress);
|
|
44053
|
+
this.listenTo(this.container.playback, Events$1.PLAYBACK_TIMEUPDATE, this.onTimeUpdate);
|
|
44054
|
+
}
|
|
44055
|
+
/**
|
|
44056
|
+
* @internal
|
|
44057
|
+
*/
|
|
44058
|
+
destroy() {
|
|
44059
|
+
this.stopReporting();
|
|
44060
|
+
super.destroy();
|
|
44061
|
+
}
|
|
44062
|
+
/**
|
|
44063
|
+
* Returns the collected metrics.
|
|
44064
|
+
* @returns Measurements collected so far
|
|
44065
|
+
*/
|
|
44066
|
+
exportMetrics() {
|
|
44067
|
+
return structuredClone(this.metrics);
|
|
44068
|
+
}
|
|
44069
|
+
onBitrate(newBitrate) {
|
|
44070
|
+
const bitrate = newBitrate.bitrate;
|
|
44071
|
+
const now = this.now();
|
|
44072
|
+
if (this.metrics.extra.bitratesHistory.length > 0) {
|
|
44073
|
+
const last = this.metrics.extra.bitratesHistory[this.metrics.extra.bitratesHistory.length - 1];
|
|
44074
|
+
last.end = now;
|
|
44075
|
+
last.time = now - last.start;
|
|
44076
|
+
}
|
|
44077
|
+
this.metrics.extra.bitratesHistory.push({ start: this.now(), bitrate });
|
|
44078
|
+
this.inc(Counter.ChangeLevel);
|
|
44079
|
+
}
|
|
44080
|
+
stopReporting() {
|
|
44081
|
+
this.buildReport();
|
|
44082
|
+
if (this.timerId !== null) {
|
|
44083
|
+
clearInterval(this.timerId);
|
|
44084
|
+
this.timerId = null;
|
|
44085
|
+
}
|
|
44086
|
+
}
|
|
44087
|
+
startTimers() {
|
|
44088
|
+
this.timerId = setInterval(this.buildReport.bind(this), this.runEach);
|
|
44089
|
+
this.start(Chronograph.Session);
|
|
44090
|
+
this.start(Chronograph.Startup);
|
|
44091
|
+
}
|
|
44092
|
+
onFirstPlaying() {
|
|
44093
|
+
this.listenTo(this.container, Events$1.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
|
|
44094
|
+
this.start(Chronograph.Watch);
|
|
44095
|
+
this.stop(Chronograph.Startup);
|
|
44096
|
+
}
|
|
44097
|
+
playAfterPause() {
|
|
44098
|
+
this.listenTo(this.container, Events$1.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
|
|
44099
|
+
this.stop(Chronograph.Pause);
|
|
44100
|
+
this.start(Chronograph.Watch);
|
|
44101
|
+
}
|
|
44102
|
+
onPlay() {
|
|
44103
|
+
this.inc(Counter.Play);
|
|
44104
|
+
}
|
|
44105
|
+
onPause() {
|
|
44106
|
+
this.stop(Chronograph.Watch);
|
|
44107
|
+
this.start(Chronograph.Pause);
|
|
44108
|
+
this.inc(Counter.Pause);
|
|
44109
|
+
this.listenToOnce(this.container, Events$1.CONTAINER_PLAY, this.playAfterPause);
|
|
44110
|
+
this.stopListening(this.container, Events$1.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
|
|
44111
|
+
}
|
|
44112
|
+
onSeek(e) {
|
|
44113
|
+
this.inc(Counter.Seek);
|
|
44114
|
+
this.metrics.extra.watchHistory.push([e * 1000, e * 1000]);
|
|
44115
|
+
}
|
|
44116
|
+
onTimeUpdate(e) {
|
|
44117
|
+
const current = e.current * 1000, total = e.total * 1000, l = this.metrics.extra.watchHistory.length;
|
|
44118
|
+
this.metrics.extra.duration = total;
|
|
44119
|
+
this.metrics.extra.currentTime = current;
|
|
44120
|
+
// TODO what if it's a live stream?
|
|
44121
|
+
this.metrics.extra.watchedPercentage = (current / total) * 100;
|
|
44122
|
+
if (l === 0) {
|
|
44123
|
+
this.metrics.extra.watchHistory.push([current, current]);
|
|
44124
|
+
}
|
|
44125
|
+
else {
|
|
44126
|
+
this.metrics.extra.watchHistory[l - 1][1] = current;
|
|
44127
|
+
}
|
|
44128
|
+
if (this.metrics.extra.bitratesHistory.length > 0) {
|
|
44129
|
+
const lastBitrate = this.metrics.extra.bitratesHistory[this.metrics.extra.bitratesHistory.length - 1];
|
|
44130
|
+
if (!lastBitrate.end) {
|
|
44131
|
+
lastBitrate.time = this.now() - lastBitrate.start;
|
|
44132
|
+
}
|
|
44133
|
+
}
|
|
44134
|
+
this.onCompletion();
|
|
44135
|
+
}
|
|
44136
|
+
onContainerUpdateWhilePlaying() {
|
|
44137
|
+
if (this.container.playback.isPlaying()) {
|
|
44138
|
+
this.stop(Chronograph.Watch);
|
|
44139
|
+
this.start(Chronograph.Watch);
|
|
44140
|
+
}
|
|
44141
|
+
}
|
|
44142
|
+
onBuffering() {
|
|
44143
|
+
this.inc(Counter.Buffering);
|
|
44144
|
+
this.start(Chronograph.Buffering);
|
|
44145
|
+
this.listenToOnce(this.container, Events$1.CONTAINER_STATE_BUFFERFULL, this.onBufferfull);
|
|
44146
|
+
}
|
|
44147
|
+
onBufferfull() {
|
|
44148
|
+
this.stop(Chronograph.Buffering);
|
|
44149
|
+
this.listenToOnce(this.container, Events$1.CONTAINER_STATE_BUFFERING, this.onBuffering);
|
|
44150
|
+
}
|
|
44151
|
+
onProgress(progress) {
|
|
44152
|
+
this.metrics.extra.buffersize = progress.current * 1000;
|
|
44153
|
+
}
|
|
44154
|
+
onCompletion() {
|
|
44155
|
+
// Decide if this is needed
|
|
44156
|
+
// const currentPercentage = this.metrics.extra.watchedPercentage;
|
|
44157
|
+
// this.trigger(ClapprStatsEvents.PERCENTAGE, currentPercentage);
|
|
44158
|
+
}
|
|
44159
|
+
buildReport() {
|
|
44160
|
+
this.stop(Chronograph.Session);
|
|
44161
|
+
this.start(Chronograph.Session);
|
|
44162
|
+
this.metrics.extra.playbackName = this.playbackName;
|
|
44163
|
+
this.metrics.extra.playbackType = this.playbackType;
|
|
44164
|
+
this.calcBitrates();
|
|
44165
|
+
this.calcBufferingPercentage();
|
|
44166
|
+
// TODO calc FPS properly, e.g., on TIMEUPDATE event
|
|
44167
|
+
this.fetchFPS();
|
|
44168
|
+
this.trigger(ClapprStatsEvents.REPORT, structuredClone(this.metrics));
|
|
44169
|
+
}
|
|
44170
|
+
fetchFPS() {
|
|
44171
|
+
// TODO check if the playback and media sources support video, then use the common method
|
|
44172
|
+
// flashls ??? - hls.droppedFramesl hls.stream.bufferLength (seconds)
|
|
44173
|
+
// hls ??? (use the same?)
|
|
44174
|
+
const fetchFPS = {
|
|
44175
|
+
html5_video: this.html5FetchFPS,
|
|
44176
|
+
hls: this.html5FetchFPS,
|
|
44177
|
+
dash: this.html5FetchFPS,
|
|
44178
|
+
};
|
|
44179
|
+
if (this.playbackName in fetchFPS) {
|
|
44180
|
+
fetchFPS[this.playbackName].call(this);
|
|
44181
|
+
}
|
|
44182
|
+
}
|
|
44183
|
+
// TODO sort out
|
|
44184
|
+
calcBitrates() {
|
|
44185
|
+
const { bitratesHistory } = this.metrics.extra;
|
|
44186
|
+
if (bitratesHistory.length === 0) {
|
|
44187
|
+
return;
|
|
44188
|
+
}
|
|
44189
|
+
let totalTime = 0;
|
|
44190
|
+
let weightedTotal = 0;
|
|
44191
|
+
for (const { bitrate, time = 0 } of bitratesHistory) {
|
|
44192
|
+
totalTime += time;
|
|
44193
|
+
weightedTotal += bitrate * time;
|
|
44194
|
+
}
|
|
44195
|
+
this.metrics.extra.bitrateWeightedMean = weightedTotal / totalTime;
|
|
44196
|
+
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;
|
|
44197
|
+
}
|
|
44198
|
+
calcBufferingPercentage() {
|
|
44199
|
+
if (this.metrics.extra.duration > 0) {
|
|
44200
|
+
this.metrics.extra.bufferingPercentage =
|
|
44201
|
+
(this.metrics.chrono.buffering / this.metrics.extra.duration) * 100;
|
|
44202
|
+
}
|
|
44203
|
+
}
|
|
44204
|
+
html5FetchFPS() {
|
|
44205
|
+
const videoTag = this.container.playback.el;
|
|
44206
|
+
const getFirstValidValue = (...args) => args.find((val) => val !== undefined);
|
|
44207
|
+
const decodedFrames = getFirstValidValue(videoTag.webkitDecodedFrameCount, videoTag.mozDecodedFrames, 0);
|
|
44208
|
+
const droppedFrames = getFirstValidValue(videoTag.webkitDroppedFrameCount, videoTag.mozParsedFrames && videoTag.mozDecodedFrames
|
|
44209
|
+
? videoTag.mozParsedFrames - videoTag.mozDecodedFrames
|
|
44210
|
+
: 0, 0);
|
|
44211
|
+
const delta = decodedFrames - (this.lastDecodedFramesCount || 0);
|
|
44212
|
+
this.metrics.counters.decodedFrames = decodedFrames;
|
|
44213
|
+
this.metrics.counters.droppedFrames = droppedFrames;
|
|
44214
|
+
this.metrics.counters.fps = delta / (this.runEach / 1000); // TODO use time delta instead of runEach
|
|
44215
|
+
this.lastDecodedFramesCount = decodedFrames;
|
|
44216
|
+
}
|
|
44217
|
+
}
|
|
44218
|
+
|
|
43888
44219
|
var mousetrap = {exports: {}};
|
|
43889
44220
|
|
|
43890
44221
|
/*global define:false */
|
|
@@ -44952,56 +45283,6 @@ function requireMousetrap () {
|
|
|
44952
45283
|
var mousetrapExports = requireMousetrap();
|
|
44953
45284
|
const Mousetrap = /*@__PURE__*/getDefaultExportFromCjs$1(mousetrapExports);
|
|
44954
45285
|
|
|
44955
|
-
/**
|
|
44956
|
-
* @beta
|
|
44957
|
-
*/
|
|
44958
|
-
var ClapprStatsEvents;
|
|
44959
|
-
(function (ClapprStatsEvents) {
|
|
44960
|
-
ClapprStatsEvents["REPORT_EVENT"] = "clappr:stats:report";
|
|
44961
|
-
ClapprStatsEvents["PERCENTAGE_EVENT"] = "clappr:stats:percentage";
|
|
44962
|
-
})(ClapprStatsEvents || (ClapprStatsEvents = {}));
|
|
44963
|
-
|
|
44964
|
-
function newMetrics$1() {
|
|
44965
|
-
return {
|
|
44966
|
-
counters: {
|
|
44967
|
-
play: 0,
|
|
44968
|
-
pause: 0,
|
|
44969
|
-
error: 0,
|
|
44970
|
-
buffering: 0,
|
|
44971
|
-
decodedFrames: 0,
|
|
44972
|
-
droppedFrames: 0,
|
|
44973
|
-
fps: 0,
|
|
44974
|
-
changeLevel: 0,
|
|
44975
|
-
seek: 0,
|
|
44976
|
-
fullscreen: 0,
|
|
44977
|
-
dvrUsage: 0,
|
|
44978
|
-
},
|
|
44979
|
-
timers: {
|
|
44980
|
-
startup: 0,
|
|
44981
|
-
watch: 0,
|
|
44982
|
-
pause: 0,
|
|
44983
|
-
buffering: 0,
|
|
44984
|
-
session: 0,
|
|
44985
|
-
latency: 0,
|
|
44986
|
-
},
|
|
44987
|
-
extra: {
|
|
44988
|
-
playbackName: '',
|
|
44989
|
-
playbackType: '',
|
|
44990
|
-
bitratesHistory: [],
|
|
44991
|
-
bitrateWeightedMean: 0,
|
|
44992
|
-
bitrateMostUsed: 0,
|
|
44993
|
-
buffersize: 0,
|
|
44994
|
-
watchHistory: [],
|
|
44995
|
-
watchedPercentage: 0,
|
|
44996
|
-
bufferingPercentage: 0,
|
|
44997
|
-
bandwidth: 0,
|
|
44998
|
-
duration: 0,
|
|
44999
|
-
currentTime: 0,
|
|
45000
|
-
},
|
|
45001
|
-
custom: {},
|
|
45002
|
-
};
|
|
45003
|
-
}
|
|
45004
|
-
|
|
45005
45286
|
var humanFormat$2 = {exports: {}};
|
|
45006
45287
|
|
|
45007
45288
|
var humanFormat$1 = humanFormat$2.exports;
|
|
@@ -46026,7 +46307,7 @@ const drawSummary = (customMetrics, vodContainer, liveContainer) => {
|
|
|
46026
46307
|
vodContainer.html(vodHtml);
|
|
46027
46308
|
liveContainer.html(liveHtml);
|
|
46028
46309
|
};
|
|
46029
|
-
const T$f = 'plugins.
|
|
46310
|
+
const T$f = 'plugins.nerd_stats';
|
|
46030
46311
|
/**
|
|
46031
46312
|
* `PLUGIN` that displays useful network-related statistics.
|
|
46032
46313
|
* @beta
|
|
@@ -46043,7 +46324,7 @@ const T$f = 'plugins.clappr_nerd_stats';
|
|
|
46043
46324
|
* When clicked, it shows an overlay window with the information about the network speed, latency, etc,
|
|
46044
46325
|
* and recommended quality level.
|
|
46045
46326
|
*/
|
|
46046
|
-
class
|
|
46327
|
+
class NerdStats extends UICorePlugin {
|
|
46047
46328
|
container = null;
|
|
46048
46329
|
customMetrics = {
|
|
46049
46330
|
connectionSpeed: 0,
|
|
@@ -46126,32 +46407,29 @@ class ClapprNerdStats extends UICorePlugin {
|
|
|
46126
46407
|
this.listenTo(bottomGear, GearEvents.RENDERED, this.addToBottomGear);
|
|
46127
46408
|
this.container = this.core.activeContainer;
|
|
46128
46409
|
const clapprStats = this.container?.getPlugin('clappr_stats');
|
|
46129
|
-
|
|
46130
|
-
|
|
46131
|
-
|
|
46132
|
-
|
|
46133
|
-
|
|
46134
|
-
|
|
46135
|
-
|
|
46136
|
-
}
|
|
46137
|
-
else {
|
|
46138
|
-
Mousetrap.bind(this.shortcut, () => this.toggle());
|
|
46139
|
-
this.listenTo(this.core, Events$1.CORE_RESIZE, this.onPlayerResize);
|
|
46140
|
-
// TODO: fix
|
|
46141
|
-
this.listenTo(clapprStats, ClapprStatsEvents.REPORT_EVENT, this.updateMetrics);
|
|
46142
|
-
clapprStats.setUpdateMetrics(this.updateMetrics.bind(this));
|
|
46143
|
-
this.updateMetrics(clapprStats.exportMetrics());
|
|
46144
|
-
this.render();
|
|
46145
|
-
}
|
|
46410
|
+
assert(clapprStats, 'clappr-stats not available. Please, include it as a plugin of your Clappr instance.\n' +
|
|
46411
|
+
'For more info, visit: https://github.com/clappr/clappr-stats.');
|
|
46412
|
+
Mousetrap.bind(this.shortcut, this.toggle);
|
|
46413
|
+
this.listenTo(this.core, Events$1.CORE_RESIZE, this.onPlayerResize);
|
|
46414
|
+
this.listenTo(clapprStats, ClapprStatsEvents.REPORT, this.updateMetrics);
|
|
46415
|
+
this.updateMetrics(clapprStats.exportMetrics());
|
|
46416
|
+
this.render();
|
|
46146
46417
|
}
|
|
46147
|
-
|
|
46418
|
+
/**
|
|
46419
|
+
* @internal
|
|
46420
|
+
*/
|
|
46421
|
+
destroy() {
|
|
46422
|
+
Mousetrap.unbind(this.shortcut);
|
|
46423
|
+
return super.destroy();
|
|
46424
|
+
}
|
|
46425
|
+
toggle = () => {
|
|
46148
46426
|
if (this.showing) {
|
|
46149
46427
|
this.hide();
|
|
46150
46428
|
}
|
|
46151
46429
|
else {
|
|
46152
46430
|
this.show();
|
|
46153
46431
|
}
|
|
46154
|
-
}
|
|
46432
|
+
};
|
|
46155
46433
|
show() {
|
|
46156
46434
|
this.core.$el.find(this.statsBoxElem).show();
|
|
46157
46435
|
this.showing = true;
|
|
@@ -46209,7 +46487,7 @@ class ClapprNerdStats extends UICorePlugin {
|
|
|
46209
46487
|
this.addGeneralMetrics();
|
|
46210
46488
|
this.addCustomMetrics();
|
|
46211
46489
|
const scrollTop = this.core.$el.find(this.statsBoxElem).scrollTop();
|
|
46212
|
-
this.$el.html(
|
|
46490
|
+
this.$el.html(NerdStats.template({
|
|
46213
46491
|
metrics: Formatter.format(this.metrics),
|
|
46214
46492
|
iconPosition: this.iconPosition,
|
|
46215
46493
|
}));
|
|
@@ -46245,8 +46523,8 @@ class ClapprNerdStats extends UICorePlugin {
|
|
|
46245
46523
|
trace(`${T$f} addToBottomGear`);
|
|
46246
46524
|
const gear = this.core.getPlugin('bottom_gear');
|
|
46247
46525
|
gear
|
|
46248
|
-
.addItem('
|
|
46249
|
-
.html(
|
|
46526
|
+
.addItem('nerd_stats')
|
|
46527
|
+
.html(NerdStats.buttonTemplate({
|
|
46250
46528
|
icon: statsIcon,
|
|
46251
46529
|
i18n: this.core.i18n,
|
|
46252
46530
|
}))
|
|
@@ -46288,362 +46566,6 @@ function newMetrics() {
|
|
|
46288
46566
|
};
|
|
46289
46567
|
}
|
|
46290
46568
|
|
|
46291
|
-
// TODO: fix
|
|
46292
|
-
const updateMetrics = () => { };
|
|
46293
|
-
/**
|
|
46294
|
-
* `PLUGIN` that collects useful statistics about playback performance.
|
|
46295
|
-
* @beta
|
|
46296
|
-
* @remarks
|
|
46297
|
-
* This plugin does not render anything and is supposed to be extended or used together with other plugins that actually render something.
|
|
46298
|
-
*/
|
|
46299
|
-
class ClapprStats extends ContainerPlugin {
|
|
46300
|
-
bwMeasureCount = 0;
|
|
46301
|
-
intervalId = null;
|
|
46302
|
-
lastDecodedFramesCount = 0;
|
|
46303
|
-
metrics = newMetrics$1();
|
|
46304
|
-
completion;
|
|
46305
|
-
_onReport;
|
|
46306
|
-
runBandwidthTestEvery;
|
|
46307
|
-
runEach;
|
|
46308
|
-
timers = {
|
|
46309
|
-
startup: 0,
|
|
46310
|
-
watch: 0,
|
|
46311
|
-
pause: 0,
|
|
46312
|
-
buffering: 0,
|
|
46313
|
-
session: 0,
|
|
46314
|
-
latency: 0,
|
|
46315
|
-
};
|
|
46316
|
-
updateFn = updateMetrics;
|
|
46317
|
-
urisToMeasureBandwidth;
|
|
46318
|
-
uriToMeasureLatency;
|
|
46319
|
-
/**
|
|
46320
|
-
* @internal
|
|
46321
|
-
*/
|
|
46322
|
-
get name() {
|
|
46323
|
-
return 'clappr_stats';
|
|
46324
|
-
}
|
|
46325
|
-
/**
|
|
46326
|
-
* @internal
|
|
46327
|
-
*/
|
|
46328
|
-
get supportedVersion() {
|
|
46329
|
-
return { min: CLAPPR_VERSION$1 };
|
|
46330
|
-
}
|
|
46331
|
-
get _playbackName() {
|
|
46332
|
-
return String(this.container.playback.name || '');
|
|
46333
|
-
}
|
|
46334
|
-
get _playbackType() {
|
|
46335
|
-
return this.container.getPlaybackType();
|
|
46336
|
-
}
|
|
46337
|
-
_now() {
|
|
46338
|
-
const hasPerformanceSupport = window.performance && typeof (window.performance.now) === 'function';
|
|
46339
|
-
return (hasPerformanceSupport) ? window.performance.now() : new Date().getTime();
|
|
46340
|
-
}
|
|
46341
|
-
_inc(counter) {
|
|
46342
|
-
this.metrics.counters[counter] += 1;
|
|
46343
|
-
}
|
|
46344
|
-
// _timerHasStarted(timer) {
|
|
46345
|
-
// return this[`_start${timer}`] !== undefined;
|
|
46346
|
-
// }
|
|
46347
|
-
start(timer) {
|
|
46348
|
-
// this[`_start${timer}`] = this._now();
|
|
46349
|
-
this.timers[timer] = this._now();
|
|
46350
|
-
}
|
|
46351
|
-
_stop(timer) {
|
|
46352
|
-
// this._metrics.timers[timer] += this._now() - this[`_start${timer}`];
|
|
46353
|
-
this.metrics.timers[timer] += this._now() - this.timers[timer];
|
|
46354
|
-
}
|
|
46355
|
-
/**
|
|
46356
|
-
* Registers a callback to receive the metrics.
|
|
46357
|
-
* @param updateMetricsFn - The callback to receive the metrics
|
|
46358
|
-
*/
|
|
46359
|
-
setUpdateMetrics(updateMetricsFn) {
|
|
46360
|
-
// TODO use events instead
|
|
46361
|
-
this.updateFn = updateMetricsFn;
|
|
46362
|
-
}
|
|
46363
|
-
_defaultReport(metrics) {
|
|
46364
|
-
this.updateFn(metrics);
|
|
46365
|
-
}
|
|
46366
|
-
constructor(container) {
|
|
46367
|
-
super(container);
|
|
46368
|
-
this.runEach = container.options.clapprStats?.runEach ?? 5000;
|
|
46369
|
-
this._onReport = container.options.clapprStats?.onReport ?? this._defaultReport;
|
|
46370
|
-
this.uriToMeasureLatency = container.options.clapprStats?.uriToMeasureLatency;
|
|
46371
|
-
this.urisToMeasureBandwidth = container.options.clapprStats?.urisToMeasureBandwidth;
|
|
46372
|
-
this.runBandwidthTestEvery = container.options.clapprStats?.runBandwidthTestEvery ?? 10;
|
|
46373
|
-
this.completion = {
|
|
46374
|
-
watch: container.options.clapprStats?.onCompletion ?? [],
|
|
46375
|
-
calls: []
|
|
46376
|
-
};
|
|
46377
|
-
}
|
|
46378
|
-
/**
|
|
46379
|
-
* @internal
|
|
46380
|
-
*/
|
|
46381
|
-
bindEvents() {
|
|
46382
|
-
this.listenTo(this.container, Events$1.CONTAINER_BITRATE, this.onBitrate);
|
|
46383
|
-
this.listenTo(this.container, Events$1.CONTAINER_STOP, this.stopReporting);
|
|
46384
|
-
this.listenTo(this.container, Events$1.CONTAINER_ENDED, this.stopReporting);
|
|
46385
|
-
this.listenToOnce(this.container.playback, Events$1.PLAYBACK_PLAY_INTENT, this.startTimers);
|
|
46386
|
-
this.listenToOnce(this.container, Events$1.CONTAINER_PLAY, this.onFirstPlaying);
|
|
46387
|
-
this.listenTo(this.container, Events$1.CONTAINER_PLAY, this.onPlay);
|
|
46388
|
-
this.listenTo(this.container, Events$1.CONTAINER_PAUSE, this.onPause);
|
|
46389
|
-
this.listenToOnce(this.container, Events$1.CONTAINER_STATE_BUFFERING, this.onBuffering);
|
|
46390
|
-
this.listenTo(this.container, Events$1.CONTAINER_SEEK, this.onSeek);
|
|
46391
|
-
this.listenTo(this.container, Events$1.CONTAINER_ERROR, () => this._inc('error'));
|
|
46392
|
-
this.listenTo(this.container, Events$1.CONTAINER_FULLSCREEN, () => this._inc('fullscreen'));
|
|
46393
|
-
this.listenTo(this.container, Events$1.CONTAINER_PLAYBACKDVRSTATECHANGED, (dvrInUse) => {
|
|
46394
|
-
dvrInUse && this._inc('dvrUsage');
|
|
46395
|
-
});
|
|
46396
|
-
this.listenTo(this.container.playback, Events$1.PLAYBACK_PROGRESS, this.onProgress);
|
|
46397
|
-
this.listenTo(this.container.playback, Events$1.PLAYBACK_TIMEUPDATE, this.onTimeUpdate);
|
|
46398
|
-
}
|
|
46399
|
-
/**
|
|
46400
|
-
* @internal
|
|
46401
|
-
*/
|
|
46402
|
-
destroy() {
|
|
46403
|
-
this.stopReporting();
|
|
46404
|
-
super.destroy();
|
|
46405
|
-
}
|
|
46406
|
-
/**
|
|
46407
|
-
* Returns the collected metrics.
|
|
46408
|
-
* @returns Currently collected metrics
|
|
46409
|
-
*/
|
|
46410
|
-
exportMetrics() {
|
|
46411
|
-
return structuredClone(this.metrics);
|
|
46412
|
-
}
|
|
46413
|
-
onBitrate(newBitrate) {
|
|
46414
|
-
const bitrate = newBitrate.bitrate;
|
|
46415
|
-
const now = this._now();
|
|
46416
|
-
if (this.metrics.extra.bitratesHistory.length > 0) {
|
|
46417
|
-
const beforeLast = this.metrics.extra.bitratesHistory[this.metrics.extra.bitratesHistory.length - 1];
|
|
46418
|
-
beforeLast.end = now;
|
|
46419
|
-
beforeLast.time = now - beforeLast.start;
|
|
46420
|
-
}
|
|
46421
|
-
this.metrics.extra.bitratesHistory.push({ start: this._now(), bitrate: bitrate });
|
|
46422
|
-
this._inc('changeLevel');
|
|
46423
|
-
}
|
|
46424
|
-
stopReporting() {
|
|
46425
|
-
this._buildReport();
|
|
46426
|
-
if (this.intervalId !== null) {
|
|
46427
|
-
clearInterval(this.intervalId);
|
|
46428
|
-
this.intervalId = null;
|
|
46429
|
-
}
|
|
46430
|
-
this._newMetrics();
|
|
46431
|
-
// TODO
|
|
46432
|
-
// @ts-ignore
|
|
46433
|
-
this.stopListening();
|
|
46434
|
-
this.bindEvents();
|
|
46435
|
-
}
|
|
46436
|
-
startTimers() {
|
|
46437
|
-
this.intervalId = setInterval(this._buildReport.bind(this), this.runEach);
|
|
46438
|
-
this.start('session');
|
|
46439
|
-
this.start('startup');
|
|
46440
|
-
}
|
|
46441
|
-
onFirstPlaying() {
|
|
46442
|
-
this.listenTo(this.container, Events$1.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
|
|
46443
|
-
this.start('watch');
|
|
46444
|
-
this._stop('startup');
|
|
46445
|
-
}
|
|
46446
|
-
playAfterPause() {
|
|
46447
|
-
this.listenTo(this.container, Events$1.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
|
|
46448
|
-
this._stop('pause');
|
|
46449
|
-
this.start('watch');
|
|
46450
|
-
}
|
|
46451
|
-
onPlay() {
|
|
46452
|
-
this._inc('play');
|
|
46453
|
-
}
|
|
46454
|
-
onPause() {
|
|
46455
|
-
this._stop('watch');
|
|
46456
|
-
this.start('pause');
|
|
46457
|
-
this._inc('pause');
|
|
46458
|
-
this.listenToOnce(this.container, Events$1.CONTAINER_PLAY, this.playAfterPause);
|
|
46459
|
-
this.stopListening(this.container, Events$1.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
|
|
46460
|
-
}
|
|
46461
|
-
onSeek(e) {
|
|
46462
|
-
this._inc('seek');
|
|
46463
|
-
this.metrics.extra.watchHistory.push([e * 1000, e * 1000]);
|
|
46464
|
-
}
|
|
46465
|
-
onTimeUpdate(e) {
|
|
46466
|
-
const current = e.current * 1000, total = e.total * 1000, l = this.metrics.extra.watchHistory.length;
|
|
46467
|
-
this.metrics.extra.duration = total;
|
|
46468
|
-
this.metrics.extra.currentTime = current;
|
|
46469
|
-
this.metrics.extra.watchedPercentage = (current / total) * 100;
|
|
46470
|
-
if (l === 0) {
|
|
46471
|
-
this.metrics.extra.watchHistory.push([current, current]);
|
|
46472
|
-
}
|
|
46473
|
-
else {
|
|
46474
|
-
this.metrics.extra.watchHistory[l - 1][1] = current;
|
|
46475
|
-
}
|
|
46476
|
-
if (this.metrics.extra.bitratesHistory.length > 0) {
|
|
46477
|
-
const lastBitrate = this.metrics.extra.bitratesHistory[this.metrics.extra.bitratesHistory.length - 1];
|
|
46478
|
-
if (!lastBitrate.end) {
|
|
46479
|
-
lastBitrate.time = this._now() - lastBitrate.start;
|
|
46480
|
-
}
|
|
46481
|
-
}
|
|
46482
|
-
this._onCompletion();
|
|
46483
|
-
}
|
|
46484
|
-
onContainerUpdateWhilePlaying() {
|
|
46485
|
-
if (this.container.playback.isPlaying()) {
|
|
46486
|
-
this._stop('watch');
|
|
46487
|
-
this.start('watch');
|
|
46488
|
-
}
|
|
46489
|
-
}
|
|
46490
|
-
onBuffering() {
|
|
46491
|
-
this._inc('buffering');
|
|
46492
|
-
this.start('buffering');
|
|
46493
|
-
this.listenToOnce(this.container, Events$1.CONTAINER_STATE_BUFFERFULL, this.onBufferfull);
|
|
46494
|
-
}
|
|
46495
|
-
onBufferfull() {
|
|
46496
|
-
this._stop('buffering');
|
|
46497
|
-
this.listenToOnce(this.container, Events$1.CONTAINER_STATE_BUFFERING, this.onBuffering);
|
|
46498
|
-
}
|
|
46499
|
-
onProgress(progress) {
|
|
46500
|
-
this.metrics.extra.buffersize = progress.current * 1000;
|
|
46501
|
-
}
|
|
46502
|
-
_newMetrics() {
|
|
46503
|
-
this.metrics = newMetrics$1();
|
|
46504
|
-
}
|
|
46505
|
-
_onCompletion() {
|
|
46506
|
-
const currentPercentage = this.metrics.extra.watchedPercentage;
|
|
46507
|
-
const allPercentages = this.completion.watch;
|
|
46508
|
-
const isCalled = this.completion.calls.indexOf(currentPercentage) !== -1;
|
|
46509
|
-
if (allPercentages.indexOf(currentPercentage) !== -1 && !isCalled) {
|
|
46510
|
-
Log.info(this.name + ' PERCENTAGE_EVENT: ' + currentPercentage);
|
|
46511
|
-
this.completion.calls.push(currentPercentage);
|
|
46512
|
-
this.trigger(ClapprStatsEvents.PERCENTAGE_EVENT, currentPercentage);
|
|
46513
|
-
}
|
|
46514
|
-
}
|
|
46515
|
-
_buildReport() {
|
|
46516
|
-
this._stop('session');
|
|
46517
|
-
this.start('session');
|
|
46518
|
-
this.metrics.extra.playbackName = this._playbackName;
|
|
46519
|
-
this.metrics.extra.playbackType = this._playbackType;
|
|
46520
|
-
this._calculateBitrates();
|
|
46521
|
-
this._calculatePercentages();
|
|
46522
|
-
this._fetchFPS();
|
|
46523
|
-
this._measureLatency();
|
|
46524
|
-
this._measureBandwidth();
|
|
46525
|
-
this._onReport(this.metrics);
|
|
46526
|
-
this.trigger(ClapprStatsEvents.REPORT_EVENT, structuredClone(this.metrics));
|
|
46527
|
-
}
|
|
46528
|
-
_fetchFPS() {
|
|
46529
|
-
// flashls ??? - hls.droppedFramesl hls.stream.bufferLength (seconds)
|
|
46530
|
-
// hls ??? (use the same?)
|
|
46531
|
-
const fetchFPS = {
|
|
46532
|
-
'html5_video': this._html5FetchFPS,
|
|
46533
|
-
'hls': this._html5FetchFPS,
|
|
46534
|
-
'dash_shaka_playback': this._html5FetchFPS
|
|
46535
|
-
};
|
|
46536
|
-
if (this._playbackName in fetchFPS) {
|
|
46537
|
-
fetchFPS[this._playbackName].call(this);
|
|
46538
|
-
}
|
|
46539
|
-
}
|
|
46540
|
-
_calculateBitrates() {
|
|
46541
|
-
const { bitratesHistory } = this.metrics.extra;
|
|
46542
|
-
if (bitratesHistory.length === 0) {
|
|
46543
|
-
return;
|
|
46544
|
-
}
|
|
46545
|
-
let totalTime = 0;
|
|
46546
|
-
let weightedTotal = 0;
|
|
46547
|
-
for (const { bitrate, time = 0 } of bitratesHistory) {
|
|
46548
|
-
totalTime += time;
|
|
46549
|
-
weightedTotal += bitrate * time;
|
|
46550
|
-
}
|
|
46551
|
-
this.metrics.extra.bitrateWeightedMean = weightedTotal / totalTime;
|
|
46552
|
-
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;
|
|
46553
|
-
}
|
|
46554
|
-
_calculatePercentages() {
|
|
46555
|
-
if (this.metrics.extra.duration > 0) {
|
|
46556
|
-
this.metrics.extra.bufferingPercentage = (this.metrics.timers.buffering / this.metrics.extra.duration) * 100;
|
|
46557
|
-
}
|
|
46558
|
-
}
|
|
46559
|
-
_html5FetchFPS() {
|
|
46560
|
-
const videoTag = this.container.playback.el;
|
|
46561
|
-
const getFirstValidValue = (...args) => args.find(val => val !== undefined);
|
|
46562
|
-
const decodedFrames = getFirstValidValue(videoTag.webkitDecodedFrameCount, videoTag.mozDecodedFrames, 0);
|
|
46563
|
-
const droppedFrames = getFirstValidValue(videoTag.webkitDroppedFrameCount, videoTag.mozParsedFrames && videoTag.mozDecodedFrames ? videoTag.mozParsedFrames - videoTag.mozDecodedFrames : 0, 0);
|
|
46564
|
-
const decodedFramesLastTime = decodedFrames - (this.lastDecodedFramesCount || 0);
|
|
46565
|
-
this.metrics.counters.decodedFrames = decodedFrames;
|
|
46566
|
-
this.metrics.counters.droppedFrames = droppedFrames;
|
|
46567
|
-
this.metrics.counters.fps = decodedFramesLastTime / (this.runEach / 1000);
|
|
46568
|
-
this.lastDecodedFramesCount = decodedFrames;
|
|
46569
|
-
}
|
|
46570
|
-
// originally from https://www.smashingmagazine.com/2011/11/analyzing-network-characteristics-using-javascript-and-the-dom-part-1/
|
|
46571
|
-
_measureLatency() {
|
|
46572
|
-
if (this.uriToMeasureLatency) {
|
|
46573
|
-
const t = [];
|
|
46574
|
-
const n = 2;
|
|
46575
|
-
let rtt;
|
|
46576
|
-
const ld = () => {
|
|
46577
|
-
t.push(this._now());
|
|
46578
|
-
if (t.length > n) {
|
|
46579
|
-
done();
|
|
46580
|
-
}
|
|
46581
|
-
else {
|
|
46582
|
-
const img = new Image;
|
|
46583
|
-
img.onload = ld;
|
|
46584
|
-
img.src = this.uriToMeasureLatency + '?' + Math.random()
|
|
46585
|
-
+ '=' + this._now();
|
|
46586
|
-
}
|
|
46587
|
-
};
|
|
46588
|
-
const done = () => {
|
|
46589
|
-
rtt = t[2] - t[1];
|
|
46590
|
-
this.metrics.timers.latency = rtt;
|
|
46591
|
-
};
|
|
46592
|
-
ld();
|
|
46593
|
-
}
|
|
46594
|
-
}
|
|
46595
|
-
// originally from https://www.smashingmagazine.com/2011/11/analyzing-network-characteristics-using-javascript-and-the-dom-part-1/
|
|
46596
|
-
_measureBandwidth() {
|
|
46597
|
-
if (this.urisToMeasureBandwidth && (this.bwMeasureCount % this.runBandwidthTestEvery === 0)) {
|
|
46598
|
-
let i = 0;
|
|
46599
|
-
const ld = (e) => {
|
|
46600
|
-
if (i > 0) {
|
|
46601
|
-
const prev = this.urisToMeasureBandwidth[i - 1];
|
|
46602
|
-
prev.end = this._now();
|
|
46603
|
-
if (prev.timer !== null) {
|
|
46604
|
-
clearTimeout(prev.timer);
|
|
46605
|
-
}
|
|
46606
|
-
}
|
|
46607
|
-
if (i >= this.urisToMeasureBandwidth.length || (i > 0 && this.urisToMeasureBandwidth[i - 1].expired)) {
|
|
46608
|
-
assert(e, 'incorrect invocation in _measureBandwidth');
|
|
46609
|
-
done(e);
|
|
46610
|
-
}
|
|
46611
|
-
else {
|
|
46612
|
-
const xhr = new XMLHttpRequest();
|
|
46613
|
-
xhr.open('GET', this.urisToMeasureBandwidth[i].url, true);
|
|
46614
|
-
xhr.responseType = 'arraybuffer';
|
|
46615
|
-
xhr.onload = xhr.onabort = ld;
|
|
46616
|
-
this.urisToMeasureBandwidth[i].start = this._now();
|
|
46617
|
-
this.urisToMeasureBandwidth[i].timer = setTimeout((j) => {
|
|
46618
|
-
this.urisToMeasureBandwidth[j].expired = true;
|
|
46619
|
-
xhr.abort();
|
|
46620
|
-
}, this.urisToMeasureBandwidth[i].timeout, i);
|
|
46621
|
-
xhr.send();
|
|
46622
|
-
}
|
|
46623
|
-
i++;
|
|
46624
|
-
};
|
|
46625
|
-
const done = (e) => {
|
|
46626
|
-
const timeSpent = (this.urisToMeasureBandwidth[i - 1].end - this.urisToMeasureBandwidth[i - 1].start) / 1000;
|
|
46627
|
-
const bandwidthBps = (e.loaded * 8) / timeSpent;
|
|
46628
|
-
this.metrics.extra.bandwidth = bandwidthBps;
|
|
46629
|
-
this.urisToMeasureBandwidth.forEach((x) => {
|
|
46630
|
-
x.start = 0;
|
|
46631
|
-
x.end = 0;
|
|
46632
|
-
x.expired = false;
|
|
46633
|
-
if (x.timer !== null) {
|
|
46634
|
-
clearTimeout(x.timer);
|
|
46635
|
-
x.timer = null;
|
|
46636
|
-
}
|
|
46637
|
-
});
|
|
46638
|
-
};
|
|
46639
|
-
ld();
|
|
46640
|
-
}
|
|
46641
|
-
this.bwMeasureCount++;
|
|
46642
|
-
}
|
|
46643
|
-
}
|
|
46644
|
-
// ClapprStats.REPORT_EVENT = 'clappr:stats:report';
|
|
46645
|
-
// ClapprStats.PERCENTAGE_EVENT = 'clappr:stats:percentage';
|
|
46646
|
-
|
|
46647
46569
|
// This work is based on the original work of the following authors:
|
|
46648
46570
|
// Copyright 2014 Globo.com Player authors. All rights reserved.
|
|
46649
46571
|
// Use of this source code is governed by a BSD-style
|
|
@@ -52404,4 +52326,4 @@ class VolumeFade extends UICorePlugin {
|
|
|
52404
52326
|
}
|
|
52405
52327
|
}
|
|
52406
52328
|
|
|
52407
|
-
export { AudioTracks as AudioSelector, AudioTracks, BigMuteButton, BottomGear, ClapprNerdStats, ClapprStats, ClickToPause, Clips, ClosedCaptions, ContextMenu, DvrControls, ErrorScreen, Favicon, GearEvents, GoogleAnalytics, QualityLevels as LevelSelector, LogTracer, Logger, Logo, MediaControl, MultiCamera, PictureInPicture, PlaybackErrorCode, PlaybackRate, Player, PlayerEvent, Poster, QualityLevels, SeekTime, SentryTracer, Share, SkipTime, SourceController, SpinnerThreeBounce as Spinner, SpinnerEvents, SpinnerThreeBounce, ClosedCaptions as Subtitles, Telemetry, TelemetryEvent, Thumbnails, VolumeFade, VolumeFadeEvents, reportError, setTracer, trace, version };
|
|
52329
|
+
export { AudioTracks as AudioSelector, AudioTracks, BigMuteButton, BottomGear, NerdStats as ClapprNerdStats, ClapprStats, ClickToPause, Clips, ClosedCaptions, ContextMenu, DvrControls, ErrorScreen, Favicon, GearEvents, GoogleAnalytics, QualityLevels as LevelSelector, LogTracer, Logger, Logo, MediaControl, MultiCamera, NerdStats, PictureInPicture, PlaybackErrorCode, PlaybackRate, Player, PlayerEvent, Poster, QualityLevels, SeekTime, SentryTracer, Share, SkipTime, SourceController, SpinnerThreeBounce as Spinner, SpinnerEvents, SpinnerThreeBounce, ClosedCaptions as Subtitles, Telemetry, TelemetryEvent, Thumbnails, VolumeFade, VolumeFadeEvents, reportError, setTracer, trace, version };
|