我想在我的应用程序中实现 SIP 呼叫,我需要解决的第一个问题是将音频从带有 ADTS 标头的压缩 AAC 格式转换为线性 PCM。
我的输入数据是具有不同帧大小的 ADTS 帧的 NSArray。每一帧都是 NSMutableData 类型。每个帧的格式和采样率相同,唯一的区别是帧大小。
我尝试实现 Igor Rotaru 针对此问题建议的示例代码,但无法使其工作。
现在我的代码看起来像这样。首先,我配置AudioConverter:
- (void)configureAudioConverter {
AudioStreamBasicDescription inFormat;
memset(&inFormat, 0, sizeof(inFormat));
inputFormat.mBitsPerChannel = 0;
inputFormat.mBytesPerFrame = 0;
inputFormat.mBytesPerPacket = 0;
inputFormat.mChannelsPerFrame = 1;
inputFormat.mFormatFlags = kMPEG4Object_AAC_LC;
inputFormat.mFormatID = kAudioFormatMPEG4AAC;
inputFormat.mFramesPerPacket = 1024;
inputFormat.mReserved = 0;
inputFormat.mSampleRate = 22050;
AudioStreamBasicDescription outputFormat;
memset(&outputFormat, 0, sizeof(outputFormat));
outputFormat.mSampleRate = inputFormat.mSampleRate;
outputFormat.mFormatID = kAudioFormatLinearPCM;
outputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
outputFormat.mBytesPerPacket = 2;
outputFormat.mFramesPerPacket = 1;
outputFormat.mBytesPerFrame = 2;
outputFormat.mChannelsPerFrame = 1;
outputFormat.mBitsPerChannel = 16;
outputFormat.mReserved = 0;
AudioClassDescription *description = [self
getAudioClassDescriptionWithType:kAudioFormatMPEG4AAC
fromManufacturer:kAppleSoftwareAudioCodecManufacturer];
OSStatus status = AudioConverterNewSpecific(&inputFormat, &outputFormat, 1, description, &_audioConverter);
if (status != 0) {
printf("setup converter error, status: %i\n", (int)status);
}
}
之后我写了回调函数:
struct MyUserData {
UInt32 mChannels;
UInt32 mDataSize;
const void* mData;
AudioStreamPacketDescription mPacket;
};
OSStatus inInputDataProc(AudioConverterRef inAudioConverter,
UInt32 *ioNumberDataPackets,
AudioBufferList *ioData,
AudioStreamPacketDescription **outDataPacketDescription,
void *inUserData)
{
struct MyUserData* userData = (struct MyUserData*)(inUserData);
if (!userData->mDataSize) {
*ioNumberDataPackets = 0;
return kNoMoreDataError;
}
if (outDataPacketDescription) {
userData->mPacket.mStartOffset = 0;
userData->mPacket.mVariableFramesInPacket = 0;
userData->mPacket.mDataByteSize = userData->mDataSize;
*outDataPacketDescription = &userData->mPacket;
}
ioData->mBuffers[0].mNumberChannels = userData->mChannels;
ioData->mBuffers[0].mDataByteSize = userData->mDataSize;
ioData->mBuffers[0].mData = (void *)userData->mData;
// No more data to provide following this run.
userData->mDataSize = 0;
return noErr;
}
我的帧解码函数如下所示:
- (void)startDecodingAudio {
if (!_converterConfigured){
return;
}
while (true){
if ([self hasFramesToDecode]){
struct MyUserData userData = {1, (UInt32)_decoderBuffer[_currPosInDecoderBuf].length, _decoderBuffer[_currPosInDecoderBuf].bytes};
uint8_t *buffer = (uint8_t *)malloc(128 * sizeof(short int));
AudioBufferList decBuffer;
decBuffer.mNumberBuffers = 1;
decBuffer.mBuffers[0].mNumberChannels = 1;
decBuffer.mBuffers[0].mDataByteSize = 128 * sizeof(short int);
decBuffer.mBuffers[0].mData = buffer;
UInt32 numFrames = 128;
AudioStreamPacketDescription outPacketDescription;
memset(&outPacketDescription, 0, sizeof(AudioStreamPacketDescription));
outPacketDescription.mDataByteSize = 128;
outPacketDescription.mStartOffset = 0;
outPacketDescription.mVariableFramesInPacket = 0;
OSStatus status = AudioConverterFillComplexBuffer(_audioConverter,
inInputDataProc,
&userData,
&numFrames,
&decBuffer,
&outPacketDescription);
NSError *error = nil;
if (status == kNoMoreDataError) {
NSLog(@"%u bytes decoded", (unsigned int)decBuffer.mBuffers[0].mDataByteSize);
[_decodedData appendData:[NSData dataWithBytes:decBuffer.mBuffers[0].mData length:decBuffer.mBuffers[0].mDataByteSize]];
_currPosInDecoderBuf += 1;
} else {
error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
}
} else {
break;
}
}
}
每次,AudioConverterFillComplexBuffer 返回状态 1852797029,根据 Apple API,kAudioCodecIllegalOperationError。如果有人成功转换了此类格式,请分享一些示例或建议。