From dc1dea955ebab215b73337347a23444d10f0873a Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 20 Jul 2026 00:53:40 +0000 Subject: [PATCH] Skip engine recovery on spurious configuration changes (long-press dropout) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Long-pressing a library row fires the context-menu haptic; the Taptic Engine shares the audio hardware and can post AVAudioEngineConfigurationChange while the engine is still rendering. The handler recovered unconditionally — stop + reschedule both stem players — turning a harmless notification into an audible ~1s dropout. Recover only when the engine actually stopped; real route/sample-rate changes still recover exactly as before. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_013TJoWkqg8bzkGdzxWhWjWP --- .../Sources/Playback/Player+AudioSession.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Packages/ContinuityKit/Sources/Playback/Player+AudioSession.swift b/Packages/ContinuityKit/Sources/Playback/Player+AudioSession.swift index 9e4e046..e471814 100644 --- a/Packages/ContinuityKit/Sources/Playback/Player+AudioSession.swift +++ b/Packages/ContinuityKit/Sources/Playback/Player+AudioSession.swift @@ -66,6 +66,14 @@ extension Player { // The engine stopped itself to apply a new configuration (sample rate/route). // Node schedules are gone; reschedule from the current position and keep going. guard let self, self.isPlaying else { return } + // Spurious changes happen with the engine still rendering — notably the + // Taptic Engine (context-menu long-press haptic) sharing the audio hardware. + // Recovery stops + reschedules both stem players (an audible ~1s dropout), + // so only do it when the engine actually stopped. + guard !engine.isRunning else { + Logger.audio.info("engine configuration change — engine still running, skipping recovery") + return + } Logger.audio.info("engine configuration change — recovering playback") self.recoverPlayback(force: true) }