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        Ok(self.devices()?.filter(DeviceTrait::supports_input))
63    }
64
65    /// An iterator yielding all `Device`s currently available to the system that support one or more
66    /// output stream formats.
67    ///
68    /// Can be empty if the system does not support audio output.
69    fn output_devices(&self) -> Result<OutputDevices<Self::Devices>, DevicesError> {
70        Ok(self.devices()?.filter(DeviceTrait::supports_output))
71    }
72}
73
74/// A device that is capable of audio input and/or output.
75///
76/// Please note that `Device`s may become invalid if they get disconnected. Therefore, all the
77/// methods that involve a device return a `Result` allowing the user to handle this case.
78pub trait DeviceTrait {
79    /// The iterator type yielding supported input stream formats.
80    type SupportedInputConfigs: Iterator<Item = SupportedStreamConfigRange>;
81    /// The iterator type yielding supported output stream formats.
82    type SupportedOutputConfigs: Iterator<Item = SupportedStreamConfigRange>;
83    /// The stream type created by [`build_input_stream_raw`] and [`build_output_stream_raw`].
84    ///
85    /// [`build_input_stream_raw`]: Self::build_input_stream_raw
86    /// [`build_output_stream_raw`]: Self::build_output_stream_raw
87    type Stream: StreamTrait;
88
89    /// The human-readable name of the device.
90    fn name(&self) -> Result<String, DeviceNameError>;
91
92    /// True if the device supports audio input, otherwise false
93    fn supports_input(&self) -> bool {
94        self.supported_input_configs()
95            .map(|mut iter| iter.next().is_some())
96            .unwrap_or(false)
97    }
98
99    /// True if the device supports audio output, otherwise false
100    fn supports_output(&self) -> bool {
101        self.supported_output_configs()
102            .map(|mut iter| iter.next().is_some())
103            .unwrap_or(false)
104    }
105
106    /// An iterator yielding formats that are supported by the backend.
107    ///
108    /// Can return an error if the device is no longer valid (e.g. it has been disconnected).
109    fn supported_input_configs(
110        &self,
111    ) -> Result<Self::SupportedInputConfigs, SupportedStreamConfigsError>;
112
113    /// An iterator yielding output stream formats that are supported by the device.
114    ///
115    /// Can return an error if the device is no longer valid (e.g. it has been disconnected).
116    fn supported_output_configs(
117        &self,
118    ) -> Result<Self::SupportedOutputConfigs, SupportedStreamConfigsError>;
119
120    /// The default input stream format for the device.
121    fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError>;
122
123    /// The default output stream format for the device.
124    fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError>;
125
126    /// Create an input stream.
127    fn build_input_stream<T, D, E>(
128        &self,
129        config: &StreamConfig,
130        mut data_callback: D,
131        error_callback: E,
132        timeout: Option<Duration>,
133    ) -> Result<Self::Stream, BuildStreamError>
134    where
135        T: SizedSample,
136        D: FnMut(&[T], &InputCallbackInfo) + Send + 'static,
137        E: FnMut(StreamError) + Send + 'static,
138    {
139        self.build_input_stream_raw(
140            config,
141            T::FORMAT,
142            move |data, info| {
143                data_callback(
144                    data.as_slice()
145                        .expect("host supplied incorrect sample type"),
146                    info,
147                )
148            },
149            error_callback,
150            timeout,
151        )
152    }
153
154    /// Create an output stream.
155    fn build_output_stream<T, D, E>(
156        &self,
157        config: &StreamConfig,
158        mut data_callback: D,
159        error_callback: E,
160        timeout: Option<Duration>,
161    ) -> Result<Self::Stream, BuildStreamError>
162    where
163        T: SizedSample,
164        D: FnMut(&mut [T], &OutputCallbackInfo) + Send + 'static,
165        E: FnMut(StreamError) + Send + 'static,
166    {
167        self.build_output_stream_raw(
168            config,
169            T::FORMAT,
170            move |data, info| {
171                data_callback(
172                    data.as_slice_mut()
173                        .expect("host supplied incorrect sample type"),
174                    info,
175                )
176            },
177            error_callback,
178            timeout,
179        )
180    }
181
182    /// Create a dynamically typed input stream.
183    fn build_input_stream_raw<D, E>(
184        &self,
185        config: &StreamConfig,
186        sample_format: SampleFormat,
187        data_callback: D,
188        error_callback: E,
189        timeout: Option<Duration>,
190    ) -> Result<Self::Stream, BuildStreamError>
191    where
192        D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
193        E: FnMut(StreamError) + Send + 'static;
194
195    /// Create a dynamically typed output stream.
196    fn build_output_stream_raw<D, E>(
197        &self,
198        config: &StreamConfig,
199        sample_format: SampleFormat,
200        data_callback: D,
201        error_callback: E,
202        timeout: Option<Duration>,
203    ) -> Result<Self::Stream, BuildStreamError>
204    where
205        D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
206        E: FnMut(StreamError) + Send + 'static;
207}
208
209/// A stream created from [`Device`](DeviceTrait), with methods to control playback.
210pub trait StreamTrait {
211    /// Run the stream.
212    ///
213    /// Note: Not all platforms automatically run the stream upon creation, so it is important to
214    /// call `play` after creation if it is expected that the stream should run immediately.
215    fn play(&self) -> Result<(), PlayStreamError>;
216
217    /// Some devices support pausing the audio stream. This can be useful for saving energy in
218    /// moments of silence.
219    ///
220    /// Note: Not all devices support suspending the stream at the hardware level. This method may
221    /// fail in these cases.
222    fn pause(&self) -> Result<(), PauseStreamError>;
223}