2017-01-15 1 views
1

Чтобы начать работу с программированием macOS, я пытаюсь создать простую программу, которая будет записывать аудио с устройства ввода (например, встроенного микрофона на моем MacBook Pro) , Я создал проект Objective-C какао в Xcode и код немного измененная версия 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, который (я считаю) не представляет собой «нет ошибки», и HandleInputBuffer называется NUM_BUFFERS раз в очень быстрой последовательности или почти мгновенно (большинство определенно не каждые 0,5 se cs, как размер буфера 22050, будет предлагать при этой частоте дискретизации), а все первые образцы равны 0.0. Что мне здесь не хватает?

+0

My C получает ржаветь. Вам не нужно выделять/'malloc'' S'? Также значения форматов выглядят как-то произвольно для меня. Почему 32 бит/канал? Почему эти formatFlags? – shallowThought

+0

Ну, при вызове 'AudioQueueNewInput' с недопустимыми значениями, установленными в ASBD, указывается сообщение об ошибке (« fmt? »), Которое включает значения по умолчанию для ввода по умолчанию, и это то, откуда я получил значения. Кроме того, я считаю, что 'AudioQueueAllocateBuffer' выполняет выделение – ehoopz

+0

' AudioQueueNewInput' работает с 'fmt-> mBitsPerChannel = 16' и' fmt-> mFormatFlags = kAudioFormatFlagIsSignedInteger', но по-прежнему нет ввода. Я действительно удивляюсь, почему он говорит «io: 44100 Гц, 32-бит Float» для встроенного микрофона, хотя – ehoopz

ответ

0

S.bufferByteSize находится в байтах, а не в кадрах, поэтому 22050 байт не является половиной секунды, а 22050/sizeof(float) кадрами, примерно восьмой секунды.

Если вы хотите полсекунды, попробуйте

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

В вашем коде выше (а также в мерзавца репо вы связаны), вы сразу же AudioQueueStop и AudioQueueDispose аудио очереди после AudioQueueStart ИНГ его. Не делай этого.

+0

Совершенно верно, спасибо! Но проблема не будет решена к сожалению :(Обратный вызов по-прежнему называется «NUM_BUFFERS» раз мгновенно, и никаких данных не получено. – ehoopz

+0

Вы просматривали отметки времени NSLog? Откуда вы не знаете данных? –

+0

Да, у меня есть. Например, они выглядели следующим образом: «2017-01-16 02: 47: 11.439407',' 2017-01-16 02: 47: 11.439440', '2017-01-16 02: 47: 11.439462' , '2017-01-16 02: 47: 11.439473',' 2017-01-16 02: 47: 11.439483', '2017-01-16 02: 47: 11.439492' с' NUM_BUFFERS = 6' и 'bufferByteSize = 44100 * 4' – ehoopz

Смежные вопросы