bpm_analyzer/
device.rs

1//! Audio device discovery and selection.
2
3use cpal::traits::{DeviceTrait, HostTrait};
4
5use crate::error::{Error, Result};
6
7/// Information about an available audio input device.
8#[derive(Debug, Clone)]
9pub struct AudioDevice {
10    /// Name of the audio device
11    pub name: String,
12    /// Whether this is the default input device
13    pub is_default: bool,
14}
15
16/// Lists all available audio input devices.
17///
18/// # Example
19///
20/// ```no_run
21/// use bpm_analyzer::list_audio_devices;
22///
23/// let devices = list_audio_devices()?;
24/// for device in devices {
25///     println!("{} {}", device.name, if device.is_default { "(default)" } else { "" });
26/// }
27/// # Ok::<(), bpm_analyzer::Error>(())
28/// ```
29pub fn list_audio_devices() -> Result<Vec<AudioDevice>> {
30    let host = cpal::default_host();
31    let default_device = host.default_input_device();
32    let default_name = default_device
33        .as_ref()
34        .and_then(|d| d.description().ok())
35        .map(|desc| desc.name().to_string());
36
37    let devices = host
38        .input_devices()?
39        .filter_map(|device| {
40            device.description().ok().map(|desc| {
41                let name = desc.name().to_string();
42                let is_default = default_name.as_ref() == Some(&name);
43                AudioDevice { name, is_default }
44            })
45        })
46        .collect();
47
48    Ok(devices)
49}
50
51/// Gets an audio input device by name.
52///
53/// # Arguments
54///
55/// * `name` - The name of the device to find (case-sensitive)
56///
57/// # Example
58///
59/// ```no_run
60/// use bpm_analyzer::get_device_by_name;
61///
62/// let device = get_device_by_name("BlackHole 2ch")?;
63/// # Ok::<(), bpm_analyzer::Error>(())
64/// ```
65pub fn get_device_by_name(name: &str) -> Result<cpal::Device> {
66    let host = cpal::default_host();
67    host.input_devices()?
68        .find(|device| {
69            device
70                .description()
71                .ok()
72                .map(|desc| desc.name() == name)
73                .unwrap_or(false)
74        })
75        .ok_or_else(|| Error::DeviceNotFound(name.to_string()))
76}
77
78/// Gets the default audio input device.
79///
80/// # Example
81///
82/// ```no_run
83/// use bpm_analyzer::get_default_device;
84///
85/// let device = get_default_device()?;
86/// # Ok::<(), bpm_analyzer::Error>(())
87/// ```
88pub fn get_default_device() -> Result<cpal::Device> {
89    let host = cpal::default_host();
90    host.default_input_device().ok_or(Error::NoDeviceFound)
91}