From 55fec605c637ea49f9b39d96e70c5bb1bdce8b61 Mon Sep 17 00:00:00 2001 From: ZGaetano Date: Sat, 16 May 2026 08:20:10 -0400 Subject: [PATCH] feat(capture): accept SRT/RTMP source params in POST /start - Accept source_type, source_url, listen, listen_port, stream_key - Validate: SDI requires device; SRT/RTMP caller requires source_url - Pass all params through to captureManager.start() - On stop: if proxyKey is null (network source), include needsProxy flag in MAM API registration so worker can generate proxy asynchronously --- services/capture/src/routes/capture.js | 54 +++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/services/capture/src/routes/capture.js b/services/capture/src/routes/capture.js index af11eaa..c968645 100644 --- a/services/capture/src/routes/capture.js +++ b/services/capture/src/routes/capture.js @@ -64,15 +64,50 @@ router.get('/status', (req, res) => { /** * POST /start * Start a new capture session - * Body: { project_id, clip_name, device, bin_id? } + * + * Body (SDI): + * { project_id, clip_name, device, bin_id?, source_type? } + * + * Body (SRT/RTMP caller): + * { project_id, clip_name, source_type, source_url, bin_id? } + * + * Body (SRT/RTMP listener): + * { project_id, clip_name, source_type, listen: true, listen_port?, stream_key?, bin_id? } */ router.post('/start', async (req, res) => { try { - const { project_id, bin_id, clip_name, device } = req.body; + const { + project_id, + bin_id, + clip_name, + device, + source_type = 'sdi', + source_url, + listen = false, + listen_port, + stream_key, + } = req.body; - if (!project_id || !clip_name || device === undefined) { + if (!project_id || !clip_name) { return res.status(400).json({ - error: 'Missing required fields: project_id, clip_name, device', + error: 'Missing required fields: project_id, clip_name', + }); + } + + // Source-specific validation + if (source_type === 'sdi') { + if (device === undefined || device === null) { + return res.status(400).json({ error: 'SDI source requires: device' }); + } + } else if (source_type === 'srt' || source_type === 'rtmp') { + if (!listen && !source_url) { + return res.status(400).json({ + error: `${source_type.toUpperCase()} caller mode requires: source_url`, + }); + } + } else { + return res.status(400).json({ + error: `Unknown source_type: ${source_type}. Must be sdi, srt, or rtmp`, }); } @@ -81,6 +116,11 @@ router.post('/start', async (req, res) => { binId: bin_id || null, clipName: clip_name, device, + sourceType: source_type, + sourceUrl: source_url, + listen, + listenPort: listen_port, + streamKey: stream_key, }); res.json(session); @@ -105,7 +145,9 @@ router.post('/stop', async (req, res) => { const completedSession = await captureManager.stop(session_id); - // Register asset with mam-api + // Register asset with mam-api. + // If proxyKey is null (SRT/RTMP source), set needsProxy=true so the + // worker generates a proxy from the hires file asynchronously. try { const mamResponse = await fetch(`${MAM_API_URL}/api/v1/assets`, { method: 'POST', @@ -114,8 +156,10 @@ router.post('/stop', async (req, res) => { projectId: completedSession.projectId, binId: completedSession.binId, clipName: completedSession.clipName, + sourceType: completedSession.sourceType, hiresKey: completedSession.hiresKey, proxyKey: completedSession.proxyKey, + needsProxy: completedSession.proxyKey === null, duration: completedSession.duration, capturedAt: completedSession.startedAt, }),