自动在内置扬声器和 HDMI 扬声器之间切换

自动在内置扬声器和 HDMI 扬声器之间切换

您知道当您将耳机插入笔记本电脑的辅助插孔时,内置扬声器会自动静音,声音会从耳机中传出吗?我希望 HDMI 也能实现这一点。

我有时会将带有内置扬声器的显示器连接到笔记本电脑来观看视频。当视频显示在显示器上(显示器距离我的桌子 3 米)但声音却从笔记本电脑的内置扬声器发出(笔记本电脑放在桌子上)时,情况非常奇怪。

当然,我可以进入声音设置并将输出通道切换为 HDMI。但是,后来,当我几个小时前拔下 HDMI 电缆,甚至可能在完全不同的位置时,声音不会播放,因为声音服务器仍尝试通过 HDMI 播放,但没有任何东西连接到它。

当没有设备通过 HDMI 连接时自动切换回内置扬声器更为重要,但当设备连接时切换到通过 HDMI 的声音输出仍然非常好。

这显然适用于 11.10但它不适用于 16.04。

答案1

背景

我在挂起/恢复期间也遇到过类似的问题,声音会从 HDMI 电视切换到笔记本电脑扬声器。恢复后,声音仍停留在笔记本电脑扬声器上,我必须手动将输出设备重置为电视 - System Settings> Sound

这是我第一次升级时遇到的令人烦恼的经历之一Ubuntu 14.0416.04并且根源是升级到 PulseAudio 8,它自带16.04 LTS

经过大量搜索,我创建了一个名为 的脚本TV-sound。虽然我不会像你一样插拔电视,但我做了一些谷歌搜索,并创建了适用于你的情况的脚本变体。我已经测试过了,它有效。

步骤 1:创建脚本以在连接的设备之间切换音频

我们将创建一个名为hotplugtvudev 调用的脚本。不过,这个脚本可以在很多地方调用。例如,在测试期间,我在lock-screen-timer屏幕锁定期间将声音恢复到笔记本电脑的地方使用了它。

cd /usr/local/bin
sudo touch hotplugtv
sudo chmod +x hotplugtv
gksu gedit hotplugtv

当编辑器打开空白屏幕时,复制并粘贴以下内容:

#! /bin/bash

# NAME: hotplugtv
# PATH: /usr/local/bin
# DESC: Update pulseaudio output device when HDMI TV plugged / unplugged
# CALL: called from /etc/udev/rules.d/99-monitor-hotplug.rules
# DATE: Created Nov 26, 2016.
# NOTE: logs output using log-file
# UPDT: Dec 14, 2016 - Sometimes /sys/class/drm/card0 & sometimes /sys/class/drm/card1
#       so use /sys/class/dmcard* instead.

if [[ $(cat /sys/class/drm/card*-HDMI-A-1/status | grep -Ec "^connected") -eq 1 ]]; then
#        log-file "HDMI TV connected" ~/bin/log-hotplugtv;
        /bin/sleep 2;
        export PULSE_RUNTIME_PATH="/run/user/1000/pulse/";
        sudo -u rick -E pacmd set-card-profile 0 output:hdmi-stereo;
else
#        log-file "HDMI TV disconnected" ~/bin/log-hotplugtv;
        export PULSE_RUNTIME_PATH="/run/user/1000/pulse/";
        sudo -u rick -E pacmd set-card-profile 0 output:analog-stereo;
fi

exit 0

您需要将出现的两次 替换rick为您自己的用户 ID,即UTF-8,等等。

