AudioQueue不会将缓冲区排入队列

时间:2017-03-28 16:38:09

标签: c macos core-audio audiotoolbox audioqueueservices

我正在写一个基于c的合成器。当我尝试使用AudioQueueEnqueueBuffer函数将缓冲区排入队列时,我遇到了问题。在不同的执行中,我有不同的错误,如缓冲区的malloc-error或BAD_ISTRUCTION或BAD_ACCESS(代码= EXC_I386 _...)。有时回调编码成功排队缓冲区,但程序在尝试启动AudioQueue或将数据复制到缓冲区时崩溃。 这里有代码,希望你能帮助我。

当我的代码进入回调时,Xcode向我打印这个奇怪的警告:“警告:无法加载任何Objective-C类信息。这将显着降低可用类型信息的质量。”,但是我已经'为什么......

synthesis.h

#include <stdio.h>
#include <stdlib.h>
#include <AudioToolBox/AudioQueue.h>
#include <CoreAudio/CoreAudioTypes.h>
#include <math.h>
#include <stdbool.h>
#include <MacTypes.h>
#include <string.h>
#include <CoreFoundation/CoreFoundation.h>

#define PI 3.141592
#define DBG(func, ex)   fprintf(stderr, "Error in %s. n. %d\n", func, ex); exit(ex);

static const UInt8 nOfBuffer = 3;

struct wave {
    Float64 samplingRate;
    Float64 phase;
    UInt32  frequency;
    SInt16  *samples;
    UInt16  seconds;
};
typedef struct wave Wave;

struct stream {
    Wave                        sine;
    AudioStreamBasicDescription asbd;
    AudioQueueRef               audioQueue;
    AudioQueueBufferRef         audioBuffer[nOfBuffer];
    UInt32                      bufferSizeByte;
    UInt32                      counter;
    UInt32                      lastPos;
    Boolean                     isRunning;
    UInt32                      nOfPacketToRead;
};
typedef struct stream Stream;

void init(
          Stream *sine
          );

static void fillBuffer(
                void                *userData,
                AudioQueueRef       aQ,
                AudioQueueBufferRef inBuf
                );

void generateSine(
                  Stream *sine
                  );

的main.c

#include "synthesis.h"

int main() {
    Stream *sine = (Stream *)malloc(sizeof(Stream));
    init(sine);
    generateSine(sine);
    return 0;
}

synthesis.c

#include "synthesis.h"
#include <limits.h>

static void fillBuffer(void *userData, AudioQueueRef aQ, AudioQueueBufferRef buf) {
    /* 
     callback for fill audioqueue's buffers
     */

    Stream *sine = (Stream *)userData;
    if(!sine->isRunning) return;

    OSStatus err = noErr;
    UInt32 dif = 0;
    UInt32 i = 0;
    SInt16 *data = (SInt16 *)buf->mAudioData;
    UInt32 lenght = buf->mAudioDataBytesCapacity / sizeof(SInt16);

    /* fill the buffer with the samples creates in generateSine */
    while (sine->counter - sine->lastPos < lenght && sine->counter < (sine->sine.samplingRate *
           sine->sine.seconds)) {
        data[i] = sine->sine.samples[sine->counter];
        i++;
        sine->counter++;
    }
    dif = sine->counter - sine->lastPos;
    buf->mAudioDataByteSize = dif * sizeof(SInt16);
    if(dif > 0) {
        err = AudioQueueEnqueueBuffer(aQ, buf, 0, NULL);
        if(err != noErr) {
            DBG("aQenqueuebuffer", err);
        }
        sine->lastPos = sine->counter;
    } else {
        sine->isRunning = false;
        err = AudioQueueStop(aQ, false);
        if(err != noErr) {
            DBG("aQstop", err);
        }
    }
}

void init(Stream *sine) {
    /*
     initialize all var and set the ASBD for an integer 16 bit linear PCM
     */

    OSStatus err = noErr;
    sine->sine.frequency = 440;
    sine->sine.phase = 0.0;
    sine->sine.samplingRate = 96000;
    sine->counter = 0;
    sine->lastPos = 0;
    sine->bufferSizeByte = 0x4000;
    sine->sine.seconds = 2;
    sine->sine.samples = (SInt16 *)malloc(sizeof(SInt16) * sine->sine.seconds * sine->asbd.mSampleRate);
    sine->asbd.mBytesPerPacket = 2;
    sine->asbd.mFramesPerPacket = 1;
    sine->asbd.mBytesPerFrame = 2;
    sine->asbd.mChannelsPerFrame = 1;
    sine->asbd.mBitsPerChannel = 16;
    sine->asbd.mSampleRate = 96000;
    sine->asbd.mFormatID = 'lpcm';
    sine->asbd.mReserved = 0;
    sine->asbd.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
    err = AudioQueueNewOutput(&sine->asbd, fillBuffer, sine, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0,
                              &sine->audioQueue);
    if(err != noErr) {
        DBG("aQnewOutput", err);
    }
    for(int i = 0; i < nOfBuffer; i++) {
        err = AudioQueueAllocateBuffer(sine->audioQueue, sine->bufferSizeByte, &sine->audioBuffer[i]);
        if(err != noErr) {
            DBG("aQallocatebuffer", err);
        }
    }
}

void generateSine(Stream *sine) {
    OSStatus err = noErr;
    UInt32 lenght = sine->sine.samplingRate * sine->sine.seconds;

    for(int i = 0; i < lenght; i++) {
        sine->sine.samples[i] = sin(2 * PI * sine->sine.frequency * i + sine->sine.phase) * SHRT_MAX;
    }
    sine->isRunning = true;
    for(int i = 0; i < nOfBuffer; i++) {
        fillBuffer((void *)sine, sine->audioQueue, sine->audioBuffer[i]);
    }
    err = AudioQueueStart(sine->audioQueue, NULL);
    if(err != noErr) {
        DBG("aQstart", err);
    }

    do {
        CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.25, false);
    }while(sine->isRunning);

    AudioQueueDispose(sine->audioQueue, false);
    free(sine->sine.samples);
    free(sine);
}

0 个答案:

没有答案