Improve HLS redundancy
This commit is contained in:
parent
20ec03846d
commit
da33241770
5 changed files with 72 additions and 24 deletions
|
@ -3,7 +3,7 @@
|
||||||
import * as videojs from 'video.js'
|
import * as videojs from 'video.js'
|
||||||
import { P2PMediaLoaderPluginOptions, PlayerNetworkInfo, VideoJSComponentInterface } from '../peertube-videojs-typings'
|
import { P2PMediaLoaderPluginOptions, PlayerNetworkInfo, VideoJSComponentInterface } from '../peertube-videojs-typings'
|
||||||
import { Engine, initHlsJsPlayer, initVideoJsContribHlsJsPlayer } from 'p2p-media-loader-hlsjs'
|
import { Engine, initHlsJsPlayer, initVideoJsContribHlsJsPlayer } from 'p2p-media-loader-hlsjs'
|
||||||
import { Events } from 'p2p-media-loader-core'
|
import { Events, Segment } from 'p2p-media-loader-core'
|
||||||
import { timeToInt } from '../utils'
|
import { timeToInt } from '../utils'
|
||||||
|
|
||||||
// videojs-hlsjs-plugin needs videojs in window
|
// videojs-hlsjs-plugin needs videojs in window
|
||||||
|
@ -57,7 +57,6 @@ class P2pMediaLoaderPlugin extends Plugin {
|
||||||
initVideoJsContribHlsJsPlayer(player)
|
initVideoJsContribHlsJsPlayer(player)
|
||||||
|
|
||||||
this.startTime = timeToInt(options.startTime)
|
this.startTime = timeToInt(options.startTime)
|
||||||
console.log(this.startTime)
|
|
||||||
|
|
||||||
player.src({
|
player.src({
|
||||||
type: options.type,
|
type: options.type,
|
||||||
|
@ -90,11 +89,13 @@ class P2pMediaLoaderPlugin extends Plugin {
|
||||||
this.trigger('resolutionChange', { auto: this.hlsjs.autoLevelEnabled, resolutionId: data.height })
|
this.trigger('resolutionChange', { auto: this.hlsjs.autoLevelEnabled, resolutionId: data.height })
|
||||||
})
|
})
|
||||||
|
|
||||||
this.p2pEngine.on(Events.SegmentError, (segment, err) => {
|
this.p2pEngine.on(Events.SegmentError, (segment: Segment, err) => {
|
||||||
console.error('Segment error.', segment, err)
|
console.error('Segment error.', segment, err)
|
||||||
|
|
||||||
|
this.options.redundancyUrlManager.removeByOriginUrl(segment.url)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.statsP2PBytes.numPeers = 1 + this.options.redundancyBaseUrls.length
|
this.statsP2PBytes.numPeers = 1 + this.options.redundancyUrlManager.countBaseUrls()
|
||||||
|
|
||||||
this.runStats()
|
this.runStats()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
import { basename, dirname } from 'path'
|
||||||
|
|
||||||
|
class RedundancyUrlManager {
|
||||||
|
|
||||||
|
// Remember by what new URL we replaced an origin URL
|
||||||
|
private replacedSegmentUrls: { [originUrl: string]: string } = {}
|
||||||
|
|
||||||
|
constructor (private baseUrls: string[] = []) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBySegmentUrl (segmentUrl: string) {
|
||||||
|
console.log('Removing redundancy of segment URL %s.', segmentUrl)
|
||||||
|
|
||||||
|
const baseUrl = dirname(segmentUrl)
|
||||||
|
|
||||||
|
this.baseUrls = this.baseUrls.filter(u => u !== baseUrl && u !== baseUrl + '/')
|
||||||
|
}
|
||||||
|
|
||||||
|
removeByOriginUrl (originUrl: string) {
|
||||||
|
const replaced = this.replacedSegmentUrls[originUrl]
|
||||||
|
if (!replaced) return
|
||||||
|
|
||||||
|
return this.removeBySegmentUrl(replaced)
|
||||||
|
}
|
||||||
|
|
||||||
|
buildUrl (url: string) {
|
||||||
|
delete this.replacedSegmentUrls[url]
|
||||||
|
|
||||||
|
const max = this.baseUrls.length + 1
|
||||||
|
const i = this.getRandomInt(max)
|
||||||
|
|
||||||
|
if (i === max - 1) return url
|
||||||
|
|
||||||
|
const newBaseUrl = this.baseUrls[i]
|
||||||
|
const slashPart = newBaseUrl.endsWith('/') ? '' : '/'
|
||||||
|
|
||||||
|
const newUrl = newBaseUrl + slashPart + basename(url)
|
||||||
|
this.replacedSegmentUrls[url] = newUrl
|
||||||
|
|
||||||
|
return newUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
countBaseUrls () {
|
||||||
|
return this.baseUrls.length
|
||||||
|
}
|
||||||
|
|
||||||
|
private getRandomInt (max: number) {
|
||||||
|
return Math.floor(Math.random() * Math.floor(max))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export {
|
||||||
|
RedundancyUrlManager
|
||||||
|
}
|
|
@ -1,17 +1,9 @@
|
||||||
import { basename } from 'path'
|
|
||||||
import { Segment } from 'p2p-media-loader-core'
|
import { Segment } from 'p2p-media-loader-core'
|
||||||
|
import { RedundancyUrlManager } from './redundancy-url-manager'
|
||||||
|
|
||||||
function segmentUrlBuilderFactory (baseUrls: string[]) {
|
function segmentUrlBuilderFactory (redundancyUrlManager: RedundancyUrlManager) {
|
||||||
return function segmentBuilder (segment: Segment) {
|
return function segmentBuilder (segment: Segment) {
|
||||||
const max = baseUrls.length + 1
|
return redundancyUrlManager.buildUrl(segment.url)
|
||||||
const i = getRandomInt(max)
|
|
||||||
|
|
||||||
if (i === max - 1) return segment.url
|
|
||||||
|
|
||||||
const newBaseUrl = baseUrls[i]
|
|
||||||
const middlePart = newBaseUrl.endsWith('/') ? '' : '/'
|
|
||||||
|
|
||||||
return newBaseUrl + middlePart + basename(segment.url)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,9 +12,3 @@ function segmentUrlBuilderFactory (baseUrls: string[]) {
|
||||||
export {
|
export {
|
||||||
segmentUrlBuilderFactory
|
segmentUrlBuilderFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function getRandomInt (max: number) {
|
|
||||||
return Math.floor(Math.random() * Math.floor(max))
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { buildVideoEmbed, buildVideoLink, copyToClipboard, getRtcConfig } from '
|
||||||
import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n'
|
import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n'
|
||||||
import { segmentValidatorFactory } from './p2p-media-loader/segment-validator'
|
import { segmentValidatorFactory } from './p2p-media-loader/segment-validator'
|
||||||
import { segmentUrlBuilderFactory } from './p2p-media-loader/segment-url-builder'
|
import { segmentUrlBuilderFactory } from './p2p-media-loader/segment-url-builder'
|
||||||
|
import { RedundancyUrlManager } from './p2p-media-loader/redundancy-url-manager'
|
||||||
|
|
||||||
// Change 'Playback Rate' to 'Speed' (smaller for our settings menu)
|
// Change 'Playback Rate' to 'Speed' (smaller for our settings menu)
|
||||||
videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed'
|
videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed'
|
||||||
|
@ -226,8 +227,10 @@ export class PeertubePlayerManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode === 'p2p-media-loader') {
|
if (mode === 'p2p-media-loader') {
|
||||||
|
const redundancyUrlManager = new RedundancyUrlManager(options.p2pMediaLoader.redundancyBaseUrls)
|
||||||
|
|
||||||
const p2pMediaLoader: P2PMediaLoaderPluginOptions = {
|
const p2pMediaLoader: P2PMediaLoaderPluginOptions = {
|
||||||
redundancyBaseUrls: options.p2pMediaLoader.redundancyBaseUrls,
|
redundancyUrlManager,
|
||||||
type: 'application/x-mpegURL',
|
type: 'application/x-mpegURL',
|
||||||
startTime: commonOptions.startTime,
|
startTime: commonOptions.startTime,
|
||||||
src: p2pMediaLoaderOptions.playlistUrl
|
src: p2pMediaLoaderOptions.playlistUrl
|
||||||
|
@ -242,7 +245,7 @@ export class PeertubePlayerManager {
|
||||||
segmentValidator: segmentValidatorFactory(options.p2pMediaLoader.segmentsSha256Url),
|
segmentValidator: segmentValidatorFactory(options.p2pMediaLoader.segmentsSha256Url),
|
||||||
rtcConfig: getRtcConfig(),
|
rtcConfig: getRtcConfig(),
|
||||||
requiredSegmentsPriority: 5,
|
requiredSegmentsPriority: 5,
|
||||||
segmentUrlBuilder: segmentUrlBuilderFactory(options.p2pMediaLoader.redundancyBaseUrls)
|
segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager)
|
||||||
},
|
},
|
||||||
segments: {
|
segments: {
|
||||||
swarmId: p2pMediaLoaderOptions.playlistUrl
|
swarmId: p2pMediaLoaderOptions.playlistUrl
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { PeerTubePlugin } from './peertube-plugin'
|
||||||
import { WebTorrentPlugin } from './webtorrent/webtorrent-plugin'
|
import { WebTorrentPlugin } from './webtorrent/webtorrent-plugin'
|
||||||
import { P2pMediaLoaderPlugin } from './p2p-media-loader/p2p-media-loader-plugin'
|
import { P2pMediaLoaderPlugin } from './p2p-media-loader/p2p-media-loader-plugin'
|
||||||
import { PlayerMode } from './peertube-player-manager'
|
import { PlayerMode } from './peertube-player-manager'
|
||||||
|
import { RedundancyUrlManager } from './p2p-media-loader/redundancy-url-manager'
|
||||||
|
|
||||||
declare namespace videojs {
|
declare namespace videojs {
|
||||||
interface Player {
|
interface Player {
|
||||||
|
@ -62,7 +63,7 @@ type WebtorrentPluginOptions = {
|
||||||
}
|
}
|
||||||
|
|
||||||
type P2PMediaLoaderPluginOptions = {
|
type P2PMediaLoaderPluginOptions = {
|
||||||
redundancyBaseUrls: string[]
|
redundancyUrlManager: RedundancyUrlManager
|
||||||
type: string
|
type: string
|
||||||
src: string
|
src: string
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue