diff options
Diffstat (limited to 'client/src/assets/player/shared/metrics/metrics-plugin.ts')
-rw-r--r-- | client/src/assets/player/shared/metrics/metrics-plugin.ts | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/client/src/assets/player/shared/metrics/metrics-plugin.ts b/client/src/assets/player/shared/metrics/metrics-plugin.ts new file mode 100644 index 000000000..1b2349eba --- /dev/null +++ b/client/src/assets/player/shared/metrics/metrics-plugin.ts | |||
@@ -0,0 +1,128 @@ | |||
1 | import videojs from 'video.js' | ||
2 | import { PlaybackMetricCreate } from '../../../../../../shared/models' | ||
3 | import { MetricsPluginOptions, PlayerMode, PlayerNetworkInfo } from '../../types' | ||
4 | |||
5 | const Plugin = videojs.getPlugin('plugin') | ||
6 | |||
7 | class MetricsPlugin extends Plugin { | ||
8 | private readonly metricsUrl: string | ||
9 | private readonly videoUUID: string | ||
10 | private readonly mode: PlayerMode | ||
11 | |||
12 | private downloadedBytesP2P = 0 | ||
13 | private downloadedBytesHTTP = 0 | ||
14 | private uploadedBytesP2P = 0 | ||
15 | |||
16 | private resolutionChanges = 0 | ||
17 | private errors = 0 | ||
18 | |||
19 | private lastPlayerNetworkInfo: PlayerNetworkInfo | ||
20 | |||
21 | private metricsInterval: any | ||
22 | |||
23 | private readonly CONSTANTS = { | ||
24 | METRICS_INTERVAL: 15000 | ||
25 | } | ||
26 | |||
27 | constructor (player: videojs.Player, options: MetricsPluginOptions) { | ||
28 | super(player) | ||
29 | |||
30 | this.metricsUrl = options.metricsUrl | ||
31 | this.videoUUID = options.videoUUID | ||
32 | this.mode = options.mode | ||
33 | |||
34 | this.player.one('play', () => { | ||
35 | this.runMetricsInterval() | ||
36 | |||
37 | this.trackBytes() | ||
38 | this.trackResolutionChange() | ||
39 | this.trackErrors() | ||
40 | }) | ||
41 | } | ||
42 | |||
43 | dispose () { | ||
44 | if (this.metricsInterval) clearInterval(this.metricsInterval) | ||
45 | } | ||
46 | |||
47 | private runMetricsInterval () { | ||
48 | this.metricsInterval = setInterval(() => { | ||
49 | let resolution: number | ||
50 | let fps: number | ||
51 | |||
52 | if (this.mode === 'p2p-media-loader') { | ||
53 | const level = this.player.p2pMediaLoader().getCurrentLevel() | ||
54 | if (!level) return | ||
55 | |||
56 | resolution = Math.min(level.height || 0, level.width || 0) | ||
57 | |||
58 | const framerate = level?.attrs['FRAME-RATE'] | ||
59 | fps = framerate | ||
60 | ? parseInt(framerate, 10) | ||
61 | : undefined | ||
62 | } else { // webtorrent | ||
63 | const videoFile = this.player.webtorrent().getCurrentVideoFile() | ||
64 | if (!videoFile) return | ||
65 | |||
66 | resolution = videoFile.resolution.id | ||
67 | fps = videoFile.fps | ||
68 | } | ||
69 | |||
70 | const body: PlaybackMetricCreate = { | ||
71 | resolution, | ||
72 | fps, | ||
73 | |||
74 | playerMode: this.mode, | ||
75 | |||
76 | resolutionChanges: this.resolutionChanges, | ||
77 | |||
78 | errors: this.errors, | ||
79 | |||
80 | downloadedBytesP2P: this.downloadedBytesP2P, | ||
81 | downloadedBytesHTTP: this.downloadedBytesHTTP, | ||
82 | |||
83 | uploadedBytesP2P: this.uploadedBytesP2P, | ||
84 | |||
85 | videoId: this.videoUUID | ||
86 | } | ||
87 | |||
88 | this.resolutionChanges = 0 | ||
89 | |||
90 | this.downloadedBytesP2P = 0 | ||
91 | this.downloadedBytesHTTP = 0 | ||
92 | |||
93 | this.uploadedBytesP2P = 0 | ||
94 | |||
95 | this.errors = 0 | ||
96 | |||
97 | const headers = new Headers({ 'Content-type': 'application/json; charset=UTF-8' }) | ||
98 | |||
99 | return fetch(this.metricsUrl, { method: 'POST', body: JSON.stringify(body), headers }) | ||
100 | }, this.CONSTANTS.METRICS_INTERVAL) | ||
101 | } | ||
102 | |||
103 | private trackBytes () { | ||
104 | this.player.on('p2pInfo', (_event, data: PlayerNetworkInfo) => { | ||
105 | this.downloadedBytesHTTP += data.http.downloaded - (this.lastPlayerNetworkInfo?.http.downloaded || 0) | ||
106 | this.downloadedBytesP2P += data.p2p.downloaded - (this.lastPlayerNetworkInfo?.p2p.downloaded || 0) | ||
107 | |||
108 | this.uploadedBytesP2P += data.p2p.uploaded - (this.lastPlayerNetworkInfo?.p2p.uploaded || 0) | ||
109 | |||
110 | this.lastPlayerNetworkInfo = data | ||
111 | }) | ||
112 | } | ||
113 | |||
114 | private trackResolutionChange () { | ||
115 | this.player.on('engineResolutionChange', () => { | ||
116 | this.resolutionChanges++ | ||
117 | }) | ||
118 | } | ||
119 | |||
120 | private trackErrors () { | ||
121 | this.player.on('error', () => { | ||
122 | this.errors++ | ||
123 | }) | ||
124 | } | ||
125 | } | ||
126 | |||
127 | videojs.registerPlugin('metrics', MetricsPlugin) | ||
128 | export { MetricsPlugin } | ||