Flask中使用Generator/Yield流式播放音频仅播放首文件问题排查
问题原因
直接拼接两个完整WAV文件的二进制内容是错误的。WAV文件由文件头和音频采样数据两部分组成,播放器会将第一个文件的头作为整个流的格式依据,第二个文件的头会被当成无效的音频数据,导致无法识别播放。
解决方案
需要合并两个WAV的音频数据,同时生成一个包含正确总时长的统一WAV头,再流式返回完整的合并内容:
- 读取两个WAV文件的格式参数(需确保采样率、位深、声道数一致,否则需转码)
- 计算合并后的总音频数据长度,修改第一个文件的头信息
- 流式返回修改后的头,再依次返回两个文件的音频采样数据
修正后的代码
from flask import Flask, Response import random import wave import struct app = Flask(__name__) @app.route('/') def paadas(): def generate_merged_wav(): # 随机选择文件路径 number_path = f"../numbers/{random.randint(1,10)}.wav" times_path = f"../times/{random.randint(1,10)}.wav" # 处理第一个WAV文件,获取格式参数和音频数据 with wave.open(number_path, 'rb') as wav1: params = wav1.getparams() nchannels, sampwidth, framerate, nframes, comptype, compname = params audio_data1 = wav1.readframes(nframes) # 处理第二个WAV文件,仅读取音频数据(跳过文件头) with wave.open(times_path, 'rb') as wav2: # 验证参数一致性,不一致需转码处理 assert wav2.getparams()[:3] == params[:3], "WAV文件采样率/声道数/位深不匹配" nframes2 = wav2.getnframes() audio_data2 = wav2.readframes(nframes2) # 计算合并后的总帧数与数据大小 total_frames = nframes + nframes2 data_size = total_frames * nchannels * sampwidth # 读取第一个文件的原始头并修改关键参数 with open(number_path, 'rb') as f: header = f.read(44) # 标准PCM WAV头为44字节 # 修改总帧数(偏移40-43字节,小端格式) header = header[:40] + struct.pack('<L', total_frames) + header[44:] # 修改文件总大小(偏移4-7字节,小端格式:36为头固定长度,加上数据大小) header = header[:4] + struct.pack('<L', 36 + data_size) + header[8:] # 流式返回合并后的内容 yield header yield audio_data1 yield audio_data2 return Response(generate_merged_wav(), mimetype='audio/wav') if __name__ == '__main__': app.run(debug=True)
关键说明
- 必须保证两个WAV文件的采样率、声道数、位深完全一致,否则合并后的音频会失真或无法播放;若参数不一致,需先通过音频处理库(如pydub)进行转码
- 使用
wave模块读取音频数据,避免直接读取二进制文件导致的头信息处理错误 - 用
struct模块修改WAV头中的总帧数和数据大小,确保播放器能正确识别整个音频流的长度
内容的提问来源于stack exchange,提问作者Sameer Mahajan
相关产品推荐
相关产品推荐

