diff --git a/src/context/offline.rs b/src/context/offline.rs index d3e3f4f0..5a8947ed 100644 --- a/src/context/offline.rs +++ b/src/context/offline.rs @@ -57,8 +57,6 @@ impl OfflineAudioContext { number_of_channels, receiver, frames_played_clone, - None, - None, ); // first, setup the base audio context diff --git a/src/io/cpal.rs b/src/io/cpal.rs index 35e90d1c..7103700b 100644 --- a/src/io/cpal.rs +++ b/src/io/cpal.rs @@ -186,14 +186,14 @@ impl AudioBackendManager for CpalBackend { // shared atomic to report output latency to the control thread let output_latency = Arc::new(AtomicF64::new(0.)); - let renderer = RenderThread::new( + let mut renderer = RenderThread::new( sample_rate, preferred_config.channels as usize, ctrl_msg_recv.clone(), Arc::clone(&frames_played), - Some(load_value_send.clone()), - Some(event_send.clone()), ); + renderer.set_event_channels(load_value_send.clone(), event_send.clone()); + renderer.spawn_garbage_collector_thread(); log::debug!( "Attempt output stream with preferred config: {:?}", @@ -227,14 +227,14 @@ impl AudioBackendManager for CpalBackend { &supported_config ); - let renderer = RenderThread::new( + let mut renderer = RenderThread::new( sample_rate, supported_config.channels as usize, ctrl_msg_recv, frames_played, - Some(load_value_send), - Some(event_send), ); + renderer.set_event_channels(load_value_send, event_send); + renderer.spawn_garbage_collector_thread(); let spawned = spawn_output_stream( &device, diff --git a/src/io/cubeb.rs b/src/io/cubeb.rs index 370559a0..bafd8f6a 100644 --- a/src/io/cubeb.rs +++ b/src/io/cubeb.rs @@ -182,14 +182,14 @@ impl AudioBackendManager for CubebBackend { _ => cubeb::ChannelLayout::UNDEFINED, // TODO, does this work? }; - let renderer = RenderThread::new( + let mut renderer = RenderThread::new( sample_rate, number_of_channels, ctrl_msg_recv, frames_played, - Some(load_value_send), - Some(event_send), ); + renderer.set_event_channels(load_value_send, event_send); + renderer.spawn_garbage_collector_thread(); let params = cubeb::StreamParamsBuilder::new() .format(cubeb::SampleFormat::Float32NE) // use float (native endian) diff --git a/src/io/none.rs b/src/io/none.rs index a98ebd5a..894bbaab 100644 --- a/src/io/none.rs +++ b/src/io/none.rs @@ -77,14 +77,10 @@ impl AudioBackendManager for NoneBackend { event_send, } = render_thread_init; - let render_thread = RenderThread::new( - sample_rate, - MAX_CHANNELS, - ctrl_msg_recv, - frames_played, - Some(load_value_send), - Some(event_send), - ); + let mut render_thread = + RenderThread::new(sample_rate, MAX_CHANNELS, ctrl_msg_recv, frames_played); + render_thread.set_event_channels(load_value_send, event_send); + render_thread.spawn_garbage_collector_thread(); // Use a bounded channel for real-time safety. A maximum of 32 control messages (resume, // suspend, ..) will be handled per render quantum. The control thread will block when the diff --git a/src/render/thread.rs b/src/render/thread.rs index cd97efc2..a953c60d 100644 --- a/src/render/thread.rs +++ b/src/render/thread.rs @@ -32,7 +32,7 @@ pub(crate) struct RenderThread { buffer_offset: Option<(usize, AudioRenderQuantum)>, load_value_sender: Option>, event_sender: Option>, - garbage_collector: llq::Producer>, + garbage_collector: Option>>, } // SAFETY: @@ -52,11 +52,7 @@ impl RenderThread { number_of_channels: usize, receiver: Receiver, frames_played: Arc, - load_value_sender: Option>, - event_sender: Option>, ) -> Self { - let (gc_producer, gc_consumer) = llq::Queue::new().split(); - spawn_garbage_collector_thread(gc_consumer); Self { graph: None, sample_rate, @@ -64,9 +60,26 @@ impl RenderThread { frames_played, receiver: Some(receiver), buffer_offset: None, - load_value_sender, - event_sender, - garbage_collector: gc_producer, + load_value_sender: None, + event_sender: None, + garbage_collector: None, + } + } + + pub(crate) fn set_event_channels( + &mut self, + load_value_sender: Sender, + event_sender: Sender, + ) { + self.load_value_sender = Some(load_value_sender); + self.event_sender = Some(event_sender); + } + + pub(crate) fn spawn_garbage_collector_thread(&mut self) { + if self.garbage_collector.is_none() { + let (gc_producer, gc_consumer) = llq::Queue::new().split(); + spawn_garbage_collector_thread(gc_consumer); + self.garbage_collector = Some(gc_producer); } } @@ -129,7 +142,9 @@ impl RenderThread { } NodeMessage { id, mut msg } => { self.graph.as_mut().unwrap().route_message(id, msg.as_mut()); - self.garbage_collector.push(msg); + if let Some(gc) = self.garbage_collector.as_mut() { + gc.push(msg) + } } } } @@ -301,8 +316,9 @@ impl RenderThread { impl Drop for RenderThread { fn drop(&mut self) { - self.garbage_collector - .push(llq::Node::new(Box::new(TerminateGarbageCollectorThread))); + if let Some(gc) = self.garbage_collector.as_mut() { + gc.push(llq::Node::new(Box::new(TerminateGarbageCollectorThread))) + } log::info!("Audio render thread has been dropped"); } }