cpal/
lib.rs

1//! # How to use cpal
2//!
3//! Here are some concepts cpal exposes:
4//!
5//! - A [`Host`] provides access to the available audio devices on the system.
6//!   Some platforms have more than one host available, but every platform supported by CPAL has at
7//!   least one [default_host] that is guaranteed to be available.
8//! - A [`Device`] is an audio device that may have any number of input and
9//!   output streams.
10//! - A [`Stream`] is an open flow of audio data. Input streams allow you to
11//!   receive audio data, output streams allow you to play audio data. You must choose which
12//!   [Device] will run your stream before you can create one. Often, a default device can be
13//!   retrieved via the [Host].
14//!
15//! The first step is to initialise the [`Host`]:
16//!
17//! ```
18//! use cpal::traits::HostTrait;
19//! let host = cpal::default_host();
20//! ```
21//!
22//! Then choose an available [`Device`]. The easiest way is to use the default input or output
23//! `Device` via the [`default_input_device()`] or [`default_output_device()`] methods on `host`.
24//!
25//! Alternatively, you can enumerate all the available devices with the [`devices()`] method.
26//! Beware that the `default_*_device()` functions return an `Option<Device>` in case no device
27//! is available for that stream type on the system.
28//!
29//! ```no_run
30//! # use cpal::traits::HostTrait;
31//! # let host = cpal::default_host();
32//! let device = host.default_output_device().expect("no output device available");
33//! ```
34//!
35//! Before we can create a stream, we must decide what the configuration of the audio stream is
36//! going to be.    
37//! You can query all the supported configurations with the
38//! [`supported_input_configs()`] and [`supported_output_configs()`] methods.
39//! These produce a list of [`SupportedStreamConfigRange`] structs which can later be turned into
40//! actual [`SupportedStreamConfig`] structs.
41//!
42//! If you don't want to query the list of configs,
43//! you can also build your own [`StreamConfig`] manually, but doing so could lead to an error when
44//! building the stream if the config is not supported by the device.
45//!
46//! > **Note**: the `supported_input/output_configs()` methods
47//! > could return an error for example if the device has been disconnected.
48//!
49//! ```no_run
50//! use cpal::traits::{DeviceTrait, HostTrait};
51//! # let host = cpal::default_host();
52//! # let device = host.default_output_device().unwrap();
53//! let mut supported_configs_range = device.supported_output_configs()
54//!     .expect("error while querying configs");
55//! let supported_config = supported_configs_range.next()
56//!     .expect("no supported config?!")
57//!     .with_max_sample_rate();
58//! ```
59//!
60//! Now that we have everything for the stream, we are ready to create it from our selected device:
61//!
62//! ```no_run
63//! use cpal::Data;
64//! use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
65//! # let host = cpal::default_host();
66//! # let device = host.default_output_device().unwrap();
67//! # let config = device.default_output_config().unwrap().into();
68//! let stream = device.build_output_stream(
69//!     &config,
70//!     move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
71//!         // react to stream events and read or write stream data here.
72//!     },
73//!     move |err| {
74//!         // react to errors here.
75//!     },
76//!     None // None=blocking, Some(Duration)=timeout
77//! );
78//! ```
79//!
80//! While the stream is running, the selected audio device will periodically call the data callback
81//! that was passed to the function. The callback is passed an instance of either [`&Data` or
82//! `&mut Data`](Data) depending on whether the stream is an input stream or output stream respectively.
83//!
84//! > **Note**: Creating and running a stream will *not* block the thread. On modern platforms, the
85//! > given callback is called by a dedicated, high-priority thread responsible for delivering
86//! > audio data to the system's audio device in a timely manner. On older platforms that only
87//! > provide a blocking API (e.g. ALSA), CPAL will create a thread in order to consistently
88//! > provide non-blocking behaviour (currently this is a thread per stream, but this may change to
89//! > use a single thread for all streams). *If this is an issue for your platform or design,
90//! > please share your issue and use-case with the CPAL team on the GitHub issue tracker for
91//! > consideration.*
92//!
93//! In this example, we simply fill the given output buffer with silence.
94//!
95//! ```no_run
96//! use cpal::{Data, Sample, SampleFormat, FromSample};
97//! use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
98//! # let host = cpal::default_host();
99//! # let device = host.default_output_device().unwrap();
100//! # let supported_config = device.default_output_config().unwrap();
101//! let err_fn = |err| eprintln!("an error occurred on the output audio stream: {}", err);
102//! let sample_format = supported_config.sample_format();
103//! let config = supported_config.into();
104//! let stream = match sample_format {
105//!     SampleFormat::F32 => device.build_output_stream(&config, write_silence::<f32>, err_fn, None),
106//!     SampleFormat::I16 => device.build_output_stream(&config, write_silence::<i16>, err_fn, None),
107//!     SampleFormat::U16 => device.build_output_stream(&config, write_silence::<u16>, err_fn, None),
108//!     sample_format => panic!("Unsupported sample format '{sample_format}'")
109//! }.unwrap();
110//!
111//! fn write_silence<T: Sample>(data: &mut [T], _: &cpal::OutputCallbackInfo) {
112//!     for sample in data.iter_mut() {
113//!         *sample = Sample::EQUILIBRIUM;
114//!     }
115//! }
116//! ```
117//!
118//! Not all platforms automatically run the stream upon creation. To ensure the stream has started,
119//! we can use [`Stream::play`](traits::StreamTrait::play).
120//!
121//! ```no_run
122//! # use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
123//! # let host = cpal::default_host();
124//! # let device = host.default_output_device().unwrap();
125//! # let supported_config = device.default_output_config().unwrap();
126//! # let sample_format = supported_config.sample_format();
127//! # let config = supported_config.into();
128//! # let data_fn = move |_data: &mut cpal::Data, _: &cpal::OutputCallbackInfo| {};
129//! # let err_fn = move |_err| {};
130//! # let stream = device.build_output_stream_raw(&config, sample_format, data_fn, err_fn, None).unwrap();
131//! stream.play().unwrap();
132//! ```
133//!
134//! Some devices support pausing the audio stream. This can be useful for saving energy in moments
135//! of silence.
136//!
137//! ```no_run
138//! # use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
139//! # let host = cpal::default_host();
140//! # let device = host.default_output_device().unwrap();
141//! # let supported_config = device.default_output_config().unwrap();
142//! # let sample_format = supported_config.sample_format();
143//! # let config = supported_config.into();
144//! # let data_fn = move |_data: &mut cpal::Data, _: &cpal::OutputCallbackInfo| {};
145//! # let err_fn = move |_err| {};
146//! # let stream = device.build_output_stream_raw(&config, sample_format, data_fn, err_fn, None).unwrap();
147//! stream.pause().unwrap();
148//! ```
149//!
150//! [`default_input_device()`]: traits::HostTrait::default_input_device
151//! [`default_output_device()`]: traits::HostTrait::default_output_device
152//! [`devices()`]: traits::HostTrait::devices
153//! [`supported_input_configs()`]: traits::DeviceTrait::supported_input_configs
154//! [`supported_output_configs()`]: traits::DeviceTrait::supported_output_configs
155
156#![recursion_limit = "2048"]
157
158// Extern crate declarations with `#[macro_use]` must unfortunately be at crate root.
159#[cfg(target_os = "emscripten")]
160#[macro_use]
161extern crate wasm_bindgen;
162#[cfg(target_os = "emscripten")]
163extern crate js_sys;
164#[cfg(target_os = "emscripten")]
165extern crate web_sys;
166
167pub use error::*;
168pub use platform::{
169    available_hosts, default_host, host_from_id, Device, Devices, Host, HostId, Stream,
170    SupportedInputConfigs, SupportedOutputConfigs, ALL_HOSTS,
171};
172pub use samples_formats::{FromSample, Sample, SampleFormat, SizedSample, I24, I48, U24, U48};
173use std::convert::TryInto;
174use std::ops::{Div, Mul};
175use std::time::Duration;
176#[cfg(target_os = "emscripten")]
177use wasm_bindgen::prelude::*;
178
179mod error;
180mod host;
181pub mod platform;
182mod samples_formats;
183pub mod traits;
184
185/// A host's device iterator yielding only *input* devices.
186pub type InputDevices<I> = std::iter::Filter<I, fn(&<I as Iterator>::Item) -> bool>;
187
188/// A host's device iterator yielding only *output* devices.
189pub type OutputDevices<I> = std::iter::Filter<I, fn(&<I as Iterator>::Item) -> bool>;
190
191/// Number of channels.
192pub type ChannelCount = u16;
193
194/// The number of samples processed per second for a single channel of audio.
195#[cfg_attr(target_os = "emscripten", wasm_bindgen)]
196#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
197pub struct SampleRate(pub u32);
198
199impl<T> Mul<T> for SampleRate
200where
201    u32: Mul<T, Output = u32>,
202{
203    type Output = Self;
204    fn mul(self, rhs: T) -> Self {
205        SampleRate(self.0 * rhs)
206    }
207}
208
209impl<T> Div<T> for SampleRate
210where
211    u32: Div<T, Output = u32>,
212{
213    type Output = Self;
214    fn div(self, rhs: T) -> Self {
215        SampleRate(self.0 / rhs)
216    }
217}
218
219/// The desired number of frames for the hardware buffer.
220pub type FrameCount = u32;
221
222/// The buffer size used by the device.
223///
224/// [`Default`] is used when no specific buffer size is set and uses the default
225/// behavior of the given host. Note, the default buffer size may be surprisingly
226/// large, leading to latency issues. If low latency is desired, [`Fixed(FrameCount)`]
227/// should be used in accordance with the [`SupportedBufferSize`] range produced by
228/// the [`SupportedStreamConfig`] API.  
229///
230/// [`Default`]: BufferSize::Default
231/// [`Fixed(FrameCount)`]: BufferSize::Fixed
232/// [`SupportedStreamConfig`]: SupportedStreamConfig::buffer_size
233#[derive(Clone, Copy, Debug, Eq, PartialEq)]
234pub enum BufferSize {
235    Default,
236    Fixed(FrameCount),
237}
238
239#[cfg(target_os = "emscripten")]
240impl wasm_bindgen::describe::WasmDescribe for BufferSize {
241    fn describe() {}
242}
243
244#[cfg(target_os = "emscripten")]
245impl wasm_bindgen::convert::IntoWasmAbi for BufferSize {
246    type Abi = Option<u32>;
247    fn into_abi(self) -> Self::Abi {
248        match self {
249            Self::Default => None,
250            Self::Fixed(fc) => Some(fc),
251        }
252        .into_abi()
253    }
254}
255
256/// The set of parameters used to describe how to open a stream.
257///
258/// The sample format is omitted in favour of using a sample type.
259#[cfg_attr(target_os = "emscripten", wasm_bindgen)]
260#[derive(Clone, Debug, Eq, PartialEq)]
261pub struct StreamConfig {
262    pub channels: ChannelCount,
263    pub sample_rate: SampleRate,
264    pub buffer_size: BufferSize,
265}
266
267/// Describes the minimum and maximum supported buffer size for the device
268#[derive(Clone, Copy, Debug, Eq, PartialEq)]
269pub enum SupportedBufferSize {
270    Range {
271        min: FrameCount,
272        max: FrameCount,
273    },
274    /// In the case that the platform provides no way of getting the default
275    /// buffersize before starting a stream.
276    Unknown,
277}
278
279/// Describes a range of supported stream configurations, retrieved via the
280/// [`Device::supported_input/output_configs`](traits::DeviceTrait#required-methods) method.
281#[derive(Debug, Clone, Copy, PartialEq, Eq)]
282pub struct SupportedStreamConfigRange {
283    pub(crate) channels: ChannelCount,
284    /// Minimum value for the samples rate of the supported formats.
285    pub(crate) min_sample_rate: SampleRate,
286    /// Maximum value for the samples rate of the supported formats.
287    pub(crate) max_sample_rate: SampleRate,
288    /// Buffersize ranges supported by the device
289    pub(crate) buffer_size: SupportedBufferSize,
290    /// Type of data expected by the device.
291    pub(crate) sample_format: SampleFormat,
292}
293
294/// Describes a single supported stream configuration, retrieved via either a
295/// [`SupportedStreamConfigRange`] instance or one of the
296/// [`Device::default_input/output_config`](traits::DeviceTrait#required-methods) methods.
297#[derive(Debug, Clone, PartialEq, Eq)]
298pub struct SupportedStreamConfig {
299    channels: ChannelCount,
300    sample_rate: SampleRate,
301    buffer_size: SupportedBufferSize,
302    sample_format: SampleFormat,
303}
304
305/// A buffer of dynamically typed audio data, passed to raw stream callbacks.
306///
307/// Raw input stream callbacks receive `&Data`, while raw output stream callbacks expect `&mut
308/// Data`.
309#[cfg_attr(target_os = "emscripten", wasm_bindgen)]
310#[derive(Debug)]
311pub struct Data {
312    data: *mut (),
313    len: usize,
314    sample_format: SampleFormat,
315}
316
317/// A monotonic time instance associated with a stream, retrieved from either:
318///
319/// 1. A timestamp provided to the stream's underlying audio data callback or
320/// 2. The same time source used to generate timestamps for a stream's underlying audio data
321///    callback.
322///
323/// `StreamInstant` represents a duration since some unspecified origin occurring either before
324/// or equal to the moment the stream from which it was created begins.
325///
326/// ## Host `StreamInstant` Sources
327///
328/// | Host | Source |
329/// | ---- | ------ |
330/// | alsa | `snd_pcm_status_get_htstamp` |
331/// | coreaudio | `mach_absolute_time` |
332/// | wasapi | `QueryPerformanceCounter` |
333/// | asio | `timeGetTime` |
334/// | emscripten | `AudioContext.getOutputTimestamp` |
335#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
336pub struct StreamInstant {
337    secs: i64,
338    nanos: u32,
339}
340
341/// A timestamp associated with a call to an input stream's data callback.
342#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
343pub struct InputStreamTimestamp {
344    /// The instant the stream's data callback was invoked.
345    pub callback: StreamInstant,
346    /// The instant that data was captured from the device.
347    ///
348    /// E.g. The instant data was read from an ADC.
349    pub capture: StreamInstant,
350}
351
352/// A timestamp associated with a call to an output stream's data callback.
353#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
354pub struct OutputStreamTimestamp {
355    /// The instant the stream's data callback was invoked.
356    pub callback: StreamInstant,
357    /// The predicted instant that data written will be delivered to the device for playback.
358    ///
359    /// E.g. The instant data will be played by a DAC.
360    pub playback: StreamInstant,
361}
362
363/// Information relevant to a single call to the user's input stream data callback.
364#[derive(Debug, Clone, PartialEq, Eq)]
365pub struct InputCallbackInfo {
366    timestamp: InputStreamTimestamp,
367}
368
369/// Information relevant to a single call to the user's output stream data callback.
370#[cfg_attr(target_os = "emscripten", wasm_bindgen)]
371#[derive(Debug, Clone, PartialEq, Eq)]
372pub struct OutputCallbackInfo {
373    timestamp: OutputStreamTimestamp,
374}
375
376impl SupportedStreamConfig {
377    pub fn new(
378        channels: ChannelCount,
379        sample_rate: SampleRate,
380        buffer_size: SupportedBufferSize,
381        sample_format: SampleFormat,
382    ) -> Self {
383        Self {
384            channels,
385            sample_rate,
386            buffer_size,
387            sample_format,
388        }
389    }
390
391    pub fn channels(&self) -> ChannelCount {
392        self.channels
393    }
394
395    pub fn sample_rate(&self) -> SampleRate {
396        self.sample_rate
397    }
398
399    pub fn buffer_size(&self) -> &SupportedBufferSize {
400        &self.buffer_size
401    }
402
403    pub fn sample_format(&self) -> SampleFormat {
404        self.sample_format
405    }
406
407    pub fn config(&self) -> StreamConfig {
408        StreamConfig {
409            channels: self.channels,
410            sample_rate: self.sample_rate,
411            buffer_size: BufferSize::Default,
412        }
413    }
414}
415
416impl StreamInstant {
417    /// The amount of time elapsed from another instant to this one.
418    ///
419    /// Returns `None` if `earlier` is later than self.
420    pub fn duration_since(&self, earlier: &Self) -> Option<Duration> {
421        if self < earlier {
422            None
423        } else {
424            (self.as_nanos() - earlier.as_nanos())
425                .try_into()
426                .ok()
427                .map(Duration::from_nanos)
428        }
429    }
430
431    /// Returns the instant in time after the given duration has passed.
432    ///
433    /// Returns `None` if the resulting instant would exceed the bounds of the underlying data
434    /// structure.
435    pub fn add(&self, duration: Duration) -> Option<Self> {
436        self.as_nanos()
437            .checked_add(duration.as_nanos() as i128)
438            .and_then(Self::from_nanos_i128)
439    }
440
441    /// Returns the instant in time one `duration` ago.
442    ///
443    /// Returns `None` if the resulting instant would underflow. As a result, it is important to
444    /// consider that on some platforms the [`StreamInstant`] may begin at `0` from the moment the
445    /// source stream is created.
446    pub fn sub(&self, duration: Duration) -> Option<Self> {
447        self.as_nanos()
448            .checked_sub(duration.as_nanos() as i128)
449            .and_then(Self::from_nanos_i128)
450    }
451
452    fn as_nanos(&self) -> i128 {
453        (self.secs as i128 * 1_000_000_000) + self.nanos as i128
454    }
455
456    #[allow(dead_code)]
457    fn from_nanos(nanos: i64) -> Self {
458        let secs = nanos / 1_000_000_000;
459        let subsec_nanos = nanos - secs * 1_000_000_000;
460        Self::new(secs, subsec_nanos as u32)
461    }
462
463    #[allow(dead_code)]
464    fn from_nanos_i128(nanos: i128) -> Option<Self> {
465        let secs = nanos / 1_000_000_000;
466        if secs > i64::MAX as i128 || secs < i64::MIN as i128 {
467            None
468        } else {
469            let subsec_nanos = nanos - secs * 1_000_000_000;
470            debug_assert!(subsec_nanos < u32::MAX as i128);
471            Some(Self::new(secs as i64, subsec_nanos as u32))
472        }
473    }
474
475    #[allow(dead_code)]
476    fn from_secs_f64(secs: f64) -> crate::StreamInstant {
477        let s = secs.floor() as i64;
478        let ns = ((secs - s as f64) * 1_000_000_000.0) as u32;
479        Self::new(s, ns)
480    }
481
482    fn new(secs: i64, nanos: u32) -> Self {
483        StreamInstant { secs, nanos }
484    }
485}
486
487impl InputCallbackInfo {
488    /// The timestamp associated with the call to an input stream's data callback.
489    pub fn timestamp(&self) -> InputStreamTimestamp {
490        self.timestamp
491    }
492}
493
494impl OutputCallbackInfo {
495    /// The timestamp associated with the call to an output stream's data callback.
496    pub fn timestamp(&self) -> OutputStreamTimestamp {
497        self.timestamp
498    }
499}
500
501#[allow(clippy::len_without_is_empty)]
502impl Data {
503    // Internal constructor for host implementations to use.
504    //
505    // The following requirements must be met in order for the safety of `Data`'s public API.
506    //
507    // - The `data` pointer must point to the first sample in the slice containing all samples.
508    // - The `len` must describe the length of the buffer as a number of samples in the expected
509    //   format specified via the `sample_format` argument.
510    // - The `sample_format` must correctly represent the underlying sample data delivered/expected
511    //   by the stream.
512    pub(crate) unsafe fn from_parts(
513        data: *mut (),
514        len: usize,
515        sample_format: SampleFormat,
516    ) -> Self {
517        Data {
518            data,
519            len,
520            sample_format,
521        }
522    }
523
524    /// The sample format of the internal audio data.
525    pub fn sample_format(&self) -> SampleFormat {
526        self.sample_format
527    }
528
529    /// The full length of the buffer in samples.
530    ///
531    /// The returned length is the same length as the slice of type `T` that would be returned via
532    /// [`as_slice`](Self::as_slice) given a sample type that matches the inner sample format.
533    pub fn len(&self) -> usize {
534        self.len
535    }
536
537    /// The raw slice of memory representing the underlying audio data as a slice of bytes.
538    ///
539    /// It is up to the user to interpret the slice of memory based on [`Data::sample_format`].
540    pub fn bytes(&self) -> &[u8] {
541        let len = self.len * self.sample_format.sample_size();
542        // The safety of this block relies on correct construction of the `Data` instance.
543        // See the unsafe `from_parts` constructor for these requirements.
544        unsafe { std::slice::from_raw_parts(self.data as *const u8, len) }
545    }
546
547    /// The raw slice of memory representing the underlying audio data as a slice of bytes.
548    ///
549    /// It is up to the user to interpret the slice of memory based on [`Data::sample_format`].
550    pub fn bytes_mut(&mut self) -> &mut [u8] {
551        let len = self.len * self.sample_format.sample_size();
552        // The safety of this block relies on correct construction of the `Data` instance. See
553        // the unsafe `from_parts` constructor for these requirements.
554        unsafe { std::slice::from_raw_parts_mut(self.data as *mut u8, len) }
555    }
556
557    /// Access the data as a slice of sample type `T`.
558    ///
559    /// Returns `None` if the sample type does not match the expected sample format.
560    pub fn as_slice<T>(&self) -> Option<&[T]>
561    where
562        T: SizedSample,
563    {
564        if T::FORMAT == self.sample_format {
565            // The safety of this block relies on correct construction of the `Data` instance. See
566            // the unsafe `from_parts` constructor for these requirements.
567            unsafe { Some(std::slice::from_raw_parts(self.data as *const T, self.len)) }
568        } else {
569            None
570        }
571    }
572
573    /// Access the data as a slice of sample type `T`.
574    ///
575    /// Returns `None` if the sample type does not match the expected sample format.
576    pub fn as_slice_mut<T>(&mut self) -> Option<&mut [T]>
577    where
578        T: SizedSample,
579    {
580        if T::FORMAT == self.sample_format {
581            // The safety of this block relies on correct construction of the `Data` instance. See
582            // the unsafe `from_parts` constructor for these requirements.
583            unsafe {
584                Some(std::slice::from_raw_parts_mut(
585                    self.data as *mut T,
586                    self.len,
587                ))
588            }
589        } else {
590            None
591        }
592    }
593}
594
595impl SupportedStreamConfigRange {
596    pub fn new(
597        channels: ChannelCount,
598        min_sample_rate: SampleRate,
599        max_sample_rate: SampleRate,
600        buffer_size: SupportedBufferSize,
601        sample_format: SampleFormat,
602    ) -> Self {
603        Self {
604            channels,
605            min_sample_rate,
606            max_sample_rate,
607            buffer_size,
608            sample_format,
609        }
610    }
611
612    pub fn channels(&self) -> ChannelCount {
613        self.channels
614    }
615
616    pub fn min_sample_rate(&self) -> SampleRate {
617        self.min_sample_rate
618    }
619
620    pub fn max_sample_rate(&self) -> SampleRate {
621        self.max_sample_rate
622    }
623
624    pub fn buffer_size(&self) -> &SupportedBufferSize {
625        &self.buffer_size
626    }
627
628    pub fn sample_format(&self) -> SampleFormat {
629        self.sample_format
630    }
631
632    /// Retrieve a [`SupportedStreamConfig`] with the given sample rate and buffer size.
633    ///
634    /// # Panics
635    ///
636    /// Panics if the given `sample_rate` is outside the range specified within
637    /// this [`SupportedStreamConfigRange`] instance. For a non-panicking
638    /// variant, use [`try_with_sample_rate`](#method.try_with_sample_rate).
639    pub fn with_sample_rate(self, sample_rate: SampleRate) -> SupportedStreamConfig {
640        self.try_with_sample_rate(sample_rate)
641            .expect("sample rate out of range")
642    }
643
644    /// Retrieve a [`SupportedStreamConfig`] with the given sample rate and buffer size.
645    ///
646    /// Returns `None` if the given sample rate is outside the range specified
647    /// within this [`SupportedStreamConfigRange`] instance.
648    pub fn try_with_sample_rate(self, sample_rate: SampleRate) -> Option<SupportedStreamConfig> {
649        if self.min_sample_rate <= sample_rate && sample_rate <= self.max_sample_rate {
650            Some(SupportedStreamConfig {
651                channels: self.channels,
652                sample_rate,
653                sample_format: self.sample_format,
654                buffer_size: self.buffer_size,
655            })
656        } else {
657            None
658        }
659    }
660
661    /// Turns this [`SupportedStreamConfigRange`] into a [`SupportedStreamConfig`] corresponding to the maximum samples rate.
662    #[inline]
663    pub fn with_max_sample_rate(self) -> SupportedStreamConfig {
664        SupportedStreamConfig {
665            channels: self.channels,
666            sample_rate: self.max_sample_rate,
667            sample_format: self.sample_format,
668            buffer_size: self.buffer_size,
669        }
670    }
671
672    /// A comparison function which compares two [`SupportedStreamConfigRange`]s in terms of their priority of
673    /// use as a default stream format.
674    ///
675    /// Some backends do not provide a default stream format for their audio devices. In these
676    /// cases, CPAL attempts to decide on a reasonable default format for the user. To do this we
677    /// use the "greatest" of all supported stream formats when compared with this method.
678    ///
679    /// SupportedStreamConfigs are prioritised by the following heuristics:
680    ///
681    /// **Channels**:
682    ///
683    /// - Stereo
684    /// - Mono
685    /// - Max available channels
686    ///
687    /// **Sample format**:
688    /// - f32
689    /// - i16
690    /// - u16
691    ///
692    /// **Sample rate**:
693    ///
694    /// - 44100 (cd quality)
695    /// - Max sample rate
696    pub fn cmp_default_heuristics(&self, other: &Self) -> std::cmp::Ordering {
697        use std::cmp::Ordering::Equal;
698        use SampleFormat::{F32, I16, U16};
699
700        let cmp_stereo = (self.channels == 2).cmp(&(other.channels == 2));
701        if cmp_stereo != Equal {
702            return cmp_stereo;
703        }
704
705        let cmp_mono = (self.channels == 1).cmp(&(other.channels == 1));
706        if cmp_mono != Equal {
707            return cmp_mono;
708        }
709
710        let cmp_channels = self.channels.cmp(&other.channels);
711        if cmp_channels != Equal {
712            return cmp_channels;
713        }
714
715        let cmp_f32 = (self.sample_format == F32).cmp(&(other.sample_format == F32));
716        if cmp_f32 != Equal {
717            return cmp_f32;
718        }
719
720        let cmp_i16 = (self.sample_format == I16).cmp(&(other.sample_format == I16));
721        if cmp_i16 != Equal {
722            return cmp_i16;
723        }
724
725        let cmp_u16 = (self.sample_format == U16).cmp(&(other.sample_format == U16));
726        if cmp_u16 != Equal {
727            return cmp_u16;
728        }
729
730        const HZ_44100: SampleRate = SampleRate(44_100);
731        let r44100_in_self = self.min_sample_rate <= HZ_44100 && HZ_44100 <= self.max_sample_rate;
732        let r44100_in_other =
733            other.min_sample_rate <= HZ_44100 && HZ_44100 <= other.max_sample_rate;
734        let cmp_r44100 = r44100_in_self.cmp(&r44100_in_other);
735        if cmp_r44100 != Equal {
736            return cmp_r44100;
737        }
738
739        self.max_sample_rate.cmp(&other.max_sample_rate)
740    }
741}
742
743#[test]
744fn test_cmp_default_heuristics() {
745    let mut formats = [
746        SupportedStreamConfigRange {
747            buffer_size: SupportedBufferSize::Range { min: 256, max: 512 },
748            channels: 2,
749            min_sample_rate: SampleRate(1),
750            max_sample_rate: SampleRate(96000),
751            sample_format: SampleFormat::F32,
752        },
753        SupportedStreamConfigRange {
754            buffer_size: SupportedBufferSize::Range { min: 256, max: 512 },
755            channels: 1,
756            min_sample_rate: SampleRate(1),
757            max_sample_rate: SampleRate(96000),
758            sample_format: SampleFormat::F32,
759        },
760        SupportedStreamConfigRange {
761            buffer_size: SupportedBufferSize::Range { min: 256, max: 512 },
762            channels: 2,
763            min_sample_rate: SampleRate(1),
764            max_sample_rate: SampleRate(96000),
765            sample_format: SampleFormat::I16,
766        },
767        SupportedStreamConfigRange {
768            buffer_size: SupportedBufferSize::Range { min: 256, max: 512 },
769            channels: 2,
770            min_sample_rate: SampleRate(1),
771            max_sample_rate: SampleRate(96000),
772            sample_format: SampleFormat::U16,
773        },
774        SupportedStreamConfigRange {
775            buffer_size: SupportedBufferSize::Range { min: 256, max: 512 },
776            channels: 2,
777            min_sample_rate: SampleRate(1),
778            max_sample_rate: SampleRate(22050),
779            sample_format: SampleFormat::F32,
780        },
781    ];
782
783    formats.sort_by(|a, b| a.cmp_default_heuristics(b));
784
785    // lowest-priority first:
786    assert_eq!(formats[0].sample_format(), SampleFormat::F32);
787    assert_eq!(formats[0].min_sample_rate(), SampleRate(1));
788    assert_eq!(formats[0].max_sample_rate(), SampleRate(96000));
789    assert_eq!(formats[0].channels(), 1);
790
791    assert_eq!(formats[1].sample_format(), SampleFormat::U16);
792    assert_eq!(formats[1].min_sample_rate(), SampleRate(1));
793    assert_eq!(formats[1].max_sample_rate(), SampleRate(96000));
794    assert_eq!(formats[1].channels(), 2);
795
796    assert_eq!(formats[2].sample_format(), SampleFormat::I16);
797    assert_eq!(formats[2].min_sample_rate(), SampleRate(1));
798    assert_eq!(formats[2].max_sample_rate(), SampleRate(96000));
799    assert_eq!(formats[2].channels(), 2);
800
801    assert_eq!(formats[3].sample_format(), SampleFormat::F32);
802    assert_eq!(formats[3].min_sample_rate(), SampleRate(1));
803    assert_eq!(formats[3].max_sample_rate(), SampleRate(22050));
804    assert_eq!(formats[3].channels(), 2);
805
806    assert_eq!(formats[4].sample_format(), SampleFormat::F32);
807    assert_eq!(formats[4].min_sample_rate(), SampleRate(1));
808    assert_eq!(formats[4].max_sample_rate(), SampleRate(96000));
809    assert_eq!(formats[4].channels(), 2);
810}
811
812impl From<SupportedStreamConfig> for StreamConfig {
813    fn from(conf: SupportedStreamConfig) -> Self {
814        conf.config()
815    }
816}
817
818// If a backend does not provide an API for retrieving supported formats, we query it with a bunch
819// of commonly used rates. This is always the case for wasapi and is sometimes the case for alsa.
820//
821// If a rate you desire is missing from this list, feel free to add it!
822#[cfg(target_os = "windows")]
823const COMMON_SAMPLE_RATES: &[SampleRate] = &[
824    SampleRate(5512),
825    SampleRate(8000),
826    SampleRate(11025),
827    SampleRate(16000),
828    SampleRate(22050),
829    SampleRate(32000),
830    SampleRate(44100),
831    SampleRate(48000),
832    SampleRate(64000),
833    SampleRate(88200),
834    SampleRate(96000),
835    SampleRate(176400),
836    SampleRate(192000),
837];
838
839#[test]
840fn test_stream_instant() {
841    let a = StreamInstant::new(2, 0);
842    let b = StreamInstant::new(-2, 0);
843    let min = StreamInstant::new(i64::MIN, 0);
844    let max = StreamInstant::new(i64::MAX, 0);
845    assert_eq!(
846        a.sub(Duration::from_secs(1)),
847        Some(StreamInstant::new(1, 0))
848    );
849    assert_eq!(
850        a.sub(Duration::from_secs(2)),
851        Some(StreamInstant::new(0, 0))
852    );
853    assert_eq!(
854        a.sub(Duration::from_secs(3)),
855        Some(StreamInstant::new(-1, 0))
856    );
857    assert_eq!(min.sub(Duration::from_secs(1)), None);
858    assert_eq!(
859        b.add(Duration::from_secs(1)),
860        Some(StreamInstant::new(-1, 0))
861    );
862    assert_eq!(
863        b.add(Duration::from_secs(2)),
864        Some(StreamInstant::new(0, 0))
865    );
866    assert_eq!(
867        b.add(Duration::from_secs(3)),
868        Some(StreamInstant::new(1, 0))
869    );
870    assert_eq!(max.add(Duration::from_secs(1)), None);
871}