pythonpipempg123

python pipes deprecated - interact with mpg123 server


I wrote some years ago an iTunes-replacing program in Python, with mpg123 accessed by a pipe (from the manual: -R, --remote: Activate generic control interface. mpg123 will then read and execute commands from stdin. Basic usage is ``load <filename>'' to play some file).

I dont have available a machine with the old python & pipes still working so it's hard to give you an example, but it was something like this:

import subprocess,pipes

mpgpipe = "/tmp/mpg123remote.cmd"
mpgout = "/tmp/mpg123.out"

fmpgout=open(mpgout,"w")
mpg123proc = subprocess.Popen(["/usr/bin/mpg123", "-vR", "--fifo", mpgpipe ], stdin=subprocess.PIPE, stdout=fmpgout)
    
t = pipes.Template()
t.append("echo load \"%s\"" % "test.mp3", '--')
f = t.open(mpgpipe, 'w')
f.close()    

Recently I started to get a warning DeprecationWarning: 'pipes' is deprecated and slated for removal in Python 3.13 - and now it happened: the pipes library isnt available anymore.

This is the test code I'm using, trying to access mpg123 by a named pipe:

import os, io, subprocess

mpgpipe = "/tmp/mpg123remote.cmd"
try:
   os.mkfifo(mpgpipe)
   print("Named pipe created successfully!")
except FileExistsError:
   print("Named pipe already exists!")
except OSError as e:
   print(f"Named pipe creation failed: {e}")


fmpgout=open("/tmp/mpg123.out","w")
mpg123proc = subprocess.Popen(["/usr/bin/mpg123", "-a", "default", "-vR", "--fifo", mpgpipe ],  stdout=fmpgout) 
    
pipfd = os.open(mpgpipe, os.O_RDWR | os.O_NONBLOCK)
songname = "test.mp3"
command=f"load \"{songname}\"\n"
with io.FileIO(pipfd, 'wb') as f: f.write(command.encode())

but it doesnt work: no audio, no error, and this text output :

High Performance MPEG 1.0/2.0/2.5 Audio Player for Layers 1, 2 and 3
    version 1.32.9; written and copyright by Michael Hipp and others
    free software (LGPL) without any warranty but with best wishes
Decoder: x86-64 (AVX)
Trying output module: alsa, device: default

(of course the audio device is ok and listening to test.mp3 with mpg123 from the terminal works perfectly...)

any idea???


Solution

  • I think I nailed it - here's the solution to drive mpg123 by subprocess, without pipes:

    import subprocess
    fmpgout=open("/tmp/mpg123.out","w")
    songname = "song.mp3"
    command=f"load {songname}\n"    
    mpg123proc = subprocess.Popen(["/usr/bin/mpg123", "-a", "default", "-vR"],  stdin=subprocess.PIPE, stdout=fmpgout, text=True) # with text=True I can send text on stdin: not needed to encode()    
    
    mpg123proc.stdin.write(command) 
    mpg123proc.stdin.flush()
    while(1): pass
    

    things that at first made me stumble:

    1. mpg123proc.communicate() doesnt work here: it launches mpg123 but closes the pipe when it returns
    2. remote commands have to be '\n' terminated, else mpg123 doesnt parse the command - and doesnt tell you why!
    3. try to use stdin.write() without a flush(), as I did ;-)