use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicBool, Ordering}; use std::thread::JoinHandle; use std::time::Instant; use cpal::{default_host, BufferSize, Device, SampleRate, Stream, StreamConfig, SupportedStreamConfig}; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use crate::core::mixer::AudioMixer; use crate::domain::event::{Event, EventBus}; use crate::utils::real_time_event::RealTimeEvent; #[derive(Clone)] pub struct Speaker { device: Device } pub struct AudioPlayback { event_bus: EventBus, speaker: Speaker, running: Arc, stream: Option, worker: Option>, mixer: AudioMixer } impl Speaker { pub fn new(device: Device) -> Self { Speaker { device } } pub fn default() -> Self { let host = default_host(); let device = host.default_output_device().unwrap(); Speaker::new(device) } pub fn get_output_config(&self) -> SupportedStreamConfig { self.device.default_output_config().unwrap() } pub fn get_stream_config(&self) -> StreamConfig { let config = self.get_output_config(); let mut stream_config: StreamConfig = config.into(); stream_config.channels = 2; stream_config.sample_rate = SampleRate(48000); stream_config.buffer_size = BufferSize::Fixed(960); stream_config } pub fn build_stream(&self, callback: F) -> Stream where F: FnMut(&mut [i16], &cpal::OutputCallbackInfo) + Send + 'static, { let config = self.get_stream_config(); self.device.build_output_stream( &config, callback, |err| println!("Error output stream: {err}"), None ).unwrap() } } impl AudioPlayback { pub fn new(event_bus: EventBus, speaker: Speaker, mixer: AudioMixer) -> Self { Self { event_bus, speaker, running: Arc::new(AtomicBool::new(false)), stream: None, worker: None, mixer } } pub fn default(event_bus: EventBus, mixer: AudioMixer) -> Self { let speaker = Speaker::default(); AudioPlayback::new(event_bus, speaker, mixer) } pub async fn start(&mut self) { self.running.store(true, Ordering::SeqCst); let stream_running = self.running.clone(); let event_bus = self.event_bus.clone(); let mixer = self.mixer.clone(); // stream cpal println!("Setting up audio playback stream..."); let last_time = Mutex::new(Instant::now()); let stream = self.speaker.build_stream(move |data, info| { println!( "CALLBACK : reçu {} samples, type info = {:?}", data.len(), info ); let now = Instant::now(); let mut last = last_time.lock().unwrap(); let dt = now.duration_since(*last); println!("Callback audio appelée chaque {:?} ms (≈ {:.1} Hz)", dt.as_millis(), 1000.0 / dt.as_millis().max(1) as f32); *last = now; if !stream_running.load(Ordering::Relaxed){ return; } println!("Audio playback stream tick"); let audio_mixer = mixer.read(data.len()); data.copy_from_slice(&audio_mixer); // println!("data content : {:?}", data); let _ = event_bus.emit_sync(Event::PlaybackTick(data.len())); }); stream.play().unwrap(); self.stream = Some(stream); println!("Audio playback stream started"); } pub async fn stop(&mut self) { self.running.store(false, Ordering::SeqCst); } }