I'm working on a software to stream audio from a source over HTTP using a Flask webservice. I can get the sound frames through sounddevice
and route them to a browser through a Flask route with yield
and the right mimetype, but the raw audio format is quite cumbersome for remote streaming, and not really the best when it comes to client compatibility.
我正在开发一个软件,使用FlaskWeb服务通过HTTP从一个来源流传输音频。我可以通过SoundDevice获得声音帧,然后用Year和正确的Mimetype将它们通过Flask路由发送到浏览器,但原始音频格式对于远程流媒体来说相当麻烦,而且在客户端兼容性方面也不是最好的。
I'd love to use pydub
to convert the raw audio frames to a format like mp3 or ogg, but it's not clear to me neither from the documentation nor from the source code how to achieve an on-the-fly format conversion without dumping the output to a file through .export()
.
我很乐意使用pydub将原始音频帧转换为mp3或ogg等格式,但无论是从文档还是从源代码来看,我都不清楚如何实现即时格式转换,而无需通过.export()将输出转储到文件。
The skeleton of my code so far is something like:
到目前为止,我的代码框架类似于:
### 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')
How would one convert the raw AudioSegment
object in audio_callback
into a compressed mp3/ogg suitable for web streaming? I know that it's possible to create a segment from an mp3 through AudioSegment.from_file
, or dump it to an mp3 file through .export()
, but that wouldn't really be an option as such I/O operations would introduce non-negligible latency. I think it might be theoretically possible to hack .export()
to get it to dump to a socket or fifo file descriptor, but that sounds a bit as a hacky workaround to me, plus I'm not sure whether it's sufficient for the file descriptor to provide the .write()
method or if it'd break because other methods (e.g. seek
) are required.
如何将AUDIO_CALLBACK中的原始AudioSegment对象转换为适合Web流媒体的压缩mp3/ogg?我知道可以通过AudioSegment.from_file从mp3创建段,或者通过.export()将其转储到mp3文件,但这不是一个真正的选择,因为这样的I/O操作将引入不可忽略的延迟。我认为从理论上讲,可以破解.export()以将其转储到套接字或FIFO文件描述符,但对我来说,这听起来有点像是一种老套的解决办法,此外,我不确定文件描述符提供.write()方法是否足够,或者它是否会中断,因为需要其他方法(例如查找)。
更多回答
I've bumped into this question from 2014: stackoverflow.com/questions/25469161/…. The last comment seems to confirm my suspicion that exporting on-the-fly (not to a file) is not an option in pydub. I'm not sure if any progress has been made in the meantime or if some user has already made a fork to support it. If that's not the case, I might give it a try and submit a PR to pydub.
我从2014年就遇到了这个问题:Stackoverflow.com/Questions/25469161/…。最后一条评论似乎证实了我的怀疑,即动态导出(不是导出到文件)不是pydub中的选项。我不确定在此期间是否取得了任何进展,或者是否有一些用户已经做出了支持它的分支。如果不是这样,我可能会试一试,向PYDUB提交一份公关。
have you found how to do this? I'm trying to save the file in a BytesIO to remove the persistence aspect
你找到怎么做了吗?我正在尝试将文件保存在BytesIO中,以删除持久性方面
优秀答案推荐
I don't know if you can prevent pydub from saving the file to the disk, but you can just get the file at the end of conversion without reopen it.
Actually, the .export()
function return the file object at the end of execution.
我不知道你是否可以阻止pydub将文件保存到磁盘上,但你可以在转换结束时获得文件,而不需要重新打开它。实际上,.EXPORT()函数在执行结束时返回文件对象。
convert_file = audio_file.export(format="flac")
I have done this and I could process the convert_file as if I had used the open()
function. (I convert to flac for my own project but you can do any format)
I found out that if you don't provide a file name, the .export()
function wont even write the file to disk without any errors.
I hope you can found a workaround for your issue.
我已经这样做了,我可以处理转换文件,就像我使用了Open()函数一样。(我为我自己的项目转换为FLAC,但您可以执行任何格式)。我发现,如果您不提供文件名,.EXPORT()函数甚至不会毫无错误地将文件写入磁盘。我希望您能找到解决您的问题的方法。
In case anyone is interested.
One can use a BytesIO object to export a converted file into an in-memory object.
如果有人感兴趣的话。可以使用BytesIO对象将转换后的文件导出到内存对象中。
# Load input song
song = from_mp3("my_song.mp3")
# create new empty BytesIO
exported_io = BytesIO()
# export to BytesIO object
song.export(exported_io, format="wav")
One can then perform any action on this BytesIO object. No file will be created using this approach.
然后,用户可以对该BytesIO对象执行任何操作。不会使用此方法创建任何文件。
更多回答
我是一名优秀的程序员,十分优秀!