Ustaw wyjście dźwięku HDMI automatycznie po podłączeniu / odłączeniu

20

Mam konfigurację podwójnego ekranu na moim laptopie (używając 12.04 LTS) za pomocą wyświetlacza podłączonego przez HDMI. Wszystko działa dobrze, ale za każdym razem, gdy podłączam / odłączam kabel, muszę przejść do Preferencji dźwięku i ręcznie zmienić urządzenie wyjściowe dźwięku.

Czy jest jakiś sposób na zmianę urządzenia wyjściowego dźwięku po podłączeniu / odłączeniu kabla, więc kiedy podłączam mój wyświetlacz, wyjście dźwięku jest ustawione na HDMI, a kiedy go odłączam, dźwięk wraca do głośników laptopa?

Salem
źródło
Mam ten sam problem.
ThiagoPonte,
Po raz pierwszy przyjechałem tu po pomoc w tej sprawie ... Jestem na tej samej łodzi 12.10. To irytujące. Z mojego doświadczenia wynika, że ​​tak jest od 10.10. Musi być gdzieś konfiguracja, która sobie z tym poradzi. EDYCJA: voices.canonical.com/david.henningsson/2012/04/14/... Tak właśnie zostało to ustawione celowo. To okropne.
user138216,
Sprawdź, czy moja odpowiedź działa z tobą.
Salem,

Odpowiedzi:

11

Z korzyścią dla ludzi, którzy natkną się na to pytanie - rozwiązanie Salem prawie dla mnie zadziałało w 13.04, skończyło się na zbieraniu kawałków z całej sieci, myślę, że przełomem dla mnie był brak zmiennej środowiskowej PULSE_SERVER

Oto moje pełne rozwiązanie, które w zasadzie powtarza rozwiązanie Salema z kilkoma brakującymi elementami. Zredagowałem go również jako skrypt powłoki (pomimo mojej miłości do Pythona), ponieważ początkowo obawiałem się, że mój skrypt w Pythonie ma problemy ze ścieżką importu:


(to samo co odpowiedź Salema) Utwórz plik /etc/udev/rules.d/hdmi_sound.rulesjako root z zawartością:

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

Utwórz plik /usr/local/bin/hdmi_sound_togglejako root z zawartością:

#!/bin/sh
USER_NAME=`who | grep "(:0)" | cut -f 1 -d ' '`
USER_ID=`id -u $USER_NAME`
HDMI_STATUS=`cat /sys/class/drm/card0/*HDMI*/status`

export PULSE_SERVER="unix:/run/user/"$USER_ID"/pulse/native"

if [ $HDMI_STATUS = "connected" ]
then
    sudo -u $USER_NAME pactl --server $PULSE_SERVER set-card-profile 0 output:hdmi-stereo+input:analog-stereo
else
    sudo -u $USER_NAME pactl --server $PULSE_SERVER set-card-profile 0 output:analog-stereo+input:analog-stereo
fi

Następnie uczyń go wykonywalnym za pomocą chmod 0755 /usr/local/bin/hdmi_sound_toggle

Próbowałem uczynić ten skrypt tak ogólnym, jak to możliwe, ale nadal może być konieczna zmiana niektórych wierszy, takich jak ścieżka pliku HDMI_STATUS lub użyte profile. Możesz zobaczyć listę profili, uruchamiając pactl list cardsi przeglądając profile.

Zauważ, że skrypt nie powiódł się, gdy usunąłem słowo kluczowe „eksport” podczas ustawiania PULSE_SERVER, myślę, że pactl szuka zmiennej env

Nie zapomnij załadować ponownie reguł udev: sudo udevadm control --reload-rules

Zaktualizuj ten skrypt został zaktualizowany do wersji 14.04. Wcześniej wszędzie używałbyś USER_NAME zamiast USER_ID

Daniel
źródło
1
Pamiętaj, że muszę dołączyć | uniqdo polecenia USER_NAME. Pamiętaj również, że ustawienia dźwięków w Ubuntu mogą wprowadzać w błąd. Nie widziałem zmian w panelu ustawień dźwięku, ale gdy coś odtwarzałem, dźwięk przełączał się płynnie tam iz powrotem. Zauważyłem też, że po kilkukrotnym podłączeniu i odłączeniu HDMI skrypt przestał działać (może trochę rodzaj błędu w udev).
FuegoFro,
1
Dodałem | sort -udo nazwy użytkownika, ponieważ mówiono o dodatkowej opcji elemer elemer --- Moja nazwa użytkownika. To samo co rozwiązanie FuegoFro na koniec dnia.
elemer82,
Użyłem | grep -v pts, ponieważ faktycznie mam tam również użytkownika root, ponieważ edytowałem skrypt za pomocą Kate, która miała otwarty terminal root.
Auspex,
Ciągle pojawia się komunikat „Błąd połączenia: połączenie odrzucone pa_context_connect () nie powiodło się: połączenie odrzucone” podczas uruchamiania pactl. : \
Tomislav Nakic-Alfirevic
7

W końcu udało mi się sprawić, by ta praca działała udev. Jeśli więc ktoś chce mieć takie samo zachowanie, wykonaj następujące czynności:

Najpierw musimy utworzyć plik /etc/udev/rules.d/hdmi_sound.ruleso następującej treści:

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

Spowoduje to udevwykonanie skryptu za hdmi_sound_togglekażdym razem, gdy nastąpi zmiana połączenia HDMI. Ten skrypt musi mieć uprawnienia do wykonywania, a jego zawartość jest następująca:

