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