AudioQueue 如何从 CallBack 读取缓冲区

Posted

技术标签:

【中文标题】AudioQueue 如何从 CallBack 读取缓冲区【英文标题】:AudioQueue How to read the buffer from CallBack 【发布时间】:2011-06-02 14:12:58 【问题描述】:

我正在使用 AUdioQueue 记录来自内置麦克风的音频并通过套接字发送,我已将 AudioQueue 缓冲区设置为在一次拍摄中记录 30 秒的缓冲区并适当地分配 bufferSize, 这是我用来设置 AudioDataFormat 的函数。

AudiostreamBasicDescription sRecordFormat;
 FillOutASBDForLPCM (sRecordFormat,
                    16000,
                    1,
                    16,
                    16,
                    false,
                    false
                    );

下面的代码计算捕获音频需要分配的bufferSize,

int AQRecorder::ComputeRecordBufferSize(const AudioStreamBasicDescription *format, float seconds)

    int packets, frames, bytes = 0;
    try 
        frames = (int)ceil(seconds * format->mSampleRate);

        if (format->mBytesPerFrame > 0)
            bytes = frames * format->mBytesPerFrame;
        else 
            UInt32 maxPacketSize;
            if (format->mBytesPerPacket > 0)
                maxPacketSize = format->mBytesPerPacket;    // constant packet size
            else 
                UInt32 propertySize = sizeof(maxPacketSize);
                XThrowIfError(AudioQueueGetProperty(mQueue, kAudioQueueProperty_MaximumOutputPacketSize, &maxPacketSize,
                                                 &propertySize), "couldn't get queue's maximum output packet size");
            
            if (format->mFramesPerPacket > 0)
                packets = frames / format->mFramesPerPacket;
            else
                packets = frames;   // worst-case scenario: 1 frame in a packet
            if (packets == 0)       // sanity check
                packets = 1;
            bytes = packets * maxPacketSize;
        
     catch (CAXException e) 
        char buf[256];
        gLog<<[[NSString stringWithFormat:@"Error:%s (%s)\n",e.mOperation,e.FormatError(buf)] UTF8String]<<endl;
        return 0;
       
    return bytes;

以下代码示例分配缓冲区,

    // allocate and enqueue buffers
    bufferByteSize = ComputeRecordBufferSize(&mRecordFormat, kBufferDurationSeconds);   // enough bytes for 20 ms
    for (i = 0; i < kNumberRecordBuffers; ++i) 
        XThrowIfError(AudioQueueAllocateBuffer(mQueue, bufferByteSize, &mBuffers[i]),
                   "AudioQueueAllocateBuffer failed");
        XThrowIfError(AudioQueueEnqueueBuffer(mQueue, mBuffers[i], 0, NULL),
                   "AudioQueueEnqueueBuffer failed");
    

是的,你猜对了,大部分代码都来自 SpeakHere 示例, 对于 AudioCallback,我需要捕获缓冲区并通过套接字将其发送到其他机器,

// ____________________________________________________________________________________
// AudioQueue callback function, called when an input buffers has been filled.
void AQRecorder::MyInputBufferHandler(  void *                              inUserData,
                                        AudioQueueRef                       inAQ,
                                        AudioQueueBufferRef                 inBuffer,
                                        const AudioTimeStamp *              inStartTime,
                                        UInt32                              inNumPackets,
                                        const AudioStreamPacketDescription* inPacketDesc)

    AQRecorder *aqr = (AQRecorder *)inUserData;
    try 
           NSLog([NSString stringWithFormat:"Inside AudioBufferCallback no of packet [%d]",inMumPackets]);
        if (inNumPackets > 0) 
            // write packets to file 
                    // This is only for the test 
            XThrowIfError(AudioFileWritePackets(aqr->mRecordFile, FALSE, inBuffer->mAudioDataByteSize,
                                              inPacketDesc, aqr->mRecordPacket, &inNumPackets, inBuffer->mAudioData),
                       "AudioFileWritePackets failed");
            aqr->mRecordPacket += inNumPackets;

            if(aqr->pInputListener)
                aqr->pInputListener(aqr->pClientUserData,inBuffer->mAudioData,(int)inBuffer->mAudioDataByteSize);
            
        

        // if we're not stopping, re-enqueue the buffe so that it gets filled again
        if (aqr->IsRunning())
            XThrowIfError(AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL), "AudioQueueEnqueueBuffer failed");
     

现在当我看到日志时,数据来了,但它说没有数据包是 256、320 这样的,当我在另一端传递数据时,它听不见,谁能告诉我,我需要做什么使用 packetSize,我对 bufferSize 的印象足以发送数据,但我想,这也与数据包的数量有关。

【问题讨论】:

在回调中我也在文件中写入数据,那部分工作正常,唯一的问题是我不明白,如何使用数据包信息。 【参考方案1】:

缓冲区管理中的一些问题, 此应用程序可能需要在 20 毫秒 +- 5 毫秒内发送数据,在我的情况下,没有处理这种特殊情况。

【讨论】:

以上是关于AudioQueue 如何从 CallBack 读取缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

如何从流数据中实现 AudioQueue

如何访问 AudioQueue 缓冲区中的数据?

如何在不冻结 GUI 的情况下让 AudioQueue 播放?

使用 CoreAudio 中的 AudioQueue 从网络播放原始 pcm

AudioQueue 内存播放示例

如何在 AudioQueue 中检查当前时间和持续时间