pulseaudio: Ausgabe der App um einen bestimmten Zeitraum verzögern

pulseaudio: Ausgabe der App um einen bestimmten Zeitraum verzögern

Ich habe eine App, bei der der Ton vor dem Video kommt, deshalb möchte ich den Ton um eine halbe Sekunde verzögern. Ich leite den Ton der App derzeit an ein Pulseaudio-Nullmodul um und verwende dann Parec, um die Monitorausgabe an ein externes Pufferprogramm zu senden, das die Daten dann eine halbe Sekunde später wieder an Pulse ausgibt. Gibt es innerhalb von Pulseaudio eine einfachere Möglichkeit, dies zu tun?

Antwort1

DerLoopback-Modulermöglicht Ihnen, bis zu 2 Sekunden Verzögerung zwischen einer Quelle und einer Senke hinzuzufügen.

Antwort2

Ich möchte mein Bash-Skript (genannt „PA-Verzögerung”), das die bereits erwähnten Loopback- und Null-Sink-Module verwendetIgnacio Vazquez-Abramsum eine Kette von virtuellen Sinks und Loopbacks beliebiger Länge zu erstellen. Ich verwende dieses Skript aktiv. Die Sinks heißen Delay1, Delay2, … DelayNund das Skript entlädt zuerst alle Senken dieses Namens und alle Loopbacks, die diese Senken verwenden und die möglicherweise von einem vorherigen Lauf erstellt wurden. Dann baut es die Kette auf die Länge auf, die für die angeforderte Verzögerung erforderlich ist, die in Millisekunden als Befehlszeilenparameter angegeben wird. (Eine Verzögerung von 0 bewirkt, dass das Skript die vorherige Kette entfernt und dann beendet wird.) Die erste virtuelle Senke, Delay1, ist immer diejenige, mit der eine Verbindung hergestellt werden muss, um die volle Verzögerung zu erhalten. Theoretisch könnten auch die Zwischensenken verwendet werden, und sie alle erhalten Beschreibungen, die die Verzögerung angeben, die durch die Verbindung mit ihnen entstehen würde. Es ist wichtig, dass Delay1 immer die zu verwendende Senke ist, da sich das System (zumindest für mich in XFCE) „merkt“, mit welcher Senke ein Programm verbunden war. Ein Programm, das mit der Senke Delay1 verbunden ist, wird darauf zurückgreifen, selbst wenn die Kette eine Zeit lang nicht existiert hat (während dieser Zeit wird das Programm mit dem Standardausgabegerät verbunden). Ich kann also aufrufenPA-Verzögerungso oft wie nötig, um die Verzögerungslänge anzupassen, und ohne weiteres Eingreifen wird jedes Programm, das die Verzögerung verwendet, die neue Kette verwenden, die bei jedem Durchlauf erstellt wurde. Dies gilt auch, nachdem ich aufgerufen habepa-Verzögerung 0um Audio über einen längeren Zeitraum unverzögert zu haben. Ich stelle fest, dass die Verzögerung nach dem Suspendieren meines Computers tendenziell länger ist als angegeben (was mit derWarnungdass dieLatenzzeit in msDer Parameter für das Loopback-Modul lautet „nur eine freundliche Anfrage“), daher wechsle ich vor dem Anhalten auch in den Zustand „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

verwandte Informationen