diff --git a/client/src/audio_streams.rs b/client/src/audio_streams.rs index c917509..1d85176 100644 --- a/client/src/audio_streams.rs +++ b/client/src/audio_streams.rs @@ -122,7 +122,7 @@ pub async fn audio_stream_receiver( let mut receive_buffer = vec![0u8; 4096]; - let mut decoded_samples = [0.0f32; 1024]; + let mut decoded_samples = [0.0f32; 2048]; let mut decoded_samples_converted = [0.0f32; 2048]; loop { @@ -240,6 +240,7 @@ pub async fn audio_stream_spawner( mut global_event_rx: Receiver, udp_socket: Arc, client_info: Arc>, + force_channels: u16, ) { let current_stream_id: u8 = rand::random(); @@ -252,7 +253,7 @@ pub async fn audio_stream_spawner( let _ = global_event_tx.send(ClientEvent::NewAudioStreamRequest(AudioStreamInfo { client_id: client_id, stream_id: current_stream_id, - channels: input_device_config.channels(), + channels: force_channels, sample_rate: input_device_config.sample_rate(), })); break; @@ -274,8 +275,7 @@ pub async fn audio_stream_spawner( let ring_buffer_ms = 80.0; let ring_buffer_frames = (ring_buffer_ms / 1000.0) * input_device_config.sample_rate() as f32; - let ring_buffer_samples = ring_buffer_frames as usize * input_device_config.channels() as usize; - let ring_buffer_size = ring_buffer_samples; + let ring_buffer_size = ring_buffer_frames as usize * input_device_config.channels() as usize; let ring_buffer = HeapRb::::new(ring_buffer_size); let (producer, mut consumer) = ring_buffer.split(); @@ -318,32 +318,63 @@ pub async fn audio_stream_spawner( input_stream.play().expect("failed to play input stream"); - let frames_needed = ((20.0 / 1000.0) * input_device_config.sample_rate() as f32) as usize; - let mut frame_buffer = vec![0.0; frames_needed]; + let samples_needed = ((20.0 / 1000.0) + * input_device_config.sample_rate() as f32 + * input_device_config.channels() as f32) as usize; - let channels: ropus::Channels = { - if input_device_config.channels() == 2 { - ropus::Channels::Stereo - } else { - ropus::Channels::Mono + let output_samples_needed = ((20.0 / 1000.0) + * input_device_config.sample_rate() as f32 + * force_channels as f32) as usize; + + let mut frame_buffer = vec![0f32; samples_needed]; + let mut output_frame_buffer = vec![0f32; output_samples_needed]; + + let encoder_channels: ropus::Channels = match force_channels { + 1 => ropus::Channels::Mono, + 2 => ropus::Channels::Stereo, + _ => { + eprintln!("unsupported by encoder channel count"); + return; } }; let mut opus_encoder = Encoder::builder( input_device_config.sample_rate(), - channels, + encoder_channels, ropus::Application::Voip, ) .build() .unwrap(); - let mut encoded_frame_buffer = [0u8; 1024]; + let mut encoded_frame_buffer = [0u8; 2048]; loop { - if consumer.occupied_len() >= frames_needed { + if consumer.occupied_len() >= samples_needed { consumer.pop_slice(&mut frame_buffer); - let mut payload = Vec::with_capacity(4 + 1 + frames_needed * 4); + if force_channels == input_device_config.channels() { + output_frame_buffer.copy_from_slice(frame_buffer.as_slice()); + } else if force_channels < input_device_config.channels() { + let div = (input_device_config.channels() / force_channels) as usize; + + output_frame_buffer.fill(0.0); + + for (i, input_sample) in frame_buffer.iter().enumerate() { + output_frame_buffer[i / div] += *input_sample / div as f32; + } + } else { + let div = (force_channels / input_device_config.channels()) as usize; + + for (i, output_sample) in output_frame_buffer.iter_mut().enumerate() { + *output_sample = frame_buffer[i / div]; + } + } + + let encoded_len = opus_encoder + .encode_float(&output_frame_buffer.as_slice(), &mut encoded_frame_buffer) + .expect("failed to encode frame"); + + let mut payload = Vec::::with_capacity(4 + 1 + encoded_len * 4); let (server_address, client_id) = { let info = client_info.read().unwrap(); @@ -353,10 +384,6 @@ pub async fn audio_stream_spawner( payload.extend(client_id.to_be_bytes()); payload.extend(current_stream_id.to_be_bytes()); - let encoded_len = opus_encoder - .encode_float(&frame_buffer.as_slice(), &mut encoded_frame_buffer) - .expect("failed to encode frame"); - payload.extend_from_slice(&encoded_frame_buffer[..encoded_len]); let _ = udp_socket.send_to(&payload, server_address).await; diff --git a/client/src/main.rs b/client/src/main.rs index a2c591a..2ed1d5a 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -101,6 +101,7 @@ async fn main() { global_event_tx.subscribe(), udp_socket.clone(), client_info.clone(), + 1, )); tokio::signal::ctrl_c().await.expect("failed to close"); diff --git a/client/src/tui.rs b/client/src/tui.rs index fad8a91..f955928 100644 --- a/client/src/tui.rs +++ b/client/src/tui.rs @@ -1,5 +1,5 @@ use cpal::{ - Device, SAMPLE_RATE_48K, SampleFormat, SupportedStreamConfig, + Device, SAMPLE_RATE_48K, SupportedStreamConfig, traits::{DeviceTrait, HostTrait}, }; use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind}; @@ -264,7 +264,7 @@ impl DeviceSelectScreen { for (device, config) in self.input_devices.iter() { input_device_rows.push(Row::new(vec![ device.description().unwrap().name().to_string(), - config.sample_format().to_string(), + config.channels().to_string(), ])); } let input_device_table = Table::new(input_device_rows, widths) @@ -299,7 +299,7 @@ impl DeviceSelectScreen { for (device, config) in self.output_devices.iter() { output_device_rows.push(Row::new(vec![ device.description().unwrap().name().to_string(), - config.sample_format().to_string(), + config.channels().to_string(), ])); } let output_device_table = Table::new(output_device_rows, widths) @@ -413,6 +413,7 @@ impl DeviceSelectScreen { self.global_event_tx.subscribe(), self.audio_control.udp_socket.clone(), self.client_info.clone(), + 1, )); self.exit_screen = TuiScreen::Blank;