Expand description
Audio as data: sounds are session resources, and playing one is a command the frame driver drains and applies to the device.
Register a sound’s bytes with Core::add_sound (a SoundId), then
play it one of three ways: NodeSpec::click_sound / hover_sound on a
node; Ui::audio with an AudioSpec, a playback that runs for as
long as the view declares the node; or Core::play / Ui::play with
PlayOptions, plus stop, set_volume, pause, resume and
set_master_volume for a host that holds the core. The windowed runner
drains the resulting AudioCommands; a host driving its own loop
drains Core::take_audio_commands. The core never touches a device, so
a headless test asserts on the queue.
use kui_core::{AudioCommand, AudioSpec, Core, NodeSpec, PlayOptions, Size};
let mut core = Core::new();
let chime = core.add_sound(b"RIFF....WAVE".to_vec()); // the file's bytes
// Imperative: start it now at half volume and ask for an `ended` event.
let playback = core.play(chime, PlayOptions::default().volume(0.5).tag("chime"));
// Declarative, in a view: a click sound, and a loop that plays while declared.
let mut ui = core.frame(Size::new(400.0, 300.0), 1.0);
ui.leaf_keyed("go", NodeSpec::row().size(80.0, 24.0).on_click("go").click_sound(chime));
ui.audio_keyed("music", AudioSpec::new(chime).looped().volume(0.3));
ui.finish();
// What a driver does with the queue.
for cmd in core.take_audio_commands() {
match cmd {
AudioCommand::Play { playback, sound, looped, .. } => {
println!("play {sound:?} as {playback:?} (loop: {looped})");
}
AudioCommand::Stop { playback, .. } => println!("stop {playback:?}"),
other => println!("{}", other.kind_name()),
}
}
core.stop(playback, 0.0);A playback started with a tag comes back as
{kind:"sound", phase:"ended", playback, tag} on the origin that
started it once the driver reports it finished (Core::audio_ended),
not when something stopped it. A play the device refused comes back as
phase:"refused" (Core::audio_refused), so nothing waits on an
ended that cannot come. A stop that cut a one-shot off mid-sound is
reported as the crate::diag::TRUNCATED_PLAYBACK warning
(Core::audio_truncated); AudioSpec::finish is the usual answer.
Structs§
- Audio
Spec - What an
audionode declares each frame (Core::audio_node). - Audio
Store - Playback bookkeeping on the session: the command queue, the tagged
playbacks awaiting their
endedevent, and theaudionodes’ retained playbacks. The queue and the ids are the session’s, because the process has one device; the mounts are keyed by window as well as by node, because each is reconciled against one window’s frame (finish_framehands in the window it finished, and only that window’s slice is diffed). - Play
Options - How to start a playback (
Core::play). - Playback
Id - One playback instance. Allocated by the core when the play command is queued, so callers get it synchronously without a driver round trip; 0 is never issued.
Enums§
- Audio
Command - An audio intent for the frame driver. Durations are ms; volumes are linear amplitude. Drivers ignore playbacks they no longer hold.
- Why
- Why a one-shot playback was cut off — what
diag::TRUNCATED_PLAYBACKreports once the driver confirms the sound was still running.