I'm not sure if today counts as a "hardware" project, but I thought it cool and something we've not highlighted before and is hardware'ish, so...
Lucian shows us UPnP for Windows 8, how we might use it and generally helps us understand it by writing code for it...
This code plays audio on UPnP speakers. If you have DLNA speakers ("Digital Lifestyle Networking Alliance") they are based on UPnP and it will also work on them.
Instead of following this article, there's a key alternative technique that's better - using the new Windows 8 support for "Play To" (this link goes to Windows SDK sample code for the PlayTo contract+API). PlayTo is far simpler, better-tested, and preferable to implementing all this UPnP stuff yourself. It takes only a few lines of code. Users of your app-store app will then be able to use the Devices charm to make your app stream its video or audio to their TV or speakers or picture-frames, so long as the device's manufacturer has provided Windows-8-certified drivers.
(Note that certified drivers are only needed for app-store apps; they're not needed for desktop apps. There's also one older technique, using a COM library called UPNP.dll dating back to XP, but it isn't allowed for app-store apps).
I wrote this code because my device doesn't yet have windows-8-certified drivers, and because I wanted to learn about UPnP. More generally, the code might help you understand the UPnP underpinnings of how things work under the hood when you use PlayTo.
- The article describes the raw UPnP protocols, i.e., the UDP and TCP messages involved between devices.
- Next it shows code that implements those raw UDP and TCP communications explicitly, both for device-discovery (SSDP) and for device control (UPnP).
There are two forms of the code: .NET45 code (runs on any .NET45 machine but not allowed on app store) and WinRT code (runs on Windows tablets, allowed on app-store, requires Windows8).
- Next it shows where you can use HttpClient and VB's XML-literals, for a higher-level abstraction rather than doing raw TCP programming.
- Next it shows how to use WinRT device-enumeration APIs, rather than implementing SSDP manually. This is a cleaner way of doing things, and will run on Windows tablets and is allowed on the app-store, but requires Windows 8.
Testing with UPnP devices
Here are three UPnP devices you can test this code on:
- I went out and bought a Sony SA-NS300 wifi speaker. This is a UPnP device (but doesn't yet as of September 2012 have windows-8-certified drivers).
- I downloaded Developer Tools for UPnP Technologies. This has a program called MediaRenderer.exe in it, which you can test against (but it also isn't yet windows-8-certified).
- I set up a different machine on the same network, ran Windows Media Player on it, and did Stream > AllowRemoteControl. (This has to be on a different machine: it doesn't work on the same machine). This technique is also described in the Windows SDK "PlayTo sample". It is windows-8-certified.
Here's a picture of my laptop simultaneously sending audio wirelessly to all three devices!
His great article starts with UPnP information and then starts diving deep into the code...
UPnP has superb documentation at www.upnp.org.
- UPnP Device Architecture - explains how the shared UPnP protocols work, including service discovery. This is common information for all UPnP protocols. The rest of the documents are specific to media-playing.
- UPnP AV Architecture - explains the particular case of media rendering, from a DMS (Digital Media Source) to a DMR (Digital Media Renderer)
- ConnectionManager:1 - documents the API of the
ConnectionManagerinterface, used to determine which protocols are supported
- AVTransport:1 - documents the API of the
AVTransportinterface, used to tell the DMR which media-source to play, and to start/stop it.
When media is played over UPnP, there are three parties involved:
Control Point - this party tells the others when and what to play
Digital Media Renderer (DMR) - the speakers/tv. They can be told what URL to play, and can be told to start/stop.
Digital Media Source (DMS) - where the media comes from, i.e. it serves up the URL that was requested by the DMR.
You can imagine lots of ways this might work. Maybe your computer is the control point, and the DMS is some archive on a server in your attic, and the DMR is your television set. Or maybe your computer is the DMS, and the control point is a tablet or cell phone or remote control, and the DMR is your set of Wi-Fi speakers.
One of the things I thought cool was how he mixed in ".Net" and WinRT sample versions. (Oh and that he used Visual Basic.Net for course!
Higher level of abstraction: use WinRT Device Enumeration
Actually, Windows 8 has SSDP discovery built in. We can remove our existing SSDP code and replace it with "WinRT Device Enumeration". I described win8 device-enumeration more fully in a separate article: http://www.codeproject.com/Articles/458550/Device-enumeration-in-Windows-8.
No WinRT probes by device-type. Recall that we send an SSDP probe for all devices that have the device-type "urn:schemas-upnp-org:device:MediaRenderer:1". Well, Windows sends out SSDP probes for absolutely all devices -- but it not longer lets us query its results by device-type.
What we'll do instead is rely on the fact that all MediaRenderer:1 devices have a
RenderingControlservice and a
ConnectionManagerinterface, and (optionally) an
AVTransportinterface. So we'll look for any device at all that has these interfaces.
It raises an interesting philosophical question -- what if there exist some devices whose type is not MediaRenderer:1, but they expose ConnectionManager and AVTransport interfaces? Should our code work with them? What will they do? I don't know!
No WinRT probes by service-type string. Also, our own SSDP implementation looked for services with type "urn:schemas-upnp-org:service:ConnectionManager:1...
In short, if you've ever wondered what UPnP was, how "Play To" works and how you might be able to use them, this is a must read article. Imagine mixing in this with some of the hardware projects we've highlighted here in the past... hum...