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}