public static async Task <ShoutcastStream> ConnectAsync(Uri serverUrl,
                                                                ShoutcastStreamFactoryConnectionSettings settings)
        {
            //http://www.smackfu.com/stuff/programming/shoutcast.html

            ShoutcastStream shoutStream = null;

            ShoutcastStreamFactoryInternalConnectResult result = await ConnectInternalAsync(serverUrl, settings);

            SocketWrapper socketWrapper = SocketWrapperFactory.CreateSocketWrapper(result);

            shoutStream = new ShoutcastStream(serverUrl, settings, socketWrapper);

            string httpLine = result.httpResponse.Substring(0, result.httpResponse.IndexOf('\n')).Trim();

            if (string.IsNullOrWhiteSpace(httpLine))
            {
                throw new InvalidOperationException("httpLine is null or whitespace");
            }

            var action = ParseHttpCodeAndResponse(httpLine, result.httpResponse, shoutStream);

            //todo handle when we get a text/html page.


            if (action != null)
            {
                switch (action.ActionType)
                {
                case ConnectionActionType.Success:
                    var headers = ParseResponse(result.httpResponse, shoutStream);
                    await shoutStream.HandleHeadersAsync(headers);

                    return(shoutStream);

                case ConnectionActionType.Fail:
                    throw action.ActionException;

                case ConnectionActionType.Redirect:
                {
                    //clean up.
                    shoutStream.Dispose();

                    return(await ConnectAsync(action.ActionUrl, settings));
                }

                default:
                    socketWrapper.Dispose();
                    throw new Exception("We weren't able to connect for some reason.");
                }
            }
            else
            {
                socketWrapper.Dispose();
                throw new Exception("We weren't able to connect for some reason.");
            }
        }
        internal ShoutcastStream(Uri serverUrl, ShoutcastStreamFactoryConnectionSettings settings, SocketWrapper socketWrapper)
        {
            this.socket         = socketWrapper;
            this.serverUrl      = serverUrl;
            this.serverSettings = settings;

            StationInfo       = new ServerStationInfo();
            AudioInfo         = new ServerAudioInfo();
            cancelTokenSource = new CancellationTokenSource();
            //MediaStreamSource = new MediaStreamSource(null);
            streamProcessor = new ShoutcastStreamProcessor(this, socket);
        }
        internal static async Task <ShoutcastStreamFactoryInternalConnectResult> ConnectInternalAsync(Uri serverUrl,
                                                                                                      ShoutcastStreamFactoryConnectionSettings settings)
        {
            //abstracted the connection bit to allow for reconnecting from the ShoutcastStream object.

            ShoutcastStreamFactoryInternalConnectResult result = new ShoutcastStreamFactoryInternalConnectResult();

            result.socket = new StreamSocket();
            result.socket.Control.QualityOfService = SocketQualityOfService.LowLatency;

            await result.socket.ConnectAsync(new Windows.Networking.HostName(serverUrl.Host), serverUrl.Port.ToString());

            result.socketWriter = new DataWriter(result.socket.OutputStream);
            result.socketReader = new DataReader(result.socket.InputStream);

            //build a http request

            string portStr = "";

            switch (serverUrl.Scheme.ToLower())
            {
            case "http":
                portStr = serverUrl.Port != 80 ? ":" + serverUrl.Port : "";
                break;

            case "https":
                portStr = serverUrl.Port != 443 ? ":" + serverUrl.Port : "";
                throw new NotImplementedException("https streams are currently not supported.");
                break;
            }

            StringBuilder requestBuilder = new StringBuilder();

            requestBuilder.AppendLine("GET " + serverUrl.LocalPath + settings.RelativePath + " HTTP/1.1");
            if (settings.RequestSongMetdata)
            {
                requestBuilder.AppendLine("Icy-MetaData: 1");
            }
            requestBuilder.AppendLine("Host: " + serverUrl.Host + portStr);
            requestBuilder.AppendLine("Connection: Keep-Alive");
            requestBuilder.AppendLine("User-Agent: " + settings.UserAgent);
            requestBuilder.AppendLine();

            //send the http request
            result.socketWriter.WriteString(requestBuilder.ToString());
            await result.socketWriter.StoreAsync();

            await result.socketWriter.FlushAsync();

            //start reading the headers from the response
            string response = string.Empty;

            while (!response.EndsWith(Environment.NewLine + Environment.NewLine))
            //loop until we get the double line-ending signifying the end of the headers
            {
                await result.socketReader.LoadAsync(1);

                response += result.socketReader.ReadString(1);
            }

            result.httpResponse = response;

            return(result);
        }