Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to send SetAVTransportURI using UPnP C#?

Tags:

c#

upnp

I'm trying to send a command to my TV (Sony Bravia KDL-42W800A) to play a video through UPnP. I can discover all UPnP devices on my network using SSDP. Here is a sample response from the TV:

HTTP/1.1 200 OK
CACHE-CONTROL: max-age=1800
EXT: 
LOCATION: http://192.168.1.11:52323/dmr.xml
SERVER: Linux/2.6 UPnP/1.0 KDL-42W800A/1.7
ST: urn:schemas-upnp-org:service:AVTransport:1
USN: uuid:00000000-0000-1010-8000-d8d43c73618b::urn:schemas-upnp-org:service:AVTransport:1
X-AV-Physical-Unit-Info: pa="BRAVIA KDL-42W800A";
X-AV-Server-Info: av=5.0; cn="Sony Corporation"; mn="BRAVIA KDL-42W800A"; mv="1.7";

From this I have followed the Location to retrieve the XML file containing more specifics on the TV. Given below:

<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0"
      xmlns:pnpx="http://schemas.microsoft.com/windows/pnpx/2005/11"
      xmlns:df="http://schemas.microsoft.com/windows/2008/09/devicefoundation">
  <specVersion>
    <major>1</major>
    <minor>0</minor>
  </specVersion>
  <device>
    <deviceType>urn:schemas-upnp-org:device:MediaRenderer:1</deviceType>
    <friendlyName>BRAVIA KDL-42W800A</friendlyName>
    <manufacturer>Sony Corporation</manufacturer>
    <manufacturerURL>http://www.sony.net/</manufacturerURL>
    <modelName>KDL-42W800A</modelName>
    <modelNumber>MINT1.7.0.1</modelNumber>
    <UDN>uuid:00000000-0000-1010-8000-d8d43c73618b</UDN>
    <dlna:X_DLNADOC xmlns:dlna="urn:schemas-dlna-org:device-1-0">DMR-1.50</dlna:X_DLNADOC>
    <microsoft:magicPacketWakeSupported xmlns:microsoft="urn:schemas-microsoft-com:WMPNSS-1-0">1</microsoft:magicPacketWakeSupported>
    <iconList>
      <icon>
        <mimetype>image/png</mimetype>
        <width>32</width>
        <height>32</height>
        <depth>24</depth>
        <url>/MediaRenderer_32x32.png</url>
      </icon>
      <icon>
        <mimetype>image/png</mimetype>
        <width>48</width>
        <height>48</height>
        <depth>24</depth>
        <url>/MediaRenderer_48x48.png</url>
      </icon>
      <icon>
        <mimetype>image/png</mimetype>
        <width>60</width>
        <height>60</height>
        <depth>24</depth>
        <url>/MediaRenderer_60x60.png</url>
      </icon>
      <icon>
        <mimetype>image/png</mimetype>
        <width>120</width>
        <height>120</height>
        <depth>24</depth>
        <url>/MediaRenderer_120x120.png</url>
      </icon>
      <icon>
        <mimetype>image/jpeg</mimetype>
        <width>32</width>
        <height>32</height>
        <depth>24</depth>
        <url>/MediaRenderer_32x32.jpg</url>
      </icon>
      <icon>
        <mimetype>image/jpeg</mimetype>
        <width>48</width>
        <height>48</height>
        <depth>24</depth>
        <url>/MediaRenderer_48x48.jpg</url>
      </icon>
      <icon>
        <mimetype>image/jpeg</mimetype>
        <width>60</width>
        <height>60</height>
        <depth>24</depth>
        <url>/MediaRenderer_60x60.jpg</url>
      </icon>
      <icon>
        <mimetype>image/jpeg</mimetype>
        <width>120</width>
        <height>120</height>
        <depth>24</depth>
        <url>/MediaRenderer_120x120.jpg</url>
      </icon>
    </iconList>
    <serviceList>
      <service>
        <serviceType>urn:schemas-upnp-org:service:RenderingControl:1</serviceType>
        <serviceId>urn:upnp-org:serviceId:RenderingControl</serviceId>
        <SCPDURL>/RenderingControlSCPD.xml</SCPDURL>
        <controlURL>/upnp/control/RenderingControl</controlURL>
        <eventSubURL>/upnp/event/RenderingControl</eventSubURL>
      </service>
      <service>
        <serviceType>urn:schemas-upnp-org:service:ConnectionManager:1</serviceType>
        <serviceId>urn:upnp-org:serviceId:ConnectionManager</serviceId>
        <SCPDURL>/ConnectionManagerSCPD.xml</SCPDURL>
        <controlURL>/upnp/control/ConnectionManager</controlURL>
        <eventSubURL>/upnp/event/ConnectionManager</eventSubURL>
      </service>
      <service>
        <serviceType>urn:schemas-upnp-org:service:AVTransport:1</serviceType>
        <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId>
        <SCPDURL>/AVTransportSCPD.xml</SCPDURL>
        <controlURL>/upnp/control/AVTransport</controlURL>
        <eventSubURL>/upnp/event/AVTransport</eventSubURL>
      </service>
      <service>
        <serviceType>urn:dial-multiscreen-org:service:dial:1</serviceType>
        <serviceId>urn:dial-multiscreen-org:serviceId:dial</serviceId>
        <SCPDURL>/DIALSCPD.xml</SCPDURL>
        <controlURL>/upnp/control/DIAL</controlURL>
        <eventSubURL></eventSubURL>
      </service>
      <service>
        <serviceType>urn:schemas-sony-com:service:IRCC:1</serviceType>
        <serviceId>urn:schemas-sony-com:serviceId:IRCC</serviceId>
        <SCPDURL>/IRCCSCPD.xml</SCPDURL>
        <controlURL>http://192.168.1.11/sony/IRCC</controlURL>
        <eventSubURL></eventSubURL>
      </service>
      <service>
        <serviceType>urn:schemas-sony-com:service:ScalarWebAPI:1</serviceType>
        <serviceId>urn:schemas-sony-com:serviceId:ScalarWebAPI</serviceId>
        <SCPDURL>/ScalarWebApiSCPD.xml</SCPDURL>
        <controlURL>/upnp/control/ScalarAPI</controlURL>
        <eventSubURL></eventSubURL>
      </service>
    </serviceList>
    <av:X_MaxBGMCount xmlns:av="urn:schemas-sony-com:av">64</av:X_MaxBGMCount>
    <av:X_StandardDMR xmlns:av="urn:schemas-sony-com:av">1.1</av:X_StandardDMR>
    <av:X_ScreenResolution xmlns:av="urn:schemas-sony-com:av">2K</av:X_ScreenResolution>
    <av:X_IRCCCodeList xmlns:av="urn:schemas-sony-com:av">
      <av:X_IRCCCode command="Power">AAAAAQAAAAEAAAAVAw==</av:X_IRCCCode>
      <av:X_IRCCCode command="Power ON">AAAAAQAAAAEAAAAuAw==</av:X_IRCCCode>
      <av:X_IRCCCode command="Power OFF">AAAAAQAAAAEAAAAvAw==</av:X_IRCCCode>
    </av:X_IRCCCodeList>
    <pnpx:X_compatibleId>MS_DigitalMediaDeviceClass_DMR_V001</pnpx:X_compatibleId>
    <pnpx:X_deviceCategory>MediaDevices</pnpx:X_deviceCategory>
    <pnpx:X_hardwareId>VEN_0106&amp;DEV_0006&amp;REV_01</pnpx:X_hardwareId>
    <df:X_deviceCategory>Display.TV Multimedia.DMR</df:X_deviceCategory>
    <av:X_TrackID_DeviceInfo xmlns:av="urn:schemas-sony-com:av">
      <av:X_TrackID_BaseURL>http://192.168.1.11/sony/BgmSearch</av:X_TrackID_BaseURL>
    </av:X_TrackID_DeviceInfo>
    <av:X_DIALEX_DeviceInfo xmlns:av="urn:schemas-sony-com:av"> 
        <av:X_DIALEX_AppsListURL>http://192.168.1.11/DIAL/sony/applist</av:X_DIALEX_AppsListURL>
    </av:X_DIALEX_DeviceInfo>
    <av:X_ScalarWebAPI_DeviceInfo xmlns:av="urn:schemas-sony-com:av">
      <av:X_ScalarWebAPI_Version>1.0</av:X_ScalarWebAPI_Version>
      <av:X_ScalarWebAPI_BaseURL>http://192.168.1.11/sony</av:X_ScalarWebAPI_BaseURL>
      <av:X_ScalarWebAPI_ServiceList>
        <av:X_ScalarWebAPI_ServiceType>guide</av:X_ScalarWebAPI_ServiceType>
        <av:X_ScalarWebAPI_ServiceType>system</av:X_ScalarWebAPI_ServiceType>
        <av:X_ScalarWebAPI_ServiceType>videoScreen</av:X_ScalarWebAPI_ServiceType>
        <av:X_ScalarWebAPI_ServiceType>audio</av:X_ScalarWebAPI_ServiceType>
        <av:X_ScalarWebAPI_ServiceType>avContent</av:X_ScalarWebAPI_ServiceType>
        <av:X_ScalarWebAPI_ServiceType>recording</av:X_ScalarWebAPI_ServiceType>
        <av:X_ScalarWebAPI_ServiceType>appControl</av:X_ScalarWebAPI_ServiceType>
        <av:X_ScalarWebAPI_ServiceType>browser</av:X_ScalarWebAPI_ServiceType>
        <av:X_ScalarWebAPI_ServiceType>notification</av:X_ScalarWebAPI_ServiceType>
        <av:X_ScalarWebAPI_ServiceType>cec</av:X_ScalarWebAPI_ServiceType>
        <av:X_ScalarWebAPI_ServiceType>accessControl</av:X_ScalarWebAPI_ServiceType>
        <av:X_ScalarWebAPI_ServiceType>irCommandProxy</av:X_ScalarWebAPI_ServiceType>
      </av:X_ScalarWebAPI_ServiceList>
    </av:X_ScalarWebAPI_DeviceInfo>
    <av:X_RDIS_DeviceInfo xmlns:av="urn:schemas-sony-com:av">
      <av:X_RDIS_Version>1.0</av:X_RDIS_Version>
      <av:X_RDIS_SESSION_CONTROL>false</av:X_RDIS_SESSION_CONTROL>
      <av:X_RDIS_ENTRY_PORT>20677</av:X_RDIS_ENTRY_PORT>
    </av:X_RDIS_DeviceInfo>
  </device>
