2016-02-15 330 views
0

我最近使用AudioUnits在Mac上设计了一个Sound录音机。它的设计表现就像一个视频安全系统,连续录制,带有用于播放浏览的功率级图形显示。 我注意到每85分钟出现3分钟扭曲。消除一天后,似乎在回调之前发生的声音采集被称为使用循环缓冲区,并且回调的audioUnitRender函数从该缓冲区中提取,但速度稍慢,这最终导致内部缓冲区写入环绕并捕捉用audioUnitRender读取。双工操作测试显示延迟时间不断增加,85分钟后,您会听到大约200-300毫秒的延迟,并且由于渲染缓冲区帧在缓冲区的末尾和开始处具有缓冲区组合,即长和短的延迟,噪声开始。随着指针分开,噪声消失,并且您听到干净的音频和原始的短延迟,然后在85分钟后再次重复。即使是低影响回调处理,这仍然会发生。我看过一些关于延迟的文章,但没有关于冲突的文章,有没有人看到这个?AudioUnit(Mac)AudioUnitRender内部缓冲区冲突

OSX 10.9.5时,Xcode 6.1.1 代码的细节: -

//modes 1=playback, 2=record, 3=both 
AudioComponentDescription outputcd = {0}; // 10.6 version 
outputcd.componentType = kAudioUnitType_Output; 
outputcd.componentSubType = kAudioUnitSubType_HALOutput; //allows duplex 
outputcd.componentManufacturer = kAudioUnitManufacturer_Apple; 
AudioComponent comp = AudioComponentFindNext (NULL, &outputcd); 
if (comp == NULL) {printf ("can't get output unit");exit (-1);} 
CheckError (AudioComponentInstanceNew(comp, au),"Couldn't open component for outputUnit"); 
//tell input bus that its's input, tell output it's an output 
if(mode==1 || mode==3) r=[self setAudioMode:*au :0];//play 
if(mode==2 || mode==3) r=[self setAudioMode:*au :1];//rec  
// register render callback 
if(mode==1 || mode==3) [self setCallBack:*au :0]; 
if(mode==2 || mode==3) [self setCallBack:*au :1]; 
// if(mode==2 || mode==3) [self setAllocBuffer:*au]; 
// get default stream, change amt of channels 
AudioStreamBasicDescription audioFormat; 
UInt32 k=sizeof(audioFormat); 
r= AudioUnitGetProperty(*au, 
           kAudioUnitProperty_StreamFormat, 
           kAudioUnitScope_Output, 
           1, 
           &audioFormat, 
         &k); 
audioFormat.mChannelsPerFrame=1; 
r= AudioUnitSetProperty(*au, 
         kAudioUnitProperty_StreamFormat, 
         kAudioUnitScope_Output, 
         1, 
         &audioFormat, 
         k); 
//start 
CheckError (AudioUnitInitialize(outputUnit),"Couldn't initialize output unit"); 

//record callback 
OSStatus RecProc(void *inRefCon, 
      AudioUnitRenderActionFlags *ioActionFlags, 
      const AudioTimeStamp *inTimeStamp, 
      UInt32 inBusNumber, 
      UInt32 inNumberFrames, 
      AudioBufferList * ioData) 
{ 
myView * mv2=(__bridge myView*)inRefCon; 
AudioBuffer buffer,buffer2; 
OSStatus status; 
buffer.mDataByteSize = inNumberFrames *4 ;// buffer size 
buffer.mNumberChannels = 1; // one channel 
buffer.mData =mv2->rdata; 
buffer2.mDataByteSize = inNumberFrames *4 ;// buffer size 
buffer2.mNumberChannels = 1; // one channel 
buffer2.mData =mv2->rdata2; 
AudioBufferList bufferList; 
bufferList.mNumberBuffers = 2; 
bufferList.mBuffers[0] = buffer; 
bufferList.mBuffers[1] = buffer2; 
status = AudioUnitRender(mv2->outputUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList); 

[mv2 recproc :mv->rdata :mv->rdata2 :inNumberFrames]; 
return noErr; 
} 
+0

