2016-07-01 2 views
4

J'essaie d'implémenter un lecteur radio en utilisant RPi. L'objectif est de configurer une playlist et de commencer à jouer une fois que la playlist est remplie. Les processus du lecteur et de la radio doivent se terminer une fois que le code d'arrêt est exécuté.Sous-processus Python Popen.terminate() toujours bloqué sur wait()

Le processus radio se termine bien mais le processus du lecteur reste toujours en attente même après l'appel terminé. Si le code d'arrêt est appelé à nouveau, puis processus de joueur se termine

choses ont essayé:

  1. réordonnancement attendre les commandes (lecteur, radio)/(radio, lecteur)
  2. réordonnancement de la même fin commandes
  3. kill au lieu de mettre fin à l'IPD se bloque

code du joueur:

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 

Joueur code arythmique (appelé à partir d'un autre thread):

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:

Une autre alternative est d'avoir un puits persistant pour la radio et sur le processus de demande pour le joueur

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() 

Mais dans ce cas, l'appel à player.terminate() ferme le lecteur en répétant le dernier paquet sur le processus radio (comme un enregistrement bloqué) . Cet enregistrement coincé joue jusqu'à ce que je démarre un nouveau joueur ou que j'arrête la radio.

+2

essayer 'player.join() joueur' puis '. terminer() '? – ritlew

+0

@ritlew 'player' est un objet Popen et n'a pas de méthode de jointure. – CuriousCat

+2

1- * "Utiliser kill au lieu de terminer bloque le RPi" * - vous devez d'abord résoudre ce problème (cela peut aussi vous permettre de répondre à la question en cours). 2- Vous devriez appeler 'player.stdout.close()' après 'radio = Popen (...)' de sorte que le processus du joueur se termine si le processus radio se termine. – jfs

Répondre

2

Comme @ J.F.Sebastian mentionné, en utilisant player.stdout.close() fonctionne. La base de code complet est publié ici https://github.com/hex007/pifm_server

Ainsi, le code final ressemble à ceci

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 

Et le code d'arrêt:

stop_requested = True 

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

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

non lié: pour implémenter 'avconv ... | pifm ... 'pipeline en Python, vous pouvez démarrer les programmes dans l'ordre inverse (cela n'affecte pas le résultat - ils devraient fonctionner en parallèle de toute façon):' pifm = Popen (['pifm', '... '], stdin = PIPE); player = Popen (['avconv', '...'], stdout = pifm.stdin); pifm.communicate(); joueur.wait() '(dans ce cas, si' pifm' meurt, 'avconv' le saura même si vous oubliez de fermer' pifm.stdin'). Voir la réponse de @ Cristian à [Comment utiliser subprocess.Popen pour connecter plusieurs processus par des tuyaux?] (Http://stackoverflow.com/q/295459/4279) – jfs

+0

@JFSebastian L'idée principale de la section Alternative était d'avoir un puits pour pifm car pifm transmet le silence si stdin est vide; une caractéristique favorable. Et puis connectez le canal à un autre processus auquel les dumps de pifm stdin ondemand. Un tel comportement demande un processus radio persistant qui ne se termine pas même si stdin est fermé. Je regarde l'article que vous avez mentionné. – CuriousCat

+0

pour être clair ** les deux méthodes ** émulent ** le même pipeline shell **: avconv | pifm' (si vous attendez un résultat différent, l'attente est fausse). – jfs