pulseaudio:延迟应用程序的输出时间

pulseaudio:延迟应用程序的输出时间

我有一个应用程序,其中音频领先于视频,所以我想将音频延迟半秒。我目前正在将应用程序的音频重定向到 pulseaudio null 模块,然后使用 parec 将监视器输出发送到外部缓冲程序,然后该程序在半秒后将数据输出回 pulse。在 pulseaudio 中有没有更简单的方法可以做到这一点?

答案1

环回模块将允许您在源和接收器之间添加最多 2 秒的延迟。

答案2

我想分享我的 bash 脚本(名为“延迟”),它使用了前面提到的 loopback 和 null-sink 模块伊格纳西奥·巴斯克斯·艾布拉姆斯建立任意长度的虚拟接收器和环回链。我正在积极使用此脚本。接收器称为 Delay1、Delay2、…Delayn并且脚本首先卸载所有同名接收器以及使用这些接收器的任何环回(这些接收器可能由之前的运行创建)。然后,它将链构建为请求的延迟所需的长度,该延迟以毫秒为单位指定为命令行参数。(延迟为 0 将使脚本删除前一个链然后退出。)第一个虚拟接收器 Delay1 始终是要连接的接收器,以便获得完整的延迟。中间接收器理论上也可以使用,并且它们都给出了说明连接到它们将导致的延迟量的描述。始终使用 Delay1 很重要,因为(至少对于我在 XFCE 中来说)系统“记住”程序连接到哪个接收器。连接到 Delay1 接收器的程序将恢复到它,即使链已经不存在了一段时间(在此期间程序将连接到默认输出设备)。所以我可以调用延迟根据需要经常调整延迟长度,并且无需进一步干预,任何使用延迟的程序都将使用每次运行建立的新链。这也适用于我调用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

相关内容