You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python pipes库废弃后,如何通过命名管道控制mpg123远程服务?

解决Python控制mpg123命名管道无音频输出问题

背景

之前用Python的pipes库配合mpg123的-R(远程控制)接口实现音频播放,因pipes在Python 3.13+被弃用,改用os.mkfifo创建命名管道,但新代码无法正常播放,无音频输出且无报错。

旧代码逻辑(依赖已弃用的pipes库):

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()    

尝试的新代码(用os.mkfifo):

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())

问题现象:
运行后仅输出以下内容,无音频:

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

注:直接在终端执行mpg123 test.mp3可正常播放,音频设备无问题。

解决方案

方案1:修复命名管道的使用问题

问题出在非阻塞模式和管道打开方式:

  • 非阻塞模式下,写入命令后mpg123可能还没来得及读取,管道就被关闭,导致命令未被处理
  • 不需要O_RDWR,只用O_WRONLY即可

修正后的代码:

import os, subprocess

mpgpipe = "/tmp/mpg123remote.cmd"
# 确保管道不存在时创建,存在则先删除(避免旧管道残留问题)
try:
    os.remove(mpgpipe)
except OSError:
    pass
try:
    os.mkfifo(mpgpipe)
    print("Named pipe created successfully!")
except OSError as e:
    print(f"Named pipe creation failed: {e}")
    exit(1)

# 启动mpg123,绑定命名管道作为控制输入
fmpgout = open("/tmp/mpg123.out", "w")
mpg123proc = subprocess.Popen(
    ["/usr/bin/mpg123", "-a", "default", "-vR", "--fifo", mpgpipe],
    stdout=fmpgout,
    stderr=subprocess.STDOUT
)

# 以阻塞模式打开管道,写入命令
songname = "test.mp3"
command = f"load \"{songname}\"\n"
# 用普通open打开管道(默认阻塞模式),替代os.open+FileIO
with open(mpgpipe, 'w') as f:
    f.write(command)

# 可选:保持进程运行,否则主程序退出可能导致mpg123终止
# mpg123proc.wait()

方案2:直接用subprocess的stdin发送命令(更简洁)

mpg123的-R模式默认从标准输入读取命令,无需额外创建命名管道,直接通过subprocess.Popen的stdin发送命令即可:

import subprocess

# 启动mpg123,开启远程控制模式
fmpgout = open("/tmp/mpg123.out", "w")
mpg123proc = subprocess.Popen(
    ["/usr/bin/mpg123", "-a", "default", "-vR"],
    stdin=subprocess.PIPE,
    stdout=fmpgout,
    stderr=subprocess.STDOUT,
    text=True  # 用文本模式,无需手动编码
)

# 发送播放命令
songname = "test.mp3"
mpg123proc.stdin.write(f"load \"{songname}\"\n")
mpg123proc.stdin.flush()  # 确保命令被发送到mpg123

# 可选:保持进程运行
# mpg123proc.wait()

说明

  • 方案2无需处理命名管道的创建和同步问题,更稳定简洁
  • 若需要多进程控制mpg123,方案1的命名管道更合适,但需注意管道的读写同步

内容的提问来源于stack exchange,提问作者alessandro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 08:07:03