pulseaudio: 시간만큼 앱의 출력을 지연시킵니다.

pulseaudio: 시간만큼 앱의 출력을 지연시킵니다.

오디오가 비디오보다 앞서는 앱이 하나 있어서 오디오를 0.5초 동안 지연시키고 싶습니다. 현재 앱의 오디오를 pulseaudio null 모듈로 리디렉션한 다음 parec을 사용하여 모니터 출력을 외부 버퍼링 프로그램으로 보낸 다음 0.5초 후에 데이터를 다시 펄스로 출력합니다. pulseaudio 내에서 이 작업을 수행하는 더 쉬운 방법이 있습니까?

답변1

그만큼루프백 모듈소스와 싱크 사이에 최대 2초의 지연을 추가할 수 있습니다.

답변2

내 bash 스크립트("라고 함)를 공유하고 싶습니다.PA 지연”) 이미 언급한 루프백 및 널 싱크 모듈을 사용합니다.이그나시오 바스케스-아브람스임의 길이의 가상 싱크 및 루프백 체인을 설정합니다. 나는 이 스크립트를 적극적으로 사용하고 있습니다. 싱크는 Delay1, Delay2, … Delay라고 합니다.N스크립트는 먼저 해당 이름의 모든 싱크와 이전 실행에서 생성되었을 수 있는 이러한 싱크를 사용하는 모든 루프백을 언로드합니다. 그런 다음 요청된 지연에 필요한 길이로 체인을 구축합니다. 지연 시간은 명령줄 매개변수로 밀리초 단위로 지정됩니다. (지연이 0이면 스크립트가 이전 체인을 제거한 다음 종료됩니다.) 첫 번째 가상 싱크인 Delay1은 항상 전체 지연을 얻기 위해 연결되는 싱크입니다. 중간 싱크도 이론적으로 사용할 수 있으며, 여기에 연결하면 발생하는 지연 정도를 나타내는 설명이 모두 제공됩니다. (적어도 XFCE에서는) 시스템이 프로그램이 연결된 싱크를 "기억"하기 때문에 Delay1이 항상 사용할 싱크라는 것이 중요합니다. 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

관련 정보