Add a test that switches the device while a stream is paused, both manual and automated

This commit is contained in:
Paul Adenot 2024-08-08 16:19:30 +02:00
Родитель 8fa685bb63
Коммит bd11e7582d
2 изменённых файлов: 85 добавлений и 0 удалений

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

@ -11,6 +11,7 @@ echo "RUST_BACKTRACE is set to ${RUST_BACKTRACE}\n"
cargo test test_aggregate -- --ignored --nocapture
cargo test test_switch_device -- --ignored --nocapture
cargo test test_switch_while_paused -- --ignored --nocapture
cargo test test_plug_and_unplug_device -- --ignored --nocapture

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

@ -22,6 +22,8 @@ use super::utils::{
};
use super::*;
use std::sync::{LockResult, WaitTimeoutResult};
use std::thread;
use std::time;
// Switch default devices used by the active streams, to test stream reinitialization
// ================================================================================================
@ -73,6 +75,88 @@ fn test_switch_device_in_scope(scope: Scope) {
});
}
#[ignore]
#[test]
fn test_switch_while_paused() {
test_switch_device_in_scope_while_paused(Scope::Input);
test_switch_device_in_scope_while_paused(Scope::Output);
}
fn test_switch_device_in_scope_while_paused(scope: Scope) {
println!(
"Switch default device for {:?} while the stream is paused.",
scope
);
// Do nothing if there is no 2 available devices at least.
let devices = test_get_devices_in_scope(scope.clone());
if devices.len() < 2 {
println!("Need 2 devices for {:?} at least. Skip.", scope);
return;
}
let mut device_switcher = TestDeviceSwitcher::new(scope.clone());
let notifier = Arc::new(Notifier::new(0));
let also_notifier = notifier.clone();
let listener = run_serially(|| {
test_create_device_change_listener(scope.clone(), move |_addresses| {
let mut cnt = notifier.lock().unwrap();
*cnt += 1;
notifier.notify(cnt);
NO_ERR
})
});
run_serially(|| listener.start());
let changed_watcher = Watcher::new(&also_notifier);
test_get_started_stream_in_scope(scope.clone(), move |stream| loop {
// pause the stream, change device, start the stream
// peek under the hood to the find the device in use currently
let stm = unsafe { &mut *(stream as *mut AudioUnitStream) };
let before = if scope == Scope::Output {
stm.core_stream_data.output_unit
} else {
stm.core_stream_data.input_unit
};
// Pause the stream, and change the default device
assert_eq!(unsafe { OPS.stream_stop.unwrap()(stream) }, ffi::CUBEB_OK);
let start_cnt = changed_watcher.lock().unwrap().clone();
device_switcher.next();
let mut guard = changed_watcher.lock().unwrap();
guard = changed_watcher
.wait_while(guard, |cnt| *cnt == start_cnt)
.unwrap();
if *guard >= devices.len() {
break;
}
// Wait until the switch is effective and the stream has been marked for delayed
// reinitialization. delayed_reinit can only be access from the queue thread. Depending on
// the setup this can take some time so we sleep a bit to not hammer the main thread.
let mut switched = false;
while !switched {
switched = stm.queue.run_sync(|| stm.delayed_reinit).unwrap();
if !switched {
let ten_millis = time::Duration::from_millis(10);
thread::sleep(ten_millis);
}
}
// Start the stream, and check that the device in use isn't the same as before pausing
assert_eq!(unsafe { OPS.stream_start.unwrap()(stream) }, ffi::CUBEB_OK);
let after = if scope == Scope::Output {
stm.core_stream_data.output_unit
} else {
stm.core_stream_data.input_unit
};
assert_ne!(before, after);
});
}
fn test_get_started_stream_in_scope<F>(scope: Scope, operation: F)
where
F: FnOnce(*mut ffi::cubeb_stream),