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
相关产品推荐
相关产品推荐

