0

I'm trying to code a simple script that will help me to start and stop video playback on multiple Raspberry Pi using mqtt.

This is the first time I'm trying to start and stop subprocess from a python script and I'm having trouble understanding the correct order of operation

there is my code

import paho.mqtt.client as mqtt
import multiprocessing, time, signal
import os

def player(video):
    print("Playing " + video)
    os.system("omxplayer-sync " + video)

def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))
    client.subscribe("player/#")

def on_message(client, userdata, msg):    
    print(msg.topic+" "+str(msg.payload))
    if msg.topic == "player/PLAY":
        p = multiprocessing.Process(target=player, args=[str(msg.payload.decode())])
        p.start()
    if msg.topic == "player/STOP":
        print("Stopping video")
        print(p, p.is_alive())
        print("Terminating video")
        p.terminate()
        print(p, p.is_alive())

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.connect("localhost", 1883, 60)

client.loop_forever()

I can successfully start the video but I can't stop it. I'm pretty sure this is due to the fact that the p object is destroyed at the end of the on_message callback but I don't see where I can create my Process elsewhere.


Edit

this is a naive approach using the global keyword

import paho.mqtt.client as mqtt
import multiprocessing, time, signal
import os

videoFile = ""

class GracefulExit:
    kill_now = False
    def __init__(self):
        signal.signal(signal.SIGINT, self.exit_gracefully)
        signal.signal(signal.SIGTERM, self.exit_gracefully)

    def exit_gracefully(self,signum, frame):
        self.kill_now = True

def player():
    global videoFile
    print("Playing " + videoFile)
    os.system("omxplayer-sync " + videoFile)

def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))
    client.subscribe("player/#")

def on_message(client, userdata, msg):
    global videoFile
    print(msg.topic+" "+str(msg.payload))
    if msg.topic == "player/PLAY":
        videoFile = str(msg.payload.decode())
        p.start()
    if msg.topic == "player/STOP":
        print("Stopping video")
        print(p, p.is_alive())
        print("Terminating video")
        p.terminate()
        print(p, p.is_alive())

def main():
    app_killer = GracefulExit()
    while not app_killer.kill_now:
        try:
            time.sleep(0.5)
        except BaseException:
            print("Encountered an exeption.")
            break
    print ("End of the program.")

if __name__ == '__main__':
    print("Starting the program")
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message
    client.connect("localhost", 1883, 60)
    client.loop_start()
    p = multiprocessing.Process(target=player)
    main()

but I can play the video just once and calling terminate doesn't stop the playback


Edit 2

Now I'm declaring p as a global as suggested, but I can't figure how to start playing a filename that I'm receiving from MQTT subscription

import paho.mqtt.client as mqtt
import multiprocessing, time, signal
import os

def player():
    print("Playing " + "synctest.mp4")
    os.system("omxplayer-sync " + "synctest.mp4")

p = multiprocessing.Process(target=player)

class GracefulExit:
    kill_now = False
    def __init__(self):
        signal.signal(signal.SIGINT, self.exit_gracefully)
        signal.signal(signal.SIGTERM, self.exit_gracefully)

    def exit_gracefully(self,signum, frame):
        self.kill_now = True

def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))
    client.subscribe("player/#")

def on_message(client, userdata, msg):
    print(msg.topic+" "+str(msg.payload))
    if msg.topic == "player/PLAY":
        print("p.args= " + p.name)
        videoFile = str(msg.payload.decode())
        #how to put the videoFile into the args given to p ?
        p.start()
    if msg.topic == "player/STOP":
        print("Stopping video")
        print(p, p.is_alive())
        print("Terminating video")
        p.terminate()
        print(p, p.is_alive())

def main():
    app_killer = GracefulExit()
    while not app_killer.kill_now:
        try:
            time.sleep(0.5)
        except BaseException:
            print("Encountered an exeption.")
            break
    print ("End of the program.")

if __name__ == '__main__':
    print("Starting the program")
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message
    client.connect("localhost", 1883, 60)
    client.loop_start()
    main()
dezmob
  • 3
  • 2
  • You need to look at the `global` keyword. – hardillb Jan 23 '20 at 15:30
  • I tried a naive approach with the global keyword but when the video ends : I can't play it a second time, and the terminated is called but nothing happened... – dezmob Jan 24 '20 at 10:12
  • Why are you making the video file global? It's the `p` object representing the process you need to keep alive and reuse between callbacks. You even pointed this out yourself. – Useless Jan 24 '20 at 10:56
  • Because when I tried to declare p as a global, then when calling p.start() I didn't managed to find a way to change the args given to the process... – dezmob Jan 24 '20 at 11:05
  • I know the solution to the problem may be obvious to a lot of you but I'm really struggling with this simple thing. I'm not even sure if using multiprocessing is the way to do to achieve this, but I found it more elegant to just send some combinaison of `os.system`, `kill` and `grep`. Can someone highlight me? – dezmob Jan 27 '20 at 09:34

0 Answers0