mirror of
https://github.com/Vateron-Media/XC_VM.git
synced 2026-10-04 12:02:33 +02:00
fix(streaming): feed delayed, LLOD and loopback channels to the daemon
Client delivery is daemon-only since ADR 0003 Phase E, but several producers never fed the daemon, or fed it in a way no player could use: - Delayed channels (delay_minutes > 0) were unwatchable: the encoder's tee is skipped for them (its output is the undelayed stream), the supervisor refuses them, and DelayCommand never registered an ingest, so every viewer got not-on-air. DelayCommand now pushes each delayed segment into the daemon as it publishes it (IngestFeeder), paced over the segment's duration, with a two-segment burst at start. Its loop polls every 50 ms instead of hashing the playlist every 1 ms. - An ffmpeg loopback (php_loopback off, or no supervision) registered no ingest at all; startStream now tees loopback streams too. - Encrypted HLS was undecodable for loopback and llod=2: the playlist declares AES-128 whenever encrypt_hls is on, but those producers registered without the key, so the daemon served plain segments. Every producer now passes the key; startLLOD/startLoopback write it before spawning the child that registers. - LlodCommand/LoopbackCommand feed through IngestFeeder (no torn packets, reconnect after a daemon restart). LLOD also honours the stream's headers/cookie/proxy/default user agent and request_prebuffer, accepts TS sources by content when the Content-Type is not video/mp2t, kills a stale segmenter by process title (it read the MONITOR's pid), and writes its playlist atomically (the loopback relay too). - LLOD ffmpeg: +nobuffer moves to the input where it has an effect; -tune zerolatency only for x264/x265 (NVENC rejects it and failed the start; it gets -zerolatency 1); an LLOD start uses the first source instead of falling through to the last. - Remote VOD subtitles URL-encoded the shell-quoted path. - cron:streams: the restreamer "attached" subqueries lacked GROUP BY, so on-demand parents could be stopped under a child LB; a stopped on-demand stream went on to spawn thumbnail/archive workers; the daemon re-feed restart now skips self-feeding producers (PHP relays, delay) and its throttle stamp moved out of STREAMS_PATH, where the restart's `rm -f <id>_*` deleted it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
4eea8a587e
commit
2b61e48ef5
@@ -139,11 +139,40 @@ final class StreamProcessBuildLiveTest extends TestCase {
|
||||
$this->assertStringContainsString('-map 0 -copy_unknown', $out);
|
||||
}
|
||||
|
||||
/** The legacy path registers no ingest for loopback and must stay on-disk only. */
|
||||
public function testLegacyLoopbackStaysOnDiskOnly(): void {
|
||||
/** With no daemon ingest (daemon unreachable) a loopback stays on-disk only. */
|
||||
public function testLoopbackWithoutIngestStaysOnDiskOnly(): void {
|
||||
$this->assertStringNotContainsString('-f tee', $this->build(['loopback' => true]));
|
||||
}
|
||||
|
||||
/** A self-launched (unsupervised) loopback feeds the daemon too — clients are daemon-only. */
|
||||
public function testUnsupervisedLoopbackTeesIntoTheDaemon(): void {
|
||||
$out = $this->build(['loopback' => true, 'ingestSock' => '/run/ingest/42.sock']);
|
||||
$this->assertStringContainsString('-f tee', $out);
|
||||
$this->assertStringContainsString('unix:/run/ingest/42.sock', $out);
|
||||
}
|
||||
|
||||
// ── LLOD ───────────────────────────────────────────────────
|
||||
|
||||
/** +nobuffer is a demuxer flag: it belongs before -i, not among the output options. */
|
||||
public function testLlodLatencyFlagsSitOnTheInput(): void {
|
||||
$out = $this->build(['llod' => true]);
|
||||
$input = substr($out, 0, (int) strpos($out, ' -i '));
|
||||
$this->assertStringContainsString('-fflags +discardcorrupt+nobuffer', $input);
|
||||
$this->assertStringNotContainsString('-fflags nobuffer', $out);
|
||||
}
|
||||
|
||||
/** A stream copy gets no encoder tune; x264 gets zerolatency; NVENC its own option. */
|
||||
public function testLlodTuneMatchesTheEncoder(): void {
|
||||
$this->assertStringNotContainsString('-tune', $this->build(['llod' => true]));
|
||||
|
||||
$x264 = $this->build(['llod' => true, 'stream_info' => ['enable_transcode' => 1, 'transcode_profile_id' => 1, 'profile_options' => json_encode(['-vcodec' => 'libx264'])]]);
|
||||
$this->assertStringContainsString('-tune zerolatency', $x264);
|
||||
|
||||
$nvenc = $this->build(['llod' => true, 'stream_info' => ['enable_transcode' => 1, 'transcode_profile_id' => 1, 'profile_options' => json_encode(['-vcodec' => 'h264_nvenc'])]]);
|
||||
$this->assertStringNotContainsString('-tune zerolatency', $nvenc, 'NVENC rejects the x264 tune value');
|
||||
$this->assertStringContainsString('-zerolatency 1', $nvenc);
|
||||
}
|
||||
|
||||
// ── custom_ffmpeg branch ───────────────────────────────────
|
||||
|
||||
public function testCustomFfmpegBypassesTemplate(): void {
|
||||
|
||||
Reference in New Issue
Block a user