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