[vlc-devel] [PATCH v3 2/6] upnp: Add basic support for registering MediaRenderer service
Hugo Beauzée-Luyssen
hugo at beauzee.fr
Wed Aug 7 15:42:53 CEST 2019
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( (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 :)
> + &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
More information about the vlc-devel
mailing list