Skip to content

Commit df62c62

Browse files
committed
[update] specification to match the audio implementation.
1 parent 7e7851d commit df62c62

File tree

1 file changed

+86
-60
lines changed

1 file changed

+86
-60
lines changed

docs/specs/audio-devices.md

Lines changed: 86 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ title: "Audio Device Abstraction"
33
document_id: "audio-device-abstraction-2026-01-28"
44
status: "draft"
55
created: "2026-01-28T22:59:00Z"
6-
last_updated: "2026-01-30T22:15:27Z"
7-
version: "0.1.10"
6+
last_updated: "2026-01-30T23:21:06Z"
7+
version: "0.1.12"
88
engine_workspace_version: "2023.1.30"
99
wgpu_version: "26.0.1"
1010
shader_backend_default: "naga"
1111
winit_version: "0.29.10"
12-
repo_commit: "e179f7de3b43f9cd822b4f7ab520c095dc3c6911"
12+
repo_commit: "7e7851da903fbc7b4aa35acd511999df659af237"
1313
owners: ["lambda-sh"]
1414
reviewers: ["engine", "rendering"]
1515
tags: ["spec", "audio", "lambda-rs", "platform", "cpal"]
@@ -82,23 +82,23 @@ tags: ["spec", "audio", "lambda-rs", "platform", "cpal"]
8282

8383
## Architecture Overview
8484

85-
- Crate `lambda-rs`
85+
- Crate `lambda` (package: `lambda-rs`)
8686
- `audio` module provides the application-facing API for output device access.
8787
- The public API MUST remain backend-agnostic and MUST NOT expose `cpal` or
8888
`lambda-rs-platform` types.
89-
- Crate `lambda-rs-platform`
90-
- `cpal` module provides internal implementations used by `lambda-rs`
91-
implementations.
89+
- Crate `lambda_platform` (package: `lambda-rs-platform`)
90+
- `cpal` module provides internal implementations used by `lambda-rs`.
9291
- `cpal::device` wraps `cpal` device discovery and stream creation.
92+
- The backend dependency MUST be pinned to `cpal = "=0.17.1"`.
9393

9494
Data flow
9595

