У меня есть одно приложение, в котором звук опережает видео, поэтому я хотел бы задержать звук на полсекунды. В настоящее время я перенаправляю звук приложения в нулевой модуль PulseAudio, а затем использую parec для отправки вывода монитора во внешнюю программу буферизации, которая затем выводит данные на полсекунды позже обратно в PulseAudio. Есть ли более простой способ сделать это в PulseAudio?
решение1
Theмодуль обратной связипозволит вам добавить до 2 секунд задержки между источником и приемником.
решение2
Я хотел бы поделиться своим bash-скриптом (называется «pa-задержка»), который использует модули loopback и null-sink, уже упомянутыеИгнасио Васкес-Абрамсдля создания цепочки виртуальных приемников и обратных петель произвольной длины. Я активно использую этот скрипт. Приемники называются Delay1, Delay2, … Delayни скрипт сначала выгружает все приемники с таким именем и все циклы, использующие эти приемники, которые могли быть созданы предыдущим запуском. Затем он строит цепочку до длины, требуемой запрошенной задержкой, которая указывается в миллисекундах как параметр командной строки. (Задержка 0 заставит скрипт удалить предыдущую цепочку и затем выйти.) Первый виртуальный приемник, Delay1, всегда является тем, к которому нужно подключиться, чтобы получить полную задержку. Промежуточные приемники теоретически также могут использоваться, и всем им даются описания, указывающие величину задержки, которая возникнет при подключении к ним. Важно, чтобы Delay1 всегда был приемником для использования, потому что (по крайней мере, для меня в XFCE) система «запоминает», к какому приемнику была подключена программа. Программа, подключенная к приемнику Delay1, вернется к нему, даже если цепочка некоторое время не существовала (в течение которого программа будет подключена к устройству вывода по умолчанию). Поэтому я могу вызватьpa-задержкатак часто, как требуется для регулировки длины задержки и без дальнейшего вмешательства любая программа, использующая задержку, будет использовать новую цепочку, установленную каждым запуском. Это также применимо после того, как я вызвалpa-задержка 0иметь звук без задержки в течение более длительного времени. Я обнаружил, что после приостановки работы моего компьютера задержка имеет тенденцию быть больше, чем указано (что соответствуетпредупреждениечтозадержка_мсекпараметр для модуля обратной связи — «только дружественный запрос»), поэтому я также перехожу в состояние «pa-delay 0» перед приостановкой.
#! /bin/bash
delay_msec="$1"
if [[ ! $delay_msec =~ ^[0-9]+$ ]]; then
echo "Usage: $( basename "$0" ) delay_milliseconds" >&2
exit 2
fi
max_loopback_delay=2000
list_delay_loopback_modules() {
pactl list modules short | grep -P '\tmodule-loopback\t(.*\s)?source=Delay[1-9][0-9]*[.]monitor(\s|$)' | cut -f1
}
list_delay_null_modules() {
pactl list modules short | grep -P '\tmodule-null-sink\t(.*\s)?sink_name=Delay[1-9][0-9]*(\s|$)' | cut -f1
}
build_module_array() {
local object_type="$1"
local array="$( echo "$1" | sed 's/-/_/g' )"
typeset -n array
local object_list="$(
pactl list "$object_type" |
perl -00 -p -e ' chomp; s{\s*\n\s*}{|}mg; s{$}{\n}; ' |
sed -En -e 's/^[a-zA-Z ]* #([0-9]+)[|].*[|]Owner Module: ([0-9]+)[|].*/\1:\2/p'
)"
while IFS=: read object module; do
array[$module]=$object
done <<<"$object_list"
}
for module in $( list_delay_loopback_modules ); do
pactl unload-module "$module"
done
for module in $( list_delay_null_modules ); do
pactl unload-module "$module"
done
last_loopback_delay=$(( (delay_msec + max_loopback_delay - 1) % max_loopback_delay + 1 ))
loops=$(( (delay_msec - last_loopback_delay) / max_loopback_delay + 1 ))
(( loops > 0 )) || exit 0
nbsp="$( echo -e '\u00a0' )"
narrownbsp="$( echo -e '\u202f' )"
i=1
module="$( pactl load-module module-null-sink sink_name="Delay$i" sink_properties="device.description=\"Delay:${nbsp}${delay_msec}${narrownbsp}ms\"" )"
while (( ++i <= loops )); do
module="$( pactl load-module module-null-sink sink_name="Delay$i" sink_properties="device.description=\"Delay:${nbsp}$(( delay_msec - (i - 1) * max_loopback_delay ))${narrownbsp}ms\"" )"
done
i=$loops
module="$( pactl load-module module-loopback source="Delay$i.monitor" latency_msec=$last_loopback_delay )"
last_loopback_module=$module
while (( --i > 0 )); do
module="$( pactl load-module module-loopback source="Delay$i.monitor" sink=Delay$(( i + 1 )) latency_msec=$max_loopback_delay )"
done
build_module_array sinks
build_module_array sources
build_module_array sink-inputs
build_module_array source-outputs
for module in $( list_delay_null_modules ); do
pactl set-source-volume ${sources[$module]} '100%'
pactl set-sink-volume ${sinks[$module]} '100%'
done
for module in $( list_delay_loopback_modules ); do
pactl set-source-output-volume ${source_outputs[$module]} '100%'
test "$module" == "$last_loopback_module" && continue
pactl set-sink-input-volume ${sink_inputs[$module]} '100%'
done