Files
ox_speak_client/src-tauri/src/domain/audio_client.rs
2025-07-19 03:45:41 +02:00

111 lines
3.7 KiB
Rust

use std::sync::Arc;
use std::sync::atomic::AtomicU32;
use std::time::Duration;
use tokio::sync::mpsc;
use tokio::sync::oneshot;
use bytes::{Bytes};
use crate::core::opus::{AudioOpus, AudioOpusDecoder};
use crate::utils::ringbuf::{RingBufReader, RingBufWriter, RingBuffer};
use crate::utils::shared_store::SharedArcMap;
pub struct AudioClient {
uuid: uuid::Uuid,
decode_sender: mpsc::Sender<DecodeRequest>,
buffer_reader: RingBufReader<i16>,
buffer_writer: RingBufWriter<i16>
}
struct DecodeRequest {
data: Bytes,
sequence: u16,
}
#[derive(Clone)]
pub struct AudioClientManager {
audio_clients: SharedArcMap<uuid::Uuid, AudioClient>,
}
impl AudioClient {
pub fn new() -> Self {
let (writer, reader) = RingBuffer::<i16>::new(4096).split();
let (decode_sender, mut decode_reader) = mpsc::channel::<DecodeRequest>(100);
let writer_clone = writer.clone();
let decode_handle = tokio::spawn(async move {
let mut decoder = AudioOpus::new(48000, 1, "voip")
.create_decoder().unwrap();
let mut last_sequence: u16 = 0;
while let Some(request) = decode_reader.recv().await {
// si la séquence est "trop vieille" on la drop. (voir plus tard pour un système de rattrapage si c'est possible)
if last_sequence < request.sequence {
// todo : si le décodage est trop long, voir pour le mettre dans un thread
// avec let result = tokio::task::spawn_blocking({
// let data = request.data.clone();
// move || decoder.decode(&data)
// }).await.unwrap();
let start = std::time::Instant::now();
let result = decoder.decode(&request.data);
if start.elapsed() > Duration::from_millis(1) {
println!("⚠️ Frame drop possible: {:?}", start.elapsed());
}
match result {
Ok(audio_frame) => {
// Pousser la frame complète dans le buffer
writer_clone.push_slice_overwrite(&audio_frame);
println!("writed frame");
},
Err(e) => {
eprintln!("Erreur de décodage audio : {}", e);
}
}
last_sequence = request.sequence;
}
}
});
Self {
uuid: uuid::Uuid::new_v4(),
decode_sender,
buffer_reader: reader,
buffer_writer: writer,
}
}
pub fn write_audio(&self, sequence: u16, data: Bytes) {
let _ = self.decode_sender.try_send(DecodeRequest {
data,
sequence
});
}
}
impl AudioClientManager {
pub fn new() -> Self {
Self {
audio_clients: SharedArcMap::new()
}
}
pub fn audio_client_exists(&self, uuid: uuid::Uuid) -> bool {
self.audio_clients.contains_key(&uuid)
}
pub fn get_audio_client(&self, uuid: uuid::Uuid) -> Option<Arc<AudioClient>> {
self.audio_clients.get(&uuid)
}
pub fn add_audio_client(&self, uuid: uuid::Uuid, audio_client: AudioClient) {
self.audio_clients.insert(uuid, audio_client);
}
pub fn remove_audio_client(&self, uuid: uuid::Uuid) {
self.audio_clients.remove(&uuid);
}
pub fn write_audio_to_client(&self, uuid: uuid::Uuid, sequence: u16, data: Bytes) {
let _ = self.audio_clients.get(&uuid).unwrap().write_audio(sequence, data);
}
}