Pulseaudio
是否可以在不編寫腳本的情況下設置動態變化的首選揚聲器順序?
我有一台筆記型電腦,它有自己的揚聲器。然後我有一台顯示器(DP 通過 USB-C,立體聲 2.0),它有更好的揚聲器,我更喜歡在連接時使用。我還有一個攜帶式揚聲器(藍牙、3.5 插孔和微型 USB 連接、立體聲),我在烹飪時觀看/收聽影片時使用。我有時也會通過 HDMI 將筆記型電腦連接到家庭影院到 AVR (5.1)。所有這些都是動態變化的,可能會同時連接三個或四個。
我想像這樣設置設備的優先級:
- AVR
- 攜帶式揚聲器
- 監視器
- 筆記型電腦
這樣當我更改配置時它們會神奇地自動選擇(每天可能發生幾次)
現在,PulseAudio 試圖挑選最好的,有時會成功,有時不會。
- 如果我的Google搜尋是正確的,我無法通過配置文件或某些 GUI 設置預設值,我需要編寫一個腳本。我對此感到有些驚訝——我認為這一定是一個常見的案例。所以我在嘗試編寫這樣的腳本之前詢問我的研究是否有誤(或者如果有人有這樣的腳本,請隨時分享,我發現的唯一內容是:https ://askubuntu.com/ questions/263248/set-hdmi-sound-output-automatically-on-connect-disconnect - 這不像我的設置那麼複雜)
- 令我困惑的另一件事是,在 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_toggle
jsut 是一個包裝腳本,用於處理在 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/藍牙設備。