C++ 核心音频环缓冲区数据为空

C++ 核心音频环缓冲区数据为空,c++,c,macos,audio,core-audio,C++,C,Macos,Audio,Core Audio,我正在制作《学习核心音频:Mac和iOS音频编程实践指南》一书中的一个演示。第8章展示了如何设置一个简单的音频单元图,以便从AUHAL输入单元播放到输出单元。此设置实际上没有连接音频单元;相反,这两个单元都使用回调并通过CARingBuffer实例传递音频数据。我正在为MacOS 10.15.6编写代码,并直接使用出版商提供的代码。下面是它的工作原理图: 代码生成并运行,但我没有得到音频。请注意,稍后,在引入语音合成单元后,我确实得到了回放,因此我知道基本功能正常 InputRenderPro

我正在制作《学习核心音频:Mac和iOS音频编程实践指南》一书中的一个演示。第8章展示了如何设置一个简单的音频单元图,以便从AUHAL输入单元播放到输出单元。此设置实际上没有连接音频单元;相反,这两个单元都使用回调并通过CARingBuffer实例传递音频数据。我正在为MacOS 10.15.6编写代码,并直接使用出版商提供的代码。下面是它的工作原理图:

代码生成并运行,但我没有得到音频。请注意,稍后,在引入语音合成单元后,我确实得到了回放,因此我知道基本功能正常

InputRenderProc请求AUHAL单元输入并将其存储在环形缓冲区中

    MyAUGraphPlayer *player = (MyAUGraphPlayer*) inRefCon;
    
    // have we ever logged input timing? (for offset calculation)
    if (player->firstInputSampleTime < 0.0) {
        player->firstInputSampleTime = inTimeStamp->mSampleTime;
        if ((player->firstOutputSampleTime > -1.0) &&
            (player->inToOutSampleTimeOffset < 0.0)) {
            player->inToOutSampleTimeOffset = player->firstInputSampleTime - player->firstOutputSampleTime;
        }
    }
    
    // render into our buffer
    OSStatus inputProcErr = noErr;
    inputProcErr = AudioUnitRender(player->inputUnit,
                                   ioActionFlags,
                                   inTimeStamp,
                                   inBusNumber,
                                   inNumberFrames,
                                   player->inputBuffer);

    if (! inputProcErr) {
        inputProcErr = player->ringBuffer->Store(player->inputBuffer,
                                                 inNumberFrames,
                                                 inTimeStamp->mSampleTime);
        
        UInt32 sz = sizeof(player->inputBuffer);
        printf ("stored %d frames at time %f (%d bytes)\n", inNumberFrames, inTimeStamp->mSampleTime, sz);
                        
        for (int i = 0; i < player->inputBuffer->mNumberBuffers; i++ ){
            //printf("stored audio string[%d]: %s\n", i, player->inputBuffer->mBuffers[i].mData);
        }
                 
                
    }
然而,当我像这样从GraphRenderCallback中的环形缓冲区提取时

    MyAUGraphPlayer *player = (MyAUGraphPlayer*) inRefCon;
    
    // have we ever logged output timing? (for offset calculation)
    if (player->firstOutputSampleTime < 0.0) {
        player->firstOutputSampleTime = inTimeStamp->mSampleTime;
        if ((player->firstInputSampleTime > -1.0) &&
            (player->inToOutSampleTimeOffset < 0.0)) {
            player->inToOutSampleTimeOffset = player->firstInputSampleTime - player->firstOutputSampleTime;
        }
    }
    
    
    // copy samples out of ring buffer
    OSStatus outputProcErr = noErr;
    // new CARingBuffer doesn't take bool 4th arg
    outputProcErr = player->ringBuffer->Fetch(ioData,
                                              inNumberFrames,
                                              inTimeStamp->mSampleTime + player->inToOutSampleTimeOffset);
    


这不是许可问题;我有其他可以获得麦克风输入的非音频单元代码。此外,我还创建了一个plist,使这个应用程序每次都提示访问麦克风,所以我知道它正在工作。我不明白为什么数据会进入这个环形缓冲区,但永远不会出来。

现在你需要声明你想使用麦克风,并提供一个解释字符串。2012年发布Learning Core Audio时并非如此

简而言之,您现在需要:

  • NSMicrophoneUsageDescription
    字符串添加到您的
    Info.plist
  • 添加沙箱功能并启用音频输入
  • 您使用的示例代码是一个命令行工具,因此在Xcode中添加一个
    Info.plist
    ,就像在.app包中一样。另外,如果从Xcode运行代码,代码似乎也不起作用。在我的情况下,它必须为Terminal.app运行。这可能是因为我的终端具有麦克风权限(可在
    系统首选项>安全与隐私>麦克风
    中查看)。通过在
    AVCaptureDevice
    上使用
    requestAccessForMediaType
    ,您可以也可能应该明确请求用户(在本例中是您自己!)访问麦克风。没错,
    AVFoundation
    code在
    Core Audio
    tutorial中,世界将走向何方

    中有关于上述步骤的更多详细信息


    p、 我认为,那些认为捕获零而不是返回错误是个好主意的人,可能是那些发明了在正文中包含错误代码返回HTTP 200的人的好朋友。

    感谢您的回复。我已经在plist中有了NSMicrophoneUsageDescription,并在构建设置中链接了它。我知道它在工作,因为我被提示启用麦克风输入,我可以在安全和隐私中看到这个应用程序(CH08_AUGraphInput)和终端启用。我甚至似乎在回调中获得了麦克风字节;他们就是无法在环缓冲区获取中生存。发布一个链接到一个可运行的项目
        MyAUGraphPlayer *player = (MyAUGraphPlayer*) inRefCon;
        
        // have we ever logged output timing? (for offset calculation)
        if (player->firstOutputSampleTime < 0.0) {
            player->firstOutputSampleTime = inTimeStamp->mSampleTime;
            if ((player->firstInputSampleTime > -1.0) &&
                (player->inToOutSampleTimeOffset < 0.0)) {
                player->inToOutSampleTimeOffset = player->firstInputSampleTime - player->firstOutputSampleTime;
            }
        }
        
        
        // copy samples out of ring buffer
        OSStatus outputProcErr = noErr;
        // new CARingBuffer doesn't take bool 4th arg
        outputProcErr = player->ringBuffer->Fetch(ioData,
                                                  inNumberFrames,
                                                  inTimeStamp->mSampleTime + player->inToOutSampleTimeOffset);
        
    
    
    fetched 512 frames at time 160776.000000
    fetched audio string[0, size 2048]: xx
    fetched audio string[1, size 2048]: xx
    fetched 512 frames at time 161288.000000
    fetched audio string[0, size 2048]: xx
    fetched audio string[1, size 2048]: xx