iOS:使用音频单元的iLBC编解码器

时间:2015-11-09 17:02:10

标签: ios audio codec audiounit

现在我在我的Audio Unit proc中获取PCM音频,它将传入的音频缓冲区数据写入循环缓冲区以便在其他地方使用。

现在我想获取iLBC音频数据,因此我将AudioStreamBasicDescription mFormatID更改为kAudioFormatiLBC

但现在它崩溃了:

  

错误:StreamFormat kAudioUnitErr_FormatNotSupported

那么iLBC如何使用音频单元正确实现?

非常感谢!

2 个答案:

答案 0 :(得分:1)

放手一搏

    mRecordFormat.mSampleRate = 8000.0;
    mRecordFormat.mFormatID = kAudioFormatiLBC;
    mRecordFormat.mChannelsPerFrame = 1;

答案 1 :(得分:0)

嗨,这是我将PCM转换为iLBC的代码。

1.创建转换器:

-(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.编码数据:

-(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功能:

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;
}

试试这个!