Pulseaudio

是否可以在不編寫腳本的情況下設置動態變化的首選揚聲器順序?

  • January 9, 2022

我有一台筆記型電腦,它有自己的揚聲器。然後我有一台顯示器(DP 通過 USB-C,立體聲 2.0),它有更好的揚聲器,我更喜歡在連接時使用。我還有一個攜帶式揚聲器(藍牙、3.5 插孔和微型 USB 連接、立體聲),我在烹飪時觀看/收聽影片時使用。我有時也會通過 HDMI 將筆記型電腦連接到家庭影院到 AVR (5.1)。所有這些都是動態變化的,可能會同時連接三個或四個。

我想像這樣設置設備的優先級:

  1. AVR
  2. 攜帶式揚聲器
  3. 監視器
  4. 筆記型電腦

這樣當我更改配置時它們會神奇地自動選擇(每天可能發生幾次)

現在,PulseAudio 試圖挑選最好的,有時會成功,有時不會。

  1. 如果我的Google搜尋是正確的,我無法通過配置文件或某些 GUI 設置預設值,我需要編寫一個腳本。我對此感到有些驚訝——我認為這一定是一個常見的案例。所以我在嘗試編寫這樣的腳本之前詢問我的研究是否有誤(或者如果有人有這樣的腳本,請隨時分享,我發現的唯一內容是:https ://askubuntu.com/ questions/263248/set-hdmi-sound-output-automatically-on-connect-disconnect - 這不像我的設置那麼複雜)
  2. 令我困惑的另一件事是,在 Gnome、KDE ​​或 pactl 中的所有工具中,“DELL U4320Q”、“JieLi AC46”等設備的實際名稱都被隱藏了(在 pactl 下的 card>properties>device.product .name) 並且不會在 UI 中公開。這是為什麼?它們肯定會更具人類可讀性。對於顯示器,我通常會得到類似“dmi-output-0:HDMI / DisplayPort”的資訊 - 我應該如何知道我將顯示器連接到哪個埠(哪個埠是 0,哪個是 1)?有什麼理由會這樣嗎?每次我更新我的安裝時,我都很好奇是否有任何改變,但它基本上保持不變。Pipewire 會對此有所幫助嗎?我認為 PulseAudio 應該使這種用法變得簡單:-)。

所以最後我寫了下面的腳本/usr/local/bin/hdmi_sound_toggle.py來為我自動切換。它使用此處提供的腳本:https ://stackoverflow.com/a/24933353/1269040找出連接了哪些監視器。

#!/usr/bin/env python3
import subprocess
# find_monitors is the script from the internet to check EDID data - I put it into $PATH
# the following implements "find_monitors 2>/dev/null | grep '#' 2>/dev/null 1"
# my internal monitor is confusing the script, outputing some weird binary data, so I strip it on the second line
monitors_gibberish = subprocess.check_output(("find_monitors"), shell=True,  stderr=subprocess.DEVNULL)
monitors_one_line = monitors_gibberish.replace(b'# eDP-1-1 HDMI   \xff\xff\xff\xff\xff\xff\r\xae\x0c\x15', b'').decode("UTF-8")
monitors_lines = [i for i in monitors_one_line.split('\n') if i]
default_sink = ''
alsa_card = "pci-0000_01_00.1"
port_number = 0
profile_name = ''
if "H/K AV AMP" in monitors_one_line:
   # AVR is connected through HDMI port and that has always number three, so it has "-extra2" added the profile name
   profile_name = "hdmi-surround-extra2"
elif "DELL U4320Q" in monitors_one_line:
   for i in monitors_lines:
       if "DELL U4320Q" in i:
           # This is being split: '# DP-0 DisplayPort   DELL U4320Q'
           # DP numbering start at 0, HDMI numbering in Pipewire/alsa starts at 1
           port_number = int(i.split(" ")[1].split("-")[1]) + 1
           if port_number == 1:
               profile_name = "hdmi-stereo"
           elif port_number == 2:
               profile_name = "hdmi-stereo-extra1"
# first we need to set default profile for HDMI - it tells Pipewire to which device it should send audio streams over HDMI
if profile_name:
   default_sink = 'alsa_output.' + alsa_card + "." + profile_name
   subprocess.run(["pactl", "set-card-profile", "alsa_card." + alsa_card, "output:" + profile_name])
   # and now we switch the default sink, ie. device that should play all audio by default
   subprocess.run(["pactl", "set-default-sink", default_sink])
~                                                                 

為了自動執行它,我放了這個:

SUBSYSTEM=="drm", ACTION=="change", RUN+="/usr/local/bin/run_hdmi_sound_toggle"

/etc/udev/rules.d/99-hdmi_sound.rules 跑了sudo udevadm control --reload-rules/usr/local/bin/run_hdmi_sound_togglejsut 是一個包裝腳本,用於處理在 root 下執行的 udev 並且無法連接到使用者執行的 Pipewire/PulseAudio:

#!/bin/bash
systemctl --machine=drew@.host --user --now start hdmi_sound_toggle.service

並且相應的 systemd 服務文件~/.config/systemd/user/hdmi_sound_toggle.service是:

[Unit]
Description=Runs /usr/local/bin/hdmi_sound_toggle.py to switch to the correct sound output
 
[Service]
Type=oneshot
ExecStart=/usr/local/bin/hdmi_sound_toggle.py

然後它在 DHMI/USB-C/DP 插拔上執行。

它只對通過 DP 或 HDMI 連接的設備起作用——Pipewire 似乎可以很好地處理 USB/藍牙設備。

引用自:https://unix.stackexchange.com/questions/685071