PipeWire/示例
环绕声系统
分离前/后声道
当使用 PipeWire 作为 PulseAudio/JACK 的替代品时,你可以设置 PipeWire 来复制 Pulseaudio 中分离前/后声道的示例。这样做允许你使用 Pulseaudio 将音频流发送到单独的输出端,用于扬声器或耳机。
将扬声器连接到线路输出端口,耳机连接到后置端口。在 pavucontrol 中,将声卡设置为模拟环绕 4.0 输出。然后使用以下命令,为扬声器和耳机创建新的输出端,将扬声器连接到前置声道,将耳机连接到后置声道
pactl load-module module-null-sink sink_name=speakers object.linger=1 media.class=Audio/Sink channel_map=FL,FR pactl load-module module-null-sink sink_name=headphones object.linger=1 media.class=Audio/Sink channel_map=RL,RR
object.linger=1 使输出端在创建客户端断开连接后仍然保持活动状态。你可以随意命名 sink_name。
要卸载模块,你可以使用 pw-cli destroy ID,其中 ID 是 pactl load-module 命令的输出。目前不支持通过 pactl unload-module 卸载单个模块 [1]。但是,你可以使用它来卸载所有 module-null-sink 模块,方法是使用 pactl unload-module module-null-sink。
使用 jack_connect,将新输出端的监视器连接到声卡的播放端口。通过运行 pw-link -iol[2] 找出声道的名称。
pw-link speakers:monitor_1 alsa_output.pci-0000_00_14.2.analog-surround-40:playback_FL pw-link speakers:monitor_2 alsa_output.pci-0000_00_14.2.analog-surround-40:playback_FR pw-link headphones:monitor_1 alsa_output.pci-0000_00_14.2.analog-surround-40:playback_RL pw-link headphones:monitor_2 alsa_output.pci-0000_00_14.2.analog-surround-40:playback_RR
alsa_output.pci-0000_00_14.2.analog-surround-40 替换为你的声卡名称。在脚本执行前添加延迟也可能使事情运行更顺畅。alsa_output.pci-0000_00_14.2.analog-surround-40:playback_FL 有时会更改为 Built-in\ Audio\ Analog\ Surround\ 4.0:playback_FL。作为快速解决方法,你可以在你的自动启动脚本中添加第二组 pw-jack 命令,使用第二组名称。要单独控制音量,一种选择是使用 alsa 工具(例如 amixer)来控制前置和后置/环绕(alsa 命名)声道。一个根据你当前默认 pulseaudio 输出端自动执行此操作的脚本可以在这里找到。
回声消除
PipeWire 可以实时消除扬声器声音在麦克风中的回声,这使得即使在其他应用程序正在播放音频时,也可以无需使用耳机参加音频聊天。
通常,语音聊天应用程序确实会消除反馈,但它们只知道通过它们的音频。例如,如果另一个语音聊天参与者通过你的扬声器讲话,聊天应用程序“知道”这一点,并能够有选择地从你的麦克风中消除这种噪音,否则这种噪音会作为令人讨厌的回声重复返回到语音聊天中。当其他应用程序正在你的扬声器上播放时,这种方法的问题往往开始出现,因为语音聊天应用程序不知道这些音频,其他参与者可能会听到并抱怨。示例情况:
- 在玩在线视频游戏时使用单独的语音聊天应用程序
- 在使用语音聊天应用程序的同时,使用同步视频播放解决方案,例如 Jellyfin SyncPlay 或 Watch2Gether
这就是系统级回声消除解决的问题;与其让语音聊天应用程序抑制回声——并在上述情况下失败——不如让 PipeWire 来做,它天生“知道”所有在扬声器上播放的音频。
假设 PipeWire 配置为空白,可以通过在 /etc/pipewire/pipewire.conf.d/ 中创建一个世界可读的配置文件来启用系统级回声消除,该文件的名称以“.conf”结尾,例如 60-echo-cancel.conf
“aec.args”的默认值可以在这里找到,只需在“aec-webrtc.cpp”中搜索“webrtc.”。
context.modules = [
# Echo cancellation
{ name = libpipewire-module-echo-cancel
args = {
# Monitor mode: Instead of creating a virtual sink into which all
# applications must play, in PipeWire the echo cancellation module can read
# the audio that should be cancelled directly from the current fallback
# audio output
monitor.mode = true
# The audio source / microphone wherein the echo should be cancelled is not
# specified explicitly; the module follows the fallback audio source setting
source.props = {
# Name and description of the virtual source where you get the audio
# without echoed speaker output
node.name = "source_ec"
node.description = "Echo-cancelled source"
}
aec.args = {
# Settings for the WebRTC echo cancellation engine
webrtc.gain_control = true
webrtc.extended_filter = false
# Other WebRTC echo cancellation settings which may or may not exist
# Documentation for the WebRTC echo cancellation library is difficult
# to find
#webrtc.analog_gain_control = false
#webrtc.digital_gain_control = true
#webrtc.experimental_agc = true
#webrtc.noise_suppression = true
}
}
}
]
诸如此类的配置更改需要 PipeWire 重启(即 pipewire.service 和 pipewire-pulse.service 用户单元)才能生效。
将额外的音频混合到麦克风音频中
上面的回声消除示例可以扩展为提供一个虚拟输出端,将音频复制到你的麦克风中。
它是 PulseAudio/Examples#Mixing additional audio into the microphone's audio 的重新创建,并解决了相同的用例。
为了实现这一点,你还需要加载两个“Combine stream”模块的实例,如下所示。
目前,在每次重启或 PipeWire 重启后,设置需要用户手动操作,例如在 Helvum 中才能完成;请参阅配置示例中的“TODO”注释。
context.modules = [
# (Configuration for system-wide echo cancellation, see above)
# Audio effects sink (stereo)
{ name = libpipewire-module-combine-stream
args = {
combine.mode = sink
node.name = sink_fx
node.description = "Effects sink (play shared audio here)"
combine.props = {
audio.position = [ FL FR ]
}
stream.props = {
# If you have an upmix configuration in client.conf.d, set the same
# parameters here, or else your sound effects application will not
# be upmixed in your local audio output
#channelmix.upmix = true # (...)
# Possible alternative: Poor man's stereo upmix, i.e. mirroring front
# to rear speakers
#combine.audio.position = [ FL FR FL FR ]
#audio.position = [ FL FR RL RR ]
}
}
}
# Main source
# Virtual source that supplies these sources mixed together:
# - source_ec (Echo-cancelled source)
# - sink_fx.monitor (Monitor of the audio effects sink)
{ name = libpipewire-module-combine-stream
args = {
combine.mode = source
node.name = source_main
node.description = "Main source (record from here)"
#combine.latency-compensate = false
combine.props = {
audio.position = [ FL FR ]
}
stream.rules = [
{ matches = [
{
node.name = "source_ec"
media.class = "Audio/Source"
}
]
actions = {
create-stream {
}
}
}
# TODO Block with matches= and actions= that matches the monitor of
# sink_fx and hooks it up to source_main
# No PipeWire configuration known yet that automates this
# See this PipeWire issue for news:
# https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/3710
# For the time being, add the required connections manually in Helvum,
# i.e. connect these points:
# - sink_fx.monitor_FL -> source_main.output.input_FL
# - sink_fx.monitor_FR -> source_main.output.input_FR
]
}
}
]