Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 输出流格式被压缩的AUHAL单元的AudioBufferList。 致谢_C++_Macos_Audio_Core Audio_Audiounit - Fatal编程技术网

C++ 输出流格式被压缩的AUHAL单元的AudioBufferList。 致谢

C++ 输出流格式被压缩的AUHAL单元的AudioBufferList。 致谢,c++,macos,audio,core-audio,audiounit,C++,Macos,Audio,Core Audio,Audiounit,我知道这篇文章很长,但我尽量将我的问题背景化,因为我认为这是非常独特的(除此之外,找不到任何相关的问题)。最后一个问题在文章的最后,并且 首先,有一点背景。我正在使用CoreAudio和AudioToolbox库,更准确地说是音频单元。我在macOS上。我的最终目标是从任何输入设备录制音频(因此在简单的AudioQueueBuffer上使用音频单元)并将其写入音频文件。我认为我的程序最棘手的部分是在单个音频单元内从LPCM转换为AAC(在我的情况下),因此没有使用AUGraph 我的程序基本上只

我知道这篇文章很长,但我尽量将我的问题背景化,因为我认为这是非常独特的(除此之外,找不到任何相关的问题)。最后一个问题在文章的最后,并且

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

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

然后,我相应地更新单元输出范围的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[输入范围]中的输入设备录制==>从LPCM转换为==>在AAC中渲染

请注意,每个流格式(输入和输出)使用2个通道。输入流和输出流的
mFormatFlags
均未设置为
kAudioFormatIsNonInterleaved
,因此两者都是交错的。 事实上,我认为这就是问题的根源,但不明白为什么

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

我发现了一张便条,上面写着:

“按照惯例,AUHAL将多声道音频解交织。这意味着您将设置每个声道的两个音频缓冲区,而不是设置一个mNumberChannels==2的音频缓冲区。AudioUnitRender()调用中参数(-50)问题的常见原因是具有其拓扑(或缓冲区排列)的AudioBufferList。”与单位准备生产的产品不匹配。在单位级别进行交易时,您几乎总是希望这样做。”

摘自: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);
}
OSStatus记录器::inputProc(
在refcon中无效*,
AudioUnitRenderActionFlags*ioActionFlags,
常量音频时间戳*inTimeStamp,
UInt32 InBunsNumber,
UInt32数字帧,
音频缓冲列表*ioData
)
{
记录器*此=(记录器*)在refcon中;
CAStreamBasicDescription输出流;
此->getStreamBasicDescription(kAudioUnitScope\u输出,outputStream);
UInt32 bufferSizeBytes=inNumberFrames*sizeof(Float32);
UInt32 propertySize=offsetof(AudioBufferList,mbuffer[0])+(sizeof(AudioBuffer)*outputStream.mcchannelsperframe);
自动缓冲列表=(AudioBufferList*)malloc(propertySize);
bufferList->mNumberBuffers=outputStream.mChannelsPerFrame;
对于(UInt32 i=0;imNumberBuffers;++i)
{
bufferList->mBuffers[i].mNumberChannels=1;
bufferList->mBuffers[i].mDataByteSize=bufferSizeBytes;
bufferList->mBuffers[i].mData=malloc(bufferSizeBytes);
}
校验错误(
AudioUnitRender(
这个单位,
ioActionFlags,
起义坦普,
在美国,
无数帧,
缓冲列表
),
“无法呈现音频单元。”
);
免费(缓冲列表);
}
然后,当我尝试渲染音频时,出现以下错误:
错误:无法渲染音频单元。(-50)
,这实际上是一个本应按照注释进行修复的错误,这让我更加困惑

问题 在这一点上,我不知道这是否与我的总体架构有关,也就是说,我是否应该使用一个AUGraph并添加一个输出单元,而不是尝试在单个AUHAL单元内从规范格式转换为压缩格式?
或者这与我预分配AudioBufferList的方式有关?

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