Время между обратными вызовами?
У меня есть лабораторный проект, в котором в основном используется PyAudio, и чтобы лучше понять, как он работает, я провел некоторые измерения, в данном случае время между обратными вызовами (используя режим обратного вызова).
Я рассчитал это, и получил интересный результат
(При размере фрагмента 256, 44,1 тыс. Фс): 0,0099701;0,0000365;0,0000201;0,0201579
Эта модель продолжается и продолжается.
Между двумя более длинными вызовами у нас есть два более коротких вызова, а иногда более длинный вызов короче (учтите, я не делаю в программе ничего другого, кроме времени обратных вызовов).
Если мы усредним это, мы получим желаемое время обратного вызова:
1/44100 * 256 (примерно 5,8 мс)
Вот мое измерение визуализируется:
Так может кто-нибудь объяснить, что именно здесь происходит под капотом?
1 ответ
То, что происходит под капотом в PortAudio, зависит от ряда факторов, в том числе:
- С каким родным аудио API PortAudio общается
- Какой размер буфера и параметры задержки вы передали
Pa_OpenStream()
- Возможности аудиооборудования и его драйверов, включая поддерживаемые размеры буфера, модель буферизации и временные характеристики.
При некоторых обстоятельствах PortAudio будет запрашивать большие буферы у нативного аудио API, а затем вызывать пользовательский обратный вызов PortAudio несколько раз в быстрой последовательности. Это может произойти, если вы выбрали небольшой размер буфера обратного вызова и большую задержку.
Другой сценарий состоит в том, что собственный аудио API не поддерживает размер буфера, который вы запрашивали для размера обратного вызова (framesPerBuffer
параметр для Pa_OpenStream()
). В этом случае PortAudio будет вынужден использовать поддерживаемый драйвером размер буфера, а затем "адаптироваться" между этим размером буфера и размером буфера обратного вызова. Этот процесс адаптации может вызвать нерегулярные сроки.
Еще одна возможность состоит в том, что нативный аудио API использует большой кольцевой буфер. Каждый раз, когда PortAudio опрашивает собственный API хоста, он будет заполнять собственный кольцевой буфер, вызывая ваш обратный вызов столько раз, сколько необходимо. В этом случае неправильное время связано с частотой опроса.
Вышесказанное не единственные возможности.
Одним из вероятных объяснений того, что происходит в вашем случае, является то, что PortAudio вызывает ваш обратный вызов 3 раза подряд (предположительно, размер встроенного буфера в 3 раза больше размера буфера обратного вызова) по одной из вышеуказанных причин.
Другая возможность состоит в том, что собственная звуковая подсистема сигнализирует PortAudio нерегулярно. Это может произойти, если системный уровень ниже PortAudio выполняет буферизацию, аналогичную описанной выше. Я видел, как это случилось с DirectSound на Windows 7, например. Драйверы ASIO4ALL будут демонстрировать джиттер +/- 1 мс (это не то, что вы видите).
Вы можете попробовать уменьшить запрошенную задержку потока до 0 и посмотреть, изменит ли это результат. Это приведет к двойной буферизации, которая может или не может обеспечить стабильный выход. Еще одна вещь, чтобы попробовать это использовать paFramesPerBufferUnspecified
параметр, который будет вызывать обратный вызов с собственным размером буфера - тогда вы можете наблюдать, существует ли большая периодичность, каков этот размер буфера, а также, изменяется ли размер буфера от обратного вызова до обратного вызова.
Вы не сказали, на какую операционную систему и хост-API вы нацеливаетесь, поэтому сложно дать более конкретную информацию, чем указано выше.
Чтобы ответить на связанный вопрос: почему это так? Помимо случаев, когда это является функцией нижних уровней встроенной звуковой подсистемы или процесса адаптации буфера, это часто является результатом указания большой предполагаемой задержки для Pa_OpenStream()
, Некоторые API хоста PortAudio уменьшают периодичность буфера, если заданная задержка очень высока, чтобы уменьшить нагрузку на систему, которая может быть вызвана высокочастотными обратными вызовами таймера.