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