Seite 1 von 1
Tastendruck unter Linux in CLI-Audioplayer verarbeiten
Verfasst: Dienstag 3. Februar 2009, 13:44
von snafu
Hallo!
Ich möchte in einen sehr minimalistischen Audioplayer, der mir die Ausgabe direkt auf die Kommandozeile gibt, Events für Tastendrucke einbauen. Zunächst einmal nur bei den Tasten Links/Rechts für Vor und Zurück.
Das curses-Modul eignet sich hierfür meiner Meinung nach nicht, weil dabei die eigentliche Kommandozeile verschwindet, was eben nicht passieren soll.
Ich habe daher den Code von
dieser Seite etwas an meine Bedürfnisse angepasst:
Code: Alles auswählen
import termios
import tty
import sys
def getseq():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
seq = sys.stdin.read(3)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return seq
if __name__ == '__main__':
print "Press an 'escape' key to get its sequence..."
print repr(getseq())
Nun stehe ich aber vor einer blöden Denkblockade. Ich muss ja jetzt wahrscheinlich mit Threads arbeiten, was ich bisher noch nie gemacht habe. Mein Player sieht bisher
so aus. Wie verbinde ich nun das Reagieren auf mögliche Tastatureingaben mit dem laufenden Programm? Denn wenn nichts gedrückt wird, sollen die Tracks ja weitergespielt werden. In der bisherigen getseq() wird jedoch gestoppt und darauf gewartet, dass der Benutzer etwas drückt. Ich bräuchte so eine Art Logger, der im Hintergrund aufpasst, ob ein bestimmtes Ereignis angefordert wird, ansonsten aber still ist.
Verfasst: Dienstag 3. Februar 2009, 14:22
von rayo
Wie wärs mit einem Thread der aus die Keypresses wartet und einer Queue um die Keys zum Abspielthread zu transportieren?
Verfasst: Dienstag 3. Februar 2009, 18:51
von veers
Falls du fürs abspielen gstreamer verwendest, das kannst du mit dem gobject mainloop laufen lassen dann brauchst du keine Threads.
- Jonas
Verfasst: Dienstag 3. Februar 2009, 22:42
von snafu
rayo hat geschrieben:Wie wärs mit einem Thread der aus die Keypresses wartet und einer Queue um die Keys zum Abspielthread zu transportieren?
Habe jetzt mal probiert, sowas in der Art zu machen (wie gesagt: erstes Mal) - leider ohne Erfolg.
Der Code:
http://paste.pocoo.org/show/102642/
Zur Erklärung:
Der Player ist jetzt eine Klasse, die von threading.Thread() erbt. Es wird für die Initialisierung eine Playlist übergeben, die in main() den Argumenten von der Kommandozeile entspricht. Die run()-Methode von Thread() habe ich mit der Abarbeitung bzw dem Abspielen der Dateien aus der Playlist überschrieben. run() gibt auch mittels yield den aktuellen Track aus, den main() für den User anzeigt. Das klappt auch alles soweit...
Jetzt dachte ich mir, ich kann aus der Player-Klasse einen Daemon machen, der ja dann eigentlich im Hintergrund laufen müsste. Das klappt aber in einem try-except-Block wohl nicht. Oder liegt es an dem for-Statement wegen dem Iterieren? Oder an beidem? Keine Ahnung...
Auf jeden Fall habe ich den ganzen PLAYING-Kram mal testweise rausgenommen:
Code: Alles auswählen
def main():
playlist = sys.argv[1:]
player = Player(playlist)
player.setDaemon(True)
player.start()
await_user_input()
Nun wird auf einen Tastendruck gewartet, aber keine Musik abgespielt. Sobald ich dann eine Taste drücke, beendet sich das Programm kommentarlos.
Ich bin alles in allem gerade mit meinem Latein am Ende. Wäre nett, wenn sich jemand erbarmen könnte, mir auf die Sprünge zu helfen...
Achso: getkey() unterscheidet jetzt zwischen normalen Zeichen (Buchstabe, Zahl, Bindestrich usw) und besonderen Eingaben wie Richtungstasten, F-Tasten und ähnliches. Diese Sondertasten liefern als erstes Zeichen wohl immer "\x1b" zurück, gefolgt von zwei weiteren Zeichen mit dem eigentlichen Code für die Taste. Zumindest habe ich mir das so erklärt. Es wird also grundsätzlich erstmal ein Zeichen ausgelesen und falls dieses afu so ein Sonderzeichen hindeutet, werden stattdessen die zwei folgenden Zeichen als Rückgabewert genommen.
Verfasst: Dienstag 3. Februar 2009, 22:58
von rayo
Hi
Lass mal setDaemon weg und lass es normal laufen.
Hier mal wie ich es etwa gedacht habe, konnte es aber nicht testen! Ist nur dein Code modifiziert.
Code
Gruss
Verfasst: Dienstag 3. Februar 2009, 23:10
von DasIch
Im Wiki ist ein [wiki=Threading_Beispiel1]Beispiel[/wiki] zu threading, lass es mal laufen, schau dir an wie es funktioniert und spiel mal etwas mit rum. Auf die Weise sollte der Aha-Moment schnell eintreten.
Solange du die elementaren Dinge davon nicht verstanden hast wirst du auch dass hier nicht hinbekommen.
Verfasst: Mittwoch 4. Februar 2009, 13:07
von snafu
Verfasst: Donnerstag 5. Februar 2009, 11:03
von snafu
Doch noch ein Problem. Ich will das komplette Programm beenden, wenn kein Track mehr da ist. Also entweder weil der letzte durchgelaufen ist oder weil man eins weiter wollte und das Ende der Tracklist erreicht wurde.
Dummerweise wartet ja jetzt await_user_input() die ganze Zeit auf Eingaben und kommt nur aus seiner Endlosschleife, wenn die Leertaste gedrückt wird.
Ich habe es auch schon - IMHO eher unschön - mit exit() in der Player-Klasse probiert. Aber dann erhalte ich am Ende der Tracklist:
Code: Alles auswählen
Traceback (most recent call last):
File "player.py", line 92, in <module>
main()
File "player.py", line 87, in main
while await_user_input(events):
File "player.py", line 67, in await_user_input
key = getkey()
File "player.py", line 57, in getkey
key = sys.stdin.read(2)
ValueError: I/O operation on closed file
Welche anderen Möglichkeiten habe ich, um aus dem Programm zu kommen?
http://paste.pocoo.org/show/102840/