-
Notifications
You must be signed in to change notification settings - Fork 5
Audio Transcoding
English | 中文
LiveForge supports on-demand audio transcoding between protocols. When a subscriber needs a different audio codec than the publisher provides, a shared transcode pipeline is created automatically — no configuration required beyond enabling the feature.
Publisher (AAC) ──→ Stream Ring Buffer ──→ RTMP Subscriber (AAC) [zero-copy, no transcoding]
──→ Transcode Manager ──→ WebRTC Subscriber (Opus) [shared pipeline]
──→ WebRTC Subscriber (Opus) [shared pipeline]
- A subscriber connects and declares its required audio codec (e.g., Opus for WebRTC WHEP)
- The
TranscodeManagercompares it against the publisher's codec - If they match → zero-overhead passthrough via the original ring buffer
- If they differ → a
TranscodedTrackis created (or reused) for that target codec - The transcode goroutine reads from the source ring buffer, decodes to PCM, resamples if needed, and re-encodes to the target codec
- Multiple subscribers requesting the same target codec share one pipeline
| Source \ Target | AAC | Opus | G.711 μ-law | G.711 A-law | MP3 |
|---|---|---|---|---|---|
| AAC | passthrough | ✅ | ✅ | ✅ | ✅ |
| Opus | ✅ | passthrough | ✅ | ✅ | ✅ |
| G.711 μ-law | ✅ | ✅ | passthrough | ✅ | ✅ |
| G.711 A-law | ✅ | ✅ | ✅ | passthrough | ✅ |
| MP3 | ✅ | ✅ | ✅ | ✅ | passthrough |
All conversions go through an intermediate PCM (16-bit signed integer) representation with optional sample rate conversion.
| Scenario | Publisher Codec | Subscriber Codec | Transcoding |
|---|---|---|---|
| RTMP push → WebRTC WHEP play | AAC | Opus | AAC → PCM → Opus |
| WebRTC WHIP push → RTMP play | Opus | AAC | Opus → PCM → AAC |
| GB28181 camera → HLS play | G.711 | AAC | G.711 → PCM → AAC |
| GB28181 camera → WebRTC play | G.711 | Opus | G.711 → PCM → Opus |
| RTMP push → RTMP play | AAC | AAC | None (passthrough) |
audio_codec:
enabled: true| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | true |
Enable on-demand audio transcoding |
When enabled: false, subscribers that require a different codec than the publisher will receive no audio track (video-only).
Audio transcoding uses FFmpeg's libavcodec and libavutil via CGO. You must have FFmpeg development libraries installed.
brew install ffmpeg
CGO_ENABLED=1 go build -o liveforge ./cmd/liveforgeapt-get install -y libavcodec-dev libavutil-dev
CGO_ENABLED=1 go build -o liveforge ./cmd/liveforgeIf you don't need audio transcoding, build without CGO:
CGO_ENABLED=0 go build -o liveforge ./cmd/liveforgeThe server runs normally — cross-protocol playback works for video, but audio will only be available when publisher and subscriber codecs match natively.
| Component | Location | Role |
|---|---|---|
TranscodeManager |
core/transcode_manager.go |
Manages per-stream transcode pipelines, creates/reuses TranscodedTrack instances |
TranscodedTrack |
core/transcode_manager.go |
Holds a ring buffer for a target codec, ref-counts subscribers |
Registry |
pkg/audiocodec/registry.go |
Global codec registry with decoder/encoder factories |
Decoder |
pkg/audiocodec/ff_decoder.go |
FFmpeg-backed decoder (AAC, Opus, G.711, MP3 → PCM) |
Encoder |
pkg/audiocodec/ff_encoder.go |
FFmpeg-backed encoder (PCM → AAC, Opus, G.711, MP3) |
Resampler |
pkg/audiocodec/ff_resampler.go |
Sample rate and channel layout conversion |
-
Subscriber connects → protocol module calls
TranscodeManager.GetOrCreateReader(targetCodec) -
First subscriber for a codec → new
TranscodedTrackcreated, goroutine starts reading source ring buffer - Subsequent subscribers → ref-count incremented, same ring buffer reader returned
- Subscriber disconnects → ref-count decremented; when zero, goroutine stops and track is removed
- Publisher disconnects → all transcode goroutines receive EOF and stop
- Each
TranscodedTrackhas its own ring buffer (SPMC lock-free) - Decoder/encoder instances are per-goroutine (not shared)
- The
TranscodeManageruses a mutex only for track creation/lookup