Блоки Windows Audio/WaveInAddBuffer()

Мое приложение записывает образцы звука с микрофона, подключенного к моему ПК. Поэтому я выбрал Windows WaveInXXX API для выполнения этой работы.

После прочтения документации я решил не использовать механизм обратного вызова с WaveInProc, чтобы избавить меня от хлопот, связанных с синхронизацией потоков. Все приложение довольно большое, и я подумал, что это упростит отладку. Когда приложение запрашивает блок сэмплов, я просто перебираю свою буферную очередь, беру один, копирую данные, не подготавливаю их, подготавливаю и добавляю обратно в буферную очередь. Базовая структура программы выглядит так, я надеюсь, что она делает основной ход программы понятным:

WaveInOpen()
WaveInStart()
FunctionAddingPreparedBuffersToTheQueue()
while(someConditionThatEventuallyBecomesFalse)
    if(NextBufferInQueueIsMarkedDone)
        GetDataFromBuffer()
        UnpreparePrepareHeaderAndAddBuffer()
    else
        WaitForAShortTime()
WaveInStop()
WaveInClose()

Теперь возникает проблема: через некоторое время (и я не могу воспроизвести точное условие) WaveInAddBuffer() вызывает взаимоблокировку, хотя находится в том же потоке, что и все остальные. Подготавливается заголовок для буфера, который должен быть добавлен при возникновении взаимоблокировки, и dwFlags == WHDR_PREPARED == 2.

Любые идеи, что может вызвать этот тупик?


person fewu    schedule 09.12.2013    source источник
comment
Даже если вы еще не знаете причину проблемы, попробуйте опубликовать SSCCE, чтобы проиллюстрировать проблему, с которой вы столкнулись. перед.   -  person IInspectable    schedule 09.12.2013
comment
Итак, какой механизм обратного вызова вы используете, CALLBACK_NULL? Во время тупика вы можете взломать и перехватить стеки вызовов замороженных потоков - это то, что будет полезно. Я предполагаю, что проблема связана с NextBufferInQueueIsMarkedDone, и вы проверяете флаги буфера, обращаясь к ним немедленно (проверяя WHDR_DONE). Если это так, вам не следует этого делать, и вы должны получать уведомление о доступности буфера через механизм обратного вызова по вашему выбору.   -  person Roman R.    schedule 09.12.2013
comment
@РоманР. Я последовал вашему совету, использовал CALLBACK_FUNCTION вместо CALLBACK_NULL, и теперь взаимоблокировки исчезли, так что спасибо за это! К сожалению, я до сих пор не могу сказать, в чем была первоначальная проблема, что немного неудовлетворительно. Как вы думаете, почему проверка флагов буфера, как я делал ранее, является проблемой?   -  person fewu    schedule 10.12.2013
comment
API читает/записывает флаги рабочих потоков. Обращаясь к ним напрямую, вы не можете синхронизировать доступ с API, поэтому вам приходится полагаться на возврат буферов API вам, а не на флаги буфера, которые вы можете прочитать напрямую.   -  person Roman R.    schedule 10.12.2013


Ответы (1)


Я не видел такой проблемы, но могу предположить, что это что-то вроде фрагментации, связанной со всеми циклами unprepare/prepare. Они не нужны. Вы можете выполнить подготовку один раз для каждого буфера, а затем отменить подготовку по окончании записи. (Подготовка блокирует буфер в физической памяти.)

person ScottMcP-MVP    schedule 09.12.2013