Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

29 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸŽ₯ streamcast

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.

✨ What It Does

  • πŸš€ 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

🧠 How It Works

  1. streamcast starts a local RTMP server, defaulting to :1935.
  2. OBS connects to it exactly like it would connect to a normal RTMP destination.
  3. Every incoming frame is copied into one ffmpeg process per selected destination.
  4. If one platform drops, that destination retries without interrupting the others.

βœ… Requirements

  • Go 1.22+ to build from source
  • ffmpeg installed and available on PATH
  • OBS or another RTMP publisher
  • At least one valid destination in config.yaml or config.json

Quick ffmpeg check:

ffmpeg -version

🌍 Supported Destination Types

  • YouTube
  • Twitch
  • Kick
  • Facebook
  • Instagram
  • TikTok
  • Any custom RTMP / RTMPS server

πŸ”‘ Getting Stream URLs And Keys

Static-ish platforms

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.

Session-based platforms

For Instagram and TikTok, the RTMP URL and key are commonly short-lived and tied to a live session.

Typical flow:

  1. Start the live session inside the platform's creator tools or app.
  2. Copy the temporary RTMP URL and key it gives you.
  3. Paste them into config.yaml.
  4. Start streamcast.

Expect to refresh these values before each stream.

⚑ Quick Start

1. Clone and enter the project

git clone https://github.com/hectorgrecco/streamcast.git
cd streamcast

2. Create your config

cp config.yaml.example config.yaml

Edit config.yaml and fill in at least one destination with a real url and stream_key.

3. Build the CLI

go build -o streamcast .

4. Run the preflight checks

./streamcast check

This verifies:

  • ffmpeg is available
  • the local RTMP ingest port is usable
  • configured destinations are network-reachable

5. Start the relay

./streamcast start

By default, start opens an interactive destination picker.

6. Point OBS at streamcast

In OBS, use:

  • Service: Custom
  • Server: rtmp://localhost:1935/live
  • Stream Key: leave blank

Then click Start Streaming in OBS.

πŸ–₯️ Common Workflows

Interactive start

./streamcast start

Start specific destinations only

./streamcast start --only youtube-main,twitch-main

Use a custom config path

./streamcast start --config ./configs/staging.yaml

Check a running instance

./streamcast status

List configured destinations

./streamcast destinations

πŸ“š CLI Reference

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

Configuration format is inferred from file extension:

  • .yaml
  • .yml
  • .json

Default config path:

config.yaml

Override it with:

--config /path/to/config.yaml

Example files:

  • config.yaml.example
  • config.json.example

Config Fields

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

Example YAML

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: true

🐳 Docker

Run with Docker Compose

cp config.yaml.example config.yaml
docker compose up --build

The compose setup:

  • exposes RTMP on 1935
  • exposes metrics on 8080
  • mounts ./config.yaml into 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

πŸ“Š Status And Monitoring

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

πŸ› οΈ Troubleshooting

ffmpeg not found

Install ffmpeg and ensure it is on your PATH, or set:

ffmpeg_path: "/absolute/path/to/ffmpeg"

Port 1935 already in use

Something else is already listening on your ingest port.

Options:

  • stop the conflicting service
  • change listen_addr in config
  • update OBS to match the new port

A destination shows unreachable during check

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

OBS connects but a platform never goes live

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

status cannot connect

Make sure a streamcast start process is already running and the metrics server is listening on the address you expect.

πŸ”’ Safety Notes

  • streamcast does not add authentication to the local RTMP ingest.
  • Anything that can reach listen_addr can try to publish.
  • Do not expose the ingest port publicly without putting it behind your own network controls.

🧱 Current Design Limits

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.

πŸ§ͺ Development

Run tests

go test ./...

Run the app directly without building a binary

go run . check
go run . start

Helpful local validation flow

go test ./...
go run . check
go run . destinations

πŸ’‘ Why This Exists

streamcast 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

πŸ“„ License

Add your preferred license here if this repository is intended for public reuse.

About

Free alternative to Restream.io

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages