-
Notifications
You must be signed in to change notification settings - Fork 455
feat: introduce description() for devices #1046
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
13aaf6b to
6c9c6d3
Compare
|
cc: @xephyris - currently the device selection was quite broken and this PR leverages your stable IDs to fix that. I'd like to fix this breakage and agree on how this should work before v0.17 - your perspectives are appreciated! |
|
This seems to be a great idea, however one suggestion I have is if we are doing a A struct for this with potentially more data about things such as device type (Input/Output), channel information, or some other important details as well as the human readable device name seems more fitting of a Another not too significant change is I think we might want to create a new What are your thoughts? |
|
Great idea. As well as address, type (headphones…) for those that support it. It could become a struct with a bunch of |
|
Working on it. Gonna be a big one - anything that stretches across all hosts is. pub struct DeviceDescription {
/// Human-readable device name (always available).
name: String,
/// Device manufacturer or vendor name (macOS, Windows).
manufacturer: Option<String>,
/// Driver name (ALSA, ASIO).
/// Example: ASIO4ALL v2
driver: Option<String>,
/// Categorization of device type (defaults to `Unknown` if not available).
/// Examples: BuiltIn, Usb, Bluetooth, WiredHeadset, ... , Unknown
device_type: DeviceType,
/// Connection/transport type (defaults to `Unknown` if not available).
/// Examples: BuiltIn, Usb, Bluetooth, Pci, FireWire, ... , Unknown
bus_type: BusType,
/// Direction: input, output, or duplex (defaults to `Unknown` if not known).
direction: DeviceDirection,
/// Physical address or connection identifier (Android).
/// Example: 00:1A:7D:DA:71:13
address: Option<String>,
/// Additional description lines with detailed information (ALSA, WASAPI).
///
/// On ALSA, this contains the multi-line description from hints.
/// On WASAPI, this may contain additional device description info.
extended: Vec<String>,
/// Name of the audio interface/adapter (WASAPI).
/// Example: Focusrite USB Audio
interface_name: Option<String>,
/// Container identifier for grouping devices from same hardware (WASAPI).
container_id: Option<String>,
} |
Deprecate DeviceTrait::name in favor of description() for human-readable labels and id() for unique identifiers. Implement description across host backends, update examples to print device IDs, and forward name() to description() where needed. Before this, the name() implementation across hosts was inconsistent. To ease upgrading users, this change keeps the name() behavior as it was in v0.16. Also removes #[inline] pragmas for code outside of the audio hot path.
* Update Display and FromStr implementations to match renamed variants (Wasapi, Asio, Alsa). This is consistent with the naming conventions used in other parts of the codebase. * Remove the IOS variant and change iOS device id to return CoreAudio. Rationale: iOS uses CoreAudio as its underlying audio API, so having a separate IOS variant is redundant and may cause confusion. iOS and macOS should never occur in the same build. * Improve DeviceId parse error message format.
* Replace device description string returns with a DeviceDescription type across hosts and traits. * Add enums for device type, interface, and direction, builder and helper conversion/parsing functions, and re-export the new module from the crate. * Provide a default name() shim that uses description().name() for compatibility.
5518b76 to
df3555a
Compare
|
@xephyris on Discord, @jwagner wrote:
Which I think is an interesting thought. Do you see any reason why we wouldn't flatten it like that? |
d71e32f to
7994df4
Compare
* Expose COMMON_SAMPLE_RATES as pub(crate) and use it in the ALSA backend instead of a private RATES array. * Remove the Windows-only cfg and add a few additional sample rates (12000, 24000, 352800).
5508d06 to
5404e9f
Compare
|
I think there are benefits to both approaches, and I would be willing to make a pull request to change the id system if the general consensus is to have a The main benefits I see from such a method would be greater simplicity for the The main benefit of the current method, would be human readability and also API specific implementations. While it is a bit clunky, I think it being more specific here can help to prevent errors that could arise from incorrect host matching. Also just a question, how would we be able to implement HostId matching if we were to do this implementation? From my limited testing it seems like if I do a |
|
Hey @xephyris, I totally agree that both approaches have their merits. I'm not quite sure what you mean with 'incorrect host matching' and 'HostId matching'? |
|
By host matching I mean when we are trying to determine what API is being used currently or what host type the id belongs to. For example, right now for the match platform {
"wasapi" => Ok(DeviceId::WASAPI(data.to_string())),
"asio" => Ok(DeviceId::ASIO(data.to_string())),
"coreaudio" => Ok(DeviceId::CoreAudio(data.to_string())),
"alsa" => Ok(DeviceId::ALSA(data.to_string())),
"aaudio" => {
let id = data.parse().map_err(|_| DeviceIdError::BackendSpecific {
err: BackendSpecificError {
description: format!("Failed to parse aaudio device id: {}", data),
},
})?;
Ok(DeviceId::AAudio(id))
}
"jack" => Ok(DeviceId::Jack(data.to_string())),
"webaudio" => Ok(DeviceId::WebAudio(data.to_string())),
"emscripten" => Ok(DeviceId::Emscripten(data.to_string())),
"ios" => Ok(DeviceId::IOS(data.to_string())),
"null" => Ok(DeviceId::Null),
&_ => todo!("implement DeviceId::FromStr for {platform}"),
}I'm just unsure about how would such an implementation work with HostId's, as there doesn't seem to be an effective way to match it, as only the device's supported platform APIs seems to show up. HostId also doesn't seem to currenly support What are your thoughts? If there are any misunderstandings that I have, I would be happy to learn more. |
|
I think from_string could then be (HostId::from_string, data). Assuming HostId has from_string, if not it can be added. But maybe I'm also missing distinction between what a Host(Id) and a platform is. I didn't consider the case where you would want to deserialize a DeviceId from an unsupported Host. If that is something we want to support, and we don't want unsupported Hosts to show up in the HostId enum then another enum is required. On a side note I think we might want to turn the into a This would avoid a panic when trying to read a value that came from a newer version, like when an older version of an application reads a state from a newer version. |
Introduces
DeviceTrait::description()and deprecatesDeviceTrait::name()to clarify the distinction between human-readable descriptions and unique device identifiers.Motivation
The current
name()implementation was inconsistent across platforms - sometimes returning unique IDs, sometimes human-readable names, and sometimes a mix of both. In this state, examples don't work as expected when--device foois given on the command line, and neither will user applications that match on device name.For example: on ALSA,
name()calledself.to_string()which combined the PCM ID and description. For a device with PCM ID "hw:0,0" and description "HD Audio",name()returned "hw:0,0 (HD Audio)". When a user passed--device hw:0,0, that string comparison failed.In conclusion, this mixing of PCM ID and description broke device selection.
Solution
This split makes the API clearer: use
description()for displaying to users, andid()for uniquely identifying devices. With this change:id()returns "alsa:hw:0,0" in our ALSA example - just the identifier, no description mixed in.description()returns "HD Audio" - just the human-readable nameDevice selection does expect
alsa:hw:0,0instead of justhw:0,0. Through the power of #1014 that's precisely what we want, because if there are more hosts available on the platform, then we have devices unique to their named scopes.Backwards compatibility
To ease upgrading, v0.16 and earlier users relying on
name()can still use that and will get the same results as they did before. In our ALSA example: just "hw:0,0" without the "alsa:" prefix.