音频缓冲区列表,用于输出流格式已压缩的 AUHAL 单元

AudioBufferList for AUHAL unit whose output stream format is compressed.

本文关键字:压缩 AUHAL 单元 格式 输出流 缓冲区 列表 用于 音频      更新时间:2023-10-16

致谢

我知道这篇文章很长,但我试图尽可能多地将我的问题置于上下文中,因为我认为它非常独特(除了这个问题之外找不到任何相关问题。最后一个问题在帖子的最后,这是完整的代码。

首先,一点背景。我正在使用CoreAudioAudioToolbox库,更准确地说是音频单元。我使用的是 macOS。我的最终目标是录制来自任何输入设备的音频(因此在简单的AudioQueueBuffer上使用音频单元)并将其写入音频文件。我认为我的程序最棘手的部分是在单个音频单元中从 LPCM 转换为 AAC(在我的情况下),因此不使用 AUGraph。

我的程序基本上只是一个音频单元,封装在一个类中,AudioUnit mInputUnit它是一个AUHAL单元。因此,我按照此技术说明进行了设置。基本上,我将输入元素的输入范围(因为输出元素被禁用)链接到音频设备,即我的内置麦克风。

然后我相应地更新单元输出范围的音频格式。

...
inputStream.mFormatID = kAudioFormatMPEG4AAC;
inputStream.mFormatFlags = 0;
inputStream.mBitsPerChannel = 0;
checkError(
AudioUnitSetProperty(
mInputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
1,
&inputStream,
propertySize
),
"Couldn't set output stream format."
);

因此,此时,音频单元按如下方式工作:

从 LPCM 中的输入设备录制 [输入范围] ==> 从 LPCM 转换为 ==> 在 AAC 中渲染。

请注意,每种流格式(输入和输出)使用2 个通道。输入和输出流都没有将其mFormatFlags设置为kAudioFormatIsNonInterleaved,因此它们都是交错的。 事实上,我认为这就是问题的来源,但看不出原因。

在这一点上,一切似乎都正常。当我在设置输入回调后尝试渲染音频单元时,会出现此问题。

我找到了一个便条,上面写着以下内容:

"按照惯例,AUHAL去交错多声道音频。这意味着您可以设置两个每个通道的音频缓冲区,而不是使用 mNumberChannel==2 设置一个音频缓冲区。在 AudioUnitRender() 调用中出现 paramErr (-50) 问题的常见原因是 AudioBufferLists的拓扑(或缓冲区的排列)与单元准备生成的内容不匹配。在单位级别处理时,您几乎总是希望像这样进行非交错处理。

摘自:Chris Adamson & Kevin Avila。"Learning Core Audio: A Hands-Practice Guide to Audio Programming for Mac and iOS "iBooks。

因此,我遵循适当的代码结构来渲染音频。

OSStatus Recorder::inputProc(
void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData
)
{
Recorder *This = (Recorder *) inRefCon;
CAStreamBasicDescription outputStream;
This->getStreamBasicDescription(kAudioUnitScope_Output, outputStream);
UInt32 bufferSizeBytes = inNumberFrames * sizeof(Float32);
UInt32 propertySize = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * outputStream.mChannelsPerFrame);
auto bufferList = (AudioBufferList*) malloc(propertySize);
bufferList->mNumberBuffers = outputStream.mChannelsPerFrame;
for(UInt32 i = 0; i < bufferList->mNumberBuffers; ++i)
{
bufferList->mBuffers[i].mNumberChannels = 1;
bufferList->mBuffers[i].mDataByteSize = bufferSizeBytes;
bufferList->mBuffers[i].mData = malloc(bufferSizeBytes);
}
checkError(
AudioUnitRender(
This->mInputUnit,
ioActionFlags,
inTimeStamp,
inBusNumber,
inNumberFrames,
bufferList
),
"Couldn't render audio unit."
);
free(bufferList);
}

然后,当我尝试渲染音频时,我遇到了以下错误Error: Couldn't render audio unit. (-50)这实际上是应该通过遵循注释来修复的错误,这让我更加困惑。

问题

在这一点上,我不知道这是否与我的整体架构有关,即我应该使用AUGraph并添加一个输出单元,而不是尝试在单个 AUHAL 单元内从规范格式转换为压缩格式? 或者这与我预先分配音频缓冲区列表的方式有关?

我设法通过重新设计整个过程来解决此问题。简而言之,我仍然有一个独特的 AUHAL 单元,但我不是在 AUHAL 单元中进行格式转换,而是在渲染回调中使用扩展音频文件进行转换,该文件采用源格式和目标格式。 整个挑战是找到正确的格式描述,这基本上只是测试mFormatIDmFormatFlags等的不同值......