From cd37796ff414dafec42b83f996a06199d87da283 Mon Sep 17 00:00:00 2001 From: csh <458761603@qq.com> Date: Sat, 6 Dec 2025 02:31:43 +0800 Subject: [PATCH 1/4] optimize: update box AFE configuration and improve audio processing logic --- src/audio.rs | 67 +++++++++++++++++++++++++++++++----------- src/boards/atom_box.rs | 10 ++++++- src/main.rs | 1 + src/ws.rs | 2 +- 4 files changed, 61 insertions(+), 19 deletions(-) diff --git a/src/audio.rs b/src/audio.rs index 282a52a..4c02274 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -16,16 +16,17 @@ unsafe fn afe_init() -> ( let afe_config = esp_sr::afe_config_init( c"MR".as_ptr() as _, models, - esp_sr::afe_type_t_AFE_TYPE_SR, + esp_sr::afe_type_t_AFE_TYPE_VC, esp_sr::afe_mode_t_AFE_MODE_HIGH_PERF, ); let afe_config = afe_config.as_mut().unwrap(); afe_config.pcm_config.sample_rate = 16000; afe_config.afe_ringbuf_size = 40; - afe_config.vad_min_noise_ms = 500; - // afe_config.vad_min_speech_ms = 300; - afe_config.vad_mode = esp_sr::vad_mode_t_VAD_MODE_3; + afe_config.vad_min_noise_ms = 250; + afe_config.vad_min_speech_ms = 250; + // afe_config.vad_delay_ms = 250; // Don't change it!! + afe_config.vad_mode = esp_sr::vad_mode_t_VAD_MODE_4; afe_config.agc_init = true; afe_config.afe_linear_gain = 2.0; @@ -37,6 +38,8 @@ unsafe fn afe_init() -> ( afe_config.wakenet_init = false; afe_config.memory_alloc_mode = esp_sr::afe_memory_alloc_mode_t_AFE_MEMORY_ALLOC_MORE_PSRAM; + crate::boards::afe_config(afe_config); + log::info!("{afe_config:?}"); let afe_ringbuf_size = afe_config.afe_ringbuf_size; @@ -403,8 +406,43 @@ impl SendBuffer { } } +struct RingBuffer { + buff: Vec>, + start_index: usize, + chunk_size: usize, +} + +impl RingBuffer { + fn new(chunk_size: usize) -> Self { + Self { + buff: vec![vec![0i16; chunk_size]; MAX], + start_index: 0, + chunk_size, + } + } + + fn push(&mut self, data: Vec) { + assert!(data.len() == self.chunk_size); + self.buff[self.start_index] = data; + self.start_index = (self.start_index + 1) % MAX; + } + + fn index(&self, n: usize) -> i16 { + let chunk_index = ((n / self.chunk_size) + self.start_index) % MAX; + let offset = n % self.chunk_size; + self.buff[chunk_index][offset] + } + + fn index_form_end(&self, n: usize) -> i16 { + self.index(self.chunk_size * MAX - n - 1) + } +} + static PLAYING: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); -static VOL_NUM: std::sync::atomic::AtomicU8 = std::sync::atomic::AtomicU8::new(3); +static VOL_NUM: std::sync::atomic::AtomicU8 = std::sync::atomic::AtomicU8::new(5); + +const CHUNK_SIZE: usize = 256; +// const CHUNK_SIZE: usize = 512; fn audio_task_run( rx: &mut tokio::sync::mpsc::UnboundedReceiver, @@ -424,6 +462,7 @@ fn audio_task_run( let feed_chunksize = afe_handle.feed_chunksize; log::info!("feed_chunksize: {}", feed_chunksize); + assert_eq!(feed_chunksize, CHUNK_SIZE); std::thread::Builder::new() .name("afe_feed".to_string()) @@ -442,9 +481,9 @@ fn audio_task_run( let mut read_buffer = vec![0i16; feed_chunksize]; let mut send_buffer = SendBuffer::new(feed_chunksize); let empty_buffer = vec![0i16; feed_chunksize]; - let mut ref_data_: Option> = send_buffer.get_chunk(); + let mut ring_cache_buffer = RingBuffer::<6>::new(feed_chunksize); - let offset = 0; + let offset = crate::boards::AFE_AEC_OFFSET; let mut hello_wav = WAKE_WAV.to_vec(); let mut allow_speech = false; @@ -528,20 +567,14 @@ fn audio_task_run( let total = len / 2; let mut samples_with_ref = Vec::with_capacity(total); - let ref_data = ref_data_.as_ref().unwrap_or(&empty_buffer); - for i in 0..total { samples_with_ref.push(read_buffer[i]); - if offset + i < total { - samples_with_ref.push(ref_data[offset + i]) - } else { - samples_with_ref.push(play_data[offset + i - total]); - } + samples_with_ref.push(ring_cache_buffer.index_form_end(offset - i)) } chunk_tx.send(samples_with_ref).unwrap(); } - ref_data_ = play_data_; + ring_cache_buffer.push(play_data.to_vec()); } log::warn!("I2S loop exited"); @@ -618,7 +651,7 @@ impl BoxAudioWorker { crate::log_heap(); let _afe_r = std::thread::Builder::new().stack_size(8 * 1024).spawn(|| { - let r = afe_worker(afe_handle_, tx, 600.0); + let r = afe_worker(afe_handle_, tx, 550.0); if let Err(e) = r { log::error!("AFE worker error: {:?}", e); } @@ -646,7 +679,7 @@ impl BoardsAudioWorker { pub fn run(self, mut rx: PlayerRx, tx: EventTx) -> anyhow::Result<()> { let i2s_config = config::StdConfig::new( config::Config::default() - .auto_clear(false) + .auto_clear(true) .dma_buffer_count(2) .frames_per_buffer(512), config::StdClkConfig::from_sample_rate_hz(SAMPLE_RATE), diff --git a/src/boards/atom_box.rs b/src/boards/atom_box.rs index 64213b5..70e4212 100644 --- a/src/boards/atom_box.rs +++ b/src/boards/atom_box.rs @@ -4,6 +4,14 @@ use esp_idf_svc::{ }; const AUDIO_STACK_SIZE: usize = 15 * 1024; +pub const AFE_AEC_OFFSET: usize = 512; + +pub fn afe_config(afe_config: &mut esp_idf_svc::sys::esp_sr::afe_config_t) { + afe_config.agc_init = true; + afe_config.agc_mode = esp_idf_svc::sys::esp_sr::afe_agc_mode_t_AFE_AGC_MODE_WEBRTC; + afe_config.afe_linear_gain = 1.0; + afe_config.ns_init = false; +} pub fn audio_init(_i2c: I2C0, _sda: Gpio48, _scl: Gpio45) { const SAMPLE_RATE: u32 = 16000; @@ -16,7 +24,7 @@ pub fn audio_init(_i2c: I2C0, _sda: Gpio48, _scl: Gpio45) { hal_driver::es8311_init(SAMPLE_RATE as i32); hal_driver::xl9555_pin_write(hal_driver::SPK_CTRL_IO as _, 1); hal_driver::es8311_set_voice_volume(70); - hal_driver::es8311_set_mic_gain(hal_driver::es8311_mic_gain_t_ES8311_MIC_GAIN_18DB); + hal_driver::es8311_set_mic_gain(hal_driver::es8311_mic_gain_t_ES8311_MIC_GAIN_24DB); hal_driver::es8311_set_voice_mute(0); /* 打开DAC */ } } diff --git a/src/main.rs b/src/main.rs index 3ba7bb3..cd4f34f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -235,6 +235,7 @@ fn main() -> anyhow::Result<()> { gui.text = format!("Please check your server URL: {server_url}\nPress K0 to open settings"); let server = b.block_on(ws::Server::new(dev_id, server_url)); if server.is_err() { + log::info!("Failed to connect to server: {:?}", server.err()); gui.display_flush().unwrap(); b.block_on(button.wait_for_falling_edge()).unwrap(); nvs.set_u8("state", 1).unwrap(); diff --git a/src/ws.rs b/src/ws.rs index 8cdc35c..466687c 100644 --- a/src/ws.rs +++ b/src/ws.rs @@ -62,7 +62,7 @@ async fn ws_manager( return Err(anyhow::anyhow!("WebSocket receive error: {}", e)); } SelectItem::Send(Some(msg)) => { - log::info!("WebSocket message sent"); + log::debug!("WebSocket message sent"); match msg { SubmitItem::JSON(cmd) => { let payload = serde_json::to_string(&cmd).map_err(|e| { From 5246d1cfd2d14f5cffab0e965c405f77975cc495 Mon Sep 17 00:00:00 2001 From: csh <458761603@qq.com> Date: Sat, 6 Dec 2025 03:26:11 +0800 Subject: [PATCH 2/4] optimize: update base & cube AFE configuration --- src/audio.rs | 9 ++------- src/boards/atom_box.rs | 1 + src/boards/base.rs | 10 ++++++++++ src/boards/cube.rs | 10 ++++++++++ src/boards/cube2.rs | 10 ++++++++++ 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/audio.rs b/src/audio.rs index 4c02274..6655388 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -651,7 +651,7 @@ impl BoxAudioWorker { crate::log_heap(); let _afe_r = std::thread::Builder::new().stack_size(8 * 1024).spawn(|| { - let r = afe_worker(afe_handle_, tx, 550.0); + let r = afe_worker(afe_handle_, tx, crate::boards::TRIGGER_MEAN_VALUE); if let Err(e) = r { log::error!("AFE worker error: {:?}", e); } @@ -740,14 +740,9 @@ impl BoardsAudioWorker { let afe_handle = Arc::new(AFE::new()); let afe_handle_ = afe_handle.clone(); - #[cfg(feature = "cube2")] - const TRIGGER_MEAN_VALUE: f32 = 500.0; - #[cfg(not(feature = "cube2"))] - const TRIGGER_MEAN_VALUE: f32 = 300.0; - let _afe_r = std::thread::Builder::new() .stack_size(8 * 1024) - .spawn(|| afe_worker(afe_handle_, tx, TRIGGER_MEAN_VALUE))?; + .spawn(|| afe_worker(afe_handle_, tx, crate::boards::TRIGGER_MEAN_VALUE))?; audio_task_run(&mut rx, &mut fn_read, &mut fn_write, afe_handle) } diff --git a/src/boards/atom_box.rs b/src/boards/atom_box.rs index 70e4212..7f656b0 100644 --- a/src/boards/atom_box.rs +++ b/src/boards/atom_box.rs @@ -5,6 +5,7 @@ use esp_idf_svc::{ const AUDIO_STACK_SIZE: usize = 15 * 1024; pub const AFE_AEC_OFFSET: usize = 512; +pub const TRIGGER_MEAN_VALUE: f32 = 550.0; pub fn afe_config(afe_config: &mut esp_idf_svc::sys::esp_sr::afe_config_t) { afe_config.agc_init = true; diff --git a/src/boards/base.rs b/src/boards/base.rs index 1b9d2a4..5da3b89 100644 --- a/src/boards/base.rs +++ b/src/boards/base.rs @@ -8,6 +8,16 @@ use esp_idf_svc::{ }; const AUDIO_STACK_SIZE: usize = 15 * 1024; +pub const AFE_AEC_OFFSET: usize = 256; +pub const TRIGGER_MEAN_VALUE: f32 = 550.0; + +pub fn afe_config(afe_config: &mut esp_idf_svc::sys::esp_sr::afe_config_t) { + afe_config.agc_init = true; + afe_config.agc_mode = esp_idf_svc::sys::esp_sr::afe_agc_mode_t_AFE_AGC_MODE_WEBRTC; + afe_config.agc_target_level_dbfs = 1; + afe_config.agc_compression_gain_db = 15; + afe_config.afe_linear_gain = 1.0; +} pub fn start_audio_workers( out_i2s: I2S1, diff --git a/src/boards/cube.rs b/src/boards/cube.rs index 8482ea4..c510d21 100644 --- a/src/boards/cube.rs +++ b/src/boards/cube.rs @@ -8,6 +8,16 @@ use esp_idf_svc::{ }; const AUDIO_STACK_SIZE: usize = 15 * 1024; +pub const AFE_AEC_OFFSET: usize = 256; +pub const TRIGGER_MEAN_VALUE: f32 = 300.0; + +pub fn afe_config(afe_config: &mut esp_idf_svc::sys::esp_sr::afe_config_t) { + afe_config.agc_init = true; + afe_config.agc_mode = esp_idf_svc::sys::esp_sr::afe_agc_mode_t_AFE_AGC_MODE_WEBRTC; + afe_config.agc_target_level_dbfs = 1; + afe_config.agc_compression_gain_db = 15; + afe_config.afe_linear_gain = 1.0; +} pub fn start_audio_workers( out_i2s: I2S1, diff --git a/src/boards/cube2.rs b/src/boards/cube2.rs index 95b1162..25ed40f 100644 --- a/src/boards/cube2.rs +++ b/src/boards/cube2.rs @@ -8,6 +8,16 @@ use esp_idf_svc::{ }; const AUDIO_STACK_SIZE: usize = 15 * 1024; +pub const AFE_AEC_OFFSET: usize = 256; +pub const TRIGGER_MEAN_VALUE: f32 = 300.0; + +pub fn afe_config(afe_config: &mut esp_idf_svc::sys::esp_sr::afe_config_t) { + afe_config.agc_init = true; + afe_config.agc_mode = esp_idf_svc::sys::esp_sr::afe_agc_mode_t_AFE_AGC_MODE_WEBRTC; + afe_config.agc_target_level_dbfs = 1; + afe_config.agc_compression_gain_db = 25; + afe_config.afe_linear_gain = 1.0; +} pub fn start_audio_workers( out_i2s: I2S1, From 3371339169c1d81c5a28d44edd89669160ddf930 Mon Sep 17 00:00:00 2001 From: csh <458761603@qq.com> Date: Sat, 6 Dec 2025 03:27:54 +0800 Subject: [PATCH 3/4] feat: add #[cfg(feature = "i2c")] for I2CInitFn and I2CLoopFn --- src/boards/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/boards/mod.rs b/src/boards/mod.rs index 01ab41b..d252448 100644 --- a/src/boards/mod.rs +++ b/src/boards/mod.rs @@ -18,7 +18,9 @@ pub mod cube2; #[cfg(feature = "cube2")] pub use cube2::*; +#[cfg(feature = "i2c")] pub type I2CInitFn = fn(&mut esp_idf_svc::hal::i2c::I2cDriver<'static>) -> anyhow::Result<()>; +#[cfg(feature = "i2c")] pub type I2CLoopFn = fn( &mut esp_idf_svc::hal::i2c::I2cDriver<'static>, &crate::audio::EventTx, From 2bfba01b3050339d97f7d7b23b40b9b705ab3c7f Mon Sep 17 00:00:00 2001 From: csh <458761603@qq.com> Date: Mon, 8 Dec 2025 21:16:34 +0800 Subject: [PATCH 4/4] perf: better voice interrupt --- src/app.rs | 107 ++++++++++++++++++++--------------------- src/audio.rs | 86 ++++++++++----------------------- src/boards/atom_box.rs | 1 - src/boards/base.rs | 1 - src/boards/cube.rs | 1 - src/boards/cube2.rs | 1 - 6 files changed, 77 insertions(+), 120 deletions(-) diff --git a/src/app.rs b/src/app.rs index 96c57c8..21537b4 100644 --- a/src/app.rs +++ b/src/app.rs @@ -14,7 +14,6 @@ pub enum Event { ServerEvent(ServerEvent), MicAudioChunk(Vec), MicAudioEnd, - MicInterrupt(Vec), MicInterruptWaitTimeout, #[cfg_attr(not(feature = "extra_server"), allow(unused))] ServerUrl(String), @@ -83,9 +82,6 @@ async fn select_evt( Event::ServerEvent(_) => { log::info!("[Select] Received ServerEvent: {:?}", evt); }, - Event::MicInterrupt(data) => { - log::info!("[Select] Received MicInterrupt with {} samples", data.len()); - }, Event::MicInterruptWaitTimeout => { log::info!("[Select] Received MicInterruptWaitTimeout"); } @@ -292,11 +288,7 @@ pub async fn main_work<'d>( Event::Event(evt) => { log::info!("Received event: {:?}", evt); } - Event::MicAudioChunk(data) => { - if state != State::Listening { - log::debug!("Received MicAudioChunk while no Listening state, ignoring"); - continue; - } + Event::MicAudioChunk(data) if state == State::Listening => { submit_audio += data.len() as f32 / 16000.0; audio_buffer.extend_from_slice(&data); @@ -313,12 +305,60 @@ pub async fn main_work<'d>( audio_buffer = Vec::with_capacity(8192); } } + Event::MicAudioChunk(data) if state == State::Speaking && allow_interrupt => { + submit_audio += data.len() as f32 / 16000.0; + audio_buffer.extend_from_slice(&data); + if audio_buffer.len() == 0 { + player_tx + .send(AudioEvent::StopSpeech) + .map_err(|_| anyhow::anyhow!("Error sending stop"))?; + } + + if submit_audio > 0.6 { + state = State::Listening; + gui.state = "Listening...".to_string(); + gui.display_flush().unwrap(); + + server.reconnect_with_retry(3).await?; + + start_submit = true; + server + .send_client_command(protocol::ClientCommand::StartChat) + .await?; + + player_tx + .send(AudioEvent::ClearSpeech) + .map_err(|_| anyhow::anyhow!("Error sending clear"))?; + } + } + Event::MicAudioChunk(_) => { + log::debug!("Received MicAudioChunk while no Listening/Speaking state, ignoring"); + } Event::MicAudioEnd => { log::info!("Received MicAudioEnd"); - if state != State::Listening { - log::debug!("Received MicAudioEnd while no Listening state, ignoring"); + if state != State::Listening && state != State::Speaking { + log::debug!("Received MicAudioEnd while no Listening/Speaking state, ignoring"); continue; } + + if state == State::Speaking { + if !allow_interrupt { + log::info!("Interrupt not allowed, ignoring MicAudioEnd"); + continue; + } + log::info!("resuming to Listening state due to MicAudioEnd"); + player_tx + .send(AudioEvent::StartSpeech) + .map_err(|_| anyhow::anyhow!("Error sending stop"))?; + log::info!("Waiting for stop speech response"); + submit_audio = 0.0; + start_submit = false; + audio_buffer.clear(); + continue; + } + + log::info!("submit_audio = {}", submit_audio); + if submit_audio > 0.5 { if !audio_buffer.is_empty() { server.send_client_audio_chunk_i16(audio_buffer).await?; @@ -338,51 +378,6 @@ pub async fn main_work<'d>( gui.display_flush().unwrap(); } } - Event::MicInterrupt(interrupt_data) => { - log::info!( - "Received MicInterrupt with {} samples", - interrupt_data.len() - ); - if !(state == State::Listening || state == State::Speaking) { - log::debug!( - "Received MicInterrupt while no Listening or Speaking state, ignoring" - ); - continue; - } - - if !allow_interrupt { - log::info!("Interrupts are disabled, ignoring MicInterrupt"); - continue; - } - - let interrupt_audio_sec = interrupt_data.len() as f32 / 16000.0; - if interrupt_audio_sec < 1.2 { - log::info!( - "Interrupt audio too short ({} s), ignoring", - interrupt_audio_sec - ); - continue; - } - - let int_notify = Arc::new(tokio::sync::Notify::new()); - player_tx - .send(AudioEvent::Interrupt(int_notify.clone())) - .map_err(|e| anyhow::anyhow!("Error sending interrupt: {e:?}"))?; - log::info!("Waiting for interrupt response"); - let _ = int_notify.notified().await; - log::info!("Interrupt response received"); - - server.reconnect_with_retry(3).await?; - - start_submit = false; - submit_audio = interrupt_audio_sec; - audio_buffer = interrupt_data; - - state = State::Listening; - gui.state = "Listening...".to_string(); - gui.display_flush().unwrap(); - timeout = INTERNAL_TIMEOUT; - } Event::MicInterruptWaitTimeout => { log::info!("Received MicInterruptWaitTimeout"); timeout = NORMAL_TIMEOUT; diff --git a/src/audio.rs b/src/audio.rs index 6655388..3e6a3c4 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -23,7 +23,7 @@ unsafe fn afe_init() -> ( afe_config.pcm_config.sample_rate = 16000; afe_config.afe_ringbuf_size = 40; - afe_config.vad_min_noise_ms = 250; + afe_config.vad_min_noise_ms = 400; afe_config.vad_min_speech_ms = 250; // afe_config.vad_delay_ms = 250; // Don't change it!! afe_config.vad_mode = esp_sr::vad_mode_t_VAD_MODE_4; @@ -150,18 +150,13 @@ pub type PlayerRx = tokio::sync::mpsc::UnboundedReceiver; pub type EventTx = tokio::sync::mpsc::Sender; pub type EventRx = tokio::sync::mpsc::Receiver; -fn afe_worker(afe_handle: Arc, tx: EventTx, trigger_mean_value: f32) -> anyhow::Result<()> { +fn afe_worker(afe_handle: Arc, tx: EventTx) -> anyhow::Result<()> { log::info!("AFE worker started"); crate::log_heap(); crate::print_stack_high(); let mut speech = false; - let mut cache_buffer = Vec::with_capacity(16000); - let mut vol = VOL_NUM.load(std::sync::atomic::Ordering::Relaxed) as i16; - let mut trigger_mean_value_ = - trigger_mean_value * (get_volume(100, vol) as f32 / 100.0).max(0.3); loop { - let playing = PLAYING.load(std::sync::atomic::Ordering::Relaxed); let result = afe_handle.fetch(); if let Err(_e) = &result { continue; @@ -174,48 +169,18 @@ fn afe_worker(afe_handle: Arc, tx: EventTx, trigger_mean_value: f32) -> any if result.speech { if !speech { log::info!("Speech started"); - vol = VOL_NUM.load(std::sync::atomic::Ordering::Relaxed) as i16; - trigger_mean_value_ = - trigger_mean_value * (get_volume(100, vol) as f32 / 100.0).max(0.3); } speech = true; log::debug!("Speech detected, sending {} bytes", result.data.len()); - if playing || cache_buffer.len() > 0 { - cache_buffer.extend_from_slice(&result.data); - } else { - tx.blocking_send(crate::app::Event::MicAudioChunk(result.data)) - .map_err(|_| anyhow::anyhow!("Failed to send data"))?; - } + tx.blocking_send(crate::app::Event::MicAudioChunk(result.data)) + .map_err(|_| anyhow::anyhow!("Failed to send data"))?; continue; } if speech { log::info!("Speech ended"); - if !cache_buffer.is_empty() { - let len = cache_buffer.len() as f32; - let mean = cache_buffer - .iter() - .map(|x| (*x as f32).abs() / len) - .sum::(); - - if mean > trigger_mean_value_ || !playing { - log::info!("Sending cached {} s, mean:{}", len / 16000.0, mean); - tx.blocking_send(crate::app::Event::MicInterrupt(cache_buffer)) - .map_err(|_| anyhow::anyhow!("Failed to send data"))?; - cache_buffer = Vec::with_capacity(16000); - } else { - log::info!( - "Dropping cached {} s, mean:{} below trigger {}", - len / 16000.0, - mean, - trigger_mean_value_ - ); - cache_buffer.clear(); - } - } else { - tx.blocking_send(crate::app::Event::MicAudioEnd) - .map_err(|_| anyhow::anyhow!("Failed to send data"))?; - } + tx.blocking_send(crate::app::Event::MicAudioEnd) + .map_err(|_| anyhow::anyhow!("Failed to send data"))?; speech = false; } @@ -256,22 +221,23 @@ pub fn player_welcome( pub enum AudioEvent { Hello(Arc), SetHello(Vec), - Interrupt(Arc), + StopSpeech, StartSpeech, + ClearSpeech, SpeechChunk(Vec), SpeechChunki16(Vec), EndSpeech(Arc), VolSet(u8), } -enum SendBufferItem { +pub enum SendBufferItem { Audio(Vec), EndSpeech(Arc), } -struct SendBuffer { - cache: std::collections::LinkedList, - chunk_size: usize, +pub struct SendBuffer { + pub cache: std::collections::LinkedList, + pub chunk_size: usize, pub rest: Vec, pub volume: i16, } @@ -289,7 +255,7 @@ fn get_volume(value: i16, volume: i16) -> i16 { } impl SendBuffer { - fn new(chunk_size: usize) -> Self { + pub fn new(chunk_size: usize) -> Self { Self { cache: std::collections::LinkedList::new(), chunk_size, @@ -298,7 +264,7 @@ impl SendBuffer { } } - fn push_u8(&mut self, data: &[u8]) { + pub fn push_u8(&mut self, data: &[u8]) { if self.rest.len() > 0 { let needed = self.chunk_size * 2 - self.rest.len() * 2; if data.len() >= needed { @@ -342,7 +308,7 @@ impl SendBuffer { } } - fn push_i16(&mut self, data: &[i16]) { + pub fn push_i16(&mut self, data: &[i16]) { if self.rest.len() > 0 { let needed = self.chunk_size - self.rest.len(); if data.len() >= needed { @@ -374,11 +340,11 @@ impl SendBuffer { } } - fn push_back_end_speech(&mut self, notify: Arc) { + pub fn push_back_end_speech(&mut self, notify: Arc) { self.cache.push_back(SendBufferItem::EndSpeech(notify)); } - fn get_chunk(&mut self) -> Option> { + pub fn get_chunk(&mut self) -> Option> { loop { match self.cache.pop_front() { Some(SendBufferItem::Audio(v)) => return Some(v), @@ -391,7 +357,7 @@ impl SendBuffer { } } - fn clear(&mut self) { + pub fn clear(&mut self) { loop { match self.cache.pop_front() { Some(SendBufferItem::EndSpeech(tx)) => { @@ -494,12 +460,6 @@ fn audio_task_run( loop { if let Ok(event) = rx.try_recv() { match event { - AudioEvent::Interrupt(notify) => { - log::info!("Received Interrupt event"); - allow_speech = false; - send_buffer.clear(); - notify.notify_one(); - } AudioEvent::Hello(notify) => { log::info!("Received Hello event"); allow_speech = true; @@ -513,6 +473,12 @@ fn audio_task_run( AudioEvent::StartSpeech => { allow_speech = true; } + AudioEvent::StopSpeech => { + allow_speech = false; + } + AudioEvent::ClearSpeech => { + send_buffer.clear(); + } AudioEvent::SpeechChunk(items) => { send_buffer.push_u8(&items); } @@ -651,7 +617,7 @@ impl BoxAudioWorker { crate::log_heap(); let _afe_r = std::thread::Builder::new().stack_size(8 * 1024).spawn(|| { - let r = afe_worker(afe_handle_, tx, crate::boards::TRIGGER_MEAN_VALUE); + let r = afe_worker(afe_handle_, tx); if let Err(e) = r { log::error!("AFE worker error: {:?}", e); } @@ -742,7 +708,7 @@ impl BoardsAudioWorker { let _afe_r = std::thread::Builder::new() .stack_size(8 * 1024) - .spawn(|| afe_worker(afe_handle_, tx, crate::boards::TRIGGER_MEAN_VALUE))?; + .spawn(|| afe_worker(afe_handle_, tx))?; audio_task_run(&mut rx, &mut fn_read, &mut fn_write, afe_handle) } diff --git a/src/boards/atom_box.rs b/src/boards/atom_box.rs index 7f656b0..70e4212 100644 --- a/src/boards/atom_box.rs +++ b/src/boards/atom_box.rs @@ -5,7 +5,6 @@ use esp_idf_svc::{ const AUDIO_STACK_SIZE: usize = 15 * 1024; pub const AFE_AEC_OFFSET: usize = 512; -pub const TRIGGER_MEAN_VALUE: f32 = 550.0; pub fn afe_config(afe_config: &mut esp_idf_svc::sys::esp_sr::afe_config_t) { afe_config.agc_init = true; diff --git a/src/boards/base.rs b/src/boards/base.rs index 5da3b89..def7b9e 100644 --- a/src/boards/base.rs +++ b/src/boards/base.rs @@ -9,7 +9,6 @@ use esp_idf_svc::{ const AUDIO_STACK_SIZE: usize = 15 * 1024; pub const AFE_AEC_OFFSET: usize = 256; -pub const TRIGGER_MEAN_VALUE: f32 = 550.0; pub fn afe_config(afe_config: &mut esp_idf_svc::sys::esp_sr::afe_config_t) { afe_config.agc_init = true; diff --git a/src/boards/cube.rs b/src/boards/cube.rs index c510d21..76b6a54 100644 --- a/src/boards/cube.rs +++ b/src/boards/cube.rs @@ -9,7 +9,6 @@ use esp_idf_svc::{ const AUDIO_STACK_SIZE: usize = 15 * 1024; pub const AFE_AEC_OFFSET: usize = 256; -pub const TRIGGER_MEAN_VALUE: f32 = 300.0; pub fn afe_config(afe_config: &mut esp_idf_svc::sys::esp_sr::afe_config_t) { afe_config.agc_init = true; diff --git a/src/boards/cube2.rs b/src/boards/cube2.rs index 25ed40f..63880b9 100644 --- a/src/boards/cube2.rs +++ b/src/boards/cube2.rs @@ -9,7 +9,6 @@ use esp_idf_svc::{ const AUDIO_STACK_SIZE: usize = 15 * 1024; pub const AFE_AEC_OFFSET: usize = 256; -pub const TRIGGER_MEAN_VALUE: f32 = 300.0; pub fn afe_config(afe_config: &mut esp_idf_svc::sys::esp_sr::afe_config_t) { afe_config.agc_init = true;