Lightweight, zero-re-encoding RTMP fan-out for OBS and other RTMP publishers.
streamcast lets you publish one incoming RTMP stream and relay it to multiple platforms at the same time without transcoding. Your video/audio is passed through with ffmpeg -c copy, so CPU usage stays low and the original quality is preserved.
- π Accepts a single local RTMP ingest, usually from OBS
- π‘ Fans that stream out to YouTube, Twitch, Kick, Facebook, TikTok, Instagram, or custom RTMP(S) endpoints
- π Reconnects each destination independently with backoff
- πͺΆ Avoids re-encoding, keeping the process lightweight
- π Exposes a small status/metrics endpoint you can poll locally
streamcaststarts a local RTMP server, defaulting to:1935.- OBS connects to it exactly like it would connect to a normal RTMP destination.
- Every incoming frame is copied into one
ffmpegprocess per selected destination. - If one platform drops, that destination retries without interrupting the others.
- Go
1.22+to build from source ffmpeginstalled and available onPATH- OBS or another RTMP publisher
- At least one valid destination in
config.yamlorconfig.json
Quick ffmpeg check:
ffmpeg -version- YouTube
- Twitch
- Kick
- TikTok
- Any custom RTMP / RTMPS server
For YouTube, Twitch, Kick, and Facebook, open the platform's live dashboard and copy:
- the RTMP server URL
- the stream key
These are usually stable enough to reuse between streams.
For Instagram and TikTok, the RTMP URL and key are commonly short-lived and tied to a live session.
Typical flow:
- Start the live session inside the platform's creator tools or app.
- Copy the temporary RTMP URL and key it gives you.
- Paste them into
config.yaml. - Start
streamcast.
Expect to refresh these values before each stream.
git clone https://github.com/hectorgrecco/streamcast.git
cd streamcastcp config.yaml.example config.yamlEdit config.yaml and fill in at least one destination with a real url and stream_key.
go build -o streamcast ../streamcast checkThis verifies:
ffmpegis available- the local RTMP ingest port is usable
- configured destinations are network-reachable
./streamcast startBy default, start opens an interactive destination picker.
In OBS, use:
- Service:
Custom - Server:
rtmp://localhost:1935/live - Stream Key: leave blank
Then click Start Streaming in OBS.
./streamcast start./streamcast start --only youtube-main,twitch-main./streamcast start --config ./configs/staging.yaml./streamcast status./streamcast destinations| Command | Purpose |
|---|---|
streamcast start |
Start local ingest and fan out to selected destinations |
streamcast start --only youtube-main,twitch-main |
Skip the picker and activate only named destinations |
streamcast check |
Run preflight validation |
streamcast doctor |
Alias for check |
streamcast status |
Query the local metrics endpoint and print destination state |
streamcast status --metrics-addr localhost:8080 |
Query a non-default metrics address |
streamcast destinations |
Print configured destinations with masked stream keys |
Configuration format is inferred from file extension:
.yaml.yml.json
Default config path:
config.yamlOverride it with:
--config /path/to/config.yamlExample files:
config.yaml.exampleconfig.json.example
| Field | Default | Meaning |
|---|---|---|
listen_addr |
:1935 |
Local RTMP ingest address |
metrics_addr |
:8080 |
Local HTTP metrics/status server |
ffmpeg_path |
ffmpeg |
ffmpeg binary path |
destinations[].name |
none | Unique name used by --only and status output |
destinations[].platform |
none | Display label such as youtube or twitch |
destinations[].url |
none | Base RTMP or RTMPS ingest URL |
destinations[].stream_key |
none | Key appended to the destination URL |
destinations[].enabled |
false |
Default selection state in interactive mode |
backoff.initial_backoff |
1s |
First retry delay after a disconnect |
backoff.max_backoff |
30s |
Maximum retry delay |
listen_addr: ":1935"
metrics_addr: ":8080"
ffmpeg_path: "ffmpeg"
destinations:
- name: "youtube-main"
platform: "youtube"
url: "rtmp://a.rtmp.youtube.com/live2"
stream_key: "YOUR-YOUTUBE-STREAM-KEY"
enabled: true
- name: "twitch-main"
platform: "twitch"
url: "rtmp://live.twitch.tv/app"
stream_key: "YOUR-TWITCH-STREAM-KEY"
enabled: truecp config.yaml.example config.yaml
docker compose up --buildThe compose setup:
- exposes RTMP on
1935 - exposes metrics on
8080 - mounts
./config.yamlinto the container as read-only - runs
start --config /config.yaml
If OBS is running on the same machine, point it to:
rtmp://localhost:1935/live
When streamcast is running, it exposes a local HTTP endpoint on:
http://localhost:8080/metrics
The status command reads from that endpoint and prints:
- uptime
- destination state
- retry count
- bytes forwarded
- last error
Install ffmpeg and ensure it is on your PATH, or set:
ffmpeg_path: "/absolute/path/to/ffmpeg"Something else is already listening on your ingest port.
Options:
- stop the conflicting service
- change
listen_addrin config - update OBS to match the new port
This is advisory during preflight and usually means one of these:
- temporary network issue
- invalid RTMP hostname
- platform ingest is blocking or timing out
- wrong URL format
Check:
- the destination
url - the destination
stream_key - whether the platform expects a fresh session key
- whether the source codec/bitrate is accepted by that platform
Make sure a streamcast start process is already running and the metrics server is listening on the address you expect.
streamcastdoes not add authentication to the local RTMP ingest.- Anything that can reach
listen_addrcan try to publish. - Do not expose the ingest port publicly without putting it behind your own network controls.
These are intentional for this version:
- β No transcoding or bitrate adaptation
- β No local RTMP auth layer
- β No backfill after reconnect
- β One active ingest publisher at a time
This means your OBS output must already be acceptable to every destination you stream to.
go test ./...go run . check
go run . startgo test ./...
go run . check
go run . destinationsstreamcast is useful when you want:
- lower CPU than full transcoding restreamers
- a self-hosted relay on your own machine or server
- one OBS output feeding several platforms at once
- simple operational behavior with visible per-destination state
Add your preferred license here if this repository is intended for public reuse.