【问题标题】:Writing a Python Music Streamer编写 Python 音乐流媒体
【发布时间】:2011-04-16 18:21:07
【问题描述】:

我想用 Python 实现一个服务器,通过 HTTP 流式传输 MP3 格式的音乐。我希望它能够广播音乐,以便客户端可以连接到流并开始收听当前正在播放的任何内容,就像广播电台一样。

以前,我使用 SocketServer.TCPServer 在 Python 中实现了我自己的 HTTP 服务器(是的,我知道 BaseHTTPServer 存在,只是想自己编写一个迷你 HTTP 堆栈),那么音乐流媒体在架构上会有什么不同呢?我需要在网络端和 MP3 端查看哪些库?

【问题讨论】:

  • 您希望 VLC 之类的东西能够链接到流中,还是只编写自己的客户端?
  • @thenoviceoof - 好问题,是的,我希望“主流”客户端能够连接。 iTunes、Winamp、VLC 等
  • 您是实时压缩音频还是流式传输预先创建的 MP3 文件?
  • @rakslice - 我只对流式传输预先创建的压缩音频感兴趣。

标签: python http streaming mp3 shoutcast


【解决方案1】:

mp3 格式专为流式传输而设计,这使得某些事情比您预期的要简单。数据本质上是带有内置边界标记的audio frames 流,而不是文件头后跟原始数据。这意味着一旦客户端期望接收音频数据,您就可以从现有 mp3 源中的任何点开始向其发送字节,无论是实时的还是文件,客户端将同步到它找到的下一帧和开始播放音频。耶!

当然,您必须为客户端提供一种建立连接的方法。事实上的标准是 SHOUTcast (ICY) 协议。这与 HTTP 非常相似,但由于状态和标头字段不同,因此它与 Python 的内置 http 服务器库不直接兼容。您可能可以让这些库为您完成一些工作,但它们的文档化接口不足以完成它;您必须阅读他们的代码才能了解如何让他们说 SHOUTcast。

以下是一些帮助您入门的链接:

http://forums.winamp.com/showthread.php?threadid=70403

http://forums.radiotoolbox.com/viewtopic.php?t=74

http://www.smackfu.com/stuff/programming/shoutcast.html

http://en.wikipedia.org/wiki/Shoutcast

我建议从单个 mp3 文件开始作为您的数据源,让客户端-服务器连接设置和播放正常工作,然后继续处理实时源、多编码比特率、带内元数据和播放列表等问题。

播放列表通常是 .pls 或 .m3u 文件,本质上只是指向直播 URL 的静态文本文件。它们并不困难,甚至不是绝对必要的,因为许多(大多数?)mp3 流媒体客户端将接受根本没有播放列表的直播 URL。

至于建筑,这个领域非常开放。您有与 HTTP 服务器一样多的选项。螺纹?工作进程?事件驱动?由你决定。对我来说,更有趣的问题是如何与服务于多个输出流的网络处理程序(播放器)共享来自单个输入流(广播器)的数据。为了避免 IPC 和同步的复杂性,我可能会从单线程事件驱动设计开始。在 python 2 中,gevent 之类的库将为您提供very good I/O performance,同时允许您以非常易于理解的方式构建代码。在 python 3 中,我更喜欢 asyncio 协程。

【讨论】:

  • 流式传输动态生成的 .mp3 数据是否需要高级 python 编程?
【解决方案2】:

由于您已经拥有良好的 python 经验(假设您已经编写了 HTTP 服务器),我只能提供一些关于如何扩展您已经完成的基础工作的建议:

  • 准备您的服务器以处理请求标头,例如:Accept-EncodingRangeTE (Transfer Encoding) 等。MP3-over-HTTP 播放器(即 VLC)什么都不是而是一个知道如何“说出”HTTP 并“寻找”文件中不同位置的 mp3 播放器。

  • 在通过 HTTP 播放 mp3 时,使用 wireshark 或 tcpdump 来嗅探 VLC 完成的实际 HTTP 请求,这样您就知道您将如何接收并实施它们。 p>

祝你的项目好运!

【讨论】:

    【解决方案3】:

    您需要考虑提供 m3upls 文件。这应该会为您提供一种玩家能够很好理解的文件格式,以便访问您的 http 服务器以查找 mp3 文件。

    最小的 m3u 文件只是一个简单的文本文件,每行有一个歌曲 url。假设您的服务器上有以下可用 URL:

    /playlists/<playlist_name/playlist_id>
    /songs/<song_name/song_id>
    

    您将从该网址提供播放列表:

    /playlists/myfirstplaylist
    

    资源的内容就是:

    /songs/1
    /songs/mysong.mp3
    

    播放器(如 Winamp)将能够在您的 HTTP 服务器上打开 m3u 文件的 URL,然后开始播放播放列表中的第一首歌曲。要支持这一点,您所要做的就是提供 mp3 文件,就像提供任何其他静态内容一样。

    根据您要支持的客户端数量,您可能希望使用 Twisted 之类的库来研究异步 IO,以支持大量同步流。

    【讨论】:

    • 这听起来类似于我喜欢的 SHOUTcast (en.wikipedia.org/wiki/SHOUTcast)。我的问题是:如何使它工作,以便“播放列表”文件只是指向“流”而不是特定 mp3 文件的通用 URL?即使 URL 是“/somefile.mp3”,我也不想生成包含每首歌曲的播放列表。相反,我希望它是连续不断的歌曲/广告等,就像广播电台一样。事实上,这是一个很好的例子。广播电台如何从他们的网站上做到这一点,您可以在那里收听他们的现场直播?
    • 我假设他们只是继续将音频内容写入客户端 http 连接。给定的 URL 没有理由不能代表无限的数据流。如果您不关闭连接,客户端将继续收听,因此当您完成流式传输歌曲文件时,只需开始将广告写入套接字,然后再写入另一首歌曲。您能否分享一些代码,以便我们看看您的简单 HTTP 服务器,或许更具体地谈谈您需要做什么?
    • 这个答案没有解决“开始收听当前正在播放的内容,就像广播电台一样”。
    【解决方案4】:

    在走得太远之前研究这些:

    http://wiki.python.org/moin/PythonInMusic

    具体

    http://edna.sourceforge.net/

    【讨论】:

    • Edna 没有解决“开始收听当前正在播放的内容,就像广播电台一样”。
    【解决方案5】:

    您需要一个指向静态 URI(例如 http://example.com/now_playing.mp3)的 .m3u 或 .pls 文件,然后当他们要求该文件时,从歌曲中的任何位置开始向他们提供 mp3 数据。可能有一堆小问题我在这里掩饰...但是,至少正如 Forest 指出的那样,您可以开始从任何字节流式传输 mp3 数据。

    【讨论】:

    • 实际上,您几乎可以在客户提出要求时立即开始向客户发送 mp3 数据。 MP3 编码不使用文件头。
    • 嗯,很有趣。你是对的,它是整个文件中交错的标题/数据。但是,这样做会错过任何 ID3 标签,我的主要观点是,您可能根本不应该从任何字节位置开始,您必须从其中一个标题开始。
    • 您绝对应该从任何字节位置开始。该格式正是为此而设计的。同步位存在于每个帧中,专门用于此目的。
    • 好的,我改了答案。谢谢
    • 您如何知道请求的是哪个帧?我想跟踪在 mp3 文件中播放的帧。
    猜你喜欢
    • 2013-03-07
    • 1970-01-01
    • 1970-01-01
    • 2012-06-07
    • 2013-02-25
    • 2012-05-17
    • 2016-02-08
    • 1970-01-01
    • 2014-05-12
    相关资源
    最近更新 更多