故障原因或错误可能出现在您的采样率设置,音频单元回调函数内或您的文件编写代码中,这些代码没有显示。 – hotpaw2

+0

我想我已经消除了所有这一切。我的第一个想法是它是我的adpcm压缩程序,但我足够见证这个问题(需要很长时间等待85分钟),缩小版本,不压缩,不归档,只是播放所记录的内容(带耳机)。还要注意延迟变化,当问题发生时,您会听到延迟延迟以及延迟约20毫秒的原始副本。那么长时间等待复制和失真消失,并且音频是干净的,直到85分钟后再次发生。 – kirkgcm

+0

继续: - 这最后的意见暗示其内部循环缓冲区问题。我会经常扔掉几帧,以避免这种情况,我知道如何。可能会错过每个回调的audiounitrender调用(或添加额外)会做到这一点,但我不确定。希望有人知道内部隐藏有关此场景的细节因为我相信它在音频硬件驱动程序(kext) – kirkgcm

回答

0

你似乎使用HAL输出单元拉输入。可能无法保证输入设备和输出设备采样率完全锁定。任一器件采样速率的任何缓慢的轻微漂移都可能最终导致缓冲器下溢或溢出。

一种解决方案是寻找并设置一个输入设备,用于一个单独的输入音频单元而不是取决于默认输出单元上。例如,尝试使用USB麦克风。

+0

这是一个非常合乎逻辑的可能性,如果rec回调拷贝到本地缓冲区然后回拨使用它,两个速率会造成显着的漂移干扰,但它总会变得更加分开。它的延迟重置意味着一个循环缓冲区必须被涉及,并且总线1(输入)的记录缓冲区就绪回调触发比实际相同总线的缓冲区填充事件慢。该设备是一个USB声卡顺便说一句。为了消除回调重新进入的可能性,我设置了双缓冲,但没有任何改变。 – kirkgcm

+0

我再次观察到它的输入总线上具有不同写入/读取时序的内部fifo循环缓冲区。最近在播放电影时录制了麦克风音频,并且在播放部分存档音频时,它在某个时间点开始听起来很刺耳,持续3分钟,在那段时间内,音频具有约1/4秒的重复回声。我仅使用线性缓冲区,所以回声必须来自内部循环缓冲区。归档intimestam-> msampletime以及日期时间不会在噪音时显示过量/下溢的迹象,只有在每3分钟写入昂贵的硬盘驱动器时才会错过回调。 – kirkgcm

0

根据这篇文章https://www.native-instruments.com/forum/threads/latency-drift-problem-on-macbook.175551/这个问题似乎是特立独行的USB音频驱动程序的bug。我没有在任何地方找到kext替换解决方案。

在制作声纳型测试仪(1个周期22khz方波,每600毫秒点击一次扬声器,点击后显示选定的记录帧数),可以看到每秒3到4个样本漂移以及失真/延迟漂移重置1.5小时后的经验,我决定环顾四周,找到如何访问缓冲区指针来稳定延迟漂移,但也没有运气。

而且API延迟查询显示没有变化,因为它漂移。

我没找到,你可以延迟与audiounitstop然后audiounitstart(同一线程)复位,但它的工作只是,如果只有一个audiounit总线系统广泛活跃。研究还表明,如果您在Audio Midi设置中切换硬件设备采样率,则可以重置延迟时间。这有点侵略性,会让一些人感到不舒服。

我的设计每60分钟(48000然后回到44100)切换标称采样率(AudioObjectSetPropertyData与kAudioDevicePropertyNominalSampleRate),延迟通过等待通过回调的更改通知。

这种原因在音频输入和输出每小时2第二空隙。播放YouTube视频的Safari会静音,并在此期间导致1-2秒的视频冻结。 VLC显示了相同的效果,但在2秒钟的静音期间,视频保持平稳

就像我说的,它不会对所有的工作,但我选择了系统宽2第二静噪每隔一小时以上是进行3分钟的模糊声音的每1.5小时录音。据报道,优胜美地升级解决了这个问题,尽管有些人在去约塞米蒂之后也发现了crack啪声。