</root>

Using this information, how can I request the TV to play a video if I have the link? I have tried to based on what I've read online and got this code so far, which is supposed to set the AVTransportURI, but it keeps on giving error 500 Internal Server Error.

    private const string SetAvTransportURIXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                                    "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" +
                                                        "<s:Body>" +
                                                            "<u:SetAVTransportURI xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\">" +
                                                                "<InstanceID>0</InstanceID>" +
                                                                "<CurrentURI>{0}</CurrentURI>" +
                                                                "<CurrentURIMetaData></CurrentURIMetaData>" +
                                                            "</u:SetAVTransportURI>" +
                                                        "</s:Body>" +
                                                    "</s:Envelope>";

    public void PlayVideo(string videoLink)
    {
        byte[] bytes;
        bytes = Encoding.UTF8.GetBytes(String.Format(SetAvTransportURIXml, videoLink));

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://192.168.1.11:52323/upnp/control/AVTransport");
        request.Headers.Add("SOAPAction", "\"urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI\"");
        request.ContentType = "text/xml; encoding=\"utf-8\"";
        request.ContentLength = bytes.Length;
        request.Method = "POST";
        Stream requestStream = request.GetRequestStream();
        requestStream.Write(bytes, 0, bytes.Length);
        requestStream.Flush();
        requestStream.Close();
        var response = (HttpWebResponse) request.GetResponse();
        if (response.StatusCode == HttpStatusCode.OK)
        {
            Stream responseStream = response.GetResponseStream();
            if (responseStream == null) return;
            string responseStr = new StreamReader(responseStream).ReadToEnd();
            Console.WriteLine(responseStr);
        }
    }

