1use std::fmt;
8
9use crate::ChannelCount;
10
11#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct DeviceDescription {
17 name: String,
19
20 manufacturer: Option<String>,
22
23 driver: Option<String>,
25
26 device_type: DeviceType,
28
29 interface_type: InterfaceType,
31
32 direction: DeviceDirection,
34
35 address: Option<String>,
37
38 extended: Vec<String>,
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
47#[non_exhaustive]
48pub enum DeviceType {
49 Speaker,
51
52 Microphone,
54
55 Headphones,
57
58 Headset,
60
61 Earpiece,
63
64 Handset,
66
67 HearingAid,
69
70 Dock,
72
73 Tuner,
75
76 Virtual,
78
79 #[default]
81 Unknown,
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
89#[non_exhaustive]
90pub enum InterfaceType {
91 BuiltIn,
93
94 Usb,
96
97 Bluetooth,
99
100 Pci,
102
103 FireWire,
105
106 Thunderbolt,
108
109 Hdmi,
111
112 Line,
114
115 Spdif,
117
118 Network,
120
121 Virtual,
123
124 DisplayPort,
126
127 Aggregate,
129
130 #[default]
132 Unknown,
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
137#[non_exhaustive]
138pub enum DeviceDirection {
139 Input,
141
142 Output,
144
145 Duplex,
147
148 #[default]
150 Unknown,
151}
152
153impl DeviceDescription {
154 pub fn name(&self) -> &str {
158 &self.name
159 }
160
161 pub fn manufacturer(&self) -> Option<&str> {
163 self.manufacturer.as_deref()
164 }
165
166 pub fn driver(&self) -> Option<&str> {
168 self.driver.as_deref()
169 }
170
171 pub fn device_type(&self) -> DeviceType {
173 self.device_type
174 }
175
176 pub fn interface_type(&self) -> InterfaceType {
178 self.interface_type
179 }
180
181 pub fn direction(&self) -> DeviceDirection {
183 self.direction
184 }
185
186 pub fn supports_input(&self) -> bool {
190 matches!(
191 self.direction,
192 DeviceDirection::Input | DeviceDirection::Duplex
193 )
194 }
195
196 pub fn supports_output(&self) -> bool {
200 matches!(
201 self.direction,
202 DeviceDirection::Output | DeviceDirection::Duplex
203 )
204 }
205
206 pub fn address(&self) -> Option<&str> {
208 self.address.as_deref()
209 }
210
211 pub fn extended(&self) -> &[String] {
213 &self.extended
214 }
215}
216
217impl fmt::Display for DeviceDescription {
218 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219 write!(f, "{}", self.name)?;
220
221 if let Some(mfr) = &self.manufacturer {
222 write!(f, " ({})", mfr)?;
223 }
224
225 if self.device_type != DeviceType::Unknown {
226 write!(f, " [{}]", self.device_type)?;
227 }
228
229 if self.interface_type != InterfaceType::Unknown {
230 write!(f, " via {}", self.interface_type)?;
231 }
232
233 Ok(())
234 }
235}
236
237impl fmt::Display for DeviceType {
238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239 match self {
240 DeviceType::Speaker => write!(f, "Speaker"),
241 DeviceType::Microphone => write!(f, "Microphone"),
242 DeviceType::Headphones => write!(f, "Headphones"),
243 DeviceType::Headset => write!(f, "Headset"),
244 DeviceType::Earpiece => write!(f, "Earpiece"),
245 DeviceType::Handset => write!(f, "Handset"),
246 DeviceType::HearingAid => write!(f, "Hearing Aid"),
247 DeviceType::Dock => write!(f, "Dock"),
248 DeviceType::Tuner => write!(f, "Tuner"),
249 DeviceType::Virtual => write!(f, "Virtual"),
250 _ => write!(f, "Unknown"),
251 }
252 }
253}
254
255impl fmt::Display for InterfaceType {
256 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
257 match self {
258 InterfaceType::BuiltIn => write!(f, "Built-in"),
259 InterfaceType::Usb => write!(f, "USB"),
260 InterfaceType::Bluetooth => write!(f, "Bluetooth"),
261 InterfaceType::Pci => write!(f, "PCI"),
262 InterfaceType::FireWire => write!(f, "FireWire"),
263 InterfaceType::Thunderbolt => write!(f, "Thunderbolt"),
264 InterfaceType::Hdmi => write!(f, "HDMI"),
265 InterfaceType::Line => write!(f, "Line"),
266 InterfaceType::Spdif => write!(f, "S/PDIF"),
267 InterfaceType::Network => write!(f, "Network"),
268 InterfaceType::Virtual => write!(f, "Virtual"),
269 InterfaceType::DisplayPort => write!(f, "DisplayPort"),
270 InterfaceType::Aggregate => write!(f, "Aggregate"),
271 _ => write!(f, "Unknown"),
272 }
273 }
274}
275
276impl fmt::Display for DeviceDirection {
277 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278 match self {
279 DeviceDirection::Input => write!(f, "Input"),
280 DeviceDirection::Output => write!(f, "Output"),
281 DeviceDirection::Duplex => write!(f, "Duplex"),
282 _ => write!(f, "Unknown"),
283 }
284 }
285}
286
287#[derive(Debug, Clone)]
292pub struct DeviceDescriptionBuilder {
293 name: String,
294 manufacturer: Option<String>,
295 driver: Option<String>,
296 device_type: DeviceType,
297 interface_type: InterfaceType,
298 direction: DeviceDirection,
299 address: Option<String>,
300 extended: Vec<String>,
301}
302
303impl DeviceDescriptionBuilder {
304 pub fn new(name: impl Into<String>) -> Self {
306 Self {
307 name: name.into(),
308 manufacturer: None,
309 driver: None,
310 device_type: DeviceType::default(),
311 interface_type: InterfaceType::default(),
312 direction: DeviceDirection::default(),
313 address: None,
314 extended: Vec::new(),
315 }
316 }
317
318 pub fn manufacturer(mut self, manufacturer: impl Into<String>) -> Self {
320 self.manufacturer = Some(manufacturer.into());
321 self
322 }
323
324 pub fn driver(mut self, driver: impl Into<String>) -> Self {
326 self.driver = Some(driver.into());
327 self
328 }
329
330 pub fn device_type(mut self, device_type: DeviceType) -> Self {
332 self.device_type = device_type;
333 self
334 }
335
336 pub fn interface_type(mut self, interface_type: InterfaceType) -> Self {
338 self.interface_type = interface_type;
339 self
340 }
341
342 pub fn direction(mut self, direction: DeviceDirection) -> Self {
344 self.direction = direction;
345 self
346 }
347
348 pub fn address(mut self, address: impl Into<String>) -> Self {
350 self.address = Some(address.into());
351 self
352 }
353
354 pub fn extended(mut self, lines: Vec<String>) -> Self {
356 self.extended = lines;
357 self
358 }
359
360 pub fn add_extended_line(mut self, line: impl Into<String>) -> Self {
362 self.extended.push(line.into());
363 self
364 }
365
366 pub fn build(self) -> DeviceDescription {
368 DeviceDescription {
369 name: self.name,
370 manufacturer: self.manufacturer,
371 driver: self.driver,
372 device_type: self.device_type,
373 interface_type: self.interface_type,
374 direction: self.direction,
375 address: self.address,
376 extended: self.extended,
377 }
378 }
379}
380
381pub(crate) fn direction_from_caps(has_input: bool, has_output: bool) -> DeviceDirection {
383 match (has_input, has_output) {
384 (true, true) => DeviceDirection::Duplex,
385 (true, false) => DeviceDirection::Input,
386 (false, true) => DeviceDirection::Output,
387 (false, false) => DeviceDirection::Unknown,
388 }
389}
390
391#[allow(dead_code)]
393pub(crate) fn direction_from_counts(
394 input_channels: Option<ChannelCount>,
395 output_channels: Option<ChannelCount>,
396) -> DeviceDirection {
397 let has_input = input_channels.map(|n| n > 0).unwrap_or(false);
398 let has_output = output_channels.map(|n| n > 0).unwrap_or(false);
399 direction_from_caps(has_input, has_output)
400}