Provide public RTMP URL to runners
This commit is contained in:
parent
b30ad9888f
commit
2870570505
7 changed files with 67 additions and 30 deletions
|
@ -55,8 +55,12 @@ const WEBSERVER = {
|
||||||
WS: '',
|
WS: '',
|
||||||
HOSTNAME: '',
|
HOSTNAME: '',
|
||||||
PORT: 0,
|
PORT: 0,
|
||||||
|
|
||||||
RTMP_URL: '',
|
RTMP_URL: '',
|
||||||
RTMPS_URL: ''
|
RTMPS_URL: '',
|
||||||
|
|
||||||
|
RTMP_BASE_LIVE_URL: '',
|
||||||
|
RTMPS_BASE_LIVE_URL: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sortable columns per schema
|
// Sortable columns per schema
|
||||||
|
@ -1242,8 +1246,11 @@ function updateWebserverUrls () {
|
||||||
const rtmpHostname = CONFIG.LIVE.RTMP.PUBLIC_HOSTNAME || CONFIG.WEBSERVER.HOSTNAME
|
const rtmpHostname = CONFIG.LIVE.RTMP.PUBLIC_HOSTNAME || CONFIG.WEBSERVER.HOSTNAME
|
||||||
const rtmpsHostname = CONFIG.LIVE.RTMPS.PUBLIC_HOSTNAME || CONFIG.WEBSERVER.HOSTNAME
|
const rtmpsHostname = CONFIG.LIVE.RTMPS.PUBLIC_HOSTNAME || CONFIG.WEBSERVER.HOSTNAME
|
||||||
|
|
||||||
WEBSERVER.RTMP_URL = 'rtmp://' + rtmpHostname + ':' + CONFIG.LIVE.RTMP.PORT + '/' + VIDEO_LIVE.RTMP.BASE_PATH
|
WEBSERVER.RTMP_URL = 'rtmp://' + rtmpHostname + ':' + CONFIG.LIVE.RTMP.PORT
|
||||||
WEBSERVER.RTMPS_URL = 'rtmps://' + rtmpsHostname + ':' + CONFIG.LIVE.RTMPS.PORT + '/' + VIDEO_LIVE.RTMP.BASE_PATH
|
WEBSERVER.RTMPS_URL = 'rtmps://' + rtmpsHostname + ':' + CONFIG.LIVE.RTMPS.PORT
|
||||||
|
|
||||||
|
WEBSERVER.RTMP_BASE_LIVE_URL = WEBSERVER.RTMP_URL + '/' + VIDEO_LIVE.RTMP.BASE_PATH
|
||||||
|
WEBSERVER.RTMPS_BASE_LIVE_URL = WEBSERVER.RTMPS_URL + '/' + VIDEO_LIVE.RTMP.BASE_PATH
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateWebserverConfig () {
|
function updateWebserverConfig () {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { join } from 'path'
|
||||||
import { createServer as createServerTLS, Server as ServerTLS } from 'tls'
|
import { createServer as createServerTLS, Server as ServerTLS } from 'tls'
|
||||||
import { logger, loggerTagsFactory } from '@server/helpers/logger'
|
import { logger, loggerTagsFactory } from '@server/helpers/logger'
|
||||||
import { CONFIG, registerConfigChangedHandler } from '@server/initializers/config'
|
import { CONFIG, registerConfigChangedHandler } from '@server/initializers/config'
|
||||||
import { VIDEO_LIVE } from '@server/initializers/constants'
|
import { VIDEO_LIVE, WEBSERVER } from '@server/initializers/constants'
|
||||||
import { sequelizeTypescript } from '@server/initializers/database'
|
import { sequelizeTypescript } from '@server/initializers/database'
|
||||||
import { RunnerJobModel } from '@server/models/runner/runner-job'
|
import { RunnerJobModel } from '@server/models/runner/runner-job'
|
||||||
import { UserModel } from '@server/models/user/user'
|
import { UserModel } from '@server/models/user/user'
|
||||||
|
@ -73,8 +73,10 @@ class LiveManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
const session = this.getContext().sessions.get(sessionId)
|
const session = this.getContext().sessions.get(sessionId)
|
||||||
|
const inputLocalUrl = session.inputOriginLocalUrl + streamPath
|
||||||
|
const inputPublicUrl = session.inputOriginPublicUrl + streamPath
|
||||||
|
|
||||||
this.handleSession(sessionId, session.inputOriginUrl + streamPath, splittedPath[2])
|
this.handleSession({ sessionId, inputPublicUrl, inputLocalUrl, streamKey: splittedPath[2] })
|
||||||
.catch(err => logger.error('Cannot handle sessions.', { err, ...lTags(sessionId) }))
|
.catch(err => logger.error('Cannot handle sessions.', { err, ...lTags(sessionId) }))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -110,7 +112,8 @@ class LiveManager {
|
||||||
this.rtmpServer = createServer(socket => {
|
this.rtmpServer = createServer(socket => {
|
||||||
const session = new NodeRtmpSession(config, socket)
|
const session = new NodeRtmpSession(config, socket)
|
||||||
|
|
||||||
session.inputOriginUrl = 'rtmp://127.0.0.1:' + CONFIG.LIVE.RTMP.PORT
|
session.inputOriginLocalUrl = 'rtmp://127.0.0.1:' + CONFIG.LIVE.RTMP.PORT
|
||||||
|
session.inputOriginPublicUrl = WEBSERVER.RTMP_URL
|
||||||
session.run()
|
session.run()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -133,7 +136,8 @@ class LiveManager {
|
||||||
this.rtmpsServer = createServerTLS(serverOptions, socket => {
|
this.rtmpsServer = createServerTLS(serverOptions, socket => {
|
||||||
const session = new NodeRtmpSession(config, socket)
|
const session = new NodeRtmpSession(config, socket)
|
||||||
|
|
||||||
session.inputOriginUrl = 'rtmps://127.0.0.1:' + CONFIG.LIVE.RTMPS.PORT
|
session.inputOriginLocalUrl = 'rtmps://127.0.0.1:' + CONFIG.LIVE.RTMPS.PORT
|
||||||
|
session.inputOriginPublicUrl = WEBSERVER.RTMPS_URL
|
||||||
session.run()
|
session.run()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -210,7 +214,14 @@ class LiveManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleSession (sessionId: string, inputUrl: string, streamKey: string) {
|
private async handleSession (options: {
|
||||||
|
sessionId: string
|
||||||
|
inputLocalUrl: string
|
||||||
|
inputPublicUrl: string
|
||||||
|
streamKey: string
|
||||||
|
}) {
|
||||||
|
const { inputLocalUrl, inputPublicUrl, sessionId, streamKey } = options
|
||||||
|
|
||||||
const videoLive = await VideoLiveModel.loadByStreamKey(streamKey)
|
const videoLive = await VideoLiveModel.loadByStreamKey(streamKey)
|
||||||
if (!videoLive) {
|
if (!videoLive) {
|
||||||
logger.warn('Unknown live video with stream key %s.', streamKey, lTags(sessionId))
|
logger.warn('Unknown live video with stream key %s.', streamKey, lTags(sessionId))
|
||||||
|
@ -239,18 +250,18 @@ class LiveManager {
|
||||||
this.videoSessions.set(video.uuid, sessionId)
|
this.videoSessions.set(video.uuid, sessionId)
|
||||||
|
|
||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
const probe = await ffprobePromise(inputUrl)
|
const probe = await ffprobePromise(inputLocalUrl)
|
||||||
|
|
||||||
const [ { resolution, ratio }, fps, bitrate, hasAudio ] = await Promise.all([
|
const [ { resolution, ratio }, fps, bitrate, hasAudio ] = await Promise.all([
|
||||||
getVideoStreamDimensionsInfo(inputUrl, probe),
|
getVideoStreamDimensionsInfo(inputLocalUrl, probe),
|
||||||
getVideoStreamFPS(inputUrl, probe),
|
getVideoStreamFPS(inputLocalUrl, probe),
|
||||||
getVideoStreamBitrate(inputUrl, probe),
|
getVideoStreamBitrate(inputLocalUrl, probe),
|
||||||
hasAudioStream(inputUrl, probe)
|
hasAudioStream(inputLocalUrl, probe)
|
||||||
])
|
])
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
'%s probing took %d ms (bitrate: %d, fps: %d, resolution: %d)',
|
'%s probing took %d ms (bitrate: %d, fps: %d, resolution: %d)',
|
||||||
inputUrl, Date.now() - now, bitrate, fps, resolution, lTags(sessionId, video.uuid)
|
inputLocalUrl, Date.now() - now, bitrate, fps, resolution, lTags(sessionId, video.uuid)
|
||||||
)
|
)
|
||||||
|
|
||||||
const allResolutions = await Hooks.wrapObject(
|
const allResolutions = await Hooks.wrapObject(
|
||||||
|
@ -268,7 +279,8 @@ class LiveManager {
|
||||||
sessionId,
|
sessionId,
|
||||||
videoLive,
|
videoLive,
|
||||||
|
|
||||||
inputUrl,
|
inputLocalUrl,
|
||||||
|
inputPublicUrl,
|
||||||
fps,
|
fps,
|
||||||
bitrate,
|
bitrate,
|
||||||
ratio,
|
ratio,
|
||||||
|
@ -281,7 +293,9 @@ class LiveManager {
|
||||||
sessionId: string
|
sessionId: string
|
||||||
videoLive: MVideoLiveVideoWithSetting
|
videoLive: MVideoLiveVideoWithSetting
|
||||||
|
|
||||||
inputUrl: string
|
inputLocalUrl: string
|
||||||
|
inputPublicUrl: string
|
||||||
|
|
||||||
fps: number
|
fps: number
|
||||||
bitrate: number
|
bitrate: number
|
||||||
ratio: number
|
ratio: number
|
||||||
|
@ -303,7 +317,7 @@ class LiveManager {
|
||||||
videoLive,
|
videoLive,
|
||||||
user,
|
user,
|
||||||
|
|
||||||
...pick(options, [ 'inputUrl', 'bitrate', 'ratio', 'fps', 'allResolutions', 'hasAudio' ])
|
...pick(options, [ 'inputLocalUrl', 'inputPublicUrl', 'bitrate', 'ratio', 'fps', 'allResolutions', 'hasAudio' ])
|
||||||
})
|
})
|
||||||
|
|
||||||
muxingSession.on('live-ready', () => this.publishAndFederateLive(videoLive, localLTags))
|
muxingSession.on('live-ready', () => this.publishAndFederateLive(videoLive, localLTags))
|
||||||
|
|
|
@ -62,7 +62,10 @@ class MuxingSession extends EventEmitter {
|
||||||
private readonly user: MUserId
|
private readonly user: MUserId
|
||||||
private readonly sessionId: string
|
private readonly sessionId: string
|
||||||
private readonly videoLive: MVideoLiveVideo
|
private readonly videoLive: MVideoLiveVideo
|
||||||
private readonly inputUrl: string
|
|
||||||
|
private readonly inputLocalUrl: string
|
||||||
|
private readonly inputPublicUrl: string
|
||||||
|
|
||||||
private readonly fps: number
|
private readonly fps: number
|
||||||
private readonly allResolutions: number[]
|
private readonly allResolutions: number[]
|
||||||
|
|
||||||
|
@ -107,7 +110,10 @@ class MuxingSession extends EventEmitter {
|
||||||
user: MUserId
|
user: MUserId
|
||||||
sessionId: string
|
sessionId: string
|
||||||
videoLive: MVideoLiveVideo
|
videoLive: MVideoLiveVideo
|
||||||
inputUrl: string
|
|
||||||
|
inputLocalUrl: string
|
||||||
|
inputPublicUrl: string
|
||||||
|
|
||||||
fps: number
|
fps: number
|
||||||
bitrate: number
|
bitrate: number
|
||||||
ratio: number
|
ratio: number
|
||||||
|
@ -120,7 +126,10 @@ class MuxingSession extends EventEmitter {
|
||||||
this.user = options.user
|
this.user = options.user
|
||||||
this.sessionId = options.sessionId
|
this.sessionId = options.sessionId
|
||||||
this.videoLive = options.videoLive
|
this.videoLive = options.videoLive
|
||||||
this.inputUrl = options.inputUrl
|
|
||||||
|
this.inputLocalUrl = options.inputLocalUrl
|
||||||
|
this.inputPublicUrl = options.inputPublicUrl
|
||||||
|
|
||||||
this.fps = options.fps
|
this.fps = options.fps
|
||||||
|
|
||||||
this.bitrate = options.bitrate
|
this.bitrate = options.bitrate
|
||||||
|
@ -375,7 +384,7 @@ class MuxingSession extends EventEmitter {
|
||||||
private onTranscodedEnded () {
|
private onTranscodedEnded () {
|
||||||
this.emit('transcoding-end', ({ videoUUID: this.videoUUID }))
|
this.emit('transcoding-end', ({ videoUUID: this.videoUUID }))
|
||||||
|
|
||||||
logger.info('RTMP transmuxing for video %s ended. Scheduling cleanup', this.inputUrl, this.lTags())
|
logger.info('RTMP transmuxing for video %s ended. Scheduling cleanup', this.inputLocalUrl, this.lTags())
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// Wait latest segments generation, and close watchers
|
// Wait latest segments generation, and close watchers
|
||||||
|
@ -468,7 +477,8 @@ class MuxingSession extends EventEmitter {
|
||||||
|
|
||||||
lTags: this.lTags,
|
lTags: this.lTags,
|
||||||
|
|
||||||
inputUrl: this.inputUrl,
|
inputLocalUrl: this.inputLocalUrl,
|
||||||
|
inputPublicUrl: this.inputPublicUrl,
|
||||||
|
|
||||||
toTranscode: this.allResolutions.map(resolution => ({
|
toTranscode: this.allResolutions.map(resolution => ({
|
||||||
resolution,
|
resolution,
|
||||||
|
|
|
@ -25,7 +25,9 @@ interface AbstractTranscodingWrapperOptions {
|
||||||
|
|
||||||
lTags: LoggerTagsFn
|
lTags: LoggerTagsFn
|
||||||
|
|
||||||
inputUrl: string
|
inputLocalUrl: string
|
||||||
|
inputPublicUrl: string
|
||||||
|
|
||||||
fps: number
|
fps: number
|
||||||
toTranscode: {
|
toTranscode: {
|
||||||
resolution: number
|
resolution: number
|
||||||
|
@ -50,7 +52,9 @@ abstract class AbstractTranscodingWrapper extends EventEmitter {
|
||||||
fps: number
|
fps: number
|
||||||
}[]
|
}[]
|
||||||
|
|
||||||
protected readonly inputUrl: string
|
protected readonly inputLocalUrl: string
|
||||||
|
protected readonly inputPublicUrl: string
|
||||||
|
|
||||||
protected readonly fps: number
|
protected readonly fps: number
|
||||||
protected readonly bitrate: number
|
protected readonly bitrate: number
|
||||||
protected readonly ratio: number
|
protected readonly ratio: number
|
||||||
|
@ -76,7 +80,9 @@ abstract class AbstractTranscodingWrapper extends EventEmitter {
|
||||||
this.videoUUID = options.videoLive.Video.uuid
|
this.videoUUID = options.videoLive.Video.uuid
|
||||||
this.streamingPlaylist = options.streamingPlaylist
|
this.streamingPlaylist = options.streamingPlaylist
|
||||||
|
|
||||||
this.inputUrl = options.inputUrl
|
this.inputLocalUrl = options.inputLocalUrl
|
||||||
|
this.inputPublicUrl = options.inputPublicUrl
|
||||||
|
|
||||||
this.fps = options.fps
|
this.fps = options.fps
|
||||||
this.toTranscode = options.toTranscode
|
this.toTranscode = options.toTranscode
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ export class FFmpegTranscodingWrapper extends AbstractTranscodingWrapper {
|
||||||
async run () {
|
async run () {
|
||||||
this.ffmpegCommand = CONFIG.LIVE.TRANSCODING.ENABLED
|
this.ffmpegCommand = CONFIG.LIVE.TRANSCODING.ENABLED
|
||||||
? await this.buildFFmpegLive().getLiveTranscodingCommand({
|
? await this.buildFFmpegLive().getLiveTranscodingCommand({
|
||||||
inputUrl: this.inputUrl,
|
inputUrl: this.inputLocalUrl,
|
||||||
|
|
||||||
outPath: this.outDirectory,
|
outPath: this.outDirectory,
|
||||||
masterPlaylistName: this.streamingPlaylist.playlistFilename,
|
masterPlaylistName: this.streamingPlaylist.playlistFilename,
|
||||||
|
@ -31,7 +31,7 @@ export class FFmpegTranscodingWrapper extends AbstractTranscodingWrapper {
|
||||||
hasAudio: this.hasAudio
|
hasAudio: this.hasAudio
|
||||||
})
|
})
|
||||||
: this.buildFFmpegLive().getLiveMuxingCommand({
|
: this.buildFFmpegLive().getLiveMuxingCommand({
|
||||||
inputUrl: this.inputUrl,
|
inputUrl: this.inputLocalUrl,
|
||||||
outPath: this.outDirectory,
|
outPath: this.outDirectory,
|
||||||
|
|
||||||
masterPlaylistName: this.streamingPlaylist.playlistFilename,
|
masterPlaylistName: this.streamingPlaylist.playlistFilename,
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { AbstractTranscodingWrapper } from './abstract-transcoding-wrapper'
|
||||||
export class RemoteTranscodingWrapper extends AbstractTranscodingWrapper {
|
export class RemoteTranscodingWrapper extends AbstractTranscodingWrapper {
|
||||||
async run () {
|
async run () {
|
||||||
await new LiveRTMPHLSTranscodingJobHandler().create({
|
await new LiveRTMPHLSTranscodingJobHandler().create({
|
||||||
rtmpUrl: this.inputUrl,
|
rtmpUrl: this.inputPublicUrl,
|
||||||
toTranscode: this.toTranscode,
|
toTranscode: this.toTranscode,
|
||||||
video: this.videoLive.Video,
|
video: this.videoLive.Video,
|
||||||
outputDirectory: this.outDirectory,
|
outputDirectory: this.outDirectory,
|
||||||
|
|
|
@ -159,11 +159,11 @@ export class VideoLiveModel extends Model<Partial<AttributesOnly<VideoLiveModel>
|
||||||
streamKey: this.streamKey,
|
streamKey: this.streamKey,
|
||||||
|
|
||||||
rtmpUrl: CONFIG.LIVE.RTMP.ENABLED
|
rtmpUrl: CONFIG.LIVE.RTMP.ENABLED
|
||||||
? WEBSERVER.RTMP_URL
|
? WEBSERVER.RTMP_BASE_LIVE_URL
|
||||||
: null,
|
: null,
|
||||||
|
|
||||||
rtmpsUrl: CONFIG.LIVE.RTMPS.ENABLED
|
rtmpsUrl: CONFIG.LIVE.RTMPS.ENABLED
|
||||||
? WEBSERVER.RTMPS_URL
|
? WEBSERVER.RTMPS_BASE_LIVE_URL
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue