Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Touble with subprocess
#1
Hello, I am trying to write a script that calls a program to play audio and then restart the program so often.

However the program is not being killed and respawned?!

"""
Playback an audio stream.

Here we want to playback audio untill the user
presses ctrl+c.  If we do not restart our playback
process every three hours the server providing
the audio may start giving us silence.
"""
import random
import subprocess
import time


def make_url():
    """Append a random value to urls end."""
    rnd = str(random.randrange(1000000))
    url_with_rnd = "https://mediaserver3.afa.net:8443/talk.mp3" + "?" + rnd
    return url_with_rnd


MPV_EXE = "F:/z0bin/mpv/mpv-0-32-0/mpv.com"

while True:
    URL = make_url()

    ARGS = [
        MPV_EXE,
        "--no-config",
        "--input-conf=./input.conf",
        "--audio-device=wasapi/{9c3e3659-8106-448c-a9b3-93881bbbfadc}",
        "--audio-exclusive=no",
        "--input-media-keys=no",
        "--no-input-default-bindings",
        "--no-video",
        URL,
    ]

    with subprocess.run(ARGS) as proc:

        # Use 30 seconds to test if exiting works.
        # Else we'd use 10800 seconds.
        TIME_TO_EXIT = time.time() + 30

        while proc.poll() is not None:
            if time.time() > TIME_TO_EXIT:
                proc.terminate()
                print("")
                print("We exited MPV.")
                print("")
                break

            time.sleep(1)

        else:
            print("")
            print("MPV exited itself.")
            print("")
Reply
#2
why not play the mp3's directly from python
for mp3 players see: https://pypi.org/search/?q=%27mp3+player%27&o=
Reply
#3
subprocess.run() don't release process of stream/audio before it's Finish.
Could try a solution with subprocess.Popen() which release the process,
then can use terminate() but then also should kill the process or it would just span new ones.
Here can use psutil.

So if do a test i don't need to use stdout=subprocess.PIPE, stderr=subprocess.PIPE in Popen,
as i don't want to communicate and now also see the output of mpv.
So here is test using time.sleep(30) and when kill process need to use subprocess.run() as Popen would exit all here.
"""
Playback an audio stream.

Here we want to playback audio untill the user
presses ctrl+c.  If we do not restart our playback
process every three hours the server providing
the audio may start giving us silence.
"""
import random
import subprocess
import time
import psutil

def make_url():
    """Append a random value to urls end."""
    rnd = str(random.randrange(1000000))
    url_with_rnd = "https://mediaserver3.afa.net:8443/talk.mp3" + "?" + rnd
    return url_with_rnd

while True:
    MPV_EXE = "mpv.com"
    URL = 'https://www.radiantmediaplayer.com/media/bbb-360p.mp4'
    ARGS = [
        MPV_EXE,
        "--no-video",
        URL
        ]

    with subprocess.Popen(ARGS) as proc:
        print("MPV exited itself.")
        time.sleep(30)
        proc.terminate()
        for pid in psutil.process_iter():
            if pid.name() == 'mpv.exe':
                subprocess.run(f"TASKKILL /F /IM {pid.name()}")
Output:
G:\1_youtube\mpv1 λ python p_restart.py MPV exited itself. Video --vid=1 (*) (h264 640x360 24.000fps) (+) Audio --aid=1 --alang=eng (*) (aac 2ch 48000Hz) AO: [wasapi] 48000Hz stereo 2ch float SUCCESS: The process "mpv.exe" with PID 88696 has been terminated. MPV exited itself. Video --vid=1 (*) (h264 640x360 24.000fps) (+) Audio --aid=1 --alang=eng (*) (aac 2ch 48000Hz) AO: [wasapi] 48000Hz stereo 2ch float SUCCESS: The process "mpv.exe" with PID 87840 has been terminated. MPV exited itself. Video --vid=1 (*) (h264 640x360 24.000fps) (+) Audio --aid=1 --alang=eng (*) (aac 2ch 48000Hz) AO: [wasapi] 48000Hz stereo 2ch float SUCCESS: The process "mpv.exe" with PID 89076 has been terminated. MPV exited itself. Video --vid=1 (*) (h264 640x360 24.000fps) (+) Audio --aid=1 --alang=eng (*) (aac 2ch 48000Hz) AO: [wasapi] 48000Hz stereo 2ch float Traceback (most recent call last): 94s/3MB File "p_restart.py", line 31, in <module> time.sleep(30) KeyboardInterrupt G:\1_youtube\mpv1
Reply
#4
If Popen does not wait for process to finish ... then why does this script not print 'foobar' once a second?


