0

I am new here and new to the whole Python coding and my programming knowledge is low. I am designing a code that receives an IM on GTalk and based on the received messages a subprocess (mp4 or mp3 file on OMXPlayer) will run. at the moment i can run the subprocess but I can't pause/stop the mp3/mp4 files (subprocess). Any suggestion?

def message_handler(connect_object, message_node):

    R = (message_node.getBody())

    if R == "video" :

        movie_path = '/home/pi/Desktop/media/video.mp4'
        p = subprocess.Popen(['omxplayer',movie_path])

    elif R == "music" :

        movie_path = '/home/pi/Desktop/media/music.mp3'
        p = subprocess.Popen(['omxplayer',movie_path])

    elif R == "pause":

        p.kill() # it gives me erroe "p is not defined"
        os.kill(p.pid, signal.SIGSTOP) # doesn't do nothing

   else:

       pass
Newbie
  • 3
  • 2
  • 1
    Have you defined p elsewhere, outside `message_handlers` scope? – Skurmedel Jul 19 '14 at 00:14
  • 2
    A little more detai on what Skurmedel is getting at. "p" will be newly defined for each invocation of `message_handler`. You want to save the `subprocess.Popen` somewhere with more permanent scope, so that the pause message can find the proper subprocess. Note the possibility of there being multiple subprocesses (playing more than one video at a time), so you need some way to track that as well. – mpez0 Jul 19 '14 at 00:24

2 Answers2

1

There are two problems with regards to this. Firstly, your variable "p" is defined inside the if blocks, and are thus not available outside that particular block. Second, you are not actually pausing the process, you are telling it to terminate. What you probably want to do is create a named pipe to your omxplayer process and feed instructions through that to omxplayer. This is, however, quite a bit more advanced. (Or not, as research progressed)

p = None #This initializes the variables globally.

def message_handler(connect_object, message_node):
    R = (message_node.getBody())
    if R== "video" :
        movie_path= '/home/pi/Desktop/media/video.mp4'
        p = subprocess.Popen(['omxplayer', movie_path],stdin=subprocess.PIPE)
    elif R== "pause":
        p.stdin.write('\x20') #Much cleaner alternative to named pipes...
    else:
        pass

Note that this is not complete code, it is merely a pointer in the right direction.

  • *"Firstly, your variable "p" is defined inside the if blocks, and are thus not available outside that particular block"* This isn't actually the case in Python. In Python, variables are always bound to the innermost function or module. So variables defined in an `if` block are in scope anywhere inside the function the `if` block occurs in. See [here](http://stackoverflow.com/q/2829528/2073595) – dano Jul 19 '14 at 00:56
  • 1
    `//` is not how to add comments to python code, probably worth pointing out before the OP ends up more confused. – Padraic Cunningham Jul 19 '14 at 00:57
  • 1
    Also, the `Popen` command as written will not work, because it's using shell redirection (`<`), and passes the entire command as a string, but isn't using `shell=True`. You should also use the `stdin=subprocess.PIPE` keyword argument to feed data to a process' stdin via `Popen`, not a named pipe. – dano Jul 19 '14 at 01:03
  • @KennethAalberg I'll be happy to reverse mine once those issues are fixed. – dano Jul 19 '14 at 01:15
  • @KennethAalberg You wouldn't want to use `communicate` to pause, because it will block until the program exits (I'm assuming omxplayer won't exit when it gets the pause command). You should just use `p.stdin.write('\x20')`. – dano Jul 19 '14 at 01:18
  • @dano I referred to this re. choosing communicate over stdin.write: http://stackoverflow.com/questions/8475290/how-do-i-write-to-a-python-subprocess-stdin – Kenneth Aalberg Jul 19 '14 at 01:24
  • 1
    @KennethAalberg It's definitely safer to use `communicate` in general, because you don't run the risk of a pipe filling up and causing a deadlock. But we can't use it here because we don't want to wait for the process to exit. It should also be safe to write directly to stdin in this case; we're just sending a small amount of data, so we shouldn't fill the pipe. – dano Jul 19 '14 at 01:47
  • I tried your code it gives me "UnboundedLocalError: local variable 'p' referenced before assignment". I don't know much, i just copied what you've written and pasted it there. and that was the result. i would like more explanation, like what is the '\x20' ? and what topic should i read about? piping ? popen and subprocess? i am sorry for all this questions, it is just my knowledge are at minimum, i am willing to put some work, if i am pointed in the right direction. – Newbie Jul 21 '14 at 17:46
  • The code is not fit to be pasted and used directly, it is provided as a pointer in the general direction. The '\x20' is a keycode, namely the keycode for the spacebar, which is the default key for pausing and restarting playback. Piping is basically providing a way for you to communicate with the process programmatically. Read up about popen.subprocess and using pipes in the Python online manual. https://docs.python.org/2/library/subprocess.html for instance. – Kenneth Aalberg Jul 21 '14 at 21:29
  • Listen, I have added "global p" under "def" and it works.. it pauses the video.. thank you so much :) – Newbie Jul 22 '14 at 10:00
  • @KennethAalberg: one more question, now if i send "video" the video plays, and if i followed that with "music" the music file plays, so the video and the music are playing at the same time. is there away? like if the video was playing when receving "music" the video will close and the music will play. i tried adding "p.stdin.write" just before the "movie_path" but that didn't work. any suggestions? – Newbie Jul 22 '14 at 11:47
0

When you declare a variable like p within a function, it only exists within that function's namespace - the list of defined variables and functions accessible at that point in time. You're creating the subprocess object with popen and binding it to p within the function message_handler, and it's in that namespace that p exists. Once message_handler exits, its namespace disappears with it - and so does the binding to p. Then the next time you access message_handler, you have no hope of accessing the same object.

A better option is to have your function accept and return the object:

def message_handler(connect_object, message_node, p):

    R = (message_node.getBody())

    if R  == "video" :

        movie_path = '/home/pi/Desktop/media/video.mp4'
        p = subprocess.Popen(['omxplayer',movie_path])

    elif R == "music" :

        movie_path = '/home/pi/Desktop/media/music.mp3'
        p = subprocess.Popen(['omxplayer',movie_path])

    elif R == "pause":

        p.kill() # it gives me erroe "p is not defined"
        os.kill(p.pid, signal.SIGSTOP) # doesn't do nothing

   else:

       pass

   return p

If you do it this way, p has been defined outside of the function, and now exists in whatever namespace you call the function from.

Now, as Kenneth Aalberg noted, your code probably isn't going to pause correctly, and you'll need to find another method. But this should answer one of your questions, at least.

TheSoundDefense
  • 6,753
  • 1
  • 30
  • 42