2015-11-09 37 views
1

現在,我在我的音頻單元proc中獲取PCM音頻,它將輸入的音頻緩衝區數據寫入循環緩衝區以便在其他地方使用。iOS:使用音頻單元的iLBC編解碼器

現在我想獲得iLBC音頻數據,所以我將AudioStreamBasicDescriptionmFormatID更改爲kAudioFormatiLBC

但現在它崩潰:

Error: StreamFormat kAudioUnitErr_FormatNotSupported

那麼我們應該如何實現的iLBC的使用音頻單元是否正確?

非常感謝!

回答

1

給這個一去

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

嗯...這個代碼初始化音頻單元時,我得到一個錯誤:'AudioUnitInitialize' '錯誤:初始化記錄( '!DAT')' 的DAT代表'kAudioCodecUnsupportedFormatError' –

+1

對不起我的錯誤,我沒有正確閱讀,這是音頻單元鏈的一部分。音頻單元無法寫入壓縮格式。您將需要使用AudioFileServices或AudioConverter來壓縮音頻數據。 –

+0

啊我明白了!這很有道理:)你可能知道一些使用AudioConverter從PCM到iLBC轉換的例子嗎? –

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.Encode數據:

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

試試這個吧!