"""
Playback an audio stream.

Here we want to playback audio untill the user
presses ctrl+c.  If we do not restart our playback
process every three hours the server providing
the audio may start giving us silence.
"""
import random
import subprocess
import time


def make_url():
    """Append a random value to urls end."""
    rnd = str(random.randrange(1000000))
    url_with_rnd = "https://mediaserver3.afa.net:8443/talk.mp3" + "?" + rnd
    return url_with_rnd


MPV_EXE = "F:/z0bin/mpv/mpv-0-32-0/mpv.com"

while True:
    URL = make_url()

    ARGS = [
        MPV_EXE,
        "--no-config",
        "--input-conf=./input.conf",
        "--audio-device=wasapi/{9c3e3659-8106-448c-a9b3-93881bbbfadc}",
        "--audio-exclusive=no",
        "--input-media-keys=no",
        "--no-input-default-bindings",
        "--no-video",
        URL,
    ]

    with subprocess.Popen(ARGS) as proc:

        # Use 30 seconds to test if exiting works.
        # Else we'd use 10800 seconds.
        TIME_TO_EXIT = time.time() + 30

        while proc.poll() is not None:
            

            print("foobar")
            

            if time.time() > TIME_TO_EXIT:
                proc.kill()
                print("")
                print("We exited MPV.")
                print("")
                break

            time.sleep(1)

        else:
            print("")
            print("MPV exited itself.")
            print("")
Reply
#5
The while True loo still hold a connection even if the process has bee released to OS.
If you look at this post you see that Popen is a true parallel solution as it leave to OS to handle the processes.
So in my solution it would no problem to set time.sleep(10800) then the stream would run for 3-hour,then it will do restart.
There can be trouble block(not running) the if time.time() > TIME_TO_EXIT solution.
Reply
#6
I'm not sure if this solution is suitable for you
or if you can work it into the way you want your program
to work, but here is an idea.
import os
import random
import time
import webbrowser as web
 
 
def make_url():
    """Append a random value to urls end."""
    rnd = str(random.randrange(1000000))
    url_with_rnd = "https://mediaserver3.afa.net:8443/talk.mp3" + "?" + rnd
    web.open(url_with_rnd)
    return url_with_rnd


while True:
    
    URL = make_url()
    time.sleep(30)
    os.system("taskkill /F /IM firefox.exe")
This will play the stream for 30 seconds, quit the browser and the stream, get a new url
and do it again for ever.
Reply
#7
Here one with schedule which can more sense to use with long running task like this.
So it do a check if stream is running every 5-sec(check_process()) if it dos do nothing,else run_stream().
Kill the process here as test every 40-sec,then check_process will restart stream.
Lightweight as only charge OS at schedule time.
import subprocess
import time, os
import psutil
import schedule
import threading

def check_process():
    proc_name = "mpv.exe"
    for proc in psutil.process_iter():
        if proc.name() == proc_name:
            return True
    else:
        return False

def kill_stream():
    proc_name = "mpv.exe"
    for pid in psutil.process_iter():
        if pid.name() == proc_name:
            subprocess.run(f"TASKKILL /F /IM {pid.name()}")

def run_stream():
    MPV_EXE = "mpv.com"
    URL = 'https://www.radiantmediaplayer.com/media/bbb-360p.mp4'
    ARGS = [
        MPV_EXE,
        "--no-video",
        URL
        ]
    with subprocess.Popen(ARGS) as proc:
        print(f'Running: {os.path.basename(URL)}')

def check_stream():
    if check_process():
        pass
    else:
        print('Stream is no running --> restart')
        run_stream()

def run_threaded(job_func):
    job_thread = threading.Thread(target=job_func)
    job_thread.start()

if __name__ == '__main__':
    schedule.every(5).seconds.do(run_threaded, check_stream)
    schedule.every(40).seconds.do(run_threaded, kill_stream)
    # 3 hour restart
    #schedule.every(3).hours.do(run_threaded, kill_stream)
    while True:
        schedule.run_pending()
        time.sleep(1)
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020