Baştan Beri Çalışan Ses Tuşları: Bir Sway Hata Ayıklama Polisiyesi

Sway · Dell XPS 13 · Fedora 43

Baştan Beri Çalışan Ses Tuşları: Bir Sway Hata Ayıklama Polisiyesi

Ses tuşlarım “çalışmayı bıraktı” — ve bozuk olmayan tek şeyin tuşlar olduğu ortaya çıktı.

XF86AudioRaiseVolume · bas → hiçbir şey · ne ses ne çubuk

Kara ekran yazısının destanın sonu olduğunu sanmıştım. Meğer bir hobinin başlangıcıymış.

Birkaç gün önce, Dell XPS 13’ümde kara bir ekranı gerçekten sevdiğim bir Sway masaüstüne nasıl çevirdiğimi yazmıştım. Bu, bir sonraki bölüm ve sürekli yeniden öğrendiğim bir kıssası var: Linux’ta bir denetim “hiçbir şey yapmıyorsa”, bastığın şey nadiren bozuk olan şeydir.


00Günlük · Şikâyet

Şikâyet

Belirti · ne ses ne çubuk

Ses tuşlarım çalışmayı bıraktı. Her iki türü de: gövdenin yanındaki fiziksel tuş ve klavyedeki Fn tuşları. Basıyorsun ve… hiçbir şey. Ne ses değişiyor ne de ekranda bir çubuk. İki yolda da aynı ölü sessizlik.

Acı ironi — ki bunu sonradan fark ettim — bunun, geçen yazıda evcilleştirmekle övündüğüm tam o ses bağlaması olması. “İhtiyacım olduğunu bilmediğim emniyet kemeri” dediğim şu satırı hatırlıyor musun?

~/.config/sway/config
bindsym XF86AudioRaiseVolume exec wpctl set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 5%+

O emniyet kemeri hâlâ takılıydı. Sadece araba artık yola bağlı değildi. Bunu aklında tut.

01Günlük · İkiye bölme

1. Adım: tuşlar Sway’e ulaşıyor mu ki?

İkiye bölme · tuş vuruşu vardı mı?

İlk içgüdüm, geçen seferki gibi, “bir kısayolu bozdum” oldu. Ama bir şeyi parçalamadan önce, tüm sorunu ikiye bölen 30 saniyelik bir test var: bağlamanın kendini duyurmasını sağla. Gerçek komutun yanına her ses tuşuna bir günlük satırı ekledim:

~/.config/sway/config
bindsym XF86AudioRaiseVolume exec echo "$(date +%T) raise" >> /tmp/volkeys.log; wpctl set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 5%+
bindsym XF86AudioLowerVolume exec echo "$(date +%T) lower" >> /tmp/volkeys.log; wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindsym XF86AudioMute        exec echo "$(date +%T) mute"  >> /tmp/volkeys.log; wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle

Sonra swaymsg reload, tuşlara bas ve bak:

shell
cat /tmp/volkeys.log
/tmp/volkeys.log
13:56:45 raise
13:56:46 lower
13:56:53 mute

Günlük doluydu. Her basış — hem gövde tuşu hem klavye — Sway’e ulaştı ve bağlamasını kusursuz tetikledi. (Eğlenceli ayrıntı: gövdedeki tuş, Sway’e klavyeden ayrı bir Intel HID 5 button array aygıtı olarak görünüyor. İkisi de çalıştı.)

Demek tuşlar masumdu. Sorun her ne ise tamamen tuş vuruşunun ardında yaşıyordu. Tıpkı geçen seferki kara çalışma alanı gibi, ilk şüphelim kusursuz davranan parçaydı.

02Günlük · Teşhis

2. Adım: komut boşluğa bağırıyordu

Teşhis · iki ses sunucusu

Bağlama, PipeWire’ı denetleyen wpctl’yi çalıştırıyordu. Ben de atladığım o bariz soruyu sordum: hoparlörlerimi şu an gerçekte ne sürüyor?

shell
pactl info | grep -i "server name"
# Server Name: pulseaudio

İşte oradaydı. Sade, bağımsız PulseAudio ses donanımının sahibiydi — ama tuşlarım nazikçe PipeWire’dan sesi değiştirmesini istiyordu. İkisi de kurulu ve aynı anda çalışıyordu:

shell
pgrep -a pulseaudio   # the real PulseAudio — holding the speakers hostage
pgrep -a pipewire     # also running
pgrep -a wireplumber  # also running

