c++iosexc-bad-accessaudioqueueservices

Prevent Objective-C object called from C++ code being released


Here is my situation:

I'm using Audio Queue Services in order to record sound. When the callback function is called (as soon as the buffer is full), I send the buffer content to an objective-C object to process it.

void AQRecorder::MyInputBufferHandler(void *                                inUserData,
                                      AudioQueueRef                         inAQ,
                                      AudioQueueBufferRef                   inBuffer,
                                      const AudioTimeStamp *                inStartTime,
                                      UInt32                                inNumPackets,
                                      const AudioStreamPacketDescription*   inPacketDesc)
{
    AQRecorder *aqr = (AQRecorder *)inUserData;
    try {
        if (inNumPackets > 0) {
            NSLog(@"Callback ! Sending buffer content ...");
            aqr->objectiveC_Call([NSData dataWithBytes:inBuffer->mAudioData length:inBuffer->mAudioDataBytesCapacity]);
            aqr->mRecordPacket += inNumPackets;
        }

        if (aqr->IsRunning())
            XThrowIfError(AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL), "AudioQueueEnqueueBuffer failed");
    } catch (CAXException e) {
        char buf[256];
        fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf));
    }
}

void AQRecorder::objectiveC_Call(NSData *buffer) {
    MyObjCObject *myObj = [[MyObjCObject alloc] init];
    [myObj process:buffer];
}

The problem here is that I get an EXC_BAD_ACCESS during my process (from myObj's process method), and after some research I guess that it's related to myObj being released.

MyObjCObject.process performs a for loop from the buffer content, and I get the EXC_BAD_ACCESS error even if I just do a NSLog on the buffer values.

-(void)run:(NSData *)bufferReceived {
   NSUInteger bufferSize = [bufferReceived length];
   self.buffer = (short *)malloc(bufferSize);
   memcpy(self.buffer, [bufferReceived bytes], bufferSize);

   for(int i= 0; i < bufferSize; i++) {
      NSLog("value: %i", buffer[i]);
   }

}  

Can you please tell me the way to do this ?

ps: My files have the .mm extension, ARC is enabled on the whole project and the rest of my code seems to works as expected.

Thanks !


Solution

  • You malloc the buffer and cast to a '(short*)' but then you enumerate the buffer using 'bufferSize' (number of bytes). That would mean that the 'for' loop would eventually attempt to read past the end of the buffer potentially resulting in 'EXE_BAD_ACCESS'. That would be because each iteration is moving forward by a 'short' rather than a 'byte'. You should change the loop to something like:

    for(int i= 0; i < bufferSize / sizeof(short); i++) {
        NSLog("value: %i", buffer[i]);
    }
    

    Either that or change the type of the 'buffer' member variable.