From 0f642c8d50f67c413766958adc710a59d306e31c Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 9 Aug 2024 13:26:29 +0200 Subject: [PATCH] Restore some state in case of reinit failure when device has changed while paused, or when starting fails --- src/backend/mod.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 1de1a31..3e1508f 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -4877,6 +4877,8 @@ impl<'ctx> Drop for AudioUnitStream<'ctx> { impl<'ctx> StreamOps for AudioUnitStream<'ctx> { fn start(&mut self) -> Result<()> { + let was_stopped = self.stopped.load(Ordering::SeqCst); + let was_draining = self.draining.load(Ordering::SeqCst); self.stopped.store(false, Ordering::SeqCst); self.draining.store(false, Ordering::SeqCst); @@ -4886,22 +4888,33 @@ impl<'ctx> StreamOps for AudioUnitStream<'ctx> { // Need reinitialization: device was changed when paused. It will be started after // reinit because self.stopped is false. if self.delayed_reinit { - self.reinit().inspect_err(|_| { + let rv = self.reinit().inspect_err(|_| { cubeb_log!( "({:p}) delayed reinit during start failed.", self.core_stream_data.stm_ptr ); - })?; + }); + // In case of failure, restore the state + if rv.is_err() { + self.stopped.store(was_stopped, Ordering::SeqCst); + self.draining.store(was_draining, Ordering::SeqCst); + return rv; + } self.delayed_reinit = false; Ok(()) } else { // Execute start in serial queue to avoid racing with destroy or reinit. - self.core_stream_data.start_audiounits().inspect_err(|_| { + let rv = self.core_stream_data.start_audiounits(); + if rv.is_err() { cubeb_log!("({:p}) start failed.", self.core_stream_data.stm_ptr); - }) + self.stopped.store(was_stopped, Ordering::SeqCst); + self.draining.store(was_draining, Ordering::SeqCst); + return rv; + } + Ok(()) } }) - .unwrap(); + .unwrap()?; self.notify_state_changed(State::Started);