Skip to content

Repository files navigation

StreamForge

StreamForge is a self-hosted control layer for small, low-latency live and recording deployments. An OBS producer remains the source of truth for physical output, a durable control plane orders operator intent, and a pinned ZLMediaKit service handles ingest, protected playback, and MP4 recording. The repository contains the product code, deployment, tests, upstream locks, and a reproducible acceptance runner; it is not a hosted service.

Product shape

operator / streamforgectl
          |
          | authenticated desired state, status, events, metrics
          v
  +-------------------+       hooks and reconciliation       +------------------+
  | control plane     | <-----------------------------------> | ZLMediaKit       |
  | SQLite + FIFO     |                                       | RTMP / HTTP-FLV |
  +-------------------+                                       | RTSP / MP4       |
          ^                                                   +------------------+
          | leased commands + acknowledged OBS facts                  |
          |                                                            v
  +-------------------+                                      finalized recordings
  | OBS Dock adapter  |                                            + retention
  | real frontend API |                                       recording-pruner
  +-------------------+

The implemented release provides:

  • Authenticated, channel-scoped operator, producer, publish, and play roles.
  • Atomic SQLite state transitions, ordered producer commands, idempotent operator mutations, bounded retention, admission limits, and reconciliation.
  • A C++/Qt OBS Dock that invokes real OBS frontend streaming and recording APIs, reports physical output facts, and fails closed on stale lifecycles or unsafe identity changes.
  • Pinned ZLMediaKit ingest with exact-origin publication policy, protected HTTP-FLV/RTSP playback, MP4 finalization, and a network-isolated retention worker that ignores dot-prefixed active files.
  • Health and Prometheus-style metrics endpoints, a dependency-free operator CLI, Docker Compose deployment, and one-command acceptance coverage.

Run locally

Requirements are Docker with Compose, Linux-container support, and PowerShell 7. From the repository root:

Copy-Item deploy/.env.example deploy/.env

Edit deploy/.env and replace all six replace-* credential placeholders with distinct, URL-safe random values of at least 16 characters. Do not reuse the published ZLMediaKit default secret. Then validate and start the stack:

pwsh ./scripts/dev.ps1 -Action Config
pwsh ./scripts/dev.ps1 -Action Start

The local-safe defaults bind only to 127.0.0.1:

Surface Address Purpose
Control API http://127.0.0.1:8081 API, /docs, /health/ready, /metrics
HTTP media http://127.0.0.1:8080 Protected HTTP-FLV playback
RTMP ingest rtmp://127.0.0.1:1935 OBS publication
RTSP media rtsp://127.0.0.1:8554 Protected RTSP playback

Build and install the OBS component using the platform-specific instructions in components/obs-plugin/README.md. Launch OBS from an environment that supplies STREAMFORGE_PRODUCER_TOKEN and, if not using the Dock fields, the control URL, channel, and stable agent ID.

For the default demo channel, configure the OBS streaming service as:

Server:     rtmp://127.0.0.1:1935/live
Stream key: demo?token=<the STREAMFORGE_PUBLISH_TOKEN value from deploy/.env>

Set the Dock control URL to http://127.0.0.1:8081, channel to demo, and agent to a stable identifier. Use the Dock's Start stream action: it first arms the channel through the control plane, then the returned producer command starts OBS. Directly pressing OBS's native Start Streaming button before the channel is armed is intentionally rejected by the media hook.

An authenticated default playback URL is:

http://127.0.0.1:8080/live/demo.live.flv?token=<STREAMFORGE_PLAY_TOKEN>

The operator CLI reads its bearer credential from the environment rather than from process arguments. In PowerShell, enter the configured value without echoing it and query the running system:

$env:STREAMFORGE_OPERATOR_TOKEN = Read-Host -MaskInput 'Operator token'
python ./tools/streamforgectl.py --url http://127.0.0.1:8081 --channel demo status
python ./tools/streamforgectl.py --url http://127.0.0.1:8081 --channel demo events
python ./tools/streamforgectl.py --url http://127.0.0.1:8081 metrics

