How to record to a compressed audio format using an AudioQueue?
I've set up an AudioQueue to record linear PCM audio. That works fine. No problem at all.
I'd like to use the queue to record to one of the compressed formats available though, like IMA4 or AppleLossless.
Can't get that to work at all.
Here is the code I'm using:
Code:
void record(){
ars.mDataFormat.mSampleRate = 44100.0;
ars.mDataFormat.mChannelsPerFrame = 1; // mono
ars.mDataFormat.mFramesPerPacket = 1;
ars.mDataFormat.mBitsPerChannel = 16;
ars.mDataFormat.mBytesPerFrame = 2;
ars.mDataFormat.mBytesPerPacket = 2;
/*----------------- FORMAT -------------------*/
ars.mDataFormat.mFormatID = kAudioFormatAppleIMA4;
ars.mDataFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
// ars.mDataFormat.mFormatID = kAudioFormatLinearPCM;
// ars.mDataFormat.mFormatFlags = kLinearPCMFormatFlagIsBigEndian
// | kLinearPCMFormatFlagIsSignedInteger
// | kLinearPCMFormatFlagIsPacked;
/*--------------------------------------------*/
// derive the buffer size
deriveInputBufferSize(ars.mQueue, ars.mDataFormat, 0.5, &ars.mBufferSize);
// create the queue
AudioQueueNewInput(&ars.mDataFormat,
AQInputCallback,
&ars,
NULL,
NULL,
0,
&ars.mQueue);
// create the output file
const UInt8 *pFilepath = (const UInt8 *)[[NSHomeDirectory() stringByAppendingPathComponent:@"/Documents/CurrentRecording.caf"] UTF8String];
CFURLRef audioFileURL = CFURLCreateFromFileSystemRepresentation (NULL, pFilepath, strlen((const char*)pFilepath), false);
AudioFileCreateWithURL(audioFileURL,
kAudioFileCAFType,
&ars.mDataFormat,
kAudioFileFlags_EraseFile,
&ars.mAudioFile);
// set the magic cookie for the queue
setMagicCookieForFile(ars.mQueue, ars.mAudioFile);
// allocate and enque the recording buffers
for (int i=0; i<NUM_BUFFERS; i++){
AudioQueueAllocateBuffer(ars.mQueue, ars.mBufferSize, &ars.mBuffers[i]);
AudioQueueEnqueueBuffer(ars.mQueue, ars.mBuffers[i], 0, NULL);
}
// set current packet index and run state
ars.mCurrentPacket = 0;
ars.mIsRunning = true;
// start the recording
AudioQueueStart(ars.mQueue, NULL);
}
If I comment out the first two lines in the section marked /*----------------- FORMAT ------------------*/, and ucomment the last 4 (i.e. if i switch to linear PCM format) then it works fine.
With the IMA4 format it won't even call my callback function. I tried a similar thing with AppleLossless, with the same effect.
Here's the code for the callback:
Code:
static void AQInputCallback(void *aqRecorderState,
AudioQueueRef inQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp *timestamp,
unsigned long inNumPackets,
const AudioStreamPacketDescription *mDataFormat) {
AQRecorderState *pArs = (AQRecorderState *)aqRecorderState;
if (inNumPackets == 0 && pArs->mDataFormat.mBytesPerPacket != 0)
inNumPackets = inBuffer->mAudioDataByteSize / pArs->mDataFormat.mBytesPerPacket;
// write current buffer to file
if (AudioFileWritePackets(pArs->mAudioFile,
false,
inBuffer->mAudioDataByteSize,
mDataFormat,
pArs->mCurrentPacket,
&inNumPackets,
inBuffer->mAudioData) == noErr){
pArs->mCurrentPacket += inNumPackets; // advance packet index pointer
}
// don't re-queue the sound buffers if stop has been pressed
if (!pArs->mIsRunning)
return;
// send the buffer back to the queue for more data
AudioQueueEnqueueBuffer(pArs->mQueue, inBuffer, 0, NULL);
}
The AudioQueueProgrammingGuide indicates that these formats are supported, but doesn't offer an example of how to set things up to get it to work with a compressed format.
Any suggestions would be much appreciated. I've looked around the net but can't find any concrete examples that actually work on the iPhone or simulator.
I've set up an AudioQueue to record linear PCM audio. That works fine. No problem at all.
I'd like to use the queue to record to one of the compressed formats available though, like IMA4 or AppleLossless.
Can't get that to work at all.
Here is the code I'm using:
Code:
void record(){
ars.mDataFormat.mSampleRate = 44100.0;
ars.mDataFormat.mChannelsPerFrame = 1; // mono
ars.mDataFormat.mFramesPerPacket = 1;
ars.mDataFormat.mBitsPerChannel = 16;
ars.mDataFormat.mBytesPerFrame = 2;
ars.mDataFormat.mBytesPerPacket = 2;
/*----------------- FORMAT -------------------*/
ars.mDataFormat.mFormatID = kAudioFormatAppleIMA4;
ars.mDataFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
// ars.mDataFormat.mFormatID = kAudioFormatLinearPCM;
// ars.mDataFormat.mFormatFlags = kLinearPCMFormatFlagIsBigEndian
// | kLinearPCMFormatFlagIsSignedInteger
// | kLinearPCMFormatFlagIsPacked;
/*--------------------------------------------*/
// derive the buffer size
deriveInputBufferSize(ars.mQueue, ars.mDataFormat, 0.5, &ars.mBufferSize);
// create the queue
AudioQueueNewInput(&ars.mDataFormat,
AQInputCallback,
&ars,
NULL,
NULL,
0,
&ars.mQueue);
// create the output file
const UInt8 *pFilepath = (const UInt8 *)[[NSHomeDirectory() stringByAppendingPathComponent:@"/Documents/CurrentRecording.caf"] UTF8String];
CFURLRef audioFileURL = CFURLCreateFromFileSystemRepresentation (NULL, pFilepath, strlen((const char*)pFilepath), false);
AudioFileCreateWithURL(audioFileURL,
kAudioFileCAFType,
&ars.mDataFormat,
kAudioFileFlags_EraseFile,
&ars.mAudioFile);
// set the magic cookie for the queue
setMagicCookieForFile(ars.mQueue, ars.mAudioFile);
// allocate and enque the recording buffers
for (int i=0; i<NUM_BUFFERS; i++){
AudioQueueAllocateBuffer(ars.mQueue, ars.mBufferSize, &ars.mBuffers[i]);
AudioQueueEnqueueBuffer(ars.mQueue, ars.mBuffers[i], 0, NULL);
}
// set current packet index and run state
ars.mCurrentPacket = 0;
ars.mIsRunning = true;
// start the recording
AudioQueueStart(ars.mQueue, NULL);
}
If I comment out the first two lines in the section marked /*----------------- FORMAT ------------------*/, and ucomment the last 4 (i.e. if i switch to linear PCM format) then it works fine.
With the IMA4 format it won't even call my callback function. I tried a similar thing with AppleLossless, with the same effect.
Here's the code for the callback:
Code:
static void AQInputCallback(void *aqRecorderState,
AudioQueueRef inQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp *timestamp,
unsigned long inNumPackets,
const AudioStreamPacketDescription *mDataFormat) {
AQRecorderState *pArs = (AQRecorderState *)aqRecorderState;
if (inNumPackets == 0 && pArs->mDataFormat.mBytesPerPacket != 0)
inNumPackets = inBuffer->mAudioDataByteSize / pArs->mDataFormat.mBytesPerPacket;
// write current buffer to file
if (AudioFileWritePackets(pArs->mAudioFile,
false,
inBuffer->mAudioDataByteSize,
mDataFormat,
pArs->mCurrentPacket,
&inNumPackets,
inBuffer->mAudioData) == noErr){
pArs->mCurrentPacket += inNumPackets; // advance packet index pointer
}
// don't re-queue the sound buffers if stop has been pressed
if (!pArs->mIsRunning)
return;
// send the buffer back to the queue for more data
AudioQueueEnqueueBuffer(pArs->mQueue, inBuffer, 0, NULL);
}
The AudioQueueProgrammingGuide indicates that these formats are supported, but doesn't offer an example of how to set things up to get it to work with a compressed format.
Any suggestions would be much appreciated. I've looked around the net but can't find any concrete examples that actually work on the iPhone or simulator.
Thanks,
Paul
i am looking same able to record in caf format not working for aac or m4a format. I tried by changing filetype and formatid but no luck. Were u able to resolve this.Let me know if u have any code sample.
Thanks