Occasional crashes in audio device callback on iOS


#1

I am close to completion with an iOS app that uses JUCE for the audio part. However, occasionally I get crashes (EXC_BAD_ACCESS) with the relevant part of the crash report as follows:

 

Thread 6 name:  AURemoteIO::IOThread
Thread 6 Crashed:
0   libsystem_c.dylib                 0x3a5d82a8 memmove$VARIANT$Swift + 674
1   Giggler                           0x00194850 juce::AudioSourcePlayer::audioDeviceIOCallback(float const**, int, float**, int, int) (juce_AudioSourcePlayer.cpp:129)
2   Giggler                           0x001930ee juce::AudioDeviceManager::audioDeviceIOCallbackInt(float const**, int, float**, int, int) (juce_AudioDeviceManager.cpp:691)
3   Giggler                           0x00199e9c juce::iOSAudioIODevice::process(unsigned long*, AudioTimeStamp const*, unsigned long, AudioBufferList*) (juce_ios_Audio.cpp:271)
4   Giggler                           0x00199d18 juce::iOSAudioIODevice::processStatic(void*, unsigned long*, AudioTimeStamp const*, unsigned long, unsigned long, AudioBufferList*) (juce_ios_Audio.cpp:411)
5   AudioToolbox                      0x31e915f0 AUInputElement::PullInput(unsigned long&, AudioTimeStamp const&, unsigned long, unsigned long) + 128
6   AudioToolbox                      0x31e91382 AUInputFormatConverter2::InputProc(OpaqueAudioConverter*, unsigned long*, AudioBufferList*, AudioStreamPacketDescription**, void*) + 250
7   AudioToolbox                      0x31e8dd9a AudioConverterChain::CallInputProc(unsigned long) + 326
8   AudioToolbox                      0x31e8db1c AudioConverterChain::FillBufferFromInputProc(unsigned long*, CABufferList*) + 72
9   AudioToolbox                      0x31e8dabe BufferedAudioConverter::GetInputBytes(unsigned long, unsigned long&, CABufferList const*&) + 102
10  AudioToolbox                      0x31e8d9da CBRConverter::RenderOutput(CABufferList*, unsigned long, unsigned long&, AudioStreamPacketDescription*) + 74
11  AudioToolbox                      0x31e8d80e BufferedAudioConverter::FillBuffer(unsigned long&, AudioBufferList&, AudioStreamPacketDescription*) + 194
12  AudioToolbox                      0x31e8d94e AudioConverterChain::RenderOutput(CABufferList*, unsigned long, unsigned long&, AudioStreamPacketDescription*) + 90
13  AudioToolbox                      0x31e8d80e BufferedAudioConverter::FillBuffer(unsigned long&, AudioBufferList&, AudioStreamPacketDescription*) + 194
14  AudioToolbox                      0x31e90df4 AudioConverterFillComplexBuffer + 352
15  AudioToolbox                      0x31e90a0a AUInputFormatConverter2::PullAndConvertInput(AudioTimeStamp const&, unsigned long&, AudioBufferList&, AudioStreamPacketDescription*, bool&) + 106
16  AudioToolbox                      0x31e90948 AUConverterBase::RenderBus(unsigned long&, AudioTimeStamp const&, unsigned long, unsigned long) + 824
17  AudioToolbox                      0x31e9057e AUBase::DoRenderBus(unsigned long&, AudioTimeStamp const&, unsigned long, AUOutputElement*, unsigned long, AudioBufferList&) + 210
18  AudioToolbox                      0x31e903a0 AUBase::DoRender(unsigned long&, AudioTimeStamp const&, unsigned long, unsigned long, AudioBufferList&) + 492
19  AudioToolbox                      0x31f48994 AURemoteIO::PerformIO(unsigned int, unsigned int, AudioTimeStamp const&, AudioTimeStamp const&, AudioBufferList const*, AudioBufferList*, int&) + 568
20  AudioToolbox                      0x31f48ddc AURIOCallbackReceiver_PerformIO + 480
21  AudioToolbox                      0x31f3ef36 _XPerformIO + 178
22  AudioToolbox                      0x31eb2588 mshMIGPerform + 380
23  AudioToolbox                      0x31f1a828 MSHMIGDispatchMessage + 28
24  AudioToolbox                      0x31f48b96 AURemoteIO::IOThread::Run() + 62
25  AudioToolbox                      0x31f4af4c AURemoteIO::IOThread::Entry(void*) + 4
26  AudioToolbox                      0x31e88932 CAPThread::Entry(CAPThread*) + 294
27  libsystem_c.dylib                 0x3a5c80de _pthread_start + 306
28  libsystem_c.dylib                 0x3a5c7fa4 thread_start + 4

Thus the crash occurs here in juce_AudioSourcePlayer.cpp:

memcpy (channels[numActiveChans], inputChans[i], sizeof (float) * (size_t) numSamples);

I am slightly behind the tip so the current source code line is 128, not 129, but I am pretty confident that this has nothing to do with this issue. Here's my theory: the JUCE in- and output buffers are preallocated when the audio device is opened, with a specific buffer size that is given to it at that time. However this buffer size seems to change occasionally, and when numSamples in the above line is bigger than the buffer size used during allocation, a crash will follow. Does that sound reasonable?


#2

Hmm... Not sure. It seems unlikely, but it'd be easy to find out for sure, by adding this assertion in the iOSAudioIODevice class:

 

    OSStatus process (AudioUnitRenderActionFlags* flags, const AudioTimeStamp* time,
                      const UInt32 numFrames, AudioBufferList* data)
    {

        jassert (numFrames <= floatData.getNumSamples());

#3

Did you get chance to try this out? I'd be interested to know whether this assertion ever got triggered..


#4

Yes, I did add that assertion... problem is it occurs very rarely, it must be some combination of factors (like incoming phone calls or so) that change the buffer size (if that is really the case). We'll be going into beta testing this week so I hope to get a few nice crash reports... will report back!


#5

Thanks, I added the assertion to the codebase, so hopefully if anyone else hits it, they'll also report it!


#6

Hi jules,

It happens when, from Audio Bus UI, I change the "Hardware audio buffer" from 256 to 512 while my app is running.

It seems like the method "AudioIODeviceCallback::audioDeviceAboutToStart" is not called, as it should, when the block size changes. 

Hope this will help you out.

 


#7

Are you actually using the latest version? I changed it so that it reallocates the buffer, so the problem reported by the OP should never happen. If you have a different problem, then at least give us a stack trace or something to go on.