未调用Audioqueue回调

时间:2013-12-19 11:44:06

标签: ios core-audio audioqueueservices

所以,基本上我想玩一些audio files(主要是mp3和caf)。但回调永远不会被调用。只有当我打电话给他们来填补队列时。

这是我的数据结构:

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

这是我的回调函数:

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;
    }
}

这是我的方法:

- (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");

}

按下播放时的输出:

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

我尝试将CFRunLoopGetCurrent()替换为CFRunLoopGetMain(),将CFRunLoopCommonModes替换为CFRunLoopDefaultMode,但没有。

引导缓冲区不应该立即开始播放我启动队列吗? 当我启动队列时,没有任何回调被解雇。 我究竟做错了什么?感谢您的任何想法

1 个答案:

答案 0 :(得分:3)

您在此基本上尝试做的是使用音频队列进行音频播放的基本示例。没有仔细查看你的代码以查看缺少的内容(这可能需要一段时间)我宁愿建议你按照this basic sample code中的步骤执行你正在做的事情(没有额外的东西'真的很相关..例如,为什么你要添加音频增益?)

在其他地方,您尝试使用音频设备播放音频。音频单元比基本音频队列播放更复杂,在对音频队列非常熟悉之前我不会尝试它们。但是您可以查看此example project以获取音频队列的基本示例。

一般来说,当谈到iOS中的Core Audio编程时,最好花点时间学习基本的例子并建立自己的方式..网上很多教程的问题是他们添加额外的东西并经常混合它使用obj-c代码..当Core Audio纯粹是C代码时(即额外的东西不会在学习过程中添加任何东西)。如果您还没有,我强烈建议您阅读本书Learning Core Audio。所有示例代码均可在线获取,但您也可以从this repo中克隆它以方便使用。这就是我学习核心音频的方式。这需要时间:)