Her basış kimsenin duyamadığı bir PipeWire çıkışını değiştiriyordu, PulseAudio ise sessizce gerçek çıkışı tutuyordu. Geçen yazıdaki emniyet kemeri bağlaması kusursuzdu; tekerleksiz bir arabaya bağlanmıştı. Birkaç gün önce harika çalışan aynı satırın şimdi hiçbir şey yapmamasının nedeni buydu — iki yazı arasında bir yerde, gerçek pulseaudio paketi geri sızmış ve donanımı PipeWire’ın elinden çalmıştı.

Bu tam da geçen sefer geçmişteki bana karşı uyardığım türden sessiz bir X11/Wayland kalıntısı, sadece ses kılığına girmiş.

Birkaç gün önce harika çalışan aynı satır şimdi hiçbir şey yapmıyordu — tekerleksiz bir arabaya bağlanmış emniyet kemeri.

03Günlük · Çözüm 1/2

Çözüm, 1. kısım: iki değil, tek yığın

Çözüm · bağımsız PulseAudio’yu çıkar

Fedora’nın amaçladığı kurulum baştan aşağı PipeWire’dır; pipewire-pulseaudio, PulseAudio API’sini bir ara katman olarak sağlar. Ben de gerçek arka plan servisini tahliye ettim:

shell
sudo dnf swap --allowerasing pulseaudio pipewire-pulseaudio
systemctl --user enable --now pipewire-pulse.socket pipewire-pulse.service

Bir tuzak hemen ısırdı: takastan hemen sonra pactl, Connection refused ile başarısız oldu, çünkü pipewire-pulse kuruluydu ama henüz çalışmıyordu. systemctl --user enable --now satırı onu uyandıran şey. Görmek istediğin sunucu adıyla doğrula:

shell
pactl info | grep -i "server name"
# Server Name: PulseAudio (on PipeWire 1.4.11)

O (on PipeWire) ifadesi bütün mesele: tek yığın, donanım için halat çekişmesi yok. Artık wpctl ve tuşlarım gerçek sesi yönetiyor.

04Günlük · Çözüm 2/2

Çözüm, 2. kısım: görmek için bir çubuk

Kurulum · wob ile ekranda bir çubuk

Şikâyetimin diğer yarısı, bir ses göstergesini hiç görmememdi. Bu bir hata değil — Sway’in yerleşik bir OSD’si yok. (waybar’ım bir ses sayısı gösteriyor ama ben tuşa basınca beliren o büyük kayan çubuğu istiyordum.)

Bunun için başvurulan araç swayosd ama Fedora 43 için paketlenmemiş. Depolarda olan şey wob — sevimli derecede küçük, içine aktardığın sayılardan bir çubuk çizen bir “Wayland Overlay Bar”.

shell
sudo dnf install -y wob

wob, stdin’den satır başına bir tam sayı (0–100) okur. Geleneksel kurgu, takip ettiği bir FIFO’dur. Sway yapılandırmamda:

~/.config/sway/config
exec rm -f $XDG_RUNTIME_DIR/wob.sock && mkfifo $XDG_RUNTIME_DIR/wob.sock && tail -f $XDG_RUNTIME_DIR/wob.sock | wob

Sonra küçük bir sarmalayıcı sesi değiştiriyor ve yeni seviyeyi FIFO’ya yazıyor. Benimki ~/.config/sway/volume-wob.sh’de duruyor:

~/.config/sway/volume-wob.sh
#!/bin/sh
# Adjust the default sink via wpctl (PipeWire-native) and push the resulting
# level (0-100) to the wob FIFO so Sway shows an on-screen bar.
export LC_ALL=C

WOBSOCK="${XDG_RUNTIME_DIR}/wob.sock"
SINK="@DEFAULT_AUDIO_SINK@"

case "$1" in
	up)   wpctl set-mute "$SINK" 0; wpctl set-volume -l 1.0 "$SINK" 5%+ ;;
	down) wpctl set-mute "$SINK" 0; wpctl set-volume "$SINK" 5%- ;;
	mute) wpctl set-mute "$SINK" toggle ;;
esac

vol=$(wpctl get-volume "$SINK" 2>/dev/null)   # e.g. "Volume: 0.10" or "... [MUTED]"
case "$vol" in
	*MUTED*) level=0 ;;
	*)       level=$(printf '%s' "$vol" | awk '{printf "%d", $2 * 100}') ;;
esac

[ -z "$level" ] && level=0
[ "$level" -gt 100 ] && level=100

# timeout guards against a dead wob reader hanging the keypress (see gotcha #3)
[ -p "$WOBSOCK" ] && timeout 1 sh -c "printf '%s\n' '$level' > '$WOBSOCK'"

Ve bağlamalar, nihayet işe yarar bir yeri gösteriyor — dikkat et, geçen yazının -l 1.0 emniyet kemeri tam ait olduğu yerde duruyor:

~/.config/sway/config
bindsym XF86AudioRaiseVolume exec ~/.config/sway/volume-wob.sh up
bindsym XF86AudioLowerVolume exec ~/.config/sway/volume-wob.sh down
bindsym XF86AudioMute        exec ~/.config/sway/volume-wob.sh mute
bindsym XF86AudioMicMute     exec wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle

Şimdi bir tuşa bas, ekranda çubuk yukarı kayarken ses de gerçekten değişiyor. Şikâyetin iki yarısı da yok oldu.

Tuşa basınca ekranda yukarı kayan wob ses çubuğu
Tuşa basınca ekranda yukarı kayan wob ses çubuğu
05Günlük · Tuzaklar

Kan akıtan üç tuzak

Tuzaklar · kan akıtan üçü

Geçen sefer %3359 ses ve tam ekran bir video köprüsüydü. Bu sefer:

  1. wob tek bir bozuk satırla ölür. Ona tek bir boş dizge ver — diyelim ses ayrıştırman sessizce başarısız oldu — Invalid value received yazıp çıkar. Bu yüzden betik seviyeyi her zaman bir sayıya varsayıyor ve sınırlıyor. wob’a asla boş satır aktarma.
  2. Yöreselleştirmem beni susturmaya çalıştı. wpctl, 0.10 yazdırır. Almanca yöremde awk, virgülü ondalık ayıracı sanıp 0.10’u düz bir 0’a çevirir. Betikte LC_ALL=C zorlamak ondalığı dürüst tutar. (Durum barına inan; yöreselleştirmene güvenme.)
  3. Okuyucusu olmayan bir FIFO’ya yazmak sonsuza dek askıda kalır. wob çalışmıyorsa, printf > fifo bloklanır — ve tuş vuruşunu da yanında götürür. Yazımı timeout 1 ile sarmak, ölü bir çubuğun ses tuşlarını donduramayacağı anlamına gelir.

Bir de Sway’e özgü dipnot: exec, swaymsg reload’da değil, girişte çalışır. Yani FIFO-ve-wob satırı bir yeniden yüklemede yeniden başlamaz; çubuk oturum ortasında kaybolursa çıkış yapıp tekrar gir.

Durum barına inan; yöreselleştirmene güvenme.

06Günlük · Yan görev

Yan görev: prize takılıyken beni kilitleme

Yan görev · sadece pilde kilitle

Hazır buradayken bir sıkıntı daha: masamda, prize takılıyken, ekran beş dakika sonra beni dışarı kilitleyip duruyordu — diğer ekranda bir şey okumak için her dönüşümde bir parola istemi. Bu, swayidle’ın ona söylediğimi yapması:

~/.config/sway/config
exec swayidle -w \
    timeout 300 'swaylock -f -c 000000' \
    timeout 600 'swaymsg "output * power off"' resume 'swaymsg "output * power on"' \
    before-sleep 'swaylock -f -c 000000'

Beş dakikada kilitle, onda arka ışığı söndür. Arka ışığın sönmesi sorun değil — bir fare oynatması paneli geri getiriyor, parola yok. Şarjdayken gevşetmek istediğim şey kilit: onuncu dakikada arka ışık yine sönsün ama prizdeyken tam bir saat geçene dek kilitleme. Pilde beş dakikalık kilit kalsın — hızlı kilitlenmesini tam da o zaman istersin.

swayidle şarj aletini göremez, bu yüzden güç denetiminin komutun içinde yaşaması gerek. Erken kilidi küçük bir betiğin arkasına aldım ve saat işaretine ikinci, koşulsuz bir kilit ekledim:

~/.config/sway/config
exec swayidle -w \
    timeout 300 "$HOME/.config/sway/lock-idle.sh" \
    timeout 600 'swaymsg "output * power off"' resume 'swaymsg "output * power on"' \
    timeout 3600 'swaylock -f -c 000000' \
    before-sleep 'swaylock -f -c 000000'

lock-idle.sh yalnızca pilde kilitler; prizde çekilip 60 dakikalık zaman aşımına bırakır. Çekirdeğin güncel tuttuğu tek bir dosyayı okuyan beş satır — şarj aleti takılıyken /sys/class/power_supply/AC/online değeri 1’dir:

~/.config/sway/lock-idle.sh
#!/bin/sh
# Called by swayidle at the short (5 min) timeout. On AC, skip locking and let
# the 60-min timeout lock instead (the backlight still powers off at 10 min).
# On battery, lock right away.
for ac in /sys/class/power_supply/A{C,DP}*/online; do
    [ -r "$ac" ] && [ "$(cat "$ac")" = "1" ] && exit 0   # on AC: don't lock yet
done
swaylock -f -c 000000

İki not: A{C,DP}* glob’u, bağdaştırıcıyı AC yerine ADP1 diye adlandıran dizüstüleri kapsar; arka ışık satırı da eski dpms off değil, output * power off (Sway 1.11). Ses çubuğuyla aynı giriş-değil-yeniden-yükleme uyarısı geçerli — swayidle, swaymsg reload’da yeniden başlamaz, o yüzden pkill swayidle yapıp yeniden başlat.

07Saha notları

Geçmişteki bana söyleyeceklerim (ses sürümü)

  1. Ölü bir denetim genelde bir tuş sorunu değil, bir yönlendirme sorunudur. Bir günlükleme bağlaması (echo >> dosya) otuz saniye sürer ve tuş vuruşunun gelip gelmediğini anında söyler. Benimki hep geldi.
  2. Kısayola dokunmadan önce donanımın sahibini sor. Önce çalıştırsaydım pactl info bunu tek satırda bitirirdi. İki ses sunucusu, tek takım hoparlör — sadece biri kazanır ve o, tuşlarımın konuştuğu değildi.
  3. Dün çalışan bir bağlama bir yazım hatasıyla değil, bir paketle sabote edilebilir. Satır geçen haftakiyle aynıydı. Altındaki yığın değildi.
  4. Depolarında var olan araçları seç. swayosd hoş ama Fedora 43’te hiç yok; wob mütevazı ve tam orada. Mütevazı-ve-mevcut, zarif-ve-hayalî olana üstün gelir.
  5. swayidle dünyayı göremez; ona görebilen bir betik ver. Koşullu olan her şey — güç durumu, günün saati — swayidle’ın kendisinde değil, çalıştırdığı komutta yaşar. Çekirdek şarj durumunu zaten tek satırlık bir dosyada veriyor; bırak beş satırlık bir hakem okusun ve karar versin.

Kara ekran yazısı bana sistemin en sakin görünen parçasının çoğu zaman suçlu olan olduğunu öğretmişti. Ses tuşları bunu yine kanıtladı — ben neredeyse onları baştan yazarken onlar orada kusursuz çalışıyordu; tıpkı kara bir dikdörtgenin altına saklanmış o kusursuz, sadık foot terminali gibi. Sanırım Sway çalıştırmanın bütün karakteri bu: hiçbir şey senin için bir şey yapmaz, dolayısıyla bir şey aksadığında çözüm hep gerçek, hep anlaşılır ve neredeyse hiçbir zaman ilk parmağını uzattığın yerde değildir.

08Sonsöz

Temizliğim bile bana direndi

Sonsöz · kendini vuran komut

Son bir kahkaha. Başıboş test süreçlerini toparlarken, eski çubuğu öldürmek için o bariz tek satırlığa uzandım:

shell
pkill -f 'tail -f .*wob.sock'

…ve kabuğum komutun ortasında öldü. İki kez. Görmem utanç verici derecede uzun sürdü: pkill -f, her sürecin tüm komut satırına karşı eşleşir — pkill’imi çalıştıran kabuğun kendisi dâhil; onun komut satırı da harfiyen tail -f .*wob.sock dizgesini içeriyordu. Kendini avlayıp vuran bir komut yazmıştım. Sway yolculuğu, anlaşılan, fraktal: temizliğin bile içinde bekleyen bir kara-çalışma-alanı anı var.

Yorumlar (0)

Henüz yorum yok. İlk yorumu sen yap!

Yorum Yaz