【问题标题】:AudioBufferList for AUHAL unit whose output stream format is compressed.AUHAL 单元的 AudioBufferList,其输出流格式被压缩。
【发布时间】:2018-08-08 20:08:42
【问题描述】:

致谢

我知道这篇文章很长,但我尽量将我的问题与上下文联系起来,因为我认为它非常独特(除了 this one 之外找不到任何相关问题。最后一个问题在最后帖子和here's the complete code

首先,有一点上下文。我正在使用 CoreAudioAudioToolbox 库,更准确地说是 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


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-30
      • 1970-01-01
      • 2018-02-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多