]>
Commit | Line | Data |
---|---|---|
fd3c2e87 C |
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 | |
6a02dd1c C |
67 | fps = videoFile.fps && videoFile.fps !== -1 |
68 | ? videoFile.fps | |
69 | : undefined | |
fd3c2e87 C |
70 | } |
71 | ||
72 | const body: PlaybackMetricCreate = { | |
73 | resolution, | |
74 | fps, | |
75 | ||
76 | playerMode: this.mode, | |
77 | ||
78 | resolutionChanges: this.resolutionChanges, | |
79 | ||
80 | errors: this.errors, | |
81 | ||
82 | downloadedBytesP2P: this.downloadedBytesP2P, | |
83 | downloadedBytesHTTP: this.downloadedBytesHTTP, | |
84 | ||
85 | uploadedBytesP2P: this.uploadedBytesP2P, | |
86 | ||
87 | videoId: this.videoUUID | |
88 | } | |
89 | ||
90 | this.resolutionChanges = 0 | |
91 | ||
92 | this.downloadedBytesP2P = 0 | |
93 | this.downloadedBytesHTTP = 0 | |
94 | ||
95 | this.uploadedBytesP2P = 0 | |
96 | ||
97 | this.errors = 0 | |
98 | ||
99 | const headers = new Headers({ 'Content-type': 'application/json; charset=UTF-8' }) | |
100 | ||
101 | return fetch(this.metricsUrl, { method: 'POST', body: JSON.stringify(body), headers }) | |
102 | }, this.CONSTANTS.METRICS_INTERVAL) | |
103 | } | |
104 | ||
105 | private trackBytes () { | |
106 | this.player.on('p2pInfo', (_event, data: PlayerNetworkInfo) => { | |
ae7b0cbb C |
107 | if (!data) return |
108 | ||
fd3c2e87 C |
109 | this.downloadedBytesHTTP += data.http.downloaded - (this.lastPlayerNetworkInfo?.http.downloaded || 0) |
110 | this.downloadedBytesP2P += data.p2p.downloaded - (this.lastPlayerNetworkInfo?.p2p.downloaded || 0) | |
111 | ||
112 | this.uploadedBytesP2P += data.p2p.uploaded - (this.lastPlayerNetworkInfo?.p2p.uploaded || 0) | |
113 | ||
114 | this.lastPlayerNetworkInfo = data | |
115 | }) | |
116 | } | |
117 | ||
118 | private trackResolutionChange () { | |
119 | this.player.on('engineResolutionChange', () => { | |
120 | this.resolutionChanges++ | |
121 | }) | |
122 | } | |
123 | ||
124 | private trackErrors () { | |
125 | this.player.on('error', () => { | |
126 | this.errors++ | |
127 | }) | |
128 | } | |
129 | } | |
130 | ||
131 | videojs.registerPlugin('metrics', MetricsPlugin) | |
132 | export { MetricsPlugin } |