Welcome to MSDN Blogs Sign in | Join | Help

Diaries from my Roku SoundBridge - Windows Media Connect

Perhaps you haven't seen this yet, but Microsoft release Windows Media Connect v2 which is available for download. A number of features/improvements were made, but one key one I'd like to point out is there is no longer a limitation when developing a WMC application on the same machine as the WMC library. In the past you needed a "code" machine and a WMC machine.
 
That said, I just love this technology for sharing Music, Pictures etc…across my home network. Recall that I am working on remote controlling my Roku Media SoundBridge. The good folks at Roku Labs release an SDK based on a Telnet type interface for controlling your SoundBridge, looking up albums, creating play lists and the like.
 
One problem I considered while working on this application was that when I telnet into my SoundBridge, select an album, and have it play the Roku SoundBridge I am effectively "repeating" the searching, selecting and streaming of the music from WMC. Thus this introduces a level of indirection that is not always necessary. In addition I could make my "remote" application more useful and separate the "library" capabilities from the actual playing of the music on the end point device.
 
For instance if I acquired all the information from my WMC directly, then I could create my own Media Player using the WMP10 Media Player control, I could create a web page that could be viewed from any machine irrespective of the OS or device. I could also now target different Digital Media Receiver as the end point device by having a module specific to the capabilities of that DMR. The library capabilities stay the same but now I can support the Roku PhotoBridge or other similar devices.
 
This is where the ContentDirectory Service Template comes in. Originally published in 2002, along with other core document available at www.upnp.org, it describes the specifications for working with MediaServers and MediaRenderers. One challenge I've found is although there is a lot of documentation, there doesn't seem to be a nice SDK and we've certainly note made it easy or well documented from a Windows Media Connect perspective. I've pointed out some documents that Microsoft has published in my previous posts but this is not nearly enough.
 
It turns out browsing your WMC "server" is relatively easy, once your learn the syntax. You will need to review the ContentDirectory Service template especially the "Theory of Operation" section if you don't feel like reading all 90 pages.
 
So let's look at some code to see what we can do. Recall from a previous post that inside our project we've got a reference to UPNPLib. Let’s create the objects we will need.
 
UPnPDeviceFinderClass findDevice = newUPnPDeviceFinderClass();
UPnPDevice Device = new UPNPLib.UPnPDevice();
UPnPService Service = new UPNPLib.UPnPService();
UPnPService ContentDirectory = new UPNPLib.UPnPService();
 
Next we need to find the device by its UDN. See an earlier post on how to get all the UPnP enabled devices on your network and specific UDN ID. This is the uuid from one of my Windows Media Connect "servers".
 
Device = findDevice.FindByUDN("uuid:88cd5346-ecfe-4cb2-9eb1-5ba2f4596d23");
 
Next let's iterate through the services that our device supports. We only want to bind to the ContentDirectory capabilities of our device.
 
foreach (UPnPService service in Device.Services)
{
if (service.Id == "urn:upnp-org:serviceId:ContentDirectory")
ContentDirectory = service;
}
 
A couple of tools that I've found super useful along with installing the platform SDK which is a must as it has lots of information you will need to review. Wfetch is a great way to troubleshoot HTTP connections, it ships with the IIS 6.0 Resource Kit and also check out this link if you need to get your hands on it. Another useful tool is EtherDetect's packet sniffer tool - I've found that if your statements aren't well formed, something that is not always obvious, the COM libraries return pretty cryptic errors that are hard to debug. So best thing is to use a packet filter tool to see exactly what you are sending/receiving.
 
Now let's setup our in/out parameters with which to call the ContentDirectory.
 
object[] objInVal = newobject[6];
object objOutVal = newobject[4];
Object outResults = newobject();
object objRetVal = newObject();
string prevNode = null;
string xmlText = null;
byte[] byteArr;
int iRetVal = 0;
int page = 100; // size limitations require you to page content back from WMC
int pageFetched = 1; // size limitations require you to page your re
 
Now we setup our in parameters to perform specific action, in this case we want to return all the music albums from WMC.
 
objInVal.SetValue("0", 0); //UPnP Object to browse, check SDK for values of the WMV hierarchy
objInVal.SetValue("upnp:class = \"object.container.album.musicAlbum\" and @refID exists false", 1); //Browse
objInVal.SetValue("", 2); //filter
objInVal.SetValue(0, 3);
objInVal.SetValue(page, 4);
objInVal.SetValue("", 5);
 
Let's call the InvokeAction on our ContentDirectory object and set our action to "Search" and pass in our in/out parameter objects.
 
ContentDirectory.InvokeAction("Search", objInVal, ref objOutVal);
xmlText = (string)((object[])(objOutVal))[0];
 
We get an XML document back which we write to a file or manipulate in any way we want.
 
StringBuilder builder = newStringBuilder();
builder.Append(xmlText);
XmlDocument doc = newXmlDocument();
StreamWriter x = newStreamWriter("f:\\temp\\test3.xml");
x.Write(builder.ToString());
x.Close();
 
Finally when you execute this code against your WMC library. The first time you should receive an icon tray notification from WMC letting you know that a new device is requesting access. You will need to give your application access through the WMC interface and rerun the code. From then on you application is "Registered" against WMC.
 
The hardest part of all this is to figure out the browse/search syntax. Again refer to the upnp.org ContentDirectory specification. Once you've figured out the syntax you've got all the power in your hands but this is where the packet sniffer can really help to double check your syntax in case you experience hard to debug problems.
 
A final example. If you take the code above and change the following IN parameters you can perform a search for artists.
 

objInVal.SetValue("upnp:class derivedfrom \"object.item.audioItem\" and @refID exists false and (dc:title contains \"" + srcText.Text + "\" or upnp:artist contains " + "\"" + srcText.Text + "\"" + " or upnp:album contains \"" + srcText.Text + "\"" + " or upnp:author contains \"" + srcText.Text + "\"" + ")", 1); //get all albums

objInVal.SetValue("res@protocolInfo,res@protection,upnp:album,upnp:originalTrackNumber", 2); //meta data info

Assuming you have a Moby album you could expect similar output. In my case srcText.Text = "moby". I've cut most of the file out but you should get the idea. And you can search for partial words for example all artists that start with "b". Finally, the UPnP API have a size limit so look at this MSDN article for more information and make sure you implement some sort of paging mechanism. IN parameter 4 specifies the starting index and IN parameter 5 specifies the page size (number items to retrieve).

-<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/">
-<item id="4-5551" restricted="1" parentID="4">
 <dc:title>18</dc:title>
 <resprotocolInfo="http-get:*:audio/x-ms-wma:*" />
 <resprotocolInfo="http-get:*:audio/L16:*" />
 <upnp:class>object.item.audioItem.musicTrack</upnp:class>
 <upnp:album>18</upnp:album>
 <upnp:originalTrackNumber>12</upnp:originalTrackNumber>
 </item>
-<item id="4-5572" restricted="1" parentID="4">
 <dc:title>7</dc:title>
 <resprotocolInfo="http-get:*:audio/x-ms-wma:*" />
 <resprotocolInfo="http-get:*:audio/L16:*" />
 <upnp:class>object.item.audioItem.musicTrack</upnp:class>
 <upnp:album>Play</upnp:album>
 <upnp:originalTrackNumber>10</upnp:originalTrackNumber>
 </item>
</DIDL-Lite>
 
 

Note: I'm trying a new tool for my blog posts so I'm keeping my fingers crossed.

 

 
 
Published Sunday, October 23, 2005 12:12 PM by jcarron

Comments

No Comments
New Comments to this post are disabled
 
Page view tracker