输入队列回调,但没有数据

时间:2017-01-15 11:48:46

标签: objective-c macos audio core-audio macos-sierra

为了开始进入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函数调用返回0,其中(我相信)表示&#34;没有错误&#34;,HandleInputBuffer被称为NUM_BUFFERS次,连续非常快或几乎立即(绝对不是每隔0.5秒,如22050的缓冲区大小就建议采样率,并且所有第一个样本都是0.0。我在这里缺少什么?

1 个答案:

答案 0 :(得分:0)

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

如果您想要半秒钟,请尝试

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

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