Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Getting bytes from continuous streams on Windows Phone 7

DZone's Guide to

Getting bytes from continuous streams on Windows Phone 7

· Mobile Zone ·
Free Resource

When it comes to getting data from the web in a Windows Phone 7 application, it is pretty easy to implement a downloading layer via asynchronous calls (synchronous web calls are not allowed), be it through WebClient or HttpWebRequest. That works well when the data is defined by a specific size restraint – to be specific, when it is known what amount is to be downloaded. In a standard situation, once the async callback is triggered, it means that the response is there ready to processed and all the needed data was downloaded and is kept in memory.

It is tempting to check the response for content length and that makes sense for content that is downloaded and remains exactly in the state it was obtained. For example, if I would be downloading a JPEG image from a remote location, my response would look like this (click to enlarge):

image

To better understand the process, take a look at this workflow scheme that shows the way a HttpWebRequest is executed:

image

When there is a fixed amount of data, the asynchronous callback is only triggered when the data is downloaded. Therefore, all you have to do is handle the response inside the callback (e.g. store the content or display it in a separate control).

And despite the common understanding of the process, it might be a bit tricky when it comes to continuous streams, since the response is sent almost instantly and HttpWebRequest recognizes it as a complete response, while in reality you should not be looking at the response itself – it won’t be even close to what you would expect to be there. To show exactly what I am talking about, take a look at the HttpWebRequest instance I get when I am trying to get data from a continuous stream [SHOUTcast] (click to enlarge):

image

The ContentLength property is not something you want to see there. But what exactly is happening? The response is actually correct. –1 means that the response hasn’t a fixed length declared but is dynamic, therefore it would make no sense to return the actual length. My initial thought was to use WebClient instead and obtain the byte buffer via reflection from an instance that was preforming the data download (since that field is not accessible by default). But that would be almost impossible due to access limitations inside the class, so obviously it wasn’t the way to go.

What did I do in this case? Read the stream that is received through the response (also known as the response stream).

To give a specific example, I am trying to obtain data from a SHOUTcast stream:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://78.159.104.183:80/;");

request.AllowReadStreamBuffering = false;

request.Method = "GET";

request.BeginGetResponse(new AsyncCallback(GetShoutAsync), request); 

Inside the async callback, I actually create a temporary byte buffer that gets the data from the response stream:

void GetShoutAsync(IAsyncResult res)

{

HttpWebRequest request = (HttpWebRequest)res.AsyncState;

HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(res);

Stream r = response.GetResponseStream();

byte[] data = new byte[4096];

int read;

while ((read = r.Read(data, 0, data.Length)) > 0)

{

Debug.WriteLine(data[0]);

}

} 

That way, I can continuously read data from the stream on a Windows Phone 7 device. This can be handy when used to stream audio data (like I mentioned – SHOUTcast) and any data that is passed in a continuous stream rather than in a fixed-length block. However, I must warn you that on a data plan, an operation like this might be a bit “bandwidth-expensive” so make sure you don’t buffer too much at once and that the user is aware of the continuous streaming mechanism.

Topics:

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}