1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
//! Device playback — the cpal-backed mlxrs port of
//! `mlx-audio-swift`'s `MLXAudioCore.AudioPlayer` streaming surface.
//!
//! Ports the *streaming* branch (issue #174) of Swift's
//! `AudioPlayer` (the `startStreaming(sampleRate:)` /
//! `scheduleAudioChunk(_:withCrossfade:)` /
//! `stopStreaming()` triad) over [cpal][cpal], the de-facto pure-Rust
//! cross-platform audio I/O crate (CoreAudio on macOS, WASAPI on
//! Windows, ALSA on Linux). The cpal equivalent of Swift's
//! `AVAudioEngine` + `AVAudioPlayerNode` pattern is:
//!
//! ```text
//! cpal::default_host() ── Host ── default_output_device() ── Device
//! │
//! build_output_stream(config, data_cb, err_cb)
//! │
//! ▼
//! cpal::Stream ── play() / pause()
//! ```
//!
//! [`AudioPlayer`] owns the [`cpal::Stream`] and a shared queue the
//! producer fills; the cpal callback pulls from the queue on the
//! audio I/O thread. [`AudioOutputStream`] is the producer-side
//! trait the speech-to-speech pipeline ([`crate::audio::sts`])
//! consumes — same shape whether the sink is a real device, a file,
//! or a unit-test recorder.
//!
//! ## Module layout
//!
//! - [`mod@config`] — [`PlaybackConfig`], [`SampleFormat`],
//! [`ChannelLayout`]. The cpal-equivalent of Swift's
//! `AVAudioFormat(standardFormatWithSampleRate:channels:)`.
//! - [`mod@output_stream`] — [`AudioOutputStream`] trait. The narrow
//! producer-side surface the upstream pipeline consumes.
//! - [`mod@player`] — [`AudioPlayer`] struct. The cpal-backed
//! default implementor of [`AudioOutputStream`].
//!
//! ## Scope cuts (explicit)
//!
//! To match the official binding design, the
//! mlxrs port intentionally omits a few Swift-side capabilities; the
//! full enumeration lives in the [`mod@player`] docstring. Quick
//! summary:
//!
//! - **Audio input / recording** — playback-only.
//! - **File I/O** — raw PCM only; file decoding lives in
//! [`crate::audio::io`].
//! - **Format conversion / resampling** — caller-supplied PCM at the
//! configured [`PlaybackConfig::sample_rate`] /
//! [`PlaybackConfig::channels`].
//! - **Crossfade / fade-in** — application-level concern.
//! - **`@Published` properties / Combine bindings** — Rust library,
//! no `ObservableObject`.
//!
//! [cpal]: https://crates.io/crates/cpal
pub use ;
pub use AudioOutputStream;
pub use AudioPlayer;