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

Python调用subprocess.Popen读取stdout导致WAV音频播放损坏如何解决?

问题根因

你遇到的采样率、位深识别错误和Python代码里的参数设置错误直接相关,和stdout.read操作本身无关:

  • aplay启动时设置了shell=True,但传参用了列表格式:shell=True开启时,只有列表的第一个元素会被作为Shell命令执行,后续的采样率、声道、位深参数全部被丢弃,aplay直接使用默认的8kHz、8bit配置播放,所以识别参数异常。
  • larynx的message参数多了多余的双引号:用列表形式给Popen传参时,不需要手动对参数加引号做转义,引号会被作为参数内容的一部分传给larynx,和终端执行的命令逻辑不一致。
  • 手动循环读写流时没有处理缓冲区刷新,可能导致部分音频数据留在Python进程缓冲区没有传给aplay,引发音频截断。
解决方案

最优方案:直接绑定进程输入输出,无需手动读写

直接将第一个进程的标准输出绑定到第二个进程的标准输入,和终端管道的行为完全一致,不需要自己处理流读写逻辑:

from subprocess import Popen, PIPE
from os import environ

# 列表传参不需要手动加引号,自动处理特殊字符
process = Popen(
    ['larynx', '-v', environ["VOICE"], "--raw-stream", message],
    stdout=PIPE
)
# 去掉shell=True,所有参数正常生效
process2 = Popen(
    ["aplay", "-r", "22050", "-c", "1", "-f", "S16_LE"],
    stdin=process.stdout,
    bufsize=4000
)

# 等待进程执行完成
process.wait()
process2.wait()

可选方案:保留手动读写逻辑的修改版本

如果确实需要手动处理流数据,修改对应参数错误并增加缓冲区刷新、流关闭逻辑即可:

from subprocess import Popen, PIPE
from os import environ

process = Popen(
    ['larynx', '-v', environ["VOICE"], "--raw-stream", message],
    stdout=PIPE
)
process2 = Popen(
    ["aplay", "-r", "22050", "-c", "1", "-f", "S16_LE"],
    stdin=PIPE,
    bufsize=4000
)

while True:
    data = process.stdout.read(4000)
    if len(data) == 0:
        break
    process2.stdin.write(data)
    process2.stdin.flush() # 手动刷新缓冲区,确保数据实时传给aplay

# 关闭aplay的标准输入,通知其数据传输完成
process2.stdin.close()
process.wait()
process2.wait()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 13:24:04