supporting multiple sample formats

This commit is contained in:
2026-09-15 16:41:35 +02:00
parent c6b15e726b
commit df3822a096
2 changed files with 54 additions and 23 deletions
+52 -15
View File
@@ -1,5 +1,5 @@
use cpal::{ use cpal::{
Device, FromSample, SampleFormat, SizedSample, StreamConfig, SupportedStreamConfig, Device, FromSample, Sample, SampleFormat, SizedSample, StreamConfig, SupportedStreamConfig,
traits::{DeviceTrait, StreamTrait}, traits::{DeviceTrait, StreamTrait},
}; };
use ringbuf::{ use ringbuf::{
@@ -21,16 +21,16 @@ use crate::models::{
InputAudioStreamsInfo, InputAudioStreamsProducers, InputAudioStreamsInfo, InputAudioStreamsProducers,
}; };
pub async fn audio_stream_receiver( fn cpal_build_output_stream<T>(
output_device: Device, output_device: &Device,
output_device_config: SupportedStreamConfig, output_device_config: StreamConfig,
active_input_audio_streams_producers: InputAudioStreamsProducers,
active_input_audio_streams_consumers: InputAudioStreamsConsumers, active_input_audio_streams_consumers: InputAudioStreamsConsumers,
active_input_audio_streams_encoders: InputAudioStreamsEncoders, ) -> cpal::Stream
active_input_audio_streams_info: InputAudioStreamsInfo, where
udp_socket: Arc<UdpSocket>, T: SizedSample,
) { T: FromSample<f32>,
let output_data_fn = move |data: &mut [f32], _: &cpal::OutputCallbackInfo| { {
let output_data_fn = move |data: &mut [T], _: &cpal::OutputCallbackInfo| {
let mut streams = active_input_audio_streams_consumers.lock().unwrap(); let mut streams = active_input_audio_streams_consumers.lock().unwrap();
for sample in data { for sample in data {
let mut mixed_value: f32 = 0.0; let mut mixed_value: f32 = 0.0;
@@ -42,14 +42,51 @@ pub async fn audio_stream_receiver(
} }
} }
*sample = mixed_value; *sample = mixed_value.to_sample::<T>();
} }
}; };
let err_fn = |err| eprintln!("stream error: {}", err); let err_fn = |err| eprintln!("stream error: {}", err);
let output_stream = output_device
.build_output_stream(output_device_config.into(), output_data_fn, err_fn, None) return output_device
.build_output_stream(output_device_config, output_data_fn, err_fn, None)
.expect("building output stream failed"); .expect("building output stream failed");
}
pub async fn audio_stream_receiver(
output_device: Device,
output_device_config: SupportedStreamConfig,
active_input_audio_streams_producers: InputAudioStreamsProducers,
active_input_audio_streams_consumers: InputAudioStreamsConsumers,
active_input_audio_streams_encoders: InputAudioStreamsEncoders,
active_input_audio_streams_info: InputAudioStreamsInfo,
udp_socket: Arc<UdpSocket>,
) {
let output_stream = match output_device_config.sample_format() {
SampleFormat::F32 => cpal_build_output_stream::<f32>(
&output_device,
output_device_config.into(),
active_input_audio_streams_consumers,
),
SampleFormat::I32 => cpal_build_output_stream::<i32>(
&output_device,
output_device_config.into(),
active_input_audio_streams_consumers,
),
SampleFormat::I16 => cpal_build_output_stream::<i16>(
&output_device,
output_device_config.into(),
active_input_audio_streams_consumers,
),
SampleFormat::U16 => cpal_build_output_stream::<u16>(
&output_device,
output_device_config.into(),
active_input_audio_streams_consumers,
),
_ => {
eprintln!("unsupported output stream format :(");
return;
}
};
output_stream.play().expect("failed to play output stream"); output_stream.play().expect("failed to play output stream");
@@ -226,7 +263,7 @@ pub async fn audio_stream_spawner(
cpal_build_input_stream::<u16>(&input_device, input_device_config.into(), producer) cpal_build_input_stream::<u16>(&input_device, input_device_config.into(), producer)
} }
_ => { _ => {
eprintln!("unsupported stream format :("); eprintln!("unsupported input stream format :(");
return; return;
} }
}; };
+2 -8
View File
@@ -172,7 +172,6 @@ impl DeviceSelectScreen {
if let Some(default_output_device) = host.default_output_device() { if let Some(default_output_device) = host.default_output_device() {
if let Ok(default_config) = default_output_device.default_output_config() { if let Ok(default_config) = default_output_device.default_output_config() {
if default_config.sample_rate() == SAMPLE_RATE_48K if default_config.sample_rate() == SAMPLE_RATE_48K
&& default_config.sample_format() == SampleFormat::F32
&& (default_config.channels() == 1 || default_config.channels() == 2) && (default_config.channels() == 1 || default_config.channels() == 2)
{ {
output_devices.push((default_output_device.clone(), default_config.into())); output_devices.push((default_output_device.clone(), default_config.into()));
@@ -182,9 +181,7 @@ impl DeviceSelectScreen {
if let Some(output_config) = if let Some(output_config) =
supported_config.try_with_sample_rate(SAMPLE_RATE_48K) supported_config.try_with_sample_rate(SAMPLE_RATE_48K)
{ {
if output_config.sample_format() == SampleFormat::F32 if output_config.channels() == 1 || output_config.channels() == 2 {
&& (output_config.channels() == 1 || output_config.channels() == 2)
{
output_devices.push((default_output_device, output_config.into())); output_devices.push((default_output_device, output_config.into()));
break; break;
} }
@@ -197,7 +194,6 @@ impl DeviceSelectScreen {
for possible_output_device in possible_output_devices { for possible_output_device in possible_output_devices {
if let Ok(default_config) = possible_output_device.default_output_config() { if let Ok(default_config) = possible_output_device.default_output_config() {
if default_config.sample_rate() == SAMPLE_RATE_48K if default_config.sample_rate() == SAMPLE_RATE_48K
&& default_config.sample_format() == SampleFormat::F32
&& (default_config.channels() == 1 || default_config.channels() == 2) && (default_config.channels() == 1 || default_config.channels() == 2)
{ {
output_devices output_devices
@@ -210,9 +206,7 @@ impl DeviceSelectScreen {
if let Some(output_config) = if let Some(output_config) =
supported_config.try_with_sample_rate(SAMPLE_RATE_48K) supported_config.try_with_sample_rate(SAMPLE_RATE_48K)
{ {
if output_config.sample_format() == SampleFormat::F32 if output_config.channels() == 1 || output_config.channels() == 2 {
&& (output_config.channels() == 1 || output_config.channels() == 2)
{
output_devices.push((possible_output_device, output_config.into())); output_devices.push((possible_output_device, output_config.into()));
break; break;
} }