9696
```
9797
application
98-
└── lambda-rs::audio
98+
└── lambda::audio
9999
├── enumerate_output_devices() -> Vec<AudioOutputDeviceInfo>
100100
└── AudioOutputDeviceBuilder::build() -> AudioOutputDevice
101-
└── lambda-rs-platform::cpal (internal)
101+
└── lambda_platform::cpal (internal)
102102
├── enumerate_devices() -> Vec<AudioDeviceInfo>
103103
└── AudioDeviceBuilder::build() -> AudioDevice
104104
└── cpal (host + device + stream)
@@ -220,16 +220,17 @@ pub fn enumerate_devices() -> Result<Vec<AudioDeviceInfo>, AudioError>;
220220
### lambda-rs Public API
221221

222222
`lambda-rs` provides the application-facing audio API and translates to
223-
`lambda-rs-platform::cpal` internally. The `lambda-rs` layer MUST remain
224-
backend-agnostic and MUST NOT expose `cpal` types.
223+
`lambda_platform::cpal` (package: `lambda-rs-platform`) internally. The
224+
`lambda-rs` layer MUST remain backend-agnostic and MUST NOT expose `cpal`
225+
types.
225226

226227
Crate boundary
227228

228229
- Applications MUST use `lambda-rs` for audio and MUST NOT use
229230
`lambda-rs-platform` directly.
230231
- `lambda-rs-platform` audio APIs are internal implementation details and MAY
231232
change without regard for application compatibility.
232-
- `lambda-rs::audio` MUST remain backend-agnostic and MUST NOT require direct
233+
- `lambda::audio` MUST remain backend-agnostic and MUST NOT require direct
233234
use of `lambda-rs-platform` types by applications.
234235

235236
Application-facing API surface
@@ -316,29 +317,30 @@ pub fn enumerate_output_devices(
316317

317318
Implementation rules
318319

319-
- `lambda-rs::audio` MUST translate into `lambda-rs-platform::cpal` internally.
320-
- `lambda-rs::audio` MUST define its own public types and MUST NOT re-export
320+
- `lambda::audio` MUST translate into `lambda_platform::cpal` (package:
321+
`lambda-rs-platform`) internally.
322+
- `lambda::audio` MUST define its own public types and MUST NOT re-export
321323
`lambda-rs-platform` audio types.
322-
- `lambda-rs::audio::AudioError` MUST remain backend-agnostic and MUST NOT
324+
- `lambda::audio::AudioError` MUST remain backend-agnostic and MUST NOT
323325
expose `cpal` types.
324326

325327
Features
326328

327329
- `lambda-rs` granular feature: `audio-output-device` (default: enabled)
328-
- Enables the `lambda-rs::audio` output device surface.
330+
- Enables the `lambda::audio` output device surface.
329331
- Enables `lambda-rs-platform` `audio-device` internally.
330332
- `lambda-rs` umbrella feature: `audio` (default: enabled)
331333
- Composes `audio-output-device` only.
332334

333335
### Application Interaction
334336

335337
This section describes the intended application-facing workflow via
336-
`lambda-rs::audio`.
338+
`lambda::audio`.
337339

338340
Initialization flow
339341

340-
- An application SHOULD enumerate devices to present names in diagnostics or a
341-
settings UI.
342+
- An application SHOULD enumerate devices to present names in diagnostics
343+
output.
342344
- An application SHOULD create exactly one default output device during
343345
startup.
344346
- The application MUST keep the returned device handle alive for as long as
@@ -347,7 +349,7 @@ Initialization flow
347349
Device enumeration
348350

349351
```rust
350-
let devices = lambda_rs::audio::enumerate_output_devices()?;
352+
let devices = lambda::audio::enumerate_output_devices()?;
351353
for device in devices {
352354
println!(
353355
"audio: {}{}",
@@ -363,7 +365,7 @@ Default device initialization (deterministic test tone)
363365
let mut phase: f32 = 0.0;
364366
let frequency_hz: f32 = 440.0;
365367

366-
let _audio_output = lambda_rs::audio::AudioOutputDeviceBuilder::new()
368+
let _audio_output = lambda::audio::AudioOutputDeviceBuilder::new()
367369
.with_sample_rate(48_000)
368370
.with_channels(2)
369371
.build_with_output_callback(move |writer, info| {
@@ -394,11 +396,11 @@ Runtime interaction
394396
Minimal application sketch
395397

396398
```rust
397-
use lambda_rs::runtime::start_runtime;
398-
use lambda_rs::runtimes::ApplicationRuntimeBuilder;
399+
use lambda::runtime::start_runtime;
400+
use lambda::runtimes::ApplicationRuntimeBuilder;
399401

400-
fn main() -> Result<(), lambda_rs::audio::AudioError> {
401-
let _audio_output = lambda_rs::audio::AudioOutputDeviceBuilder::new()
402+
fn main() -> Result<(), lambda::audio::AudioError> {
403+
let _audio_output = lambda::audio::AudioOutputDeviceBuilder::new()
402404
.build()?;
403405

404406
let runtime = ApplicationRuntimeBuilder::new("Lambda App").build();
@@ -409,7 +411,7 @@ fn main() -> Result<(), lambda_rs::audio::AudioError> {
409411

410412
### Behavior
411413

412-
Device enumeration (`lambda_rs::audio::enumerate_output_devices`)
414+
Device enumeration (`lambda::audio::enumerate_output_devices`)
413415

414416
- `enumerate_output_devices` MUST return only output-capable devices.
415417
- `enumerate_output_devices` MUST include the default output device when one
@@ -425,9 +427,9 @@ Default device initialization (`AudioOutputDeviceBuilder::build`)
425427
- `build` MUST validate the requested configuration against the device’s
426428
supported output configurations.
427429
- When `sample_rate` is not specified, `build` MUST prefer 48_000 Hz when
428-
supported and otherwise fall back to the device default configuration.
429-
- When `channels` is not specified, `build` MUST prefer stereo (`2`) when
430-
supported and otherwise fall back to the device default configuration.
430+
supported and otherwise clamp to the nearest supported rate within the chosen
431+
configuration range.
432+
- When `channels` is not specified, `build` MUST NOT filter by channel count.
431433
- `build` MUST create an output stream that produces silence (all samples set
432434
to zero) and MUST keep the stream alive for the lifetime of
433435
`AudioOutputDevice`.
@@ -484,15 +486,15 @@ Error type
484486

485487
- `lambda-rs` MUST define an `AudioError` error enum suitable for actionable
486488
diagnostics.
487-
- `lambda-rs::audio::AudioError` MUST remain backend-agnostic and MUST NOT
489+
- `lambda::audio::AudioError` MUST remain backend-agnostic and MUST NOT
488490
expose `cpal` or `lambda-rs-platform` types.
489491
- `lambda-rs-platform` MUST define an internal `AudioError` suitable for
490492
actionable diagnostics inside the platform layer.
491-
- `lambda-rs-platform::cpal::AudioError` MUST NOT expose `cpal` types in its
492-
public API.
493-
- `lambda-rs` MUST translate `lambda-rs-platform::cpal::AudioError` into
494-
`lambda-rs::audio::AudioError`. Backend-specific failures SHOULD map to
495-
`AudioError::Platform { details }`.
493+
- `lambda_platform::cpal::AudioError` (package: `lambda-rs-platform`) MUST NOT
494+
expose `cpal` types in its public API.
495+
- `lambda-rs` MUST translate `lambda_platform::cpal::AudioError` (package:
496+
`lambda-rs-platform`) into `lambda::audio::AudioError`. Backend-specific
497+
failures SHOULD map to `AudioError::Platform { details }`.
496498

497499
Platform `AudioError` variants (internal)
498500

@@ -521,7 +523,7 @@ Features introduced by this spec
521523

522524
- Crate: `lambda-rs`
523525
- Granular feature: `audio-output-device` (default: enabled)
524-
- Enables `lambda-rs::audio` output device APIs.
526+
- Enables `lambda::audio` output device APIs.
525527
- Enables `lambda-rs-platform` `audio-device` internally.
526528
- Umbrella feature: `audio` (default: enabled)
527529
- Composes `audio-output-device` only.
@@ -568,32 +570,50 @@ Feature gating requirements
568570
## Requirements Checklist
569571

570572
- Functionality
571-
- [ ] Feature flags defined (`lambda-rs`: `audio-output-device`, `audio`)
572-
- [ ] Feature flags defined (`lambda-rs-platform`: `audio-device`, `audio`)
573-
- [ ] `enumerate_output_devices` implemented and returns output devices
574-
- [ ] `AudioOutputDeviceBuilder::build` initializes default output device
575-
- [ ] `AudioOutputDeviceBuilder::build_with_output_callback` invokes callback
576-
- [ ] Stream created and kept alive for `AudioOutputDevice` lifetime
577-
- [ ] Platform enumeration implemented (`lambda-rs-platform::cpal`)
578-
- [ ] Platform builder implemented (`lambda-rs-platform::cpal`)
573+
- [x] Feature flags defined (`lambda-rs`: `audio-output-device`, `audio`)
574+
(`crates/lambda-rs/Cargo.toml:22`)
575+
- [x] Feature flags defined (`lambda-rs-platform`: `audio-device`, `audio`)
576+
(`crates/lambda-rs-platform/Cargo.toml:53`)
577+
- [x] `enumerate_output_devices` implemented and returns output devices
578+
(`crates/lambda-rs/src/audio.rs:294`)
579+
- [x] `AudioOutputDeviceBuilder::build` initializes default output device
580+
(`crates/lambda-rs/src/audio.rs:222`,
581+
`crates/lambda-rs-platform/src/cpal/device.rs:403`)
582+
- [x] `AudioOutputDeviceBuilder::build_with_output_callback` invokes callback
583+
(`crates/lambda-rs/src/audio.rs:247`,
584+
`crates/lambda-rs-platform/src/cpal/device.rs:524`)
585+
- [x] Stream created and kept alive for `AudioOutputDevice` lifetime
586+
(`crates/lambda-rs/src/audio.rs:182`,
587+
`crates/lambda-rs-platform/src/cpal/device.rs:352`)
588+
- [x] Platform enumeration implemented (`lambda_platform::cpal`)
589+
(`crates/lambda-rs-platform/src/cpal/device.rs:807`)
590+
- [x] Platform builder implemented (`lambda_platform::cpal`)
591+
(`crates/lambda-rs-platform/src/cpal/device.rs:365`)
579592
- API Surface
580-
- [ ] Public `lambda-rs` types implemented: `AudioOutputDevice`,
593+
- [x] Public `lambda` types implemented: `AudioOutputDevice`,
581594
`AudioOutputDeviceInfo`, `AudioOutputDeviceBuilder`, `AudioCallbackInfo`,
582-
`AudioOutputWriter`, `AudioError`
583-
- [ ] Internal platform types implemented: `AudioDevice`, `AudioDeviceInfo`,
595+
`AudioOutputWriter`, `AudioError` (`crates/lambda-rs/src/audio.rs:12`)
596+
- [x] Internal platform types implemented: `AudioDevice`, `AudioDeviceInfo`,
584597
`AudioDeviceBuilder`, `AudioCallbackInfo`, `AudioOutputWriter`, `AudioError`
585-
- [ ] `lambda-rs::audio` does not re-export `lambda-rs-platform` types
598+
(`crates/lambda-rs-platform/src/cpal/device.rs:12`)
599+
- [x] `lambda::audio` does not re-export `lambda-rs-platform` types
600+
(`crates/lambda-rs/src/audio.rs:10`)
586601
- Validation and Errors
587-
- [ ] Invalid builder inputs rejected (sample rate and channel count)
588-
- [ ] Descriptive `AudioError` variants emitted on failures
589-
- [ ] Unsupported configurations reported via `AudioError::UnsupportedConfig`
602+
- [x] Invalid builder inputs rejected (sample rate and channel count)
603+
(`crates/lambda-rs-platform/src/cpal/device.rs:403`,
604+
`crates/lambda-rs-platform/src/cpal/device.rs:847`)
605+
- [x] Descriptive `AudioError` variants emitted on failures
606+
(`crates/lambda-rs/src/audio.rs:65`,
607+
`crates/lambda-rs-platform/src/cpal/device.rs:265`)
608+
- [x] Unsupported configurations reported via `AudioError::UnsupportedConfig`
609+
(`crates/lambda-rs-platform/src/cpal/device.rs:800`,
610+
`crates/lambda-rs/src/audio.rs:72`)
590611
- Documentation and Examples
591-
- [ ] `docs/features.md` updated with audio feature documentation
592-
- [ ] Example added demonstrating audible playback (behind `audio-output-device`)
593-
- [ ] `lambda-rs` audio facade implemented
594-
595-
For each checked item, include a reference to a commit, pull request, or file
596-
path that demonstrates the implementation.
612+
- [x] `docs/features.md` updated with audio feature documentation
613+
(`docs/features.md:1`)
614+
- [x] Example added demonstrating audible playback (behind `audio-output-device`)
615+
(`crates/lambda-rs/examples/audio_sine_wave.rs:1`)
616+
- [x] `lambda-rs` audio facade implemented (`crates/lambda-rs/src/audio.rs:1`)
597617

598618
## Verification and Testing
599619

@@ -603,7 +623,7 @@ This example is the primary application-facing reference.
603623

604624
- Add `crates/lambda-rs/examples/audio_sine_wave.rs` (feature:
605625
`audio-output-device`, enabled by default) that:
606-
- Prints `lambda_rs::audio::enumerate_output_devices()` output.
626+
- Prints `lambda::audio::enumerate_output_devices()` output.
607627
- Builds the default output device via the facade builder and plays a
608628
deterministic 440 Hz tone for at least 2 seconds.
609629

@@ -614,7 +634,7 @@ Unit tests (crate: `lambda-rs-platform`)
614634
- `with_sample_rate` and `with_channels` override requested values.
615635
- Invalid values (`0`) are rejected.
616636
- Enumeration
617-
- `enumerate_devices` returns `Ok(_)` and does not panic.
637+
- `enumerate_devices` returns `Result<_, _>` and does not panic.
618638

619639
Commands
620640

@@ -633,12 +653,18 @@ Manual checks
633653

634654
## Changelog
635655

656+
- 2026-01-30 (v0.1.12) — Populate the requirements checklist with file
657+
references matching the implemented surface.
658+
- 2026-01-30 (v0.1.11) — Align examples with the `lambda` crate name, document
659+
the internal `lambda_platform::cpal` path and pin, and refine default
660+
configuration selection requirements to match the implementation.
636661
- 2026-01-30 (v0.1.10) — Enable `lambda-rs` audio features by default.
637662
- 2026-01-29 (v0.1.9) — Fix YAML front matter to use a single `version` field.
638663
- 2026-01-29 (v0.1.8) — Make the `lambda-rs` facade example the primary
639664
reference and remove the platform example requirement.
640665
- 2026-01-29 (v0.1.7) — Rename the platform audio implementation module to
641-
`lambda-rs-platform::cpal` to reflect the internal backend.
666+
`lambda_platform::cpal` (package: `lambda-rs-platform`) to reflect the
667+
internal backend.
642668
- 2026-01-29 (v0.1.6) — Specify `lambda-rs` as the only supported
643669
application-facing API and treat `lambda-rs-platform` as internal.
644670
- 2026-01-29 (v0.1.5) — Specify how `lambda-rs` applications enumerate devices

0 commit comments

Comments
 (0)