choose profile from supported
This commit is contained in:
+3
-3
@@ -97,13 +97,13 @@ impl AudioProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AudioProcessor {
|
impl AudioProcessor {
|
||||||
pub fn process(&mut self, audio: &[f32], output: &mut Vec<f32>) {
|
pub fn process(&mut self, audio: &[f32], channels: usize, output: &mut Vec<f32>) {
|
||||||
let mut include_raw = true;
|
let mut include_raw = true;
|
||||||
if self.denoise {
|
if self.denoise {
|
||||||
with_denoising_model(&self.spawn, |df| {
|
with_denoising_model(&self.spawn, |df| {
|
||||||
include_raw = false;
|
include_raw = false;
|
||||||
|
|
||||||
self.buffer.extend_from_slice(audio);
|
self.buffer.extend(audio.iter().step_by(channels).copied());
|
||||||
output.reserve(audio.len());
|
output.reserve(audio.len());
|
||||||
|
|
||||||
let hop = df.hop_size;
|
let hop = df.hop_size;
|
||||||
@@ -130,7 +130,7 @@ impl AudioProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if include_raw {
|
if include_raw {
|
||||||
output.extend_from_slice(audio);
|
output.extend(audio.iter().step_by(channels).copied());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-18
@@ -1,7 +1,7 @@
|
|||||||
use crate::app::Command;
|
use crate::app::Command;
|
||||||
use crate::effects::{AudioProcessor, AudioProcessorSender};
|
use crate::effects::{AudioProcessor, AudioProcessorSender};
|
||||||
use color_eyre::eyre::{eyre, Context, Error};
|
use color_eyre::eyre::{eyre, Context, Error};
|
||||||
use cpal::traits::{DeviceTrait, HostTrait};
|
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait as _};
|
||||||
use dioxus::hooks::UnboundedReceiver;
|
use dioxus::hooks::UnboundedReceiver;
|
||||||
use futures::io::{AsyncRead, AsyncWrite};
|
use futures::io::{AsyncRead, AsyncWrite};
|
||||||
use mumble_protocol::control::ClientControlCodec;
|
use mumble_protocol::control::ClientControlCodec;
|
||||||
@@ -64,11 +64,34 @@ impl AudioSystem {
|
|||||||
self.processors.store(Some(processor))
|
self.processors.store(Some(processor))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn choose_config(&self, configs: impl Iterator<Item=cpal::SupportedStreamConfigRange>) -> Result<cpal::StreamConfig, Error> {
|
||||||
|
let mut supported_configs: Vec<_> = configs
|
||||||
|
.filter_map(|cfg| cfg.try_with_sample_rate(cpal::SampleRate(SAMPLE_RATE)))
|
||||||
|
.filter(|cfg| cfg.sample_format() == cpal::SampleFormat::I16)
|
||||||
|
.map(|cfg| {
|
||||||
|
cpal::StreamConfig {
|
||||||
|
buffer_size: cpal::BufferSize::Fixed(match *cfg.buffer_size() {
|
||||||
|
cpal::SupportedBufferSize::Range { min, max } => 480.clamp(min, max),
|
||||||
|
cpal::SupportedBufferSize::Unknown => 480,
|
||||||
|
}),
|
||||||
|
..cfg.config()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
supported_configs.sort_by(|a, b| {
|
||||||
|
let cpal::BufferSize::Fixed(a_buf) = a.buffer_size else { unreachable!() };
|
||||||
|
let cpal::BufferSize::Fixed(b_buf) = b.buffer_size else { unreachable!() };
|
||||||
|
Ord::cmp(&a.channels, &b.channels).then(Ord::cmp(&a_buf, &b_buf))
|
||||||
|
});
|
||||||
|
supported_configs.get(0).cloned().ok_or(eyre!("no supported stream configs"))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn start_recording(
|
pub fn start_recording(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut each: impl FnMut(Vec<u8>) + Send + 'static,
|
mut each: impl FnMut(Vec<u8>) + Send + 'static,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
info!("creating recording on {:?} with {:#?}", self.input.name()?, self.input.supported_input_configs()?.collect::<Vec<_>>());
|
let config = self.choose_config(self.input.supported_input_configs()?)?;
|
||||||
|
info!("creating recording on {:?} with {:#?}", self.input.name()?, config);
|
||||||
let mut encoder =
|
let mut encoder =
|
||||||
opus::Encoder::new(SAMPLE_RATE, opus::Channels::Mono, opus::Application::Voip)?;
|
opus::Encoder::new(SAMPLE_RATE, opus::Channels::Mono, opus::Application::Voip)?;
|
||||||
let mut current_processor = AudioProcessor::new_plain();
|
let mut current_processor = AudioProcessor::new_plain();
|
||||||
@@ -79,7 +102,7 @@ impl AudioSystem {
|
|||||||
if let Some(new_processor) = processors.take() {
|
if let Some(new_processor) = processors.take() {
|
||||||
current_processor = new_processor;
|
current_processor = new_processor;
|
||||||
}
|
}
|
||||||
current_processor.process(frame, &mut output_buffer);
|
current_processor.process(frame, config.channels as usize, &mut output_buffer);
|
||||||
if output_buffer.len() < PACKET_SAMPLES as usize {
|
if output_buffer.len() < PACKET_SAMPLES as usize {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -96,16 +119,13 @@ impl AudioSystem {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match self.input.build_input_stream(
|
match self.input.build_input_stream(
|
||||||
&cpal::StreamConfig {
|
&config,
|
||||||
channels: 1,
|
|
||||||
sample_rate: cpal::SampleRate(SAMPLE_RATE),
|
|
||||||
buffer_size: cpal::BufferSize::Fixed(PACKET_SAMPLES),
|
|
||||||
},
|
|
||||||
data_callback,
|
data_callback,
|
||||||
error_callback,
|
error_callback,
|
||||||
None,
|
None,
|
||||||
) {
|
) {
|
||||||
Ok(stream) => {
|
Ok(stream) => {
|
||||||
|
stream.play()?;
|
||||||
self.recording_stream = Some(stream);
|
self.recording_stream = Some(stream);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -117,7 +137,8 @@ impl AudioSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_player(&mut self) -> Result<AudioPlayer, Error> {
|
pub fn create_player(&mut self) -> Result<AudioPlayer, Error> {
|
||||||
info!("creating player on {:?} with {:#?}", self.output.name()?, self.output.supported_output_configs()?.collect::<Vec<_>>());
|
let config = self.choose_config(self.input.supported_input_configs()?)?;
|
||||||
|
info!("creating player on {:?} with {:#?}", self.output.name().ok(), &config);
|
||||||
let buffer = Arc::new(Mutex::new(dasp_ring_buffer::Bounded::from_raw_parts(
|
let buffer = Arc::new(Mutex::new(dasp_ring_buffer::Bounded::from_raw_parts(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -130,20 +151,16 @@ impl AudioSystem {
|
|||||||
let stream = {
|
let stream = {
|
||||||
let buffer = buffer.clone();
|
let buffer = buffer.clone();
|
||||||
self.output.build_output_stream(
|
self.output.build_output_stream(
|
||||||
&cpal::StreamConfig {
|
&config,
|
||||||
channels: 1,
|
move |frame, _info| {
|
||||||
sample_rate: cpal::SampleRate(SAMPLE_RATE),
|
|
||||||
buffer_size: cpal::BufferSize::Fixed(480), // 10ms playback delay
|
|
||||||
},
|
|
||||||
move |frame, info| {
|
|
||||||
let mut buffer = buffer.lock().unwrap();
|
let mut buffer = buffer.lock().unwrap();
|
||||||
for x in frame.iter_mut() {
|
for x in frame.chunks_mut(config.channels as usize) {
|
||||||
match buffer.pop() {
|
match buffer.pop() {
|
||||||
Some(y) => {
|
Some(y) => {
|
||||||
*x = y;
|
x.fill(y);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
*x = 0;
|
x.fill(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,6 +169,7 @@ impl AudioSystem {
|
|||||||
None,
|
None,
|
||||||
)?
|
)?
|
||||||
};
|
};
|
||||||
|
stream.play()?;
|
||||||
Ok(AudioPlayer {
|
Ok(AudioPlayer {
|
||||||
decoder,
|
decoder,
|
||||||
stream,
|
stream,
|
||||||
|
|||||||
+1
-1
@@ -209,7 +209,7 @@ fn process_audio(frame: &JsValue, processor: &mut AudioProcessor) {
|
|||||||
};
|
};
|
||||||
let input = samples.to_vec();
|
let input = samples.to_vec();
|
||||||
let mut output = Vec::with_capacity(input.len());
|
let mut output = Vec::with_capacity(input.len());
|
||||||
processor.process(&input, &mut output);
|
processor.process(&input, 1, &mut output);
|
||||||
samples.copy_from(&output);
|
samples.copy_from(&output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user