Skip to content

Commit

Permalink
Return both a stream's id and its owning device id from get_device_st…
Browse files Browse the repository at this point in the history
…reams

This could be useful if a caller needs to filter something based on the
owning device's properties, and is not possible to put outside of
get_device_streams since it could get the streams from a sub device, in
case streams were requested on an aggregate device.
  • Loading branch information
Pehrsons committed May 30, 2024
1 parent 652fc24 commit ba91b2b
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 28 deletions.
31 changes: 23 additions & 8 deletions src/backend/device_property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,15 @@ pub fn get_device_latency(
}
}

#[derive(Debug)]
pub struct DeviceStream {
pub device: AudioDeviceID,
pub stream: AudioStreamID,
}
pub fn get_device_streams(
id: AudioDeviceID,
devtype: DeviceType,
) -> std::result::Result<Vec<AudioStreamID>, OSStatus> {
) -> std::result::Result<Vec<DeviceStream>, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();

Expand All @@ -210,12 +215,16 @@ pub fn get_device_streams(
return Err(err);
}

let mut streams: Vec<AudioObjectID> = allocate_array_by_size(size);
let mut streams = vec![AudioObjectID::default(); size / mem::size_of::<AudioObjectID>()];
let err = audio_object_get_property_data(id, &address, &mut size, streams.as_mut_ptr());
if err != NO_ERR {
return Err(err);
}

let mut device_streams = streams
.into_iter()
.map(|stream| DeviceStream { device: id, stream })
.collect::<Vec<_>>();
if devtype.contains(DeviceType::INPUT) {
// With VPIO, output devices will/may get a Tap that appears as an input stream on the
// output device id. It is unclear what kind of Tap this is as it cannot be enumerated
Expand Down Expand Up @@ -251,26 +260,32 @@ pub fn get_device_streams(
}
debug_assert!(devices.contains(&id));
devices.sort();
let next_id = devices.into_iter().skip_while(|&i| i != id).skip(1).next();
let next_id = devices.into_iter().skip_while(|&i| i != id).nth(1);
cubeb_log!(
"Filtering input streams {:?} for device {}. Next device is {:?}.",
streams,
device_streams
.iter()
.map(|ds| ds.stream)
.collect::<Vec<_>>(),
id,
next_id
);
if let Some(next_id) = next_id {
streams.retain(|&s| s > id && s < next_id);
device_streams.retain(|ds| ds.stream > id && ds.stream < next_id);
} else {
streams.retain(|&s| s > id);
device_streams.retain(|ds| ds.stream > id);
}
cubeb_log!(
"Input stream filtering for device {} retained {:?}.",
id,
streams
device_streams
.iter()
.map(|ds| ds.stream)
.collect::<Vec<_>>()
);
}

Ok(streams)
Ok(device_streams)
}

pub fn get_device_sample_rate(
Expand Down
12 changes: 6 additions & 6 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1620,10 +1620,10 @@ fn get_channel_count(
assert_ne!(devid, kAudioObjectUnknown);
debug_assert_running_serially();

let streams = get_device_streams(devid, devtype)?;
let devstreams = get_device_streams(devid, devtype)?;
let mut count = 0;
for stream in streams {
if let Ok(format) = get_stream_virtual_format(stream) {
for ds in devstreams {
if let Ok(format) = get_stream_virtual_format(ds.stream) {
count += format.mChannelsPerFrame;
}
}
Expand Down Expand Up @@ -1670,16 +1670,16 @@ fn get_fixed_latency(devid: AudioObjectID, devtype: DeviceType) -> u32 {
}
};

let stream_latency = get_device_streams(devid, devtype).and_then(|streams| {
if streams.is_empty() {
let stream_latency = get_device_streams(devid, devtype).and_then(|devstreams| {
if devstreams.is_empty() {
cubeb_log!(
"No stream on device {} in {:?} scope!",
devid,
devtype
);
Ok(0) // default stream latency
} else {
get_stream_latency(streams[0])
get_stream_latency(devstreams[0].stream)
}
}).map_err(|e| {
cubeb_log!(
Expand Down
28 changes: 14 additions & 14 deletions src/backend/tests/device_property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,20 +413,20 @@ fn test_get_ranges_of_device_sample_rate_by_unknown_device() {
#[test]
fn test_get_stream_latency() {
if let Some(device) = test_get_default_device(Scope::Input) {
let streams = run_serially(|| get_device_streams(device, DeviceType::INPUT)).unwrap();
for stream in streams {
let latency = run_serially(|| get_stream_latency(stream)).unwrap();
println!("latency of the input stream {} is {}", stream, latency);
let devstreams = run_serially(|| get_device_streams(device, DeviceType::INPUT)).unwrap();
for ds in devstreams {
let latency = run_serially(|| get_stream_latency(ds.stream)).unwrap();
println!("latency of the input stream {} is {}", ds.stream, latency);
}
} else {
println!("No input device.");
}

if let Some(device) = test_get_default_device(Scope::Output) {
let streams = run_serially(|| get_device_streams(device, DeviceType::OUTPUT)).unwrap();
for stream in streams {
let latency = run_serially(|| get_stream_latency(stream)).unwrap();
println!("latency of the output stream {} is {}", stream, latency);
let devstreams = run_serially(|| get_device_streams(device, DeviceType::OUTPUT)).unwrap();
for ds in devstreams {
let latency = run_serially(|| get_stream_latency(ds.stream)).unwrap();
println!("latency of the output stream {} is {}", ds.stream, latency);
}
} else {
println!("No output device.");
Expand All @@ -444,10 +444,10 @@ fn test_get_stream_latency_by_unknown_device() {
#[test]
fn test_get_stream_virtual_format() {
if let Some(device) = test_get_default_device(Scope::Input) {
let streams = run_serially(|| get_device_streams(device, DeviceType::INPUT)).unwrap();
let formats = streams
let devstreams = run_serially(|| get_device_streams(device, DeviceType::INPUT)).unwrap();
let formats = devstreams
.iter()
.map(|s| run_serially(|| get_stream_virtual_format(*s)))
.map(|ds| run_serially(|| get_stream_virtual_format(ds.stream)))
.collect::<Vec<std::result::Result<AudioStreamBasicDescription, OSStatus>>>();
println!("input stream formats: {:?}", formats);
assert!(!formats.is_empty());
Expand All @@ -456,10 +456,10 @@ fn test_get_stream_virtual_format() {
}

if let Some(device) = test_get_default_device(Scope::Output) {
let streams = run_serially(|| get_device_streams(device, DeviceType::OUTPUT)).unwrap();
let formats = streams
let devstreams = run_serially(|| get_device_streams(device, DeviceType::OUTPUT)).unwrap();
let formats = devstreams
.iter()
.map(|s| run_serially(|| get_stream_virtual_format(*s)))
.map(|ds| run_serially(|| get_stream_virtual_format(ds.stream)))
.collect::<Vec<std::result::Result<AudioStreamBasicDescription, OSStatus>>>();
println!("output stream formats: {:?}", formats);
assert!(!formats.is_empty());
Expand Down

0 comments on commit ba91b2b

Please sign in to comment.