Repository navigation
Fix SIGABRT on audio interruptions: reject stale render clocks in Deck.play - #93
Merged
sanylax0 merged 1 commit intoJul 18, 2026
Conversation
…k.play The stem-sync anchor used lastRenderTime guarded only by isHostTimeValid — but after a stop + engine restart (Siri announcement interruptions, route/config changes), lastRenderTime can be valid yet STALE, a timestamp from the pre-interruption render timeline. Anchoring play(at:) to it puts the start time in the past, raising the uncatchable AVFAudio start-time exception — a mid-song SIGABRT whenever the system pokes the audio environment (matches the Siri-announcement crash and the invisible mid-song deaths). Require a render cycle within the last second and anchor to mach_absolute_time() now; otherwise fall back to plain play() calls.
sanylax0
approved these changes
Jul 18, 2026
sanylax0
left a comment
Collaborator
There was a problem hiding this comment.
looks like it should work
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Fixes the crash that fired exactly when a Siri announcement interrupted playback — and very likely the other "invisible" mid-song deaths since the memory fixes landed.
RCA
A Siri announcement (or phone call, timer, route/config change) delivers an audio interruption: the system stops the engine; on
.ended(.shouldResume)the app runsrecoverPlayback→ engine restart → reschedule →Deck.play(). The stem-sync anchor there usedaccompPlayer.lastRenderTimeguarded only byisHostTimeValid— but after a stop→restart,lastRenderTimecan be valid yet stale: a host timestamp from the pre-interruption render timeline.play(at: staleTime + 0.03s)is a start time in the past → AVFAudio raises the uncatchablecom.apple.coreaudio.avfaudioNSException → SIGABRT. The same line is reached byAVAudioEngineConfigurationChangerecovery (force: true), which fires on invisible system events (Bluetooth chatter, sample-rate switches) — so every such event mid-song rolled the same dice, matching "crashed mid-song, nothing special happening."How
Deck.play()'s stem branch now requires the render clock to be fresh (a render cycle within the last second — proof the engine is actively rendering) and anchors the shared start atmach_absolute_time()now + 30 ms, never at the render timestamp. Anything else — cold start, post-interruption restart, stale clock — falls back to two plainplay()calls (the pre-sync behavior; on a freshly restarted engine they land on the same quantum in practice).Testing
On device: play a stem-separated track and trigger a few Siri announcements / timers mid-song — playback should pause and resume cleanly every time (the window is racy, so repeat). If a crash from before this fix is still in Settings → Analytics Data, a
Continuity-*.ipswithEXC_CRASH (SIGABRT)andAVAudioPlayerNode play(at:)in the crashed thread confirms this RCA.🤖 Generated with Claude Code
https://claude.ai/code/session_013TJoWkqg8bzkGdzxWhWjWP
Generated by Claude Code