| Lift freeq's AV media plane out of sleek 90f8b89 nandi 19d ago | 1 | //! Enumerates all available audio hosts, devices, and their supported configurations. |
| 2 | //! |
| 3 | //! This example demonstrates: |
| 4 | //! - Querying available audio hosts on the system |
| 5 | //! - Enumerating all audio devices for each host |
| 6 | //! - Retrieving device IDs for persistent identification |
| 7 | //! - Getting device descriptions with metadata |
| 8 | //! - Listing supported input and output stream configurations |
| 9 | //! |
| 10 | //! Run with: `cargo run --example enumerate` |
| 11 | |
| 12 | extern crate anyhow; |
| 13 | extern crate cpal; |
| 14 | |
| 15 | use cpal::traits::{DeviceTrait, HostTrait}; |
| 16 | |
| 17 | fn main() -> Result<(), anyhow::Error> { |
| 18 | // To print raw ALSA errors to stderr during enumeration, comment out the line below: |
| 19 | #[cfg(target_os = "linux")] |
| 20 | let _silence_alsa_errors = alsa::Output::local_error_handler()?; |
| 21 | |
| 22 | println!("Supported hosts:\n {:?}", cpal::ALL_HOSTS); |
| 23 | let available_hosts = cpal::available_hosts(); |
| 24 | println!("Available hosts:\n {available_hosts:?}"); |
| 25 | |
| 26 | for host_id in available_hosts { |
| 27 | println!("{}", host_id.name()); |
| 28 | let host = cpal::host_from_id(host_id)?; |
| 29 | |
| 30 | let default_in = host |
| 31 | .default_input_device() |
| 32 | .map(|dev| dev.id().unwrap()) |
| 33 | .map(|id| id.to_string()); |
| 34 | let default_out = host |
| 35 | .default_output_device() |
| 36 | .map(|dev| dev.id().unwrap()) |
| 37 | .map(|id| id.to_string()); |
| 38 | println!(" Default Input Device:\n {default_in:?}"); |
| 39 | println!(" Default Output Device:\n {default_out:?}"); |
| 40 | |
| 41 | let devices = host.devices()?; |
| 42 | println!(" Devices: "); |
| 43 | for (device_index, device) in devices.enumerate() { |
| 44 | let id = device |
| 45 | .id() |
| 46 | .map_or("Unknown ID".to_string(), |id| id.to_string()); |
| 47 | if let Ok(desc) = device.description() { |
| 48 | println!(" {}. {id} ({})", device_index + 1, desc); |
| 49 | } else { |
| 50 | println!(" {}. {id}", device_index + 1); |
| 51 | } |
| 52 | |
| 53 | // Input configs |
| 54 | if let Ok(conf) = device.default_input_config() { |
| 55 | println!(" Default input stream config:\n {conf:?}"); |
| 56 | } |
| 57 | let input_configs = match device.supported_input_configs() { |
| 58 | Ok(f) => f.collect(), |
| 59 | Err(e) => { |
| 60 | println!(" Error getting supported input configs: {e:?}"); |
| 61 | Vec::new() |
| 62 | } |
| 63 | }; |
| 64 | if !input_configs.is_empty() { |
| 65 | println!(" All supported input stream configs:"); |
| 66 | for (config_index, config) in input_configs.into_iter().enumerate() { |
| 67 | println!( |
| 68 | " {}.{}. {:?}", |
| 69 | device_index + 1, |
| 70 | config_index + 1, |
| 71 | config |
| 72 | ); |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | // Output configs |
| 77 | if let Ok(conf) = device.default_output_config() { |
| 78 | println!(" Default output stream config:\n {conf:?}"); |
| 79 | } |
| 80 | let output_configs = match device.supported_output_configs() { |
| 81 | Ok(f) => f.collect(), |
| 82 | Err(e) => { |
| 83 | println!(" Error getting supported output configs: {e:?}"); |
| 84 | Vec::new() |
| 85 | } |
| 86 | }; |
| 87 | if !output_configs.is_empty() { |
| 88 | println!(" All supported output stream configs:"); |
| 89 | for (config_index, config) in output_configs.into_iter().enumerate() { |
| 90 | println!( |
| 91 | " {}.{}. {:?}", |
| 92 | device_index + 1, |
| 93 | config_index + 1, |
| 94 | config |
| 95 | ); |
| 96 | } |
| 97 | } |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | Ok(()) |
| 102 | } |