AudioQueue doesn't enqueue buffer

260 Views Asked by At

I'm writing a little c based synthesizer. I'm having a problem when I try to enqueue buffers with the function AudioQueueEnqueueBuffer. In different executions i'm having different errors, like malloc-error of the buffer or BAD_ISTRUCTION or BAD_ACCESS(code=EXC_I386_...). Sometimes the callback encode successfully enqueue buffers, but the program crashes when is trying to start the AudioQueue or when is copying data into the buffer. Here there is the code, I hope you can help me.

Xcode print to me also this strange warning when my code go into the callback: "warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available.", but I'don't now why...

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

There are 0 best solutions below