views:

310

answers:

2

Hello,

I am writing a class that opens an AudioQueue and analyzes its characteristics, and then under certain conditions can begin or end writing out a file from that AudioQueue that is already instantiated. This is my code (entirely based on SpeakHere) that opens the AudioQueue without writing anything out to tmp:

void AQRecorder::StartListen() {
int i, bufferByteSize;
UInt32 size;

try {       

    SetupAudioFormat(kAudioFormatLinearPCM);

    XThrowIfError(AudioQueueNewInput(&mRecordFormat,
                    MyInputBufferHandler,
                    this,
                    NULL, NULL,
                    0, &mQueue), "AudioQueueNewInput failed");

    mRecordPacket = 0;

    size = sizeof(mRecordFormat);
    XThrowIfError(AudioQueueGetProperty(mQueue, kAudioQueueProperty_StreamDescription,  
            &mRecordFormat, &size), "couldn't get queue's format");

    bufferByteSize = ComputeRecordBufferSize(&mRecordFormat, kBufferDurationSeconds);
    for (i = 0; i < kNumberRecordBuffers; ++i) {
        XThrowIfError(AudioQueueAllocateBuffer(mQueue, bufferByteSize, &mBuffers[i]),
                      "AudioQueueAllocateBuffer failed");
        XThrowIfError(AudioQueueEnqueueBuffer(mQueue, mBuffers[i], 0, NULL),
                      "AudioQueueEnqueueBuffer failed");
    }

    mIsRunning = true;
    XThrowIfError(AudioQueueStart(mQueue, NULL), "AudioQueueStart failed");
}
catch (CAXException &e) {
    char buf[256];
    fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf));
}
catch (...) {
    fprintf(stderr, "An unknown error occurred\n");
}
}

But I'm a little unclear on how to write a function that will tell this queue "from now until the stop signal, start writing out this queue to tmp as a file". I understand how to tell an AudioQueue to write out as a file at the time that it's created, how to set files format, etc, but not how to tell it to start and stop midstream. Much appreciative of any pointers, thanks.

+2  A: 

You can pause/start audioqueue anytime with AudioQueuePause(AudioQueueRef inAQ) and AudioQueueStart (AudioQueueRef inAQ, const AudioTimeStamp *inStartTime);

And there is more possibilities. Because you write audiofile in callback function you can choose there when and what data should be saved.

To control write data or not, create bool flag for example "doWrite" in your recorder class and write only if it set to YES. The queue begin to receive data from start and continually fills buffers, but you just inore these data in callback until flag remains NO. Then at any moment set doWrite=YES and next buffer will be saved to file. This approach is especialy useful when you change recording based on sound itself (for example record only if sound is louder than some thredhold value).

void AQRecorder::MyInputBufferHandler(  void * inUserData, AudioQueueRef    inAQ, AudioQueueBufferRef inBuffer, const AudioTimeStamp * inStartTime, UInt32  inNumPackets, const  AudioStreamPacketDescription* inPacketDesc)
{
    AQRecorder *aqr = (AQRecorder *)inUserData;
    try {
        if (inNumPackets > 0) {

                    if (aqr.doWrite){
                            // write packets to file
                            XThrowIfError(AudioFileWritePackets(aqr->mRecordFile, FALSE, inBuffer->mAudioDataByteSize, inPacketDesc, aqr->mRecordPacket, &inNumPackets, inBuffer->mAudioData), "AudioFileWritePackets failed");
                            aqr->mRecordPacket += inNumPackets;
                     }
        }

        // if we're not stopping, re-enqueue the buffe so that it gets filled again
        if (aqr->IsRunning())
            XThrowIfError(AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL), "AudioQueueEnqueueBuffer failed");
    } catch (CAXException e) {
        char buf[256];
        fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf));
    }
}
Vladimir
Thank you Vladimir, the boolean flag approach for MyInputBufferHandler worked perfectly.
Halle
I wanted to add (for anyone reading this who wants to try it) that my function above would need to be changed to include a call to AudioFileCreateWithURL so that it has an audio file to write out to when it is being told to write - the function StartRecord() in Apple's sample code project SpeakHere shows a good example of how to do this.
Halle
A: 

How did you solve the problem with magic Cookie etc for the file?

I mean how do you redirect your already streaming audio to a file to playback another day? Shouldn't that file need a header informations etc?