Native audio capture, encoding, and decoding for Media over QUIC.
Counterpart to moq-video for audio
tracks, and shaped the same way. Sits on top of [moq_mux] and [hang] and
adds the missing piece for native callers: Rust-native Opus and uncompressed
PCM codecs that turn raw samples into HANG audio tracks and back.
capturedescribes an audio source (capture::Config) and grabs buffers per platform: a microphone via cpal (CoreAudio / WASAPI / ALSA) everywhere, or macOS system audio via ScreenCaptureKit.capture::Sourcepicks between them andcapture::deviceslists the inputs and hands back the ids it takes. Requires thecapturefeature, so these names are unlinked here: they don't exist in a default build.- [
encode] encodes PCM and publishes it throughmoq_mux::container, registering the rendition in thehangcatalog. Two entry points:encode::publish_capturecaptures a microphone and publishes it (turnkey). It encodes strictly on demand: the track and catalog are advertised up front, but the device opens only while a subscriber is listening and is released when the last one leaves.- [
encode::Producer] publishes PCM you hand it.
- [
decode] subscribes to an encoded track and decodes it back to PCM. [decode::Consumer] is the mirror of [encode::Producer]. playbackplays decoded PCM out a speaker.playback::Engineowns the output device and mixes theplayback::Sinks registered with it, so one device serves every track in a call. Requires theplaybackfeature, so these names are unlinked here too.aeckeeps the speaker out of the microphone, which is what a conference on a laptop needs to not send itself back.playback::Engine::cancellerbuilds anaec::Cancellerfrom the mix it is playing andcapture::Config::aechands it to the microphone. Requires theaecfeature, which implies both of the above.
[Format] mirrors WebCodecs AudioData.format; the helpers convert between
any supported layout and the interleaved f32 representation libopus
expects. [Frame] is a thin owned buffer: a timestamp and a payload. PCM
layout lives on the producer / consumer via [encode::Input] /
[decode::Config], not on each frame, so callers can't drift between calls.