locked
UPnP Control Point API in WinRT

    Question

  • Is there a UPNP Control Point API in WinRT?  I'm looking for something similar to the API defined here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa381122(v=vs.85).aspx

    I'm aware of the WinRT APIs in the Windows.Devices.Enumeration and Windows.Devices.Enumeration.Pnp namespaces.  But I can't seem to find a way to invoke UPnP actions or even discover the devices network name through the DeviceInformation or PnpObject APIs.


    Saturday, February 18, 2012 1:32 AM

Answers

  • There is no UPnP APIs in WinRT. If your UPnP device supports PNP-X then you can discover and pair your device using metro device settings UI. Once the device is paired, you can enumerate your device and retrieve the device properties such as ServiceControlUrl, ServiceDescriptionUrl, ServiceEventSubscriptionUrl and IP address. Check the sample code snippet below. Once you get these properties you could use SOAP messages to interact with the device. (Note, there are DLNA APIs
    in WinRT, and we recommend using DLAN APIs to interact with DLNA devices such as DMRs and DMSs.)

    Regarding UDP multicast port 1900, your application should be able to open it for shared access.

    // C# sample code:
    // Use SHA1 (version 5 GUID using RFC 4122 - http://tools.ietf.org/html/rfc4122#section-4.3) to generate Device Interface Class UUID from UPnP device service type
    // For Example:
    //      For sample UPnP dimmer Device Service Types: "urn:microsoft-com:serviceId:DimmerService1.0"
    //      the RFC 4122 algorithm produces the class 5 GUID: "{bb66ac6e-4e59-58dc-bafa-ce6af7e50cfc}"
    //

    using Windows.Devices.Enumeration;
    using Windows.Devices.Enumeration.Pnp;           

    //
    // Use the Device Interface Class UUID to get the UPnP device Interface object
    //

    // Set the AQS (Advanced Query Syntax) Filter for this query
    var selector = "System.Devices.InterfaceClassGuid:=\"" + "{bb66ac6e-4e59-58dc-bafa-ce6af7e50cfc}" + "\"";

    // PKEY_PNPX_ServiceDescUrl = "{656A3BB3-ECC0-43FD-8477-4AE0404A96CD},16389"
    string serviceDescriptionUrlProperty = "{656A3BB3-ECC0-43FD-8477-4AE0404A96CD},16389";

    // PKEY_PNPX_ServiceEventSubUrl = "{656A3BB3-ECC0-43FD-8477-4AE0404A96CD},16390"
    string serviceEventSubscriptionUrlProperty = "{656A3BB3-ECC0-43FD-8477-4AE0404A96CD},16390";

    // Create Interface properties to read from the interface object
    string[] interfaceProperties = { "System.Devices.ServiceAddress", "System.Devices.ServiceId", "System.Devices.DeviceInstanceId", serviceDescriptionUrlProperty, serviceEventSubscriptionUrlProperty };

    var interfaceObject = await DeviceInformation.FindAllAsync(selector, interfaceProperties);

    // Service Control Url
    string[] serviceControlUrlArray = (string[])interfaceObject[0].Properties["System.Devices.ServiceAddress"];
    string serviceControlUrl = serviceControlUrlArray[0];

    // Service Description Url
    var serviceDescriptionUrl = interfaceObject[0].Properties[serviceDescriptionUrlProperty];

    // Service Event Subscription Url
    var serviceEventSubscriptionUrl = interfaceObject[0].Properties[serviceEventSubscriptionUrlProperty];
                   
    // Service ID Property
    var serviceId = interfaceObject[0].Properties["System.Devices.ServiceId"];

    //
    // Use Interface object and DeviceInstanceId to get the Device Object
    //

    // Create a Device properties
    string[] deviceProperties = { "System.Devices.IpAddress"};

    // Device Instance ID
    string deviceInstanceId = (string)interfaceObject[0].Properties["System.Devices.DeviceInstanceId"];

    var deviceObject = await PnpObject.CreateFromIdAsync(PnpObjectType.Device, deviceInstanceId, deviceProperties);

    // IP Address
    string[] ipAddressArray = (string[])deviceObject.Properties["System.Devices.IpAddress"];
    string ipAddress = ipAddressArray[0];


    OutputText.Text = "Service Control Url: " + serviceControlUrl + "\rService Description Url: " + serviceDescriptionUrl + "\rService Event Subscription Url: " + serviceEventSubscriptionUrl + "\rService ID: " + serviceId + "\rIP Address: " + ipAddress;



    Monday, March 05, 2012 10:39 PM

