cpal/
traits.rs

1//! The suite of traits allowing CPAL to abstract over hosts, devices, event loops and stream IDs.
2
3use std::time::Duration;
4
5use crate::{
6    BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
7    InputCallbackInfo, InputDevices, OutputCallbackInfo, OutputDevices, PauseStreamError,
8    PlayStreamError, SampleFormat, SizedSample, StreamConfig, StreamError, SupportedStreamConfig,
9    SupportedStreamConfigRange, SupportedStreamConfigsError,
10};
11
12/// A [`Host`] provides access to the available audio devices on the system.
13///
14/// Each platform may have a number of available hosts depending on the system, each with their own
15/// pros and cons.
16///
17/// For example, WASAPI is the standard audio host API that ships with the Windows operating
18/// system. However, due to historical limitations with respect to performance and flexibility,
19/// Steinberg created the ASIO API providing better audio device support for pro audio and
20/// low-latency applications. As a result, it is common for some devices and device capabilities to
21/// only be available via ASIO, while others are only available via WASAPI.
22///
23/// Another great example is the Linux platform. While the ALSA host API is the lowest-level API
24/// available to almost all distributions of Linux, its flexibility is limited as it requires that
25/// each process have exclusive access to the devices with which they establish streams. PulseAudio
26/// is another popular host API that aims to solve this issue by providing user-space mixing,
27/// however it has its own limitations w.r.t. low-latency and high-performance audio applications.
28/// JACK is yet another host API that is more suitable to pro-audio applications, however it is
29/// less readily available by default in many Linux distributions and is known to be tricky to
30/// set up.
31///
32/// [`Host`]: crate::Host
33pub trait HostTrait {
34    /// The type used for enumerating available devices by the host.
35    type Devices: Iterator<Item = Self::Device>;
36    /// The `Device` type yielded by the host.
37    type Device: DeviceTrait;
38
39    /// Whether or not the host is available on the system.
40    fn is_available() -> bool;
41
42    /// An iterator yielding all [`Device`](DeviceTrait)s currently available to the host on the system.
43    ///
44    /// Can be empty if the system does not support audio in general.
45    fn devices(&self) -> Result<Self::Devices, DevicesError>;
46
47    /// The default input audio device on the system.
48    ///
49    /// Returns `None` if no input device is available.
50    fn default_input_device(&self) -> Option<Self::Device>;
51
52    /// The default output audio device on the system.
53    ///
54    /// Returns `None` if no output device is available.
55    fn default_output_device(&self) -> Option<Self::Device>;
56
57    /// An iterator yielding all `Device`s currently available to the system that support one or more
58    /// input stream formats.
59    ///
60    /// Can be empty if the system does not support audio input.
61    fn input_devices(&self) -> Result<InputDevices<Self::Devices>, DevicesError> {
62        fn supports_input<D: DeviceTrait>(device: &D) -> bool {
63            device
64                .supported_input_configs()
65                .map(|mut iter| iter.next().is_some())
66                .unwrap_or(false)
67        }
68        Ok(self.devices()?.filter(supports_input::<Self::Device>))
69    }
70
71    /// An iterator yielding all `Device`s currently available to the system that support one or more
72    /// output stream formats.
73    ///
74    /// Can be empty if the system does not support audio output.
75    fn output_devices(&self) -> Result<OutputDevices<Self::Devices>, DevicesError> {
76        fn supports_output<D: DeviceTrait>(device: &D) -> bool {
77            device
78                .supported_output_configs()
79                .map(|mut iter| iter.next().is_some())
80                .unwrap_or(false)
81        }
82        Ok(self.devices()?.filter(supports_output::<Self::Device>))
83    }
84}
85
86/// A device that is capable of audio input and/or output.
87///
88/// Please note that `Device`s may become invalid if they get disconnected. Therefore, all the
89/// methods that involve a device return a `Result` allowing the user to handle this case.
90pub trait DeviceTrait {
91    /// The iterator type yielding supported input stream formats.
92    type SupportedInputConfigs: Iterator<Item = SupportedStreamConfigRange>;
93    /// The iterator type yielding supported output stream formats.
94    type SupportedOutputConfigs: Iterator<Item = SupportedStreamConfigRange>;
95    /// The stream type created by [`build_input_stream_raw`] and [`build_output_stream_raw`].
96    ///
97    /// [`build_input_stream_raw`]: Self::build_input_stream_raw
98    /// [`build_output_stream_raw`]: Self::build_output_stream_raw
99    type Stream: StreamTrait;
100
101    /// The human-readable name of the device.
102    fn name(&self) -> Result<String, DeviceNameError>;
103
104    /// An iterator yielding formats that are supported by the backend.
105    ///
106    /// Can return an error if the device is no longer valid (e.g. it has been disconnected).
107    fn supported_input_configs(
108        &self,
109    ) -> Result<Self::SupportedInputConfigs, SupportedStreamConfigsError>;
110
111    /// An iterator yielding output stream formats that are supported by the device.
112    ///
113    /// Can return an error if the device is no longer valid (e.g. it has been disconnected).
114    fn supported_output_configs(
115        &self,
116    ) -> Result<Self::SupportedOutputConfigs, SupportedStreamConfigsError>;
117
118    /// The default input stream format for the device.
119    fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError>;
120
121    /// The default output stream format for the device.
122    fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError>;
123
124    /// Create an input stream.
125    fn build_input_stream<T, D, E>(
126        &self,
127        config: &StreamConfig,
128        mut data_callback: D,
129        error_callback: E,
130        timeout: Option<Duration>,
131    ) -> Result<Self::Stream, BuildStreamError>
132    where
133        T: SizedSample,
134        D: FnMut(&[T], &InputCallbackInfo) + Send + 'static,
135        E: FnMut(StreamError) + Send + 'static,
136    {
137        self.build_input_stream_raw(
138            config,
139            T::FORMAT,
140            move |data, info| {
141                data_callback(
142                    data.as_slice()
143                        .expect("host supplied incorrect sample type"),
144                    info,
145                )
146            },
147            error_callback,
148            timeout,
149        )
150    }
151
152    /// Create an output stream.
153    fn build_output_stream<T, D, E>(
154        &self,
155        config: &StreamConfig,
156        mut data_callback: D,
157        error_callback: E,
158        timeout: Option<Duration>,
159    ) -> Result<Self::Stream, BuildStreamError>
160    where
161        T: SizedSample,
162        D: FnMut(&mut [T], &OutputCallbackInfo) + Send + 'static,
163        E: FnMut(StreamError) + Send + 'static,
164    {
165        self.build_output_stream_raw(
166            config,
167            T::FORMAT,
168            move |data, info| {
169                data_callback(
170                    data.as_slice_mut()
171                        .expect("host supplied incorrect sample type"),
172                    info,
173                )
174            },
175            error_callback,
176            timeout,
177        )
178    }
179
180    /// Create a dynamically typed input stream.
181    fn build_input_stream_raw<D, E>(
182        &self,
183        config: &StreamConfig,
184        sample_format: SampleFormat,
185        data_callback: D,
186        error_callback: E,
187        timeout: Option<Duration>,
188    ) -> Result<Self::Stream, BuildStreamError>
189    where
190        D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
191        E: FnMut(StreamError) + Send + 'static;
192
193    /// Create a dynamically typed output stream.
194    fn build_output_stream_raw<D, E>(
195        &self,
196        config: &StreamConfig,
197        sample_format: SampleFormat,
198        data_callback: D,
199        error_callback: E,
200        timeout: Option<Duration>,
201    ) -> Result<Self::Stream, BuildStreamError>
202    where
203        D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
204        E: FnMut(StreamError) + Send + 'static;
205}
206
207/// A stream created from [`Device`](DeviceTrait), with methods to control playback.
208pub trait StreamTrait {
209    /// Run the stream.
210    ///
211    /// Note: Not all platforms automatically run the stream upon creation, so it is important to
212    /// call `play` after creation if it is expected that the stream should run immediately.
213    fn play(&self) -> Result<(), PlayStreamError>;
214
215    /// Some devices support pausing the audio stream. This can be useful for saving energy in
216    /// moments of silence.
217    ///
218    /// Note: Not all devices support suspending the stream at the hardware level. This method may
219    /// fail in these cases.
220    fn pause(&self) -> Result<(), PauseStreamError>;
221}