Core Audio running two AudioQueues at once, continuous record/playback

本文探讨了使用 Core Audio 在 macOS 或 iOS 上实现同时录音和播放功能的方法。通过设置输入和输出队列,并利用缓冲区暂存数据,作者尝试实现实时的录音回放效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

from:  http://stackoverflow.com/questions/10806813/core-audio-running-two-audioqueues-at-once-continuous-record-playback
    
Core Audio running two AudioQueues at once, continuous record/playback

So lets say I wanted to record into my input queue by going through the usual process of setting everything up and receiving the audio data in my input callback. Instead of writing this to a file I would like to start buffering it somewhere briefly and then supply it out to an output queue that would start running shortly after my input queue, consuming the data that I would be buffering from the input queue, playing back the audio as I am recording it. Is this possible? I have tried implementing this but I am running into an issue with starting my output queue, I initialize and start it with no errors reported but after calling the AudioQueueStart function my supplied output callback is never called. Perhaps this is a problem with my implementation but I just wanted to make sure I am not crawling into a dead end first.

Thanks

EDIT: Code Added

Im running this POC in a command line app. In main I initialize a recorder:

    Recorder recorder = {0};

    AudioStreamBasicDescription asbd;
    memset(&asbd, 0, sizeof(asbd));

    asbd.mFormatID  = kAudioFormatLinearPCM;
    asbd.mSampleRate = SAMPLE_RATE;
    asbd.mBytesPerPacket = 4;
    asbd.mBytesPerFrame = 4;
    asbd.mChannelsPerFrame = 2;
    asbd.mBitsPerChannel = 16;
    asbd.mFramesPerPacket = 1;
    asbd.mFormatFlags = kAudioFormatFlagIsBigEndian |
    kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;

    AudioQueueRef queue = {0};


    reportError(AudioQueueNewInput(&asbd, MyAQInputCallback, &recorder, NULL, NULL, 0, &queue), "AudioQueue Input Create");

     int bufferSize = 88200;

    for (int i = 0; i < BUFFER_COUNT; i++) {

        AudioQueueBufferRef retBuffer;
        reportError(AudioQueueAllocateBuffer(queue, bufferSize, &retBuffer), "Error Allocating Buffer");
        reportError(AudioQueueEnqueueBuffer(queue, retBuffer, 0, NULL), "Error enqueuing buffer");


    }

    recorder.running = YES;
    reportError(AudioQueueStart(queue, NULL), "Start Failed");
    CFRunLoopRunInMode(kCFRunLoopDefaultMode, 3, false);

I declared a global void pointer array to hold data that comes in, this will change I just wanted to see if I can get it running:

   static void *buffer[1000];

My Input Callback. This does get called up to a certain point so the recorder has been running fine for me I have been recording to files and such before this:

   static void MyAQInputCallback(void *inUserData,
                          AudioQueueRef inQueue,
                          AudioQueueBufferRef inBuffer,
                          const AudioTimeStamp *inStartTime,
                          UInt32 inNumPackets,
                          const AudioStreamPacketDescription *inPacketDesc)
{

Recorder *recorder = (Recorder *) inUserData;

buffer[globalBufferIndex] = (short *)inBuffer->mAudioData;
++globalBufferIndex;

if (globalBufferIndex == 1000) {
    globalBufferIndex = 0;
    clearBuffer();
}
if ( recorder->running ) {
    reportError(AudioQueueEnqueueBuffer(inQueue, inBuffer, 0, NULL), "CallbackEnqueue Failed");
}
}

Basically the goal here is just to pull chunks off and store it in the buffer. I believe this works as it should.

The player is initialized:

Player player = {0};
AudioQueueRef que = {0};

reportError(AudioQueueNewOutput(&asbd, MyAQOutputCallback, &player, NULL, NULL, 0, &que), "New Output Error");

AudioQueueBufferRef buffers[BUFFER_COUNT];

 for (int i = 0; i < BUFFER_COUNT; ++i) {

        reportError(AudioQueueAllocateBuffer(que, bufferSize, &buffers[i]), "Error Buffer Allocating");

        MyAQOutputCallback(&player, que, buffers[i]);

  }

 reportError(AudioQueueStart(que, NULL), "Start Failed");

The player callback:

static void MyAQOutputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef   inCompleteAQBuffer)
{

Player *player;

player = (Player *) inUserData;

short *chunk = (short *) inCompleteAQBuffer->mAudioData;
chunk = buffer[globalOutputBufferIndex];
globalOutputBufferIndex++;

AudioQueueEnqueueBuffer(inAQ, inCompleteAQBuffer, sizeof(chunk)/4, player->packetDescs);

}

The goal being to store whats in the global buffer into the queue and send it off.

So I know this is not great structure but the behavior I get when I run it is that the recorder will run making its calls to the input callback and storing the data but then I start the player initialization and the output callback is called 3 times (my for loop calls) and never gets called again. I block the termination of the app at the end by making a call to getchar(). I have had the player work to read from files and play it, obviously this was a lot different. My recorder keeps on doing its job but my player callback is never called. I thought maybe its a problem with my descriptions but an error is never reported to me during allocation. Any guidance here would be great.

Thanks
ios core-audio
share|edit
    
edited May 30 at 15:15

    
asked May 29 at 21:14
Greg Price
6261210

85% accept rate
    
    
Show your code. – Robert Harvey♦ May 29 at 21:16
feedback
1 Answer
active oldest votes
up vote 0 down vote accepted
    

Since no one seems to know this, here is a link to a pretty good sample project that does this: https://github.com/alexbw/novocaine
share|edit
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值