1
votes

Here's my code to set up the audio queue service:

aqData = AQRecorderState()
    aqData.mDataFormat.mFormatID             = kAudioFormatMPEG4AAC
    aqData.mDataFormat.mSampleRate           = 16000.0
    aqData.mDataFormat.mChannelsPerFrame     = 1
    aqData.mDataFormat.mBitsPerChannel       = 16
    aqData.mDataFormat.mBytesPerPacket       = aqData.mDataFormat.mChannelsPerFrame * UInt32(sizeof(UInt16))
    aqData.mDataFormat.mBytesPerFrame        = aqData.mDataFormat.mChannelsPerFrame * UInt32(sizeof(UInt16))
    aqData.mDataFormat.mFramesPerPacket      = 1
    aqData.mDataFormat.mFormatFlags          = kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsBigEndian
    aqData.mQueue                            = AudioQueueRef()
    fileType                                 = kAudioFileM4AType

    // create new input for audio queue
    AudioQueueNewInput(&aqData.mDataFormat, handleInputBuffer, &aqData, nil, kCFRunLoopCommonModes, 0, &aqData.mQueue)
    var dataFormatSize:UInt32 = UInt32(sizeof(aqData.mDataFormat.dynamicType))
    AudioQueueGetProperty(aqData.mQueue, kAudioQueueProperty_StreamDescription, &aqData.mDataFormat, &dataFormatSize)

    // create file to store audio
    let data = recordUrl.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    let audioFileURL: CFURLRef = CFURLCreateFromFileSystemRepresentation(nil, UnsafePointer(data.bytes), data.length, false)
    AudioFileCreateWithURL(audioFileURL, fileType, &aqData.mDataFormat, AudioFileFlags.EraseFile, &aqData.mAudioFile)

    // set magic cookie for file if needed
    setMegicCookieForFile(aqData.mQueue, inFile: aqData.mAudioFile)

    // derive buffer size
    deriveBufferSize(aqData.mQueue, ASBDescription: &aqData.mDataFormat, seconds: kBufferLengthInSecond, outbufferSize: &aqData.bufferByteSize)

    // allocate and enqueue each buffer
    for i in 0..<Record.kNumberBuffers {
        AudioQueueAllocateBuffer(aqData.mQueue, aqData.bufferByteSize, &aqData.mBuffers[i])
        AudioQueueEnqueueBuffer(aqData.mQueue, aqData.mBuffers[i], 0, nil)
    }

The code produce error at line

AudioQueueNewInput(&aqData.mDataFormat, handleInputBuffer, &aqData, nil, kCFRunLoopCommonModes, 0, &aqData.mQueue)

And the error message is

AudioConverterNew from AudioQueueNew returned 'fmt?'

io: 1 ch, 44100 Hz, Float32 client: 1 ch, 44100 Hz, 'aac ' (0x00000003) 16 bits/channel, 2 bytes/packet, 1 frames/packet, 2 bytes/frame

I have tried different setting for the audio format but it seems none of them fix this bug. Can anyone help?

1

1 Answers

0
votes

From the CoreAudioTypes.h header file, we glean that:

kAudioFormatMPEG4AAC MPEG-4 Low Complexity AAC audio object, has no flags.

And a comment above AudioStreamBasicDescription in the same file says:

In compressed audio, a Packet is an indivisible chunk of compressed data, for example an AAC packet will contain 1024 sample frames.

And since AAC can be variable bit rate (this is hinted at in the CAF spec and in the notes on For variable mBytesPerPacket compressed audio formats) mBitsPerChannel, mBytesPerPacket and mFramesPerPacket should be zero.

So I would try changing these fields of your AudioStreamBasicDescription:

aqData.mDataFormat.mBitsPerChannel       = 0
aqData.mDataFormat.mBytesPerPacket       = 0
aqData.mDataFormat.mBytesPerFrame        = 0
aqData.mDataFormat.mFramesPerPacket      = 1024
aqData.mDataFormat.mFormatFlags          = 0