Skip to content

Fix file transcription failing to open .MOV audio (CoreAudio error -54) - #983

Draft
YHKCyber wants to merge 1 commit into
altic-dev:mainfrom
YHKCyber:fix/mov-audio-conversion-error-54
Draft

YHKCyber wants to merge 1 commit into
altic-dev:mainfrom
YHKCyber:fix/mov-audio-conversion-error-54

Conversation

@YHKCyber

@YHKCyber YHKCyber commented Sep 17, 2026

Copy link
Copy Markdown

Description

Fixes file transcription failing on .MOV uploads with Failed to convert audio; Could not open audio file: ... (com.apple.coreaudio.avfaudio error -54.), even though .mov is advertised as a supported format.

Root cause: in MeetingTranscriptionService.transcribeFile(_:), the chunked/buffered transcription path (the path used for video containers) opened the raw video file URL directly with AVAudioFile(forReading:). AVAudioFile expects a standalone audio file and can't open many video containers this way, which throws CoreAudio error -54.

Fix: when the source is a video container (isVideoContainer), first extract its audio track to a temporary standalone .m4a file via AVAssetExportSession (AVAssetExportPresetAppleM4A), then open that with AVAudioFile. The temporary file is removed via defer once transcription finishes, whether it succeeds or throws.

Scope note: this only touches the buffered transcription path taken for video containers. The path for native audio files (wav/mp3/m4a/etc.) and the speaker-diarization path (which already skips video containers) are unchanged.

Type of Change

  • 🐞 Bug fix
  • ✨ New feature
  • 💥 Breaking change
  • 🧹 Chore
  • 📝 Documentation update

Related Issue or Discussion

Fixes #982

Testing

  • Tested on Intel Mac
  • Tested on Apple Silicon Mac
  • Tested on macOS version:
  • Ran linter locally: swiftlint --strict --config .swiftlint.yml Sources Tests Package.swift
  • Ran formatter locally: swiftformat --config .swiftformat Sources0/1 files require formatting for the changed file.
  • Ran tests locally:

Not yet verified (see Notes): this environment has only Xcode Command Line Tools, not full Xcode, so I could not run xcodebuild, the app itself, or swiftlint (which needs sourcekitd from a full Xcode install). No .mov file has been run through this code path yet. Opening as a draft for that reason — please do not merge until the manual testing below is done.

Screenshots / Video

  • No UI/visual changes; screenshots/video are not applicable.

Notes

What still needs to happen before this is ready for review:

  1. Build the app with full Xcode (./build.sh unsigned or the normal Xcode build) and confirm it compiles — this change has only been reviewed by eye and passed through swiftformat, not compiled.
  2. Manually upload a .mov file (ideally the same file/export settings that originally triggered error -54) to file transcription and confirm it now transcribes successfully instead of erroring.
  3. Manually confirm existing non-video formats (wav/mp3/m4a/etc.) still transcribe correctly — this path is unchanged for them, but worth a spot check.
  4. Confirm the temporary extracted .m4a (written to FileManager.default.temporaryDirectory) is actually removed after a run, including after a failed/cancelled transcription.
  5. Try a .mov with an unusual audio codec/no audio track at all, to confirm the new error path (Could not extract audio track from video: ...) surfaces a sane message instead of a crash.

Will move this out of draft once the above has been done.

AVAudioFile(forReading:) cannot open many video containers directly
even though .mov/.mp4 are advertised as supported formats. The
buffered/chunked transcription path used for video containers was
opening the raw video file URL with AVAudioFile, which throws
com.apple.coreaudio.avfaudio error -54 ("Could not open audio file").

Extract the audio track to a standalone .m4a via AVAssetExportSession
before handing it to AVAudioFile when the source is a video container,
and clean up the temporary file afterward.

Fixes altic-dev#982

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions github-actions Bot added needs PR template Pull request is missing required template content. needs screenshots Pull request needs screenshot or video evidence. labels Sep 17, 2026
@github-actions

Copy link
Copy Markdown

The PR Policy check is blocking this PR because required template information is missing.

Please update the PR description with:

  • Description
  • Type of Change
  • Related Issue or Discussion
  • Testing
  • Screenshots / Video

