0

I simply cannot figure out this issue. The audio from the code below is playing extremely fast and choppy. There's one other issue on SO that is similar, but it is for variable bitrate and not applicable.

Some possible answers on other sites (directly set number of frames per packet) no longer work and give a aq -50 error code.

This is from a synthesizer codebase, source audio is 8:24 Linear PCM at 44,100 Hz, non-interleaved. Setting the frames (4096) to the sample rate (44100Hz) seems to fix the choppiness, but the audio generation backend cannot keep up, so it stalls every packet.

Any solutions? For the life of me, I cannot figure out what's causing this to run so fast.

static const int kNumBuffers = 3;
typedef struct CoreAudio_audiodriver
{
    A2_audiodriver              ad;
    AudioQueueRef               queue;
    AudioQueueBufferRef         buffer[kNumBuffers];
    AudioStreamBasicDescription desc;
} CoreAudio_audiodriver;

/* CoreAudio render thread callback */
static void coreaudio_process(void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
{
    A2_audiodriver *driver = (A2_audiodriver *)inUserData;
    CoreAudio_audiodriver * cad = (CoreAudio_audiodriver *)inUserData;
    A2_config * config = driver->driver.config;
    int c, i;

    int frames = 4096 /* samples */;

    if( driver->Process )
    {
        driver->Process(driver, 4096 /* samples */); // loads 4096 samples into internal buffers
    }

    /* copy and interleave internal buffers to queue */
    for ( i = 0; i < frames; i++ )
    {
        for ( c = 0; c < 2 /* channels */; c++ )
        {
            ((int32_t *)inBuffer->mAudioData)[i + c] = driver->buffers[c][i];
        }
    }
    inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity;

    AudioQueueEnqueueBuffer(cad->queue, inBuffer, 0, NULL);
}

static int coreaudiod_Open(A2_driver *driver)
{
    CoreAudio_audiodriver * drv         = (CoreAudio_audiodriver *)driver;
    A2_config * config                  = drv->ad.driver.config;
    AudioStreamBasicDescription * desc  = &drv->desc;
    OSStatus err;
    int c, i;

    /* set up stream description */
    desc->mSampleRate        = (Float64)config->samplerate;
    desc->mFormatID          = kAudioFormatLinearPCM;
    desc->mFormatFlags       = kAudioFormatFlagIsSignedInteger;

    desc->mFramesPerPacket   = 1;
    desc->mChannelsPerFrame  = 2 /* channels */;

    /* packet -> frame -> channel -> data */
    desc->mBytesPerFrame     = desc->mChannelsPerFrame * sizeof(int32_t);
    desc->mBytesPerPacket    = desc->mBytesPerFrame * desc->mFramesPerPacket;
    desc->mBitsPerChannel    = 24; /* 8:24 PCM */

    /* set up queue */
    err = AudioQueueNewOutput(
                        desc,               // data format
                        coreaudio_process,  // callback
                        driver,             // data passed to callback
                        NULL,               // internal run loop
                        kCFRunLoopCommonModes, // kCFRunLoopCommonMode
                        0,                  // reserved by Apple
                        &drv->queue         // queue output
                    );

    for ( i = 0; i < kNumBuffers; i++ )
    {
        /* internal buffer */
        err = AudioQueueAllocateBuffer(
                            drv->queue,
                            desc->mBytesPerPacket * 4096 /* samples */,
                            &drv->buffer[i]
                        );

        /* start callback polling */
        drv->buffer[i]->mAudioDataByteSize = drv->buffer[i]->mAudioDataBytesCapacity;
        err = AudioQueueEnqueueBuffer(drv->queue, drv->buffer[i], 0, NULL);
    }

    err = AudioQueueStart(drv->queue, NULL);

    return 1;
}
Jonathan Howard
  • 216
  • 1
  • 10

1 Answers1

1

You may be handling the Audio Queue callback in your app's main UI thread. If you block this thread for too long (by spending too much doing doing synthesis, UI or drawRects, etc.) the AQ callback won't get called in time. Thus the audio output will underflow and sound choppy.

hotpaw2
  • 70,107
  • 14
  • 90
  • 153
  • Thanks. How would I determine what thread the callback is running in (this is a console app, so no UI running, but probably the synthesis. I thought AudioQueues run on a separate CFRunLoop. – Jonathan Howard Dec 18 '15 at 04:51