python - 如何在 Python 中给定 NumPy 数组流式传输 MP3 块?
问题描述
我正在努力寻找从 Python 服务器流式传输合成音频的解决方案。合成的音频以增量方式生成并作为np.float32
NumPy 数组返回。然后需要将其从 NumPy 数组转换为 MP3 块。最后,MP3 块通过flask
.
这是一些伪代码:
import numpy
from flask import Flask
from flask import Response
app = Flask(__name__)
sample_rate = 24000
def pcm_to_mp3():
raise NotImplementedError()
def get_synthetic_audio():
""" Mock function for synthetic audio. """
while True:
yield numpy.random.rand(1024) * 2 - 1 # Return: 32-bit Floating Point PCM
@app.route('/stream', methods=['GET'])
def get_stream():
""" Stream synthetic audio. """
def response():
for numpy_array in get_synthetic_audio():
# NOTE: The raw audio needs additional metadata to be playable like sample rate.
yield pcm_to_mp3(numpy_array, sample_rate=sample_rate)
return Response(
response(),
headers={
# NOTE: Ensure stream is not cached.
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Pragma': 'no-cache',
'Expires': '0',
# NOTE: Enable streaming.
'Transfer-Encoding': 'chunked'
},
mimetype='audio/mpeg')
if __name__ == "__main__":
app.run()
虽然类似的设置适用于 WAV 文件,但我无法弄清楚如何为 MP3 文件做类似的事情。
谢谢!
来源
- 通过 PyDub 将 NumPy 数组转换为 MP3 文件:如何将 MP3 音频文件读入 numpy 数组/将 numpy 数组保存到 MP3?
- 使用 Flask 流式传输音频 WAV 文件:HTTP 实时音频流服务器
- 使用 PyAudio 流式传输音频 WAV 文件:Python:使用 PyAudio(或其他)进行实时音频流式传输?
- 使用 FFMpeg 和 Flask 进行流式传输:https ://gist.github.com/anthonyeden/f3b3bdf6f62badd8f87bb574283f488a
解决方案
我能够找出一种工作方法:
import select
import subprocess
import numpy
from flask import Flask
from flask import Response
app = Flask(__name__)
def get_synthetic_audio(num_samples):
audio = numpy.random.rand(num_samples).astype(numpy.float32) * 2 - 1
assert audio.max() <= 1.0
assert audio.min() >= -1.0
assert audio.dtype == numpy.float32
return audio
def response():
pipe = subprocess.Popen(
'ffmpeg -f f32le -acodec pcm_f32le -ar 24000 -ac 1 -i pipe: -f mp3 pipe:'
.split(),
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
poll = select.poll()
poll.register(pipe.stdout, select.POLLIN)
while True:
pipe.stdin.write(get_synthetic_audio(24000).tobytes())
while poll.poll(0):
yield pipe.stdout.readline()
@app.route('/stream.mp3', methods=['GET'])
def stream():
return Response(
response(),
headers={
# NOTE: Ensure stream is not cached.
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Pragma': 'no-cache',
'Expires': '0',
},
mimetype='audio/mpeg')
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8000, debug=True)
在我的探索过程中,我了解到flask
不支持分块传输编码。这是令人惊讶的,因为分块传输编码是在 1997 年作为 HTTP 1.1 的一部分引入的。
无论如何,我很惊讶地得知ffmpeg
的流与 兼容flask
,并且 Safari、Firefox 和 Chrome 都支持它。
推荐阅读
- .net - 无法读取“GetProcessPreferredUILanguages”函数返回的所有语言名称
- php - 如何隐藏表格中的空字段?
- java - 带有 Spring 的 DDD Java - 返回 Mono/Flux 的存储库
- reactjs - Redux - 当我调度一个动作时,Reducer 没有被调用
- r-markdown - 如何将 YAML 中的动态参数传递到 word 文档每一页中出现的标题?
- google-apps-script - 将工作表保持在 500 行
- javascript - OpenLayers ZoomSlider 没有出现
- c++ - 如何在 C++ 中将二维向量转换为一维数组?
- javascript - 如何使复选框单独与输入字段一起使用
- javascript - 如何自定义音频播放器?