Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 217
CuriousCat Avatar asked Oct 31 '22 00:10

CuriousCat


1 Answers

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()
like image 83
CuriousCat Avatar answered Nov 02 '22 10:11

CuriousCat