aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/live/shared
diff options
context:
space:
mode:
Diffstat (limited to 'server/lib/live/shared')
-rw-r--r--server/lib/live/shared/muxing-session.ts71
1 files changed, 48 insertions, 23 deletions
diff --git a/server/lib/live/shared/muxing-session.ts b/server/lib/live/shared/muxing-session.ts
index 25ecf1c64..2727fc4a7 100644
--- a/server/lib/live/shared/muxing-session.ts
+++ b/server/lib/live/shared/muxing-session.ts
@@ -1,4 +1,3 @@
1
2import { mapSeries } from 'bluebird' 1import { mapSeries } from 'bluebird'
3import { FSWatcher, watch } from 'chokidar' 2import { FSWatcher, watch } from 'chokidar'
4import { FfmpegCommand } from 'fluent-ffmpeg' 3import { FfmpegCommand } from 'fluent-ffmpeg'
@@ -9,12 +8,18 @@ import { EventEmitter } from 'stream'
9import { getLiveMuxingCommand, getLiveTranscodingCommand } from '@server/helpers/ffmpeg' 8import { getLiveMuxingCommand, getLiveTranscodingCommand } from '@server/helpers/ffmpeg'
10import { logger, loggerTagsFactory, LoggerTagsFn } from '@server/helpers/logger' 9import { logger, loggerTagsFactory, LoggerTagsFn } from '@server/helpers/logger'
11import { CONFIG } from '@server/initializers/config' 10import { CONFIG } from '@server/initializers/config'
12import { MEMOIZE_TTL, VIDEO_LIVE } from '@server/initializers/constants' 11import { MEMOIZE_TTL, P2P_MEDIA_LOADER_PEER_VERSION, VIDEO_LIVE } from '@server/initializers/constants'
13import { removeHLSFileObjectStorageByPath, storeHLSFileFromFilename, storeHLSFileFromPath } from '@server/lib/object-storage' 12import { removeHLSFileObjectStorageByPath, storeHLSFileFromFilename, storeHLSFileFromPath } from '@server/lib/object-storage'
14import { VideoFileModel } from '@server/models/video/video-file' 13import { VideoFileModel } from '@server/models/video/video-file'
14import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist'
15import { MStreamingPlaylistVideo, MUserId, MVideoLiveVideo } from '@server/types/models' 15import { MStreamingPlaylistVideo, MUserId, MVideoLiveVideo } from '@server/types/models'
16import { VideoStorage } from '@shared/models' 16import { VideoStorage, VideoStreamingPlaylistType } from '@shared/models'
17import { getLiveDirectory, getLiveReplayBaseDirectory } from '../../paths' 17import {
18 generateHLSMasterPlaylistFilename,
19 generateHlsSha256SegmentsFilename,
20 getLiveDirectory,
21 getLiveReplayBaseDirectory
22} from '../../paths'
18import { VideoTranscodingProfilesManager } from '../../transcoding/default-transcoding-profiles' 23import { VideoTranscodingProfilesManager } from '../../transcoding/default-transcoding-profiles'
19import { isAbleToUploadVideo } from '../../user' 24import { isAbleToUploadVideo } from '../../user'
20import { LiveQuotaStore } from '../live-quota-store' 25import { LiveQuotaStore } from '../live-quota-store'
@@ -53,7 +58,6 @@ class MuxingSession extends EventEmitter {
53 private readonly user: MUserId 58 private readonly user: MUserId
54 private readonly sessionId: string 59 private readonly sessionId: string
55 private readonly videoLive: MVideoLiveVideo 60 private readonly videoLive: MVideoLiveVideo
56 private readonly streamingPlaylist: MStreamingPlaylistVideo
57 private readonly inputUrl: string 61 private readonly inputUrl: string
58 private readonly fps: number 62 private readonly fps: number
59 private readonly allResolutions: number[] 63 private readonly allResolutions: number[]
@@ -70,12 +74,13 @@ class MuxingSession extends EventEmitter {
70 private readonly outDirectory: string 74 private readonly outDirectory: string
71 private readonly replayDirectory: string 75 private readonly replayDirectory: string
72 76
73 private readonly liveSegmentShaStore: LiveSegmentShaStore
74
75 private readonly lTags: LoggerTagsFn 77 private readonly lTags: LoggerTagsFn
76 78
77 private segmentsToProcessPerPlaylist: { [playlistId: string]: string[] } = {} 79 private segmentsToProcessPerPlaylist: { [playlistId: string]: string[] } = {}
78 80
81 private streamingPlaylist: MStreamingPlaylistVideo
82 private liveSegmentShaStore: LiveSegmentShaStore
83
79 private tsWatcher: FSWatcher 84 private tsWatcher: FSWatcher
80 private masterWatcher: FSWatcher 85 private masterWatcher: FSWatcher
81 private m3u8Watcher: FSWatcher 86 private m3u8Watcher: FSWatcher
@@ -98,7 +103,6 @@ class MuxingSession extends EventEmitter {
98 user: MUserId 103 user: MUserId
99 sessionId: string 104 sessionId: string
100 videoLive: MVideoLiveVideo 105 videoLive: MVideoLiveVideo
101 streamingPlaylist: MStreamingPlaylistVideo
102 inputUrl: string 106 inputUrl: string
103 fps: number 107 fps: number
104 bitrate: number 108 bitrate: number
@@ -112,7 +116,6 @@ class MuxingSession extends EventEmitter {
112 this.user = options.user 116 this.user = options.user
113 this.sessionId = options.sessionId 117 this.sessionId = options.sessionId
114 this.videoLive = options.videoLive 118 this.videoLive = options.videoLive
115 this.streamingPlaylist = options.streamingPlaylist
116 this.inputUrl = options.inputUrl 119 this.inputUrl = options.inputUrl
117 this.fps = options.fps 120 this.fps = options.fps
118 121
@@ -131,17 +134,13 @@ class MuxingSession extends EventEmitter {
131 this.outDirectory = getLiveDirectory(this.videoLive.Video) 134 this.outDirectory = getLiveDirectory(this.videoLive.Video)
132 this.replayDirectory = join(getLiveReplayBaseDirectory(this.videoLive.Video), new Date().toISOString()) 135 this.replayDirectory = join(getLiveReplayBaseDirectory(this.videoLive.Video), new Date().toISOString())
133 136
134 this.liveSegmentShaStore = new LiveSegmentShaStore({
135 videoUUID: this.videoLive.Video.uuid,
136 sha256Path: join(this.outDirectory, this.streamingPlaylist.segmentsSha256Filename),
137 streamingPlaylist: this.streamingPlaylist,
138 sendToObjectStorage: CONFIG.OBJECT_STORAGE.ENABLED
139 })
140
141 this.lTags = loggerTagsFactory('live', this.sessionId, this.videoUUID) 137 this.lTags = loggerTagsFactory('live', this.sessionId, this.videoUUID)
142 } 138 }
143 139
144 async runMuxing () { 140 async runMuxing () {
141 this.streamingPlaylist = await this.createLivePlaylist()
142
143 this.createLiveShaStore()
145 this.createFiles() 144 this.createFiles()
146 145
147 await this.prepareDirectories() 146 await this.prepareDirectories()
@@ -257,17 +256,18 @@ class MuxingSession extends EventEmitter {
257 this.masterWatcher = watch(this.outDirectory + '/' + this.streamingPlaylist.playlistFilename) 256 this.masterWatcher = watch(this.outDirectory + '/' + this.streamingPlaylist.playlistFilename)
258 257
259 this.masterWatcher.on('add', async () => { 258 this.masterWatcher.on('add', async () => {
260 if (this.streamingPlaylist.storage === VideoStorage.OBJECT_STORAGE) { 259 try {
261 try { 260 if (this.streamingPlaylist.storage === VideoStorage.OBJECT_STORAGE) {
262 const url = await storeHLSFileFromFilename(this.streamingPlaylist, this.streamingPlaylist.playlistFilename) 261 const url = await storeHLSFileFromFilename(this.streamingPlaylist, this.streamingPlaylist.playlistFilename)
263 262
264 this.streamingPlaylist.playlistUrl = url 263 this.streamingPlaylist.playlistUrl = url
265 this.streamingPlaylist.assignP2PMediaLoaderInfoHashes(this.videoLive.Video, this.allResolutions)
266
267 await this.streamingPlaylist.save()
268 } catch (err) {
269 logger.error('Cannot upload live master file to object storage.', { err, ...this.lTags() })
270 } 264 }
265
266 this.streamingPlaylist.assignP2PMediaLoaderInfoHashes(this.videoLive.Video, this.allResolutions)
267
268 await this.streamingPlaylist.save()
269 } catch (err) {
270 logger.error('Cannot update streaming playlist.', { err, ...this.lTags() })
271 } 271 }
272 272
273 this.masterPlaylistCreated = true 273 this.masterPlaylistCreated = true
@@ -478,6 +478,31 @@ class MuxingSession extends EventEmitter {
478 logger.error('Cannot copy segment %s to replay directory.', segmentPath, { err, ...this.lTags() }) 478 logger.error('Cannot copy segment %s to replay directory.', segmentPath, { err, ...this.lTags() })
479 } 479 }
480 } 480 }
481
482 private async createLivePlaylist (): Promise<MStreamingPlaylistVideo> {
483 const playlist = await VideoStreamingPlaylistModel.loadOrGenerate(this.videoLive.Video)
484
485 playlist.playlistFilename = generateHLSMasterPlaylistFilename(true)
486 playlist.segmentsSha256Filename = generateHlsSha256SegmentsFilename(true)
487
488 playlist.p2pMediaLoaderPeerVersion = P2P_MEDIA_LOADER_PEER_VERSION
489 playlist.type = VideoStreamingPlaylistType.HLS
490
491 playlist.storage = CONFIG.OBJECT_STORAGE.ENABLED
492 ? VideoStorage.OBJECT_STORAGE
493 : VideoStorage.FILE_SYSTEM
494
495 return playlist.save()
496 }
497
498 private createLiveShaStore () {
499 this.liveSegmentShaStore = new LiveSegmentShaStore({
500 videoUUID: this.videoLive.Video.uuid,
501 sha256Path: join(this.outDirectory, this.streamingPlaylist.segmentsSha256Filename),
502 streamingPlaylist: this.streamingPlaylist,
503 sendToObjectStorage: CONFIG.OBJECT_STORAGE.ENABLED
504 })
505 }
481} 506}
482 507
483// --------------------------------------------------------------------------- 508// ---------------------------------------------------------------------------