[vlc-devel] [PATCH v3 2/6] upnp: Add basic support for registering MediaRenderer service

Johan Gunnarsson johan.gunnarsson at gmail.com
Sat Aug 10 13:30:13 CEST 2019


Den ons 7 aug. 2019 kl 15:42 skrev Hugo Beauzée-Luyssen <hugo at beauzee.fr>:
>
> Hi,
>
> On Thu, Jul 25, 2019, at 11:26 PM, Johan Gunnarsson wrote:
> > ---
> >  modules/services_discovery/upnp-wrapper.cpp | 109 +++++++++++++++++++-
> >  modules/services_discovery/upnp-wrapper.hpp |   7 ++
> >  2 files changed, 115 insertions(+), 1 deletion(-)
> >
> > diff --git a/modules/services_discovery/upnp-wrapper.cpp
> > b/modules/services_discovery/upnp-wrapper.cpp
> > index 38f18a1192..27c3b9595d 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_client_handle( -1 )
> > +    , m_device_handle( -1 )
> >      , m_refcount( 0 )
> > +    , m_mediarenderer_refcount( 0 )
> >  {
> >  }
> >
> >  UpnpInstanceWrapper::~UpnpInstanceWrapper()
> >  {
> > -    UpnpUnRegisterClient( m_client_handle );
> > +    if( m_client_handle != -1 )
> > +        UpnpUnRegisterClient( m_client_handle );
> > +    if( m_device_handle != -1 )
> > +        UpnpUnRegisterRootDevice( m_device_handle );
> >      UpnpFinish();
> >  }
> >
> > @@ -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 config_GetSysPath fails, the later call will disable the webserver and won't return an error, which is probably not the behavior you want

If root is NULL UpnpSetWebServerRootDir will return an error and print
a warning. When this happens the XML files in the
VLC_PKG_DATA_DIR/upnp directory will not be available, but the SOAP
calls are still working fine. I think this is an acceptable best
effort fallback.

>
> > +        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++;
> > @@ -128,6 +183,11 @@ UpnpClient_Handle
> > UpnpInstanceWrapper::client_handle() const
> >      return m_client_handle;
> >  }
> >
> > +UpnpDevice_Handle UpnpInstanceWrapper::device_handle() const
> > +{
> > +    return m_device_handle;
> > +}
> > +
> >  int UpnpInstanceWrapper::Callback(Upnp_EventType event_type,
> > UpnpEventPtr p_event, void *p_user_data)
> >  {
> >      vlc::threads::mutex_locker lock( &s_lock );
> > @@ -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,
>
> Please use nullptr :)

Feels a bit silly to have nullptr here but NULL in all other places in
this file. If you really want me to do it I can fix it in v4 of this
patch.

>
> > +                                         &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 c59592b0b3..c9f3e152d4 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
> > @@ -71,7 +73,9 @@ private:
> >      static UpnpInstanceWrapper* s_instance;
> >      static vlc_mutex_t s_lock;
> >      UpnpClient_Handle m_client_handle;
> > +    UpnpDevice_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;
> > @@ -81,8 +85,11 @@ public:
> >      static UpnpInstanceWrapper* get( vlc_object_t* p_obj );
> >      void release();
> >      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 );
> > --
> > 2.17.1
> >
> > _______________________________________________
> > vlc-devel mailing list
> > To unsubscribe or modify your subscription options:
> > https://mailman.videolan.org/listinfo/vlc-devel
>
> LGTM otherwise
>
> --
>   Hugo Beauzée-Luyssen
>   hugo at beauzee.fr
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list