[vlc-devel] [PATCH] VLC as UPnP/DLNA MediaRenderer

Pierre Lamot pierre at videolabs.io
Wed Jul 10 10:03:16 CEST 2019


Hi,

This patch doesn't compile with the current version libupnp of from the 
contribs (1.6.19).
It probably needs to be updated first.

On 2019-07-06 17:13, Johan Gunnarsson wrote:
> This adds support for VLC to act as a UPnP/DLNA MediaRenderer on the
> LAN. This means a UPnP/DLNA control point can "cast" media to a VLC
> instance and control playback.
> 
> Consider this patch a proof of concept.
> ---
>  modules/control/dlna.cpp                    | 706 ++++++++++++++++++
>  modules/control/dlna.hpp                    |  68 ++
>  modules/services_discovery/Makefile.am      |   4 +-
>  modules/services_discovery/upnp-wrapper.cpp | 117 ++-
>  modules/services_discovery/upnp-wrapper.hpp |  11 +-
>  modules/services_discovery/upnp.cpp         |  15 +-
>  modules/services_discovery/upnp.hpp         |   1 +
>  modules/stream_out/dlna/dlna.hpp            |   2 +-
>  share/Makefile.am                           |   5 +
>  share/upnp/AVTransportSCPD.xml              | 585 +++++++++++++++
>  share/upnp/ConnectionManagerSCPD.xml        | 182 +++++
>  share/upnp/RenderingControlSCPD.xml         | 762 ++++++++++++++++++++
>  12 files changed, 2445 insertions(+), 13 deletions(-)
>  create mode 100644 modules/control/dlna.cpp
>  create mode 100644 modules/control/dlna.hpp
>  create mode 100644 share/upnp/AVTransportSCPD.xml
>  create mode 100644 share/upnp/ConnectionManagerSCPD.xml
>  create mode 100644 share/upnp/RenderingControlSCPD.xml
> 
> diff --git a/modules/control/dlna.cpp b/modules/control/dlna.cpp
> new file mode 100644
> index 0000000000..3f41ca515a
> --- /dev/null
> +++ b/modules/control/dlna.cpp
> @@ -0,0 +1,706 @@
> +/*****************************************************************************
> + * dlna.cpp :  DLNA MediaRenderer module
> + 
> *****************************************************************************
> + * Copyright (C) 2019 VLC authors and VideoLAN
> + *
> + * Authors: Johan Gunnarsson <johan.gunnarsson at gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or 
> modify it
> + * under the terms of the GNU Lesser General Public License as 
> published by
> + * the Free Software Foundation; either version 2.1 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public 
> License
> + * along with this program; if not, write to the Free Software 
> Foundation,
> + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
> + 
> *****************************************************************************/
> +
> +#ifdef HAVE_CONFIG_H
> +# include "config.h"
> +#endif
> +
> +#include <string>
> +#include <map>
> +#include <iostream>
> +#include <regex>
> +
> +#include "../services_discovery/upnp-wrapper.hpp"
> +
> +#include <vlc_plugin.h>
> +#include <vlc_interface.h>
> +#include <vlc_playlist.h>
> +#include <vlc_player.h>
> +#include <vlc_input.h>
> +
> +#include "dlna.hpp"
> +
> +#define SINK_PROTOCOL_INFO ("http-get:*:video/mpeg:*," \
> +                            "http-get:*:video/mp4:*," \
> +                            "http-get:*:video/vnd.dlna.mpeg-tts:*," \
> +                            "http-get:*:video/avi:*," \
> +                            "http-get:*:video/x-matroska:*," \
> +                            "http-get:*:video/x-ms-wmv:*," \
> +                            "http-get:*:video/wtv:*," \
> +                            "http-get:*:audio/mpeg:*," \
> +                            "http-get:*:audio/mp3:*," \
> +                            "http-get:*:audio/mp4:*," \
> +                            "http-get:*:audio/x-ms-wma*," \
> +                            "http-get:*:audio/wav:*," \
> +                            "http-get:*:audio/L16:*," \
> +                            "http-get:*image/jpeg:*," \
> +                            "http-get:*image/png:*," \
> +                            "http-get:*image/gif:*," \
> +                            "http-get:*image/tiff:*")
> +
> +struct intf_sys_t
> +{
> +    UpnpInstanceWrapper *p_upnp;
> +    std::shared_ptr<DLNA::EventHandler> p_listener;
> +    vlc_playlist_t *playlist;
> +    vlc_player_t *player;
> +    vlc_player_listener_id *p_player_listener;
> +    vlc_player_aout_listener_id *p_player_aout_listener;
> +};
> +
> +typedef std::map<std::string,std::string> parammap;
> +
> +typedef bool (*ActionRequestHandler)( parammap&, parammap&, 
> intf_thread_t* );
> +
> +namespace DLNA
> +{
> +
> +static bool
> +handle_AVT_SetAVTransportURI( parammap& in_params, parammap& 
> out_params,
> +                              intf_thread_t *p_intf )
> +{
> +    VLC_UNUSED(out_params);
> +
> +    std::string s = in_params["CurrentURI"];
> +
> +    input_item_t *item = input_item_New(s.c_str(), NULL);
> +    if( !item )
> +    {
> +        printf("failed to parse URL?");
> +        return -1;
> +    }
> +
> +    vlc_player_t *player = vlc_playlist_GetPlayer( 
> p_intf->p_sys->playlist );
> +
> +    vlc_player_Lock( player );
> +    vlc_player_SetCurrentMedia( player, item );
> +    vlc_player_Start( player );
> +    vlc_player_Unlock( player );
> +
> +    input_item_Release( item );
> +
> +    return true;
> +}
> +
> +static bool
> +handle_AVT_GetMediaInfo( parammap& in_params, parammap& out_params,
> +                         intf_thread_t *p_intf )
> +{
> +    VLC_UNUSED(in_params);
> +    VLC_UNUSED(p_intf);
> +
> +    out_params["MediaDuration"] = "00:00";
> +
> +    return true;
> +}
> +
> +
> +static bool
> +handle_AVT_GetTransportInfo( parammap& in_params, parammap& 
> out_params,
> +                             intf_thread_t *p_intf )
> +{
> +    VLC_UNUSED(in_params);
> +
> +    vlc_player_t *player = vlc_playlist_GetPlayer( 
> p_intf->p_sys->playlist );
> +
> +    vlc_player_Lock( player );
> +    enum vlc_player_state state = vlc_player_GetState( player );
> +    vlc_player_Unlock( player );
> +
> +    switch( state )
> +    {
> +    case VLC_PLAYER_STATE_STOPPED:
> +        out_params["CurrentTransportState"] = "STOPPED";
> +        break;
> +    case VLC_PLAYER_STATE_PLAYING:
> +        out_params["CurrentTransportState"] = "PLAYING";
> +        break;
> +    case VLC_PLAYER_STATE_PAUSED:
> +        out_params["CurrentTransportState"] = "PAUSED_PLAYBACK";
> +        break;
> +    case VLC_PLAYER_STATE_STARTED: /* fall through */
> +    case VLC_PLAYER_STATE_STOPPING:
> +        out_params["CurrentTransportState"] = "TRANSITIONING";
> +        break;
> +    default:
> +        out_params["CurrentTransportState"] = "UNKNOWN";
> +        break;
> +    }
> +
> +    out_params["CurrentTransportStatus"] = "";
> +    out_params["CurrentSpeed"] = "";
> +
> +    return true;
> +}
> +
> +static bool
> +handle_AVT_Stop( parammap& in_params, parammap& out_params,
> +                 intf_thread_t *p_intf )
> +{
> +    VLC_UNUSED(in_params);
> +    VLC_UNUSED(out_params);
> +
> +    vlc_player_t *player = vlc_playlist_GetPlayer( 
> p_intf->p_sys->playlist );
> +
> +    vlc_player_Lock( player );
> +    vlc_player_Stop( player );
> +    vlc_player_Unlock( player );
> +
> +    return true;
> +}
> +
> +static bool
> +handle_AVT_Play( parammap& in_params, parammap& out_params,
> +                 intf_thread_t *p_intf )
> +{
> +    VLC_UNUSED(in_params);
> +    VLC_UNUSED(out_params);
> +
> +    vlc_player_t *player = vlc_playlist_GetPlayer( 
> p_intf->p_sys->playlist );
> +
> +    vlc_player_Lock( player );
> +    vlc_player_Resume( player );
> +    vlc_player_Unlock( player );
> +
> +    return true;
> +}
> +
> +static bool
> +handle_AVT_Pause( parammap& in_params, parammap& out_params,
> +                  intf_thread_t *p_intf )
> +{
> +    VLC_UNUSED(in_params);
> +    VLC_UNUSED(out_params);
> +
> +    vlc_player_t *player = vlc_playlist_GetPlayer( 
> p_intf->p_sys->playlist );
> +
> +    vlc_player_Lock( player );
> +    vlc_player_Pause( player );
> +    vlc_player_Unlock( player );
> +
> +    return true;
> +}
> +
> +static bool
> +handle_CM_GetProtocolInfo( parammap& in_params, parammap& out_params,
> +                           intf_thread_t *p_intf )
> +{
> +    VLC_UNUSED(p_intf);
> +    VLC_UNUSED(in_params);
> +
> +    out_params["Source"] = "";
> +    out_params["Sink"] = SINK_PROTOCOL_INFO;
> +
> +    return true;
> +}
> +
> +static bool
> +handle_RC_GetVolume( parammap& in_params, parammap& out_params,
> +                     intf_thread_t *p_intf )
> +{
> +    VLC_UNUSED(in_params);
> +
> +    /* Volume as in range [0.0, 2.0] or -1.0 if no audio */
> +    float volume = vlc_player_aout_GetVolume( p_intf->p_sys->player );
> +    if( volume < 0.0 )
> +        volume = 0.0;
> +    else if( volume > 2.0 )
> +        volume = 2.0;
> +
> +    std::string v = std::to_string( std::round( volume * 50 ) );
> +
> +    out_params["CurrentVolume"] = v;
> +
> +    return true;
> +}
> +
> +static bool
> +handle_RC_SetVolume( parammap& in_params, parammap& out_params,
> +                     intf_thread_t *p_intf )
> +{
> +    VLC_UNUSED(out_params);
> +
> +    /* Volume in range [0, 100] */
> +    unsigned long volume = std::stoul( in_params["DesiredVolume"] );
> +    if( volume > 100 )
> +        volume = 100;
> +
> +    int ret = vlc_player_aout_SetVolume( p_intf->p_sys->player,
> volume / 50.0 );
> +    if ( ret != UPNP_E_SUCCESS )
> +    {
> +    }
> +
> +    return true;
> +}
> +
> +#define SRV_AVT "urn:upnp-org:serviceId:AVTransport"
> +#define SRV_RC  "urn:upnp-org:serviceId:RenderingControl"
> +#define SRV_CM  "urn:upnp-org:serviceId:ConnectionManager"
> +
> +static struct {
> +    const char *service;
> +    const char *action;
> +    ActionRequestHandler handler;
> +} actions[] = {
> +    { SRV_AVT, "SetAVTransportURI", handle_AVT_SetAVTransportURI },
> +    { SRV_AVT, "GetMediaInfo", handle_AVT_GetMediaInfo },
> +    { SRV_AVT, "GetTransportInfo", handle_AVT_GetTransportInfo },
> +    { SRV_AVT, "Stop", handle_AVT_Stop },
> +    { SRV_AVT, "Play", handle_AVT_Play },
> +    { SRV_AVT, "Pause", handle_AVT_Pause },
> +    { SRV_CM, "GetProtocolInfo", handle_CM_GetProtocolInfo },
> +    { SRV_RC, "GetVolume", handle_RC_GetVolume },
> +    { SRV_RC, "SetVolume", handle_RC_SetVolume },
> +    { NULL, NULL, NULL }
> +};
> +
> +static parammap
> +build_param_map( IXML_Node *p_node )
> +{
> +    parammap params;
> +
> +    for( IXML_Node *param = ixmlNode_getFirstChild( p_node );
> +         param != NULL;
> +         param = ixmlNode_getNextSibling( param ) )
> +    {
> +        const DOMString key = ixmlNode_getNodeName(param);
> +        if( !key )
> +            continue;
> +
> +        IXML_Node *vnode = ixmlNode_getFirstChild( param );
> +        if( !vnode )
> +            continue;
> +
> +        const DOMString value = ixmlNode_getNodeValue( vnode );
> +        if( !value )
> +            continue;
> +
> +        params[std::string(key)] = std::string(value);
> +    }
> +
> +    return params;
> +}
> +
> +static std::string
> +build_event_xml( const char **keys, const char **values, int count )
> +{
> +    IXML_Document *doc = NULL;
> +    IXML_Element *event = NULL;
> +    IXML_Element *instance = NULL;
> +    DOMString xmlcstr = NULL;
> +    std::string xmlstr;
> +
> +    doc = ixmlDocument_createDocument();
> +    if( !doc )
> +        return xmlstr;
> +
> +    event = ixmlDocument_createElement( doc, "Event" );
> +    if( !event )
> +        goto err1;
> +
> +    if( ixmlNode_appendChild( (IXML_Node *)doc,
> +                              (IXML_Node *)event ) != IXML_SUCCESS )
> +    {
> +        ixmlElement_free( event );
> +        goto err1;
> +    }
> +
> +    instance = ixmlDocument_createElement( doc, "InstanceID" );
> +    if( !instance )
> +        goto err1;
> +
> +    if( ixmlNode_appendChild( (IXML_Node *)event,
> +                              (IXML_Node *)instance ) != IXML_SUCCESS 
> )
> +    {
> +        ixmlElement_free( instance );
> +        goto err1;
> +    }
> +
> +    if( ixmlElement_setAttribute( instance, "val", "0") != 
> IXML_SUCCESS )
> +        goto err1;
> +
> +    for( int i = 0; i < count; i++ )
> +    {
> +        IXML_Element *arg = ixmlDocument_createElement( doc, keys[i] 
> );
> +        if( !arg )
> +            goto err1;
> +
> +        if( ixmlNode_appendChild( (IXML_Node *)instance,
> +                                  (IXML_Node *)arg ) != IXML_SUCCESS )
> +        {
> +            ixmlElement_free( arg );
> +            goto err1;
> +        }
> +
> +        if( ixmlElement_setAttribute( arg, "val", values[i]) != 
> IXML_SUCCESS )
> +            goto err1;
> +    }
> +
> +    xmlcstr = ixmlNodetoString( (IXML_Node *)doc );
> +    if( !xmlcstr )
> +        goto err1;
> +
> +    xmlstr = std::string(xmlcstr);
> +
> +    free( xmlcstr );
> +
> +    ixmlDocument_free( doc );
> +
> +    xmlstr = std::regex_replace(xmlstr, std::regex("&"), "&");
> +    xmlstr = std::regex_replace(xmlstr, std::regex("\""), """);
> +    xmlstr = std::regex_replace(xmlstr, std::regex("\'"), "'");
> +    xmlstr = std::regex_replace(xmlstr, std::regex("<"), "<");
> +    xmlstr = std::regex_replace(xmlstr, std::regex(">"), ">");
> +
> +    return xmlstr;
> +
> +err1:
> +    ixmlDocument_free( doc );
> +
> +    return xmlstr;
> +}
> +
> +int EventHandler::onActionRequest( UpnpActionRequest *p_event,
> +                                   void *p_user_data )
> +{
> +    (void) p_user_data;
> +
> +    /* For example urn:upnp-org:serviceId:AVTransport */
> +    char *service_id = UpnpActionRequest_get_ServiceID_cstr( p_event 
> );
> +
> +    /* For example SetAVTransportURI */
> +    char *action_name = UpnpActionRequest_get_ActionName_cstr( p_event 
> );
> +
> +    /* "Body" XML node in the request */
> +    IXML_Document *body = UpnpActionRequest_get_ActionRequest( p_event 
> );
> +    if( !body )
> +        return 0;
> +
> +    for( IXML_Node *action = ixmlNode_getFirstChild( (IXML_Node*) body 
> );
> +         action != NULL;
> +         action = ixmlNode_getNextSibling( action ) )
> +    {
> +        parammap in_params = build_param_map( action );
> +
> +        for( size_t i = 0; actions[i].handler; i++ )
> +        {
> +            if( strcmp( actions[i].service, service_id ) ||
> +                strcmp( actions[i].action, action_name ) )
> +                continue;
> +
> +            parammap out_params;
> +
> +            p_event->ErrCode = UPNP_E_SUCCESS;
> +            p_event->ActionResult = NULL;
> +
> +            int r = actions[i].handler( in_params, out_params, p_intf 
> );
> +            if( !r )
> +                continue;
> +
> +            p_event->ActionResult = UpnpMakeActionResponse( 
> action_name,
> +                                                            
> service_id,
> +                                                            0,
> +                                                            NULL );
> +            if( !p_event->ActionResult )
> +                continue;
> +
> +            for( auto& x : out_params )
> +            {
> +                int r = UpnpAddToActionResponse( 
> &p_event->ActionResult,
> +                                                 action_name,
> +                                                 service_id,
> +                                                 x.first.c_str(),
> +                                                 x.second.c_str() );
> +                if( r != UPNP_E_SUCCESS )
> +                {
> +                    if( p_event->ActionResult != NULL )
> +                        ixmlDocument_free( p_event->ActionResult );
> +                    p_event->ActionResult = NULL;
> +
> +                    return r;
> +                }
> +            }
> +
> +            return UPNP_E_SUCCESS;
> +        }
> +    }
> +
> +    // TODO: return "not implemented"
> +
> +    return UPNP_E_INTERNAL_ERROR;
> +}
> +
> +int EventHandler::onGetVarRequest( UpnpStateVarRequest *p_event,
> +                                   void *p_user_data )
> +{
> +    (void) p_event;
> +    (void) p_user_data;
> +
> +    // TODO
> +
> +    return -124;
> +}
> +
> +int EventHandler::onSubscriptionRequest( UpnpSubscriptionRequest 
> *p_event,
> +                                         void *p_user_data )
> +{
> +    (void) p_user_data;
> +
> +    /* For example urn:upnp-org:serviceId:AVTransport */
> +    char *service_id = UpnpSubscriptionRequest_get_ServiceId_cstr( 
> p_event );
> +
> +    /* For example ... */
> +    char *udn = UpnpSubscriptionRequest_get_UDN_cstr( p_event );
> +
> +    std::string event_xml = build_event_xml( NULL, NULL, 0 );
> +std::cout << event_xml << std::endl;
> +
> +    const char *var_keys[1] = { "LastChange" };
> +    const char *var_values[1] = { event_xml.c_str() };
> +
> +    int ret = UpnpAcceptSubscription( 
> p_intf->p_sys->p_upnp->device_handle(),
> +                                      udn,
> +                                      service_id,
> +                                      (const char **) &var_keys,
> +                                      (const char **) &var_values,
> +                                      1,
> +                                      p_event->Sid );
> +    if( ret != UPNP_E_SUCCESS )
> +    {
> +        printf("UpnpAcceptSubscription failed\n");
> +    }
> +
> +    return ret;
> +}
> +
> +int EventHandler::onEvent( Upnp_EventType event_type,
> +                           UpnpEventPtr p_event,
> +                           void* p_user_data )
> +{
> +    switch( event_type )
> +    {
> +    case UPNP_CONTROL_ACTION_REQUEST:
> +        return onActionRequest( (UpnpActionRequest *) p_event, 
> p_user_data );
> +    case UPNP_CONTROL_GET_VAR_REQUEST:
> +        return onGetVarRequest( (UpnpStateVarRequest *) p_event, 
> p_user_data );
> +    case UPNP_EVENT_SUBSCRIPTION_REQUEST:
> +        return onSubscriptionRequest( (UpnpSubscriptionRequest *) 
> p_event,
> +                                      p_user_data );
> +    default:
> +        break;
> +    }
> +
> +    return -123;
> +}
> +
> +static void
> +player_state_changed( vlc_player_t *player, enum vlc_player_state 
> state,
> +                      void *data )
> +{
> +    (void) player;
> +
> +    intf_thread_t *p_intf = (intf_thread_t *)data;
> +
> +    const char *new_state;
> +
> +    switch (state)
> +    {
> +    case VLC_PLAYER_STATE_STOPPED:
> +        new_state = "STOPPED";
> +        break;
> +    case VLC_PLAYER_STATE_PLAYING:
> +        new_state = "PLAYING";
> +        break;
> +    case VLC_PLAYER_STATE_PAUSED:
> +        new_state = "PAUSED_PLAYBACK";
> +        break;
> +    case VLC_PLAYER_STATE_STARTED: /* fall through */
> +    case VLC_PLAYER_STATE_STOPPING:
> +        new_state = "TRANSITIONING";
> +        break;
> +    default:
> +        new_state = "UNKNOWN";
> +        break;
> +    }
> +
> +    const char *event_keys[1] = { "TransportState" };
> +    const char *event_values[1] = { new_state };
> +
> +    std::string event_xml = build_event_xml( event_keys, event_values, 
> 1 );
> +std::cout << event_xml << std::endl;
> +
> +    const char *var_keys[1] = { "LastChange" };
> +    const char *var_values[1] = { event_xml.c_str() };
> +
> +    int ret = UpnpNotify( p_intf->p_sys->p_upnp->device_handle(),
> +                          UPNP_UDN,
> +                          SRV_AVT,
> +                          (const char **) &var_keys,
> +                          (const char **) &var_values,
> +                          1 );
> +    if ( ret != UPNP_E_SUCCESS )
> +    {
> +        printf("UpnpNotify failed\n");
> +    }
> +}
> +
> +static void
> +player_aout_volume_changed( vlc_player_t *player, float new_volume,
> +                            void *data )
> +{
> +    (void) player;
> +
> +    intf_thread_t *p_intf = (intf_thread_t *) data;
> +
> +    if( new_volume < 0.0 )
> +        new_volume = 0.0;
> +    else if( new_volume > 2.0 )
> +        new_volume = 2.0;
> +
> +    /* Volume in range [0, 100] */
> +    std::string v = std::to_string( std::round( new_volume * 50 ) );
> +
> +    const char *event_keys[1] = { "Volume" };
> +    const char *event_values[1] = { v.c_str() };
> +
> +    std::string event_xml = build_event_xml( event_keys, event_values, 
> 1 );
> +std::cout << event_xml << std::endl;
> +
> +    const char *var_keys[1] = { "LastChange" };
> +    const char *var_values[1] = { event_xml.c_str() };
> +
> +    int ret = UpnpNotify( p_intf->p_sys->p_upnp->device_handle(),
> +                          UPNP_UDN,
> +                          SRV_RC,
> +                          (const char **) &var_keys,
> +                          (const char **) &var_values,
> +                          1 );
> +    if ( ret != UPNP_E_SUCCESS )
> +    {
> +        printf("UpnpNotify failed\n");
> +    }
> +}
> +
> +int OpenControl( vlc_object_t *p_this )
> +{
> +    intf_thread_t *p_intf = (intf_thread_t *)p_this;
> +
> +    p_intf->p_sys = (intf_sys_t *)calloc ( 1, sizeof( intf_sys_t ) );
> +    if( unlikely(p_intf->p_sys == NULL) )
> +        return VLC_ENOMEM;
> +
> +    p_intf->p_sys->playlist = vlc_intf_GetMainPlaylist( p_intf );
> +    if( !p_intf->p_sys->playlist )
> +        goto error1;
> +
> +    p_intf->p_sys->p_upnp = UpnpInstanceWrapper::get( p_this );
> +    if( !p_intf->p_sys->p_upnp )
> +        goto error1;
> +
> +    /* Start the UPnP MediaRenderer service */
> +    p_intf->p_sys->p_upnp->startMediaRenderer( p_this );
> +    try
> +    {
> +        p_intf->p_sys->p_listener =
> +            std::make_shared<DLNA::EventHandler>( p_intf );
> +    }
> +    catch ( const std::bad_alloc& )
> +    {
> +        msg_Err( p_this, "Failed to alloc");
> +        goto error2;
> +    }
> +
> +    p_intf->p_sys->p_upnp->addListener( p_intf->p_sys->p_listener );
> +
> +    static struct vlc_player_cbs player_cbs = {};
> +    player_cbs.on_state_changed = player_state_changed;
> +
> +    static struct vlc_player_aout_cbs player_aout_cbs = {};
> +    player_aout_cbs.on_volume_changed = player_aout_volume_changed;
> +
> +    p_intf->p_sys->player = vlc_playlist_GetPlayer( 
> p_intf->p_sys->playlist );
> +    if( !p_intf->p_sys->player )
> +        goto error2;
> +
> +    vlc_playlist_Lock( p_intf->p_sys->playlist );
> +
> +    p_intf->p_sys->p_player_listener =
> +        vlc_player_AddListener( p_intf->p_sys->player, &player_cbs, 
> p_intf );
> +    if ( !p_intf->p_sys->p_player_listener )
> +        goto error3;
> +
> +    p_intf->p_sys->p_player_aout_listener =
> +        vlc_player_aout_AddListener( p_intf->p_sys->player, 
> &player_aout_cbs,
> +                                     p_intf );
> +    if ( !p_intf->p_sys->p_player_aout_listener )
> +        goto error4;
> +
> +    vlc_playlist_Unlock( p_intf->p_sys->playlist );
> +
> +    msg_Info( p_this, "Started MediaRenderer service");
> +
> +    return VLC_SUCCESS;
> +
> +error4:
> +    vlc_playlist_Lock( p_intf->p_sys->playlist );
> +    vlc_player_RemoveListener( p_intf->p_sys->player,
> +                               p_intf->p_sys->p_player_listener );
> +    vlc_playlist_Unlock( p_intf->p_sys->playlist );
> +
> +error3:
> +    p_intf->p_sys->p_upnp->removeListener( p_intf->p_sys->p_listener 
> );
> +
> +error2:
> +    p_intf->p_sys->p_upnp->release();
> +
> +error1:
> +    free( p_intf->p_sys );
> +
> +    return VLC_EGENERIC;
> +}
> +
> +void CloseControl( vlc_object_t *p_this )
> +{
> +    intf_thread_t *p_intf = (intf_thread_t *)p_this;
> +
> +    /* Remove player listeners */
> +    vlc_playlist_Lock( p_intf->p_sys->playlist );
> +    vlc_player_aout_RemoveListener( p_intf->p_sys->player,
> +                                    
> p_intf->p_sys->p_player_aout_listener );
> +    vlc_player_RemoveListener( p_intf->p_sys->player,
> +                               p_intf->p_sys->p_player_listener );
> +    vlc_playlist_Unlock( p_intf->p_sys->playlist );
> +
> +    /* Remove UPnP listener */
> +    p_intf->p_sys->p_upnp->removeListener( p_intf->p_sys->p_listener 
> );
> +
> +    /* Stop the UPnP MediaRenderer service */
> +    p_intf->p_sys->p_upnp->stopMediaRenderer( p_this );
> +
> +    p_intf->p_sys->p_upnp->release();
> +
> +    free( p_intf->p_sys );
> +
> +    msg_Info( p_this, "Stopped MediaRenderer service");
> +}
> +
> +} // namespace DLNA
> diff --git a/modules/control/dlna.hpp b/modules/control/dlna.hpp
> new file mode 100644
> index 0000000000..c6ee6439a8
> --- /dev/null
> +++ b/modules/control/dlna.hpp
> @@ -0,0 +1,68 @@
> +/*****************************************************************************
> + * dlna.cpp :  DLNA MediaRenderer module
> + 
> *****************************************************************************
> + * Copyright (C) 2019 VLC authors and VideoLAN
> + *
> + * Authors: Johan Gunnarsson <johan.gunnarsson at gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or 
> modify it
> + * under the terms of the GNU Lesser General Public License as 
> published by
> + * the Free Software Foundation; either version 2.1 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public 
> License
> + * along with this program; if not, write to the Free Software 
> Foundation,
> + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
> + 
> *****************************************************************************/
> +
> +#ifndef CONTROL_DLNA_H
> +#define CONTROL_DLNA_H
> +
> +#include "../services_discovery/upnp-wrapper.hpp"
> +
> +#include <vlc_plugin.h>
> +#include <vlc_interface.h>
> +
> +namespace DLNA
> +{
> +
> +int OpenControl( vlc_object_t *p_this );
> +void CloseControl( vlc_object_t *p_this );
> +
> +class EventHandler : public UpnpInstanceWrapper::Listener
> +{
> +public:
> +    EventHandler( intf_thread_t *_p_intf )
> +        : p_intf( _p_intf )
> +    {
> +    }
> +
> +    ~EventHandler()
> +    {
> +    }
> +
> +    int onEvent( Upnp_EventType event_type,
> +                 UpnpEventPtr p_event,
> +                 void *p_user_data ) override;
> +
> +private:
> +    intf_thread_t *p_intf = NULL;
> +
> +    int onActionRequest( UpnpActionRequest *p_event,
> +                         void *p_user_data );
> +
> +    int onGetVarRequest( UpnpStateVarRequest *p_event,
> +                         void *p_user_data );
> +
> +    int onSubscriptionRequest( UpnpSubscriptionRequest *p_event,
> +                               void *p_user_data );
> +};
> +
> +} // namespace DLNA
> +
> +#endif
> diff --git a/modules/services_discovery/Makefile.am
> b/modules/services_discovery/Makefile.am
> index 72c21efb56..65af52edf8 100644
> --- a/modules/services_discovery/Makefile.am
> +++ b/modules/services_discovery/Makefile.am
> @@ -31,7 +31,9 @@ libupnp_plugin_la_SOURCES =
> services_discovery/upnp.cpp services_discovery/upnp.
>  			    stream_out/dlna/profile_names.hpp \
>  			    stream_out/dlna/dlna_common.hpp \
>  			    stream_out/dlna/dlna.hpp \
> -			    stream_out/dlna/dlna.cpp
> +			    stream_out/dlna/dlna.cpp \
> +			    control/dlna.hpp \
> +			    control/dlna.cpp
>  libupnp_plugin_la_CXXFLAGS = $(AM_CXXFLAGS) $(UPNP_CFLAGS)
>  libupnp_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(sddir)'
>  libupnp_plugin_la_LIBADD = $(UPNP_LIBS)
> diff --git a/modules/services_discovery/upnp-wrapper.cpp
> b/modules/services_discovery/upnp-wrapper.cpp
> index c001492f37..9f3748ec21 100644
> --- a/modules/services_discovery/upnp-wrapper.cpp
> +++ b/modules/services_discovery/upnp-wrapper.cpp
> @@ -36,19 +36,65 @@
>  #include "upnp-wrapper.hpp"
>  #include <vlc_cxx_helpers.hpp>
> 
> +static const char *mediarenderer_desc =
> +    "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
> +    "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
> +      "<specVersion>"
> +        "<major>1</major>"
> +        "<minor>0</minor>"
> +      "</specVersion>"
> +      "<device>"
> +        
> "<deviceType>urn:schemas-upnp-org:device:MediaRenderer:1</deviceType>"
> +        "<friendlyName>VLC media player</friendlyName>" /* TODO:
> include hostname */
> +        "<manufacturer>VideoLAN</manufacturer>"
> +        "<modelName>" PACKAGE_NAME "</modelName>"
> +        "<modelNumber>" PACKAGE_VERSION "</modelNumber>"
> +        "<modelURL>https://www.videolan.org/vlc/</modelURL>"
> +        "<UDN>" UPNP_UDN "</UDN>" /* TODO: generate at each startup */
> +        "<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>"
> +        "</serviceList>"
> +      "</device>"
> +    "</root>";
> +
>  UpnpInstanceWrapper* UpnpInstanceWrapper::s_instance;
>  UpnpInstanceWrapper::Listeners UpnpInstanceWrapper::s_listeners;
>  vlc_mutex_t UpnpInstanceWrapper::s_lock = VLC_STATIC_MUTEX;
> 
>  UpnpInstanceWrapper::UpnpInstanceWrapper()
> -    : m_handle( -1 )
> +    : m_client_handle( -1 )
> +    , m_device_handle( -1 )
>      , m_refcount( 0 )
> +    , m_mediarenderer_refcount( 0 )
>  {
>  }
> 
>  UpnpInstanceWrapper::~UpnpInstanceWrapper()
>  {
> -    UpnpUnRegisterClient( m_handle );
> +    if( m_client_handle > 0 )
> +        UpnpUnRegisterClient( m_client_handle );
> +    if( m_device_handle > 0 )
> +        UpnpUnRegisterRootDevice( m_device_handle );
>      UpnpFinish();
>  }
> 
> @@ -86,7 +132,7 @@ UpnpInstanceWrapper
> *UpnpInstanceWrapper::get(vlc_object_t *p_obj)
>          ixmlRelaxParser( 1 );
> 
>          /* Register a control point */
> -        i_res = UpnpRegisterClient( Callback, NULL, 
> &instance->m_handle );
> +        i_res = UpnpRegisterClient( Callback, NULL,
> &instance->m_client_handle );
>          if( i_res != UPNP_E_SUCCESS )
>          {
>              msg_Err( p_obj, "Client registration failed: %s",
> UpnpGetErrorMessage( i_res ) );
> @@ -104,6 +150,15 @@ UpnpInstanceWrapper
> *UpnpInstanceWrapper::get(vlc_object_t *p_obj)
>              delete instance;
>              return NULL;
>          }
> +
> +        char *root = config_GetSysPath( VLC_PKG_DATA_DIR, "upnp" );
> +        if( (i_res = UpnpSetWebServerRootDir( root )) != 
> UPNP_E_SUCCESS)
> +        {
> +            msg_Warn( p_obj, "UpnpSetWebServerRootDir failed: %s",
> +                      UpnpGetErrorMessage( i_res ));
> +        }
> +        free( root );
> +
>          s_instance = instance;
>      }
>      s_instance->m_refcount++;
> @@ -123,9 +178,14 @@ void UpnpInstanceWrapper::release()
>      delete p_delete;
>  }
> 
> -UpnpClient_Handle UpnpInstanceWrapper::handle() const
> +UpnpClient_Handle UpnpInstanceWrapper::client_handle() const
> +{
> +    return m_client_handle;
> +}
> +
> +UpnpDevice_Handle UpnpInstanceWrapper::device_handle() const
>  {
> -    return m_handle;
> +    return m_device_handle;
>  }
> 
>  int UpnpInstanceWrapper::Callback(Upnp_EventType event_type,
> UpnpEventPtr p_event, void *p_user_data)
> @@ -153,3 +213,50 @@ void
> UpnpInstanceWrapper::removeListener(ListenerPtr listener)
>      if ( iter != s_listeners.end() )
>          s_listeners.erase( iter );
>  }
> +
> +void UpnpInstanceWrapper::startMediaRenderer( vlc_object_t *p_obj )
> +{
> +    vlc::threads::mutex_locker lock( &s_lock );
> +    if( m_mediarenderer_refcount == 0 )
> +    {
> +        int i_res;
> +        if( (i_res = UpnpEnableWebserver( TRUE )) != UPNP_E_SUCCESS)
> +        {
> +            msg_Err( p_obj, "Failed to enable webserver: %s",
> UpnpGetErrorMessage( i_res ) );
> +            return;
> +        }
> +        i_res = UpnpRegisterRootDevice2( UPNPREG_BUF_DESC,
> +                                         mediarenderer_desc,
> +                                         strlen(mediarenderer_desc),
> +                                         1,
> +                                         Callback,
> +                                         NULL,
> +                                         &m_device_handle );
> +        if( i_res != UPNP_E_SUCCESS )
> +        {
> +            msg_Err( p_obj, "Device registration failed: %s",
> UpnpGetErrorMessage( i_res ) );
> +        }
> +    }
> +    m_mediarenderer_refcount++;
> +}
> +
> +void UpnpInstanceWrapper::stopMediaRenderer( vlc_object_t *p_obj )
> +{
> +    vlc::threads::mutex_locker lock( &s_lock );
> +    m_mediarenderer_refcount--;
> +    if( m_mediarenderer_refcount == 0 )
> +    {
> +        int i_res;
> +        i_res = UpnpUnRegisterRootDevice( m_device_handle );
> +        if( i_res != UPNP_E_SUCCESS )
> +        {
> +            msg_Err( p_obj, "Device unregistration failed: %s",
> UpnpGetErrorMessage( i_res ) );
> +        }
> +        m_device_handle = -1;
> +        i_res = UpnpEnableWebserver( FALSE );
> +        if( i_res != UPNP_E_SUCCESS )
> +        {
> +            msg_Warn( p_obj, "Failed to disable webserver: %s",
> UpnpGetErrorMessage( i_res ) );
> +        }
> +    }
> +}
> diff --git a/modules/services_discovery/upnp-wrapper.hpp
> b/modules/services_discovery/upnp-wrapper.hpp
> index 3002599172..e0e4652b08 100644
> --- a/modules/services_discovery/upnp-wrapper.hpp
> +++ b/modules/services_discovery/upnp-wrapper.hpp
> @@ -41,6 +41,8 @@
>  #include <upnp.h>
>  #include <upnptools.h>
> 
> +#define UPNP_UDN "uuid:034fc8dc-ec22-44e5-a79b-38c935f11663"
> +
>  #if UPNP_VERSION < 10800
>  typedef void* UpnpEventPtr;
>  #else
> @@ -70,8 +72,10 @@ public:
>  private:
>      static UpnpInstanceWrapper* s_instance;
>      static vlc_mutex_t s_lock;
> -    UpnpClient_Handle m_handle;
> +    UpnpClient_Handle m_client_handle;
> +    UpnpClient_Handle m_device_handle;
>      int m_refcount;
> +    int m_mediarenderer_refcount;
>      typedef std::shared_ptr<Listener> ListenerPtr;
>      typedef std::vector<ListenerPtr> Listeners;
>      static Listeners s_listeners;
> @@ -80,9 +84,12 @@ public:
>      // This increases the refcount before returning the instance
>      static UpnpInstanceWrapper* get( vlc_object_t* p_obj );
>      void release();
> -    UpnpClient_Handle handle() const;
> +    UpnpClient_Handle client_handle() const;
> +    UpnpDevice_Handle device_handle() const;
>      void addListener(ListenerPtr listener);
>      void removeListener(ListenerPtr listener);
> +    void startMediaRenderer( vlc_object_t *p_obj );
> +    void stopMediaRenderer( vlc_object_t *p_obj );
> 
>  private:
>      static int Callback( Upnp_EventType event_type, UpnpEventPtr
> p_event, void* p_user_data );
> diff --git a/modules/services_discovery/upnp.cpp
> b/modules/services_discovery/upnp.cpp
> index a467caaaa8..310969f908 100644
> --- a/modules/services_discovery/upnp.cpp
> +++ b/modules/services_discovery/upnp.cpp
> @@ -180,6 +180,13 @@ vlc_module_begin()
>          add_string(SOUT_CFG_PREFIX "base_url", NULL, BASE_URL_TEXT,
> BASE_URL_LONGTEXT, false)
>          add_string(SOUT_CFG_PREFIX "url", NULL, URL_TEXT, 
> URL_LONGTEXT, false)
>          add_renderer_opts(SOUT_CFG_PREFIX)
> +
> +    add_submodule()
> +        set_description( N_("UPnP/DLNA MediaRenderer") )
> +        set_category( CAT_INTERFACE )
> +        set_subcategory( SUBCAT_INTERFACE_CONTROL )
> +        set_callbacks( DLNA::OpenControl, DLNA::CloseControl )
> +        set_capability( "interface", 0 )
>  vlc_module_end()
> 
>  /*
> @@ -271,7 +278,7 @@ SearchThread( void *p_data )
>      services_discovery_sys_t *p_sys =
> reinterpret_cast<services_discovery_sys_t *>( p_sd->p_sys );
> 
>      /* Search for media servers */
> -    int i_res = UpnpSearchAsync( p_sys->p_upnp->handle(), 5,
> +    int i_res = UpnpSearchAsync( p_sys->p_upnp->client_handle(), 5,
>              MEDIA_SERVER_DEVICE_TYPE, MEDIA_SERVER_DEVICE_TYPE );
>      if( i_res != UPNP_E_SUCCESS )
>      {
> @@ -280,7 +287,7 @@ SearchThread( void *p_data )
>      }
> 
>      /* Search for Sat Ip servers*/
> -    i_res = UpnpSearchAsync( p_sys->p_upnp->handle(), 5,
> +    i_res = UpnpSearchAsync( p_sys->p_upnp->client_handle(), 5,
>              SATIP_SERVER_DEVICE_TYPE, MEDIA_SERVER_DEVICE_TYPE );
>      if( i_res != UPNP_E_SUCCESS )
>          msg_Err( p_sd, "Error sending search request: %s",
> UpnpGetErrorMessage( i_res ) );
> @@ -1249,7 +1256,7 @@ IXML_Document* MediaServer::_browseAction( const
> char* psz_object_id_,
>      /* Setup an interruptible callback that will call sendActionCb if 
> not
>       * interrupted by vlc_interrupt_kill */
>      i11eCb = new Upnp_i11e_cb( sendActionCb, &p_response );
> -    i_res = UpnpSendActionAsync( sys->p_upnp->handle(),
> +    i_res = UpnpSendActionAsync( sys->p_upnp->client_handle(),
>                m_psz_root,
>                CONTENT_DIRECTORY_SERVICE_TYPE,
>                NULL, /* ignored in SDK, must be NULL */
> @@ -1587,7 +1594,7 @@ void *SearchThread(void *data)
>      renderer_discovery_sys_t *p_sys = 
> (renderer_discovery_sys_t*)p_rd->p_sys;
>      int i_res;
> 
> -    i_res = UpnpSearchAsync(p_sys->p_upnp->handle(),
> UPNP_SEARCH_TIMEOUT_SECONDS,
> +    i_res = UpnpSearchAsync(p_sys->p_upnp->client_handle(),
> UPNP_SEARCH_TIMEOUT_SECONDS,
>              MEDIA_RENDERER_DEVICE_TYPE, MEDIA_RENDERER_DEVICE_TYPE);
>      if( i_res != UPNP_E_SUCCESS )
>      {
> diff --git a/modules/services_discovery/upnp.hpp
> b/modules/services_discovery/upnp.hpp
> index 4eef534f91..ca527af250 100644
> --- a/modules/services_discovery/upnp.hpp
> +++ b/modules/services_discovery/upnp.hpp
> @@ -29,6 +29,7 @@
> 
>  #include "upnp-wrapper.hpp"
>  #include "../stream_out/dlna/dlna_common.hpp"
> +#include "../control/dlna.hpp"
> 
>  #include <vlc_url.h>
>  #include <vlc_interrupt.h>
> diff --git a/modules/stream_out/dlna/dlna.hpp 
> b/modules/stream_out/dlna/dlna.hpp
> index 128ee1c423..6bda6a7587 100644
> --- a/modules/stream_out/dlna/dlna.hpp
> +++ b/modules/stream_out/dlna/dlna.hpp
> @@ -76,7 +76,7 @@ public:
>          : parent(p_stream)
>          , base_url(base_url)
>          , device_url(device_url)
> -        , handle(upnp->handle())
> +        , handle(upnp->client_handle())
>          , ConnectionID("0")
>          , AVTransportID("0")
>          , RcsID("0")
> diff --git a/share/Makefile.am b/share/Makefile.am
> index e5b801a5be..3c2b34641b 100644
> --- a/share/Makefile.am
> +++ b/share/Makefile.am
> @@ -67,6 +67,11 @@ if KDE_SOLID
>  soliddata_DATA = $(DIST_solid)
>  endif
> 
> +nobase_dist_pkgdata_DATA += \
> +	upnp/AVTransportSCPD.xml \
> +	upnp/ConnectionManagerSCPD.xml \
> +	upnp/RenderingControlSCPD.xml
> +
>  DIST_icons = \
>  	vlc512x512.png
> 
> diff --git a/share/upnp/AVTransportSCPD.xml 
> b/share/upnp/AVTransportSCPD.xml
> new file mode 100644
> index 0000000000..fbb75f9978
> --- /dev/null
> +++ b/share/upnp/AVTransportSCPD.xml
> @@ -0,0 +1,585 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<scpd xmlns="urn:schemas-upnp-org:service-1-0">
> +   <specVersion>
> +      <major>1</major>
> +      <minor>0</minor>
> +   </specVersion>
> +   <actionList>
> +      <action>
> +         <name>SetAVTransportURI</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentURI</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>AVTransportURI</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentURIMetaData</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>AVTransportURIMetaData</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetNextAVTransportURI</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>NextURI</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>NextAVTransportURI</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>NextURIMetaData</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>NextAVTransportURIMetaData</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetMediaInfo</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>NrTracks</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>NumberOfTracks</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>MediaDuration</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>CurrentMediaDuration</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentURI</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>AVTransportURI</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentURIMetaData</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>AVTransportURIMetaData</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>NextURI</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>NextAVTransportURI</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>NextURIMetaData</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>NextAVTransportURIMetaData</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>PlayMedium</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>PlaybackStorageMedium</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>RecordMedium</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>RecordStorageMedium</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>WriteStatus</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>RecordMediumWriteStatus</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetTransportInfo</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentTransportState</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>TransportState</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentTransportStatus</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>TransportStatus</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentSpeed</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>TransportPlaySpeed</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetPositionInfo</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Track</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>CurrentTrack</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>TrackDuration</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>CurrentTrackDuration</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>TrackMetaData</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>CurrentTrackMetaData</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>TrackURI</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>CurrentTrackURI</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>RelTime</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>RelativeTimePosition</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>AbsTime</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>AbsoluteTimePosition</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>RelCount</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>RelativeCounterPosition</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>AbsCount</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>AbsoluteCounterPosition</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetDeviceCapabilities</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>PlayMedia</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>PossiblePlaybackStorageMedia</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>RecMedia</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>PossibleRecordStorageMedia</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>RecQualityModes</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>PossibleRecordQualityModes</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetTransportSettings</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>PlayMode</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>CurrentPlayMode</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>RecQualityMode</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>CurrentRecordQualityMode</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>Stop</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>Play</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Speed</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>TransportPlaySpeed</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>Pause</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>Seek</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Unit</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>A_ARG_TYPE_SeekMode</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Target</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_SeekTarget</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>Next</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>Previous</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetPlayMode</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>NewPlayMode</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>CurrentPlayMode</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetCurrentTransportActions</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Actions</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>CurrentTransportActions</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +   </actionList>
> +   <serviceStateTable>
> +      <stateVariable sendEvents="no">
> +         <name>TransportState</name>
> +         <dataType>string</dataType>
> +         <allowedValueList>
> +            <allowedValue>STOPPED</allowedValue>
> +            <allowedValue>PAUSED_PLAYBACK</allowedValue>
> +            <allowedValue>PAUSED_RECORDING</allowedValue>
> +            <allowedValue>PLAYING</allowedValue>
> +            <allowedValue>RECORDING</allowedValue>
> +            <allowedValue>TRANSITIONING</allowedValue>
> +            <allowedValue>NO_MEDIA_PRESENT</allowedValue>
> +         </allowedValueList>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>TransportStatus</name>
> +         <dataType>string</dataType>
> +         <allowedValueList>
> +            <allowedValue>OK</allowedValue>
> +            <allowedValue>ERROR_OCCURRED</allowedValue>
> +            <allowedValue>vendor-defined</allowedValue>
> +         </allowedValueList>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>PlaybackStorageMedium</name>
> +         <dataType>string</dataType>
> +         <allowedValueList>
> +            <allowedValue>UNKNOWN</allowedValue>
> +            <allowedValue>DV</allowedValue>
> +            <allowedValue>MINI-DV</allowedValue>
> +            <allowedValue>VHS</allowedValue>
> +            <allowedValue>W-VHS</allowedValue>
> +            <allowedValue>S-VHS</allowedValue>
> +            <allowedValue>D-VHS</allowedValue>
> +            <allowedValue>VHSC</allowedValue>
> +            <allowedValue>VIDEO8</allowedValue>
> +            <allowedValue>HI8</allowedValue>
> +            <allowedValue>CD-ROM</allowedValue>
> +            <allowedValue>CD-DA</allowedValue>
> +            <allowedValue>CD-R</allowedValue>
> +            <allowedValue>CD-RW</allowedValue>
> +            <allowedValue>VIDEO-CD</allowedValue>
> +            <allowedValue>SACD</allowedValue>
> +            <allowedValue>MD-AUDIO</allowedValue>
> +            <allowedValue>MD-PICTURE</allowedValue>
> +            <allowedValue>DVD-ROM</allowedValue>
> +            <allowedValue>DVD-VIDEO</allowedValue>
> +            <allowedValue>DVD-R</allowedValue>
> +            <allowedValue>DVD+RW</allowedValue>
> +            <allowedValue>DVD-RW</allowedValue>
> +            <allowedValue>DVD-RAM</allowedValue>
> +            <allowedValue>DVD-AUDIO</allowedValue>
> +            <allowedValue>DAT</allowedValue>
> +            <allowedValue>LD</allowedValue>
> +            <allowedValue>HDD</allowedValue>
> +            <allowedValue>MICRO-MV</allowedValue>
> +            <allowedValue>NETWORK</allowedValue>
> +            <allowedValue>NONE</allowedValue>
> +            <allowedValue>NOT_IMPLEMENTED</allowedValue>
> +            <allowedValue>vendor-defined</allowedValue>
> +         </allowedValueList>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>RecordStorageMedium</name>
> +         <dataType>string</dataType>
> +         <allowedValueList>
> +            <allowedValue>UNKNOWN</allowedValue>
> +            <allowedValue>DV</allowedValue>
> +            <allowedValue>MINI-DV</allowedValue>
> +            <allowedValue>VHS</allowedValue>
> +            <allowedValue>W-VHS</allowedValue>
> +            <allowedValue>S-VHS</allowedValue>
> +            <allowedValue>D-VHS</allowedValue>
> +            <allowedValue>VHSC</allowedValue>
> +            <allowedValue>VIDEO8</allowedValue>
> +            <allowedValue>HI8</allowedValue>
> +            <allowedValue>CD-ROM</allowedValue>
> +            <allowedValue>CD-DA</allowedValue>
> +            <allowedValue>CD-R</allowedValue>
> +            <allowedValue>CD-RW</allowedValue>
> +            <allowedValue>VIDEO-CD</allowedValue>
> +            <allowedValue>SACD</allowedValue>
> +            <allowedValue>MD-AUDIO</allowedValue>
> +            <allowedValue>MD-PICTURE</allowedValue>
> +            <allowedValue>DVD-ROM</allowedValue>
> +            <allowedValue>DVD-VIDEO</allowedValue>
> +            <allowedValue>DVD-R</allowedValue>
> +            <allowedValue>DVD+RW</allowedValue>
> +            <allowedValue>DVD-RW</allowedValue>
> +            <allowedValue>DVD-RAM</allowedValue>
> +            <allowedValue>DVD-AUDIO</allowedValue>
> +            <allowedValue>DAT</allowedValue>
> +            <allowedValue>LD</allowedValue>
> +            <allowedValue>HDD</allowedValue>
> +            <allowedValue>MICRO-MV</allowedValue>
> +            <allowedValue>NETWORK</allowedValue>
> +            <allowedValue>NONE</allowedValue>
> +            <allowedValue>NOT_IMPLEMENTED</allowedValue>
> +            <allowedValue>vendor-defined</allowedValue>
> +         </allowedValueList>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>PossiblePlaybackStorageMedia</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>PossibleRecordStorageMedia</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>CurrentPlayMode</name>
> +         <dataType>string</dataType>
> +         <allowedValueList>
> +            <allowedValue>NORMAL</allowedValue>
> +            <allowedValue>SHUFFLE</allowedValue>
> +            <allowedValue>REPEAT_ONE</allowedValue>
> +            <allowedValue>REPEAT_ALL</allowedValue>
> +            <allowedValue>RANDOM</allowedValue>
> +            <allowedValue>DIRECT_1</allowedValue>
> +            <allowedValue>INTRO</allowedValue>
> +         </allowedValueList>
> +         <defaultValue>NORMAL</defaultValue>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>TransportPlaySpeed</name>
> +         <dataType>string</dataType>
> +         <allowedValueList>
> +            <allowedValue>1</allowedValue>
> +            <allowedValue>vendor-defined</allowedValue>
> +         </allowedValueList>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>RecordMediumWriteStatus</name>
> +         <dataType>string</dataType>
> +         <allowedValueList>
> +            <allowedValue>WRITABLE</allowedValue>
> +            <allowedValue>PROTECTED</allowedValue>
> +            <allowedValue>NOT_WRITABLE</allowedValue>
> +            <allowedValue>UNKNOWN</allowedValue>
> +            <allowedValue>NOT_IMPLEMENTED</allowedValue>
> +         </allowedValueList>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>CurrentRecordQualityMode</name>
> +         <dataType>string</dataType>
> +         <allowedValueList>
> +            <allowedValue>0:EP</allowedValue>
> +            <allowedValue>1:LP</allowedValue>
> +            <allowedValue>2:SP</allowedValue>
> +            <allowedValue>0:BASIC</allowedValue>
> +            <allowedValue>1:MEDIUM</allowedValue>
> +            <allowedValue>2:HIGH</allowedValue>
> +            <allowedValue>NOT_IMPLEMENTED</allowedValue>
> +            <allowedValue>vendor-defined</allowedValue>
> +         </allowedValueList>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>PossibleRecordQualityModes</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>NumberOfTracks</name>
> +         <dataType>ui4</dataType>
> +         <allowedValueRange>
> +            <minimum>0</minimum>
> +            <maximum>vendor-defined</maximum>
> +         </allowedValueRange>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>CurrentTrack</name>
> +         <dataType>ui4</dataType>
> +         <allowedValueRange>
> +            <minimum>0</minimum>
> +            <maximum>vendor-defined</maximum>
> +            <step>1</step>
> +         </allowedValueRange>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>CurrentTrackDuration</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>CurrentMediaDuration</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>CurrentTrackMetaData</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>CurrentTrackURI</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>AVTransportURI</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>AVTransportURIMetaData</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>NextAVTransportURI</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>NextAVTransportURIMetaData</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>RelativeTimePosition</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>AbsoluteTimePosition</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>RelativeCounterPosition</name>
> +         <dataType>i4</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>AbsoluteCounterPosition</name>
> +         <dataType>i4</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>CurrentTransportActions</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="yes">
> +         <name>LastChange</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>A_ARG_TYPE_SeekMode</name>
> +         <dataType>string</dataType>
> +         <allowedValueList>
> +            <allowedValue>ABS_TIME</allowedValue>
> +            <allowedValue>REL_TIME</allowedValue>
> +            <allowedValue>ABS_COUNT</allowedValue>
> +            <allowedValue>REL_COUNT</allowedValue>
> +            <allowedValue>TRACK_NR</allowedValue>
> +            <allowedValue>CHANNEL_FREQ</allowedValue>
> +            <allowedValue>TAPE-INDEX</allowedValue>
> +            <allowedValue>FRAME</allowedValue>
> +         </allowedValueList>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>A_ARG_TYPE_SeekTarget</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>A_ARG_TYPE_InstanceID</name>
> +         <dataType>ui4</dataType>
> +      </stateVariable>
> +   </serviceStateTable>
> +</scpd>
> diff --git a/share/upnp/ConnectionManagerSCPD.xml
> b/share/upnp/ConnectionManagerSCPD.xml
> new file mode 100644
> index 0000000000..77c835bebe
> --- /dev/null
> +++ b/share/upnp/ConnectionManagerSCPD.xml
> @@ -0,0 +1,182 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<scpd xmlns="urn:schemas-upnp-org:service-1-0">
> +   <specVersion>
> +      <major>1</major>
> +      <minor>0</minor>
> +   </specVersion>
> +   <actionList>
> +      <action>
> +         <name>GetProtocolInfo</name>
> +         <argumentList>
> +            <argument>
> +               <name>Source</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>SourceProtocolInfo</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Sink</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>SinkProtocolInfo</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>PrepareForConnection</name>
> +         <argumentList>
> +            <argument>
> +               <name>RemoteProtocolInfo</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_ProtocolInfo</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>PeerConnectionManager</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_ConnectionManager</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>PeerConnectionID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_ConnectionID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Direction</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_Direction</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>ConnectionID</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_ConnectionID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>AVTransportID</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_AVTransportID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>RcsID</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>A_ARG_TYPE_RcsID</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>ConnectionComplete</name>
> +         <argumentList>
> +            <argument>
> +               <name>ConnectionID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_ConnectionID</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetCurrentConnectionIDs</name>
> +         <argumentList>
> +            <argument>
> +               <name>ConnectionIDs</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>CurrentConnectionIDs</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetCurrentConnectionInfo</name>
> +         <argumentList>
> +            <argument>
> +               <name>ConnectionID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_ConnectionID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>RcsID</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>A_ARG_TYPE_RcsID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>AVTransportID</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_AVTransportID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>ProtocolInfo</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_ProtocolInfo</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>PeerConnectionManager</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_ConnectionManager</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>PeerConnectionID</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_ConnectionID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Direction</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_Direction</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Status</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_ConnectionStatus</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +   </actionList>
> +   <serviceStateTable>
> +      <stateVariable sendEvents="yes">
> +         <name>SourceProtocolInfo</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="yes">
> +         <name>SinkProtocolInfo</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="yes">
> +         <name>CurrentConnectionIDs</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>A_ARG_TYPE_ConnectionStatus</name>
> +         <dataType>string</dataType>
> +         <allowedValueList>
> +            <allowedValue>OK</allowedValue>
> +            <allowedValue>ContentFormatMismatch</allowedValue>
> +            <allowedValue>InsufficientBandwidth</allowedValue>
> +            <allowedValue>UnreliableChannel</allowedValue>
> +            <allowedValue>Unknown</allowedValue>
> +         </allowedValueList>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>A_ARG_TYPE_ConnectionManager</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>A_ARG_TYPE_Direction</name>
> +         <dataType>string</dataType>
> +         <allowedValueList>
> +            <allowedValue>Input</allowedValue>
> +            <allowedValue>Output</allowedValue>
> +         </allowedValueList>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>A_ARG_TYPE_ProtocolInfo</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>A_ARG_TYPE_ConnectionID</name>
> +         <dataType>i4</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>A_ARG_TYPE_AVTransportID</name>
> +         <dataType>i4</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>A_ARG_TYPE_RcsID</name>
> +         <dataType>i4</dataType>
> +      </stateVariable>
> +   </serviceStateTable>
> +</scpd>
> diff --git a/share/upnp/RenderingControlSCPD.xml
> b/share/upnp/RenderingControlSCPD.xml
> new file mode 100644
> index 0000000000..5c5c0f9a5e
> --- /dev/null
> +++ b/share/upnp/RenderingControlSCPD.xml
> @@ -0,0 +1,762 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<scpd xmlns="urn:schemas-upnp-org:service-1-0">
> +   <specVersion>
> +      <major>1</major>
> +      <minor>0</minor>
> +   </specVersion>
> +   <actionList>
> +      <action>
> +         <name>ListPresets</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentPresetNameList</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>PresetNameList</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SelectPreset</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>PresetName</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_PresetName</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetBrightness</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentBrightness</name>
> +               <direction>out</direction>
> +               <relatedStateVariable>Brightness</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetBrightness</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>DesiredBrightness</name>
> +               <direction>in</direction>
> +               <relatedStateVariable>Brightness</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetContrast</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentContrast</name>
> +               <direction>out</direction>
> +               <relatedStateVariable>Contrast</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetContrast</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>DesiredContrast</name>
> +               <direction>in</direction>
> +               <relatedStateVariable>Contrast</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetSharpness</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentSharpness</name>
> +               <direction>out</direction>
> +               <relatedStateVariable>Sharpness</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetSharpness</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>DesiredSharpness</name>
> +               <direction>in</direction>
> +               <relatedStateVariable>Sharpness</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetRedVideoGain</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentRedVideoGain</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>RedVideoGain</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetRedVideoGain</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>DesiredRedVideoGain</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>RedVideoGain</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetGreenVideoGain</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentGreenVideoGain</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>GreenVideoGain</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetGreenVideoGain</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>DesiredGreenVideoGain</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>GreenVideoGain</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetBlueVideoGain</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentBlueVideoGain</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>BlueVideoGain</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetBlueVideoGain</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>DesiredBlueVideoGain</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>BlueVideoGain</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetRedVideoBlackLevel</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentRedVideoBlackLevel</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>RedVideoBlackLevel</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetRedVideoBlackLevel</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>DesiredRedVideoBlackLevel</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>RedVideoBlackLevel</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetGreenVideoBlackLevel</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentGreenVideoBlackLevel</name>
> +               <direction>out</direction>
> +
> <relatedStateVariable>GreenVideoBlackLevel</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetGreenVideoBlackLevel</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>DesiredGreenVideoBlackLevel</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>GreenVideoBlackLevel</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetBlueVideoBlackLevel</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentBlueVideoBlackLevel</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>BlueVideoBlackLevel</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetBlueVideoBlackLevel</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>DesiredBlueVideoBlackLevel</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>BlueVideoBlackLevel</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetColorTemperature</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentColorTemperature</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>ColorTemperature</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetColorTemperature</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>DesiredColorTemperature</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>ColorTemperature</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetHorizontalKeystone</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentHorizontalKeystone</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>HorizontalKeystone</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetHorizontalKeystone</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>DesiredHorizontalKeystone</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>HorizontalKeystone</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetVerticalKeystone</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentVerticalKeystone</name>
> +               <direction>out</direction>
> +               
> <relatedStateVariable>VerticalKeystone</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetVerticalKeystone</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>DesiredVerticalKeystone</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>VerticalKeystone</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetMute</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Channel</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>A_ARG_TYPE_Channel</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentMute</name>
> +               <direction>out</direction>
> +               <relatedStateVariable>Mute</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetMute</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Channel</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>A_ARG_TYPE_Channel</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>DesiredMute</name>
> +               <direction>in</direction>
> +               <relatedStateVariable>Mute</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetVolume</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Channel</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>A_ARG_TYPE_Channel</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentVolume</name>
> +               <direction>out</direction>
> +               <relatedStateVariable>Volume</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetVolume</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Channel</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>A_ARG_TYPE_Channel</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>DesiredVolume</name>
> +               <direction>in</direction>
> +               <relatedStateVariable>Volume</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetVolumeDB</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Channel</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>A_ARG_TYPE_Channel</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentVolume</name>
> +               <direction>out</direction>
> +               <relatedStateVariable>VolumeDB</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetVolumeDB</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Channel</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>A_ARG_TYPE_Channel</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>DesiredVolume</name>
> +               <direction>in</direction>
> +               <relatedStateVariable>VolumeDB</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetVolumeDBRange</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Channel</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>A_ARG_TYPE_Channel</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>MinValue</name>
> +               <direction>out</direction>
> +               <relatedStateVariable>VolumeDB</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>MaxValue</name>
> +               <direction>out</direction>
> +               <relatedStateVariable>VolumeDB</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>GetLoudness</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Channel</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>A_ARG_TYPE_Channel</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>CurrentLoudness</name>
> +               <direction>out</direction>
> +               <relatedStateVariable>Loudness</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +      <action>
> +         <name>SetLoudness</name>
> +         <argumentList>
> +            <argument>
> +               <name>InstanceID</name>
> +               <direction>in</direction>
> +
> <relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>Channel</name>
> +               <direction>in</direction>
> +               
> <relatedStateVariable>A_ARG_TYPE_Channel</relatedStateVariable>
> +            </argument>
> +            <argument>
> +               <name>DesiredLoudness</name>
> +               <direction>in</direction>
> +               <relatedStateVariable>Loudness</relatedStateVariable>
> +            </argument>
> +         </argumentList>
> +      </action>
> +   </actionList>
> +   <serviceStateTable>
> +      <stateVariable sendEvents="no">
> +         <name>PresetNameList</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="yes">
> +         <name>LastChange</name>
> +         <dataType>string</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>Brightness</name>
> +         <dataType>ui2</dataType>
> +         <allowedValueRange>
> +            <minimum>0</minimum>
> +            <maximum>Vendor defined</maximum>
> +            <step>1</step>
> +         </allowedValueRange>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>Contrast</name>
> +         <dataType>ui2</dataType>
> +         <allowedValueRange>
> +            <minimum>0</minimum>
> +            <maximum>Vendor defined</maximum>
> +            <step>1</step>
> +         </allowedValueRange>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>Sharpness</name>
> +         <dataType>ui2</dataType>
> +         <allowedValueRange>
> +            <minimum>0</minimum>
> +            <maximum>Vendor defined</maximum>
> +            <step>1</step>
> +         </allowedValueRange>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>RedVideoGain</name>
> +         <dataType>ui2</dataType>
> +         <allowedValueRange>
> +            <minimum>0</minimum>
> +            <maximum>Vendor defined</maximum>
> +            <step>1</step>
> +         </allowedValueRange>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>GreenVideoGain</name>
> +         <dataType>ui2</dataType>
> +         <allowedValueRange>
> +            <minimum>0</minimum>
> +            <maximum>Vendor defined</maximum>
> +            <step>1</step>
> +         </allowedValueRange>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>BlueVideoGain</name>
> +         <dataType>ui2</dataType>
> +         <allowedValueRange>
> +            <minimum>0</minimum>
> +            <maximum>Vendor defined</maximum>
> +            <step>1</step>
> +         </allowedValueRange>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>RedVideoBlackLevel</name>
> +         <dataType>ui2</dataType>
> +         <allowedValueRange>
> +            <minimum>0</minimum>
> +            <maximum>Vendor defined</maximum>
> +            <step>1</step>
> +         </allowedValueRange>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>GreenVideoBlackLevel</name>
> +         <dataType>ui2</dataType>
> +         <allowedValueRange>
> +            <minimum>0</minimum>
> +            <maximum>Vendor defined</maximum>
> +            <step>1</step>
> +         </allowedValueRange>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>BlueVideoBlackLevel</name>
> +         <dataType>ui2</dataType>
> +         <allowedValueRange>
> +            <minimum>0</minimum>
> +            <maximum>Vendor defined</maximum>
> +            <step>1</step>
> +         </allowedValueRange>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>ColorTemperature</name>
> +         <dataType>ui2</dataType>
> +         <allowedValueRange>
> +            <minimum>0</minimum>
> +            <maximum>Vendor defined</maximum>
> +            <step>1</step>
> +         </allowedValueRange>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>HorizontalKeystone</name>
> +         <dataType>i2</dataType>
> +         <allowedValueRange>
> +            <minimum>Vendor defined (Must be >= 0)</minimum>
> +            <maximum>Vendor defined</maximum>
> +            <step>1</step>
> +         </allowedValueRange>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>VerticalKeystone</name>
> +         <dataType>i2</dataType>
> +         <allowedValueRange>
> +            <minimum>Vendor defined (Must be >= 0)</minimum>
> +            <maximum>Vendor defined</maximum>
> +            <step>1</step>
> +         </allowedValueRange>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>Mute</name>
> +         <dataType>boolean</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>Volume</name>
> +         <dataType>ui2</dataType>
> +         <allowedValueRange>
> +            <minimum>0</minimum>
> +            <maximum>Vendor defined</maximum>
> +            <step>1</step>
> +         </allowedValueRange>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>VolumeDB</name>
> +         <dataType>i2</dataType>
> +         <allowedValueRange>
> +            <minimum>Vendor defined</minimum>
> +            <maximum>Vendor defined</maximum>
> +            <step>Vendor defined</step>
> +         </allowedValueRange>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>Loudness</name>
> +         <dataType>boolean</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>A_ARG_TYPE_Channel</name>
> +         <dataType>string</dataType>
> +         <allowedValueList>
> +            <allowedValue>Master</allowedValue>
> +            <allowedValue>LF</allowedValue>
> +            <allowedValue>RF</allowedValue>
> +            <allowedValue>CF</allowedValue>
> +            <allowedValue>LFE</allowedValue>
> +            <allowedValue>LS</allowedValue>
> +            <allowedValue>RS</allowedValue>
> +            <allowedValue>LFC</allowedValue>
> +            <allowedValue>RFC</allowedValue>
> +            <allowedValue>SD</allowedValue>
> +            <allowedValue>SL</allowedValue>
> +            <allowedValue>SR</allowedValue>
> +            <allowedValue>T</allowedValue>
> +            <allowedValue>B</allowedValue>
> +            <allowedValue>Vendor defined</allowedValue>
> +         </allowedValueList>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>A_ARG_TYPE_InstanceID</name>
> +         <dataType>ui4</dataType>
> +      </stateVariable>
> +      <stateVariable sendEvents="no">
> +         <name>A_ARG_TYPE_PresetName</name>
> +         <dataType>string</dataType>
> +         <allowedValueList>
> +            <allowedValue>FactoryDefaults</allowedValue>
> +            <allowedValue>InstallationDefaults</allowedValue>
> +            <allowedValue>Vendor defined</allowedValue>
> +         </allowedValueList>
> +      </stateVariable>
> +   </serviceStateTable>
> +</scpd>


More information about the vlc-devel mailing list