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