Opening a stream with the default input config is unsupported
I'm trying to open an basic audio input stream, but can't seem to find any config that works, including any of the configurations that the device claims to support. Sample code is attached.
Mac OS 12.3 / CPAL 0.15.3 / Rust 1.60
Output:
Device: Ok("Scarlett Solo USB")
Config: StreamConfig { channels: 2, sample_rate: SampleRate(48000), buffer_size: Default }
thread 'main' panicked at 'Invalid stream: StreamConfigNotSupported', src/main.rs:23:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
use cpal::traits::DeviceTrait;
use cpal::traits::HostTrait;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let host = cpal::default_host();
let device = host
.default_input_device()
.expect("No default input device");
println!("Device: {:?}", device.name());
let config = device
.default_input_config()
.expect("No default input config")
.config();
println!("Config: {:?}", config);
let stream = device
.build_input_stream(&config, |data: &[i16], callback_info| {}, |error| {})
.expect("Invalid stream");
Ok(())
}
Hi @leecbaker, have you tried using something other than &[i16] for the callback? I tried your example and it panicked, but the same code with &[f32] worked.
Hi @ed-bassett , that does work, but I do need i16 data (which is a supported output format for the mac).
It looks like the problem is that CPAL hardcodes the mac platform to only use f32 data types: https://github.com/RustAudio/cpal/blob/b1457e5945cfeb136b7b04c8870b63c2ae3f2212/src/host/coreaudio/macos/mod.rs#L248-L250
In addition, the default input device reports the wrong number of channels for my machine; System Information reports only 1 channel, but CPAL's supported input formats are all 2 channel. I wonder where the extra data is coming from?
Here are my supported configs:
SupportedStreamConfigRange { channels: 1, min_sample_rate: SampleRate(44100), max_sample_rate: SampleRate(44100), buffer_size: Range { min: 15, max: 4096 }, sample_format: F32 }
SupportedStreamConfigRange { channels: 1, min_sample_rate: SampleRate(48000), max_sample_rate: SampleRate(48000), buffer_size: Range { min: 15, max: 4096 }, sample_format: F32 }
SupportedStreamConfigRange { channels: 1, min_sample_rate: SampleRate(88200), max_sample_rate: SampleRate(88200), buffer_size: Range { min: 15, max: 4096 }, sample_format: F32 }
SupportedStreamConfigRange { channels: 1, min_sample_rate: SampleRate(96000), max_sample_rate: SampleRate(96000), buffer_size: Range { min: 15, max: 4096 }, sample_format: F32 }
Seems like the mac support in CPAL isn't complete.
Hi @leecbaker
Can I know how you resolved this issue? I am facing a similar issue here. I want to send the samples as U16 to my client playerstream and also play the incoming U16 I am receiving from my client but only F32 works for cpal.
let stream = match config.sample_format() {
cpal::SampleFormat::U16 => device.build_input_stream(
&config.into(),
move |data, _: &_| write_input_data::<u16>(data, channels, &sender),
err_fn,
)?,
_ => panic!("Unsupported"),
};
This just panics and prints Unsupported but works with f32 and that is not the sample I need.
And I cannot just start converting F32toU16 to my client and convert the incoming U16toF32 so I can play both streams.
Oh I forgot to mention that I tried it on my raspberrypi 4 and the result was still the same. Which means it did not work with Linux also.
I just had this issue.
I fixed it by ensuring the callback gets a closure with a slice type that matches the SampleFormat.
This meant handling every possible sample format with a different call to Device::build_input_stream.
I used a macro for this. Note that for my purposes, I want the audio samples as f64s. Your needs may be different.
macro_rules! input_stream {
($sample:ty, |$x:ident| $convert:expr) => {
device.build_input_stream(
&config,
move |data: &[$sample], _: &InputCallbackInfo| {
for &$x in data {
let s = $convert;
// Do something with s
}
},
|err| panic!("{err}"),
None,
)
};
}
let stream = match config.sample_format() {
SampleFormat::F32 => input_stream!(f32, |x| x as f64),
SampleFormat::I16 => input_stream!(i16, |x| x as f64 / i16::MAX as f64),
SampleFormat::U16 => input_stream!(u16, |x| x as f64 - u16::MAX as f64 / 2.0),
SampleFormat::I8 => input_stream!(i8, |x| x as f64 / i8::MAX as f64),
SampleFormat::I32 => input_stream!(i32, |x| x as f64 / i32::MAX as f64),
SampleFormat::I64 => input_stream!(i64, |x| x as f64 / i64::MAX as f64),
SampleFormat::U8 => input_stream!(u8, |x| x as f64 - u8::MAX as f64 / 2.0),
SampleFormat::U32 => input_stream!(u32, |x| x as f64 - u32::MAX as f64 / 2.0),
SampleFormat::U64 => input_stream!(u64, |x| x as f64 - u64::MAX as f64 / 2.0),
SampleFormat::F64 => input_stream!(f64, |x| x),
_ => panic!("Unsupported sample format"),
}?;