我最近使用AudioUnits在Mac上设计了一个录音机。它被设计成像视频安全系统一样,连续录制,具有用于回放浏览的功率级别的图形显示。 我注意到每隔85分钟出现失真3分钟。经过一天的消除后,似乎调用回调之前发生的声音采集使用循环缓冲区,并且回调的audioUnitRender函数从此缓冲区中提取但速度稍慢,最终导致内部缓冲区写入环绕并捕获用audioUnitRender读取。双工操作测试显示延迟不断增加,并且在85分钟后您听到大约200-300ms的延迟并且噪声开始,因为渲染缓冲器帧在缓冲器的结束和开始处具有缓冲器段的组合,即长和短的延迟。当指针漂移时,噪音消失,你听到原始短暂延迟的干净音频,然后在85分钟后再次重复。即使使用低影响回调处理,这仍然会发生。我看过一些有关延迟的帖子但没有关于冲突的帖子,有人见过这个吗?
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 :(得分:0)
您似乎正在使用HAL输出单元来提取输入。可能无法保证输入设备和输出设备采样率完全锁定。任何一个器件的采样率的任何缓慢的轻微漂移都可能最终导致缓冲器下溢或溢出。
一种解决方案可能是为单独的输入音频单元查找和设置输入设备,而不是依赖于默认输出单元。例如,尝试使用USB麦克风。
答案 1 :(得分:0)
根据这篇文章https://www.native-instruments.com/forum/threads/latency-drift-problem-on-macbook.175551/,这个问题似乎是特立独行的usb音频驱动程序错误。我没有在任何地方找到kext替代解决方案。
制作声纳型测试仪(1个周期22khz方波每隔600毫秒点击一次扬声器,点击后显示选定的记录帧数),可以看到每秒3到4个样本漂移以及失真/延迟漂移重置体验1.5小时后,我决定环顾四周,找到如何访问缓冲区指针以稳定延迟漂移,但也没有运气。
此外,api延迟查询在漂移时不会显示任何更改。
我确实发现您可以使用audiounitstop然后audiounitstart(相同的线程)重置延迟,但只有当只有一个audiounit总线系统处于活动状态时它才有效。研究还表明,如果您在Audio Midi Setup中切换硬件设备采样率,则可以重置延迟。这有点激进,有些人会感到不舒服。
我的设计每隔60分钟(48000然后回到44100)切换nominalsamplerate(AudioObjectSetPropertyData with kAudioDevicePropertyNominalSampleRate),并通过回调等待更改通知的延迟。
这导致每小时音频输入和输出有2秒的空白。播放youtube视频的Safari会静音,并在此期间导致1-2秒的视频冻结。 VLC显示相同但视频在2秒静音期间保持平滑。
就像我说的那样,它并不适用于所有人,但是我每小时选择系统范围的2秒静音,而不是每1.5小时有3分钟模糊音频的录音。据推测,优胜美地升级修复了这个问题,虽然有些人在去约塞米蒂后也发现了噼啪声。