import { LiveVideoStartPayload } from '@peertube/peertube-models' import { logger, loggerTagsFactory } from '@server/helpers/logger.js' import { startScheduledLiveSession } from '@server/controllers/api/live-stream.js' import { CONFIG } from '@server/initializers/config.js' import { LiveVideoProcessManager } from '@server/lib/live-videos/live-video-process-manager.js' import { LIVE_VIDEO_START_LEAD_TIME_MS } from '@server/lib/live-videos/shared.js' import { LiveVideoModel, LiveVideoStatus } from '@server/models/video/live-video.js' import { Job } from 'bullmq' import { setTimeout as wait } from 'node:timers/promises' const lTags = loggerTagsFactory('jobs', 'live-video-start') const LIVE_VIDEO_START_POLL_MS = 5_000 export async function processLiveVideoStart (job: Job) { const payload = job.data as LiveVideoStartPayload let liveVideo: LiveVideoModel while (true) { const currentLiveVideo = await LiveVideoModel.loadById(payload.liveVideoId) if (!currentLiveVideo) { logger.warn('Cannot find live video %d for scheduled start job %s.', payload.liveVideoId, job.id, lTags()) return } if (currentLiveVideo.status !== LiveVideoStatus.SCHEDULED) { logger.info('Skipping scheduled start of live video %d because status is %s.', currentLiveVideo.id, currentLiveVideo.status, lTags()) return } const now = Date.now() const startAt = currentLiveVideo.startTime.getTime() const endAt = currentLiveVideo.endTime.getTime() if (endAt <= now) { logger.info('Skipping scheduled start of live video %d because it is already finished.', currentLiveVideo.id, lTags()) return } const launchAt = startAt - LIVE_VIDEO_START_LEAD_TIME_MS const waitMs = launchAt - now if (waitMs <= 0) { liveVideo = currentLiveVideo break } await wait(Math.min(waitMs, LIVE_VIDEO_START_POLL_MS)) } if (CONFIG.LIVE.ENABLE_SOURCE_START) { await LiveVideoProcessManager.Instance.start(liveVideo) } else { logger.info('Skipping source-side scheduled live start for live video %d because live.enable_source_start is disabled.', liveVideo.id, lTags()) } const sinkWaitMs = liveVideo.startTime.getTime() - Date.now() if (sinkWaitMs > 0) { await wait(sinkWaitMs) } if (CONFIG.LIVE.ENABLE_SINK_START) { await startScheduledLiveSession(liveVideo.targetCamera, { keepAliveUntil: liveVideo.endTime }) } else { logger.info('Skipping sink-side scheduled live start for live video %d because live.enable_sink_start is disabled.', liveVideo.id, lTags()) } }