Help - Search - Members - Calendar
Full Version: Streaming MP3s to shoutcast
Hydrogenaudio Forums > Lossy Audio Compression > MP3 > MP3 - Tech
Xoph
I'm programming a new application thats acts as a digital jukebox. It will replace the winamp/dsp plugin combo and connect directly to a shoutcast server to broadcast music. I have alot of it done, but theres just one small problem i need solved.

Depending on the bitrate and the frequency of the mp3 that i'm sending, i'll need to change the way i send the mp3 data. Right now, with songs encoded at low quaility (11025Hz @ 64kbit) I'm sending an array of 4096 bytes every 500 miliseconds (ie 8 kilobytes per second). This works well for this particular quality setting. But if i later on decide to change the quality (maybe make it better) I'm sure the time delay will have to change from 500 miliseconds to somthing else.

What i need now is a way to find out the time to wait between each 4096 bytes sent, where i know the bitrate and frequency of the mp3s i'm sending.

I may be overcomplicating things a bit (maybe its a simple formula using the bitrate?) but getting this special formula would be wonderful. Thanks for all your help smile.gif
maikmerten
hmmmm.... why not use libshout? http://www.icecast.org/download.php

example in python (C will be similiar with more code wink.gif ):

CODE
#!/usr/bin/python
#
# Simple streaming to icecast.
#
# Daniel Holth, 2004

import sys
import shoutpy

s           = shoutpy.Shout()
s.user      = "source"
s.password  = "hackme"
s.mount     = "/shoutpy.ogg"
s.port      = 8001
s.format    = shoutpy.FORMAT_VORBIS

s.open()

for arg in sys.argv[1:]:
   f = open(arg, "rb")

   buf = f.read(4096)

   while buf:
       s.send(buf)
       buf = f.read(512)
       s.sync()

   f.close()

s.close()
freakngoat
Actually, the way most Shoutcast servers seem to work is by dumping the data on you as fast as you can receive it--much faster than the rate at which it is being played. This takes full advantage of the buffering used on the client end.

In implementing my embedded MP3 player project, the way I controlled flow was letting the TCP driver do it for me. If I stopped reading from the TCP input stream, the TCP window would gradually shrink--not allowing the sender to send more data than I could handle.

So in your server, you could use the same technique. Your TCP socket driver should have a way to determine whether its okay to write to the socket (perhaps it will block until the write is complete, or you can poll it)--thus your application can write to the socket whenever it can. This is actually much simpler than using a timer.
Xoph
First of all, I'm trying not to use any third party programs/libraries if possible. I'm already using the lame encoder to get all the files i play on the same bitrate/frequency at runtime.

Secondly, are you serious about putting as much out to shoutcast as possible?

I tried my same code with a 10 milisecond delay, and i heard the music started to skip, almost as if my client (or shoutcast) was skipping ahead to catch up with all the data i was sending. I'm pretty sure that i'm supposed to put in a delay and let the shoutcast server take in all the music as fast as it needs to be, maybe a tad faster.

I've noticed that if i put the delay too high (greater pauses between chunks), my client would have to frequently need to rebuffer (cause data wasn't coming fast enough). If i put the delay too low (smaller pauses between chunks) then it seems i'm sending the information too fast, causing the music to skip ahead dramatically (ie: trying to catch up with the fast incoming data).

Anyone else got any ideas?
freakngoat
What are you using as a client? TCP should handle the flow control for you...

Try sniffing a real Shoutcast session from a third-party server and a client. You normally see the server dumping data to the client at a rate greater than playback until the client's buffer fills up, at which time the rate will average out to the playback rate...

This method allows the client's buffer to be as full as possible as much of the time as possible... Imagine if you sent the data at exactly the same rate as you played it at (which is what your timer method does). Any network latency would result in the client buffer being drained, but not filled up, eventually depleting it completely. There has to be some sort of flow control between the client and the server--there really should be some client feedback that says, "hey, I'm ready for data." With Shoutcast, there is no application layer flow control (there's hardly any application layer anything); it relies on TCP for this.

EDIT: If you're not using a packet sniffer yet, that will help you immensly. Try Ethereal; its free...
Xoph
QUOTE (freakngoat @ Mar 10 2005, 09:33 PM)
What are you using as a client? TCP should handle the flow control for you...

Try sniffing a real Shoutcast session from a third-party server and a client. You normally see the server dumping data to the client at a rate greater than playback until the client's buffer fills up, at which time the rate will average out to the playback rate...

This method allows the clients buffer to be as full as possible as much of the time as possible... Imagine if you sent the data at exactly the same rate as you played it at (which is what your timer method does). Any network latency would result in the client buffer being drained, but not filled up, eventually depleting it completely. There has to be some sort of flow control between the client and the server--there really should be some client feedback that says, "hey, I'm ready for data." With Shoutcast, there is no application layer flow control (there's hardly any application layer anything); it relies on TCP for this.

EDIT: If you're not using a packet sniffer yet, that will help you immensly. Try Ethereal; its free...
*


so i should just flood (output as much as possible) the output stream buffer and let tcp and the client handle the rest?
freakngoat
QUOTE (Xoph @ Mar 10 2005, 07:37 PM)
so i should just flood (output as much as possible) the output stream buffer and let tcp and the client handle the rest?
*


Yes. What are you using for a client BTW?

EDIT: Don't overflow your output buffer however--you need to make sure that when you write to it, it is able to accept your write. This depends on your socket driver--it may block, or you may poll it, or whatever... If you overflow your output buffer you will experience skipping...
Xoph
QUOTE (freakngoat @ Mar 10 2005, 09:44 PM)
QUOTE (Xoph @ Mar 10 2005, 07:37 PM)
so i should just flood (output as much as possible) the output stream buffer and let tcp and the client handle the rest?
*


Yes. What are you using for a client BTW?

EDIT: Don't overflow your output buffer however--you need to make sure that when you write to it, it is able to accept your write. This depends on your socket driver--it may block, or you may poll it, or whatever... If you overflow your output buffer you will experience skipping...
*




ahh, so maybe thats why it was skipping, i was sending TOO much

so i need to poll the buffer, and make sure its ready for more data, right?

oh, i'm using winamp 2.8 as my client lol you'll never get me to change it, i love 2.8
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2009 Invision Power Services, Inc.