0

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 !

g0tcha-
  • 323
  • 3
  • 5
  • I'm not sure why you think 'myObj' would be released as you are not making a call to 'autorelease'. My 'objective c' is a little rusty but the code you show would be more like a memory leak. Perhaps you could show the internals for 'MyObjCObject.process'. – karmasponge Mar 10 '15 at 00:00
  • @karmasponge just added some details. – g0tcha- Mar 10 '15 at 00:49
  • You'll get `EXC_BAD_ACCESS` when you don't use `NSLog` properly. – l'L'l Mar 10 '15 at 00:52
  • We need to know the internals of `MyObjCObject process:` Right now, from what I can tell, this line `qr->objectiveC_Call([NSData dataWithBytes:inBuffer->mAudioData length:inBuffer->mAudioDataBytesCapacity]);` is creating an `autoreleased` `NSData` object which will dealloc after the current run loop unless you specifically retain it somewhere. – Tim Reddy Mar 10 '15 at 01:01

1 Answers1

0

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.

karmasponge
  • 1,169
  • 2
  • 12
  • 26