All replies

  • Since I couldn't find any UPnP apis in WinRT, nor could I find a way to retrieve the device url from the PnpObject, I thought I would implement my own UPnP control point API in my app.  

    The first thing you need to do in a UPnP API is be able to discover devices.  So, I started by trying to implement an SSDP client to discover UPnP devices on the network.   In order to implement SSDP you have to listen for UDP multicast device notifications on port 1900.  However, binding to port 1900 fails if any other application has already bound to that port (Say you have another app running that needs to listen for SSDP updates).  This is because two Metro apps can't bind to the same UDP port.  No binding to port 1900 = no device discovery.

    So, there is no UPnP api in WinRT and it is impossible to implement your own.  How is a device companion app supposed to discover and communicate with the devices it's supposed to be "enhancing"???


    Sunday, March 04, 2012 3:37 AM
  • There is no UPnP APIs in WinRT. If your UPnP device supports PNP-X then you can discover and pair your device using metro device settings UI. Once the device is paired, you can enumerate your device and retrieve the device properties such as ServiceControlUrl, ServiceDescriptionUrl, ServiceEventSubscriptionUrl and IP address. Check the sample code snippet below. Once you get these properties you could use SOAP messages to interact with the device. (Note, there are DLNA APIs
    in WinRT, and we recommend using DLAN APIs to interact with DLNA devices such as DMRs and DMSs.)

    Regarding UDP multicast port 1900, your application should be able to open it for shared access.

    // C# sample code:
    // Use SHA1 (version 5 GUID using RFC 4122 - http://tools.ietf.org/html/rfc4122#section-4.3) to generate Device Interface Class UUID from UPnP device service type
    // For Example:
    //      For sample UPnP dimmer Device Service Types: "urn:microsoft-com:serviceId:DimmerService1.0"
    //      the RFC 4122 algorithm produces the class 5 GUID: "{bb66ac6e-4e59-58dc-bafa-ce6af7e50cfc}"
    //

    using Windows.Devices.Enumeration;
    using Windows.Devices.Enumeration.Pnp;           

    //
    // Use the Device Interface Class UUID to get the UPnP device Interface object
    //

    // Set the AQS (Advanced Query Syntax) Filter for this query
    var selector = "System.Devices.InterfaceClassGuid:=\"" + "{bb66ac6e-4e59-58dc-bafa-ce6af7e50cfc}" + "\"";

    // PKEY_PNPX_ServiceDescUrl = "{656A3BB3-ECC0-43FD-8477-4AE0404A96CD},16389"
    string serviceDescriptionUrlProperty = "{656A3BB3-ECC0-43FD-8477-4AE0404A96CD},16389";

    // PKEY_PNPX_ServiceEventSubUrl = "{656A3BB3-ECC0-43FD-8477-4AE0404A96CD},16390"
    string serviceEventSubscriptionUrlProperty = "{656A3BB3-ECC0-43FD-8477-4AE0404A96CD},16390";

    // Create Interface properties to read from the interface object
    string[] interfaceProperties = { "System.Devices.ServiceAddress", "System.Devices.ServiceId", "System.Devices.DeviceInstanceId", serviceDescriptionUrlProperty, serviceEventSubscriptionUrlProperty };

    var interfaceObject = await DeviceInformation.FindAllAsync(selector, interfaceProperties);

    // Service Control Url
    string[] serviceControlUrlArray = (string[])interfaceObject[0].Properties["System.Devices.ServiceAddress"];
    string serviceControlUrl = serviceControlUrlArray[0];

    // Service Description Url
    var serviceDescriptionUrl = interfaceObject[0].Properties[serviceDescriptionUrlProperty];

    // Service Event Subscription Url
    var serviceEventSubscriptionUrl = interfaceObject[0].Properties[serviceEventSubscriptionUrlProperty];
                   
    // Service ID Property
    var serviceId = interfaceObject[0].Properties["System.Devices.ServiceId"];

    //
    // Use Interface object and DeviceInstanceId to get the Device Object
    //

    // Create a Device properties
    string[] deviceProperties = { "System.Devices.IpAddress"};

    // Device Instance ID
    string deviceInstanceId = (string)interfaceObject[0].Properties["System.Devices.DeviceInstanceId"];

    var deviceObject = await PnpObject.CreateFromIdAsync(PnpObjectType.Device, deviceInstanceId, deviceProperties);

    // IP Address
    string[] ipAddressArray = (string[])deviceObject.Properties["System.Devices.IpAddress"];
    string ipAddress = ipAddressArray[0];


    OutputText.Text = "Service Control Url: " + serviceControlUrl + "\rService Description Url: " + serviceDescriptionUrl + "\rService Event Subscription Url: " + serviceEventSubscriptionUrl + "\rService ID: " + serviceId + "\rIP Address: " + ipAddress;



    Monday, March 05, 2012 10:39 PM
  • Thanks for the reply Datta.  I'll give this a shot.  "System.Devices.ServiceAddress" and the other related properties look exactly like what I need!  Is there any way I could have discovered that device property on my own?  Is there any way to enumerate all the properties that are set on a device?  Or is there an exhaustive listing of available device properties?  (I couldn't find it here: http://msdn.microsoft.com/en-us/library/windows/desktop/ff521659(v=vs.85).aspx)

    Regarding the DLNA APIs in WinRT, I assume you are referring to the PlayTo APIs.  Those won't work for my scenario.  Say I'm building a companion app for a network speaker that my company makes (called Speaker-X).  With the PlayTo APIs I have no control over what device the user selects to play to.  I don't want to implement the PlayTo contract because I don't want my Speaker-X companion app to play it's special content to our competitors speakers.  

    Also, using the PlayTo APIs, the user experience is not seamless for my companion app.  Ex:

    1. Customer launches the "Speaker-X companion"
    2. Customer browses our cool content
    3. Customer hits the "Play" button on our cool content
    4. Customer sees a list of devices on the network, including their TV, Speaker-X and Competitor Speaker-Y (Bad)
    5. Customer picks Speaker-X
    6. Customer closes the app
    7. Customer starts the app again, finds some cool content, hits "Play"
    8. Customer sees a list of devices on the network, including their TV, Speaker-X and Competitor Speaker-Y (Bad, again.  It should just remember the device)

    Is there some way to Play To a device, without the user having to pick a device from the devices charm?  I know I can invoke the play to device picker ui, but that's not exactly what I want.  I'd like to have my own UI in the app that only shows the Speaker-X devices on the network and let's the user switch the speaker that is currently being controlled.  I can enumerate the devices with System.Devices.DeviceInformation, and show UI for them, but I can't find a way to tell a PlayToSource to play to a specific device.  Does that make sense?

    Regarding UDP multicast, my understanding is that Metro apps can't open sockets/ports for shared access.  It was intentionally left out.  (See this thread http://social.msdn.microsoft.com/Forums/en-US/winappswithhtml5/thread/2e4cc209-843c-484e-982f-d434d663eca0).

    Thanks again Datta!


    Monday, March 05, 2012 11:44 PM
  • I thought I would add some additional information about why the PlayTo APIs aren't suitable for the device companion apps we want to create.

    We're working on an app for a network speaker made by company X.  We want to create an awesome companion app so that when our customers want to listen to music in their home, they launch our app.  Customers can play music from the local computer, control which zones the music is playing in, use premium music services that are unique to our device, access custom audio controls that are unique to our device, etc.  

    If we were to use the Play To APIs for playing music from the local computer, then a user could pick any DLNA audio device on the network as the target.  When they do that, all our custom audio controls stop working because it's not one of our devices.  

    So, unfortunately, the Play To APIs as they currently exist won't work for us.  We can implement our own DMR client APIs (or port an open source implementation to WinRT), and that's what we are planning.  But the time we spend implementing a DMR client APIs is time we can't spend building cool new features for customers.  It would be great if it were available in WinRT.

    BTW, I was able to retrieve the device ip address and the service control url using the sample code you provided.  Thanks again!


    Tuesday, March 06, 2012 10:08 PM
  • I can't retrieve the device ip address and the service control url using the sample code. 

    var interfaceObject = await DeviceInformation.FindAllAsync(selector, interfaceProperties);

    string[] serviceControlUrlArray = (string[])interfaceObject[0].Properties["System.Devices.ServiceAddress"];

    I test it and found that the count of interfaceObject is 2. but the serviceControlUrlArray is null.

    Here list additional properties for a device or PnP object:

    http://msdn.microsoft.com/en-us/library/windows/apps/hh464997.aspx

    I can't find the property "System.Devices.ServiceAddress",  "System.Devices.ServiceId", "System.Devices.IpAddress".

    Couldn't you give me some help? thanks.


    Monday, March 19, 2012 8:26 AM
  • There is no UPnP APIs in WinRT. If your UPnP device supports PNP-X then you can discover and pair your device using metro device settings UI. Once the device is paired, you can enumerate your device and retrieve the device properties such as ServiceControlUrl, ServiceDescriptionUrl, ServiceEventSubscriptionUrl and IP address. Check the sample code snippet below. Once you get these properties you could use SOAP messages to interact with the device. (Note, there are DLNA APIs
    in WinRT, and we recommend using DLAN APIs to interact with DLNA devices such as DMRs and DMSs.)

    Regarding UDP multicast port 1900, your application should be able to open it for shared access.

    // C# sample code:
    // Use SHA1 (version 5 GUID using RFC 4122 - http://tools.ietf.org/html/rfc4122#section-4.3) to generate Device Interface Class UUID from UPnP device service type
    // For Example:
    //      For sample UPnP dimmer Device Service Types: "urn:microsoft-com:service:DimmerService:1"
    //      the RFC 4122 algorithm produces the class 5 GUID: "{bb66ac6e-4e59-58dc-bafa-ce6af7e50cfc}"
    //

    using Windows.Devices.Enumeration;
    using Windows.Devices.Enumeration.Pnp;           

    //
    // Use the Device Interface Class UUID to get the UPnP device Interface object
    //

    // Set the AQS (Advanced Query Syntax) Filter for this query
    var selector = "System.Devices.InterfaceClassGuid:=\"" + "{bb66ac6e-4e59-58dc-bafa-ce6af7e50cfc}" + "\"";

    // PKEY_PNPX_ServiceDescUrl = "{656A3BB3-ECC0-43FD-8477-4AE0404A96CD},16389"
    string serviceDescriptionUrlProperty = "{656A3BB3-ECC0-43FD-8477-4AE0404A96CD},16389";

    // PKEY_PNPX_ServiceEventSubUrl = "{656A3BB3-ECC0-43FD-8477-4AE0404A96CD},16390"
    string serviceEventSubscriptionUrlProperty = "{656A3BB3-ECC0-43FD-8477-4AE0404A96CD},16390";

    // Create Interface properties to read from the interface object
    string[] interfaceProperties = { "System.Devices.ServiceAddress", "System.Devices.ServiceId", "System.Devices.DeviceInstanceId", serviceDescriptionUrlProperty, serviceEventSubscriptionUrlProperty };

    var interfaceObject = await DeviceInformation.FindAllAsync(selector, interfaceProperties);

    // Service Control Url
    string[] serviceControlUrlArray = (string[])interfaceObject[0].Properties["System.Devices.ServiceAddress"];
    string serviceControlUrl = serviceControlUrlArray[0];

    // Service Description Url
    var serviceDescriptionUrl = interfaceObject[0].Properties[serviceDescriptionUrlProperty];

    // Service Event Subscription Url
    var serviceEventSubscriptionUrl = interfaceObject[0].Properties[serviceEventSubscriptionUrlProperty];
                   
    // Service ID Property
    var serviceId = interfaceObject[0].Properties["System.Devices.ServiceId"];

    //
    // Use Interface object and DeviceInstanceId to get the Device Object
    //

    // Create a Device properties
    string[] deviceProperties = { "System.Devices.IpAddress"};

    // Device Instance ID
    string deviceInstanceId = (string)interfaceObject[0].Properties["System.Devices.DeviceInstanceId"];

    var deviceObject = await PnpObject.CreateFromIdAsync(PnpObjectType.Device, deviceInstanceId, deviceProperties);

    // IP Address
    string[] ipAddressArray = (string[])deviceObject.Properties["System.Devices.IpAddress"];
    string ipAddress = ipAddressArray[0];


    OutputText.Text = "Service Control Url: " + serviceControlUrl + "\rService Description Url: " + serviceDescriptionUrl + "\rService Event Subscription Url: " + serviceEventSubscriptionUrl + "\rService ID: " + serviceId + "\rIP Address: " + ipAddress;




    Tuesday, July 17, 2012 10:17 PM
  • I was sucessfull getting the service ids, ip address, service description Urls. But does anybody now how to get the url of the Device Description Document ?

    I tried a lot of PKEY_PNPX_xxx keys but was not able to get it.

    Wednesday, September 05, 2012 10:25 AM
  • Since I couldn't find any UPnP apis in WinRT, nor could I find a way to retrieve the device url from the PnpObject, I thought I would implement my own UPnP control point API in my app.  

    The first thing you need to do in a UPnP API is be able to discover devices.  So, I started by trying to implement an SSDP client to discover UPnP devices on the network.   In order to implement SSDP you have to listen for UDP multicast device notifications on port 1900.  However, binding to port 1900 fails if any other application has already bound to that port (Say you have another app running that needs to listen for SSDP updates).  This is because two Metro apps can't bind to the same UDP port.  No binding to port 1900 = no device discovery.

    So, there is no UPnP api in WinRT and it is impossible to implement your own.  How is a device companion app supposed to discover and communicate with the devices it's supposed to be "enhancing"???


    Hi Robert;

    There is a brand new UPnP control point class library on its way. I setup a project to design and implement this earlier in the year and it's progressed very well. A thorough analysis was first carried out on the various specifications and an overall architectural model was then devised before embarking upon the detailed design.

    The most important goal was that the API must be syntactically and semantically identical across all supported platforms and the second most important goal was that it must support Windows Desktop/Server and Windows Phone 8 and WinRT (Surface tablets).

    These goals have been met and all underlying platform differences are masked by the library so that its straightforward to develop UPnP control apps which are source code portable across these platforms. Providing you code with care a control app written for Phone 8 should be able to compile build and run on Surface.

    The system is completely async and uses a robust model which strives to make the writing of a controller app as straightforward as possible.

    Currently I'm finalizing the DIDL-Lite support which is essential for working with media libraries, this phase is close to completion.

    Testing is being augmented by the simultaneous development of a Sonos controller app for Phone and Surface, this app (which is a single source code base) will ultimately use just XAML to create the two different user interfaces.

    Currently the Sonos control app discovers and displays all players on the network, lets you select a player, adjust a player's volume, bass, treble and you may mute/unmute a player or all players.

    You can also browse all media in the system's media repository.

    The above functionality is running very reliably now.

    There is more work yet to do, but a beta version isn't far away and I'll have more to say about this over the coming weeks.

    The final API will be accompanied by some helpful UPnP tools which will themselves all rely on the API, including a network browser, a log viewing tool and a class library source generator which creates a partial class that exposes all actions and state variables defined for any given UPnP service.

    Cap'n

    PS This post shows a picture of the test Sonos app, FYI.

    http://social.msdn.microsoft.com/Forums/windowsapps/en-US/f61501a3-d842-45c4-ba3a-3861eef2bd05/best-visual-elements-to-use-for-listing-folderscontents?forum=winappsuidesign#f61501a3-d842-45c4-ba3a-3861eef2bd05


    Sunday, November 03, 2013 4:50 AM
  • How will this api be release?

    I am trying to write a UPNP control point right now to both learn windows store app development and also because i am tired of not having a control point that works with my synology based server and Linn DSM renderer.

    Linn Kinsky app is available on ipad and andriod but nothing equivalent in winrt/wp8. 

    Sunday, November 03, 2013 4:55 AM
  • Hi,

    is there any news on this? I would like to do the same kind of things as discussed here.

    Sunday, October 12, 2014 4:24 PM
  • Hi

    I had same problem with UPnP library, I have just completed UPnP control point library, that includes, discovery actions and events. Its written for phone and win 8.1 as a PCL.

    I am currently finishing testing and will soon release as a nugget package.


    Lyzard

    Sunday, April 05, 2015 5:43 PM