ios - Core Audio 同时运行两个 AudioQueues,连续录音/回放

标签 ios core-audio

假设我想通过设置所有内容并在我的输入回调中接收音频数据的常规过程来记录到我的输入队列中。我不想将其写入文件,而是想在某个地方开始短暂地缓冲它,然后将其提供给输出队列,输出队列将在我的输入队列后不久开始运行,消耗我将从输入队列缓冲的数据,回放我正在录制的音频。这可能吗?我已尝试实现此功能,但在启动输出队列时遇到问题,我初始化并启动它时没有报告任何错误,但在调用 AudioQueueStart 函数后,我提供的输出回调从未被调用。也许这是我的实现问题,但我只是想确保我不会先爬进死胡同。

谢谢

编辑:添加代码

我在命令行应用程序中运行这个 POC。在 main 中,我初始化了一个记录器:

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

我声明了一个全局 void 指针数组来保存传入的数据,这将改变我只是想看看我是否可以让它运行:

   static void *buffer[1000];

我的输入回调。这确实会被调用到某个点,所以录音机对我来说一直运行良好,在此之前我一直在记录文件等:

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

基本上,这里的目标只是提取 block 并将其存储在缓冲区中。我相信这是应该的。

播放器初始化:

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

播放器回调:

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

}

目标是将全局缓冲区中的内容存储到队列中并将其发送出去。

所以我知道这不是很好的结构,但是当我运行它时我得到的行为是记录器将运行,调用输入回调并存储数据,然后我开始播放器初始化并调用输出回调3 次(我的 for 循环调用)并且再也没有被调用过。最后,我通过调用 getchar() 来阻止应用程序的终止。我让播放器工作来读取文件并播放它,显然这有很大不同。我的录音机继续工作,但我的播放器回调从未被调用。我认为这可能是我的描述有问题,但在分配期间从未向我报告错误。这里的任何指导都会很棒。

谢谢

最佳答案

由于似乎没有人知道这一点,这里有一个指向执行此操作的非常好的示例项目的链接:https://github.com/alexbw/novocaine

关于ios - Core Audio 同时运行两个 AudioQueues,连续录音/回放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10806813/

相关文章:

ios - 如何使用带有 Pinterest.sharextension 的 UIActivityViewController 设置 Pinterest sourceURL 和描述

iOS Firebase Crashlytics 缺少 dSYM

ios - Rails Search 无法在 Heroku 的移动设备上运行

ios - 看看相机方法?不是 SCNLookAtConstraint

ios - 应用评论多久会出现在 iTunes Connect 中?

ios - 使用音频单元播放多个重叠的短音频文件

ios - 录制后更改音频比特率

iphone - 在 iPhone 上使用 RemoteIO 和 AudioUnits 播放 MP3...可能吗?

swift - AVAudioPCMBuffer 以编程方式构建,不以立体声播放

cocoa - 核心 MIDI : when I send a MIDIPacketList using MIDISend() only the first packet is being sent