From 87949d859bb5682d54c63714a3e5c7e3801b59bd Mon Sep 17 00:00:00 2001 From: tomaka Date: Fri, 20 Oct 2017 21:18:40 +0200 Subject: [PATCH] Add SupportedFormat (#168) --- CHANGELOG.md | 2 ++ examples/beep.rs | 3 ++- src/alsa/mod.rs | 29 ++++++++++++++------------- src/coreaudio/enumerate.rs | 3 ++- src/coreaudio/mod.rs | 6 ++++-- src/emscripten/mod.rs | 8 +++++--- src/lib.rs | 40 +++++++++++++++++++++++++++++++++++--- src/null/mod.rs | 5 +++-- src/wasapi/endpoint.rs | 9 +++++---- 9 files changed, 75 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34b1f40..ebc5685 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,3 +6,5 @@ and `EventLoop::pause` that can be used to create, destroy, play and pause voices. - Added a `VoiceId` struct that is now used to identify a voice owned by an `EventLoop`. - Changed `EventLoop::run()` to take a callback that is called whenever a voice requires sound data. +- Changed `supported_formats()` to produce a list of `SupportedFormat` instead of `Format`. A + `SupportedFormat` must then be turned into a `Format` in order to build a voice. diff --git a/examples/beep.rs b/examples/beep.rs index 4237497..579a92a 100644 --- a/examples/beep.rs +++ b/examples/beep.rs @@ -6,7 +6,8 @@ fn main() { .supported_formats() .unwrap() .next() - .expect("Failed to get endpoint format"); + .expect("Failed to get endpoint format") + .with_max_samples_rate(); let event_loop = cpal::EventLoop::new(); let voice_id = event_loop.build_voice(&endpoint, &format).unwrap(); diff --git a/src/alsa/mod.rs b/src/alsa/mod.rs index ec3069f..17e0d2a 100644 --- a/src/alsa/mod.rs +++ b/src/alsa/mod.rs @@ -9,6 +9,7 @@ use Format; use FormatsEnumerationError; use SampleFormat; use SamplesRate; +use SupportedFormat; use UnknownTypeBuffer; use std::{cmp, ffi, iter, mem, ptr}; @@ -16,7 +17,7 @@ use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::vec::IntoIter as VecIntoIter; -pub type SupportedFormatsIterator = VecIntoIter; +pub type SupportedFormatsIterator = VecIntoIter; mod enumerate; @@ -152,10 +153,9 @@ impl Endpoint { .expect("unable to get maximum supported rate"); let samples_rates = if min_rate == max_rate { - vec![min_rate] - /*} else if alsa::snd_pcm_hw_params_test_rate(playback_handle, hw_params.0, min_rate + 1, 0) == 0 { - (min_rate .. max_rate + 1).collect()*/ - // TODO: code is correct but returns lots of stuff + vec![(min_rate, max_rate)] + } else if alsa::snd_pcm_hw_params_test_rate(playback_handle, hw_params.0, min_rate + 1, 0) == 0 { + vec![(min_rate, max_rate)] } else { const RATES: [libc::c_uint; 13] = [ 5512, @@ -180,15 +180,15 @@ impl Endpoint { rate, 0) == 0 { - rates.push(rate); + rates.push((rate, rate)); } } - /*if rates.len() == 0 { - (min_rate .. max_rate + 1).collect() - } else {*/ - rates // TODO: code is correct but returns lots of stuff - //} + if rates.len() == 0 { + vec![(min_rate, max_rate)] + } else { + rates + } }; let mut min_channels = mem::uninitialized(); @@ -227,10 +227,11 @@ impl Endpoint { samples_rates.len()); for &data_type in supported_formats.iter() { for channels in supported_channels.iter() { - for &rate in samples_rates.iter() { - output.push(Format { + for &(min_rate, max_rate) in samples_rates.iter() { + output.push(SupportedFormat { channels: channels.clone(), - samples_rate: SamplesRate(rate as u32), + min_samples_rate: SamplesRate(min_rate as u32), + max_samples_rate: SamplesRate(max_rate as u32), data_type: data_type, }); } diff --git a/src/coreaudio/enumerate.rs b/src/coreaudio/enumerate.rs index ea7c20f..93fc527 100644 --- a/src/coreaudio/enumerate.rs +++ b/src/coreaudio/enumerate.rs @@ -1,6 +1,7 @@ use super::Endpoint; use Format; +use SupportedFormat; use std::vec::IntoIter as VecIntoIter; @@ -33,4 +34,4 @@ pub fn default_endpoint() -> Option { Some(Endpoint) } -pub type SupportedFormatsIterator = VecIntoIter; +pub type SupportedFormatsIterator = VecIntoIter; diff --git a/src/coreaudio/mod.rs b/src/coreaudio/mod.rs index e816f06..2740e25 100644 --- a/src/coreaudio/mod.rs +++ b/src/coreaudio/mod.rs @@ -7,6 +7,7 @@ use FormatsEnumerationError; use Sample; use SampleFormat; use SamplesRate; +use SupportedFormat; use UnknownTypeBuffer; use std::mem; @@ -30,9 +31,10 @@ impl Endpoint { -> Result { Ok( vec![ - Format { + SupportedFormat { channels: vec![ChannelPosition::FrontLeft, ChannelPosition::FrontRight], - samples_rate: SamplesRate(44100), + min_samples_rate: SamplesRate(44100), + max_samples_rate: SamplesRate(44100), data_type: SampleFormat::F32, }, ].into_iter(), diff --git a/src/emscripten/mod.rs b/src/emscripten/mod.rs index 0b38a47..3c8aed8 100644 --- a/src/emscripten/mod.rs +++ b/src/emscripten/mod.rs @@ -7,6 +7,7 @@ use CreationError; use Format; use FormatsEnumerationError; use Sample; +use SupportedFormat; use UnknownTypeBuffer; extern { @@ -182,9 +183,10 @@ impl Endpoint { // TODO: right now cpal's API doesn't allow flexibility here // "44100" and "2" (channels) have also been hard-coded in the rest of the code ; if // this ever becomes more flexible, don't forget to change that - Ok(vec![Format { + Ok(vec![SupportedFormat { channels: vec![::ChannelPosition::BackLeft, ::ChannelPosition::BackRight], - samples_rate: ::SamplesRate(44100), + min_samples_rate: ::SamplesRate(44100), + max_samples_rate: ::SamplesRate(44100), data_type: ::SampleFormat::F32, }].into_iter()) } @@ -195,7 +197,7 @@ impl Endpoint { } } -pub type SupportedFormatsIterator = ::std::vec::IntoIter; +pub type SupportedFormatsIterator = ::std::vec::IntoIter; pub struct Buffer<'a, T: 'a> where T: Sample { temporary_buffer: Vec, diff --git a/src/lib.rs b/src/lib.rs index d92a378..cf36c9f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,8 @@ let endpoint = cpal::default_endpoint().unwrap(); // a `Result` to handle this situation // getting a format for the PCM -let format = endpoint.supported_formats().unwrap().next().unwrap(); +let supported_formats_range = endpoint.supported_formats().unwrap().next().unwrap(); +let format = supported_formats_range.with_max_samples_rate(); let event_loop = cpal::EventLoop::new(); @@ -188,10 +189,10 @@ pub struct Format { pub struct SupportedFormatsIterator(cpal_impl::SupportedFormatsIterator); impl Iterator for SupportedFormatsIterator { - type Item = Format; + type Item = SupportedFormat; #[inline] - fn next(&mut self) -> Option { + fn next(&mut self) -> Option { self.0.next() } @@ -201,6 +202,39 @@ impl Iterator for SupportedFormatsIterator { } } +/// Describes a format. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SupportedFormat { + pub channels: Vec, + pub min_samples_rate: SamplesRate, + pub max_samples_rate: SamplesRate, + pub data_type: SampleFormat, +} + +impl SupportedFormat { + /// Builds a corresponding `Format` corresponding to the maximum samples rate. + #[inline] + pub fn with_max_samples_rate(self) -> Format { + Format { + channels: self.channels, + samples_rate: self.max_samples_rate, + data_type: self.data_type, + } + } +} + +impl From for SupportedFormat { + #[inline] + fn from(format: Format) -> SupportedFormat { + SupportedFormat { + channels: format.channels, + min_samples_rate: format.samples_rate, + max_samples_rate: format.samples_rate, + data_type: format.data_type, + } + } +} + pub struct EventLoop(cpal_impl::EventLoop); impl EventLoop { diff --git a/src/null/mod.rs b/src/null/mod.rs index 4d3fb34..faa6977 100644 --- a/src/null/mod.rs +++ b/src/null/mod.rs @@ -5,6 +5,7 @@ use std::marker::PhantomData; use CreationError; use Format; use FormatsEnumerationError; +use SupportedFormat; use UnknownTypeBuffer; pub struct EventLoop; @@ -84,10 +85,10 @@ impl Endpoint { pub struct SupportedFormatsIterator; impl Iterator for SupportedFormatsIterator { - type Item = Format; + type Item = SupportedFormat; #[inline] - fn next(&mut self) -> Option { + fn next(&mut self) -> Option { None } } diff --git a/src/wasapi/endpoint.rs b/src/wasapi/endpoint.rs index c130adc..15d143a 100644 --- a/src/wasapi/endpoint.rs +++ b/src/wasapi/endpoint.rs @@ -8,17 +8,17 @@ use std::slice; use std::sync::{Arc, Mutex, MutexGuard}; use ChannelPosition; -use Format; use FormatsEnumerationError; use SampleFormat; use SamplesRate; +use SupportedFormat; use super::check_result; use super::com; use super::ole32; use super::winapi; -pub type SupportedFormatsIterator = OptionIntoIter; +pub type SupportedFormatsIterator = OptionIntoIter; /// Wrapper because of that stupid decision to remove `Send` and `Sync` from raw pointers. #[derive(Copy, Clone)] @@ -236,9 +236,10 @@ impl Endpoint { f => panic!("Unknown data format returned by GetMixFormat: {:?}", f), }; - Format { + SupportedFormat { channels: channels, - samples_rate: SamplesRate((*format_ptr).nSamplesPerSec), + min_samples_rate: SamplesRate((*format_ptr).nSamplesPerSec), + max_samples_rate: SamplesRate((*format_ptr).nSamplesPerSec), data_type: data_type, } };