use wasapi::*;
fn expect_no_devices() -> bool {
std::env::var_os("WASAPI_EXPECT_NO_DEVICES").is_some()
}
#[test]
fn enumerator_works_without_any_device() {
initialize_mta().ok().unwrap();
let enumerator = DeviceEnumerator::new().expect("DeviceEnumerator::new failed");
for direction in [Direction::Render, Direction::Capture] {
let collection = enumerator
.get_device_collection(&direction)
.expect("get_device_collection failed");
let count = collection
.get_nbr_devices()
.expect("get_nbr_devices failed");
let default = enumerator.get_default_device(&direction);
match &default {
Ok(device) => println!(
"{direction}: {count} devices, default: {}",
device.get_friendlyname().unwrap_or_default()
),
Err(e) => println!("{direction}: {count} devices, no default device: {e}"),
}
if expect_no_devices() {
assert_eq!(count, 0, "{direction} devices on a runner with none");
assert!(
default.is_err(),
"a default {direction} device appeared on a runner with none"
);
assert_eq!((&collection).into_iter().count(), 0);
assert!(collection.get_device_at_index(0).is_err());
}
}
}
#[test]
fn channel_masks_are_consistent() {
for channels in 1..=18 {
let masks = make_channelmasks(channels);
assert_eq!(
masks.last(),
Some(&0),
"the {channels} channel list does not end with the zero mask: {masks:x?}"
);
for mask in &masks[..masks.len() - 1] {
assert_ne!(
*mask, 0,
"a zero mask before the end for {channels} channels"
);
assert_eq!(
mask.count_ones() as usize,
channels,
"mask {mask:#x} for {channels} channels has {} positions",
mask.count_ones()
);
}
assert_eq!(make_simple_channelmask(channels), (1 << channels) - 1);
}
for channels in 19..=32 {
assert_eq!(make_channelmasks(channels), vec![0]);
assert_eq!(make_simple_channelmask(channels), 0);
}
}
#[test]
fn period_arithmetic_round_trips() {
for rate in [44100, 48000, 88200, 96000, 192000] {
let mut previous = 0;
for frames in [1, 16, 128, 441, 480, 1024, 4096, 44100] {
let period = calculate_period_100ns(frames, rate);
assert!(period > previous, "{period} is not above {previous}");
previous = period;
let back = (period as f64 * rate as f64 / 10_000_000.0).round() as i64;
assert!(
(back - frames).abs() <= 1,
"{frames} frames at {rate} Hz became {period} units and back to {back}"
);
}
}
}
#[test]
fn buffer_flags_round_trip() {
let none = BufferFlags::none();
assert!(!none.data_discontinuity && !none.silent && !none.timestamp_error);
assert_eq!(none.to_u32(), 0);
let discontinuity = BufferFlags::new(0x1);
assert!(discontinuity.data_discontinuity && !discontinuity.silent);
let silent = BufferFlags::new(0x2);
assert!(silent.silent && !silent.data_discontinuity && !silent.timestamp_error);
let timestamp = BufferFlags::new(0x4);
assert!(timestamp.timestamp_error && !timestamp.silent);
for mask in 0..8u32 {
let flags = BufferFlags::new(mask);
assert_eq!(
flags.to_u32(),
mask,
"{mask:#x} came back as {:#x}",
flags.to_u32()
);
}
assert_eq!(BufferFlags::new(0x8).to_u32(), 0);
}
#[test]
fn hardware_support_bits() {
let none = HardwareSupport::new(0);
assert!(!none.volume && !none.mute && !none.meter);
let volume = HardwareSupport::new(0x1);
assert!(volume.volume && !volume.mute && !volume.meter);
let mute = HardwareSupport::new(0x2);
assert!(!mute.volume && mute.mute && !mute.meter);
let meter = HardwareSupport::new(0x4);
assert!(!meter.volume && !meter.mute && meter.meter);
let all = HardwareSupport::new(0x7);
assert!(all.volume && all.mute && all.meter);
}
#[test]
fn client_properties_accumulate_options() {
let raw = AudioClientProperties::new().set_option(StreamOption::Raw);
let both = AudioClientProperties::new()
.set_option(StreamOption::Raw)
.set_option(StreamOption::MatchFormat);
let twice = AudioClientProperties::new()
.set_option(StreamOption::Raw)
.set_option(StreamOption::Raw);
assert_ne!(
format!("{raw:?}"),
format!("{both:?}"),
"a second option did not change the properties"
);
assert_eq!(
format!("{raw:?}"),
format!("{twice:?}"),
"setting the same option twice changed the result"
);
}