2016-02-15 10 views
0

Недавно я разработал звукозапись на Mac с помощью AudioUnits. Он был разработан так, чтобы вести себя как система видеонаблюдения, непрерывно записываясь с графическим дисплеем уровней мощности для просмотра в режиме просмотра. Я заметил, что каждые 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 callback копирует в локальный буфер, а затем использует обратный вызов, две скорости могут вызвать помехи как дрейф значительно, но он всегда будет расширяться. что сбрасывание с задержкой означает, что необходимо задействовать циклический буфер, а готовый триггер обратного вызова буфера записи буфера 1 (вход) медленнее, чем фактические события заполнения буфера одной шины. Устройство является звуковой картой USB. чтобы исключить возможность обратного вызова, я установил двойную буферизацию, но ничего не изменилось. – kirkgcm

+0

Снова я наблюдаю, что его внутренний кольцевой буфер с круговым буфером с различными таймингами записи/чтения на входной шине. недавно записанный звук микрофона во время воспроизведения фильма, а при воспроизведении части архивированного звука он начал звучать раздражающе в какой-то момент в течение 3 минут, за это время звук имел повторное эхо около 1/4 секунды. Я использую только так что эхо должно поступать из внутреннего циклического буфера. архивирование intimestam-> msampletime вместе с датой времени не показывает признаков переполнения/недостаточности во время шума, только пропущенные обратные вызовы во время дорогостоящего жесткого диска записываются каждые 3 минуты. – kirkgcm

0

В соответствии с этой статьей https://www.native-instruments.com/forum/threads/latency-drift-problem-on-macbook.175551/ эта проблема представляется ошибкой драйвера USB в maverick. Я не нашел решение для замены kext в любом месте.

После изготовления тестера сонарного типа (1 цикл 22кГц квадратная волна нажимает каждые 600 мс на громкоговоритель, отображает выбранный номер записанного кадра после нажатия) и может видеть от 3 до 4 отсчетов в секунду, а также сброс демпфера искажения/задержки опыт через 1,5 часа, я решил осмотреться и найти, как получить доступ к указателям на буфер, чтобы стабилизировать дрейф задержки, но также и не повезло.

Кроме того, запросы api latency не показывают изменений, поскольку они дрейфуют.

Я обнаружил, что вы можете сбросить задержку с помощью audiounitstop, затем audiounitstart (тот же поток), но он работал только в том случае, если активна только одна шина системы audiounit. Исследования также показали, что задержка может быть сброшена, если вы переключаете частоту дискретизации аппаратного устройства в Audio Midi Setup. это немного агрессивно, и для некоторых это будет неудобно.

Мой проект переключил nominalsamplerate (AudioObjectSetPropertyData с kAudioDevicePropertyNominalSampleRate) каждые 60 минут (48000, затем обратно на 44100), с задержкой в ​​ожидании уведомления об изменении через обратный вызов.

Это вызывает 2-секундную пустоту в аудиовходе и выходе каждый час. Safari, играющий видео с YouTube, отключится, и за это время будет заморожено видео за 1-2 секунды. VLC показал то же самое, но видео оставалось плавным во время 2-секундной тишины.

Как я уже сказал, это не сработает для всех, но я выбрал системную ширину 2 секунды без звука каждый час над записью, которая имеет 3 минуты нечеткого звука каждые 1,5 часа. Было опубликовано, что обновление yosemite исправляет это, хотя некоторые из них также нашли потрескивание после перехода на йосемит.