From 5764d060ddc6bf93843c99e6cc788302c8787c87 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 18 Jul 2026 16:20:02 +0000 Subject: [PATCH] Fix play-button crash: only sync-start stems once a render clock exists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The shared host-time anchor introduced for stem start sync used play(at:) unconditionally; on the very first start after the engine is built the player node has no render clock yet, and play(at:) throws the AVFAudio start-time exception — crashing on the play button. Anchor to the node's own lastRenderTime when it's host-time valid, and fall back to plain play() (the pre-sync behavior) on a cold start. --- .../ContinuityKit/Sources/Playback/Deck.swift | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Packages/ContinuityKit/Sources/Playback/Deck.swift b/Packages/ContinuityKit/Sources/Playback/Deck.swift index 4cd8f1f..cc4392e 100644 --- a/Packages/ContinuityKit/Sources/Playback/Deck.swift +++ b/Packages/ContinuityKit/Sources/Playback/Deck.swift @@ -135,9 +135,20 @@ final class Deck { // Two bare play() calls can land on different render quanta, starting the stems // several ms apart — and nothing ever re-aligns them. Anchor both to one shared // host-clock start just far enough out to cover the second call. - let start = AVAudioTime(hostTime: mach_absolute_time() + AVAudioTime.hostTime(forSeconds: 0.03)) - accompPlayer.play(at: start) - vocalsPlayer.play(at: start) + // + // Only when the node already has a render clock: play(at:) on a node that hasn't + // seen an IO cycle yet (first start after engine build) throws the AVFAudio + // start-time exception and crashes on the play button. On that first start the + // two play() calls run back-to-back on a freshly started engine, which in practice + // lands them on the same quantum; every later start (pause/resume, seek) syncs. + if let render = accompPlayer.lastRenderTime, render.isHostTimeValid { + let start = AVAudioTime(hostTime: render.hostTime + AVAudioTime.hostTime(forSeconds: 0.03)) + accompPlayer.play(at: start) + vocalsPlayer.play(at: start) + } else { + accompPlayer.play() + vocalsPlayer.play() + } } else { accompPlayer.play() }