【发布时间】:2018-08-08 20:08:42
【问题描述】:
致谢
我知道这篇文章很长,但我尽量将我的问题与上下文联系起来,因为我认为它非常独特(除了 this one 之外找不到任何相关问题。最后一个问题在最后帖子和here's the complete code。
首先,有一点上下文。我正在使用 CoreAudio 和 AudioToolbox 库,更准确地说是 Audio Units。我在 macOS 上。我的最终目标是记录来自任何输入设备的音频(因此在简单的 AudioQueueBuffer 上使用音频单元)并将其写入音频文件。我认为我的程序中最棘手的部分是在一个单个音频单元内从 LPCM 转换为 AAC(在我的情况下),因此没有使用 AUGraph。
我的程序基本上只是一个音频单元,封装在一个类中,AudioUnit mInputUnit 是一个 AUHAL 单元。因此,我按照this technical note 进行了设置。基本上,我将输入元素的输入范围(因为输出元素被禁用)链接到音频设备,即我的内置麦克风。
然后我相应地更新单元的输出范围的 AudioFormat。
...
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 [INPUT SCOPE] 中从输入设备录制 ==> 从 LPCM 转换为 ==> 在 AAC 中渲染。
请注意,每种流格式(输入和输出)都使用 2 个通道。输入流和输出流都没有将其mFormatFlags 设置为kAudioFormatIsNonInterleaved,因此它们都是交错的。
事实上,我认为这就是问题所在,但不明白为什么。
此时,一切似乎都正常。当我在设置输入回调后尝试渲染音频单元时会出现问题。
我找到了一个注释,上面写着:
“按照惯例,AUHAL 对多声道音频进行去交错处理。这意味着您设置了两个 AudioBuffers,每个 AudioBuffers 一个通道,而不是设置一个 mNumberChannels==2 的 AudioBuffer。 AudioUnitRender() 调用中 paramErr (-50) 问题的一个常见原因是 AudioBufferLists 的拓扑(或缓冲区排列)与单元准备生成的内容不匹配。在单元级别处理时,您几乎总是希望像这样进行非交错处理。”
摘自:克里斯·亚当森和凯文·阿维拉。 “学习核心音频:Mac 和 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 单元内的压缩格式? 还是这与我预先分配 AudioBufferList 的方式有关?
【问题讨论】:
标签: c++ macos audio core-audio audiounit