2016-07-01 11 views
4

Ich versuche, einen Radio-Player mit RPi zu implementieren. Das Ziel besteht darin, eine Wiedergabeliste einzurichten und mit der Wiedergabe zu beginnen, sobald die Wiedergabeliste ausgefüllt ist. Die Player- und Radio-Prozesse werden voraussichtlich beendet, sobald der Stop-Code ausgeführt wird.Python Subprozess Popen.terminate() immer noch auf warten()

Der Radio-Prozess beendet schön, aber der Player-Prozess bleibt immer noch auf warten, auch nach dem Beenden zu beenden. Wenn der Stop-Code erneut aufgerufen wird dann Spieler Prozess beendet

Dinge versucht:

  1. Neuordnungs Befehle warten (Spieler, Radio)/(Radio, Spieler)
  2. ähnlich Befehle beenden Neuordnungs
  3. kill statt beenden hängt RPI

Spieler Code:

while playlist: 
    player = subprocess.Popen(
      ["avconv", "-i", "Music/%s" % playlist[0], "-f", "s16le", "-ar", 
      "22.05k", "-ac", "1", "-"], stdout=subprocess.PIPE) 

    radio = subprocess.Popen(["./pifm", "-", freq], stdin=player.stdout) 

    radio.wait() 
    print "************ exiting from radio :)" 
    player.wait() 
    print "************ exiting from player :)" 

    playlist.pop(0) 
player = None 
radio = None 

Spieler Stop-Code (von einem anderen Thread genannt):

print "************ stop requested" 

if radio and radio.poll() is None: 
    print "************ terminating radio :)" 
    radio.terminate() 

if player and player.poll() is None: 
    print "************ terminating player :)" 
    player.terminate() 

Alternative:

Eine weitere Alternative für Spieler

def start_radio(): 
    global radio 
    radio = subprocess.Popen(["./pifm"...], stdin=subprocess.PIPE) 

def play(): 
    global player 
    while playlist and radio: 
     player = subprocess.Popen(["avconv"...], stdout=radio.stdin) 
     player.wait() 
     playlist.pop(0) 

def stop(): 
    if player and player.poll() is None: 
     print "************ terminating player :)" 
     player.terminate() 
eine persistente Senke für Radio und auf Anfrage Prozess zu haben war

Aber in diesem Fall schließt der Aufruf von player.terminate() den Player, während das letzte Paket wiederholt im Radio-Prozess abgespielt wird (wie ein festsitzender Datensatz). . Dieser steckengebliebene Rekord spielt, bis ich einen neuen Spieler starte oder das Radio beende.

+2

Versuch 'player.join()' 'dann Spieler. terminate() '? – ritlew

+0

@ritlew 'player' ist Popen-Objekt und hat keine Join-Methode. – CuriousCat

+2

1- * "mit kill anstelle von terminate hängt das RPi" * - Sie sollten dieses Problem zuerst beheben (es könnte Ihnen auch ermöglichen, die aktuelle Frage zu beantworten). 2- Sie sollten 'player.stdout.close()' nach 'radio = Popen (...)' aufrufen, damit der Player-Prozess beendet wird, wenn der Radio-Prozess beendet wird. – jfs

Antwort

2

Wie @ J.F.Sebastian erwähnt, funktioniert mit player.stdout.close() funktioniert. Die gesamte Code-Basis wird hier veröffentlicht https://github.com/hex007/pifm_server

So ist der endgültige Code so etwas wie diese

while playlist: 
    player = subprocess.Popen(
      ["avconv", "-i", "Music/%s" % playlist[0], "-f", "s16le", "-ar", 
      "22.05k", "-ac", "1", "-"], stdout=subprocess.PIPE) 

    radio = subprocess.Popen(["./pifm", "-", freq], stdin=player.stdout) 

    player.stdout.close() 

    radio.wait() 
    player.wait() 

    if stop_requested: 
     stop_requested = False 
     break 

    playlist.pop(0) 

player = None 
radio = None 

und den Stopp Code sieht:

stop_requested = True 

if radio and radio.poll() is None: 
    radio.terminate() 

if player and player.poll() is None: 
    player.terminate() 
+0

nicht verwandt: zu implementieren 'avconv ... | pifm ... 'pipeline in Python, Sie könnten die Programme in umgekehrter Reihenfolge starten (das Ergebnis wird nicht beeinflusst - sie sollten trotzdem parallel laufen):' pifm = Popen (['pifm', '... '], stdin = PIPE); Spieler = Popen (['avconv', '...'], stdout = pifm.stdin); pifm.communicate(); Spieler.wait() '(in diesem Fall, wenn' pifm' stirbt, dann 'avconv' wird es wissen, selbst wenn Sie' pifm.stdin' vergessen haben). Siehe @ Cristian's Antwort auf [Wie verwende ich subprocess.Popen, um mehrere Prozesse über Pipes zu verbinden?] (Http://stackoverflow.com/q/295459/4279) – jfs

+0

@JFSebastian Die Hauptidee für den Abschnitt Alternative war zu haben eine Senke für pifm, da pifm Stille überträgt, wenn stdin leer ist; eine günstige Eigenschaft. Und verbinden Sie dann die Pipe mit einem anderen Prozess, auf den Sie nach Bedarf stdin onmand stapeln. Ein solches Verhalten verlangt nach einem persistenten Funkprozess, der nicht beendet wird, selbst wenn Stdin geschlossen ist. Ich untersuche den Artikel, den Sie erwähnt haben. – CuriousCat

+0

um klar zu sein ** beide ** Methoden emulieren ** die gleiche ** Shell-Pipeline: 'avconv | pifm' (wenn Sie ein anderes Ergebnis erwarten, ist die Erwartung falsch). – jfs