Josh Laase Josh Laase - 8 days ago 7
Objective-C Question

Call to AudioConverterFillComplexBuffer results in CrashIfClientProvidedBogusAudioBufferList only on MacOS Sierra

I have an audio program that makes a call to AudioConverterFillComplexBuffer with the following code:

OSStatus error = AudioConverterFillComplexBuffer(recorderObj->audioConverter,
MyAudioConverterCallback,
(__bridge void *)playerLocal,
&ioOutputDataPackets,
convertedData,
&streamDesc);


When this code runs on 10.6-10.11, it works fine. When the code runs on 10.12, it crashes with the following message

Crashed Thread: 16 com.apple.audio.IOThread.client

Exception Type: EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes: 0x0000000000000001, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY

Termination Signal: Illegal instruction: 4
Termination Reason: Namespace SIGNAL, Code 0x4
Terminating Process: exc handler [0]


The call stack ends in CrashIfClientProvidedBogusAudioBufferList.

Most articles, documentation and mailing lists would say that I have a bad output buffer but for the life of me, I cannot tell what I would be doing wrong but still have my code work on all versions of MacOS but the latest. Here is how I am setting up the buffer:

AudioBufferList *convertedData = (AudioBufferList*)malloc(sizeof(AudioBufferList) * 2);

convertedData->mNumberBuffers = 1;
convertedData->mBuffers[0].mNumberChannels = 2;
convertedData->mBuffers[0].mDataByteSize = 64 * 1024;
convertedData->mBuffers[0].mData = (UInt8 *)malloc(sizeof(UInt8) * 64 * 1024);


Here is the full stack at the point of the crash

Thread 16 Crashed:: com.apple.audio.IOThread.client
0 com.apple.audio.toolbox.AudioToolbox 0x00007fff89b9a330 CADebuggerStop() + 4
1 com.apple.audio.toolbox.AudioToolbox 0x00007fff89a21e71 CrashIfClientProvidedBogusAudioBufferList + 97
2 com.apple.audio.toolbox.AudioToolbox 0x00007fff89a2f710 AudioConverterChain::CallInputProc(unsigned int) + 646
3 com.apple.audio.toolbox.AudioToolbox 0x00007fff89a2f386 AudioConverterChain::FillBufferFromInputProc(unsigned int*, CABufferList*) + 130
4 com.apple.audio.toolbox.AudioToolbox 0x00007fff89a2f2ee BufferedAudioConverter::GetInputBytes(unsigned int, unsigned int&, CABufferList const*&) + 178
5 com.apple.audio.toolbox.AudioToolbox 0x00007fff89a2f1b2 CBRConverter::RenderOutput(CABufferList*, unsigned int, unsigned int&, AudioStreamPacketDescription*) + 106
6 com.apple.audio.toolbox.AudioToolbox 0x00007fff89a2225d BufferedAudioConverter::FillBuffer(unsigned int&, AudioBufferList&, AudioStreamPacketDescription*) + 281
7 com.apple.audio.toolbox.AudioToolbox 0x00007fff89a2f2c3 BufferedAudioConverter::GetInputBytes(unsigned int, unsigned int&, CABufferList const*&) + 135
8 com.apple.audio.toolbox.AudioToolbox 0x00007fff89a9369b Resampler2Wrapper::RenderOutput(CABufferList*, unsigned int, unsigned int&) + 183
9 com.apple.audio.toolbox.AudioToolbox 0x00007fff89a2225d BufferedAudioConverter::FillBuffer(unsigned int&, AudioBufferList&, AudioStreamPacketDescription*) + 281
10 com.apple.audio.toolbox.AudioToolbox 0x00007fff89a2f2c3 BufferedAudioConverter::GetInputBytes(unsigned int, unsigned int&, CABufferList const*&) + 135
11 com.apple.audio.toolbox.AudioToolbox 0x00007fff89a2f1b2 CBRConverter::RenderOutput(CABufferList*, unsigned int, unsigned int&, AudioStreamPacketDescription*) + 106
12 com.apple.audio.toolbox.AudioToolbox 0x00007fff89a2225d BufferedAudioConverter::FillBuffer(unsigned int&, AudioBufferList&, AudioStreamPacketDescription*) + 281
13 com.apple.audio.toolbox.AudioToolbox 0x00007fff89a2253f AudioConverterChain::RenderOutput(CABufferList*, unsigned int, unsigned int&, AudioStreamPacketDescription*) + 99
14 com.apple.audio.toolbox.AudioToolbox 0x00007fff89a2225d BufferedAudioConverter::FillBuffer(unsigned int&, AudioBufferList&, AudioStreamPacketDescription*) + 281
15 com.apple.audio.toolbox.AudioToolbox 0x00007fff89a21d2f AudioConverterFillComplexBuffer + 282
16 com.pc-intercom.Intercom 0x0000000107a52803 0x107a4a000 + 34819
17 com.apple.audio.units.Components 0x000000010a38c97c AUHAL::AUIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*) + 2324
18 com.apple.audio.CoreAudio 0x00007fff8a71f951 HALC_ProxyIOContext::IOWorkLoop() + 4369
19 com.apple.audio.CoreAudio 0x00007fff8a71e667 HALC_ProxyIOContext::IOThreadEntry(void*) + 131
20 com.apple.audio.CoreAudio 0x00007fff8a71e38b HALB_IOThread::Entry(void*) + 75
21 libsystem_pthread.dylib 0x0000000108134aab _pthread_body + 180
22 libsystem_pthread.dylib 0x00000001081349f7 _pthread_start + 286
23 libsystem_pthread.dylib 0x0000000108134221 thread_start + 13


If anyone has any suggestions on how I can debug this issue, I would greatly appreciate the help.

Answer

In MyAudioConverterCallback, ioDataPacketCount is supposed to return frames for LPCM (I guess packets are frames for uncompressed audio), so set it to:

*ioDataPacketCount = recorderObj->inputBuffer->mBuffers[0].mDataByteSize/recorderObj->streamFormat.mBytesPerFrame; 

Pass a NULL AudioStreamPacketDescription to AudioConverterFillComplexBuffer instead of an array of 1 (this was causing crashes for me on 10.11). Your destination format is LPCM, so packet descriptions are unnecessary because your "packets" are all the same size.

Similarly, your source format is LPCM too, so you can remove the code that returns packet descriptions in MyAudioConverterCallback - it's also wrong.

On my machine, I get non-interleaved stereo for streamFormat which means MyAudioConverterCallback has to fill out ioData->mBuffers[1] too.

When setting up your convertedData AudioBufferList, sizePerPacket was using the source format packet size instead of the destination packet size. It should be:

sizePerPacket = mOutputFormat.mBytesPerPacket;

And finally, even when it's not crashing, this code can't be right because you're recording (say) 512 frames from the microphone, then asking the audio converter to convert 16384 - that's going to give you audio glitches.