用于AUHAL单元的AudioBufferList,其输出流格式被压缩。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用于AUHAL单元的AudioBufferList,其输出流格式被压缩。相关的知识,希望对你有一定的参考价值。

ACKNOWLEDGEMENTS

我知道这篇文章很长,但我尽可能地将我的问题置于语境中,因为我认为它非常独特(除了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,而不是使用mNumberChannels == 2设置一个AudioBuffer。 AudioUnitRender()调用中paramErr(-50)问题的常见原因是具有AudioBufferLists,其拓扑(或缓冲区的排列)与单元准备生成的内容不匹配。在单位级别进行交易时,你几乎总是希望像这样进行非交错。“

摘录自:Chris Adamson和Kevin Avila。 “学习核心音频:适用于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的方式有关?

答案

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

以上是关于用于AUHAL单元的AudioBufferList,其输出流格式被压缩。的主要内容,如果未能解决你的问题,请参考以下文章

使用 Pyaudio 在 Python 中录制音频,错误 ||PaMacCore (AUHAL)|| ... msg=音频单元:在当前上下文中无法执行

iPhone:AudioBufferList 初始化和释放

将 AudioBufferList 转换为 CMSampleBuffer 会产生意外结果

在 AUHAL 上设置采样率

AudioBufferList 的 AurioTouch 用途

如何在渲染回调中交错非交错的 AudioBufferList?