mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-29 00:06:09 +08:00
feat(native): async recorder (#14700)
#### PR Dependency Tree * **PR #14700** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Durable, resumable import queue with explicit import lifecycle and updated popup/tray status behavior. * Async native recording APIs and ability to abort recordings; audio quality metrics (degraded, overflow count). * Added "Importing..." translation. * **Bug Fixes** * More reliable single-claim import processing, retries and cleanup to avoid duplicate imports. * Improved stop/abort teardown stability and safer shutdown behavior. * **Tests** * New/updated tests covering coordinator, import queue, native async flows and teardown scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
use std::sync::Arc;
|
||||
use std::sync::{
|
||||
Arc,
|
||||
atomic::{AtomicU64, Ordering},
|
||||
};
|
||||
|
||||
use crossbeam_channel::Sender;
|
||||
use crossbeam_channel::{Sender, TrySendError};
|
||||
use napi::{
|
||||
bindgen_prelude::Float32Array,
|
||||
threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode},
|
||||
@@ -11,7 +14,10 @@ use napi::{
|
||||
#[derive(Clone)]
|
||||
pub enum AudioCallback {
|
||||
Js(Arc<ThreadsafeFunction<Float32Array, ()>>),
|
||||
Channel(Sender<Vec<f32>>),
|
||||
Channel {
|
||||
sender: Sender<Vec<f32>>,
|
||||
overflow_count: Arc<AtomicU64>,
|
||||
},
|
||||
}
|
||||
|
||||
impl AudioCallback {
|
||||
@@ -22,10 +28,38 @@ impl AudioCallback {
|
||||
// audio thread.
|
||||
let _ = func.call(Ok(samples.into()), ThreadsafeFunctionCallMode::NonBlocking);
|
||||
}
|
||||
Self::Channel(sender) => {
|
||||
// Drop the chunk if the channel is full to avoid blocking capture.
|
||||
let _ = sender.try_send(samples);
|
||||
}
|
||||
Self::Channel { sender, overflow_count } => match sender.try_send(samples) {
|
||||
Ok(()) => {}
|
||||
Err(TrySendError::Full(_)) => {
|
||||
overflow_count.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
Err(TrySendError::Disconnected(_)) => {}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use crossbeam_channel::bounded;
|
||||
|
||||
use super::AudioCallback;
|
||||
|
||||
#[test]
|
||||
fn channel_overflow_only_increments_the_counter() {
|
||||
let (sender, _rx) = bounded(1);
|
||||
let overflow_count = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0));
|
||||
let callback = AudioCallback::Channel {
|
||||
sender: sender.clone(),
|
||||
overflow_count: overflow_count.clone(),
|
||||
};
|
||||
|
||||
sender.send(vec![0.0]).unwrap();
|
||||
callback.call(vec![1.0]);
|
||||
callback.call(vec![2.0]);
|
||||
|
||||
assert_eq!(overflow_count.load(Ordering::Relaxed), 2);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user