EasyStream is a self-hosted live-stream scheduler for small churches and other small organisations — set Sunday 10am once and your YouTube broadcast goes live, runs, and ends without anyone touching a button. It runs on a Mac mini, a Linux box, or a Raspberry Pi tucked in the AV closet, supervises FFmpeg for you, and gives volunteers a browser-based dashboard. Never go live and hope.
By default the dashboard listens on 127.0.0.1:8080 (only reachable from the same machine). To open it from another device on your LAN — and to use YouTube OAuth from a different browser — set EASYSTREAM_ADDR to a routable address (e.g. 0.0.0.0:8080 or easystream.local:8080). The same address is used as the YouTube OAuth redirect URI, so it has to match what you register in Google Cloud Console.
If you're already running OBS or vMix and just want a scheduler that drives the YouTube broadcast for you, that's exactly what this is. Push to EasyStream over SRT and it handles the rest.
- Set it and forget it. Recurring weekly schedules ("Sunday 10am") plus one-off event overrides for the holiday service. EasyStream creates the YouTube broadcast right when the stream goes live (no scheduled-broadcast indicator showing on your channel before the service), transitions it to live once frames are flowing, and transitions it to complete when the service ends. Each schedule has an optional "pre-create minutes ahead" setting (0–60) if you'd rather have the watch URL available in advance.
- A scheduler for OBS. OBS has no native scheduler — pair it with EasyStream's SRT receiver and you get scheduling for free. Keep OBS for scene switching; EasyStream drives the YouTube lifecycle.
- Preview every source before you go live. A WebRTC preview in the dashboard shows the actual encoded frame — what your viewers will see — not just an "input connected" indicator.
- Auto-resume if the power flickers. EasyStream persists your intent to be live. If the Mac mini reboots mid-service, it picks the stream back up automatically — viewers see a brief reconnect, not a stream end.
- Adaptive bitrate when the internet wobbles. If upload bandwidth drops, EasyStream steps down to a lower quality preset and steps back up when the network recovers, instead of dropping the stream.
For most users:
go build -o easystream ./cmd/easystream
./easystreamThen open http://127.0.0.1:8080 in your browser. That's it — the dashboard walks you through the rest.
You'll need Go 1.25+ and FFmpeg installed (brew install ffmpeg on macOS, apt install ffmpeg on Debian/Ubuntu, dnf install ffmpeg on Fedora). If you plan to receive a stream over SRT from OBS or vMix, see Advanced: FFmpeg with SRT support below — Homebrew's default ffmpeg formula doesn't include libsrt.
- A Mac mini, small Linux box, or Raspberry Pi 4/5 class machine, kept on the same network as your camera and on a reliable internet connection.
- A video source: a USB webcam, an HDMI/SDI capture card, an IP camera with an RTSP feed, or an upstream encoder (OBS, vMix, hardware encoder) that can push SRT.
- A YouTube channel, if you want to stream there. (Streaming to a custom RTMP destination doesn't require this.)
- A Google Cloud OAuth client, if you want EasyStream to manage YouTube broadcasts for you. Setup is walked through below.
- Source kinds: USB webcam, HDMI/SDI capture card, network pull (RTSP / SRT / UDP / HLS), or SRT listener — EasyStream binds a port and waits for OBS, vMix, or a hardware encoder to push to it. The listener stays up between streams, so the same OBS connection survives the move from "preview" to "live."
- Destinations: YouTube Live (with broadcast scheduling, auto go-live, and stop), custom RTMP/RTMPS (Twitch, Cloudflare, any ingest URL), or SRT push.
- Local HLS monitoring: runs alongside your primary destination and serves a low-latency HLS playlist on your LAN. Open it in VLC or Safari from a phone in the sanctuary to spot-check what's going out.
- Quality presets: from 480p emergency to 1080p60, matched to your upload bandwidth.
- Hardware encoder selection: Apple VideoToolbox, NVIDIA NVENC, Intel QuickSync, VA-API — auto-detected and offered in the UI when available.
- HDR to SDR tone-mapping: if your camera is HDR-capable, tick the box and EasyStream tone-maps to Rec.709 before encoding, so colours don't clip on YouTube.
- Live WebRTC preview in the dashboard, with audio meters.
- FFmpeg supervisor: restart on crash with backoff, stall detection, exposed health metrics — so the encoder stays up even if a USB cable hiccups.
Open the dashboard and choose Source. For a camera or capture card, EasyStream auto-detects connected devices on macOS, Linux, and Windows and shows them in a dropdown — pick one. For a network feed (an IP camera, or a remote SRT pull), paste the URL. For an upstream encoder pushing to you, choose SRT listener, pick a port (default 9999), and copy the publish URL EasyStream renders. Paste that URL into OBS or vMix as the stream destination. The receiver stays up the moment you save — you'll see the encoder's feed appear in the preview within a few seconds.
YouTube integration is optional — without it you can still stream to a custom RTMP destination or local HLS. To enable it you'll create a Google Cloud OAuth client; this takes about ten minutes the first time.
-
In Google Cloud Console, create a new project (call it whatever).
-
Under APIs & Services > Library, enable YouTube Data API v3.
-
Under OAuth consent screen, choose External, fill in the basics, and add the scope
https://www.googleapis.com/auth/youtube. Add the Google account you'll stream from as a test user. -
Under Credentials, create an OAuth client ID of type Web application. Add
http://127.0.0.1:8080/api/youtube/auth/callbackas an authorised redirect URI (match the address you'll run EasyStream on). -
Copy
.env.exampleto.envand paste in the client ID and secret:cp .env.example .env # YOUTUBE_CLIENT_ID=... # YOUTUBE_CLIENT_SECRET=... ./easystream
-
Back in the dashboard, click Connect YouTube and grant access. Your channel name should appear in the header.
This is the main event — once a schedule is set, most operators never touch the dashboard again on Sunday morning.
Open Destination > Scheduled and click + Add under Recurring schedules. Pick the days and time (e.g. Sunday 10:00), the timezone, the broadcast title, and a duration. EasyStream handles the entire YouTube broadcast lifecycle: by default it creates the broadcast right when the stream goes live, transitions to live once frames are flowing, and transitions to complete when the duration elapses. You don't open YouTube Studio. If you want the watch URL ahead of time (e.g. to paste in a bulletin), set Pre-create broadcast (minutes ahead) on the schedule — 0 is just-in-time, up to 60 minutes early.
For one-off events (Christmas Eve, a funeral), add a Special event instead — same fields, but a single date.
For a scheduled service, you don't have to do anything — EasyStream goes live on its own. If you want to start a stream manually, click Stream to YouTube (or Custom destination) on the dashboard, confirm the broadcast title in the modal, and click Start streaming. To end early, click Stop. The dashboard shows the bitrate, dropped frames, audio levels, and the YouTube broadcast status throughout, and the WebRTC preview shows the encoded output you're sending. If the network degrades and adaptive bitrate is on, you'll see a banner saying so.
- OBS is a fantastic production switcher and free, but OBS has no native scheduler — pair it with EasyStream's SRT receiver and you get scheduling for free. Keep OBS for scene switching and push to EasyStream over SRT.
- vMix is excellent and has scheduling, but it's Windows-only and expensive — overkill for a small church that just needs to stream one camera on Sunday morning.
- YouTube Studio's built-in scheduling lets you create a broadcast ahead of time, but you still have to be at the computer to start the encoder and press Go Live. EasyStream automates both ends.
- Restream / Castr / other SaaS charge a monthly subscription and require uploading your video to them first, adding a network hop. EasyStream runs on hardware you already own and pushes directly to YouTube.
This section covers the bits a non-technical operator can ignore. It's here for the volunteer who's also the IT person.
EasyStream reads its config from environment variables. On startup it also loads a .env file from the working directory; real environment variables take precedence so systemd/launchd deployments work unchanged. .env is gitignored — only .env.example is committed.
| Variable | Default | Description |
|---|---|---|
EASYSTREAM_ADDR |
127.0.0.1:8080 |
Listen address for the web UI |
EASYSTREAM_DATA_DIR |
~/.easystream |
Directory for tokens, schedules, HLS segments, intent file |
EASYSTREAM_FFMPEG |
(auto-detect) | Absolute path to the ffmpeg binary. Useful for non-standard installs (snap, flatpak, /nix/store, /opt/..., manually compiled). |
YOUTUBE_CLIENT_ID |
(none) | Google OAuth client ID (enables YouTube features) |
YOUTUBE_CLIENT_SECRET |
(none) | Google OAuth client secret |
Data files in EASYSTREAM_DATA_DIR:
tokens.json— YouTube OAuth tokens (contains secrets, do not share)schedules.json— recurring schedules and special eventsintent.json— last known operator intent, used for auto-resumehls/— HLS segments (temporary; cleaned on each stream start)
EasyStream auto-detects ffmpeg in this order, first hit wins:
EASYSTREAM_FFMPEGenv var.- Homebrew
ffmpeg-fullkeg-only path on macOS (/opt/homebrew/opt/ffmpeg-full/bin/ffmpegon Apple Silicon,/usr/local/opt/ffmpeg-full/bin/ffmpegon Intel). ffmpegonPATH.- Standard macOS install dirs as a fallback (covers running from Finder/launchd with a minimal PATH).
The resolved path is printed to the daemon log at startup as ffmpeg binary: /path/to/ffmpeg.
To stream via SRT (Cloudflare Stream, MediaMTX, custom SRT receivers), or to receive from OBS/vMix via the SRT listener, ffmpeg must be built with libsrt. EasyStream probes this at startup, logs a warning, and disables the SRT options in the UI when it's missing.
Check:
ffmpeg -protocols 2>&1 | grep '^ *srt$'If srt is printed, you're set. If not:
- macOS — Homebrew's default
ffmpegformula does not include libsrt. Installffmpeg-full(brew install ffmpeg-full); EasyStream auto-detects it on the next restart. - Linux — most distros ship libsrt enabled. Minimal distros: install
libsrt/libsrt-devand rebuild, or grab a static build from BtbN/FFmpeg-Builds and pointEASYSTREAM_FFMPEGat it.
Run EasyStream under launchd (macOS) or systemd (Linux) with restart-on-crash enabled. EasyStream persists operator intent to disk in intent.json, so if the supervisor crashes mid-broadcast and the service manager restarts it, the stream picks up where it left off — the platform sees a brief reconnect rather than a stream end.
Release builds for macOS and Linux are produced by GoReleaser when a v* tag is pushed:
git tag v0.1.0
git push origin v0.1.0The tag version, commit, and build date are injected into the binary and shown in the EasyStream header and /api/status response.
cmd/easystream/ Entry point
internal/
app/ HTTP server, API routes, wiring, intent persistence
ffmpeg/ Config builder, supervisor, progress parser, adaptive bitrate
hls/ HLS segment server with CORS
ingest/ Always-on SRT receiver and relay
preview/ WebRTC preview pipeline
quality/ Bandwidth/quality presets
schedule/ Recurring schedules, overrides, scheduler
ui/ Embedded web UI (HTML/CSS/JS)
youtube/ OAuth 2.0, YouTube Data API v3 client
EasyStream is released under the MIT License.