Screenshots or video are required for UI, UX, settings, onboarding, overlay, menu bar, or visual behavior changes. If this PR has no visual changes, check the no-visual-change box in the template.

If this remains incomplete for 48 hours after opening, the PR may be closed.

@greptile-apps

greptile-apps Bot commented Sep 17, 2026

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

The PR appears safe to merge after addressing the non-blocking failure-path temporary-file cleanup concern.

Summary

The PR fixes .mov and other video-container transcription by exporting their audio track to a temporary .m4a before opening it with AVAudioFile.

  • Adds video-container audio extraction using AVAssetExportSession.
  • Routes buffered transcription through the extracted audio file.
  • Cleans successful extraction outputs after transcription, but leaves failure-path cleanup incomplete.

Reviews (1) · Last reviewed commit: "Fix file transcription failing to open ...."

Comment on lines +681 to +698
let outputURL = FileManager.default.temporaryDirectory
.appendingPathComponent(UUID().uuidString)
.appendingPathExtension("m4a")

exportSession.outputURL = outputURL
exportSession.outputFileType = .m4a

await exportSession.export()

if let error = exportSession.error {
throw error
}
guard exportSession.status == .completed else {
throw TranscriptionError
.audioConversionFailed("Audio export did not complete (status: \(exportSession.status.rawValue))")
}

return outputURL

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Failed exports leave temporary files

If an export creates its destination before failing or being cancelled, extractAudioTrack throws without removing that file. The caller cannot clean it up because it receives the URL only after a successful return, so repeated failures can accumulate temporary .m4a files. Register cleanup inside this helper and preserve the file only after export completes.

Suggested change
let outputURL = FileManager.default.temporaryDirectory
.appendingPathComponent(UUID().uuidString)
.appendingPathExtension("m4a")
exportSession.outputURL = outputURL
exportSession.outputFileType = .m4a
await exportSession.export()
if let error = exportSession.error {
throw error
}
guard exportSession.status == .completed else {
throw TranscriptionError
.audioConversionFailed("Audio export did not complete (status: \(exportSession.status.rawValue))")
}
return outputURL
let outputURL = FileManager.default.temporaryDirectory
.appendingPathComponent(UUID().uuidString)
.appendingPathExtension("m4a")
var shouldRemoveOutput = true
defer {
if shouldRemoveOutput {
try? FileManager.default.removeItem(at: outputURL)
}
}
exportSession.outputURL = outputURL
exportSession.outputFileType = .m4a
await exportSession.export()
if let error = exportSession.error {
throw error
}
guard exportSession.status == .completed else {
throw TranscriptionError
.audioConversionFailed("Audio export did not complete (status: \(exportSession.status.rawValue))")
}
shouldRemoveOutput = false
return outputURL
Prompt To Fix With AI
This is a comment left during a code review.
Path: Sources/Fluid/Services/MeetingTranscriptionService.swift
Line: 681-698

Comment:
**Failed exports leave temporary files**

If an export creates its destination before failing or being cancelled, `extractAudioTrack` throws without removing that file. The caller cannot clean it up because it receives the URL only after a successful return, so repeated failures can accumulate temporary `.m4a` files. Register cleanup inside this helper and preserve the file only after export completes.

```suggestion
        let outputURL = FileManager.default.temporaryDirectory
            .appendingPathComponent(UUID().uuidString)
            .appendingPathExtension("m4a")
        var shouldRemoveOutput = true
        defer {
            if shouldRemoveOutput {
                try? FileManager.default.removeItem(at: outputURL)
            }
        }

        exportSession.outputURL = outputURL
        exportSession.outputFileType = .m4a

        await exportSession.export()

        if let error = exportSession.error {
            throw error
        }
        guard exportSession.status == .completed else {
            throw TranscriptionError
                .audioConversionFailed("Audio export did not complete (status: \(exportSession.status.rawValue))")
        }

        shouldRemoveOutput = false
        return outputURL
```

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Codex

@YHKCyber
YHKCyber marked this pull request as draft September 17, 2026 16:22
@github-actions github-actions Bot removed needs PR template Pull request is missing required template content. needs screenshots Pull request needs screenshot or video evidence. labels Sep 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] File transcription fails to convert .MOV audio: "Could not open audio file" (com.apple.coreaudio.avfaudio error -54)

1 participant