Error -50 writing to AVAudioFile

I'm trying to write 16-bit interleaved 2-channel data captured from a LiveSwitch audio source to a AVAudioFile. The buffer and file formats match but I get a bad parameter error from the API. Does this API not support the specified format or is there some other issue?

Here is the debugger output.

(lldb) po audioFile.url
▿ file:///private/var/mobile/Containers/Data/Application/1EB14379-0CF2-41B6-B742-4C9A80728DB3/tmp/Heart%20Sounds%201
  - _url : file:///private/var/mobile/Containers/Data/Application/1EB14379-0CF2-41B6-B742-4C9A80728DB3/tmp/Heart%20Sounds%201
  - _parseInfo : nil
  - _baseParseInfo : nil
(lldb) po error
Error Domain=com.apple.coreaudio.avfaudio Code=-50 "(null)" UserInfo={failed call=ExtAudioFileWrite(_impl->_extAudioFile, buffer.frameLength, buffer.audioBufferList)}
(lldb) po buffer.format
<AVAudioFormat 0x302a12b20:  2 ch,  44100 Hz, Int16, interleaved>
(lldb) po audioFile.fileFormat
<AVAudioFormat 0x302a515e0:  2 ch,  44100 Hz, Int16, interleaved>
(lldb) po buffer.frameLength
882
(lldb) po buffer.audioBufferList
▿ 0x0000000300941e60
  - pointerValue : 12894608992

This code handles the details of converting the Live Switch frame into an AVAudioPCMBuffer.

extension FMLiveSwitchAudioFrame {
    func convertedToPCMBuffer() -> AVAudioPCMBuffer {
        Self.convertToAVAudioPCMBuffer(from: self)!
    }

    static func convertToAVAudioPCMBuffer(from frame: FMLiveSwitchAudioFrame) -> AVAudioPCMBuffer? {
        // Retrieve the audio buffer and format details from the FMLiveSwitchAudioFrame
        guard
            let buffer = frame.buffer(),
            let format = buffer.format() as? FMLiveSwitchAudioFormat else { return nil }

        // Extract PCM format details from FMLiveSwitchAudioFormat
        let sampleRate = Double(format.clockRate())
        let channelCount = AVAudioChannelCount(format.channelCount())

        // Determine bytes per sample based on bit depth
        let bitsPerSample = 16
        let bytesPerSample = bitsPerSample / 8
        let bytesPerFrame = bytesPerSample * Int(channelCount)
        let frameLength = AVAudioFrameCount(Int(buffer.dataBuffer().length()) / bytesPerFrame)

        // Create an AVAudioFormat from the FMLiveSwitchAudioFormat
        guard let avAudioFormat = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: sampleRate, channels: channelCount, interleaved: true) else {
            return nil
        }

        // Create an AudioBufferList to wrap the existing buffer
        let audioBufferList = UnsafeMutablePointer<AudioBufferList>.allocate(capacity: 1)
        audioBufferList.pointee.mNumberBuffers = 1
        audioBufferList.pointee.mBuffers.mNumberChannels = channelCount
        audioBufferList.pointee.mBuffers.mDataByteSize = UInt32(buffer.dataBuffer().length())
        audioBufferList.pointee.mBuffers.mData = buffer.dataBuffer().data().mutableBytes // Directly use LiveSwitch buffer

        // Transfer ownership of the buffer to AVAudioPCMBuffer
        let pcmBuffer = AVAudioPCMBuffer(pcmFormat: avAudioFormat, bufferListNoCopy: audioBufferList) /* { buffer in
            // Ensure the buffer is freed when AVAudioPCMBuffer is deallocated
            buffer.deallocate() // Only call this if LiveSwitch allows manual deallocation
        } */

        pcmBuffer?.frameLength = frameLength
        return pcmBuffer
    }
}

This is the handler that is invoked with every frame in order to convert it for use with AVAudioFile and optionally update a scrolling signal display on the screen.

    private func onRaisedFrame(obj: Any!) -> Void {
        // Bail out early if no one is interested in the data.
        guard isMonitoring else { return }

        // Convert LS frame to AVAudioPCMBuffer (no-copy)
        let frame = obj as! FMLiveSwitchAudioFrame
        let buffer = frame.convertedToPCMBuffer()

        // Hand subscribers a reference to the buffer for rendering to display.
        bufferPublisher?.send(buffer)

        // If we have and output file, store the data there, as well.
        guard let audioFile = self.audioFile else { return }
        do {
            try audioFile.write(from: buffer) // FIXME: This call is throwing error -50
        } catch {
            FMLiveSwitchLog.error(withMessage: "Failed to write buffer to audio file at \(audioFile.url): \(error)")
            self.audioFile = nil
        }
    }

This is how the audio file is being setup.

static var recordingFormat: AVAudioFormat = {
        AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 44_100, channels: 2, interleaved: true)!
    }()

let audioFile = try AVAudioFile(forWriting: outputURL, settings: Self.recordingFormat.settings)
Error -50 writing to AVAudioFile
 
 
Q