Take the 2-minute tour ×

I'm trying to encode the raw PCM data from microphone to MP3 using AudioToolbox framework and Lame. And although everything seems to run fine, there is this problem with "clicks" and "distortions" present in the encoded stream. I'm not sure that I setup AudioQueue correctly and also that I process the encoded buffer in the right wat... My code to setup audio recording:

    AudioStreamBasicDescription streamFormat;
    memset(&streamFormat, 0, sizeof(AudioStreamBasicDescription));
    streamFormat.mSampleRate = 44100;
    streamFormat.mFormatID = kAudioFormatLinearPCM;
    streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger|kLinearPCMFormatFlagIsPacked;
    streamFormat.mBitsPerChannel = 16;
    streamFormat.mChannelsPerFrame = 1;
    streamFormat.mBytesPerPacket = 2;
    streamFormat.mBytesPerFrame = 2;
    streamFormat.mFramesPerPacket = 1;
    streamFormat.mReserved = 0;        

    AudioQueueNewInput(&streamFormat, InputBufferCallback, (__bridge void*)(self), nil, nil, 0, &mQueue);
    UInt32 bufferByteSize = 44100;
    memset(&mEncodedBuffer, 0, sizeof(mEncodedBuffer)); //mEncoded buffer is 
                                                        //unsigned char [72000]
    AudioQueueBufferRef buffer;
         AudioQueueAllocateBuffer(mQueue, bufferByteSize, &buffer);      
         AudioQueueEnqueueBuffer(mQueue, buffer, 0, NULL);
    AudioQueueStart(mQueue, nil);

Then the AudioQueue callback function calls to lame_encode_buffer and then writes the encoded buffer to file:

void InputBufferCallback (void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, const AudioTimeStamp *inStartTime, UInt32 inNumPackets, const AudioStreamPacketDescription* inPacketDesc) {
      int encodedBytes = lame_encode_buffer(glf, (short*)inBuffer->mAudioData, NULL, inBuffer->mAudioDataByteSize, mEncodedBuffer, 72000);
      //What I don't understand is that if I write the full 'encodedBytes' data,  then there are A LOT of distortions and original sound is seriously broken 
      NSData* data = [NSData dataWithBytes:mEncodedBuffer length:encodedBytes/2]; 
      [mOutputFile writeData:data];

And when I afterward try to play the file which contains Lame encoded data with AVAudioPlayer I clearly hear original sound but with some clicks and distortions around.

Can anybody advise what's wrong here?

share|improve this question
hi anton could you post corrected code inside InputBufferCallback method? –  Ravindhiran Aug 20 '13 at 7:27
add comment

1 Answer

up vote 2 down vote accepted

Your code does not appear to be paying attention to inNumPackets, which is the amount of actual audio data given the callback.

Also, doing a long operation, such as running an encoder, inside an audio callback might not be fast enough and thus may violate response requirements. Any long function calls should be done outside the callback.

share|improve this answer
Correct me if I'm wrong, but the amount of audio data passed to callback is indicated in the AudioQueueBuffer.mAudioDataByteSize value? However, the note regarding time required for Lame encoding is interesting - I will need to try to move encoding to a separate thread, though I didn't see any requirements on the maximum time allowed for the callback to return –  Anton Jun 5 '12 at 11:01
That buffer byte size is the maximum, not the actual amount of data passed to the callback. –  hotpaw2 Jun 5 '12 at 15:15
Thank you! Managed to solve it –  Anton Jun 6 '12 at 12:07
@Anton so instead of inBuffer->mAudioDataByteSize you passed inNumPackets? Is this correct? Another question: what did you set glf to be? –  JonathanC Nov 5 '12 at 18:16
@JonathanC This work has been completed fairly long ago, I refactored things a lot. But yes, it seems that inNumPacket is the correct way to go. Regarding initialisation of glf - go through some Lame samples. Basically you init it by calling lame_init() function and then apply the required settings to it –  Anton Nov 5 '12 at 22:06
show 1 more comment

Your Answer


