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