Stop the stack without deleting the named state and recording volumes:

pwsh ./scripts/dev.ps1 -Action Stop

Verified release evidence

Commit 0244cb1393210a3f4346534b529be249a57286c6 was exercised with exactly:

pwsh ./scripts/acceptance.ps1 -Case All

Run 20260904T194934Z-7c083dd6 completed on 2026-09-05 with 15/15 cases PASS and scoped cleanup PASS. Both provenance snapshots record that exact HEAD, git_dirty: false, head_is_exact_source: true, and source-tree SHA-256 bd07b1386bb62727ae015c65a1d0bd85c57c027f0fc881219b7560df304dd6a0; the source remained unchanged throughout the run.

The run includes 221 control-plane tests, 2 operator CLI security tests, all 4 real-SDK OBS CTest targets, and both Qt-only CTest targets. A real OBS 30.0.2 process—not FFmpeg—published H.264/AAC and ACKed START_STREAM, START_RECORDING, STOP_RECORDING, and STOP_STREAM. OBS finalized its own 445,666-byte, 4.400-second H.264/AAC MKV. The separate ZLMediaKit recording case finalized a 2,047,917-byte, 7.433-second MP4 and exercised retention safety.

The five protected HTTP-FLV player-start samples were 1168.262, 1004.926, 1009.177, 979.333, and 993.148 ms (mean 1030.969 ms; nearest-rank p95 1168.262 ms). This metric ends when ffprobe receives its first selected video packet. It is not capture-to-display or glass-to-glass latency.

Raw acceptance artifacts are intentionally Git-ignored because they include runtime logs and media. The tracked manifests carry the stable, secret-free release facts and raw-summary hash. The runner found zero credential leaks in 108 pre-redactor source-form checks; a separate read-only scan found zero raw credential hits across 519 evidence files.

Repository map

Path Responsibility
components/obs-plugin C++/Qt OBS producer adapter and four test targets
services/control-plane HTTP API, SQLite state/command engine, hooks, reconciliation
deploy Compose stack, pinned ZLMediaKit build, recording pruner
tools/streamforgectl.py Secret-safe operator CLI
scripts Local lifecycle and reproducible acceptance entrypoints
tests/e2e End-to-end acceptance implementation
docs Product boundary, upstream, and acceptance records
upstreams.lock.json Audited upstream commits and local patch lock

Evidence and support boundaries

  • The OBS source reference is lite-tx/obs-studio at a2400fe9803811b6e691a019e8bc2b1acfaf6250. No fork-only delta was identified. Formal acceptance compiled and ran against Ubuntu's packaged OBS 30.0.2 SDK and process; it did not build or execute the audited OBS 32 source commit.
  • ZLMediaKit is pinned at 9f90548a67df0a9f1425a1c884186bf48eb7be21; the applied hook-log patch is locked in upstreams.lock.json.
  • The automated OBS loop uses Xvfb, an empty scene, and a real OBS process. It proves module loading, OBS-owned publication and local recording, all four stream/record command acknowledgements, protected playback, finalized-file probing, and clean stop—not interactive Dock ergonomics or a production capture scene. The ZLMediaKit Recording case remains a separate server-side MP4 proof.
  • No vulnerability scan, penetration test, legal clearance, HA/failover test, WAN test, or capture-to-display latency study is claimed. Before Internet exposure, add TLS termination, network policy, secret management, backups, monitoring, and an environment-specific security review.

See SECURITY.md, docs/architecture/ADR-001-product-boundaries.md, and docs/UPSTREAM_AUDIT.md for the detailed trust and provenance boundaries.

License and provenance

StreamForge is distributed under GPL-2.0-or-later; see LICENSE. The OBS-linked module therefore remains GPL-compatible. ZLMediaKit is deployed as a separate service under its MIT-derived license and attribution conditions. Source URLs, exact revisions, local patch provenance, and notices are recorded in upstreams.lock.json and THIRD_PARTY_NOTICES.md.

About

Self-hosted low-latency live streaming and recording control platform for OBS Studio and ZLMediaKit.

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages