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 { RedundancyUrlManager } from '../p2p-media-loader/redundancy-url-manager'
5 import { segmentUrlBuilderFactory } from '../p2p-media-loader/segment-url-builder'
6 import { segmentValidatorFactory } from '../p2p-media-loader/segment-validator'
7 import { getAverageBandwidthInStore } from '../peertube-player-local-storage'
8 import { P2PMediaLoader, P2PMediaLoaderPluginOptions } from '../peertube-videojs-typings'
9 import { getRtcConfig } from '../utils'
10 import { PeertubePlayerManagerOptions } from './manager-options.model'
12 export class HLSOptionsBuilder {
15 private options: PeertubePlayerManagerOptions,
16 private p2pMediaLoaderModule?: any
22 const commonOptions = this.options.common
24 const redundancyUrlManager = new RedundancyUrlManager(this.options.p2pMediaLoader.redundancyBaseUrls)
26 const p2pMediaLoaderConfig = this.getP2PMediaLoaderOptions(redundancyUrlManager)
27 const loader = new this.p2pMediaLoaderModule.Engine(p2pMediaLoaderConfig).createLoaderClass() as P2PMediaLoader
29 const p2pMediaLoader: P2PMediaLoaderPluginOptions = {
31 type: 'application/x-mpegURL',
32 startTime: commonOptions.startTime,
33 src: this.options.p2pMediaLoader.playlistUrl,
38 levelLabelHandler: (level: { height: number, width: number }) => {
39 const resolution = Math.min(level.height || 0, level.width || 0)
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
45 let label = file.resolution.label
46 if (file.fps >= 50) label += file.fps
51 hlsjsConfig: this.getHLSJSOptions(loader)
55 return { p2pMediaLoader, hlsjs }
58 // ---------------------------------------------------------------------------
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.')
67 const trackerAnnounce = this.options.p2pMediaLoader.trackerAnnounce
68 .filter(t => t.startsWith('ws'))
70 const specificLiveOrVODOptions = this.options.common.isLive
71 ? this.getP2PMediaLoaderLiveOptions()
72 : this.getP2PMediaLoaderVODOptions()
78 rtcConfig: getRtcConfig(),
80 simultaneousHttpDownloads: 1,
81 httpFailedSegmentTimeout: 1000,
83 segmentValidator: segmentValidatorFactory(this.options.p2pMediaLoader.segmentsSha256Url, this.options.common.isLive),
84 segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager, 1),
86 useP2P: this.options.common.p2pEnabled,
89 ...specificLiveOrVODOptions
92 swarmId: this.options.p2pMediaLoader.playlistUrl,
93 forwardSegmentCount: specificLiveOrVODOptions.p2pDownloadMaxPriority
98 private getP2PMediaLoaderLiveOptions (): Partial<HybridLoaderSettings> {
100 requiredSegmentsPriority: 1
103 const latencyMode = this.options.common.liveOptions.latencyMode
105 switch (latencyMode) {
106 case LiveVideoLatencyMode.SMALL_LATENCY:
111 httpDownloadProbability: 1
114 case LiveVideoLatencyMode.HIGH_LATENCY:
122 private getP2PMediaLoaderVODOptions (): Partial<HybridLoaderSettings> {
124 requiredSegmentsPriority: 3,
126 cachedSegmentExpiration: 86400000,
127 cachedSegmentsCount: 100,
129 httpDownloadMaxPriority: 9,
130 httpDownloadProbability: 0.06,
131 httpDownloadProbabilitySkipIfNoPeers: true,
133 p2pDownloadMaxPriority: 50
137 // ---------------------------------------------------------------------------
139 private getHLSJSOptions (loader: P2PMediaLoader) {
140 const specificLiveOrVODOptions = this.options.common.isLive
141 ? this.getHLSLiveOptions()
142 : this.getHLSVODOptions()
145 capLevelToPlayerSize: true,
146 autoStartLoad: false,
150 ...specificLiveOrVODOptions
153 const averageBandwidth = getAverageBandwidthInStore()
154 if (!averageBandwidth) return base
159 abrEwmaDefaultEstimate: averageBandwidth * 8, // We want bit/s
161 testBandwidth: false,
166 private getHLSLiveOptions () {
167 const latencyMode = this.options.common.liveOptions.latencyMode
169 switch (latencyMode) {
170 case LiveVideoLatencyMode.SMALL_LATENCY:
172 liveSyncDurationCount: 2
175 case LiveVideoLatencyMode.HIGH_LATENCY:
177 liveSyncDurationCount: 10
182 liveSyncDurationCount: 5
187 private getHLSVODOptions () {
189 liveSyncDurationCount: 5