#!/usr/bin/env python

import subprocess
from syslog import syslog

def output(cmd):
    return subprocess.check_output(cmd, shell=True)

# the following variables may need some modification.
user = "my_username"
card = "/sys/class/drm/card0"
dev_speaker = "output:analog-stereo+input:analog-stereo"
dev_hdmi = "output:hdmi-stereo+input:analog-stereo"
#

interfaces = output("ls {0}".format(card), ).split("\n")

vga = filter(lambda x: "VGA" in x, interfaces)[0]
hdmi = filter(lambda x: "HDMI" in x, interfaces)[0]

syslog("HDMI connection was changed!")

hdmi_connected = output("cat {0}/{1}/status".format(card,hdmi)).startswith("connected")
title = "HDMI was {0}".format("connected" if hdmi_connected else "disconnected")
message = "Audio output has changed to {opt}.".format(opt = "HDMI" if hdmi_connected else "built-in speakers")

cmd = "sudo -u " + user + " /usr/bin/pactl set-card-profile 0 " + (dev_hdmi if hdmi_connected else dev_speaker)

syslog("HDMI was connected." if hdmi_connected else "HDMI was disconnected.")
try:
    a = output(cmd)
    output("sudo -u {0} notify-send \"{1}\" \"{2}\"".format(user, title, message))
    syslog("Audio output changed.")
except Exception as ex:
    syslog("Error changing output device: " + str(ex))

Prawdopodobnie można to łatwo zrobić w bash, ale ponieważ moim głównym językiem jest python, użyłem go. Wszystko działa oprócz powiadomienia: nie pokazuje się, naprawdę nie wiem dlaczego. Jeśli ktoś wie, jak to naprawić, proszę coś powiedzieć.

Uwaga: nazwy reguły skryptu / udev można zmienić, ale musisz użyć pełnej ścieżki.

Salem
źródło
3

Na podstawie Salem „s odpowiedź i Daniel odpowiedź” s

Wziąłem odpowiedź Salema i Daniela i wprowadziłem niezbędne zmiany, ich rozwiązanie nie zadziałało dla mnie po wyjęciu z pudełka:

(podobnie jak odpowiedź Salema).

Utwórz plik /etc/udev/rules.d/hdmi_sound.rulesjako root z zawartością:

SUBSYSTEM=="drm", RUN+="/usr/local/bin/hdmi_sound_toggle"

Uwaga ACTION=="change", brakuje!

Utwórz plik /usr/local/bin/hdmi_sound_togglejako root z zawartością:

#!/bin/sh
USER_NAME=`who | grep "(:0)" | cut -f 1 -d ' '| sort -u`
USER_ID=`id -u $USER_NAME`
HDMI_STATUS=`cat /sys/class/drm/card0/*HDMI*/status`

export PULSE_SERVER="unix:/run/user/"$USER_ID"/pulse/native"

if [ $HDMI_STATUS = "connected" ]
then
    sudo -u $USER_NAME pactl --server $PULSE_SERVER set-card-profile 0 output:hdmi-stereo+input:analog-stereo
else
    sudo -u $USER_NAME pactl --server $PULSE_SERVER set-card-profile 0 output:analog-stereo+input:analog-stereo
fi

Uwaga USER_NAME =who | grep "(:0)" | cut -f 1 -d ' '| sort -u Dodałem,| sort -uponieważ w przeciwnym razie wrócił zelemer elemer elemer3 - moją nazwą użytkownika.

Następnie uczyń go wykonywalnym za pomocą chmod 0755 /usr/local/bin/hdmi_sound_toggle

Nie zapomnij załadować ponownie reguł udev: sudo udevadm control --reload-rules

Ważne: ten skrypt został zaktualizowany do wersji 14.04. Wcześniej wszędzie używałbyś USER_NAME zamiast USER_ID

Kredyty: Salem i Daniel .

elemer82
źródło
1

Ubuntu 16.04 - 17.04 Odpowiedź

Działa to w systemie Ubuntu 16.04 - 17.04, który wprowadził błąd w Pulse Audio 8. Utwórz plik hotplugtv(lub hotplug-hdmijeśli wolisz) i skopiuj w następujących wierszach:

#!/bin/bash

# NAME: hotplugtv
# PATH: /home/$USER/bin
# DESC: Update pulseaudio output device when HDMI TV plugged / unplugged
# CALL: called from /etc/udev/rules.d/99-hotplugtv.rules 
#       and /home/$USER/bin/lock-screen-timer
# 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.
#       Dec 21, 2016 - Relocated to /home/$USER/bin for calling by lock-screen-timer
#       Aug 06, 2017 - Convert from home grown log-file to universal logger command.

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

exit 0

WAŻNE: zmień nazwę użytkownika „rick” na swoją nazwę użytkownika.

Aby wywołać ten skrypt z udevwydarzeń typu hot-plug, utwórz plik /etc/udev/rules.d/99-hotplugtv.ruleszawierający:

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

Przejdź /home/rick/bin/do ścieżki, w której umieściłeś hotplugtvskrypt.

WinEunuuchs2Unix
źródło
Dziękuję bardzo! Działa również na Ubuntu 17.04! To mnie denerwowało od dłuższego czasu i to było proste rozwiązanie :)
Georgi Koemdzhiev
1
Proszę bardzo Dziękujemy za komentarz potwierdzający, że jest on również potrzebny do 17.04.
WinEunuuchs2Unix,