Audio Queue cannot start again after AudioQueueStop

862 views Asked by At

I can set up an Audio Queue for recording, and AudioQueueStart works well to start recording.

But after calling AudioQueueStop, I found that the same Audio Queue cannot be started again, instead, I need to create a new Audio Queue and Buffers for another recording start.

Is it possible to reuse the same Audio Queue after stopping it?

Thanks.

2

There are 2 answers

0
helioz On BEST ANSWER

I am experiencing the same issue. Careful study of the documentation has not revealed any clues as to the source of this problem but looking the sample code all recording queues are only used once - no indication that they can be re-used.

The only hint in the documentation is that AudioQueueStart is used to RESUME after pausing a queue with AudioQueuePause.

It appears that recording queues are designed for one-off use and need to be disposed (AudioQueueDispose) at the end and re-created for any subsequent recordings.

0
Steve Melnikoff On

Despite the absence of any documentation, there does appear to be a way of doing this.

It requires ensuring that, after AudioQueueStop is called asynchronously, any data which is still in the queue is properly dealt with.

So, in the call to stop recording, we have a state variable (recordingState) to keep track of what's happening. Given that this function and the callback execute in different threads, we try to avoid any possible complications by synchronising to the current class (called Listener in this example):

-(void) stopRecording
{
    @synchronized(self)
    {
        if(self.recordingState != RecordingStateRunning) {return;}

        self.recordingState = RecordingStateStopping;
        AudioQueueStop(self.audioQueue, false);
    }
}

Experimentation showed that after an asynchronous call to AudioQueueStop (i.e. parameter inImmediate is set to false), the callback will be called a few more times, so we have an opportunity to tidy up:

static void AQInputCallback(void *inUserData,
                        AudioQueueRef inAQ,
                        AudioQueueBufferRef inBuffer,
                        const AudioTimeStamp *inStartTime,
                        UInt32 inNumberPacketDescriptions,
                        const AudioStreamPacketDescription *inPacketDescs)
{
    Listener *listener = (__bridge Listener *) inUserData;

    @synchronized(listener)
    {
        if(listener.recordingState == RecordingStateRunning)
        {
            // Do audio processing here.
            // ...
        }
        else if(listener.recordingState == RecordingStateStopping)
        {
            listener.recordingState = RecordingStateStopped;

            // Do tidying here.
            // ...
        }

        AudioQueueEnqueueBuffer(listener.audioQueue, inBuffer, 0, NULL);
    }
}