pub struct AudioEngine { /* private fields */ }Expand description
A mixing audio player backed by a platform output device.
The device is opened lazily, on the first call that actually makes sound, so an app that installs the engine but never plays anything costs no audio thread and no battery. Loading clips is not such a call: a clip load is a queue push, and the queue exists from construction, so a title screen can have its whole sound bank resident with the output device still shut.
The device does not stay open either. When nothing has sounded for
IDLE_GRACE_SECONDS the mixer gives the
stream up and the next play starts it again, so a
silent screen costs nothing however it was reached.
Implementations§
Source§impl AudioEngine
impl AudioEngine
Sourcepub fn new() -> AudioEngine
pub fn new() -> AudioEngine
Creates an engine that opens the platform output device on first use.
Sourcepub fn with_sink_opener(
open_sink: Box<dyn Fn(MixerSeed) -> Result<Box<dyn AudioSink>, AudioError>>,
) -> AudioEngine
pub fn with_sink_opener( open_sink: Box<dyn Fn(MixerSeed) -> Result<Box<dyn AudioSink>, AudioError>>, ) -> AudioEngine
Creates an engine over a caller-supplied device opener. The platform backends and the crate’s own tests both go through this.
Sourcepub fn take_last_error(&self) -> Option<AudioError>
pub fn take_last_error(&self) -> Option<AudioError>
The most recent failure, if the device refused to open or a call was rejected. Cleared by reading it.
Sourcepub fn leaked_clips(&self) -> u32
pub fn leaked_clips(&self) -> u32
How many clips the mixer could not hand back for dropping. Any value above zero means the app stopped calling the engine while clips were being replaced; it is reported rather than hidden.
Sourcepub fn underruns(&self) -> u32
pub fn underruns(&self) -> u32
How many times the device asked for a buffer the mixer could not fill.
Sourcepub fn is_running(&self) -> bool
pub fn is_running(&self) -> bool
Whether the output device is open.
Open is not the same as running: a device that has been open for a while
spends most of a quiet screen stopped. See
is_streaming.
Sourcepub fn is_streaming(&self) -> bool
pub fn is_streaming(&self) -> bool
Whether the output stream is live rather than given up as idle.
false with is_running true is the
steady state of a silent screen: the device object and every loaded clip
are still there, the stream is not, and the next play starts it again.
A stream paused by suspend still counts as
live — the app took it away, not the mixer, and it comes back on
resume.
Trait Implementations§
Source§impl AudioPlayer for AudioEngine
impl AudioPlayer for AudioEngine
Source§fn load_clip(&self, clip: AudioClip) -> Result<SoundId, AudioError>
fn load_clip(&self, clip: AudioClip) -> Result<SoundId, AudioError>
Takes a clip table slot and queues the clip for the mixer.
This deliberately does not open the output device. Loading a bank of cues is what an app does on the way into a screen, long before it plays anything, and opening the device there was costing a silent title screen an audio thread and an always-on DSP rail for as long as it was on display. The command ring outlives every mixer, so the load waits in it and is drained by the first mixer to start.
The consequence is a narrower error contract than this used to have.
The only failure it can still report is the one it can determine here,
AudioError::ClipTableFull; a device that is missing or refuses to
open is no longer a load-time error, because finding that out means
opening it. Callers that need to know ask
is_available, and the failure itself is
available from take_last_error once a
play has tried. That also makes this agree with NoopAudioPlayer, which
hands out real SoundIds on a machine with no audio at all so app
logic does not have to branch.
Source§fn play(&self, id: SoundId, params: PlaybackParams)
fn play(&self, id: SoundId, params: PlaybackParams)
Source§fn play_loop(&self, id: SoundId, params: PlaybackParams) -> VoiceId
fn play_loop(&self, id: SoundId, params: PlaybackParams) -> VoiceId
Source§fn stop_voice(&self, voice: VoiceId)
fn stop_voice(&self, voice: VoiceId)
Source§fn set_voice_params(&self, voice: VoiceId, params: PlaybackParams)
fn set_voice_params(&self, voice: VoiceId, params: PlaybackParams)
Source§fn set_master_volume(&self, volume: f32)
fn set_master_volume(&self, volume: f32)
Source§fn master_volume(&self) -> f32
fn master_volume(&self) -> f32
Source§fn set_bus_volume(&self, bus: AudioBus, volume: f32)
fn set_bus_volume(&self, bus: AudioBus, volume: f32)
Source§fn bus_volume(&self, bus: AudioBus) -> f32
fn bus_volume(&self, bus: AudioBus) -> f32
Source§fn set_bus_enabled(&self, bus: AudioBus, enabled: bool)
fn set_bus_enabled(&self, bus: AudioBus, enabled: bool)
Source§fn bus_enabled(&self, bus: AudioBus) -> bool
fn bus_enabled(&self, bus: AudioBus) -> bool
Source§fn suspend(&self)
fn suspend(&self)
Source§fn is_available(&self) -> bool
fn is_available(&self) -> bool
false, so an app can honestly grey out its audio settings.