interflow/lib.rs
1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3
4use bitflags::bitflags;
5use std::borrow::Cow;
6
7use crate::audio_buffer::{AudioMut, AudioRef};
8use crate::channel_map::ChannelMap32;
9use crate::timestamp::Timestamp;
10
11pub mod audio_buffer;
12pub mod backends;
13pub mod channel_map;
14pub mod duplex;
15pub mod prelude;
16pub mod timestamp;
17
18bitflags! {
19 /// Represents the types/capabilities of an audio device.
20 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21 pub struct DeviceType: u32 {
22 /// Device supports audio input.
23 const INPUT = 1 << 0;
24
25 /// Device supports audio output.
26 const OUTPUT = 1 << 1;
27
28 /// Physical audio device (hardware).
29 const PHYSICAL = 1 << 2;
30
31 /// Virtual/software application device.
32 const APPLICATION = 1 << 3;
33
34 /// This device is set as default
35 const DEFAULT = 1 << 4;
36
37 /// Device that supports both input and output.
38 const DUPLEX = Self::INPUT.bits() | Self::OUTPUT.bits();
39 }
40}
41
42/// Audio drivers provide access to the inputs and outputs of devices.
43/// Several drivers might provide the same accesses, some sharing it with other applications,
44/// while others work in exclusive mode.
45pub trait AudioDriver {
46 /// Type of errors that can happen when using this audio driver.
47 type Error: std::error::Error;
48 /// Type of audio devices this driver provides.
49 type Device: AudioDevice;
50
51 /// Driver display name.
52 const DISPLAY_NAME: &'static str;
53
54 /// Runtime version of the audio driver. If there is a difference between "client" and
55 /// "server" versions, then this should reflect the server version.
56 fn version(&self) -> Result<Cow<'_, str>, Self::Error>;
57
58 /// Default device of the given type. This is most often tied to the audio settings at the
59 /// operating system level.
60 fn default_device(&self, device_type: DeviceType) -> Result<Option<Self::Device>, Self::Error>;
61
62 /// List all devices available through this audio driver.
63 fn list_devices(&self) -> Result<impl IntoIterator<Item = Self::Device>, Self::Error>;
64}
65
66impl DeviceType {
67 /// Returns true if this device type has the input capability.
68 pub fn is_input(&self) -> bool {
69 self.contains(Self::INPUT)
70 }
71
72 /// Returns true if this device type has the output capability.
73 pub fn is_output(&self) -> bool {
74 self.contains(Self::OUTPUT)
75 }
76
77 /// Returns true if this device type is a physical device.
78 pub fn is_physical(&self) -> bool {
79 self.contains(Self::PHYSICAL)
80 }
81
82 /// Returns true if this device type is an application/virtual device.
83 pub fn is_application(&self) -> bool {
84 self.contains(Self::APPLICATION)
85 }
86
87 /// Returns true if this device is set as default
88 pub fn is_default(&self) -> bool {
89 self.contains(Self::DEFAULT)
90 }
91
92 /// Returns true if this device type supports both input and output.
93 pub fn is_duplex(&self) -> bool {
94 self.contains(Self::DUPLEX)
95 }
96}
97
98/// Configuration for an audio stream.
99#[derive(Debug, Clone, Copy, PartialEq)]
100pub struct StreamConfig {
101 /// Configured sample rate of the requested stream. The opened stream can have a different
102 /// sample rate, so don't rely on this parameter being correct at runtime.
103 pub samplerate: f64,
104 /// Map of channels requested by the stream. Entries correspond in order to
105 /// [AudioDevice::channel_map].
106 ///
107 /// Some drivers allow specifying which channels are going to be opened and available through
108 /// the audio buffers. For other drivers, only the number of requested channels is used, and
109 /// order does not matter.
110 pub channels: ChannelMap32,
111 /// Range of preferential buffer sizes, in units of audio samples per channel.
112 /// The library will make a best-effort attempt at honoring this setting, and in future versions
113 /// may provide additional buffering to ensure it, but for now you should not make assumptions
114 /// on buffer sizes based on this setting.
115 pub buffer_size_range: (Option<usize>, Option<usize>),
116 /// Whether the device should be exclusively held (meaning no other application can open the
117 /// same device).
118 pub exclusive: bool,
119}
120
121/// Audio channel description.
122#[derive(Debug, Clone)]
123pub struct Channel<'a> {
124 /// Index of the channel in the device
125 pub index: usize,
126 /// Display name for the channel, if available, else a generic name like "Channel 1"
127 pub name: Cow<'a, str>,
128}
129
130/// Trait for types describing audio devices. Audio devices have zero or more inputs and outputs,
131/// and depending on the driver, can be duplex devices which can provide both of them at the same
132/// time natively.
133pub trait AudioDevice {
134 /// Type of errors that can happen when using this device.
135 type Error: std::error::Error;
136
137 /// Device display name
138 fn name(&self) -> Cow<'_, str>;
139
140 /// Device type. Either input, output, or duplex.
141 fn device_type(&self) -> DeviceType;
142
143 /// Iterator of the available channels in this device. Channel indices are used when
144 /// specifying which channels to open when creating an audio stream.
145 fn channel_map(&self) -> impl IntoIterator<Item = Channel<'_>>;
146
147 /// Not all configuration values make sense for a particular device, and this method tests a
148 /// configuration to see if it can be used in an audio stream.
149 fn is_config_supported(&self, config: &StreamConfig) -> bool;
150
151 /// Enumerate all possible configurations this device supports. If that is not provided by
152 /// the device, and not easily generated manually, this will return `None`.
153 fn enumerate_configurations(&self) -> Option<impl IntoIterator<Item = StreamConfig>>;
154
155 /// Returns the supported I/O buffer size range for the device.
156 fn buffer_size_range(&self) -> Result<(Option<usize>, Option<usize>), Self::Error> {
157 Ok((None, None))
158 }
159}
160
161/// Marker trait for values which are [Send] everywhere but on the web (as WASM does not yet have
162/// web targets.
163///
164/// This should only be used to define the traits and should not be relied upon in external code.
165///
166/// This definition is selected on non-web platforms, and does require [`Send`].
167#[cfg(not(wasm))]
168pub trait SendEverywhereButOnWeb: 'static + Send {}
169#[cfg(not(wasm))]
170impl<T: 'static + Send> SendEverywhereButOnWeb for T {}
171
172/// Marker trait for values which are [Send] everywhere but on the web (as WASM does not yet have
173/// web targets.
174///
175/// This should only be used to define the traits and should not be relied upon in external code.
176///
177/// This definition is selected on web platforms, and does not require [`Send`].
178#[cfg(wasm)]
179pub trait SendEverywhereButOnWeb {}
180#[cfg(wasm)]
181impl<T> SendEverywhereButOnWeb for T {}
182
183/// Trait for types which can provide input streams.
184///
185/// Input devices require a [`AudioInputCallback`] which receives the audio data from the input
186/// device, and processes it.
187pub trait AudioInputDevice: AudioDevice {
188 /// Type of the resulting stream. This stream can be used to control the audio processing
189 /// externally, or stop it completely and give back ownership of the callback with
190 /// [`AudioStreamHandle::eject`].
191 type StreamHandle<Callback: AudioInputCallback>: AudioStreamHandle<Callback>;
192
193 /// Return the default configuration for this device, if there is one. The returned configuration *must* be
194 /// valid according to [`Self::is_config_supported`].
195 fn default_input_config(&self) -> Result<StreamConfig, Self::Error>;
196
197 /// Creates an input stream with the provided stream configuration. For this call to be
198 /// valid, [`AudioDevice::is_config_supported`] should have returned `true` on the provided
199 /// configuration.
200 ///
201 /// An input callback is required to process the audio, whose ownership will be transferred
202 /// to the audio stream.
203 fn create_input_stream<Callback: SendEverywhereButOnWeb + AudioInputCallback>(
204 &self,
205 stream_config: StreamConfig,
206 callback: Callback,
207 ) -> Result<Self::StreamHandle<Callback>, Self::Error>;
208
209 /// Create an input stream with the default configuration (as returned by [`Self::default_input_config`]).
210 ///
211 /// # Arguments
212 ///
213 /// - `callback`: Callback to process the audio input
214 fn default_input_stream<Callback: SendEverywhereButOnWeb + AudioInputCallback>(
215 &self,
216 callback: Callback,
217 ) -> Result<Self::StreamHandle<Callback>, Self::Error> {
218 self.create_input_stream(self.default_input_config()?, callback)
219 }
220}
221
222/// Trait for types which can provide output streams.
223///
224/// Output devices require a [`AudioOutputCallback`] which receives the audio data from the output
225/// device, and processes it.
226pub trait AudioOutputDevice: AudioDevice {
227 /// Type of the resulting stream. This stream can be used to control the audio processing
228 /// externally, or stop it completely and give back ownership of the callback with
229 /// [`AudioStreamHandle::eject`].
230 type StreamHandle<Callback: AudioOutputCallback>: AudioStreamHandle<Callback>;
231
232 /// Return the default output configuration for this device, if it exists
233 fn default_output_config(&self) -> Result<StreamConfig, Self::Error>;
234
235 /// Creates an output stream with the provided stream configuration. For this call to be
236 /// valid, [`AudioDevice::is_config_supported`] should have returned `true` on the provided
237 /// configuration.
238 ///
239 /// An output callback is required to process the audio, whose ownership will be transferred
240 /// to the audio stream.
241 fn create_output_stream<Callback: SendEverywhereButOnWeb + AudioOutputCallback>(
242 &self,
243 stream_config: StreamConfig,
244 callback: Callback,
245 ) -> Result<Self::StreamHandle<Callback>, Self::Error>;
246
247 /// Create an output stream using the default configuration as returned by [`Self::default_output_config`].
248 ///
249 /// # Arguments
250 ///
251 /// - `callback`: Output callback to generate audio data with.
252 fn default_output_stream<Callback: SendEverywhereButOnWeb + AudioOutputCallback>(
253 &self,
254 callback: Callback,
255 ) -> Result<Self::StreamHandle<Callback>, Self::Error> {
256 self.create_output_stream(self.default_output_config()?, callback)
257 }
258}
259
260/// Trait for types which handles an audio stream (input or output).
261pub trait AudioStreamHandle<Callback> {
262 /// Type of errors which have caused the stream to fail.
263 type Error: std::error::Error;
264
265 /// Eject the stream, returning ownership of the callback.
266 ///
267 /// An error can occur when an irrecoverable error has occured and ownership has been lost
268 /// already.
269 fn eject(self) -> Result<Callback, Self::Error>;
270}
271
272#[duplicate::duplicate_item(
273 name bufty;
274 [AudioInput] [AudioRef < 'a, T >];
275 [AudioOutput] [AudioMut < 'a, T >];
276)]
277/// Plain-old-data object holding references to the audio buffer and the associated time-keeping
278/// [`Timestamp`]. This timestamp is associated with the stream, and in the cases where the
279/// driver provides timing information, it is used instead of relying on sample-counting.
280pub struct name<'a, T> {
281 /// Associated time stamp for this callback. The time represents the duration for which the
282 /// stream has been opened, and is either provided by the driver if available, or is kept up
283 /// manually by the library.
284 pub timestamp: Timestamp,
285 /// Audio buffer data.
286 pub buffer: bufty,
287}
288
289/// Plain-old-data object holding the passed-in stream configuration, as well as a general
290/// callback timestamp, which can be different from the input and output streams in case of
291/// cross-stream latencies; differences in timing can indicate desync.
292pub struct AudioCallbackContext {
293 /// Passed-in stream configuration. Values have been updated where necessary to correspond to
294 /// the actual stream properties.
295 pub stream_config: StreamConfig,
296 /// Callback-wide timestamp.
297 pub timestamp: Timestamp,
298}
299
300/// Trait of types which process input audio data. This is the trait that users will want to
301/// implement when processing an input device.
302pub trait AudioInputCallback {
303 /// Callback called when input data is available to be processed.
304 fn on_input_data(&mut self, context: AudioCallbackContext, input: AudioInput<f32>);
305}
306
307/// Trait of types which process output audio data. This is the trait that users will want to
308/// implement when processing an output device.
309pub trait AudioOutputCallback {
310 /// Callback called when output data is available to be processed.
311 fn on_output_data(&mut self, context: AudioCallbackContext, input: AudioOutput<f32>);
312}