Any help would be appreciated, thanks.

like image 917
James Fairbairn Avatar asked Feb 10 '15 01:02

James Fairbairn


2 Answers

Try to put some DIDL-Lite meta-data in the CurrentURIMetaData parameter. My LG TV refuses to play anything if I just leave that field empty.

For example the following works for me (naturally this needs to be escaped when embedded in the outer XML structure):

<?xml version="1.0"?>
<DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sec="http://www.sec.co.kr/">
<item id="f-0" parentID="0" restricted="0">
    <dc:title>Video</dc:title>
    <dc:creator>Anonymous</dc:creator>
    <upnp:class>object.item.videoItem</upnp:class>
    <res protocolInfo="http-get:*:video/mp4:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01700000000000000000000000000000">{0}</res>
</item>
</DIDL-Lite>

Also there may be a need to have some special headers in the HTTP response to the TV's media request (at the URL you supply). My LG TV refuses to play unless the media file response has the following headers (case-sensitive BTW!):

contentFeatures.dlna.org: DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01700000000000000000000000000000
transferMode.dlna.org: Streaming

There are a lot of things that can go wrong when implementing UPnP/DLNA. If there is anything that the TV does not like, it will just refuse to accept it. The error messages can be rather unspecific. Lots of testing iterations are needed to figure how different DLNA device implementations can be coerced to co-operate. Many/most of the TV devices on the market implement only a small subset of the specs. In their own way.

Searching for SetAVTransportURI etc. at Github code search can be helpful for figuring out how others have implemented things.

like image 200
snap Avatar answered Nov 02 '22 09:11

snap


I'm coding for my Sony BRAVIA KDL-40EX505 and had the same problem.

