首页 > 解决方案 > 如何在没有中间音频文件的情况下转换 pydub `AudioSegment` 以用于流式传输?

问题描述

我正在开发一种软​​件,以使用 Flask 网络服务通过 HTTP 流式传输来自源的音频。sounddevice我可以通过带有正确 mimetype 的 Flask 路由获取声音帧并将它们路由到浏览器yield,但是原始音频格式对于远程流式传输来说非常麻烦,并且在客户端兼容性方面并不是最好的。

我很想用来将原始音频帧转换为像 mp3 或 ogg 这样的格式,但是从文档源代码pydub中我都不清楚如何在不转储输出的情况下实现即时格式转换通过..export()

到目前为止,我的代码框架类似于:

### audio.py

import queue
import sounddevice as sd
from pydub.audio_segment import AudioSegment


def input_stream(device, sample_width=2, sample_rate=44100,
        channels=1, latency=0, blocksize=2048, timeout=5.0):
    audio_queue = queue.Queue()

    def audio_callback(indata, frames, time_duration, status):
        audio = AudioSegment(indata, sample_width=sample_width,
                channels=channels, frame_rate=sample_rate)

        # Some pydub magic should happen here to convert the raw frame to mp3/ogg

        audio_queue.put(audio.raw_data)


    with sd.InputStream(samplerate=sample_rate, device=device,
                        channels=channels, callback=audio_callback,
                        latency=latency, blocksize=blocksize):
        while not recording_terminated():
            yield audio_queue.get(block=True, timeout=timeout)


### web.py

from flask import route, request, Response

from audio import input_stream


@route('/sound/stream', methods=['GET'])
def get_sound_feed():
    device = request.args.get('device')
    return Response(input_stream(device), mimetype='audio/ogg')

如何将原始AudioSegment对象转换audio_callback为适合网络流媒体的压缩 mp3/ogg?我知道可以通过 mp3 创建一个片段AudioSegment.from_file,或者通过 将其转储到 mp3 文件.export()中,但这并不是一个真正的选择,因为这样的 I/O 操作会引入不可忽略的延迟。我认为理论上可以破解.export()以将其转储到套接字或 fifo 文件描述符,但这对我来说听起来有点像 hacky 解决方法,而且我不确定文件描述符是否足以提供.write()方法,或者它是否会因为seek需要其他方法(例如)而中断。

标签: pythonaudiostreamingpydub

解决方案


我不知道您是否可以阻止pydub将文件保存到磁盘,但是您可以在转换结束时获取文件而无需重新打开它。实际上,该.export()函数在执行结束时返回文件对象。

convert_file = audio_file.export(format="flac")

我已经这样做了,我可以像使用该open()函数一样处理 convert_file。(我为自己的项目转换为 flac,但您可以使用任何格式)
我发现如果您不提供文件名,该.export()函数甚至不会将文件写入磁盘而不会出现任何错误。
我希望您能找到解决问题的方法。


推荐阅读