在Python中给定NumPy数组的情况下,如何流式传输MP3块? [英] How to stream MP3 chunks given a NumPy array in Python?

查看:77
本文介绍了在Python中给定NumPy数组的情况下,如何流式传输MP3块?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力寻找一种解决方案,用于从Python服务器流式传输合成音频.合成的音频将增量生成并作为 np.float32 NumPy数组返回.然后需要将其从NumPy数组转换为MP3块.最后,MP3块通过 flask 提供.

I'm struggling to find a solution for streaming synthesized audio from a Python server. The synthesized audio is incrementally generated and returned as a np.float32 NumPy array. It then needs to be transformed from a NumPy array into an MP3 chunk. Finally, the MP3 chunk is served via 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文件执行类似的操作.

While a similar setup works for WAV files, I am unable to figure out how to do something similar for MP3 files.

谢谢!

来源

推荐答案

我能够找出一种可行的方法:

I was able to figure out a working approach:

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的一部分引入的.

During my exploration, I learned that flask does not support chunked transfer encoding. This was surprising because chunked transfer encoding was introduced in 1997 as part of HTTP 1.1.

无论如何,我惊讶地发现 ffmpeg 的流与 flask 兼容,并且在Safari,Firefox和Chrome中受支持.

Regardless, I was surprised to learn that ffmpeg's stream is compatible with flask, and that it was supported on Safari, Firefox, and Chrome.

这篇关于在Python中给定NumPy数组的情况下,如何流式传输MP3块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