@agora-build/stream-to-agora
v0.4.0
Published
Stream local files or http(s)/rtmp/rtsp URLs to an Agora RTC channel.
Maintainers
Readme
@agora-build/stream-to-agora
Stream a local file or http(s):// / rtmp:// / rtsp:// URL to an Agora RTC channel as a regular publisher. ffmpeg decodes/demuxes the source; codecs the SDK's encoded senders accept (H.264, H.265, VP8, VP9, AV1 video; AAC/HE-AAC/HE-AACv2, Opus, G.711 audio) pass through as-is, anything else is decoded to raw YUV/PCM and pushed via the raw senders — useful for load testing, demos, simulated participants, and pumping pre-recorded media into a live channel.
Features
- Local files — any container/codec ffmpeg can read (
./demo.mp4,./loop.mkv, …). - Remote sources —
http://,https://,rtmp://,rtsp://. - Encoded passthrough — H.264/H.265/VP8/VP9/AV1 video and AAC/HE-AAC/HE-AACv2/Opus/G.711 audio are demuxed with
-c copy(zero CPU on our side); the SDK gets the bitstream as-is. Mode is per-input all-or-nothing: both streams must be passthrough-eligible or the whole input falls back to Raw. - Raw fallback — anything else (MP3, MPEG-2, AC-3, …) is decoded by ffmpeg to yuv420p + s16le PCM and pushed via the raw senders.
- Selective publish —
--audio-only/--video-only. - Hybrid reconnect —
http(s)uses ffmpeg's built-in-reconnectflags; RTMP/RTSP respawn the ffmpeg subprocess, bounded by--reconnect-attempts. - Token renewal —
--token-renew-cmd <shell-cmd>runs your token-minter onTokenWillExpireand rotates the token without dropping the channel. --loopforever — steady-state load testing from a single short file.- ffmpeg passthrough flags —
--http-header K:V(repeatable),--user-agent,--rtsp-transport tcp|udp|http.
Encoded passthrough caveats
- Subscriber decode support is codec-dependent: H.264/VP8 every WebRTC client; H.265 Safari + hardware-accelerated Chrome; VP9/AV1 Chrome/Edge/Firefox. Agora's native SDK subscriber decodes all.
- Passthrough cannot synthesise keyframes to answer
onIntraRequestReceived; mid-join black at a browser subscriber is bounded by the source's keyframe interval (sub-second for keyframe-dense inputs). Use--mode rawif you need the SDK's own encoder to answer subscriber PLIs on demand (costs a re-encode generation; see Modes below). - AV1 encoded passthrough is partial. Agora's SDK marks
VIDEO_CODEC_AV1as@technical preview. H.264/H.265/VP8/VP9 deliver cleanly end-to-end, but AV1 with a hierarchical-B encoder (SVT-AV1's default) loses ~60–70% of frames at the receiver. Use--mode rawfor reliable AV1, or pre-encode source with-svtav1-params 'pred-struct=1'(low-delay, noshow_existing_frame). Will be reliable once Agora promotes AV1 out of preview.
Install
npm install -g @agora-build/stream-to-agoraOr via shell script:
curl -fsSL https://dl.agora.build/stream-to-agora/install.sh | bashBoth download a prebuilt bundle for your platform — the binary plus the Agora SDK shared libraries it depends on. The binary's rpath finds the libs at runtime, so there's no LD_LIBRARY_PATH / DYLD_LIBRARY_PATH setup.
v0.4.0 currently ships Linux x86_64 only. Linux aarch64 and macOS releases were on v0.3.x against the previous SDK; the SDK upgrade in v0.4.0 (which delivers the VP9/AV1 packetizer fix) is currently only published for Linux x86_64. aarch64 + macOS releases will return once Agora publishes the matching SDK builds for those targets.
Usage
stream-to-agora <INPUT> --app-id <ID> --channel <NAME> --rtc-user-id <UID> --token <TOKEN> [OPTIONS]# Local file
stream-to-agora ./demo.mp4 \
--app-id $AGORA_APP_ID \
--channel demo \
--rtc-user-id 42 \
--token "$RTC_TOKEN"
# String account (same "s/" convention as `atem serv rtc`)
stream-to-agora ./demo.mp4 --app-id ... --channel demo --rtc-user-id s/alice --token "$RTC_TOKEN"
# Loop forever — steady-state load testing
stream-to-agora ./loop.mp4 --app-id ... --channel demo --rtc-user-id 42 --token "$RTC_TOKEN" --loop
# Audio only / video only
stream-to-agora ./demo.mp4 --app-id ... --channel demo --rtc-user-id 42 --token "$RTC_TOKEN" --audio-only
# Remote source (later release — ffmpeg already handles these, so the arg shape is unchanged)
stream-to-agora rtmp://live.example.com/app/key --app-id ... --channel demo --rtc-user-id 42 --token "$RTC_TOKEN"Options
| Flag | Description |
|---|---|
| --app-id <ID> | Agora App ID. Falls back to AGORA_APP_ID env var. |
| --channel <NAME> | RTC channel to join. |
| --rtc-user-id <UID> | RTC user. All-digit → int uid; non-digit → string account; s/ prefix forces string mode. |
| --token <TOKEN> | Pre-minted RTC token (required). |
| --mode <auto\|raw\|encoded> | Sender path (default auto). See Modes below. |
| --hwaccel <auto\|none\|...> | ffmpeg HW decode backend for Raw mode (default auto). See Hardware acceleration. |
| --loop | Restart the input on EOF. |
| --audio-only / --video-only | Push just one track. |
| --ffmpeg-path <PATH> | ffmpeg binary (default: ffmpeg on PATH). |
Modes
| --mode | Behaviour |
|---|---|
| auto (default) | Encoded passthrough when every stream's codec is passthrough-eligible, else Raw. |
| raw | Force ffmpeg-decode → SDK-re-encode for every input. More CPU + one re-encode generation, but the SDK's internal encoder owns the bitstream — it answers subscriber keyframe requests (PLI) itself, so mid-join subscribers aren't stuck on black, and it works for any codec ffmpeg decodes, including VP9/AV1. Hardware-accelerated — see below. |
| encoded | Force zero-CPU passthrough; errors at startup (naming the codec) if a stream can't pass through, instead of silently falling back. |
Hardware acceleration
Raw mode is hardware-accelerated by default: ffmpeg decodes with
-hwaccel and the SDK is asked to use its hardware video encoder.
--hwaccel <auto|none|cuda|vaapi|qsv|videotoolbox>(defaultauto). At startup the tool runs a silent probe; withautoit tries a platform candidate list and picks the first that works; a pinned backend is probed too and falls back to software with a one-line message if unavailable (no crash, no noise);noneskips the probe. You'll see one ofhardware decode: <backend>orhardware decode unavailable — using software decodeon startup.- Applies only to Raw mode's video decode —
--mode encodeddecodes nothing, so--hwaccelis a no-op there. - SDK hardware encode is best-effort: it falls back to software when the platform build has no hardware encoder.
Tokens
stream-to-agora does not mint tokens — token minting is a security-sensitive concern that belongs in your token service or atem. Supply a pre-minted token:
TOKEN=$(atem token rtc create --channel demo --rtc-user-id 42)
stream-to-agora ./demo.mp4 --app-id $AGORA_APP_ID --channel demo --rtc-user-id 42 --token "$TOKEN"Two publishers on the same channel must use different uids (Agora kicks a duplicate uid). Same channel + different uids = fine.
Requirements
- ffmpeg on
PATH(or pass--ffmpeg-path). Used to decode the input into raw frames. - The project must have an App Certificate and the token must be valid for the channel + uid + publisher role.
Supported Platforms
| Platform | Source build | Released binary | |----------|--------------|-----------------| | Linux x86_64 | ✅ | ✅ | | Linux aarch64 | ⏸ paused (matching SDK URL pending from Agora) | ⏸ paused | | macOS arm64 / x86_64 | ⏸ paused (matching SDK URL pending from Agora) | ❌ | | Windows | — | — (not on the roadmap) |
Build from Source
git clone https://github.com/Agora-Build/stream-to-agora.git
cd stream-to-agora
cargo build --release # CMake fetches the Agora SDK on first build
# Binary at target/release/stream-to-agoraTo skip the SDK auto-download and point at a pre-staged SDK:
AGORA_RTC_SDK_PATH=/path/to/agora_rtc_sdk cargo build --releaseRelated Projects
- atem — Agora platform terminal: projects, tokens, ConvoAI test pages, webhook receiver, AI agent integration
- Astation — macOS menubar hub coordinating Chisel, atem, and AI agents
- Vox — AI latency evaluation platform
License
MIT
