Skip to content

Commit f07c88e

Browse files
committed
Add a test that switches the device while a stream is paused, both manual and automated
1 parent 0210d62 commit f07c88e

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

run_device_tests.sh

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ echo "RUST_BACKTRACE is set to ${RUST_BACKTRACE}\n"
1111
cargo test test_aggregate -- --ignored --nocapture
1212

1313
cargo test test_switch_device -- --ignored --nocapture
14+
cargo test test_switch_device_while_paused -- --ignored --nocapture
1415

1516
cargo test test_plug_and_unplug_device -- --ignored --nocapture
1617

src/backend/tests/device_change.rs

+84
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ use super::utils::{
2222
};
2323
use super::*;
2424
use std::sync::{LockResult, WaitTimeoutResult};
25+
use std::thread;
26+
use std::time;
2527

2628
// Switch default devices used by the active streams, to test stream reinitialization
2729
// ================================================================================================
@@ -73,6 +75,88 @@ fn test_switch_device_in_scope(scope: Scope) {
7375
});
7476
}
7577

78+
#[ignore]
79+
#[test]
80+
fn test_switch_device_while_paused() {
81+
test_switch_device_in_scope_while_paused(Scope::Input);
82+
test_switch_device_in_scope_while_paused(Scope::Output);
83+
}
84+
85+
fn test_switch_device_in_scope_while_paused(scope: Scope) {
86+
println!(
87+
"Switch default device for {:?} while the stream is paused.",
88+
scope
89+
);
90+
91+
// Do nothing if there is no 2 available devices at least.
92+
let devices = test_get_devices_in_scope(scope.clone());
93+
if devices.len() < 2 {
94+
println!("Need 2 devices for {:?} at least. Skip.", scope);
95+
return;
96+
}
97+
98+
let mut device_switcher = TestDeviceSwitcher::new(scope.clone());
99+
100+
let notifier = Arc::new(Notifier::new(0));
101+
let also_notifier = notifier.clone();
102+
let listener = run_serially(|| {
103+
test_create_device_change_listener(scope.clone(), move |_addresses| {
104+
let mut cnt = notifier.lock().unwrap();
105+
*cnt += 1;
106+
notifier.notify(cnt);
107+
NO_ERR
108+
})
109+
});
110+
run_serially(|| listener.start());
111+
112+
let changed_watcher = Watcher::new(&also_notifier);
113+
test_get_started_stream_in_scope(scope.clone(), move |stream| loop {
114+
// pause the stream, change device, start the stream
115+
// peek under the hood to the find the device in use currently
116+
let stm = unsafe { &mut *(stream as *mut AudioUnitStream) };
117+
let before = if scope == Scope::Output {
118+
stm.core_stream_data.output_unit
119+
} else {
120+
stm.core_stream_data.input_unit
121+
};
122+
123+
// Pause the stream, and change the default device
124+
assert_eq!(unsafe { OPS.stream_stop.unwrap()(stream) }, ffi::CUBEB_OK);
125+
126+
let start_cnt = changed_watcher.lock().unwrap().clone();
127+
device_switcher.next();
128+
let mut guard = changed_watcher.lock().unwrap();
129+
guard = changed_watcher
130+
.wait_while(guard, |cnt| *cnt == start_cnt)
131+
.unwrap();
132+
if *guard >= devices.len() {
133+
break;
134+
}
135+
136+
// Wait until the switch is effective and the stream has been marked for delayed
137+
// reinitialization. delayed_reinit can only be access from the queue thread. Depending on
138+
// the setup this can take some time so we sleep a bit to not hammer the main thread.
139+
let mut switched = false;
140+
while !switched {
141+
switched = stm.queue.run_sync(|| stm.delayed_reinit).unwrap();
142+
if !switched {
143+
let ten_millis = time::Duration::from_millis(10);
144+
thread::sleep(ten_millis);
145+
}
146+
}
147+
148+
// Start the stream, and check that the device in use isn't the same as before pausing
149+
assert_eq!(unsafe { OPS.stream_start.unwrap()(stream) }, ffi::CUBEB_OK);
150+
151+
let after = if scope == Scope::Output {
152+
stm.core_stream_data.output_unit
153+
} else {
154+
stm.core_stream_data.input_unit
155+
};
156+
assert_ne!(before, after);
157+
});
158+
}
159+
76160
fn test_get_started_stream_in_scope<F>(scope: Scope, operation: F)
77161
where
78162
F: FnOnce(*mut ffi::cubeb_stream),

0 commit comments

Comments
 (0)