Add new `DeviceNameError` type
The coreaudio and wasapi backends may both potentially fail to produce the name associated with a device. This changes the API to allow for returning the errors in these cases.
This commit is contained in:
parent
78a7cb9e79
commit
105086a108
|
@ -7,6 +7,7 @@ use ChannelCount;
|
|||
use BackendSpecificError;
|
||||
use BuildStreamError;
|
||||
use DefaultFormatError;
|
||||
use DeviceNameError;
|
||||
use Format;
|
||||
use SupportedFormatsError;
|
||||
use SampleFormat;
|
||||
|
@ -74,8 +75,8 @@ pub struct Device(String);
|
|||
|
||||
impl Device {
|
||||
#[inline]
|
||||
pub fn name(&self) -> String {
|
||||
self.0.clone()
|
||||
pub fn name(&self) -> Result<String, DeviceNameError> {
|
||||
Ok(self.0.clone())
|
||||
}
|
||||
|
||||
unsafe fn supported_formats(
|
||||
|
|
|
@ -5,6 +5,7 @@ use ChannelCount;
|
|||
use BackendSpecificError;
|
||||
use BuildStreamError;
|
||||
use DefaultFormatError;
|
||||
use DeviceNameError;
|
||||
use Format;
|
||||
use SupportedFormatsError;
|
||||
use Sample;
|
||||
|
@ -76,7 +77,7 @@ pub struct Device {
|
|||
}
|
||||
|
||||
impl Device {
|
||||
pub fn name(&self) -> String {
|
||||
pub fn name(&self) -> Result<String, DeviceNameError> {
|
||||
let property_address = AudioObjectPropertyAddress {
|
||||
mSelector: kAudioDevicePropertyDeviceNameCFString,
|
||||
mScope: kAudioDevicePropertyScopeOutput,
|
||||
|
@ -93,16 +94,17 @@ impl Device {
|
|||
&data_size as *const _ as *mut _,
|
||||
&device_name as *const _ as *mut _,
|
||||
);
|
||||
if status != kAudioHardwareNoError as i32 {
|
||||
return format!("<OSStatus: {:?}>", status);
|
||||
}
|
||||
check_os_status(status)?;
|
||||
|
||||
let c_string: *const c_char = CFStringGetCStringPtr(device_name, kCFStringEncodingUTF8);
|
||||
if c_string == null() {
|
||||
return "<null>".into();
|
||||
let description = "core foundation unexpectedly returned null string".to_string();
|
||||
let err = BackendSpecificError { description };
|
||||
return Err(err.into());
|
||||
}
|
||||
CStr::from_ptr(c_string as *mut _)
|
||||
};
|
||||
c_str.to_string_lossy().into_owned()
|
||||
Ok(c_str.to_string_lossy().into_owned())
|
||||
}
|
||||
|
||||
// Logic re-used between `supported_input_formats` and `supported_output_formats`.
|
||||
|
|
|
@ -10,6 +10,7 @@ use stdweb::web::set_timeout;
|
|||
|
||||
use BuildStreamError;
|
||||
use DefaultFormatError;
|
||||
use DeviceNameError;
|
||||
use DevicesError;
|
||||
use Format;
|
||||
use SupportedFormatsError;
|
||||
|
@ -229,8 +230,8 @@ pub struct Device;
|
|||
|
||||
impl Device {
|
||||
#[inline]
|
||||
pub fn name(&self) -> String {
|
||||
"Default Device".to_owned()
|
||||
pub fn name(&self) -> Result<String, DeviceNameError> {
|
||||
Ok("Default Device".to_owned())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
19
src/lib.rs
19
src/lib.rs
|
@ -308,6 +308,17 @@ pub enum DevicesError {
|
|||
}
|
||||
}
|
||||
|
||||
/// An error that may occur while attempting to retrieve a device name.
|
||||
#[derive(Debug, Fail)]
|
||||
pub enum DeviceNameError {
|
||||
/// See the `BackendSpecificError` docs for more information about this error variant.
|
||||
#[fail(display = "{}", err)]
|
||||
BackendSpecific {
|
||||
#[fail(cause)]
|
||||
err: BackendSpecificError,
|
||||
}
|
||||
}
|
||||
|
||||
/// Error that can happen when enumerating the list of supported formats.
|
||||
#[derive(Debug, Fail)]
|
||||
pub enum SupportedFormatsError {
|
||||
|
@ -410,7 +421,7 @@ pub fn default_output_device() -> Option<Device> {
|
|||
impl Device {
|
||||
/// The human-readable name of the device.
|
||||
#[inline]
|
||||
pub fn name(&self) -> String {
|
||||
pub fn name(&self) -> Result<String, DeviceNameError> {
|
||||
self.0.name()
|
||||
}
|
||||
|
||||
|
@ -742,6 +753,12 @@ impl From<BackendSpecificError> for DevicesError {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<BackendSpecificError> for DeviceNameError {
|
||||
fn from(err: BackendSpecificError) -> Self {
|
||||
DeviceNameError::BackendSpecific { err }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BackendSpecificError> for SupportedFormatsError {
|
||||
fn from(err: BackendSpecificError) -> Self {
|
||||
SupportedFormatsError::BackendSpecific { err }
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::marker::PhantomData;
|
|||
use BuildStreamError;
|
||||
use DefaultFormatError;
|
||||
use DevicesError;
|
||||
use DeviceNameError;
|
||||
use Format;
|
||||
use SupportedFormatsError;
|
||||
use StreamData;
|
||||
|
@ -107,8 +108,8 @@ impl Device {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn name(&self) -> String {
|
||||
"null".to_owned()
|
||||
pub fn name(&self) -> Result<String, DeviceNameError> {
|
||||
Ok("null".to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ use std::sync::{Arc, Mutex, MutexGuard};
|
|||
|
||||
use BackendSpecificError;
|
||||
use DefaultFormatError;
|
||||
use DeviceNameError;
|
||||
use DevicesError;
|
||||
use Format;
|
||||
use SupportedFormatsError;
|
||||
|
@ -297,7 +298,7 @@ unsafe impl Sync for Device {
|
|||
}
|
||||
|
||||
impl Device {
|
||||
pub fn name(&self) -> String {
|
||||
pub fn name(&self) -> Result<String, DeviceNameError> {
|
||||
unsafe {
|
||||
// Open the device's property store.
|
||||
let mut property_store = ptr::null_mut();
|
||||
|
@ -305,15 +306,24 @@ impl Device {
|
|||
|
||||
// Get the endpoint's friendly-name property.
|
||||
let mut property_value = mem::zeroed();
|
||||
check_result(
|
||||
if let Err(err) = check_result(
|
||||
(*property_store).GetValue(
|
||||
&devpkey::DEVPKEY_Device_FriendlyName as *const _ as *const _,
|
||||
&mut property_value
|
||||
)
|
||||
).expect("failed to get friendly-name from property store");
|
||||
) {
|
||||
let description = format!("failed to retrieve name from property store: {}", err);
|
||||
let err = BackendSpecificError { description };
|
||||
return Err(err.into());
|
||||
}
|
||||
|
||||
// Read the friendly-name from the union data field, expecting a *const u16.
|
||||
assert_eq!(property_value.vt, wtypes::VT_LPWSTR as _);
|
||||
if property_value.vt != wtypes::VT_LPWSTR as _ {
|
||||
let description =
|
||||
format!("property store produced invalid data: {:?}", property_value.vt);
|
||||
let err = BackendSpecificError { description };
|
||||
return Err(err.into());
|
||||
}
|
||||
let ptr_usize: usize = *(&property_value.data as *const _ as *const usize);
|
||||
let ptr_utf16 = ptr_usize as *const u16;
|
||||
|
||||
|
@ -326,12 +336,15 @@ impl Device {
|
|||
// Create the utf16 slice and covert it into a string.
|
||||
let name_slice = slice::from_raw_parts(ptr_utf16, len as usize);
|
||||
let name_os_string: OsString = OsStringExt::from_wide(name_slice);
|
||||
let name_string = name_os_string.into_string().unwrap();
|
||||
let name_string = match name_os_string.into_string() {
|
||||
Ok(string) => string,
|
||||
Err(os_string) => os_string.to_string_lossy().into(),
|
||||
};
|
||||
|
||||
// Clean up the property.
|
||||
PropVariantClear(&mut property_value);
|
||||
|
||||
name_string
|
||||
Ok(name_string)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue