Click here to Skip to main content
Click here to Skip to main content
Go to top

ShoutcastStream Class

, 10 Jun 2007
Rate this:
Please Sign up or sign in to vote.
A ShoutcastStream class for receiving Shoutcast media streams.

Introduction

This article describes a class for receiving Shoutcast streams. For some background information, look at this short protocol description, or visit the Shoutcast website.

Background

In my last project, I had to receive, capture, and play Shoutcast streams. I looked for some ready to use implementations, but didn't find any, so I decided to write my own.

Using the Code

Because it's a relatively simple protocol, the code is also quite simple, but it does what it should. Smile | :)

For the best interoperability to other classes (e.g., for DirectSound playing it), I derived from the abstract Stream, so other classes that can handle streams can handle my stream too.

/// <span class="code-SummaryComment"><summary></span>
/// Creates a new ShoutcastStream and connects to the specified Url
/// <span class="code-SummaryComment"></summary></span>
/// <span class="code-SummaryComment"><param name="url">Url of the Shoutcast stream</param></span>
public ShoutcastStream(string url)
{
  HttpWebResponse response;
  HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
  request.Headers.Clear();
  request.Headers.Add("Icy-MetaData", "1");
  request.KeepAlive = false;
  request.UserAgent = "VLC media player";

  response = (HttpWebResponse)request.GetResponse();
  metaInt = int.Parse(response.Headers["Icy-MetaInt"]);
  receivedBytes = 0;

  netStream = response.GetResponseStream();
  connected = true;
}

In the constructor, the connection is established. Therefore, we have to put a new field into the HTTP request, Icy-MetaData:1. We also set the UserAgent to "VLC Media Player" (we can also use WinAmp etc.) because some Shoutcast servers behave different with different UserAgents.

After we get the response, we read out the Icy-MetaInt value. This is the value that shows how many data bytes we receive before the server will send a metainfo block.

/// <span class="code-SummaryComment"><summary></span>
/// Reads data from the ShoutcastStream.
/// <span class="code-SummaryComment"></summary></span>
/// <span class="code-SummaryComment"><param name="buffer">An array of bytes to store</span>
///         the received data from the ShoutcastStream.<span class="code-SummaryComment"></param></span>
/// <span class="code-SummaryComment"><param name="offset">The location in the buffer</span>
///         to begin storing the data to.<span class="code-SummaryComment"></param></span>
/// <span class="code-SummaryComment"><param name="count">The number of bytes</span>
///         to read from the ShoutcastStream.<span class="code-SummaryComment"></param></span>
/// <span class="code-SummaryComment"><returns>The number of bytes read from the ShoutcastStream.</returns></span>
public override int Read(byte[] buffer, int offset, int count)
{
  try
  {
    if (receivedBytes == metaInt)
    {
      int metaLen = netStream.ReadByte();
      if (metaLen > 0)
      {
        byte[] metaInfo = new byte[metaLen * 16];
        int len = 0;
        while ((len += netStream.Read(metaInfo, len, 
                metaInfo.Length - len)) < metaInfo.Length) ;
        ParseMetaInfo(metaInfo);
      }
      receivedBytes = 0;
    }
    int bytesLeft = ((metaInt - receivedBytes) > count) ? 
                      count : (metaInt - receivedBytes);
    int result = netStream.Read(buffer, offset, bytesLeft);
    receivedBytes += result;
    return result;
  }
  catch (Exception e)
  {
    connected = false;
    Console.WriteLine(e.Message);
    return -1;
  }
}

If the requested count of bytes is less than the remaining bytes before the next metainfo block, we will read as much bytes as requested. But if there are less bytes before the next metainfo block as the user has requested, we will only read the remaining bytes and return. When the user calls Read the next time, we fill first receive the metainfo block and then continue reading the media data from the stream.

Every time a metainfo block is received, the current stream title is extracted. If the stream title changes, the corresponding event is fired.

Note

Before using this in your application, you have to extend your App.config by the following:

<configuration>
  <system.net>
    <settings>
      <httpWebRequest useUnsafeHeaderParsing ="true"/>
    </settings>
  </system.net>
</configuration>

Points of Interest

If someone is interested in playing a Shoutcast stream using Managed DirectSound (pure .NET), ask for it. Perhaps, I'm going to write an article about that.

History

  • 1.0 - Initial revision (10 June 2007)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Dirk Reske
Software Developer
Germany Germany
After I worked for 12 Months as Java developer in a litte company, I worked at a global directoy publishing company (also as Java developer).
 
At the moment I'm studying Information Technologies.
 
My favorite areas are network and internet programming.

Comments and Discussions

 
NewsOpenSource Audio library and Server Shoutcast [modified] PinmemberDAXweb_IT31-Jul-07 6:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140921.1 | Last Updated 10 Jun 2007
Article Copyright 2007 by Dirk Reske
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid