| Lift freeq's AV media plane out of sleek 90f8b89 nandi 19d ago | 1 | //! WASAPI backend implementation. |
| 2 | //! |
| 3 | //! Default backend on Windows. |
| 4 | |
| 5 | #[allow(unused_imports)] |
| 6 | pub use self::device::{ |
| 7 | default_input_device, default_output_device, Device, Devices, SupportedInputConfigs, |
| 8 | SupportedOutputConfigs, |
| 9 | }; |
| 10 | #[allow(unused_imports)] |
| 11 | pub use self::stream::Stream; |
| 12 | use crate::traits::HostTrait; |
| 13 | use crate::BackendSpecificError; |
| 14 | use crate::DevicesError; |
| 15 | use std::io::Error as IoError; |
| 16 | use windows::Win32::Media::Audio; |
| 17 | |
| 18 | mod device; |
| 19 | mod stream; |
| 20 | |
| 21 | /// The WASAPI host, the default windows host type. |
| 22 | /// |
| 23 | /// Note: If you use a WASAPI output device as an input device it will |
| 24 | /// transparently enable loopback mode (see |
| 25 | /// https://docs.microsoft.com/en-us/windows/win32/coreaudio/loopback-recording). |
| 26 | #[derive(Debug)] |
| 27 | pub struct Host; |
| 28 | |
| 29 | impl Host { |
| 30 | pub fn new() -> Result<Self, crate::HostUnavailable> { |
| 31 | Ok(Host) |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | impl HostTrait for Host { |
| 36 | type Devices = Devices; |
| 37 | type Device = Device; |
| 38 | |
| 39 | fn is_available() -> bool { |
| 40 | // Assume WASAPI is always available on Windows. |
| 41 | true |
| 42 | } |
| 43 | |
| 44 | fn devices(&self) -> Result<Self::Devices, DevicesError> { |
| 45 | Devices::new() |
| 46 | } |
| 47 | |
| 48 | fn default_input_device(&self) -> Option<Self::Device> { |
| 49 | default_input_device() |
| 50 | } |
| 51 | |
| 52 | fn default_output_device(&self) -> Option<Self::Device> { |
| 53 | default_output_device() |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | impl From<windows::core::Error> for BackendSpecificError { |
| 58 | fn from(error: windows::core::Error) -> Self { |
| 59 | BackendSpecificError { |
| 60 | description: format!("{}", IoError::from(error)), |
| 61 | } |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | trait ErrDeviceNotAvailable: From<BackendSpecificError> { |
| 66 | fn device_not_available() -> Self; |
| 67 | } |
| 68 | |
| 69 | impl ErrDeviceNotAvailable for crate::BuildStreamError { |
| 70 | fn device_not_available() -> Self { |
| 71 | Self::DeviceNotAvailable |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | impl ErrDeviceNotAvailable for crate::SupportedStreamConfigsError { |
| 76 | fn device_not_available() -> Self { |
| 77 | Self::DeviceNotAvailable |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | impl ErrDeviceNotAvailable for crate::DefaultStreamConfigError { |
| 82 | fn device_not_available() -> Self { |
| 83 | Self::DeviceNotAvailable |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | impl ErrDeviceNotAvailable for crate::StreamError { |
| 88 | fn device_not_available() -> Self { |
| 89 | Self::DeviceNotAvailable |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | fn windows_err_to_cpal_err<E: ErrDeviceNotAvailable>(e: windows::core::Error) -> E { |
| 94 | windows_err_to_cpal_err_message::<E>(e, "") |
| 95 | } |
| 96 | |
| 97 | fn windows_err_to_cpal_err_message<E: ErrDeviceNotAvailable>( |
| 98 | e: windows::core::Error, |
| 99 | message: &str, |
| 100 | ) -> E { |
| 101 | match e.code() { |
| 102 | Audio::AUDCLNT_E_DEVICE_INVALIDATED | Audio::AUDCLNT_E_DEVICE_IN_USE => { |
| 103 | E::device_not_available() |
| 104 | } |
| 105 | _ => { |
| 106 | let description = format!("{}{}", message, e); |
| 107 | let err = BackendSpecificError { description }; |
| 108 | err.into() |
| 109 | } |
| 110 | } |
| 111 | } |