]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - client/src/assets/player/shared/manager-options/hls-options-builder.ts
Reorganize player manager options builder
[github/Chocobozzz/PeerTube.git] / client / src / assets / player / shared / manager-options / hls-options-builder.ts
1 import { HybridLoaderSettings } from '@peertube/p2p-media-loader-core'
2 import { HlsJsEngineSettings } from '@peertube/p2p-media-loader-hlsjs'
3 import { LiveVideoLatencyMode } from '@shared/models'
4 import { getAverageBandwidthInStore } from '../../peertube-player-local-storage'
5 import { P2PMediaLoader, P2PMediaLoaderPluginOptions } from '../../types'
6 import { PeertubePlayerManagerOptions } from '../../types/manager-options'
7 import { getRtcConfig } from '../common'
8 import { RedundancyUrlManager } from '../p2p-media-loader/redundancy-url-manager'
9 import { segmentUrlBuilderFactory } from '../p2p-media-loader/segment-url-builder'
10 import { segmentValidatorFactory } from '../p2p-media-loader/segment-validator'
11
12 export class HLSOptionsBuilder {
13
14 constructor (
15 private options: PeertubePlayerManagerOptions,
16 private p2pMediaLoaderModule?: any
17 ) {
18
19 }
20
21 getPluginOptions () {
22 const commonOptions = this.options.common
23
24 const redundancyUrlManager = new RedundancyUrlManager(this.options.p2pMediaLoader.redundancyBaseUrls)
25
26 const p2pMediaLoaderConfig = this.getP2PMediaLoaderOptions(redundancyUrlManager)
27 const loader = new this.p2pMediaLoaderModule.Engine(p2pMediaLoaderConfig).createLoaderClass() as P2PMediaLoader
28
29 const p2pMediaLoader: P2PMediaLoaderPluginOptions = {
30 redundancyUrlManager,
31 type: 'application/x-mpegURL',
32 startTime: commonOptions.startTime,
33 src: this.options.p2pMediaLoader.playlistUrl,
34 loader
35 }
36
37 const hlsjs = {
38 levelLabelHandler: (level: { height: number, width: number }) => {
39 const resolution = Math.min(level.height || 0, level.width || 0)
40
41 const file = this.options.p2pMediaLoader.videoFiles.find(f => f.resolution.id === resolution)
42 // We don't have files for live videos
43 if (!file) return level.height
44
45 let label = file.resolution.label
46 if (file.fps >= 50) label += file.fps
47
48 return label
49 },
50 html5: {
51 hlsjsConfig: this.getHLSJSOptions(loader)
52 }
53 }
54
55 return { p2pMediaLoader, hlsjs }
56 }
57
58 // ---------------------------------------------------------------------------
59
60 private getP2PMediaLoaderOptions (redundancyUrlManager: RedundancyUrlManager): HlsJsEngineSettings {
61 let consumeOnly = false
62 if ((navigator as any)?.connection?.type === 'cellular') {
63 console.log('We are on a cellular connection: disabling seeding.')
64 consumeOnly = true
65 }
66
67 const trackerAnnounce = this.options.p2pMediaLoader.trackerAnnounce
68 .filter(t => t.startsWith('ws'))
69
70 const specificLiveOrVODOptions = this.options.common.isLive
71 ? this.getP2PMediaLoaderLiveOptions()
72 : this.getP2PMediaLoaderVODOptions()
73
74 return {
75 loader: {
76
77 trackerAnnounce,
78 rtcConfig: getRtcConfig(),
79
80 simultaneousHttpDownloads: 1,
81 httpFailedSegmentTimeout: 1000,
82
83 segmentValidator: segmentValidatorFactory(this.options.p2pMediaLoader.segmentsSha256Url, this.options.common.isLive),
84 segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager, 1),
85
86 useP2P: this.options.common.p2pEnabled,
87 consumeOnly,
88
89 ...specificLiveOrVODOptions
90 },
91 segments: {
92 swarmId: this.options.p2pMediaLoader.playlistUrl,
93 forwardSegmentCount: specificLiveOrVODOptions.p2pDownloadMaxPriority
94 }
95 }
96 }
97
98 private getP2PMediaLoaderLiveOptions (): Partial<HybridLoaderSettings> {
99 const base = {
100 requiredSegmentsPriority: 1
101 }
102
103 const latencyMode = this.options.common.liveOptions.latencyMode
104
105 switch (latencyMode) {
106 case LiveVideoLatencyMode.SMALL_LATENCY:
107 return {
108 ...base,
109
110 useP2P: false,
111 httpDownloadProbability: 1
112 }
113
114 case LiveVideoLatencyMode.HIGH_LATENCY:
115 return base
116
117 default:
118 return base
119 }
120 }
121
122 private getP2PMediaLoaderVODOptions (): Partial<HybridLoaderSettings> {
123 return {
124 requiredSegmentsPriority: 3,
125
126 cachedSegmentExpiration: 86400000,
127 cachedSegmentsCount: 100,
128
129 httpDownloadMaxPriority: 9,
130 httpDownloadProbability: 0.06,
131 httpDownloadProbabilitySkipIfNoPeers: true,
132
133 p2pDownloadMaxPriority: 50
134 }
135 }
136
137 // ---------------------------------------------------------------------------
138
139 private getHLSJSOptions (loader: P2PMediaLoader) {
140 const specificLiveOrVODOptions = this.options.common.isLive
141 ? this.getHLSLiveOptions()
142 : this.getHLSVODOptions()
143
144 const base = {
145 capLevelToPlayerSize: true,
146 autoStartLoad: false,
147
148 loader,
149
150 ...specificLiveOrVODOptions
151 }
152
153 const averageBandwidth = getAverageBandwidthInStore()
154 if (!averageBandwidth) return base
155
156 return {
157 ...base,
158
159 abrEwmaDefaultEstimate: averageBandwidth * 8, // We want bit/s
160 startLevel: -1,
161 testBandwidth: false,
162 debug: false
163 }
164 }
165
166 private getHLSLiveOptions () {
167 const latencyMode = this.options.common.liveOptions.latencyMode
168
169 switch (latencyMode) {
170 case LiveVideoLatencyMode.SMALL_LATENCY:
171 return {
172 liveSyncDurationCount: 2
173 }
174
175 case LiveVideoLatencyMode.HIGH_LATENCY:
176 return {
177 liveSyncDurationCount: 10
178 }
179
180 default:
181 return {
182 liveSyncDurationCount: 5
183 }
184 }
185 }
186
187 private getHLSVODOptions () {
188 return {
189 liveSyncDurationCount: 5
190 }
191 }
192 }