192.168.0.102 is my computer and server for the music files. 192.168.0.10 is the Sony TV.

When I do the setAVTransportURI, the following happens:

The following POST is sent to the TV

POST /upnp/control/AVTransport HTTP/1.1
Host: 192.168.0.10:52323
Connection: keep-alive
Content-Length: 442
Cache-Control: no-cache
Origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop
Content-Type: text/xml;charset="UTF-8"
Soapaction: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
Postman-Token: a8169b28-fb09-7029-60a9-b7e2641dc1d6
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
   <s:Body>
      <u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
         <InstanceID>0</InstanceID>
         <CurrentURI>http://192.168.0.102:80/music.php?f=geradeaus</CurrentURI>
         <CurrentURIMetaData></CurrentURIMetaData>
      </u:SetAVTransportURI>
   </s:Body>
</s:Envelope>

The TV sents a HEAD request to the URL specified in the CurrentURI from the POST above:

HEAD /music.php?f=geradeaus HTTP/1.1
getcontentFeatures.dlna.org: 1
X-AV-Physical-Unit-Info: pa="BRAVIA KDL-40EX505";
X-AV-Client-Info: av="5.0"; cn="Sony Corporation"; mn="BRAVIA KDL-40EX505"; mv="1.7";
Host: 192.168.0.102:80

The answer for the HEAD request is:

HTTP/1.1 200 OK
Date: Sat, 05 Mar 2016 20:58:58 GMT
Server: Apache/2.4.9 (Win64) PHP/5.5.12
X-Powered-By: PHP/5.5.12
Content-Length: 9622288
transferMode.dlna.org: Streaming
Accept-Ranges: bytes
Cache-Control: no-cache
contentFeatures.dlna.org: DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01700000000000000000000000000000
Content-Type: audio/mpeg

If everything worked, the TV responses the first POST request with a 200 OK, otherwise you get a 500 Internal Server Error.

Result

So, for the Sony BRAVIA KDL-40EX505 it is important to enable

transferMode.dlna.org: Streaming

and

contentFeatures.dlna.org: DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01700000000000000000000000000000

in the response of the HEADER request to the audio or video file. I did that with a php file:

<?php 
   $file = $_GET['f'].'.mp3';

   header('Content-Length: '.filesize($file));
   header('Content-Type: audio/mpeg');
   header('transferMode.dlna.org: Streaming');
   header('Accept-Ranges: bytes');
   header('Cache-Control: no-cache');
   header('contentFeatures.dlna.org: DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01700000000000000000000000000000');

   fpassthru(fopen($file, 'rb'));
   exit;
?>

This is called via 192.168.0.102:80/music.php?f=geradeaus and returns geradeaus.mp3

Find out the contentFeatures.dlna.org string

I used BubbleUPnP for Android (you have to find a UPnP player that works for you) to play a music file. After that I opened Cling Workbench ( http://4thline.org/projects/cling/workbench/ ) choose my TV, choose AVTransport in the treeview and the "Use Service" button. The URI of the file played via BubbleUPnP is displayed under "Current URI". Then I did a HEAD call against that URI with the HEADERs I found via WireShark (important are getcontentFeatures.dlna.org, X-AV-Physical-Unit-Info and X-AV-Client-Info, you could also send a http GET to yourTV:52323/upnp/control/AVTransport instead of using WireShark, which returns X-AV-Physical-Unit-Info and X-AV-Client-Info in the response header).

HEAD call to BubbleUPnP on Android:

HEAD /external/audio/media/8588.mp3 HTTP/1.1
Host: 192.168.0.12:57645
Connection: keep-alive
Cache-Control: no-cache
X-AV-Physical-Unit-Info: pa="BRAVIA KDL-40EX505";
X-AV-Client-Info: av="5.0"; cn="Sony Corporation"; mn="BRAVIA KDL-40EX505"; mv="1.7";
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
getcontentFeatures.dlna.org: 1
Postman-Token: 39fabd1c-7464-6631-2645-c62cdca6f83d
Accept: */*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4

BubbleUPnP answers with the correct contentFeatures.dlna.org string

HTTP/1.1 200 OK
Date: Sat, 05 Mar 2016 21:31:37 GMT
Server: Android, UPnP/1.0 DLNADOC/1.50, BubbleUPnP/2.6.0.2-amz
Cache-Control: no-cache
transferMode.dlna.org: Streaming
contentFeatures.dlna.org: DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01700000000000000000000000000000
Content-Type: audio/mpeg
Last-Modified: Sat, 05 Mar 2016 18:21:43 GMT
Content-Length: 8523162
Accept-Ranges: bytes
like image 42
KeKru Avatar answered Nov 02 '22 09:11

KeKru