为什么我的AudioQueueOutputCallback不能被调用?

时间:2011-09-27 21:05:19

标签: iphone ios core-audio audioqueueservices

我正在使用Audio Queue Services API通过iPhone上的TCP套接字连接播放从服务器流式传输的音频。我可以播放从套接字连接填充的缓冲区,我似乎无法让我的AudioQueue调用我的AudioQueueOutputCallback函数,而且我没有想法。

高级设计

  1. 数据从套接字连接传递给播放器并写入 立即进入内存中的循环缓冲区。
  2. 当AudioQueueBuffers变为可用时,数据将从循环缓冲区复制到 可用的AudioQueueBuffer,立即重新排队。 (或者,如果我的回调发生了)
  3. 会发生什么

    缓冲区全部填满并排队成功,我清楚地听到了音频流。为了测试,我使用大量缓冲区(15)并且所有缓冲区都无缝地播放,但是AudioQueueOutputCallback永远不会被调用,因此我从不重新排队任何缓冲区,尽管事实上一切似乎都在完美地运行。如果我不等待我的回调,假设它永远不会被调用,而是根据写入的数据驱动缓冲区的入队,我可以无限期地播放音频流,重用和重新入队缓冲区就好像它们一样已经通过回调明确地回复了我。事实就是这样:我可以根据需要重复使用缓冲区来完美地播放流,这让我感到困惑。为什么不调用回调?

    可能相关的代码

    流的格式是16位线性PCM,8 kHz,Mono:

    _streamDescription.mSampleRate = 8000.0f;
    _streamDescription.mFormatID = kAudioFormatLinearPCM;
    _streamDescription.mBytesPerPacket = 2;
    _streamDescription.mFramesPerPacket = 1;
    _streamDescription.mBytesPerFrame = sizeof(AudioSampleType);
    _streamDescription.mChannelsPerFrame = 1;
    _streamDescription.mBitsPerChannel = 8 * sizeof(AudioSampleType)
    _streamDescription.mReserved = 0;
    _streamDescription.mFormatFlags = (kLinearPCMFormatFlagIsBigEndian | 
                                       kLinearPCMFormatFlagIsPacked);
    

    我的原型和回调的实现如下。没有什么花哨的,与我到目前为止看到的每个例子几乎相同:

    // Prototype, declared above the class's @implementation
    void AQBufferCallback(void* inUserData, AudioQueueRef inAudioQueue, AudioQueueBufferRef inAudioQueueBuffer);
    
    // Definition at the bottom of the file.
    void AQBufferCallback(void* inUserData, AudioQueueRef inAudioQueue, AudioQueueBufferRef inAudioQueueBuffer) {
    
        printf("callback\n");
        [(MyAudioPlayer *)inUserData audioQueue:inAudioQueue didAquireBufferForReuse:inAudioQueueBuffer];
    }
    

    我像这样创建AudioQueue:

    OSStatus status = 0;
    status = AudioQueueNewOutput(&_streamDescription, 
                                 AQBufferCallback, // <-- Doesn't work...
                                 self, 
                                 CFRunLoopGetCurrent(),
                                 kCFRunLoopCommonModes, 
                                 0,
                                 &_audioQueue);
    if (status) {
    
        // This is not called...
        NSLog(@"Error creating new audio output queue: %@", [MyAudioPlayer stringForOSStatus:status]);
        return;
    }
    

    我将这样的缓冲区排入队列。此时,已知本地缓冲区包含用于复制的正确数据量:

    memcpy(aqBuffer->mAudioData, localBuffer, kAQBufferSize);
    aqBuffer->mAudioDataByteSize = kAQBufferSize;
    
    OSStatus status = AudioQueueEnqueueBuffer(_audioQueue, aqBuffer, 0, NULL);
    if (status) {
        // This is also not called.
        NSLog(@"Error enqueueing buffer %@", [MyAudioPlayer stringForOSStatus:status]);
    }
    

    请救救我。

2 个答案:

答案 0 :(得分:7)

这是在主线程还是后台线程上执行的?如果CFRunLoopGetCurrent()返回可能消失的线程的运行循环(线程池等)或者是一个不关心kCFRunLoopCommonModes的运行循环,则可能不太好。

尝试将CFRunLoopGetCurrent()更改为CFRunLoopGetMain()或确保在主线程或您已控制的线程上执行AudioQueueNewOutput()CFRunLoopGetCurrent()并且运行正常循环。

答案 1 :(得分:-2)

尝试更改self的{​​{1}}。像这样:

(void*)self