From 523eafd4d7a5272ed0ef0b9cf22afcd84ac1c438 Mon Sep 17 00:00:00 2001 From: Edison Jwa Date: Thu, 11 Jun 2026 21:58:32 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20evaluate=20platform=20backend=20extract?= =?UTF-8?q?ion=20=E2=80=94=20leave=20as-is=20(TODO-024)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Single-crate with module-level cfg gates is correct architecture. Splitting would add dependency complexity with no compilation benefit. --- docs/designs/platform-backends-evaluation.md | 62 ++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 docs/designs/platform-backends-evaluation.md diff --git a/docs/designs/platform-backends-evaluation.md b/docs/designs/platform-backends-evaluation.md new file mode 100644 index 0000000..6c8059e --- /dev/null +++ b/docs/designs/platform-backends-evaluation.md @@ -0,0 +1,62 @@ +# Platform Backend Extraction Evaluation — chanora_audio + +**Date:** 2026-06-11 +**Status:** Evaluation (not implementation) +**Crate:** `chanora_audio` (~18,500 lines total) + +## Current Structure + +Platform-specific code is isolated into dedicated files with `#[cfg]` gates at the module boundary. The engine module (`engine/mod.rs`, `engine/lifecycle.rs`) uses pervasive inline `cfg` attributes to dispatch across platforms. + +### Lines Per Platform (exclusive files only) + +| Platform | Files | Lines | Key Dependencies | +|----------|-------|-------|-----------------| +| **iOS/macOS** | `ios_voice_unit.rs`, `vad/apple_coreml.rs`, `ptt_backends/macos.rs`, `voice_render.rs` | ~2,600 | `coreaudio-rs`, `dispatch2` | +| **Android** | `android_voice_unit.rs`, `android_render_ring.rs`, `audio_event_queue.rs` | ~2,130 | `oboe`, `jni`, `ndk-context`, `bytemuck` | +| **Desktop** | `engine/capture.rs`, `engine/render.rs`, `sdl_output.rs`, `ptt_backends/windows*.rs`, `ptt_backends/linux.rs`, `vad/silero_onnx.rs` | ~4,400 | `cpal`, `sdl2`, `ort`, `windows`, `zbus` | + +### Shared Code (cross-platform) + +| Module | Lines | Notes | +|--------|-------|-------| +| `mobile_voice_backend.rs` | 813 | Trait + types for iOS/Android backends | +| `engine/mod.rs` + `engine/lifecycle.rs` | 2,255 | Heavy inline `cfg` dispatch | +| `processor/` | ~500 | AudioProcessor trait + backends | +| `vad/mod.rs` + `vad/resampler.rs` | 393 | VAD trait + WebRTC fallback | +| Other shared (`frame`, `opus_voice`, `ptt`, `voice_activity`, etc.) | ~3,200 | Platform-neutral | + +## Assessment + +### Would splitting help? + +**No — not recommended at this time.** + +### Reasons Against Splitting + +1. **cfg gating already works.** Platform files are cleanly isolated at the module boundary. The compiler strips unused code per-target; a separate crate doesn't add compilation speed for the active target. + +2. **Shared types are deeply embedded.** `AudioError`, `AudioEffects`, `AudioProcessingConfig`, `VoiceActivityStateMachine`, `OpusEncoder` setup, `frame::*` helpers, and the `AudioProcessor` trait are used by every platform. Extracting these into a `chanora_audio_common` crate is mandatory before splitting, adding a dependency node every platform crate must pull in. + +3. **engine/lifecycle.rs is the real problem — but it's an integration point, not a platform backend.** This 1,149-line file dispatches `start_audio` / `stop_audio` across all platforms with inline `cfg`. Splitting backends into separate crates wouldn't reduce this file's complexity — it would just move the cross-crate import surface here. + +4. **Dependency graph complexity.** The current single crate has 5 `cfg`-gated dependency blocks in Cargo.toml. Splitting into 3+ crates means each platform crate needs its own Cargo.toml with the shared types dependency, and the top-level `chanora_audio` (or `chanora_core`) must depend on all of them with target-conditional `cfg` features. + +5. **Test surface stays the same.** Platform-specific tests already compile only on their target OS. A crate boundary doesn't improve test isolation. + +6. **The `MobileVoiceAudioBackend` trait is the natural seam — and it already exists.** `mobile_voice_backend.rs` defines the cross-platform interface. The iOS backend will implement it under SDD-117. This is the correct abstraction boundary without adding a crate boundary. + +### When Splitting Would Make Sense + +- If build times for **cross-compilation** become painful (building all 3 platform variants from CI) +- If platform-specific dependencies cause **feature flag conflicts** (not observed today) +- If the crate exceeds ~30k lines and the `cfg` density makes navigation difficult +- If a platform team needs to own a crate independently + +## Recommendation + +Keep the current single-crate structure. Focus cleanup effort on: + +1. **Reducing inline `cfg` in `engine/lifecycle.rs`** — extract platform dispatch into the existing `IosVoiceBackend` enum pattern +2. **Back-filling `IosVoiceUnit` to `MobileVoiceAudioBackend`** (SDD-117) — this unifies the mobile interface +3. **Documenting the cfg convention** — module-level `cfg` at the file boundary (current pattern) vs. inline `cfg` blocks in shared files