Nebenprogramm öffnen und Kommunikation mit Nebenprogramm

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
Ls342
User
Beiträge: 5
Registriert: Dienstag 28. März 2017, 05:53

Hallo,
seit ein paar Tagen versuche ich madplay so zu konfigurieren, dass ich die Möglichkeit habe es im Python Script aufzurufen um dann die gewünschten Einstellungen vornehmen zu können.
Am Anfang habe ich es mit:

Code: Alles auswählen

os.system('wget -q -O- '+str(fav_adress[1])+' | madplay -')
aufgerufen. Da dadurch das Python Script angehalten wird, habe ich diese Version genommen:

Code: Alles auswählen

internetradio_adress = subprocess.Popen(['wget -q -O- '+str(fav_adress[1])+' | madplay -'], shell=True)
Nun läuft das Python Script wenigstens weiter, jedoch gibt es jetzt Probleme das Programm wieder zu schließen.
Ich habe gelesen, dass man

Code: Alles auswählen

shell=True
nicht verwenden soll, jedoch funktioniert es ohne dem

Code: Alles auswählen

shell=True
nicht.
Da ich über die madplay Befehle, die Wiedergabe schließen kann, wäre meiner Meinung nach die eleganteste Lösung, über Befehle den Unterprozess zu steuern.
In der Konsole kann ich alles hintereinander eingeben. Ich gehe mal davon aus, dass ich nicht mehrmals hintereinander den Befehl

Code: Alles auswählen

subprocess.Popen
benutzen kann, da er dann immer einen neuen Unterprozess erstellt.
Dann gibt es die möglichkeit über:

Code: Alles auswählen

internetradio_adress = subprocess.Popen(['wget -q -O- '+str(fav_adress[1])+' | madplay -'], stdin=subprocess.PIPE, shell=True)
internetradio_adress.communicate('BefehlAusListe')
Genau an diesem Punkt hänge ich momentan fest. Ist

Code: Alles auswählen

.communicate()
gleichzusetzen mit einer Eingabe im Terminal oder gibt es bessere Lösungen für diesen Fall?

Funktion(kurz Zusammengefasst):
Das Unterprogramm soll die Internetradioadresse abspielen und man soll dabei die Möglichkeit haben, dass Unterprogramm mit Befehlen zu füttern, um gegebenenfalls Einstellungen zu ändern oder das Programm zu schließen.




Befehle madplay: https://man.cx/madplay(1)
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Ls342: die Standardeingabe wird Dir nichts helfen, weil das ja die Eingabe von wget ist. Der Weg, das Programm zu beenden ist ein kill auf den wget-Prozess:

Code: Alles auswählen

wget_process = subprocess.Popen(['wget', '-q', '-O-', str(fav_adress[1])], stdout=subprocess.PIPE)
madplay_process = subprocess.Popen(['madplay', '-'], stdin=wget_process.stdout)
[...]
wget_process.kill()
wget_process.wait()
madplay_process.wait()
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich wuerde das gleich ueber Python loesen.

https://github.com/jaqx0r/pymad

erlaubt dir, libmad (den Code hinter madplay) zu kontrollieren, und einen Stream zu oeffnen und zu lesen ist auch direkt mit Python moeglich. Und schon gibt's keine Prozesskontrolliererei mehr.
Ls342
User
Beiträge: 5
Registriert: Dienstag 28. März 2017, 05:53

Sirius3 hat geschrieben:@Ls342: die Standardeingabe wird Dir nichts helfen, weil das ja die Eingabe von wget ist. Der Weg, das Programm zu beenden ist ein kill auf den wget-Prozess:

Code: Alles auswählen

wget_process = subprocess.Popen(['wget', '-q', '-O-', str(fav_adress[1])], stdout=subprocess.PIPE)
madplay_process = subprocess.Popen(['madplay', '-'], stdin=wget_process.stdout)
[...]
wget_process.kill()
wget_process.wait()
madplay_process.wait()
Diese Lösung gefällt mir gut, schlicht und einfach, jedoch dauert es ca 5s bis er den wget Prozess killt. Wenn ich das richtig sehe, stoppe ich hiermit so gesagt die Datenzufuhr zu madplay.
__deets__ hat geschrieben:Ich wuerde das gleich ueber Python loesen.

https://github.com/jaqx0r/pymad

erlaubt dir, libmad (den Code hinter madplay) zu kontrollieren, und einen Stream zu oeffnen und zu lesen ist auch direkt mit Python moeglich. Und schon gibt's keine Prozesskontrolliererei mehr.
Unter den Tests ist auch ein Internetradio Programm, jedoch finde ich es sehr kompliziert. Für mich ist es auch sehr unübersichtlich, welche Funktionen mir die Wrapper Klasse bietet.
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wenn du mit den 5 Sekunden fuer das killen leben kannst, nimm was du verstehst. Man kann halt zB keine Lautstaerke regeln usw, aber es ist dein Radio, nicht meins :)
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Ls342: die 5 Sekunden sind wahrscheinlich der Puffer, den wget schon heruntergeladen hat. Wenn Dich das stört, kannst Du auch madplay killen.
BlackJack

Wobei ich das `kill()` ein bisschen ”overkill” finde. `terminate()` ist freundlicher und sollte eigentlich die erste Wahl sein um ein Programm von aussen *normal* zu beenden.
Ls342
User
Beiträge: 5
Registriert: Dienstag 28. März 2017, 05:53

Mit den 5 Sekunden Wartezeit kann ich leben, da das Hauptprogramm weiter abläuft.

Nun denke ich, dass ich den Code mit dem Unterprozess wget und madplay verstanden habe:
- wget besorgt die Daten von der URL
- madplay decodiert die Daten, die wget madplay sendet

Jetzt gibt es aber ein nächstes Problem, das mit den MP3 Dateien abspielen funktioniert auch nicht so wie geplant, doch warum nur?

Code: Alles auswählen

os.system("madplay "+directory_files+"/"+files[0] )
Funktioniert wie immer, jedoch stoppt er aufgrund des Befehls das Programm.

Code: Alles auswählen

usbplay = subprocess.call(["madplay "+directory_files+"/"+files[0]],shell=True )
Funktioniert auch, jedoch der gleiche negative Grund wie oben.

Code: Alles auswählen

usbplay = subprocess.Popen(["madplay "+directory_files+"/"+files[0]],shell=True )
Gibt einen Fehler aus tty: read: Input/Output Error.
Der Befehl startet den Player und versucht die Datei abzuspielen, jedoch scheint es bei der Datenübertragung Probleme zu geben, sodass der Player sie nicht bekommt.

Vielleicht kann jemand mir ein Buch/Webseite empfehlen oder einen Tipp geben, warum es nicht funktioniert. Ich würde es gerne verstehen und nicht nur die Lösung präsentiert bekommen.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Ls342: das kann nicht sein, da `subprocess.call` auch nur `subprocess.Popen` aufruft.

Korrekt wäre übrigens, nicht shell=True zu benutzen:

Code: Alles auswählen

filename = os.path.join(directory_files, files[0])
usbplay = subprocess.Popen(["madplay", filename])
Antworten