Audioqueue callback not being called

2.3k Views Asked by At

So, basically I want to play some audio files (mp3 and caf mostly). But the callback never gets called. Only when I call them to prime the queue.

Here's my data struct:

struct AQPlayerState
{
    CAStreamBasicDescription        mDataFormat;
    AudioQueueRef                   mQueue;
    AudioQueueBufferRef             mBuffers[kBufferNum];
    AudioFileID                     mAudioFile;
    UInt32                          bufferByteSize;
    SInt64                          mCurrentPacket;
    UInt32                          mNumPacketsToRead;
    AudioStreamPacketDescription   *mPacketDescs;
    bool                            mIsRunning;
};

Here's my callback function:

static void HandleOutputBuffer (void *aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
{
    NSLog(@"HandleOutput");
    AQPlayerState *pAqData = (AQPlayerState *) aqData;

    if (pAqData->mIsRunning == false) return;

    UInt32 numBytesReadFromFile;
    UInt32 numPackets = pAqData->mNumPacketsToRead;
    AudioFileReadPackets (pAqData->mAudioFile,
                          false,
                          &numBytesReadFromFile,
                          pAqData->mPacketDescs,
                          pAqData->mCurrentPacket,
                          &numPackets,
                          inBuffer->mAudioData);
    if (numPackets > 0) {    
        inBuffer->mAudioDataByteSize = numBytesReadFromFile;
        AudioQueueEnqueueBuffer (pAqData->mQueue,
                                 inBuffer,
                                 (pAqData->mPacketDescs ? numPackets : 0),
                                 pAqData->mPacketDescs);
        pAqData->mCurrentPacket += numPackets;
    } else {
//        AudioQueueStop(pAqData->mQueue, false);
//        AudioQueueDispose(pAqData->mQueue, true);
//        AudioFileClose (pAqData->mAudioFile);
//        free(pAqData->mPacketDescs);
//        free(pAqData->mFloatBuffer);
        pAqData->mIsRunning = false;
    }
}

And here's my method:

- (void)playFile
{
    AQPlayerState aqData;

    // get the source file
    NSString *p = [[NSBundle mainBundle] pathForResource:@"1_Female" ofType:@"mp3"];
    NSURL *url2 = [NSURL fileURLWithPath:p];
    CFURLRef srcFile = (__bridge CFURLRef)url2;

    OSStatus result = AudioFileOpenURL(srcFile, 0x1/*fsRdPerm*/, 0/*inFileTypeHint*/, &aqData.mAudioFile);
    CFRelease (srcFile);

    CheckError(result, "Error opinning sound file");

    UInt32 size = sizeof(aqData.mDataFormat);
    CheckError(AudioFileGetProperty(aqData.mAudioFile, kAudioFilePropertyDataFormat, &size, &aqData.mDataFormat),
               "Error getting file's data format");

    CheckError(AudioQueueNewOutput(&aqData.mDataFormat, HandleOutputBuffer, &aqData, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &aqData.mQueue),
               "Error AudioQueueNewOutPut");

    // we need to calculate how many packets we read at a time and how big a buffer we need
    // we base this on the size of the packets in the file and an approximate duration for each buffer
    {
        bool isFormatVBR = (aqData.mDataFormat.mBytesPerPacket == 0 || aqData.mDataFormat.mFramesPerPacket == 0);

        // first check to see what the max size of a packet is - if it is bigger
        // than our allocation default size, that needs to become larger
        UInt32 maxPacketSize;
        size = sizeof(maxPacketSize);
        CheckError(AudioFileGetProperty(aqData.mAudioFile, kAudioFilePropertyPacketSizeUpperBound, &size, &maxPacketSize),
                   "Error getting max packet size");

        // adjust buffer size to represent about a second of audio based on this format
        CalculateBytesForTime(aqData.mDataFormat, maxPacketSize, 1.0/*seconds*/, &aqData.bufferByteSize, &aqData.mNumPacketsToRead);

        if (isFormatVBR) {
            aqData.mPacketDescs = new AudioStreamPacketDescription [aqData.mNumPacketsToRead];
        } else {
            aqData.mPacketDescs = NULL; // we don't provide packet descriptions for constant bit rate formats (like linear PCM)
        }

        printf ("Buffer Byte Size: %d, Num Packets to Read: %d\n", (int)aqData.bufferByteSize, (int)aqData.mNumPacketsToRead);
    }

    // if the file has a magic cookie, we should get it and set it on the AQ
    size = sizeof(UInt32);
    result = AudioFileGetPropertyInfo(aqData.mAudioFile, kAudioFilePropertyMagicCookieData, &size, NULL);

    if (!result && size) {
        char* cookie = new char [size];
        CheckError(AudioFileGetProperty(aqData.mAudioFile, kAudioFilePropertyMagicCookieData, &size, cookie),
                   "Error getting cookie from file");
        CheckError(AudioQueueSetProperty(aqData.mQueue, kAudioQueueProperty_MagicCookie, cookie, size),
                   "Error setting cookie to file");
        delete[] cookie;
    }

    aqData.mCurrentPacket = 0;
    for (int i = 0; i < kBufferNum; ++i) {
        CheckError(AudioQueueAllocateBuffer (aqData.mQueue,
                                             aqData.bufferByteSize,
                                             &aqData.mBuffers[i]),
                   "Error AudioQueueAllocateBuffer");

        HandleOutputBuffer (&aqData,
                            aqData.mQueue,
                            aqData.mBuffers[i]);
    }

    // set queue's gain

    Float32 gain = 1.0;
    CheckError(AudioQueueSetParameter (aqData.mQueue,
                                       kAudioQueueParam_Volume,
                                       gain),
               "Error AudioQueueSetParameter");

    aqData.mIsRunning = true;
    CheckError(AudioQueueStart(aqData.mQueue,
                               NULL),
               "Error AudioQueueStart");

}

And the output when I press play:

Buffer Byte Size: 40310, Num Packets to Read: 38
HandleOutput start
HandleOutput start
HandleOutput start

I tryed replacing CFRunLoopGetCurrent() with CFRunLoopGetMain() and CFRunLoopCommonModes with CFRunLoopDefaultMode, but nothing.

Shouldn't the primed buffers start playing right away I start the queue? When I start the queue, no callbacks are bang fired. What am I doing wrong? Thanks for any ideas

1

There are 1 best solutions below

3
On BEST ANSWER

What you are basically trying to do here is a basic example of audio playback using Audio Queues. Without looking at your code in detail to see what's missing (that could take a while) i'd rather recommend to you to follow the steps in this basic sample code that does exactly what you're doing (without the extras that aren't really relevant.. for example why are you trying to add audio gain?)

Somewhere else you were trying to play audio using audio units. Audio units are more complex than basic audio queue playback, and I wouldn't attempt them before being very comfortable with audio queues. But you can look at this example project for a basic example of audio queues.

In general when it comes to Core Audio programming in iOS, it's best you take your time with the basic examples and build your way up.. the problem with a lot of tutorials online is that they add extra stuff and often mix it with obj-c code.. when Core Audio is purely C code (ie the extra stuff won't add anything to the learning process). I strongly recommend you go over the book Learning Core Audio if you haven't already. All the sample code is available online, but you can also clone it from this repo for convenience. That's how I learned core audio. It takes time :)