如何在Python中流式传输给定NumPy数组的MP3块



我正在努力寻找一个从Python服务器流式传输合成音频的解决方案。合成的音频被递增地生成并作为np.float32NumPy数组返回。然后需要将它从NumPy数组转换为MP3块。最后,通过flask来提供MP3块。

这里有一些伪代码:

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
  • 流音频WAV文件与Flask:HTTP实时音频流服务器
  • 流音频WAV文件与PyAudio:Python:实时音频流与PyAudio(或其他什么(
  • 带有FFMpeg和烧瓶的流: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年作为HTTP1.1的一部分引入的。

不管怎样,我惊讶地发现ffmpeg的流与flask兼容,并且在Safari、Firefox和Chrome上都支持它。

最新更新