6

I'm trying to write a Python server that streams one requested mp3 file from start to end. (No live streaming)
I'd like to have the functionality to play that stream with any media player (like VLC) and be able to change playback position.

I've heard a lot about HTTP Streaming, but after reading a few wikipedia articles it seems to me that 'HTTP Streaming' is just an umbrella term for different streaming protocols such as RTSP/RTCP/RTP.

Then I came across SHOUTcast which is a proprietary software (server!) for streaming media using its own protocol. Another existing server program which seems to offer similiar functionality is Icecast.
I'm not really sure on the relationship between SHOUTcast and Icecast, but there seems to be one.

I figured streaming one specific media file couldn't be that different from streaming a continuous stream like a web-radio so I googled the first webradio and downloaded a .pls or .m3u file.
Both basically were textfiles containing a url. So i started wireshark and pointed VLC to that url.
What I saw was essentially HTTP Traffic:

VLC:

GET /schizoid HTTP/1.1

VLC:

Host: <ip>:8000
User-Agent: VLC/2.0.5 LibVLC/2.0.5
Range: bytes=0-
Connection: close
Icy-MetaData: 1

Server responded:

HTTP/1.0 200 OK
Content-Type: audio/mpeg
icy-br:128
ice-audio-info: bitrate=128
icy-br:128
icy-description:PsyTrance 24x7
icy-genre:psytrance
icy-name:Radio Schizoid
icy-pub:1
icy-url:http://schizoid.in:8000/schizoid
Server: Icecast 2.3.2
Cache-Control: no-cache
icy-metaint:16000

Then the server begins sending raw data, which seems to be the mp3 stream.

According to Wikipedia this is the SHOUTcast protocol.
(Im not sure wether this is the same protocol that Icecast uses)

But I figured a closed (not documented) protocol couldn't possibly be the standard for streaming media.
So my Question is what's the best (easiest and best supported) way to integrate streaming (specific mp3 files) into a python server ?
Do I have to manually implement the SHOUTcast protocol or is something like RTP the way to go?
(I don't mind using a third-party library)

Ansgar
  • 371
  • 3
  • 15
  • 1
    The Wikipedia page for `icecast` that you linked to explicitly says "The Icecast server is capable of streaming content as… MP3 over the protocol used by SHOUTcast…" And the SHOUTcast protocol headers that you captured clearly say `Server: Icecast 2.3.2`, too. – abarnert May 24 '13 at 20:59
  • 1
    Anyway, there is no protocol in the world that can "play that stream with any media player". Icecast can play to a pretty wide variety of players, but certainly not _everything_. HTML5 and/or Flash (whether RTMP, RTMFP, or HTTP) or Silverlight streaming can play to most web browsers, but not many other clients. What's appropriate depends on your use case, which you haven't really described. – abarnert May 24 '13 at 21:04
  • Ultimately, it sounds like your question is "What's the best streaming protocol", which is exactly the kind of thing that the [FAQ](http://stackoverflow.com/faq) describes as "not a good fit for this site". – abarnert May 24 '13 at 23:01
  • When I wrote 'media players' I wasn't thinking about Browsers, sorry. I'm trying to build a server that gets request (IDs not actual filenames) from clients (client and server share a database containing infos about what ID is what song) I will be writing my own client application, but I wanted to use the protocol that is most widespread. (I don't think there is __anything__ that __all__ media players support) I'm asking what the best (easiest to implement in python server) streaming protocol is to do that. (I'm not really looking forward to implement an reverse-enginrd undocum. protocol) – Ansgar May 24 '13 at 23:23
  • Is there a reason you need to actually serve the data from Python, as opposed to, say, just controlling a stock icecast server? (On the _client_ side, the ice library has great bindings.) – abarnert May 24 '13 at 23:34
  • Meanwhile, "radio"-style streaming audio that plays to open clients is really not that popular anymore; closed systems like Pandora, MOG, Rhapsody, IHeartRadio, etc. have pretty much replaced it. But Icecast was among the most popular in its heyday, and it can broadcast to iTunes, VLC, and WinAmp, which is very handy for testing (until your own client is finished and solid). – abarnert May 24 '13 at 23:37
  • I'm not quite sure how this question is "not constructive". The question is quite clear, and the focus is narrow. There are specific requirements, and there are very few correct answers. I'm voting to reopen, and suggest you do as well. – Brad May 26 '13 at 07:59
  • The reason why I don't just control a stock icecast server is that I just want to deploy an application and walk away. I don't want to deal with different installations or different configurations of icecast servers. But, nevermind Brads answer answered all my questions, thanks Brad :) – Ansgar May 29 '13 at 14:26

1 Answers1

5

The SHOUTcast client protocol is effectively the same as HTTP/1.0. The only relevant difference is the response status line:

ICY 200 OK

Instead of HTTP/1.0, you get ICY. That's really it! From there, it behaves the same. Web browsers, and most HTTP clients ignore this. Android chokes on it, and some browsers, but most are fine. Icecast's client stream behavior is the same as SHOUTcast's, except that it actually returns HTTP/1.0 200 OK for its status line.

Now, you have noticed in those response headers, there are some extra headers with stream information. All but one are just extra information that don't have any impact on the data you're getting back. If you request no metadata, then the server does nothing but take every byte sent to it from the source, and relay it on to each client (with a little server-side buffer as well).

If in your request headers, you specify Icy-MetaData: 1, then the behavior changes slightly. In the response, you will get Icy-MetaInt: 8192 or similar. This means that every 8,192 bytes, there will be a chunk of metadata. Sometimes that chunk is just 0x00 which means that there is no metadata update. Other times there will be a byte like 0x01. If you multiply that value by 16, you know that the next 16 bytes will be ASCII metadata, like StreamTitle: 'My Stream';StreamUrl='';, padded by 0x00. I've described the metadata in more detail in another post, if you are curious.

All of this to say is that the most popular streaming protocol is in fact HTTP, and SHOUTcast/Icecast/many other servers have added a request header where you can get metadata interleaved into the stream. HTTP clients that don't request that metadata will just get a regular MP3 stream, which a browser will think is just some file somewhere. Afterall, the browser doesn't care how you get the data.

Now, what should you be using? Your requirement:

I'm trying to write a Python server that streams one requested mp3 file from start to end. (No live streaming)

HTTP is all you need. In fact, no need to write some server for this. Apache/Nginx/whatever will work fine. Just a simple HTTP server! If you want to serve up files by ID, that's where your Python comes in. Write something that goes and fetches the appropriate resource from disk, based on that ID. I wouldn't bother with RTSP for this... that is way too much overhead for what you need, and you will be hurting client compatibility.

I'd like to have the functionality to play that stream with any media player (like VLC) and be able to change playback position.

For that requirement, just make sure your server supports range requests. The client will take care of the rest.

Summing this all up

  • SHOUTcast/Icecast servers are for "live" radio-like streams where all the clients get the same audio stream at (roughly) the same time
  • HTTP is the most compatible protocol for delivering anything to the client, streaming or not
  • RTSP/RTMP/RTP and all related protocols are not necessary unless you are streaming a long-running or live stream where variable bitrate based on client bandwidth availability is important. (There are other features of these protocols, but this seems to be the deciding factor for choosing them. I recommend reading up on each if you want more info.)
Community
  • 1
  • 1
Brad
  • 159,648
  • 54
  • 349
  • 530