Bridge livestreams to RTMP & HLS on macOS.
Website · GitHub Releases · Issues
Back Channel is a macOS app for turning livestream URLs into RTMP or HLS outputs that fit into production workflows. It is designed for producers, newsroom teams, and technical creators who need a dependable bridge between web livestreams and downstream ingest systems.
- Converts livestream URLs into RTMP or HLS output
- Supports both GUI and CLI workflows
- Bundles its own core native tooling for end-user installs
- Offers a managed Python source runtime for
yt-dlp+Streamlink, plus managed support updates - Built for Apple Silicon Macs running macOS 13 or later
- GitHub Pages: chrisgherbert.github.io/backchannel
- Source:
website/ - Workflow: pages.yml
The marketing/documentation site deploys automatically through GitHub Actions when changes under website/ are pushed to main.
- Ensure standalone
denoexists for managed support payloads. - Optional: set a portable Python runtime URL/archive for the managed Python source runtime build, or let the script use its tested default.
- Create/update private release config:
cp -n scripts/release.env.example scripts/release.env- Fill
scripts/release.envrequired values (DEV_ID_APP,AC_PROFILE,DENO_BINARY). - Run full signed + notarized GitHub release:
./scripts/github_release.sh --version X.Y.Z --notes-file /absolute/path/to/release-notes.md- To publish newer managed support payloads without cutting a full app release:
./scripts/publish_managed_support.sh- Confirm the GitHub app release includes:
- app zip
- app zip checksum
backchannel-managed-support.json- managed Python source runtime archive + checksum
- managed
denoarchive + checksum
- Confirm the dedicated
managed-supportrelease was updated with the same managed assets. - Distribute:
open dist- macOS 13+
- portable
ffmpeg/ffprobebinaries available for packaging - standalone
denobinary available for managed support packaging - optional portable Python runtime archive/URL for managed Python source runtime packaging
These are release-time/build-time requirements, not end-user runtime requirements. The shipped app bundles or manages its own dependencies.
swift runFast local build:
swift buildRun directly from source:
swift runThis creates dist/Back Channel.app and bundles the stable native tools ffmpeg and ffprobe into:
Contents/Resources/bin/
It also bundles a CLI launcher and installer:
Contents/Resources/bin/backchannelContents/Resources/bin/install-cli.sh
./scripts/package_app.shApp icon (optional):
- Drop
assets/AppIcon.png(orassets/AppIcon.icns) before packaging. - The script will automatically convert PNG to
.icns.
You can override tool paths:
FFMPEG_BINARY=/path/to/ffmpeg FFPROBE_BINARY=/path/to/ffprobe APP_ICON_FILE=/path/to/icon.png ./scripts/package_app.shInstall terminal command from the packaged app:
"/Users/herbert/web/youtube-live-converter/dist/Back Channel.app/Contents/Resources/bin/install-cli.sh"This installs to ~/.local/bin/backchannel by default (no sudo).
For a system-wide install, override target dir:
CLI_TARGET_DIR=/usr/local/bin "/Users/herbert/web/youtube-live-converter/dist/Back Channel.app/Contents/Resources/bin/install-cli.sh"Then run:
backchannel --helpThe managed Python source runtime (yt-dlp + Streamlink) and deno are both managed separately as app support components rather than being sealed inside the .app bundle.
Use the packaging script directly:
./scripts/package_app.shIt will:
- Build release binary.
- Create
dist/Back Channel.app. - Bundle required native tools into
Contents/Resources/bin. - Apply ad-hoc signing (for local execution).
Use the current release pipeline scripts:
First-time setup:
cp scripts/release.env.example scripts/release.envFill required values in scripts/release.env:
DEV_ID_APPAC_PROFILEDENO_BINARY(standalone Mach-O binary for managed support payloads)
Optional managed-runtime settings:
PYTHON_STANDALONE_URLorPYTHON_STANDALONE_ARCHIVEYTDLP_PACKAGE_SPEC
Create a notarized local release build:
./scripts/notarize_release.shCreate or update the GitHub release, including managed support assets:
./scripts/github_release.sh --version X.Y.Z --notes-file /absolute/path/to/release-notes.mdThe GitHub release script uploads:
- notarized app zip
- app zip checksum
- managed support manifest
- managed Python source runtime archive + checksum
- managed deno archive + checksum
It also republishes those managed support assets to the dedicated managed-support release channel so the app can pick up newer source-runtime / deno payloads without waiting for a new app build.
If you only want to refresh managed support payloads:
./scripts/publish_managed_support.shIf you need to run manual notarization steps instead of scripts/notarize_release.sh:
codesign --force --options runtime --timestamp --sign "Developer ID Application: <Name> (<TEAMID>)" "dist/Back Channel.app"
ditto -c -k --keepParent "dist/Back Channel.app" "dist/Back-Channel.zip"
xcrun notarytool submit "dist/Back-Channel.zip" --keychain-profile "<profile>" --wait
xcrun stapler staple "dist/Back Channel.app"
xcrun stapler validate "dist/Back Channel.app"- Enter source livestream URL.
- Click
Load Infoto fetch and preview title/thumbnail/description excerpt. - Choose output format:
RTMPfor push targets (rtmp://server/app/key)HLSfor local/served playlist output (/path/to/out.m3u8)
- For RTMP, either:
- fill
Server URL+Stream Key, or - paste a full RTMP URL in
Full RTMP URL (optional override)
- fill
- Choose mode:
Stream Copyfor lowest CPU on RTMP (Streamlink -> FFmpeg remux, best-effort passthrough)Compatiblefor RTMP resync/transcode (Streamlink -> single FFmpeg resync/transcode,libx264+aac, fixed GOP/CFR)
- Click
Start. - Use
Statustab for parsed health/progress, andAdvancedtab for raw console logs.
Sources/youtube-live-converter/: Swift app sourcescripts/: build, packaging, notarization, and release scriptswebsite/: GitHub Pages sitedist/: local build outputs
- The app captures source-tool (
Streamlinkoryt-dlp) andffmpegstderr logs in the UI. - On process failure, it retries with exponential backoff (up to 30 seconds).
- For RTMP,
CompatibleusesStreamlinkplus a single FFmpeg resync/transcode stage. Stream Copymay fail if target/container codec compatibility does not match. UseCompatiblemode in that case.- Runtime tool resolution prefers:
- app-managed support components in
~/Library/Application Support/Back Channel/ - bundled app resources in
.app/Contents/Resources/bin
- app-managed support components in
- End users do not need Homebrew, Python, Xcode command line tools, or manually installed runtimes.