pulseaudio: retrasa la salida de la aplicación por cantidad de tiempo

pulseaudio: retrasa la salida de la aplicación por cantidad de tiempo

Tengo una aplicación en la que el audio va delante del vídeo, por lo que me gustaría retrasar el audio medio segundo. Actualmente estoy redirigiendo el audio de la aplicación a un módulo nulo de pulseaudio y luego usando parec para enviar la salida del monitor a un programa de almacenamiento en búfer externo, que luego envía los datos medio segundo después a pulso. ¿Existe una manera más sencilla dentro de pulseaudio de hacer esto?

Respuesta1

Elmódulo de bucle invertidole permitirá agregar hasta 2 segundos de retraso entre una fuente y un sumidero.

Respuesta2

Me gustaría compartir mi script bash (llamado "pa-retraso”) que utiliza los módulos loopback y null-sink ya mencionados porIgnacio Vázquez-Abramspara establecer una cadena de sumideros virtuales y loopbacks de longitud arbitraria. Estoy usando activamente este script. Los sumideros se llaman Delay1, Delay2,… Delaynortey el script primero descarga los receptores con ese nombre y los loopbacks que utilicen estos receptores y que puedan haber sido creados en una ejecución anterior. Luego construye la cadena hasta la longitud requerida por el retraso solicitado, que se especifica en milisegundos como parámetro de la línea de comando. (Un retraso de 0 hará que el script elimine la cadena anterior y luego salga). El primer receptor virtual, Delay1, es siempre al que conectarse para obtener el retraso completo. En teoría, los sumideros intermedios también podrían usarse, y todos reciben descripciones que indican la cantidad de retraso que resultaría de conectarse a ellos. Es importante que Delay1 siempre sea el receptor a usar porque (al menos para mí en XFCE) el sistema "recuerda" a qué receptor estaba conectado un programa. Un programa que esté conectado al receptor Delay1 volverá a él incluso si la cadena ha estado inexistente por un tiempo (durante el cual el programa estará conectado al dispositivo de salida predeterminado). Entonces puedo llamarpa-retrasotantas veces como sea necesario para ajustar la duración del retraso y, sin más intervención, cualquier programa que utilice el retraso utilizará la nueva cadena establecida en cada ejecución. Esto también se aplica después de haber llamadopa-retraso 0tener audio sin retrasos durante más tiempo. Encuentro que después de suspender mi computadora, la demora tiende a ser mayor de lo especificado (lo cual está en línea con eladvertenciaque ellatencia_msecEl parámetro para el módulo loopback es "solo una solicitud amigable"), por lo que también cambio al estado "pa-delay 0" antes de suspender.

#! /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

información relacionada