Skip to content
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Unreleased

- ALSA(process_output): pass `silent=true` to `PCM.try_recover`, so it doesn't write to stderr.
- ALSA(process_output): Pass `silent=true` to `PCM.try_recover`, so it doesn't write to stderr.
- CoreAudio: `Device::supported_configs` now returns a single element containing the available sample rate range when all elements have the same `mMinimum` and `mMaximum` values (which is the most common case).
- CoreAudio: Detect default audio device lazily when building a stream, instead of during device enumeration.
- iOS: Fix example by properly activating audio session.
- WASAPI: Expose IMMDevice from WASAPI host Device.

Expand Down
11 changes: 2 additions & 9 deletions src/host/coreaudio/macos/enumerate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ impl Iterator for Devices {
fn next(&mut self) -> Option<Device> {
self.0.next().map(|id| Device {
audio_device_id: id,
is_default: false,
})
}
}
Expand Down Expand Up @@ -109,10 +108,7 @@ pub fn default_input_device() -> Option<Device> {
return None;
}

let device = Device {
audio_device_id,
is_default: true,
};
let device = Device { audio_device_id };
Some(device)
}

Expand All @@ -139,10 +135,7 @@ pub fn default_output_device() -> Option<Device> {
return None;
}

let device = Device {
audio_device_id,
is_default: true,
};
let device = Device { audio_device_id };
Some(device)
}

Expand Down
22 changes: 13 additions & 9 deletions src/host/coreaudio/macos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,18 +159,22 @@ impl DeviceTrait for Device {
#[derive(Clone, PartialEq, Eq)]
pub struct Device {
pub(crate) audio_device_id: AudioDeviceID,
is_default: bool,
}

fn is_default_device(device: &Device) -> bool {
Copy link

Copilot AI Aug 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The is_default_device() function calls system APIs on every invocation. Consider caching the result or accepting that this function may be called frequently during stream operations, which could impact performance.

Copilot uses AI. Check for mistakes.
default_input_device()
.map(|d| d.audio_device_id == device.audio_device_id)
.unwrap_or(false)
|| default_output_device()
.map(|d| d.audio_device_id == device.audio_device_id)
.unwrap_or(false)
Comment on lines +165 to +170
Copy link

Copilot AI Aug 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function calls default_input_device() and default_output_device() on every check, which duplicates system calls. Consider refactoring to get both device IDs in a single operation or add early return optimization.

Suggested change
default_input_device()
.map(|d| d.audio_device_id == device.audio_device_id)
.unwrap_or(false)
|| default_output_device()
.map(|d| d.audio_device_id == device.audio_device_id)
.unwrap_or(false)
if let Some(d) = default_input_device() {
if d.audio_device_id == device.audio_device_id {
return true;
}
}
default_output_device()
.map(|d| d.audio_device_id == device.audio_device_id)
.unwrap_or(false)

Copilot uses AI. Check for mistakes.
}

impl Device {
/// Construct a new device given its ID.
/// Useful for constructing hidden devices.
pub fn new(audio_device_id: AudioDeviceID) -> Self {
Device {
audio_device_id,
// TODO: This could be made to detect the default device properly.
is_default: false,
}
Self { audio_device_id }
}

fn name(&self) -> Result<String, DeviceNameError> {
Expand Down Expand Up @@ -523,7 +527,7 @@ where
}

fn audio_unit_from_device(device: &Device, input: bool) -> Result<AudioUnit, coreaudio::Error> {
let output_type = if device.is_default && !input {
let output_type = if is_default_device(device) && !input {
coreaudio::audio_unit::IOType::DefaultOutput
} else {
coreaudio::audio_unit::IOType::HalOutput
Expand Down Expand Up @@ -665,7 +669,7 @@ impl Device {

// If we didn't request the default device, stop the stream if the
// device disconnects.
if !self.is_default {
if !is_default_device(self) {
add_disconnect_listener(&stream, error_callback_disconnect)?;
}

Expand Down Expand Up @@ -770,7 +774,7 @@ impl Device {

// If we didn't request the default device, stop the stream if the
// device disconnects.
if !self.is_default {
if !is_default_device(self) {
add_disconnect_listener(&stream, error_callback_disconnect)?;
}

Expand Down
2 changes: 0 additions & 2 deletions src/samples_formats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,11 @@ pub enum SampleFormat {

/// `U24` with a valid range of '0..16777216' with `1 << 23 == 8388608` being the origin
// U24,

/// `u32` with a valid range of `u32::MIN..=u32::MAX` with `1 << 31` being the origin.
U32,

/// `U48` with a valid range of '0..(1 << 48)' with `1 << 47` being the origin
// U48,

/// `u64` with a valid range of `u64::MIN..=u64::MAX` with `1 << 63` being the origin.
U64,

Expand Down
Loading