We recently got a new kitchen radio (a Christmas present my wife and I bought for ourselves) and it is a lovely little device. It features:

plain old FM radio stations

also Web radio

Spotify Connect

network media playback

podcast discovery and playback

The only thing it lacks is a remote control, which is apparently considered unnecessary since there is an app for this device.

As so often, this app is not available for Windows or Windows Phone.

So, once again, I decided to do some network recording using my favorite tool, some protocol reverse engineering and crafting my very own Windows Phone app for this device.

Locating the Device on the Network

The first interesting challenge was discovering this new device on the network. Actually this turned out to be quite the challenge, and it’ the main reason I decided to write this blog post about it.

The radio uses SSDP (Simple Service Discovery Protocol) to announce its presence and services on the network, which (fortunately) is a common and standardized behavior for devices like that.

SSDP uses HTTP over UDP (HTTPU) to request or announce service data.

A typical SSDP M-SEARCH request asking for “all kinds of services” on a network looks like this (frame data copied from Microsoft Network Monitor):

- http: Request, M-SEARCH *

Command: M-SEARCH

- URI: *

Location: *

ProtocolVersion: HTTP/1.1

ST: ssdp:all

MX: 3

MAN: "ssdp:discover"

Host: 239.255.255.250:1900

HeaderEnd: CRLF

A device responds in the same format with an additional LOCATION header, which usually points to a URL that contains further metadata about the device:

- http: Response, HTTP/1.1, Status: Ok, URL:

ProtocolVersion: HTTP/1.1

StatusCode: 200, Ok

Reason: OK

ST: urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1

USN: uuid:bb418659-8b41-4247-9cb4-f7a4719d4cb2::urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1

Location: http://192.168.1.149:2869/upnphost/udhisapi.dll?content=uuid:bb418659-8b41-4247-9cb4-f7a4719d4cb2

OPT: " http://schemas.upnp.org/upnp/1/0/"; ns=01

01-NLS: 01d397012d31c69c18df286a97210895

Cache-Control: max-age=900

Server: Microsoft-Windows/6.3 UPnP/1.0 UPnP-Device-Host/1.0

Ext:

HeaderEnd: CRLF

It’s interesting how many devices on a typical local network will advertise their services that way. I “discovered” my Xbox One, two routers, a couple of PCs and laptops in addition to the actual radio answering my request.

Implementing the Protocol

Let’s have a look at the actual SSDP protocol implementation for a Windows Phone Universal app.

First, we create an instance of a DatagramSocket (UDP) and register an event handler for receiving data.

_socket = new DatagramSocket(); _socket.MessageReceived += HandleMessageReceived;

Then, we need to bind the socket to a local port and prepare it for multicast usage. Hard-coding the local port is currently a weak point of this implementation and I will have to find a better solution to do that.

await _socket.BindServiceNameAsync(6000); _socket.JoinMulticastGroup(new HostName("239.255.255.250"));

The next step is opening an output stream to a multicast endpoint and sending the request data. It’s not a lot of code, but the UDP multicast API is poorly documented and it’s critical to use the right set of API calls in the correct order here.

Because of its simplicity, the SSDP message is hard-coded here. Note: the ST part of the headers is the specific service ( urn:schemas-frontier-silicon-com:fs_reference:fsapi:1 ) we are requesting to found the Internet Radio device.

var s = await _socket.GetOutputStreamAsync(new HostName(239.255.255.250), "1900"); using (var dataWriter = new DataWriter(s)) { var msg = "M-SEARCH * HTTP/1.1\r

" + "HOST:239.255.255.250:1900\r

" + "MAN:\"ssdp:discover\"\r

" + "ST:urn:schemas-frontier-silicon-com:fs_reference:fsapi:1\r

" + "MX:3\r

\r

"; var data = Encoding.UTF8.GetBytes(msg); dataWriter.WriteBytes(data); await dataWriter.StoreAsync(); }

After that, we expect the HandleMessageReceived event handler to get called, in which we can process the response.

private void HandleMessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args) { var reader = args.GetDataReader(); var data = new byte[reader.UnconsumedBufferLength]; reader.ReadBytes(data); var s = Encoding.UTF8.GetString(data, 0, data.Length); // TODO ParseResponse(s); }

That’s everything we need to make first contact with our device on the network. The LOCATION header contains a URL which again returns a bit of XML describing the device further. We get:

a “friendly” name

it’s software version

and the base URL for its Web API.

<netRemote> <friendlyName>DUAL IR6 002261c53c78</friendlyName> <version>ir-mmi-FS2026-0500-0095_V2.6.17.EX53300-1RC5</version> <webfsapi>http://192.168.1.144:80/fsapi</webfsapi> </netRemote>





Dude, where’s the Code?

The code for the SSDP implementation will probably end up in my development framework Newport, since I can see its general usefulness. Meanwhile you can use the code in the snippets since it’s completely functional.

The code for the Web API implementation will be on GitHub as soon as it is in a half-way usable and decent state.

The app itself will probably be available on GitHub too some day. But as I said, there’s still a long way to go.