audio_device/wasapi/
mod.rs

1//! An idiomatic Rust WASAPI interface.
2
3use std::mem;
4use std::ptr;
5use thiserror::Error;
6use windows::Interface as _;
7use windows_sys::Windows::Win32::Com as com;
8use windows_sys::Windows::Win32::CoreAudio as core;
9
10mod initialized_client;
11pub use self::initialized_client::InitializedClient;
12
13mod client;
14pub use self::client::Client;
15
16mod render_client;
17pub use self::render_client::RenderClient;
18
19mod buffer_mut;
20pub use self::buffer_mut::BufferMut;
21
22mod sample;
23pub use self::sample::Sample;
24
25/// WASAPI-specific errors.
26#[derive(Debug, Error)]
27pub enum Error {
28    /// A system error.
29    #[error("system error: {0}")]
30    Sys(
31        #[from]
32        #[source]
33        windows::Error,
34    ),
35    /// Trying to use a mix format which is not supported by the device.
36    #[error("Device doesn't support a compatible mix format")]
37    UnsupportedMixFormat,
38}
39
40/// The audio prelude to use for wasapi.
41pub fn audio_prelude() {
42    if let Err(e) = windows::initialize_mta() {
43        panic!("failed to initialize multithreaded apartment: {}", e);
44    }
45}
46
47/// The sample format detected for the device.
48#[derive(Debug, Clone, Copy)]
49pub enum SampleFormat {
50    /// A 16-bit sample format.
51    I16,
52    /// A 32-bit floating point sample format.
53    F32,
54}
55
56/// A client configuration.
57///
58/// Constructed through [Client::default_client_config].
59#[derive(Debug, Clone, Copy)]
60pub struct ClientConfig {
61    tag: ste::Tag,
62    /// The number of channels in use.
63    pub channels: u16,
64    /// The sample rate in use.
65    pub sample_rate: u32,
66    /// The sample format in use.
67    pub sample_format: SampleFormat,
68}
69
70/// Open the default output device for WASAPI.
71pub fn default_output_client() -> Result<Option<Client>, Error> {
72    let tag = ste::Tag::current_thread();
73
74    let enumerator: core::IMMDeviceEnumerator =
75        windows::create_instance(&core::MMDeviceEnumerator)?;
76
77    let mut device = None;
78
79    unsafe {
80        enumerator
81            .GetDefaultAudioEndpoint(core::EDataFlow::eRender, core::ERole::eConsole, &mut device)
82            .ok()?;
83
84        let device = match device {
85            Some(device) => device,
86            None => return Ok(None),
87        };
88
89        let mut audio_client: mem::MaybeUninit<core::IAudioClient> = mem::MaybeUninit::zeroed();
90
91        device
92            .Activate(
93                &core::IAudioClient::IID,
94                com::CLSCTX::CLSCTX_ALL.0,
95                ptr::null_mut(),
96                audio_client.as_mut_ptr() as *mut _,
97            )
98            .ok()?;
99
100        let audio_client = audio_client.assume_init();
101
102        Ok(Some(Client { tag, audio_client }))
103    }
104}