Conversation
tutis
force-pushed
the
fix-audio-append-crash
branch
from
September 10, 2026 16:00
8e9c38a to
540b76a
Compare
AVAssetWriterInput.append() raises an Objective-C exception, which Swift cannot catch, when the writer has not yet started a session or has already failed. isReadyForMoreMediaData reports neither of those states, so the audio and microphone branches could append in both, terminating the app with SIGABRT and leaving a zero byte file behind, since finishWriting() never runs. Two ways in: an audio buffer arriving before the first video frame has called startSession(), and any buffer arriving after the writer has failed partway through a recording. The AVAudioEngine mic tap already checked startTime, so this extends the same reasoning to every append site. A failed writer now also ends the recording instead of leaving it running while every sample is dropped, which finalises the file written so far. The failure is reported through os.Logger rather than print, because a bundled app launched normally has stdout and stderr pointing at /dev/null, so neither print nor NSLog is recoverable afterwards. Verified on macOS 26: an os.Logger line appears under the dev.mnpn.Azayaka subsystem, the NSLog equivalent does not appear at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
tutis
force-pushed
the
fix-audio-append-crash
branch
from
September 11, 2026 14:18
540b76a to
25a5a5f
Compare
Author
|
Updated: the failure is now reported through A bundled app launched from Finder or LaunchServices has No change to the guard itself. |
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.
The crash
Azayaka aborts mid-recording with
SIGABRTand leaves a zero byte file behind. Captured on macOS 26.6.2 with Azayaka 1.4 (67), microphone recording enabled, 25 seconds into a recording:asiisabort() called, thrown from the audio receive queue.Cause
AVAssetWriterInput.append()raises an Objective-C exception when the writer has not started a session yet, or has already moved to.failed. Swift cannot catch an Objective-C exception, so either case terminates the process.isReadyForMoreMediaDatareports neither state, and inClassicProcessing.swiftit was the only guard on the.audioand.microphoneappends:Only the
.screenbranch callsstartSession(atSourceTime:), and nothing anywhere inspectsvW.statusorvW.errorafter setup. That leaves two ways in:Because the abort skips
finishWriting(), the mp4 never gets itsmoovatom and the whole recording is lost, not just the tail.The AVAudioEngine mic tap a few lines above already had the right idea (
micInput.isReadyForMoreMediaData && startTime != nil), so this extends the same check to every append site.The change
canAppend(to:)checks the writer exists, the session has started, and the status is.writingbefore consultingisReadyForMoreMediaData. Used by all four append sites, video included, since a failed writer breaks that one too.stopRecording(withError:)runsfinishWriting(), so the user keeps a playable file of everything captured up to the failure instead of an empty one.Verification
mainwith Xcode 26.6 (Swift 6.3.3), ad hoc signed.AVAssetWriterinto.failedon demand, so the failure branch is reasoned from the API contract and the crash report rather than exercised in a test. The guard itself is the part the crash proves is needed.Happy to adjust scope. I deliberately kept it to the guard and did not add a user facing alert for the mid recording failure, since
alertRecordingFailureis worded for start up failures and a new string would mean touching the localisation catalogue. Glad to add one if you would prefer that.🤖 Generated with Claude Code