Core Audio一次运行两个AudioQueues,连续录制/播放

时间:2012-05-29 21:14:53

标签: ios core-audio

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

由于

编辑:已添加代码

我在命令行应用程序中运行此POC。主要是我初始化一个录音机:

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

基本上,这里的目标只是拉出块并将其存储在缓冲区中。我相信这是可行的。

播放器已初始化:

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

}

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

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

由于

1 个答案:

答案 0 :(得分:2)

由于似乎没有人知道这一点,所以这里有一个非常好的示例项目链接:https://github.com/alexbw/novocaine