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