summaryrefslogtreecommitdiffstats
path: root/third_party/rust/cubeb-coreaudio/src/backend/tests/manual.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/rust/cubeb-coreaudio/src/backend/tests/manual.rs288
1 files changed, 221 insertions, 67 deletions
diff --git a/third_party/rust/cubeb-coreaudio/src/backend/tests/manual.rs b/third_party/rust/cubeb-coreaudio/src/backend/tests/manual.rs
index b2b2241cc9..3bf96c65c6 100644
--- a/third_party/rust/cubeb-coreaudio/src/backend/tests/manual.rs
+++ b/third_party/rust/cubeb-coreaudio/src/backend/tests/manual.rs
@@ -4,7 +4,6 @@ use super::utils::{
};
use super::*;
use std::io;
-use std::sync::atomic::AtomicBool;
#[ignore]
#[test]
@@ -153,25 +152,84 @@ fn test_device_collection_change() {
let _ = std::io::stdin().read_line(&mut input);
}
+struct StreamData {
+ stream_ptr: *mut ffi::cubeb_stream,
+ enable_loopback: AtomicBool,
+}
+
+impl StreamData {
+ fn new() -> Self {
+ Self {
+ stream_ptr: ptr::null_mut(),
+ enable_loopback: AtomicBool::new(false),
+ }
+ }
+}
+
+struct StreamsData {
+ streams: Vec<StreamData>,
+ current_idx: Option<usize>,
+}
+
+impl StreamsData {
+ fn new() -> Self {
+ Self {
+ streams: Vec::new(),
+ current_idx: None,
+ }
+ }
+
+ fn len(&self) -> usize {
+ self.streams.len()
+ }
+
+ fn current_mut(&mut self) -> &mut StreamData {
+ &mut self.streams[self.current_idx.unwrap()]
+ }
+
+ fn current(&self) -> &StreamData {
+ &self.streams[self.current_idx.unwrap()]
+ }
+
+ fn select(&mut self, idx: usize) {
+ assert!(idx < self.len());
+ self.current_idx = Some(idx);
+ }
+
+ fn push(&mut self, stream: StreamData) {
+ self.streams.push(stream)
+ }
+}
+
#[ignore]
#[test]
fn test_stream_tester() {
test_ops_context_operation("context: stream tester", |context_ptr| {
- let mut stream_ptr: *mut ffi::cubeb_stream = ptr::null_mut();
- let enable_loopback = AtomicBool::new(false);
+ let mut input_prefs = StreamPrefs::NONE;
+ let mut output_prefs = StreamPrefs::NONE;
+ let mut streams = StreamsData::new();
loop {
println!(
- "commands:\n\
+ "Current stream: {} (of {}). Commands:\n\
\t'q': quit\n\
+ \t'b': change current stream\n\
+ \t'i': set input stream prefs to be used for creating streams\n\
+ \t'o': set output stream prefs to be used for creating streams\n\
\t'c': create a stream\n\
- \t'd': destroy a stream\n\
- \t's': start the created stream\n\
- \t't': stop the created stream\n\
+ Commands on the current stream:\n\
+ \t'd': destroy\n\
+ \t's': start\n\
+ \t't': stop\n\
\t'r': register a device changed callback\n\
\t'l': set loopback (DUPLEX-only)\n\
\t'v': set volume\n\
\t'm': set input mute\n\
- \t'p': set input processing"
+ \t'p': set input processing",
+ streams
+ .current_idx
+ .map(|i| format!("{}", i + 1 as usize))
+ .unwrap_or(String::from("N/A")),
+ streams.len(),
);
let mut command = String::new();
@@ -181,66 +239,130 @@ fn test_stream_tester() {
match command.as_str() {
"q" => {
println!("Quit.");
- destroy_stream(&mut stream_ptr);
+ for mut stream in streams.streams {
+ if !stream.stream_ptr.is_null() {
+ destroy_stream(&mut stream);
+ }
+ }
break;
}
- "c" => create_stream(&mut stream_ptr, context_ptr, &enable_loopback),
- "d" => destroy_stream(&mut stream_ptr),
- "s" => start_stream(stream_ptr),
- "t" => stop_stream(stream_ptr),
- "r" => register_device_change_callback(stream_ptr),
- "l" => set_loopback(stream_ptr, &enable_loopback),
- "v" => set_volume(stream_ptr),
- "m" => set_input_mute(stream_ptr),
- "p" => set_input_processing(stream_ptr),
- x => println!("Unknown command: {}", x),
+ "i" => set_prefs(&mut input_prefs),
+ "o" => set_prefs(&mut output_prefs),
+ "c" => create_stream(context_ptr, &mut streams, input_prefs, output_prefs),
+ _ if streams.current_idx.is_none() => {
+ println!("There are no streams! Create a stream first.")
+ }
+ cmd => match cmd {
+ "b" => select_stream(&mut streams),
+ "d" => destroy_stream(streams.current_mut()),
+ "s" => start_stream(streams.current()),
+ "t" => stop_stream(streams.current()),
+ "r" => register_device_change_callback(streams.current()),
+ "l" => set_loopback(streams.current()),
+ "v" => set_volume(streams.current()),
+ "m" => set_input_mute(streams.current()),
+ "p" => set_input_processing(streams.current()),
+ x => println!("Unknown command: {}", x),
+ },
}
}
});
- fn start_stream(stream_ptr: *mut ffi::cubeb_stream) {
- if stream_ptr.is_null() {
+ fn set_prefs(prefs: &mut StreamPrefs) {
+ let mut done = false;
+ while !done {
+ println!(
+ "Current prefs: {:?}\nSelect action:\n\
+ \t1) Set None\n\
+ \t2) Toggle Loopback\n\
+ \t3) Toggle Disable Device Switching\n\
+ \t4) Toggle Voice\n\
+ \t5) Set All\n\
+ \t0) Done",
+ prefs
+ );
+ let mut input = String::new();
+ let _ = io::stdin().read_line(&mut input);
+ assert_eq!(input.pop().unwrap(), '\n');
+ match input.as_str() {
+ "1" => *prefs = StreamPrefs::NONE,
+ "2" => prefs.toggle(StreamPrefs::LOOPBACK),
+ "3" => prefs.toggle(StreamPrefs::DISABLE_DEVICE_SWITCHING),
+ "4" => prefs.toggle(StreamPrefs::VOICE),
+ "5" => *prefs = StreamPrefs::all(),
+ "0" => done = true,
+ _ => println!("Invalid action. Select again.\n"),
+ }
+ }
+ }
+
+ fn select_stream(streams: &mut StreamsData) {
+ let num_streams = streams.len();
+ let current_idx = streams.current_idx.unwrap();
+ println!(
+ "Current stream is {}. Select stream 1 to {} on which to apply commands:",
+ current_idx + 1 as usize,
+ num_streams
+ );
+ let mut selection: Option<usize> = None;
+ while selection.is_none() {
+ let mut input = String::new();
+ let _ = io::stdin().read_line(&mut input);
+ assert_eq!(input.pop().unwrap(), '\n');
+ selection = match input.parse::<usize>() {
+ Ok(i) if (1..=num_streams).contains((&i).into()) => Some(i),
+ _ => {
+ println!("Invalid stream. Select again.\n");
+ None
+ }
+ }
+ }
+ streams.select(selection.unwrap() - 1)
+ }
+
+ fn start_stream(stream: &StreamData) {
+ if stream.stream_ptr.is_null() {
println!("No stream can start.");
return;
}
assert_eq!(
- unsafe { OPS.stream_start.unwrap()(stream_ptr) },
+ unsafe { OPS.stream_start.unwrap()(stream.stream_ptr) },
ffi::CUBEB_OK
);
- println!("Stream {:p} started.", stream_ptr);
+ println!("Stream {:p} started.", stream.stream_ptr);
}
- fn stop_stream(stream_ptr: *mut ffi::cubeb_stream) {
- if stream_ptr.is_null() {
+ fn stop_stream(stream: &StreamData) {
+ if stream.stream_ptr.is_null() {
println!("No stream can stop.");
return;
}
assert_eq!(
- unsafe { OPS.stream_stop.unwrap()(stream_ptr) },
+ unsafe { OPS.stream_stop.unwrap()(stream.stream_ptr) },
ffi::CUBEB_OK
);
- println!("Stream {:p} stopped.", stream_ptr);
+ println!("Stream {:p} stopped.", stream.stream_ptr);
}
- fn set_volume(stream_ptr: *mut ffi::cubeb_stream) {
- if stream_ptr.is_null() {
+ fn set_volume(stream: &StreamData) {
+ if stream.stream_ptr.is_null() {
println!("No stream can set volume.");
return;
}
const VOL: f32 = 0.5;
assert_eq!(
- unsafe { OPS.stream_set_volume.unwrap()(stream_ptr, VOL) },
+ unsafe { OPS.stream_set_volume.unwrap()(stream.stream_ptr, VOL) },
ffi::CUBEB_OK
);
- println!("Set stream {:p} volume to {}", stream_ptr, VOL);
+ println!("Set stream {:p} volume to {}", stream.stream_ptr, VOL);
}
- fn set_loopback(stream_ptr: *mut ffi::cubeb_stream, enable_loopback: &AtomicBool) {
- if stream_ptr.is_null() {
+ fn set_loopback(stream: &StreamData) {
+ if stream.stream_ptr.is_null() {
println!("No stream can set loopback.");
return;
}
- let stm = unsafe { &mut *(stream_ptr as *mut AudioUnitStream) };
+ let stm = unsafe { &mut *(stream.stream_ptr as *mut AudioUnitStream) };
if !stm.core_stream_data.has_input() || !stm.core_stream_data.has_output() {
println!("Duplex stream needed to set loopback");
return;
@@ -261,20 +383,20 @@ fn test_stream_tester() {
}
}
let loopback = loopback.unwrap();
- enable_loopback.store(loopback, Ordering::SeqCst);
+ stream.enable_loopback.store(loopback, Ordering::SeqCst);
println!(
"Loopback {} for stream {:p}",
if loopback { "enabled" } else { "disabled" },
- stream_ptr
+ stream.stream_ptr
);
}
- fn set_input_mute(stream_ptr: *mut ffi::cubeb_stream) {
- if stream_ptr.is_null() {
+ fn set_input_mute(stream: &StreamData) {
+ if stream.stream_ptr.is_null() {
println!("No stream can set input mute.");
return;
}
- let stm = unsafe { &mut *(stream_ptr as *mut AudioUnitStream) };
+ let stm = unsafe { &mut *(stream.stream_ptr as *mut AudioUnitStream) };
if !stm.core_stream_data.has_input() {
println!("Input stream needed to set loopback");
return;
@@ -295,7 +417,7 @@ fn test_stream_tester() {
}
}
let mute = mute.unwrap();
- let res = unsafe { OPS.stream_set_input_mute.unwrap()(stream_ptr, mute.into()) };
+ let res = unsafe { OPS.stream_set_input_mute.unwrap()(stream.stream_ptr, mute.into()) };
println!(
"{} set stream {:p} input {}",
if res == ffi::CUBEB_OK {
@@ -303,17 +425,17 @@ fn test_stream_tester() {
} else {
"Failed to"
},
- stream_ptr,
+ stream.stream_ptr,
if mute { "mute" } else { "unmute" }
);
}
- fn set_input_processing(stream_ptr: *mut ffi::cubeb_stream) {
- if stream_ptr.is_null() {
+ fn set_input_processing(stream: &StreamData) {
+ if stream.stream_ptr.is_null() {
println!("No stream can set input processing.");
return;
}
- let stm = unsafe { &mut *(stream_ptr as *mut AudioUnitStream) };
+ let stm = unsafe { &mut *(stream.stream_ptr as *mut AudioUnitStream) };
if !stm.core_stream_data.using_voice_processing_unit() {
println!("Duplex stream with voice processing needed to set input processing params");
return;
@@ -338,6 +460,23 @@ fn test_stream_tester() {
params.set(InputProcessingParams::ECHO_CANCELLATION, true);
params.set(InputProcessingParams::NOISE_SUPPRESSION, true);
}
+ let mut agc = u32::from(false);
+ let mut size: usize = mem::size_of::<u32>();
+ assert_eq!(
+ audio_unit_get_property(
+ stm.core_stream_data.input_unit,
+ kAUVoiceIOProperty_VoiceProcessingEnableAGC,
+ kAudioUnitScope_Global,
+ AU_IN_BUS,
+ &mut agc,
+ &mut size,
+ ),
+ NO_ERR
+ );
+ assert_eq!(size, mem::size_of::<u32>());
+ if agc == 1 {
+ params.set(InputProcessingParams::AUTOMATIC_GAIN_CONTROL, true);
+ }
}
let mut done = false;
while !done {
@@ -367,8 +506,9 @@ fn test_stream_tester() {
_ => println!("Invalid action. Select again.\n"),
}
}
- let res =
- unsafe { OPS.stream_set_input_processing_params.unwrap()(stream_ptr, params.bits()) };
+ let res = unsafe {
+ OPS.stream_set_input_processing_params.unwrap()(stream.stream_ptr, params.bits())
+ };
println!(
"{} set stream {:p} input processing params to {:?}",
if res == ffi::CUBEB_OK {
@@ -376,48 +516,62 @@ fn test_stream_tester() {
} else {
"Failed to"
},
- stream_ptr,
+ stream.stream_ptr,
params,
);
}
- fn register_device_change_callback(stream_ptr: *mut ffi::cubeb_stream) {
+ fn register_device_change_callback(stream: &StreamData) {
extern "C" fn callback(user_ptr: *mut c_void) {
println!("user pointer @ {:p}", user_ptr);
assert!(user_ptr.is_null());
}
- if stream_ptr.is_null() {
+ if stream.stream_ptr.is_null() {
println!("No stream for registering the callback.");
return;
}
assert_eq!(
unsafe {
- OPS.stream_register_device_changed_callback.unwrap()(stream_ptr, Some(callback))
+ OPS.stream_register_device_changed_callback.unwrap()(
+ stream.stream_ptr,
+ Some(callback),
+ )
},
ffi::CUBEB_OK
);
- println!("Stream {:p} now has a device change callback.", stream_ptr);
+ println!(
+ "Stream {:p} now has a device change callback.",
+ stream.stream_ptr
+ );
}
- fn destroy_stream(stream_ptr: &mut *mut ffi::cubeb_stream) {
- if stream_ptr.is_null() {
+ fn destroy_stream(stream: &mut StreamData) {
+ if stream.stream_ptr.is_null() {
println!("No need to destroy stream.");
return;
}
unsafe {
- OPS.stream_destroy.unwrap()(*stream_ptr);
+ OPS.stream_destroy.unwrap()((*stream).stream_ptr);
}
- println!("Stream {:p} destroyed.", *stream_ptr);
- *stream_ptr = ptr::null_mut();
+ println!("Stream {:p} destroyed.", stream.stream_ptr);
+ stream.stream_ptr = ptr::null_mut();
}
fn create_stream(
- stream_ptr: &mut *mut ffi::cubeb_stream,
context_ptr: *mut ffi::cubeb,
- enable_loopback: &AtomicBool,
+ streams: &mut StreamsData,
+ input_prefs: StreamPrefs,
+ output_prefs: StreamPrefs,
) {
- if !stream_ptr.is_null() {
+ if streams.len() == 0 || !streams.current().stream_ptr.is_null() {
+ println!("Allocating stream {}.", streams.len() + 1);
+ streams.push(StreamData::new());
+ streams.select(streams.len() - 1);
+ }
+
+ let stream = streams.current_mut();
+ if !stream.stream_ptr.is_null() {
println!("Stream has been created.");
return;
}
@@ -486,8 +640,8 @@ fn test_stream_tester() {
}
};
- let mut input_params = get_dummy_stream_params(Scope::Input);
- let mut output_params = get_dummy_stream_params(Scope::Output);
+ let mut input_params = get_dummy_stream_params(Scope::Input, input_prefs);
+ let mut output_params = get_dummy_stream_params(Scope::Output, output_prefs);
let (input_device, input_stream_params) = if stream_type.contains(StreamType::INPUT) {
(
@@ -519,7 +673,7 @@ fn test_stream_tester() {
unsafe {
OPS.stream_init.unwrap()(
context_ptr,
- stream_ptr,
+ &mut stream.stream_ptr,
stream_name.as_ptr(),
input_device as ffi::cubeb_devid,
input_stream_params,
@@ -528,13 +682,13 @@ fn test_stream_tester() {
4096, // latency
Some(data_callback),
Some(state_callback),
- enable_loopback as *const AtomicBool as *mut c_void, // user pointer
+ &stream.enable_loopback as *const AtomicBool as *mut c_void, // user pointer
)
},
ffi::CUBEB_OK
);
- assert!(!stream_ptr.is_null());
- println!("Stream {:p} created.", *stream_ptr);
+ assert!(!stream.stream_ptr.is_null());
+ println!("Stream {:p} created.", stream.stream_ptr);
extern "C" fn state_callback(
stream: *mut ffi::cubeb_stream,
@@ -592,14 +746,14 @@ fn test_stream_tester() {
nframes
}
- fn get_dummy_stream_params(scope: Scope) -> ffi::cubeb_stream_params {
+ fn get_dummy_stream_params(scope: Scope, prefs: StreamPrefs) -> ffi::cubeb_stream_params {
// The stream format for input and output must be same.
const STREAM_FORMAT: u32 = ffi::CUBEB_SAMPLE_FLOAT32NE;
// Make sure the parameters meet the requirements of AudioUnitContext::stream_init
// (in the comments).
let mut stream_params = ffi::cubeb_stream_params::default();
- stream_params.prefs = ffi::CUBEB_STREAM_PREF_VOICE;
+ stream_params.prefs = prefs.bits();
let (format, rate, channels, layout) = match scope {
Scope::Input => (STREAM_FORMAT, 48000, 1, ffi::CUBEB_LAYOUT_MONO),
Scope::Output => (STREAM_FORMAT, 44100, 2, ffi::CUBEB_LAYOUT_STEREO),