1

Right now I am getting PCM audio in my Audio Unit proc, which writes incoming audio buffer data into a Circular Buffer to be used somewhere else.

Now I would like to get iLBC audio data, so I changed the AudioStreamBasicDescription mFormatID to kAudioFormatiLBC.

But now it crashes:

Error: StreamFormat kAudioUnitErr_FormatNotSupported

So how should iLBC implemented correctly using Audio Units?

Thanks a lot!

DeveloBär
  • 673
  • 8
  • 20

2 Answers2

1

Give this a go

    mRecordFormat.mSampleRate = 8000.0;
    mRecordFormat.mFormatID = kAudioFormatiLBC;
    mRecordFormat.mChannelsPerFrame = 1;
Daniel Broad
  • 2,512
  • 18
  • 14
  • Hmm… with this code I'm getting an error when initializing the audio unit: `AudioUnitInitialize` `Error: Initialise Recording ('!dat')` The !dat represents `kAudioCodecUnsupportedFormatError` – DeveloBär Nov 09 '15 at 18:05
  • 1
    Sorry my error, I hadn't read properly that this was part of an audio unit chain. Audio units cannot write to compressed formats. You will need to use AudioFileServices or AudioConverter to compress the audio data. – Daniel Broad Nov 10 '15 at 14:01
  • ah I see! That makes sense :) Do you maybe know some examples for the conversion from PCM to iLBC using AudioConverter? – DeveloBär Nov 10 '15 at 14:36
0

Hi this is my code that convert PCM to iLBC.

1.Create converter:

-(BOOL)createAudioConvert:(CMSampleBufferRef)sampleBuffer { 
if (m_converter != nil)
{
    return TRUE;
}

AudioStreamBasicDescription inputFormat = *(CMAudioFormatDescriptionGetStreamBasicDescription(CMSampleBufferGetFormatDescription(sampleBuffer))); 
AudioStreamBasicDescription outputFormat; 

memset(&outputFormat, 0, sizeof(outputFormat));
outputFormat.mSampleRate       = 8000;
outputFormat.mFormatID         = kAudioFormatiLBC;
outputFormat.mChannelsPerFrame = 1;

// use AudioFormat API to fill out the rest of the description
UInt32 size = sizeof(outputFormat);
AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &size, &outputFormat);

outputFormat.mBytesPerPacket  = 50;
outputFormat.mFramesPerPacket = 240;

AudioClassDescription *desc = [self getAudioClassDescriptionWithType:kAudioFormatiLBC fromManufacturer:kAppleSoftwareAudioCodecManufacturer];
if (AudioConverterNewSpecific(&inputFormat, &outputFormat, 1, desc, &m_converter) != noErr)
{
    printf("AudioConverterNewSpecific failed\n");
    return NO;
}

return YES;
}

2.getAudioClassDescriptionWithType

-(AudioClassDescription*)getAudioClassDescriptionWithType:(UInt32)type fromManufacturer:(UInt32)manufacturer { // 获得相应的编码器
static AudioClassDescription audioDesc;

UInt32 encoderSpecifier = type, size = 0;
OSStatus status;

memset(&audioDesc, 0, sizeof(audioDesc));
status = AudioFormatGetPropertyInfo(kAudioFormatProperty_Encoders, sizeof(encoderSpecifier), &encoderSpecifier, &size);
if (status)
{
    return nil;
}

uint32_t count = size / sizeof(AudioClassDescription);
AudioClassDescription descs[count];
status = AudioFormatGetProperty(kAudioFormatProperty_Encoders, sizeof(encoderSpecifier), &encoderSpecifier, &size, descs);
for (uint32_t i = 0; i < count; i++)
{
    if ((type == descs[i].mSubType) && (manufacturer == descs[i].mManufacturer))
    {
        memcpy(&audioDesc, &descs[i], sizeof(audioDesc));
        break;
    }
}
return &audioDesc;
}

3.Encode data:

-(BOOL)encoderData:(CMSampleBufferRef)sampleBuffer Data:(char*)Data Len:(int*)Len { 
if ([self createAudioConvert:sampleBuffer] != YES)
{
    return NO;
}

CMBlockBufferRef blockBuffer = nil;
AudioBufferList  inBufferList;
if (CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, NULL, &inBufferList, sizeof(inBufferList), NULL, NULL, 0, &blockBuffer) != noErr)
{
    printf("CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer failed");
    return NO;
}

AudioBufferList outBufferList;
outBufferList.mNumberBuffers              = 1;
outBufferList.mBuffers[0].mNumberChannels = 1;
outBufferList.mBuffers[0].mDataByteSize   = *Len; 
outBufferList.mBuffers[0].mData           = Data; 

UInt32 outputDataPacketSize               = 1;


OSStatus err = AudioConverterFillComplexBuffer(m_converter, inputDataProc, &inBufferList, &outputDataPacketSize, &outBufferList, NULL);
printf("AudioConverterFillComplexBuffer\n");


if ( err != noErr)
{
    printf("AudioConverterFillComplexBuffer failed\n");
    return NO;
}

*Len = outBufferList.mBuffers[0].mDataByteSize; 
CFRelease(blockBuffer);
return YES;
}

4.Callback function:

OSStatus inputDataProc(AudioConverterRef inConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData,AudioStreamPacketDescription **outDataPacketDescription, void *inUserData) { 

ioData->mNumberBuffers = 1;

AudioBufferList bufferList = *(AudioBufferList*)inUserData;
ioData->mBuffers[0].mNumberChannels = 1;
ioData->mBuffers[0].mData           = bufferList.mBuffers[0].mData;
ioData->mBuffers[0].mDataByteSize   = bufferList.mBuffers[0].mDataByteSize;

UInt32 maxPackets = bufferList.mBuffers[0].mDataByteSize / 2;
*ioNumberDataPackets = maxPackets;

return noErr;
}

try this!

Wei Wen Hsiao
  • 191
  • 1
  • 17