5
votes

I've been working on a frequency detection application for iOS and I'm having an issue filling a user-defined AudioBufferList with audio samples from the microphone.

I'm getting a return code of -50 when I call AudioUnitRender in my InputCallback method. I believe this means one of my parameters is invalid. I'm guessing it's the AudioBufferList, but I haven't been able to figure out what is wrong with it. I think I've set it up so it matches the data format I've specified in my ASBD.

Below is the remote I/O setup and function calls that I believe could be incorrect:

ASBD:

size_t bytesPerSample = sizeof(AudioUnitSampleType);
AudioStreamBasicDescription localStreamFormat = {0};
localStreamFormat.mFormatID = kAudioFormatLinearPCM;
localStreamFormat.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical;
localStreamFormat.mBytesPerPacket = bytesPerSample;
localStreamFormat.mBytesPerFrame = bytesPerSample;
localStreamFormat.mFramesPerPacket = 1;
localStreamFormat.mBitsPerChannel = 8 * bytesPerSample;
localStreamFormat.mChannelsPerFrame = 2;
localStreamFormat.mSampleRate = sampleRate;

InputCallback Declaration:

err = AudioUnitSetProperty(ioUnit, kAudioOutputUnitProperty_SetInputCallback, 
                           kAudioUnitScope_Input, 
                           kOutputBus, &callbackStruct, sizeof(callbackStruct));

AudioBufferList Declaration:

// Allocate AudioBuffers
bufferList = (AudioBufferList *)malloc(sizeof(AudioBuffer));
bufferList->mNumberBuffers = 1;
bufferList->mBuffers[0].mNumberChannels = 2;

bufferList->mBuffers[0].mDataByteSize = 1024;
bufferList->mBuffers[0].mData = calloc(256, sizeof(uint32_t));

InputCallback Function:

AudioUnit rioUnit = THIS->ioUnit;
OSStatus renderErr;
UInt32 bus1 = 1;
renderErr = AudioUnitRender(rioUnit, ioActionFlags, inTimeStamp, bus1, inNumberFrames, THIS->bufferList);

A few things to note:

  • Sample Rate = 22050 Hz
  • Since the canonical format of remote I/O data is 8.24-bit fixed point, I'm assuming the samples are 32 bits each (or 4 bytes). Since an unsigned int is 4 bytes, I'm using that to allocate my audio buffer.
  • I can get the same code to render audio correctly if I implement the audio data flow as PassThru rather than input only.
  • I've already looked at Michael Tyson's blog post on Remote I/O. Didn't see anything there different from what I'm doing.

Thanks again, you all are awesome!

Demetri

3
I finally finished the frequency detection application I mentioned. I've posted a write-up along with the source code for those interested. EDIT: the link...sleepyleaf.com/2011/01/25/pitch-detection-in-ios-4-xirtemed88
No Code has been found in mentioned.. Links sleepyleaf.com/2011/01/25/pitch-detection-in-ios-4-x – irtemed88h.kishan
Oops sorry, I updated my domain. New link: demetrimiller.com/2011/01/25/pitch-detection-in-ios-4-xirtemed88

3 Answers

6
votes

If you have 2 channels per frame, you cannot have bytesPerSample as the size of the frame. Since the terminology is a bit confusing:

  • A sample is a single value at a given position in a waveform
  • A channel refers to data associated with a particular audio stream, ie, left/right channel for stereo, a single channel for mono, etc.
  • A frame contains the samples for all channels for a given position in a waveform
  • A packet contains one or more frames

So basically, you need to use bytesPerSample * mChannelsPerFrame for mBytesPerFrame, and use mBytesPerFrame * mFramesPerPacket for mBytesPerPacket.

Also I noticed that you are using 32-bits for your sample size. I'm not sure if you really want to do this -- usually, you want to record audio using 16-bit samples. The sound difference between 16 and 32 bit audio is almost impossible for most listeners to hear (the average CD is mastered at 44.1kHz, 16-bit PCM), and it will spare you 50% of the I/O and storage costs.

0
votes

One difference is that Tyson's RemoteIO blog post uses 2 bytes per sample of linear PCM. So this might be a format incompatible error.

0
votes

The line bufferList = (AudioBufferList *)malloc(sizeof(AudioBuffer)); is also wrong. Since AudioBuffer is smaller than AudioBufferList, it allocates not enough memory.