Skip listener-removed assertion if aggregate device is dead (#114)

This patch works around a crash we get in BMO 1658982 [1].

When creating the aggregate device, somehow we will get
`kAudioHardwareBadObjectError` error during `set_sub_devices_sync` step.
This error occurs when removing the device-changed listeners for the
newly created aggregate device. This error implies the aggregate device
is somehow dead. In this case, it's ok to not remove the listener
manually since the listener should receive nothing from a dead device.
We can just return error to indicate the aggregate device isn't
initialized successfully.

We should return the error if sub devices cannot be set. However, this
patch only return the error when timeout of setting the sub devices. The
reason to do so is to investigate when `kAudioHardwareBadObjectError` is
thrown.

[1] https://bugzilla.mozilla.org/show_bug.cgi?id=1658982
This commit is contained in:
Chun-Min Chang 2020-10-14 16:55:56 -07:00 коммит произвёл GitHub
Родитель b4f45e18a4
Коммит faa9c58506
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
1 изменённых файлов: 13 добавлений и 5 удалений

Просмотреть файл

@ -292,15 +292,14 @@ impl AggregateDevice {
return Err(status);
}
let _teardown = finally(|| {
let r = audio_object_remove_property_listener(
let remove_listener = || -> OSStatus {
audio_object_remove_property_listener(
device_id,
&address,
devices_changed_callback,
data_ptr as *mut c_void,
);
assert_eq!(r, NO_ERR);
});
)
};
Self::set_sub_devices(device_id, input_id, output_id)?;
@ -318,6 +317,13 @@ impl AggregateDevice {
);
}
if *dev != device_id {
let r = remove_listener();
// If the error is kAudioHardwareBadObjectError, it implies `device_id` is somehow
// dead, so its listener should receive nothing. It's ok to leave here.
assert!(r == NO_ERR || r == (kAudioHardwareBadObjectError as OSStatus));
// TODO: Destroy the aggregate device immediately if error is not
// kAudioHardwareBadObjectError. Otherwise the `devices_changed_callback` is able
// to touch the `cloned_condvar_pair` after it's freed.
return Err(APPLE_EVENT_TIMEOUT);
}
}
@ -336,6 +342,8 @@ impl AggregateDevice {
NO_ERR
}
let r = remove_listener();
assert_eq!(r, NO_ERR);
Ok(())
}