Skip to main content

firewheel_graph/
backend.rs

1use bevy_platform::prelude::{String, Vec};
2use core::error::Error;
3use core::time::Duration;
4
5use firewheel_core::{node::StreamStatus, StreamInfo};
6
7use crate::processor::FirewheelProcessor;
8
9/// A trait describing an audio backend.
10///
11/// When an instance is dropped, then it must automatically stop its
12/// corresponding audio stream.
13///
14/// All methods in this trait are only ever invoked from the main
15/// thread (the thread where the [`crate::context::FirewheelCtx`]
16/// lives).
17pub trait AudioBackend: Sized {
18    /// The type used to retrieve the list of available audio devices on
19    /// the system and their available ocnfigurations.
20    type Enumerator;
21    /// The configuration of the audio stream.
22    type Config: Default;
23    /// An error when starting a new audio stream.
24    type StartStreamError: Error;
25    /// An error that has caused the audio stream to stop.
26    type StreamError: Error;
27    /// A type describing an instant in time.
28    type Instant: Send + Clone;
29
30    /// Get a struct used to retrieve the list of available audio devices
31    /// on the system and their available ocnfigurations.
32    fn enumerator() -> Self::Enumerator;
33
34    /// Get a list of available input audio devices (for the default API).
35    ///
36    /// The first item in the list is the default device.
37    fn input_devices_simple(&mut self) -> Vec<DeviceInfoSimple> {
38        Vec::new()
39    }
40
41    /// Get a list of available output audio devices (for the default API).
42    ///
43    /// The first item in the list is the default device.
44    fn output_devices_simple(&mut self) -> Vec<DeviceInfoSimple> {
45        Vec::new()
46    }
47
48    /// Convert the easy-to-use, backend-agnostic audio stream configuration
49    /// into the corresponding backend-specific configuration.
50    fn convert_simple_config(&mut self, config: &SimpleStreamConfig) -> Self::Config {
51        let _ = config;
52        Self::Config::default()
53    }
54
55    /// Start the audio stream with the given configuration, and return
56    /// a handle for the audio stream.
57    fn start_stream(config: Self::Config) -> Result<(Self, StreamInfo), Self::StartStreamError>;
58
59    /// Send the given processor to the audio thread for processing.
60    fn set_processor(&mut self, processor: FirewheelProcessor<Self>);
61
62    /// Poll the status of the running audio stream. Return an error if the
63    /// audio stream has stopped for any reason.
64    fn poll_status(&mut self) -> Result<(), Self::StreamError>;
65
66    /// Return the amount of time that has elapsed from the instant
67    /// [`FirewheelProcessor::process_interleaved`] was last called and now.
68    ///
69    /// The given `process_timestamp` is the `Self::Instant` that was passed
70    /// to the latest call to [`FirewheelProcessor::process_interleaved`].
71    /// This can be used to calculate the delay if needed.
72    ///
73    /// If for any reason the delay could not be determined, return `None`.
74    fn delay_from_last_process(&self, process_timestamp: Self::Instant) -> Option<Duration>;
75}
76
77#[derive(Debug, Clone, PartialEq, Eq)]
78pub struct BackendProcessInfo<B: AudioBackend> {
79    pub num_in_channels: usize,
80    pub num_out_channels: usize,
81    pub frames: usize,
82    pub process_timestamp: B::Instant,
83    pub duration_since_stream_start: Duration,
84    pub input_stream_status: StreamStatus,
85    pub output_stream_status: StreamStatus,
86    pub dropped_frames: u32,
87}
88
89/// Basic information about an audio device. It contains the name of the
90/// device and a unique identifier that persists across reboots.
91#[derive(Default, Debug, Clone, PartialEq)]
92#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
93#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
94pub struct DeviceInfoSimple {
95    /// The display name of this audio device.
96    pub name: String,
97
98    /// A unique identifier for the device, serialized into a string.
99    ///
100    /// This identifier persists across application restarts and system
101    /// reboots.
102    pub id: String,
103}
104
105/// The configuration of an input/output device for a [`SimpleStreamConfig`]
106#[derive(Default, Debug, Clone, PartialEq)]
107#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
108#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
109pub struct SimpleDeviceConfig {
110    /// The ID of the device to use. (The ID from [`DeviceInfoSimple::id`].)
111    ///
112    /// Set to `None` to use the default device.
113    ///
114    /// By default this is set to `None`.
115    pub device: Option<String>,
116
117    /// The number of channels to use. The backend may end up using a different
118    /// channel count if the given channel count is not supported.
119    ///
120    /// Set to `None` to use the default number of channels for the device.
121    ///
122    /// By default this is set to `None`.
123    pub channels: Option<usize>,
124}
125
126/// An easy-to-use, backend-agnostic configuration for an audio stream
127#[derive(Debug, Clone, PartialEq)]
128#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
129#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
130pub struct SimpleStreamConfig {
131    /// The configuration of the output audio device
132    pub output: SimpleDeviceConfig,
133
134    /// The configuration of the input audio device
135    ///
136    /// Set to `None` to not connect an input audio device.
137    ///
138    /// By default this is set to `None`.
139    pub input: Option<SimpleDeviceConfig>,
140
141    /// The block size (latency) to use. Set to `None` to use the device's default
142    /// block size. The backend may end up using a different block size if the given
143    /// block size is not supported.
144    ///
145    /// By default this is set to `Some(1024)`, which should be good enough for most
146    /// games.
147    ///
148    /// If your application is not a game and doesn't need low latency playback,
149    /// then prefer to set this to `None` to reduce system resources.
150    pub desired_block_frames: Option<u32>,
151
152    /// The sample rate to use. The backend may end up using a different sample
153    /// rate if the given sample rate is not supported.
154    ///
155    /// Set to `None` to use the device's default sample rate.
156    ///
157    /// By default this is set to `None`.
158    pub desired_sample_rate: Option<u32>,
159}
160
161impl Default for SimpleStreamConfig {
162    fn default() -> Self {
163        Self {
164            output: SimpleDeviceConfig::default(),
165            input: None,
166            desired_block_frames: Some(1024),
167            desired_sample_rate: None,
168        }
169    }
170}