diff options
Diffstat (limited to 'server/lib/live/shared')
-rw-r--r-- | server/lib/live/shared/muxing-session.ts | 71 |
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 | |||
2 | import { mapSeries } from 'bluebird' | 1 | import { mapSeries } from 'bluebird' |
3 | import { FSWatcher, watch } from 'chokidar' | 2 | import { FSWatcher, watch } from 'chokidar' |
4 | import { FfmpegCommand } from 'fluent-ffmpeg' | 3 | import { FfmpegCommand } from 'fluent-ffmpeg' |
@@ -9,12 +8,18 @@ import { EventEmitter } from 'stream' | |||
9 | import { getLiveMuxingCommand, getLiveTranscodingCommand } from '@server/helpers/ffmpeg' | 8 | import { getLiveMuxingCommand, getLiveTranscodingCommand } from '@server/helpers/ffmpeg' |
10 | import { logger, loggerTagsFactory, LoggerTagsFn } from '@server/helpers/logger' | 9 | import { logger, loggerTagsFactory, LoggerTagsFn } from '@server/helpers/logger' |
11 | import { CONFIG } from '@server/initializers/config' | 10 | import { CONFIG } from '@server/initializers/config' |
12 | import { MEMOIZE_TTL, VIDEO_LIVE } from '@server/initializers/constants' | 11 | import { MEMOIZE_TTL, P2P_MEDIA_LOADER_PEER_VERSION, VIDEO_LIVE } from '@server/initializers/constants' |
13 | import { removeHLSFileObjectStorageByPath, storeHLSFileFromFilename, storeHLSFileFromPath } from '@server/lib/object-storage' | 12 | import { removeHLSFileObjectStorageByPath, storeHLSFileFromFilename, storeHLSFileFromPath } from '@server/lib/object-storage' |
14 | import { VideoFileModel } from '@server/models/video/video-file' | 13 | import { VideoFileModel } from '@server/models/video/video-file' |
14 | import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist' | ||
15 | import { MStreamingPlaylistVideo, MUserId, MVideoLiveVideo } from '@server/types/models' | 15 | import { MStreamingPlaylistVideo, MUserId, MVideoLiveVideo } from '@server/types/models' |
16 | import { VideoStorage } from '@shared/models' | 16 | import { VideoStorage, VideoStreamingPlaylistType } from '@shared/models' |
17 | import { getLiveDirectory, getLiveReplayBaseDirectory } from '../../paths' | 17 | import { |
18 | generateHLSMasterPlaylistFilename, | ||
19 | generateHlsSha256SegmentsFilename, | ||
20 | getLiveDirectory, | ||
21 | getLiveReplayBaseDirectory | ||
22 | } from '../../paths' | ||
18 | import { VideoTranscodingProfilesManager } from '../../transcoding/default-transcoding-profiles' | 23 | import { VideoTranscodingProfilesManager } from '../../transcoding/default-transcoding-profiles' |
19 | import { isAbleToUploadVideo } from '../../user' | 24 | import { isAbleToUploadVideo } from '../../user' |
20 | import { LiveQuotaStore } from '../live-quota-store' | 25 | import { 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 | // --------------------------------------------------------------------------- |