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}
222