diff --git a/linux-rust/src/media_controller.rs b/linux-rust/src/media_controller.rs index 5bd68b1a2..60f30e9f2 100644 --- a/linux-rust/src/media_controller.rs +++ b/linux-rust/src/media_controller.rs @@ -327,18 +327,45 @@ impl MediaController { } } - if !self.is_a2dp_profile_available().await { + let mut a2dp_available = self.is_a2dp_profile_available().await; + if !a2dp_available { + // A freshly (re)connected card often lists no a2dp-sink profiles + // for a moment while enumeration finishes. Give it a chance to + // settle before reaching for the sledgehammer below -- restarting + // WirePlumber tears down the whole audio session, and doing so + // mid-reconnect can leave the card stuck on profile "off". + tokio::time::sleep(Duration::from_secs(2)).await; + if let Some(idx) = self.get_audio_device_index(&mac).await { + self.state.lock().await.device_index = Some(idx); + } + a2dp_available = self.is_a2dp_profile_available().await; + } + + if !a2dp_available { warn!("A2DP profile not available, attempting to restart WirePlumber"); if self.restart_wire_plumber().await { - let mut state = self.state.lock().await; - state.device_index = self - .get_audio_device_index(&state.connected_device_mac) - .await; - debug!( - "Updated device_index after WirePlumber restart: {:?}", - state.device_index - ); - if !self.is_a2dp_profile_available().await { + // pipewire-pulse needs a moment to re-enumerate the Bluetooth + // card after WirePlumber restarts; a single immediate re-check + // races that re-enumeration and usually loses. + let mac = self.state.lock().await.connected_device_mac.clone(); + let mut ready = false; + for attempt in 1..=5u64 { + if let Some(idx) = self.get_audio_device_index(&mac).await { + self.state.lock().await.device_index = Some(idx); + if self.is_a2dp_profile_available().await { + ready = true; + break; + } + } + if attempt < 5 { + debug!( + "A2DP profile still not ready after WirePlumber restart \ + (attempt {attempt}/5), retrying" + ); + tokio::time::sleep(Duration::from_secs(attempt)).await; + } + } + if !ready { error!("A2DP profile still not available after WirePlumber restart"); return; }