Skip to content

feat: add AudioSource/AudioSink traits + G.711 codec#21

Merged
wavekat-eason merged 5 commits into
mainfrom
feat/audio-io-and-g711
May 14, 2026
Merged

feat: add AudioSource/AudioSink traits + G.711 codec#21
wavekat-eason merged 5 commits into
mainfrom
feat/audio-io-and-g711

Conversation

@wavekat-eason
Copy link
Copy Markdown
Contributor

Summary

Two upstream-shaped additions for the WaveKat audio ecosystem:

  • audio_io::{AudioSource, AudioSink} — the producer/consumer seam any audio pipeline composes against. Send-bounded traits with Send-bounded future returns, keyed on `AudioFrame`. Concrete impls live in their consuming crates (cpal mic in `wavekat-voice`, a future agent-backed impl in `wavekat-agent`) so the trait stays neutral.
  • `codec::g711` — PCMU + PCMA encode/decode, the `G711Codec` enum (resolves SDP payload types), and standard constants (sample rate, frame size, payload-type numbers). Codecs are consumer-layer for `wavekat-sip` (which deliberately stays codec-agnostic), but multiple downstream crates need them — keep one canonical implementation here.

CLAUDE.md updated to document the new modules under "What Belongs Here" and the repo-structure tree.

Why this lives here

Originally drafted inside `wavekat-voice` as part of the M1 audio scaffolding (doc 12's "one architectural seam worth drawing now"). Moved upstream so that:

  1. `wavekat-agent` (v2's AI-answered mode) can impl `AudioSource` / `AudioSink` without depending on the closed-source `wavekat-voice` crate.
  2. `wavekat-asr` and any future codec-handling crate can use `codec::g711` without re-implementing it.

The `wavekat-sip` port-plan explicitly excludes codecs from that crate, so they don't go there.

Test plan

39 unit tests in the lib + 3 doctests. Coverage:

  • G.711 silence, full-scale, slice-length, payload-type round-trip
  • G.711 decode is a fixed-point for every codeword (256 cases per codec)
  • G.711 decode covers full codeword space without panic
  • G.711 `G711Codec` enum dispatch matches the standalone functions
  • G.711 sine-wave round-trip with mean-error bound (PCMU and PCMA)
  • G.711 slice-encode appends rather than replaces (buffer-reuse contract)
  • G.711 payload-type constants pinned to RFC 3551 (PCMU=0, PCMA=8)
  • `audio_io`: source drains in order then returns None (and stays None)
  • `audio_io`: sink can drop on backpressure
  • `audio_io`: sample-rate preserved through the sink
  • `audio_io`: trait impls are `Send` (compile-time check; if this stops compiling, the bound regressed)
  • `cargo clippy --all-targets --all-features` clean
  • `cargo fmt --all --check` clean

🤖 Generated with Claude Code

wavekat-eason and others added 2 commits May 14, 2026 16:00
Two upstream-shaped additions for the WaveKat audio ecosystem:

- `audio_io::{AudioSource, AudioSink}` — the producer/consumer seam the
  whole audio pipeline is drawn against. Frames keyed on `AudioFrame`
  so the trait doesn't have to know about the codec.
- `codec::g711` — PCMU / PCMA encode/decode + `G711Codec` enum.
  Codecs are consumer-layer (`wavekat-sip` stays codec-agnostic) but
  benefit from a shared home so future consumers (wavekat-asr,
  wavekat-voice, an eventual `wavekat-agent`) don't each reimplement.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- audio_io: source-drain ordering, sink backpressure pattern,
  per-frame sample-rate preservation, compile-time Send check.
- g711: per-codeword decode fixed-point sweep, full-codeword-space
  no-panic, distinctness sanity, PCMU vs PCMA cross-check, slice
  encode/decode buffer-append behavior, sine-wave round-trip with a
  mean-error bound, RFC 3551 payload-type pinning.

Also document the new modules under "What Belongs Here" and the
repo-structure tree in CLAUDE.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sentry
Copy link
Copy Markdown

sentry Bot commented May 14, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

wavekat-eason and others added 3 commits May 14, 2026 16:14
Replace seg_for's loop with leading_zeros bit-math so it can't fall
through, and remove the unreachable seg >= 8 arms in linear_to_ulaw
and linear_to_alaw. Inputs are already bounded to [0, 0x7FFF], so
the guards never fired and showed up as missing patch coverage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@wavekat-eason wavekat-eason merged commit 55c883e into main May 14, 2026
2 checks passed
@wavekat-eason wavekat-eason deleted the feat/audio-io-and-g711 branch May 14, 2026 04:20
@github-actions github-actions Bot mentioned this pull request May 14, 2026
wavekat-eason pushed a commit that referenced this pull request May 14, 2026
## 🤖 New release

* `wavekat-core`: 0.0.8 -> 0.0.9 (✓ API compatible changes)

<details><summary><i><b>Changelog</b></i></summary><p>

<blockquote>

##
[0.0.9](v0.0.8...v0.0.9)
- 2026-05-14

### Added

- add AudioSource/AudioSink traits + G.711 codec
([#21](#21))
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant