Lautes Knacken im Kopfhöhrer – ein Workaround

August 4, 2014 um 12:00 pm | Veröffentlicht in Bash, Multimedia, Programmieren, Ubuntuusers | 6 Kommentare
Ich habe mir kurz vor Ostern einen neuen Laptop angeschafft (ein Lenovo Thinkpad E540; mein HP war davor sanft entschlafen). Seit damals habe ich das Problem, dass bei eingestecktem Kopfhörer in unregelmäßigen Abständen ein lautes und sehr unangenehmes Knacken zu hören war. Und das immer direkt bevor eine Audioausgabe gestartet wurde. Sei das nun ein Musikstück in Amarok, ein Video auf YouTube oder ein Snippet zur Bearbeitung in Audacity. Letzteres habe ich besonders in letzter Zeit häufig gemacht und werde ich noch eine Zeit lang tun, wodurch das nervige Problem etwas pressender wurde.
Ich konnte mehrere Faktoren ausschließen. Zum einen bestand das Problem nicht mit meinem Vorgängergerät, was auf ein Problem entweder beim Treiber oder bei der Hardware schließen lässt. Dass ich das Problem sowohl unter Ubuntu 13.10, 14.04, Debian 7 (Sid) und Tanglu Aurora hatte legt ebenfalls diesen Schluss nahe. Auch habe ich mehrere verschiedene Kopfhörer durchprobiert. Manchmal wird ein ein-/ausgestecker Kopfhöhrer gleich, manchmal erst ein paar Sekunden später erkannt. Für mich, als relativer Laie in diesem Gebiet, klingt das wie ein Problem mit der Buchse.
Da ich weder das Wissen, noch das Werkzeug habe um es mir anzusehen oder zu reparieren habe ich mich entschieden einen Workaround zu basteln.

Der Workaround

Mir ist aufgefallen, dass das Knacksen niemals auftritt, wenn irgendein anderes Programm eine Audioausgabe produziert. Die Idee ist also: schreib ein Programm/Skript, welches wenig Ressourcen benötigt, welches eine permanente Audioausgabe macht und welches so unbemerkt wie möglich agiert.
Meine Lösung:
  • Ein Bash-Skript, welches
  • das Programm play aufruft, welches
  • die Datei silence.ogg abspielt, welche 12 Stunden Stille beinhält
Das Programm  play benötigt die Installation des Paketes  sox. Die Datei  silence.ogg habe ich schnell mal in  Audacity kreiert. Sie kommt auf eine Größe von ca. 3,8 MB. Natürlich passt auch jedes andere Format.
Hier ist das Skript:
#!/bin/bash

FILE=silence.ogg
DIR="$HOME/Musik"
if [[ $(ps -ef | grep play | grep "$FILE" -c) -eq 0 ]]; then
    echo "Silencer on"
    play -q "$DIR/$FILE" &
else
    echo "Silencer off"
    pid="$(ps -O command -C play | grep $FILE | tail -
 
shopt -s extglob
    pid=“${pid##*( )}“
    shopt -u extglob
 
    pid=“$(echo „$pid“ | cut -f1 -d‘ ‚)“
    kill "$pid"
fi
Die Zeile
if [[ $(ps -ef | grep play | grep $FILE -c) -eq 0 ]]; then
prüft ob das Skript bereits ausgeführt wird. Dazu holen wir uns mit ps -ef eine Liste aller Prozesse, filtern sie mit grep nach dem String silence.ogg und besorgen uns mit dem Schalter -c die Anzahl der gefundenen Zeilen. Wenn diese 0 ist, dann wird der Prozess noch nicht ausgeführt und wir wollen ihn starten. Nach einer entsprechenden Meldung wird das Programm play mit der gewünschten Datei im Hintergrund (dafür das ‚&‚) gestartet. Der Schalter -q sorgt dafür, dass play selbst keine Ausgabe erzeugt.
Sollte das if nicht zutreffen, also bereits ein Prozess mit dem Skript laufen, begeben wir uns ins else. Hier besorgen wir uns die Programm ID, kurz: pid. In der Zeile
pid=“$(ps -O command -C play | grep $FILE | tail -n1)“
wird dem Programm ps der Schalter -O command übergeben. Damit wird die PID zusammen mit dem jeweiligen Befehl ausgegeben. Die PID steht in der ersten Spalte, kann aber Leerzeichen vorangestellt haben. Mit dem zusätzlichen Schalter -C filtern wir die Liste gleich nach Prozessen des Programmes play. Danach wenden wir grep an um aus den übrig gebliebenen Zeilen die Prozesse zu bekommen, die die Datei silence.ogg verwenden. Da die erste Zeile von ps eine Überschrift ist holen wir uns die Zeile am unteren Ende mittels tail -n1. Sollte es mehrere entsprechende Prozesse geben wird nur der unterste damit gefunden. Man kann natürlich eine Schleife basteln, welche einfach Prozesse beendet, solange es welche gibt. Da sich das Skript aber theoretisch bei jedem zweiten Aufruf selbst beendet, sollte nie mehr als ein Prozess gleichzeitig laufen.
Die Zeile
pid=“${pid##*( )}“
schneidet nun alle vorangestellten Leerzeichen ab. Damit diese Syntax funktioniert haben wir die Shell Option (shopt) Extended Globbing (extglob) aktiviert (-s). Diese ermöglicht der Bash die Verarbeitung von etwas mächtigeren Regulären Ausdrücken. Da wir sie später nicht mehr brauchen, deaktivieren wir sie danach sofort wieder. Nach allem was ich gelesen habe schadet es aber nicht sie in der .bashrc generell zu aktivieren, da sie nur aus Kompatibilitätsgründen deaktiviert ist. Dann kann man diese beiden Zeilen natürlich entfernen.
Mittels dem Befehl cut schneiden wir nun die erste Spalte aus unserer Zeile. Dadurch sollte nun nurmehr die PID übergeblieben sein.
pid=“$(echo „$pid“ | cut -f1 -d‘ ‚)“
Jetzt können wir dem Kommando kill diese pid übergeben und die „Ausgabe“ unserer Stille damit beenden.
Das ist mein Workaround. Für einfachere Ideen oder Vorschläge das Grundproblem anzugehen bin ich jederzeit offen.

=-=-=-=-=
Powered by Blogilo

6 Kommentare »

RSS feed for comments on this post. TrackBack URI

  1. Hört sich nach Problemen beim Autosuspend des Soundchips an. Probier mal die Stromsparfunktion auszuschalten.

  2. Hallo,
    ich hatte so ein Knacken mit Thinkpad auch schon einmal. Nutzt du bereits TLP [1]? Kann ich sehr empfehlen um Stromspareinstellungen vorzunehmen. Könnte hier möglicherweise die Stromsparfunktion des Audiotreibers verantwortlich sein? Diese lässt sich leicht mit TLP deaktivieren [2]. Vielleicht hilft das ja schon.
    Grüße

    [1] http://thinkwiki.de/TLP_-_Linux_Stromsparen
    [2] http://thinkwiki.de/TLP_Einstellungen#Sound

  3. Ich habe das gleiche Problem auf meinem Samsung ATIV Book 8. Bei Netzstrom habe ich nur einen einzelnen Knackton aus den integrierten Lautsprechern beim Hoch/herunterfahren, der mich nicht sonderlich stört. Aber bei Akkubetrieb knackt es jeweils vor und nach jedem einzelnen abgespielten Ton. Wenn ich nebenbei eine silence.ogg im Terminal abspiele, tritt das Problem zwar nicht auf, ich habe jedoch permanent etwas Last auf dem Prozessor, was ich auch nicht hinnehmen will. Es muss irgendeine Stromspareinstellung geben, die das Audio-Device mit jedem abgespielten Ton an- und abschaltet. Still diggin’…

  4. Cooles Skript! Habe persönlich nicht das Problem, aber interessant, wie man sowas lösen kann (mit ps und grep usw.) also besten Dank dafür.

    Ich vermute zu deinem Problem allerdings: Das riecht für mich ganz stark nach Stromsparfunktion des Sound-modules. Zeigt mal bitte die Ausgabe von „lsmod | grep snd“

    Dann schaust du die Module durch und kannst mit modinfo schauen, ob man die Funktion deaktivieren kann, falls es eine Stromsparfunktion gibt.

    Das scheint mir das Knacken zu sein, zumindest bevor etwas abgespielt wird. Und es würde auch erklären, warum das Knacken sonst nicht auftritt, wenn permanent eine Audioausgabe produziert wird.

  5. PS: Bin gerade unter Debian 8 (jessie/testing) unterwegs. Da musste ich vor modinfo allerdings noch ein „sudo“ setzen, sonst kommt, dass er modinfo als Befehl nicht finden könnte.

    also: lsmod | grep snd
    Ausgabe: […] snd 61094 7 snd_hwdep,snd_timer,snd_hda_codec_conexant,snd_pcm,snd_hda_codec_generic,snd_hda_codec,snd_hda_intel […]

    und dann: sudo modinfo snd_hda_intel
    Ausgabe: […]
    parm: power_save:Automatic power-saving timeout (in second, 0 = disable). (xint)
    parm: power_save_controller:Reset controller in power save mode. (bool)
    [… u.v.m.]

    Da wird es bei deinem Soundmodul/treiber, etc. vermutlich eine ähnliche Option geben. Vielleicht auch nicht. Aber um im Beispiel zu bleiben, wenn ich das dann ändern will (obwohl ich kein knacken habe), dann erstelle ich im Verzeichnis /etc/modprobe.d/ die Datei namens „snd-hda-intel.conf“ Darein käme:
    options snd-hda-intel power_save=0

    Das wärs. Zur Sicherheit würde ich das ganze nochmals in /etc/modprobe/alsa-base.conf reinschreiben. bzw. diese Datei dann erstellen, falls nicht da, und den Einzeiler dort rein setzen.

    Viel Erfolg!

    • Danke für die Hilfe! Das Anlegen der .conf Datei hat keine Verbesserung gebracht. Eine Sucher im Ubuntu-Users Wiki hat mich aber auf die Lösung gebracht:

      http://wiki.ubuntuusers.de/Soundkarten_konfigurieren/HDA?redirect=no#Problembehebungen

      > sudo echo 0 | sudo tee /sys/module/snd_hda_intel/parameters/power_save

      Das manuelle Einstellen zur Laufzeit hat funktioniert, vielleucht habe ich bei der .conf Datei etwas flasch gemacht. Da es beim Hoch/herunterfahren immernoch knackt, ist es nur eine partielle Hilfe…


Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

Bloggen auf WordPress.com.
Entries und Kommentare feeds.

%d Bloggern gefällt das: