I'm making a shoutcast server in Java and I've a hit a bump in the road. My server can stream data well if I send the client (VLC/WINAMP) an HTTP response:
HTTP/1.1 200 OK\r\nContent-Type:audio/mpeg\r\n\r\n\
and then start streaming the files, However, when I send the client an ICY response, the sound starts getting a little bit choppy and squeaky and sometimes plays a little bit fast. Sometimes it plays little bits of chunks from all the songs in the playlist at the same time but if I disconnect the client and connect again it plays properly, properly in this case being a little bit choppy and squeaky. I've tried to connect to shoutcast servers on the internet and they seem flawless. (I'm also sending my data in 24kb chunks)
Here's my ICY response
String respond = "ICY 200 OK\r\n"
+"icy-notice1: <BR> This stream requires"
+ "<a href=\"http://www.videolan.org/\">VLC</a><BR>\r\n"
+ "icy-notice2: Lee Shoutcast<BR>\r\n"
+ "icy-name: Lee's Mix\r\n"
+ "icy-genre: Rock\r\n"
+ "icy-url: http://localhost:9025\r\n"
+ "content-type: audio/mpeg\r\n"
+ "icy-pub: 1\r\n"
+ "icy-metaint: 24576\r\n"
+ "icy-br: 96\r\n\r\n";
I've done a little bit of reading and found out that I have to send the client data in the format Header|DataChunk|Header..... so I looked up how to do the header and came up with this as a test run to see if it would remedy the choppiness.
String header = "";
String heading ="StreamTitle='The year of the ram';"
+ "StreamUrl='someaddress:9025';";
byte []headingBytes = heading.getBytes();
int NumberOfBlocks = ((headingBytes.length - 1) / 16) + 1;
int toPad = NumberOfBlocks*16 - headingBytes.length;
header = NumberOfBlocks + "StreamTitle='The year of the ram';"
+ "StreamUrl='http://someaddress:9025';";
String finalStr = header + padding(toPad);
System.out.println(finalStr);
byte []finalByte = finalStr.getBytes();
return finalByte;
Padding method just adds zeros to the right of the string:
public String padding(int numberOfPads)
{
String ret = "";
for(int i = 1; i <= numberOfPads; i++)
{
ret += "0";
}
return ret;
}
The resulting string is:
5StreamTitle='The year of the ram';StreamUrl='http://someaddress:9025';000000000000
I then convert the String to bytes and write those header bytes to the stream then write my 24kb chunk and then header and so on. This doesn't seem to help the situation at all. Is there something I'm doing wrong with SHOUTcast since it works perfectly well with ICEcast ?
P.S I know the code looks a bit messy and could be better but this was just a test. I am also sending this constant string as a test to see if it helps. The plan was to do it properly If it worked.
Any help is appreciated.
My information was acquired from
- http://ample.sourceforge.net/developers.shtml
- http://www.smackfu.com/stuff/programming/shoutcast.html
EDIT:
This is how I am determining when to send the bytes (this code is in a while(true) loop)
buffer = new byte[24576];
//read the file into the buffer
bytesRead = song.read(buffer);
//start streaming the file.
outputStream.write(buffer);
24KB of the song are read into the buffer then written to the output stream. I deleted the bit of code that wrote the metadata but I was writing the metadata before outputStream.write(buffer).
VLC and wimamp do send icy-metadata = 1.