If you really need the controls, you can't just use Popen
.
mpg123
only enables terminal control if its stdin is a tty, not if it's a file or pipe. That's why you get this line in the banner:
Terminal control enabled, press 'h' for listing of keys and functions.
And the whole point of Popen
(and subprocess
, and the POSIX APIs it's built on) is pipes.
So, what can you do about it?
On linux, you can use the pty
module. It may also work on other *nix platforms, but it may not—even if it gets built and included in your stdlib. As the docs say:
Because pseudo-terminal handling is highly platform dependent, there is code to do it only for Linux. (The Linux code is supposed to work on other platforms, but hasn’t been tested yet.)
It definitely runs on *BSD platforms on 2.7 and 3.3, and the example in the docs seem to work on both Mac OS X and FreeBSD… but that's as far as I've checked.
Meanwhile, most POSIX platforms will at least have os.forkpty
, and that's not much harder, so here's a trivial program that plays the first 5 seconds of a song passed as its first arg:
import os
import pty
import sys
import time
pid, fd = os.forkpty()
if pid:
time.sleep(5)
os.write(fd, 'q')
else:
os.spawnl(os.P_WAIT, # mode
'/usr/local/bin/mpg123', # path
'/usr/local/bin/mpg123', '-C', sys.argv[1]) # args
Note that I used os.spawnl
above. This is probably not what you want in a real program; it's for pedagogic purposes, to encourage you to read the docs (and the corresponding manpages) and understand this family of functions.
As the docs explain, this does not use the PATH
environment variable, so you need to specify the full path to the program. You can just use spawnlp
instead of spawnl
to fix this.
Also, spawn
may (in fact, always does, although the docs aren't entirely clear) do another fork to execute the child. This really isn't necessary, but spawn
does things that you would need to do manually if you just called exec
. If you know what you're doing, you may well want to use execl
(or execlp
) instead of spawnl
.
You can even use most of the functionality in subprocess
as long as you're careful (do not create any pipes, and remember that you'll end up doing two fork
s, so make sure to set up the parent/child relationship properly).
Also notice that you need to pass the path to mpg123
twice—once as the path, and then once as the child program's argv[0]
. You could also just pass mpg123
the second time. Or, ideally, look at what ps
says when you run it from the shell, and pass that. At any rate, you have to pass something as the argv[0]
; otherwise, -C
ends up being the argv[0]
, which means mpg123 won't think you gave it a -C
flag to enable control keys, but rather than you renamed it to -C
and ran it with no flags…
Anyway, you really do need to read the docs to understand what each of these functions does, instead of just treating it like magic code that you don't understand. So, I intentionally used the simplest possible solution to encourage that.
On Windows, there is no such thing as a pty
, and no way to do this at all with the facilities built in to Python. You will need to use one of the various third-party libraries for controlling a cmd.exe console (aka DOS prompt) instead.