Listen for changes to the configuration of the attached device too (#28045)
Release Notes: - Fixed an issue causing "robot voice" when enabling the microphone on some bluetooth headphones (hopefully). Co-authored-by: Zed AI <ai+claude-3.7@zed.dev>
This commit is contained in:
parent
c04c5812b6
commit
ee4b6a8db4
1 changed files with 94 additions and 7 deletions
|
@ -163,9 +163,8 @@ impl AudioStack {
|
|||
sample_rate: u32,
|
||||
num_channels: u32,
|
||||
) -> Result<()> {
|
||||
let mut default_change_listener = DeviceChangeListener::new(false)?;
|
||||
|
||||
loop {
|
||||
let mut device_change_listener = DeviceChangeListener::new(false)?;
|
||||
let (output_device, output_config) = default_device(false)?;
|
||||
let (end_on_drop_tx, end_on_drop_rx) = std::sync::mpsc::channel::<()>();
|
||||
let mixer = mixer.clone();
|
||||
|
@ -225,7 +224,7 @@ impl AudioStack {
|
|||
end_on_drop_rx.recv().ok();
|
||||
});
|
||||
|
||||
default_change_listener.next().await;
|
||||
device_change_listener.next().await;
|
||||
drop(end_on_drop_tx)
|
||||
}
|
||||
}
|
||||
|
@ -236,8 +235,8 @@ impl AudioStack {
|
|||
sample_rate: u32,
|
||||
num_channels: u32,
|
||||
) -> Result<()> {
|
||||
let mut default_change_listener = DeviceChangeListener::new(true)?;
|
||||
loop {
|
||||
let mut device_change_listener = DeviceChangeListener::new(true)?;
|
||||
let (device, config) = default_device(true)?;
|
||||
let (end_on_drop_tx, end_on_drop_rx) = std::sync::mpsc::channel::<()>();
|
||||
let apm = apm.clone();
|
||||
|
@ -310,7 +309,7 @@ impl AudioStack {
|
|||
.log_err();
|
||||
});
|
||||
|
||||
default_change_listener.next().await;
|
||||
device_change_listener.next().await;
|
||||
drop(end_on_drop_tx)
|
||||
}
|
||||
}
|
||||
|
@ -646,6 +645,7 @@ mod macos {
|
|||
rx: UnboundedReceiver<()>,
|
||||
callback: Box<PropertyListenerCallbackWrapper>,
|
||||
input: bool,
|
||||
device_id: AudioObjectID, // Store the device ID to properly remove listeners
|
||||
}
|
||||
|
||||
trait _AssertSend: Send {}
|
||||
|
@ -672,7 +672,9 @@ mod macos {
|
|||
tx.unbounded_send(()).ok();
|
||||
})));
|
||||
|
||||
unsafe {
|
||||
// Get the current default device ID
|
||||
let device_id = unsafe {
|
||||
// Listen for default device changes
|
||||
coreaudio::Error::from_os_status(AudioObjectAddPropertyListener(
|
||||
kAudioObjectSystemObject,
|
||||
&AudioObjectPropertyAddress {
|
||||
|
@ -687,12 +689,78 @@ mod macos {
|
|||
Some(property_listener_handler_shim),
|
||||
&*callback as *const _ as *mut _,
|
||||
))?;
|
||||
}
|
||||
|
||||
// Also listen for changes to the device configuration
|
||||
let device_id = if input {
|
||||
let mut input_device: AudioObjectID = 0;
|
||||
let mut prop_size = std::mem::size_of::<AudioObjectID>() as u32;
|
||||
let result = coreaudio::sys::AudioObjectGetPropertyData(
|
||||
kAudioObjectSystemObject,
|
||||
&AudioObjectPropertyAddress {
|
||||
mSelector: kAudioHardwarePropertyDefaultInputDevice,
|
||||
mScope: kAudioObjectPropertyScopeGlobal,
|
||||
mElement: kAudioObjectPropertyElementMaster,
|
||||
},
|
||||
0,
|
||||
std::ptr::null(),
|
||||
&mut prop_size as *mut _,
|
||||
&mut input_device as *mut _ as *mut _,
|
||||
);
|
||||
if result != 0 {
|
||||
log::warn!("Failed to get default input device ID");
|
||||
0
|
||||
} else {
|
||||
input_device
|
||||
}
|
||||
} else {
|
||||
let mut output_device: AudioObjectID = 0;
|
||||
let mut prop_size = std::mem::size_of::<AudioObjectID>() as u32;
|
||||
let result = coreaudio::sys::AudioObjectGetPropertyData(
|
||||
kAudioObjectSystemObject,
|
||||
&AudioObjectPropertyAddress {
|
||||
mSelector: kAudioHardwarePropertyDefaultOutputDevice,
|
||||
mScope: kAudioObjectPropertyScopeGlobal,
|
||||
mElement: kAudioObjectPropertyElementMaster,
|
||||
},
|
||||
0,
|
||||
std::ptr::null(),
|
||||
&mut prop_size as *mut _,
|
||||
&mut output_device as *mut _ as *mut _,
|
||||
);
|
||||
if result != 0 {
|
||||
log::warn!("Failed to get default output device ID");
|
||||
0
|
||||
} else {
|
||||
output_device
|
||||
}
|
||||
};
|
||||
|
||||
if device_id != 0 {
|
||||
// Listen for format changes on the device
|
||||
coreaudio::Error::from_os_status(AudioObjectAddPropertyListener(
|
||||
device_id,
|
||||
&AudioObjectPropertyAddress {
|
||||
mSelector: coreaudio::sys::kAudioDevicePropertyStreamFormat,
|
||||
mScope: if input {
|
||||
coreaudio::sys::kAudioObjectPropertyScopeInput
|
||||
} else {
|
||||
coreaudio::sys::kAudioObjectPropertyScopeOutput
|
||||
},
|
||||
mElement: kAudioObjectPropertyElementMaster,
|
||||
},
|
||||
Some(property_listener_handler_shim),
|
||||
&*callback as *const _ as *mut _,
|
||||
))?;
|
||||
}
|
||||
|
||||
device_id
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
rx,
|
||||
callback,
|
||||
input,
|
||||
device_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -700,6 +768,7 @@ mod macos {
|
|||
impl Drop for CoreAudioDefaultDeviceChangeListener {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
// Remove the system-level property listener
|
||||
AudioObjectRemovePropertyListener(
|
||||
kAudioObjectSystemObject,
|
||||
&AudioObjectPropertyAddress {
|
||||
|
@ -714,6 +783,24 @@ mod macos {
|
|||
Some(property_listener_handler_shim),
|
||||
&*self.callback as *const _ as *mut _,
|
||||
);
|
||||
|
||||
// Remove the device-specific property listener if we have a valid device ID
|
||||
if self.device_id != 0 {
|
||||
AudioObjectRemovePropertyListener(
|
||||
self.device_id,
|
||||
&AudioObjectPropertyAddress {
|
||||
mSelector: coreaudio::sys::kAudioDevicePropertyStreamFormat,
|
||||
mScope: if self.input {
|
||||
coreaudio::sys::kAudioObjectPropertyScopeInput
|
||||
} else {
|
||||
coreaudio::sys::kAudioObjectPropertyScopeOutput
|
||||
},
|
||||
mElement: kAudioObjectPropertyElementMaster,
|
||||
},
|
||||
Some(property_listener_handler_shim),
|
||||
&*self.callback as *const _ as *mut _,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue