]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/lib/live/live-manager.ts
Don't run ffmpeg twice for lives
[github/Chocobozzz/PeerTube.git] / server / lib / live / live-manager.ts
index c78cf82eb41ec11dab1d9d2a7cdd988f14d4e5c1..68aa184431e3c96e21b8d986cad26321d935f00e 100644 (file)
@@ -4,8 +4,9 @@ import { join } from 'path'
 import { createServer as createServerTLS, Server as ServerTLS } from 'tls'
 import { logger, loggerTagsFactory } from '@server/helpers/logger'
 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 { RunnerJobModel } from '@server/models/runner/runner-job'
 import { UserModel } from '@server/models/user/user'
 import { VideoModel } from '@server/models/video/video'
 import { VideoLiveModel } from '@server/models/video/video-live'
@@ -25,7 +26,6 @@ import { computeResolutionsToTranscode } from '../transcoding/transcoding-resolu
 import { LiveQuotaStore } from './live-quota-store'
 import { cleanupAndDestroyPermanentLive, getLiveSegmentTime } from './live-utils'
 import { MuxingSession } from './shared'
-import { RunnerJobModel } from '@server/models/runner/runner-job'
 
 const NodeRtmpSession = require('node-media-server/src/node_rtmp_session')
 const context = require('node-media-server/src/node_core_ctx')
@@ -73,13 +73,18 @@ class LiveManager {
       }
 
       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) }))
     })
 
     events.on('donePublish', sessionId => {
       logger.info('Live session ended.', { sessionId, ...lTags(sessionId) })
+
+      // Force session aborting, so we kill ffmpeg even if it still has data to process (slow CPU)
+      setTimeout(() => this.abortSession(sessionId), 2000)
     })
 
     registerConfigChangedHandler(() => {
@@ -107,7 +112,8 @@ class LiveManager {
       this.rtmpServer = createServer(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()
       })
 
@@ -130,7 +136,8 @@ class LiveManager {
       this.rtmpsServer = createServerTLS(serverOptions, 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()
       })
 
@@ -207,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)
     if (!videoLive) {
       logger.warn('Unknown live video with stream key %s.', streamKey, lTags(sessionId))
@@ -236,18 +250,18 @@ class LiveManager {
     this.videoSessions.set(video.uuid, sessionId)
 
     const now = Date.now()
-    const probe = await ffprobePromise(inputUrl)
+    const probe = await ffprobePromise(inputLocalUrl)
 
     const [ { resolution, ratio }, fps, bitrate, hasAudio ] = await Promise.all([
-      getVideoStreamDimensionsInfo(inputUrl, probe),
-      getVideoStreamFPS(inputUrl, probe),
-      getVideoStreamBitrate(inputUrl, probe),
-      hasAudioStream(inputUrl, probe)
+      getVideoStreamDimensionsInfo(inputLocalUrl, probe),
+      getVideoStreamFPS(inputLocalUrl, probe),
+      getVideoStreamBitrate(inputLocalUrl, probe),
+      hasAudioStream(inputLocalUrl, probe)
     ])
 
     logger.info(
       '%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(
@@ -265,7 +279,8 @@ class LiveManager {
       sessionId,
       videoLive,
 
-      inputUrl,
+      inputLocalUrl,
+      inputPublicUrl,
       fps,
       bitrate,
       ratio,
@@ -278,7 +293,9 @@ class LiveManager {
     sessionId: string
     videoLive: MVideoLiveVideoWithSetting
 
-    inputUrl: string
+    inputLocalUrl: string
+    inputPublicUrl: string
+
     fps: number
     bitrate: number
     ratio: number
@@ -300,7 +317,7 @@ class LiveManager {
       videoLive,
       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))