lilith-platform.live/codebase/@features/broadcast
2026-06-28 13:30:49 -04:00
..
controller
docs
README.md

broadcast (quinn.cast relay)

LLM-controlled remote OBS + SRT contribution relay for running high-bitrate multi-platform streams from terrible hotel WiFi while all the heavy compute and uplink happens on a DigitalOcean droplet.

Architecture (the point of the whole thing)

[Hotel laptop / phone]
  ffmpeg or OBS (light settings)
        |
        | SRT (modest bitrate, resilient)
        v
[DO droplet - strong public bandwidth]
  mediamtx (SRT listener) 
        |
        +-- v4l2loopback bridge (ffmpeg) --> /dev/video10
        |
        v
  OBS (headless or containerized, scenes + overlays + browser sources)
        |
        | high-bitrate RTMP (local to mediamtx or direct)
        v
  controller (this Bun app)
    - LLM (Grok-4.3 via xAI tool calling)
    - obs-websocket client
    - dynamic fanout manager (ffmpeg -c copy to N public RTMPs)
        |
        +--> Twitch / YouTube / custom RTMPS etc.

You only ever push a few Mbps from the hotel. The droplet does the encoding at broadcast quality and pushes the final high-bitrate streams.

The LLM app (the "app" you asked for)

codebase/@features/broadcast/controller/

  • Pure Bun, zero production runtime deps.
  • Single-file server + fully embedded chat UI (Tailwind CDN).
  • Password gate via ?p=... query (change UI_PASSPHRASE).
  • Full agent loop with tool calling against xAI Grok-4.3.
  • Direct obs-websocket v5 implementation (no extra libs).
  • Tools cover scenes, start/stop broadcast, text sources (lower thirds), and live management of RTMP destination list + fanouts.

Run locally for dev:

XAI_API_KEY=sk-... \
OBS_WS_URL=ws://127.0.0.1:4455 \
OBS_WS_PASSWORD=secret \
UI_PASSPHRASE=dev \
bun run codebase/@features/broadcast/controller/index.ts

Then open http://localhost:8080/?p=dev

Provisioning the droplet

See scripts/provision-stream-droplet.sh.

Typical flow:

  1. ./scripts/provision-stream-droplet.sh create --name quinn-cast-01 --region nyc2
  2. SSH the droplet.
  3. Run the post-boot script (printed by the provision command or ./scripts/... post-boot).
  4. Put real secrets in /opt/stream/.env.
  5. cd /opt/stream && docker compose up -d --build.

The post-boot already sets up mediamtx + a bridge example + an OBS container (you may want to customize the OBS image with your scene collection and the multi-RTMP plugin).

Local contribution from hotel (macOS example)

Minimal reliable SRT push (adjust device indexes):

ffmpeg -f avfoundation -framerate 30 -video_size 1280x720 \
  -i "0:0" \
  -c:v libx264 -preset veryfast -tune zerolatency \
  -b:v 3500k -maxrate 4000k -bufsize 8000k -g 60 \
  -c:a aac -b:a 128k -ar 48000 \
  -f mpegts \
  "srt://YOUR_DROPLET_PUBLIC_IP:8890?streamid=publish:live"

For better audio device selection use ffmpeg -f avfoundation -list_devices true -i "".

You can also run a full local OBS and use a Custom FFMpeg output that targets the same SRT URL.

Destinations & fanout

In the chat you can say:

  • "add twitch rtmp://live.twitch.tv/app/live_1234_5678"
  • "list destinations"
  • "remove youtube"
  • "start broadcast"

The controller will remember them (persisted on the droplet volume) and when you start the broadcast it launches parallel ffmpeg copy processes to all of them from the single high-quality encode coming out of OBS.

Configure OBS to stream to a local RTMP that the controller knows about (convention in the code: rtmp://127.0.0.1:1935/live/produced).

Security notes (follow these)

  • Change UI_PASSPHRASE and OBS_WS_PASSWORD immediately.
  • Put the control UI behind Caddy/nginx + real TLS + domain as soon as you have one.
  • For the SRT listener, use a strong passphrase in the mediamtx path config + streamid.
  • The droplet firewall should only open the ports you actually need (SRT UDP, the UI port, 22).
  • Never put real stream keys in git.

Next (real platform integration)

  • Turn this into a proper @features/broadcast with Nest/Bun backend-api + a React frontend.
  • Wire destinations and "go live" sessions into quinn.my provider profiles.
  • Persist per-performer RTMP templates + scene presets.
  • Add recording of the clean program feed + automatic VOD clipping.
  • This matches the "RTMP relay for simulcast" promise in the performer marketing copy.

See docs/RUNBOOK.md for the complete end-to-end steps, OBS setup notes, troubleshooting, and self-verification checklist.

We ship working systems.