CuriousCat CuriousCat - 5 months ago 58
Python Question

Python subprocess Popen.terminate() still stuck on wait()

I am trying to implement a radio player using RPi. The goal is to setup a playlist and start playing once playlist is populated. The player and radio processes are expected to exit once stop code is executed.

The radio process terminates nicely but the player process still remains on wait even after calling terminate. If the stop code is called again then player process terminates

Things tried:


  1. reordering wait commands (player,radio)/(radio,player)

  2. similarly reordering terminate commands

  3. using kill instead of terminate hangs the RPi



Player 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


Player Stop code (called from another 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:

Another alternative was to have a persistent sink for radio and on demand process for player

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


But in this case calling player.terminate() closes the player while playing last packet repeatedly on the radio process (like a stuck record). This stuck record plays till I start a new player or terminate the radio.

Answer

As @J.F.Sebastian mentioned, using player.stdout.close() works. The entire code base is published here https://github.com/hex007/pifm_server

So the final code looks something like this

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

And the stopping code:

stop_requested = True

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

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