1

因此,假设我想通过设置所有内容并在我的输入回调中接收音频数据的常规过程来记录到我的输入队列中。我不想将其写入文件,而是想开始在某处短暂缓冲,然后将其提供给输出队列,该队列将在我的输入队列后不久开始运行,消耗我将从输入队列缓冲的数据,播放我正在录制的音频。这可能吗?我已尝试实现此功能,但在启动输出队列时遇到问题,我初始化并启动它时未报告任何错误,但在调用 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);

}

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

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

谢谢

4

1 回答 1

2

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

于 2012-05-31T15:48:44.597 回答