Skip to main content

cpal/
error.rs

1use std::error::Error;
2use std::fmt::{Display, Formatter};
3
4/// The requested host, although supported on this platform, is unavailable.
5#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
6pub struct HostUnavailable;
7
8impl Display for HostUnavailable {
9    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
10        f.write_str("the requested host is unavailable")
11    }
12}
13
14impl Error for HostUnavailable {}
15
16/// Some error has occurred that is specific to the backend from which it was produced.
17///
18/// This error is often used as a catch-all in cases where:
19///
20/// - It is unclear exactly what error might be produced by the backend API.
21/// - It does not make sense to add a variant to the enclosing error type.
22/// - No error was expected to occur at all, but we return an error to avoid the possibility of a
23///   `panic!` caused by some unforeseen or unknown reason.
24///
25/// **Note:** If you notice a `BackendSpecificError` that you believe could be better handled in a
26/// cross-platform manner, please create an issue at <https://github.com/RustAudio/cpal/issues>
27/// with details about your use case, the backend you're using, and the error message. Or submit
28/// a pull request with a patch that adds the necessary error variant to the appropriate error enum.
29#[derive(Clone, Debug, PartialEq, Eq, Hash)]
30pub struct BackendSpecificError {
31    pub description: String,
32}
33
34impl Display for BackendSpecificError {
35    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
36        write!(
37            f,
38            "A backend-specific error has occurred: {}",
39            self.description
40        )
41    }
42}
43
44impl Error for BackendSpecificError {}
45
46/// An error that might occur while attempting to enumerate the available devices on a system.
47#[derive(Clone, Debug, PartialEq, Eq, Hash)]
48pub enum DevicesError {
49    /// See the [`BackendSpecificError`] docs for more information about this error variant.
50    BackendSpecific { err: BackendSpecificError },
51}
52
53impl Display for DevicesError {
54    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
55        match self {
56            Self::BackendSpecific { err } => err.fmt(f),
57        }
58    }
59}
60
61impl Error for DevicesError {}
62
63impl From<BackendSpecificError> for DevicesError {
64    fn from(err: BackendSpecificError) -> Self {
65        Self::BackendSpecific { err }
66    }
67}
68
69/// An error that may occur while attempting to retrieve a device ID.
70#[derive(Clone, Debug, Eq, PartialEq)]
71pub enum DeviceIdError {
72    /// See the [`BackendSpecificError`] docs for more information about this error variant.
73    BackendSpecific {
74        err: BackendSpecificError,
75    },
76    UnsupportedPlatform,
77}
78
79impl Display for DeviceIdError {
80    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
81        match self {
82            Self::BackendSpecific { err } => err.fmt(f),
83            Self::UnsupportedPlatform => f.write_str("Device IDs are unsupported for this OS"),
84        }
85    }
86}
87
88impl Error for DeviceIdError {}
89
90impl From<BackendSpecificError> for DeviceIdError {
91    fn from(err: BackendSpecificError) -> Self {
92        Self::BackendSpecific { err }
93    }
94}
95
96/// An error that may occur while attempting to retrieve a device name.
97#[derive(Clone, Debug, PartialEq, Eq, Hash)]
98pub enum DeviceNameError {
99    /// See the [`BackendSpecificError`] docs for more information about this error variant.
100    BackendSpecific { err: BackendSpecificError },
101}
102
103impl Display for DeviceNameError {
104    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
105        match self {
106            Self::BackendSpecific { err } => err.fmt(f),
107        }
108    }
109}
110
111impl Error for DeviceNameError {}
112
113impl From<BackendSpecificError> for DeviceNameError {
114    fn from(err: BackendSpecificError) -> Self {
115        Self::BackendSpecific { err }
116    }
117}
118
119/// Error that can happen when enumerating the list of supported formats.
120#[derive(Clone, Debug, PartialEq, Eq, Hash)]
121pub enum SupportedStreamConfigsError {
122    /// The device no longer exists. This can happen if the device is disconnected while the
123    /// program is running.
124    DeviceNotAvailable,
125    /// We called something the C-Layer did not understand
126    InvalidArgument,
127    /// See the [`BackendSpecificError`] docs for more information about this error variant.
128    BackendSpecific { err: BackendSpecificError },
129}
130
131impl Display for SupportedStreamConfigsError {
132    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
133        match self {
134            Self::BackendSpecific { err } => err.fmt(f),
135            Self::DeviceNotAvailable => f.write_str("The requested device is no longer available. For example, it has been unplugged."),
136            Self::InvalidArgument => f.write_str("Invalid argument passed to the backend. For example, this happens when trying to read capture capabilities when the device does not support it.")
137        }
138    }
139}
140
141impl Error for SupportedStreamConfigsError {}
142
143impl From<BackendSpecificError> for SupportedStreamConfigsError {
144    fn from(err: BackendSpecificError) -> Self {
145        Self::BackendSpecific { err }
146    }
147}
148
149/// May occur when attempting to request the default input or output stream format from a [`Device`](crate::Device).
150#[derive(Clone, Debug, PartialEq, Eq, Hash)]
151pub enum DefaultStreamConfigError {
152    /// The device no longer exists. This can happen if the device is disconnected while the
153    /// program is running.
154    DeviceNotAvailable,
155    /// Returned if e.g. the default input format was requested on an output-only audio device.
156    StreamTypeNotSupported,
157    /// See the [`BackendSpecificError`] docs for more information about this error variant.
158    BackendSpecific { err: BackendSpecificError },
159}
160
161impl Display for DefaultStreamConfigError {
162    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
163        match self {
164            Self::BackendSpecific { err } => err.fmt(f),
165            Self::DeviceNotAvailable => f.write_str(
166                "The requested device is no longer available. For example, it has been unplugged.",
167            ),
168            Self::StreamTypeNotSupported => {
169                f.write_str("The requested stream type is not supported by the device.")
170            }
171        }
172    }
173}
174
175impl Error for DefaultStreamConfigError {}
176
177impl From<BackendSpecificError> for DefaultStreamConfigError {
178    fn from(err: BackendSpecificError) -> Self {
179        Self::BackendSpecific { err }
180    }
181}
182/// Error that can happen when creating a [`Stream`](crate::Stream).
183#[derive(Clone, Debug, PartialEq, Eq, Hash)]
184pub enum BuildStreamError {
185    /// The device no longer exists. This can happen if the device is disconnected while the
186    /// program is running.
187    DeviceNotAvailable,
188    /// The specified stream configuration is not supported.
189    StreamConfigNotSupported,
190    /// We called something the C-Layer did not understand
191    ///
192    /// On ALSA device functions called with a feature they do not support will yield this. E.g.
193    /// Trying to use capture capabilities on an output only format yields this.
194    InvalidArgument,
195    /// Occurs if adding a new Stream ID would cause an integer overflow.
196    StreamIdOverflow,
197    /// See the [`BackendSpecificError`] docs for more information about this error variant.
198    BackendSpecific { err: BackendSpecificError },
199}
200
201impl Display for BuildStreamError {
202    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
203        match self {
204            Self::BackendSpecific { err } => err.fmt(f),
205            Self::DeviceNotAvailable => f.write_str(
206                "The requested device is no longer available. For example, it has been unplugged.",
207            ),
208            Self::StreamConfigNotSupported => {
209                f.write_str("The requested stream configuration is not supported by the device.")
210            }
211            Self::InvalidArgument => f.write_str(
212                "The requested device does not support this capability (invalid argument)",
213            ),
214            Self::StreamIdOverflow => f.write_str("Adding a new stream ID would cause an overflow"),
215        }
216    }
217}
218
219impl Error for BuildStreamError {}
220
221impl From<BackendSpecificError> for BuildStreamError {
222    fn from(err: BackendSpecificError) -> Self {
223        Self::BackendSpecific { err }
224    }
225}
226
227/// Errors that might occur when calling [`Stream::play()`](crate::traits::StreamTrait::play).
228///
229/// As of writing this, only macOS may immediately return an error while calling this method. This
230/// is because both the alsa and wasapi backends only enqueue these commands and do not process
231/// them immediately.
232#[derive(Clone, Debug, PartialEq, Eq, Hash)]
233pub enum PlayStreamError {
234    /// The device associated with the stream is no longer available.
235    DeviceNotAvailable,
236    /// See the [`BackendSpecificError`] docs for more information about this error variant.
237    BackendSpecific { err: BackendSpecificError },
238}
239
240impl Display for PlayStreamError {
241    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
242        match self {
243            Self::BackendSpecific { err } => err.fmt(f),
244            Self::DeviceNotAvailable => {
245                f.write_str("the device associated with the stream is no longer available")
246            }
247        }
248    }
249}
250
251impl Error for PlayStreamError {}
252
253impl From<BackendSpecificError> for PlayStreamError {
254    fn from(err: BackendSpecificError) -> Self {
255        Self::BackendSpecific { err }
256    }
257}
258
259/// Errors that might occur when calling [`Stream::pause()`](crate::traits::StreamTrait::pause).
260///
261/// As of writing this, only macOS may immediately return an error while calling this method. This
262/// is because both the alsa and wasapi backends only enqueue these commands and do not process
263/// them immediately.
264#[derive(Clone, Debug, PartialEq, Eq, Hash)]
265pub enum PauseStreamError {
266    /// The device associated with the stream is no longer available.
267    DeviceNotAvailable,
268    /// See the [`BackendSpecificError`] docs for more information about this error variant.
269    BackendSpecific { err: BackendSpecificError },
270}
271
272impl Display for PauseStreamError {
273    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
274        match self {
275            Self::BackendSpecific { err } => err.fmt(f),
276            Self::DeviceNotAvailable => {
277                f.write_str("the device associated with the stream is no longer available")
278            }
279        }
280    }
281}
282
283impl Error for PauseStreamError {}
284
285impl From<BackendSpecificError> for PauseStreamError {
286    fn from(err: BackendSpecificError) -> Self {
287        Self::BackendSpecific { err }
288    }
289}
290
291/// Errors that might occur while a stream is running.
292#[derive(Clone, Debug, PartialEq, Eq, Hash)]
293pub enum StreamError {
294    /// The device no longer exists. This can happen if the device is disconnected while the
295    /// program is running.
296    DeviceNotAvailable,
297
298    /// The stream configuration is no longer valid and must be rebuilt.
299    StreamInvalidated,
300
301    /// Buffer underrun or overrun occurred, causing a potential audio glitch.
302    BufferUnderrun,
303
304    /// See the [`BackendSpecificError`] docs for more information about this error variant.
305    BackendSpecific { err: BackendSpecificError },
306}
307
308impl Display for StreamError {
309    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
310        match self {
311            Self::BackendSpecific { err } => err.fmt(f),
312            Self::StreamInvalidated => {
313                f.write_str("The stream configuration is no longer valid and must be rebuilt.")
314            }
315            Self::BufferUnderrun => f.write_str("Buffer underrun/overrun occurred."),
316            Self::DeviceNotAvailable => f.write_str(
317                "The requested device is no longer available. For example, it has been unplugged.",
318            ),
319        }
320    }
321}
322
323impl Error for StreamError {}
324
325impl From<BackendSpecificError> for StreamError {
326    fn from(err: BackendSpecificError) -> Self {
327        Self::BackendSpecific { err }
328    }
329}