我知道将用户名自动设置为 bash 变量可以更专业,但我还不那么熟练:(无论如何,保存文件并退出gedit

第 2 步:创建 udev 规则

当您插入和拔出 HDMI 显示器时,udev 会监控热插拔事件。输入以下内容以创建新规则。

cd /etc/udev/rules.d
sudo cp 70-persistent-net.rules 99-hotplugtv.rules
gksu gedit 99-hotplugtv.rules

笔记:如果该文件70-persistent-net.rules不存在于您的目录中,请复制任何其他文件。我们不需要文件内容,只需要文件权限来确保我们的权限相同。

编辑器会显示一堆不相关的文本,将其突出显示并删除。然后突出显示下面的代码并将其粘贴到编辑器中:

# NAME: 99-hotplugtv.rules
# PATH: /etc/udev/rules.d
# DESC: Update pulseaudio output device when HDMI TV plugged / unplugged
# CALL: automatically called on system events
# DATE: Created Nov 26, 2016.
# NOTE: in future may requre systemd service hooks

ACTION=="change", SUBSYSTEM=="drm", ENV{HOTPLUG}=="1", RUN+="/usr/local/bin/hotplugtv"

保存文件并退出。

要启用规则(无需重新启动),我们需要重新加载 udev:

sudo udevadm control --reload-rules

现在您可以插入和拔下 HDMI 显示器/电视,并且声音可以正常切换。

警告

在我的系统上,拔掉 HDMI 后,声音会自动恢复到笔记本电脑扬声器。在您的系统上则不会。如果拔掉 HDMI 后,声音不会传到笔记本电脑扬声器,则可能需要进一步增强代码。请通过下面的评论回复事情如何运作/不运作。

在 CLI 中快速测试

您可以使用以下方法在终端快速测试代码:

    export PULSE_RUNTIME_PATH="/run/user/1000/pulse/";
  • 切换到 HDMI/电视:

        sudo -u rick -E pacmd set-card-profile 0 output:hdmi-stereo;
    
  • 切换回内置扬声器:

        sudo -u rick -E pacmd set-card-profile 0 output:analog-stereo;
    
  • 请记住替换rick为您的用户名。

  • 最初的export那行可能不是必需的,但是为了安全起见我还是把它包括在内了。
  • 如果您有多张声卡,或者hdmi-stereo在编写脚本之前显然需要进行调整以外的其他操作来找出正确的参数。

在 PulseAudio 中解密您的设备名称

下面的代码使用了两次相同的命令。第一次是将声音设置为外部 HDMI 电视时。第二次是将声音设置为笔记本电脑的内置扬声器时。每次看到名称 PulseAudio 时都会使用:

$ pacmd list-sinks | grep -e 'name:' -e 'index'
  * index: 28
    name: <alsa_output.pci-0000_00_1b.0.hdmi-stereo>
───────────────────────────────────────────────────────────────────────────────
$ pacmd list-sinks | grep -e 'name:' -e 'index'
  * index: 30
    name: <alsa_output.pci-0000_00_1b.0.analog-stereo>

当您有多个声卡时

使用命令aplay -l查看您是否有大于 0 号的卡。如果是,则需要在脚本中使用适当的卡号。例如:

$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: PCH [HDA Intel PCH], device 0: 92HD91BXX Analog [92HD91BXX Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: PCH [HDA Intel PCH], device 3: HDMI 0 [HDMI 0]
  Subdevices: 0/1
  Subdevice #0: subdevice #0

在上面的例子中,所有卡号均为 0,输出源也不同。如果您有 USB 扬声器,则它们的卡号可以不同于 0。

编辑于 2016 年 12 月 2 日

由于某些未知原因,脚本今天被破坏了。上面的代码以前是这样的:“$(cat /sys/class/drm/card0-HDMI-A-1/status”,但我不得不改成card0这样card1,上面的代码也做了相应的修改。除了 2016 年 11 月 26 日以来的常规 Ubuntu 更新外,我无法解释我的系统上发生了什么变化。

编辑于2016年12月14日

上述代码需要再次切换回:“$(cat /sys/class/drm/card0-HDMI-A-1/status”。无需修改启动之间的代码card0card1依赖于启动,而是修改程序以引用card*来捕获这两种情况。

相关内容