AVAudioPCMBuffer Memory Management

I’m using AVAudioEngine to get a stream of AVAudioPCMBuffers from the device’s microphone using the usual installTap(onBus:) setup.

To distribute the audio stream to other parts of the program, I’m sending the buffers to a Combine publisher similar to the following:

private let publisher = PassthroughSubject<AVAudioPCMBuffer, Never>()

I’m starting to suspect I have some kind of concurrency or memory management issue with the buffers, because when consuming the buffers elsewhere I’m getting a range of crashes that suggest some internal pointer in a buffer is NULL (specifically, I’m seeing crashes in vDSP.convertElements(of:to:) when I try to read samples from the buffer).

These crashes are in production and fairly rare — I can’t reproduce them locally.

I never modify the audio buffers, only read them for analysis.


My question is: should it be possible to put AVAudioPCMBuffers into a Combine pipeline? Does the AVAudioPCMBuffer class not retain/release the underlying AudioBufferList’s memory the way I’m assuming? Is this a fundamentally flawed approach?

Did you ever figure this out? I've been doing the same thing. I don't get any crashes but when I hand the buffers of to LiveSwitch for playback, there is not audio signal.

  1. I receive the buffer from a tap on bus zero.
  2. I send the buffer to the publisher.
  3. Buffer is received, potentially by up to two consumers (currently one).
  4. Buffer has to be converted using AVAudioConverter from Float32 to Int16, which is required for consumption by LiveSwitch APIs.
  5. Buffer memory converted to NSMutableData (required by LiveSwitch)
  6. Buffer wrapped / converted in FMLiveSwitchAudioFrame.
  7. Buffer raised to LiveSwitch for processing.

Result: No signal.

AVAudioPCMBuffer Memory Management
 
 
Q