converting audio streams to specified channels (dont work for every combination)
This commit is contained in:
+46
-19
@@ -122,7 +122,7 @@ pub async fn audio_stream_receiver(
|
|||||||
|
|
||||||
let mut receive_buffer = vec![0u8; 4096];
|
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];
|
let mut decoded_samples_converted = [0.0f32; 2048];
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@@ -240,6 +240,7 @@ pub async fn audio_stream_spawner(
|
|||||||
mut global_event_rx: Receiver<ClientEvent>,
|
mut global_event_rx: Receiver<ClientEvent>,
|
||||||
udp_socket: Arc<UdpSocket>,
|
udp_socket: Arc<UdpSocket>,
|
||||||
client_info: Arc<RwLock<ClientInfo>>,
|
client_info: Arc<RwLock<ClientInfo>>,
|
||||||
|
force_channels: u16,
|
||||||
) {
|
) {
|
||||||
let current_stream_id: u8 = rand::random();
|
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 {
|
let _ = global_event_tx.send(ClientEvent::NewAudioStreamRequest(AudioStreamInfo {
|
||||||
client_id: client_id,
|
client_id: client_id,
|
||||||
stream_id: current_stream_id,
|
stream_id: current_stream_id,
|
||||||
channels: input_device_config.channels(),
|
channels: force_channels,
|
||||||
sample_rate: input_device_config.sample_rate(),
|
sample_rate: input_device_config.sample_rate(),
|
||||||
}));
|
}));
|
||||||
break;
|
break;
|
||||||
@@ -274,8 +275,7 @@ pub async fn audio_stream_spawner(
|
|||||||
|
|
||||||
let ring_buffer_ms = 80.0;
|
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_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_frames as usize * input_device_config.channels() as usize;
|
||||||
let ring_buffer_size = ring_buffer_samples;
|
|
||||||
let ring_buffer = HeapRb::<f32>::new(ring_buffer_size);
|
let ring_buffer = HeapRb::<f32>::new(ring_buffer_size);
|
||||||
let (producer, mut consumer) = ring_buffer.split();
|
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");
|
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 samples_needed = ((20.0 / 1000.0)
|
||||||
let mut frame_buffer = vec![0.0; frames_needed];
|
* input_device_config.sample_rate() as f32
|
||||||
|
* input_device_config.channels() as f32) as usize;
|
||||||
|
|
||||||
let channels: ropus::Channels = {
|
let output_samples_needed = ((20.0 / 1000.0)
|
||||||
if input_device_config.channels() == 2 {
|
* input_device_config.sample_rate() as f32
|
||||||
ropus::Channels::Stereo
|
* force_channels as f32) as usize;
|
||||||
} else {
|
|
||||||
ropus::Channels::Mono
|
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(
|
let mut opus_encoder = Encoder::builder(
|
||||||
input_device_config.sample_rate(),
|
input_device_config.sample_rate(),
|
||||||
channels,
|
encoder_channels,
|
||||||
ropus::Application::Voip,
|
ropus::Application::Voip,
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut encoded_frame_buffer = [0u8; 1024];
|
let mut encoded_frame_buffer = [0u8; 2048];
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if consumer.occupied_len() >= frames_needed {
|
if consumer.occupied_len() >= samples_needed {
|
||||||
consumer.pop_slice(&mut frame_buffer);
|
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::<u8>::with_capacity(4 + 1 + encoded_len * 4);
|
||||||
|
|
||||||
let (server_address, client_id) = {
|
let (server_address, client_id) = {
|
||||||
let info = client_info.read().unwrap();
|
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(client_id.to_be_bytes());
|
||||||
payload.extend(current_stream_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]);
|
payload.extend_from_slice(&encoded_frame_buffer[..encoded_len]);
|
||||||
|
|
||||||
let _ = udp_socket.send_to(&payload, server_address).await;
|
let _ = udp_socket.send_to(&payload, server_address).await;
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ async fn main() {
|
|||||||
global_event_tx.subscribe(),
|
global_event_tx.subscribe(),
|
||||||
udp_socket.clone(),
|
udp_socket.clone(),
|
||||||
client_info.clone(),
|
client_info.clone(),
|
||||||
|
1,
|
||||||
));
|
));
|
||||||
|
|
||||||
tokio::signal::ctrl_c().await.expect("failed to close");
|
tokio::signal::ctrl_c().await.expect("failed to close");
|
||||||
|
|||||||
+4
-3
@@ -1,5 +1,5 @@
|
|||||||
use cpal::{
|
use cpal::{
|
||||||
Device, SAMPLE_RATE_48K, SampleFormat, SupportedStreamConfig,
|
Device, SAMPLE_RATE_48K, SupportedStreamConfig,
|
||||||
traits::{DeviceTrait, HostTrait},
|
traits::{DeviceTrait, HostTrait},
|
||||||
};
|
};
|
||||||
use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind};
|
use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind};
|
||||||
@@ -264,7 +264,7 @@ impl DeviceSelectScreen {
|
|||||||
for (device, config) in self.input_devices.iter() {
|
for (device, config) in self.input_devices.iter() {
|
||||||
input_device_rows.push(Row::new(vec![
|
input_device_rows.push(Row::new(vec![
|
||||||
device.description().unwrap().name().to_string(),
|
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)
|
let input_device_table = Table::new(input_device_rows, widths)
|
||||||
@@ -299,7 +299,7 @@ impl DeviceSelectScreen {
|
|||||||
for (device, config) in self.output_devices.iter() {
|
for (device, config) in self.output_devices.iter() {
|
||||||
output_device_rows.push(Row::new(vec![
|
output_device_rows.push(Row::new(vec![
|
||||||
device.description().unwrap().name().to_string(),
|
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)
|
let output_device_table = Table::new(output_device_rows, widths)
|
||||||
@@ -413,6 +413,7 @@ impl DeviceSelectScreen {
|
|||||||
self.global_event_tx.subscribe(),
|
self.global_event_tx.subscribe(),
|
||||||
self.audio_control.udp_socket.clone(),
|
self.audio_control.udp_socket.clone(),
|
||||||
self.client_info.clone(),
|
self.client_info.clone(),
|
||||||
|
1,
|
||||||
));
|
));
|
||||||
|
|
||||||
self.exit_screen = TuiScreen::Blank;
|
self.exit_screen = TuiScreen::Blank;
|
||||||
|
|||||||
Reference in New Issue
Block a user