From d4924b044f5c334040bcbb0e0dae993a31d9e342 Mon Sep 17 00:00:00 2001 From: zgaetano Date: Mon, 1 Jun 2026 07:55:34 -0400 Subject: [PATCH] feat(capture): wire bridge process lifecycle into start/stop for deltacast --- services/capture/src/capture-manager.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/services/capture/src/capture-manager.js b/services/capture/src/capture-manager.js index 2bc99ad..0149656 100644 --- a/services/capture/src/capture-manager.js +++ b/services/capture/src/capture-manager.js @@ -355,7 +355,8 @@ class CaptureManager { const startedAt = new Date().toISOString(); - const { inputArgs, isNetwork } = await this._buildInputArgs({ + this._sessionIdForBridge = sessionId; + const { inputArgs, isNetwork, bridgeProcess = null, audioFifo = null, interlaced = false } = await this._buildInputArgs({ sourceType, device, sourceUrl, listen, listenPort, streamKey, }); @@ -369,7 +370,8 @@ class CaptureManager { console.log('[capture] hires ffmpeg args:', hiresCodecArgs.join(' ')); - const sdiFilterArgs = (sourceType === 'sdi') ? ['-vf', 'yadif=mode=1:deint=1'] : []; + const isInterlacedSource = sourceType === 'sdi' || (sourceType === 'deltacast' && interlaced); + const sdiFilterArgs = isInterlacedSource ? ['-vf', 'yadif=mode=1:deint=1'] : []; // When growing-files is on, write directly to the SMB share so Premier // can mount and edit the live file. Promotion worker uploads to S3 on EOF. @@ -382,7 +384,7 @@ class CaptureManager { // ffmpeg: one decklink read -> yadif -> split -> [ProRes/S3] + [H.264/HLS]. let sdiHlsDir = null; let hiresArgs; - if (sourceType === 'sdi' && this._assetIdForHls) { + if ((sourceType === 'sdi' || sourceType === 'deltacast') && this._assetIdForHls) { const fsMod = await import('node:fs'); sdiHlsDir = '/live/' + this._assetIdForHls; try { fsMod.mkdirSync(sdiHlsDir, { recursive: true }); } catch (_) {} @@ -409,12 +411,16 @@ class CaptureManager { } const hiresProcess = spawn('ffmpeg', hiresArgs, { stdio: hiresStdio }); + if (bridgeProcess) { + bridgeProcess.stdout.pipe(hiresProcess.stdin); + } const hiresUpload = growingPath ? Promise.resolve({ growingPath }) : createUploadStream(S3_BUCKET, hiresKey, hiresProcess.stdout); const processes = { hires: hiresProcess }; + if (bridgeProcess) processes.bridge = bridgeProcess; const uploads = { hires: hiresUpload }; // ── HLS tee for network sources (live preview in the UI) ────────── @@ -478,6 +484,7 @@ class CaptureManager { device, sourceType, sourceUrl, + audioFifo, hiresKey, proxyKey, growingPath, @@ -505,6 +512,7 @@ class CaptureManager { if (processes.hires) processes.hires.kill('SIGINT'); if (processes.proxy) processes.proxy.kill('SIGINT'); if (processes.hls) { try { processes.hls.kill('SIGINT'); } catch (_) {} } + if (processes.bridge) { try { processes.bridge.kill('SIGINT'); } catch (_) {} } try { const uploadPromises = [currentSession.uploads.hires]; @@ -514,6 +522,10 @@ class CaptureManager { console.error('Error during upload completion:', error); } + if (currentSession.audioFifo) { + try { (await import('node:fs')).unlinkSync(currentSession.audioFifo); } catch (_) {} + } + const stoppedAt = new Date().toISOString(); const startTime = new Date(currentSession.startedAt); const stopTime = new Date(stoppedAt);