Python: Send command to mplayer under slave mode

mplayer, pipe, python, subprocess

Solution

You can only use `.communicate()` once per subprocess. So using it in a `while` loop doesn't work.

Instead, you should parse the output of `p.stdout` directly. There seems to be one line per answer if there is an answer.

In order to prevent blocking, you have 3 options:

Work with threads. You have a separate thread who reads from `p.stdout` and sends its data to the main thread. It blocks if no data is available.

Set `p.stdout` to non-blocking mode. Essentially, you'll have to do this:

import fcntl, os
fcntl.fcntl(p.stdout.fileno(), fcntl.F_SETFL,
    fcntl.fcntl(p.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK)

If you read then without data being available, you get an exception (`IOError: [Errno 11] Resource temporarily unavailable`).

Work with `select.select()`: perform `p.stdout.readline()` only if `select.select([p.stdout], [], [], <timeout>)[0]` is a non-empty list. In that case, the given file object is guaranteed to have data available and to not block on reading.

In order to separate "garbage output" from "useful" output, you could do this:

def perform_command(p, cmd, expect):
    import select
    p.stdin.write(cmd + '\n') # there's no need for a \n at the beginning
    while select.select([p.stdout], [], [], 0.05)[0]: # give mplayer time to answer...
        output = p.stdout.readline()
        print("output: {}".format(output.rstrip()))
        split_output = output.split(expect + '=', 1)
        if len(split_output) == 2 and split_output[0] == '': # we have found it
            value = split_output[1]
            return value.rstrip()

and then do

print perform_command(p, 'get_meta_artist', 'ANS_META_ARTIST')
print perform_command(p, 'get_time_pos', 'ANS_TIME_POSITION')

Problem

I'm trying to send command via pipe to mplayer when running it under slave mode like this: ``` import subprocess, time # start mplayer song = 'mysong.mp3' cmd = ['mplayer', '-slave', '-quiet', song] p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) # send a command every 3 seconds. # Full command reference here: http://www.mplayerhq.hu/DOCS/tech/slave.txt while True: print('sleep 3 seconds ...') time.sleep(3) cmd = 'get_meta_artist' print('send command: {}'.format(cmd)) p.stdin.write(cmd) output = p.communicate()[0] print(output) ``` But the output was nothing. I took the example from this question. Running the same mplayer command in the terminal works fine. What am I missing here? UPDATE: I changed my cmd from "get_meta_artist" to "get_meta_artist\n" so that a line-break is sent to the pipe as well but still I got nothing in the output. UPDATE2: I changed the cmd into "\npause\n" and the music was paused. So that means sending command via stdin worked. It means the output string of "\nget_meta_artist\n" command didn't get piped back as expected....

Original source

Related problems