调用了输入队列回调但没有数据

Input queue callback called but no data

为了开始学习 macOS 编程,我尝试制作一个简单的程序来记录来自输入设备(例如,我的 MacBook Pro 上的内置麦克风)的音频。我在 Xcode 中创建了一个 Objective-C Cocoa 项目,代码是 this tutorial from developer.apple.com.

的稍微改编的版本

这是我的代码:

// AppDelegate.m:  

#include <AudioToolbox/AudioToolbox.h>  

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {  

     struct AQRecorderState S;  

#define PRINT_R do{\  
printf("%d: r = %d\n",__LINE__, r);\  
}while(0)  

    AudioStreamBasicDescription *fmt = &S.mDataFormat;  

    fmt->mFormatID         = kAudioFormatLinearPCM;  
    fmt->mSampleRate       = 44100.0;  
    fmt->mChannelsPerFrame = 1;  
    fmt->mBitsPerChannel   = 32;  
    fmt->mBytesPerFrame    = fmt->mChannelsPerFrame * sizeof (float);  
    fmt->mFramesPerPacket  = 1;  
    fmt->mBytesPerPacket   = fmt->mBytesPerFrame * fmt->mFramesPerPacket;  
    fmt->mFormatFlags      = kAudioFormatFlagIsFloat | kAudioFormatFlagIsNonInterleaved;  

    OSStatus r = 0;  

    r = AudioQueueNewInput(&S.mDataFormat, HandleInputBuffer, &S, NULL, kCFRunLoopCommonModes, 0, &S.mQueue);  

    PRINT_R;  

    UInt32 dataFormatSize = sizeof (S.mDataFormat);  

    r = AudioQueueGetProperty (  
                       S.mQueue,  
                       kAudioConverterCurrentInputStreamDescription,  
                       &S.mDataFormat,  
                       &dataFormatSize  
                       );  

    S.bufferByteSize = 22050;      

    for (int i = 0; i < NUM_BUFFERS; ++i) {        
        r = AudioQueueAllocateBuffer(S.mQueue, S.bufferByteSize, &S.mBuffers[i]);  
        PRINT_R;  

        r = AudioQueueEnqueueBuffer(S.mQueue, S.mBuffers[i], 0, NULL);  
        PRINT_R;  
    }  

    S.mCurrentPacket = 0;        
    S.mIsRunning = true;        

    r = AudioQueueStart(S.mQueue, NULL);  
    PRINT_R;  

    r = AudioQueueStop(S.mQueue, true);  
    S.mIsRunning = false;  

    PRINT_R;  

    r = AudioQueueDispose(S.mQueue, true);  
}

这是我的输入回调函数(在单独的 C 文件中定义):

void HandleInputBuffer (  
                           void                                *aqData,             
                           AudioQueueRef                       inAQ,                
                           AudioQueueBufferRef                 inBuffer,            
                           const AudioTimeStamp                *inStartTime,        
                           UInt32                              inNumPackets,        
                           const AudioStreamPacketDescription  *inPacketDesc          
) {  

    struct AQRecorderState *pAqData = (struct AQRecorderState *) aqData;               

    if (inNumPackets == 0 && pAqData->mDataFormat.mBytesPerPacket != 0) {  
        inNumPackets =  
        inBuffer->mAudioDataByteSize / pAqData->mDataFormat.mBytesPerPacket;  
    }  
    printf("%f\n", *(float*)inBuffer->mAudioData);  
    if (pAqData->mIsRunning == 0)                                      
        return;  

    AudioQueueEnqueueBuffer(pAqData->mQueue, inBuffer, 0, NULL);  
}  

当程序是运行时,所有Core Audio函数调用return 0,(我相信)代表"no error",HandleInputBuffer被调用NUM_BUFFERS非常快速连续或几乎立即的时间(绝对不是每 0.5 秒一次,就像 22050 的缓冲区大小在这个采样率下所建议的那样),并且所有第一个样本都是 0.0.0.0。我在这里错过了什么?

S.bufferByteSize 以字节为单位,而不是帧,所以 22050 字节不是半秒,而是 22050/sizeof(float) 帧,所以大约八分之一秒。

如果你想要半秒,试试

S.bufferByteSize = fmt->mSampleRate * fmt->mBytesPerFrame / 2; 

在您上面的代码中(以及在您链接的 git 回购中),您在 AudioQueueStart 之后立即 AudioQueueStopAudioQueueDispose 音频队列。不要那样做。