[vlc-devel] [PATCH 1/3] add a new type of module: vlc_renderer_discovery
Thomas Guillem
thomas at gllm.fr
Tue Apr 19 17:45:55 CEST 2016
This new type of module will be used to discover renderers (chromecast, UPnP
Renderer, miracast, airport, DIAL, ConeCast).
These modules will send new vlc_renderer_item via an event manager callback.
This new kind of item contain the necessary information to setup a new sout.
Also-by: Steve Lhomme <robux4 at videolabs.io>
---
include/vlc_common.h | 2 +
include/vlc_events.h | 14 ++
include/vlc_plugin.h | 1 +
include/vlc_renderer_discovery.h | 230 +++++++++++++++++++++++++++++
src/Makefile.am | 2 +
src/libvlccore.sym | 17 +++
src/misc/renderer_discovery.c | 303 +++++++++++++++++++++++++++++++++++++++
7 files changed, 569 insertions(+)
create mode 100644 include/vlc_renderer_discovery.h
create mode 100644 src/misc/renderer_discovery.c
diff --git a/include/vlc_common.h b/include/vlc_common.h
index 296439e..f05d9c6 100644
--- a/include/vlc_common.h
+++ b/include/vlc_common.h
@@ -208,6 +208,8 @@ typedef struct playlist_item_t playlist_item_t;
typedef struct services_discovery_t services_discovery_t;
typedef struct services_discovery_sys_t services_discovery_sys_t;
typedef struct playlist_add_t playlist_add_t;
+typedef struct vlc_renderer_discovery vlc_renderer_discovery;
+typedef struct vlc_renderer_item vlc_renderer_item;
/* Modules */
typedef struct module_t module_t;
diff --git a/include/vlc_events.h b/include/vlc_events.h
index 9ca571a..328e2bd 100644
--- a/include/vlc_events.h
+++ b/include/vlc_events.h
@@ -132,6 +132,10 @@ typedef enum vlc_event_type_t {
vlc_ServicesDiscoveryStarted,
vlc_ServicesDiscoveryEnded,
+ /* Renderer Discovery events */
+ vlc_RendererDiscoveryItemAdded,
+ vlc_RendererDiscoveryItemRemoved,
+
/* Addons Manager events */
vlc_AddonFound,
vlc_AddonsDiscoveryEnded,
@@ -212,6 +216,16 @@ typedef struct vlc_event_t
void * unused;
} services_discovery_ended;
+ /* Renderer discovery events */
+ struct vlc_renderer_discovery_item_added
+ {
+ vlc_renderer_item * p_new_item;
+ } renderer_discovery_item_added;
+ struct vlc_renderer_discovery_item_removed
+ {
+ vlc_renderer_item * p_item;
+ } renderer_discovery_item_removed;
+
/* Addons */
struct vlc_addon_generic_event
{
diff --git a/include/vlc_plugin.h b/include/vlc_plugin.h
index 23fff51..02eb64f 100644
--- a/include/vlc_plugin.h
+++ b/include/vlc_plugin.h
@@ -172,6 +172,7 @@ enum vlc_module_properties
#define SUBCAT_SOUT_ACO 504
#define SUBCAT_SOUT_PACKETIZER 505
#define SUBCAT_SOUT_VOD 507
+#define SUBCAT_SOUT_RENDERER 508
#define CAT_ADVANCED 6
#define SUBCAT_ADVANCED_MISC 602
diff --git a/include/vlc_renderer_discovery.h b/include/vlc_renderer_discovery.h
new file mode 100644
index 0000000..61cfa45
--- /dev/null
+++ b/include/vlc_renderer_discovery.h
@@ -0,0 +1,230 @@
+/*****************************************************************************
+ * vlc_renderer_discovery.h : Renderer Discovery functions
+ *****************************************************************************
+ * Copyright (C) 2016 VLC authors and VideoLAN
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @file
+ * This file declares VLC renderer discvoery structures and functions
+ */
+
+#ifndef VLC_RENDERER_DISCOVERY_H
+#define VLC_RENDERER_DISCOVERY_H 1
+
+#include <vlc_input.h>
+#include <vlc_events.h>
+#include <vlc_probe.h>
+#include <vlc_url.h>
+
+/**
+ * @defgroup vlc_renderer VLC renderer discovery
+ * @{
+ * @defgroup vlc_renderer_item VLC renderer items returned by the discovery
+ * @{
+ */
+
+typedef struct vlc_renderer_item vlc_renderer_item;
+
+#define VLC_RENDERER_CAN_AUDIO 0x0001
+#define VLC_RENDERER_CAN_VIDEO 0x0002
+
+/**
+ * Create a new renderer item
+ *
+ * @param psz_name name of the item
+ * @param psz_uri uri of the renderer item, must contains a valid protocol and
+ * a valid host
+ * @param psz_extra_sout extra sout options
+ * @param psz_icon_uri icon uri of the renderer item
+ * @param i_flags flags for the item
+ * @return a renderer item or NULL in case of error
+ */
+VLC_API vlc_renderer_item *
+vlc_renderer_item_new(const char *psz_name, const char *psz_uri,
+ const char *psz_extra_sout, const char *psz_icon_uri,
+ int i_flags) VLC_USED;
+
+/**
+ * Hold a renderer item, i.e. creates a new reference
+ */
+VLC_API vlc_renderer_item *
+vlc_renderer_item_hold(vlc_renderer_item *p_item);
+
+/**
+ * Releases a renderer item, i.e. decrements its reference counter
+ */
+VLC_API void
+vlc_renderer_item_release(vlc_renderer_item *p_item);
+
+/**
+ * Get the human readable name of a renderer item
+ */
+VLC_API const char *
+vlc_renderer_item_name(const vlc_renderer_item *p_item);
+
+/**
+ * Get the sout command of a renderer item
+ */
+VLC_API const char *
+vlc_renderer_item_sout(const vlc_renderer_item *p_item);
+
+/**
+ * Get the icon uri of a renderer item
+ */
+VLC_API const char *
+vlc_renderer_item_icon_uri(const vlc_renderer_item *p_item);
+
+/**
+ * Get the flags of a renderer item
+ */
+VLC_API int
+vlc_renderer_item_flags(const vlc_renderer_item *p_item);
+
+/**
+ * Set an opaque context
+ */
+VLC_API void
+vlc_renderer_item_set_ctx(vlc_renderer_item *p_item, void *p_ctx);
+
+/**
+ * Get the opaque context previously set
+ */
+VLC_API void*
+vlc_renderer_item_ctx(const vlc_renderer_item *p_item);
+
+/**
+ * @}
+ * @defgroup vlc_renderer_discovery VLC renderer discovery interface
+ * @{
+ */
+
+typedef struct vlc_renderer_discovery vlc_renderer_discovery;
+typedef struct vlc_renderer_discovery_sys vlc_renderer_discovery_sys;
+
+/**
+ * Return a list of renderer discovery modules
+ *
+ * @param pppsz_names a pointer to a list of module name, NULL terminated
+ * @param pppsz_longnames a pointer to a list of module longname, NULL
+ * terminated
+ *
+ * @return VLC_SUCCESS on success, or VLC_EGENERIC on error
+ */
+VLC_API int
+vlc_rd_get_names(vlc_object_t *p_obj, char ***pppsz_names,
+ char ***pppsz_longnames) VLC_USED;
+#define vlc_rd_get_names(a, b, c) \
+ vlc_rd_get_names(VLC_OBJECT(a), b, c)
+
+/**
+ * Create a new renderer discovery module
+ *
+ * @param psz_name name of the module to load, see vlc_rd_get_names() to get
+ * the list of names
+ *
+ * @return a valid vlc_renderer_discovery, need to be released with
+ * vlc_rd_release()
+ */
+VLC_API vlc_renderer_discovery *
+vlc_rd_new(vlc_object_t *p_obj, const char *psz_name) VLC_USED;
+
+#define vlc_rd_release(p_rd) vlc_object_release(p_rd)
+
+/**
+ * Get the event manager of the renderer discovery module
+ *
+ * @see vlc_RendererDiscoveryItemAdded
+ * @see vlc_RendererDiscoveryItemRemoved
+ */
+VLC_API vlc_event_manager_t *
+vlc_rd_event_manager(vlc_renderer_discovery *p_rd);
+
+/**
+ * Start the renderer discovery module
+ *
+ * Once started, the module can send new vlc_renderer_item via the
+ * vlc_RendererDiscoveryItemAdded event.
+ */
+VLC_API int
+vlc_rd_start(vlc_renderer_discovery *p_rd);
+
+/**
+ * Stop the renderer discovery module
+ */
+VLC_API void
+vlc_rd_stop(vlc_renderer_discovery *p_rd);
+
+/**
+ * @}
+ * @defgroup vlc_renderer_discovery_module VLC renderer module
+ * @{
+ */
+
+struct vlc_renderer_discovery
+{
+ VLC_COMMON_MEMBERS
+ module_t * p_module;
+
+ vlc_event_manager_t event_manager;
+
+ char * psz_name;
+ config_chain_t * p_cfg;
+
+ vlc_renderer_discovery_sys *p_sys;
+};
+
+/**
+ * Add a new renderer item
+ *
+ * This will send the vlc_RendererDiscoveryItemAdded event
+ */
+VLC_API void
+vlc_rd_add_item(vlc_renderer_discovery * p_rd, vlc_renderer_item * p_item);
+
+/**
+ * Add a new renderer item
+ *
+ * This will send the vlc_RendererDiscoveryItemRemoved event
+ */
+VLC_API void
+vlc_rd_remove_item(vlc_renderer_discovery * p_rd, vlc_renderer_item * p_item);
+
+/**
+ * Renderer Discovery proble helpers
+ */
+VLC_API int
+vlc_rd_probe_add(vlc_probe_t *p_probe, const char *psz_name,
+ const char *psz_longname);
+
+#define VLC_RD_PROBE_HELPER(name, longname) \
+static int vlc_rd_probe_open(vlc_object_t *obj) \
+{ \
+ return vlc_rd_probe_add((struct vlc_probe_t *)obj, name, longname); \
+}
+
+#define VLC_RD_PROBE_SUBMODULE \
+ add_submodule() \
+ set_capability("renderer probe", 100) \
+ set_callbacks(vlc_rd_probe_open, NULL)
+
+/**
+ * @}
+ * @}
+ */
+
+#endif
diff --git a/src/Makefile.am b/src/Makefile.am
index 5ee185f..94b317b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -82,6 +82,7 @@ pluginsinclude_HEADERS = \
../include/vlc_services_discovery.h \
../include/vlc_fingerprinter.h \
../include/vlc_interrupt.h \
+ ../include/vlc_renderer_discovery.h \
../include/vlc_sout.h \
../include/vlc_spu.h \
../include/vlc_stream.h \
@@ -444,6 +445,7 @@ SOURCES_libvlc_common = \
misc/interrupt.h \
misc/interrupt.c \
misc/keystore.c \
+ misc/renderer_discovery.c \
modules/modules.h \
modules/modules.c \
modules/bank.c \
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 5d8813e..eb89e6a 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -733,3 +733,20 @@ addons_manager_Remove
addon_entry_New
addon_entry_Hold
addon_entry_Release
+vlc_renderer_item_new
+vlc_renderer_item_hold
+vlc_renderer_item_release
+vlc_renderer_item_name
+vlc_renderer_item_sout
+vlc_renderer_item_icon_uri
+vlc_renderer_item_flags
+vlc_renderer_item_set_ctx
+vlc_renderer_item_ctx
+vlc_rd_get_names
+vlc_rd_new
+vlc_rd_event_manager
+vlc_rd_start
+vlc_rd_stop
+vlc_rd_add_item
+vlc_rd_remove_item
+vlc_rd_probe_add
diff --git a/src/misc/renderer_discovery.c b/src/misc/renderer_discovery.c
new file mode 100644
index 0000000..112086b
--- /dev/null
+++ b/src/misc/renderer_discovery.c
@@ -0,0 +1,303 @@
+/*****************************************************************************
+ * renderer_discovery.c : Renderer Discovery functions
+ *****************************************************************************
+ * Copyright(C) 2016 VLC authors and VideoLAN
+ *
+ * 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.
+ *****************************************************************************/
+
+/** @ingroup vlc_renderer */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include <vlc_common.h>
+#include <vlc_atomic.h>
+#include <vlc_events.h>
+#include <vlc_renderer_discovery.h>
+#include <vlc_probe.h>
+#include <vlc_modules.h>
+#include <libvlc.h>
+
+struct vlc_renderer_item
+{
+ char *psz_name;
+ char *psz_sout;
+ char *psz_icon_uri;
+ void *p_ctx;
+ int i_flags;
+ atomic_uint refs;
+};
+
+vlc_renderer_item *
+vlc_renderer_item_new(const char *psz_name, const char *psz_uri,
+ const char *psz_extra_sout, const char *psz_icon_uri,
+ int i_flags)
+{
+ assert(psz_uri != NULL);
+ vlc_renderer_item *p_item = NULL;
+ vlc_url_t url;
+ vlc_UrlParse(&url, psz_uri);
+
+ if (url.psz_protocol == NULL || url.psz_host == NULL)
+ goto error;
+
+ p_item = calloc(1, sizeof(vlc_renderer_item));
+ if (unlikely(p_item == NULL))
+ goto error;
+
+ if (psz_name != NULL)
+ p_item->psz_name = strdup(psz_name);
+ else if (asprintf(&p_item->psz_name, "%s (%s)", url.psz_protocol,
+ url.psz_host) == -1)
+ p_item->psz_name = NULL;
+ if (p_item->psz_name == NULL)
+ goto error;
+
+ if (asprintf(&p_item->psz_sout, "%s{ip=%s%s%s}",
+ url.psz_protocol, url.psz_host,
+ psz_extra_sout != NULL ? "," : "",
+ psz_extra_sout != NULL ? psz_extra_sout : "") == -1)
+ goto error;
+
+ if ((p_item->psz_icon_uri = strdup(psz_icon_uri)) == NULL)
+ goto error;
+
+ p_item->i_flags = i_flags;
+ atomic_init(&p_item->refs, 1);
+ vlc_UrlClean(&url);
+ return p_item;
+
+error:
+ vlc_UrlClean(&url);
+ if (p_item != NULL)
+ {
+ free(p_item->psz_name);
+ free(p_item->psz_sout);
+ free(p_item->psz_icon_uri);
+ free(p_item);
+ }
+ return NULL;
+}
+
+const char *
+vlc_renderer_item_name(const vlc_renderer_item *p_item)
+{
+ assert(p_item != NULL);
+
+ return p_item->psz_name;
+}
+
+const char *
+vlc_renderer_item_sout(const vlc_renderer_item *p_item)
+{
+ assert(p_item != NULL);
+
+ return p_item->psz_sout;
+}
+
+const char *
+vlc_renderer_item_icon_uri(const vlc_renderer_item *p_item)
+{
+ assert(p_item != NULL);
+
+ return p_item->psz_icon_uri;
+}
+
+int
+vlc_renderer_item_flags(const vlc_renderer_item *p_item)
+{
+ assert(p_item != NULL);
+
+ return p_item->i_flags;
+}
+
+void
+vlc_renderer_item_set_ctx(vlc_renderer_item *p_item, void *p_ctx)
+{
+ assert(p_item != NULL);
+
+ p_item->p_ctx = p_ctx;
+}
+
+void*
+vlc_renderer_item_ctx(const vlc_renderer_item *p_item)
+{
+ assert(p_item != NULL);
+
+ return p_item->p_ctx;
+}
+
+vlc_renderer_item *
+vlc_renderer_item_hold(vlc_renderer_item *p_item)
+{
+ assert(p_item != NULL);
+
+ atomic_fetch_add(&p_item->refs, 1);
+ return p_item;
+}
+
+void
+vlc_renderer_item_release(vlc_renderer_item *p_item)
+{
+ assert(p_item != NULL);
+
+ if (atomic_fetch_sub(&p_item->refs, 1) != 1)
+ return;
+ free(p_item->psz_name);
+ free(p_item->psz_sout);
+ free(p_item->psz_icon_uri);
+ free(p_item);
+}
+
+struct vlc_rd_probe
+{
+ char *psz_name;
+ char *psz_longname;
+};
+
+int
+vlc_rd_probe_add(vlc_probe_t *probe, const char *psz_name,
+ const char *psz_longname)
+{
+ struct vlc_rd_probe names = { strdup(psz_name), strdup(psz_longname) };
+
+ if (unlikely(names.psz_name == NULL || names.psz_longname == NULL
+ || vlc_probe_add(probe, &names, sizeof(names))))
+ {
+ free(names.psz_name);
+ free(names.psz_longname);
+ return VLC_ENOMEM;
+ }
+ return VLC_PROBE_CONTINUE;
+}
+
+#undef vlc_rd_get_names
+int
+vlc_rd_get_names(vlc_object_t *p_obj, char ***pppsz_names,
+ char ***pppsz_longnames)
+{
+ size_t i_count;
+ struct vlc_rd_probe *p_tab = vlc_probe(p_obj, "renderer probe", &i_count);
+
+ if (i_count == 0)
+ {
+ free(p_tab);
+ return VLC_EGENERIC;
+ }
+
+ char **ppsz_names = malloc(sizeof(char *) * (i_count + 1));
+ char **ppsz_longnames = malloc(sizeof(char *) * (i_count + 1));
+
+ if (unlikely(ppsz_names == NULL || ppsz_longnames == NULL))
+ {
+ free(ppsz_names);
+ free(ppsz_longnames);
+ free(p_tab);
+ return VLC_EGENERIC;
+ }
+
+ for (size_t i = 0; i < i_count; i++)
+ {
+ ppsz_names[i] = p_tab[i].psz_name;
+ ppsz_longnames[i] = p_tab[i].psz_longname;
+ }
+ ppsz_names[i_count] = ppsz_longnames[i_count] = NULL;
+ free(p_tab);
+ *pppsz_names = ppsz_names;
+ *pppsz_longnames = ppsz_longnames;
+ return VLC_SUCCESS;
+}
+
+static void
+rd_destructor(vlc_object_t *p_obj)
+{
+ vlc_renderer_discovery * p_rd =(vlc_renderer_discovery *)p_obj;
+ assert(!p_rd->p_module); /* Forgot to call Stop */
+
+ config_ChainDestroy(p_rd->p_cfg);
+ free(p_rd->psz_name);
+ vlc_event_manager_fini(&p_rd->event_manager);
+}
+
+vlc_renderer_discovery *
+vlc_rd_new(vlc_object_t *p_obj, const char *psz_name)
+{
+ vlc_renderer_discovery *p_rd;
+
+ p_rd = vlc_custom_create(p_obj, sizeof(*p_rd), "renderer discovery");
+ if(!p_rd)
+ return NULL;
+ free(config_ChainCreate(&p_rd->psz_name, &p_rd->p_cfg, psz_name));
+
+ vlc_event_manager_t *p_em = &p_rd->event_manager;
+ vlc_event_manager_init(p_em, p_rd);
+ vlc_event_manager_register_event_type(p_em, vlc_RendererDiscoveryItemAdded);
+ vlc_event_manager_register_event_type(p_em, vlc_RendererDiscoveryItemRemoved);
+
+ vlc_object_set_destructor(p_rd, rd_destructor);
+ return p_rd;
+}
+
+VLC_API vlc_event_manager_t *
+vlc_rd_event_manager(vlc_renderer_discovery *p_rd)
+{
+ return &p_rd->event_manager;
+}
+
+int
+vlc_rd_start(vlc_renderer_discovery *p_rd)
+{
+ assert(!p_rd->p_module);
+
+ p_rd->p_module = module_need(p_rd, "renderer_discovery",
+ p_rd->psz_name, true);
+ if (p_rd->p_module == NULL)
+ {
+ msg_Err(p_rd, "no suitable renderer discovery module");
+ return VLC_EGENERIC;
+ }
+
+ return VLC_SUCCESS;
+}
+
+void
+vlc_rd_stop(vlc_renderer_discovery * p_rd)
+{
+ module_unneed(p_rd, p_rd->p_module);
+ p_rd->p_module = NULL;
+}
+
+void
+vlc_rd_add_item(vlc_renderer_discovery * p_rd, vlc_renderer_item * p_item)
+{
+ vlc_event_t event;
+ event.type = vlc_RendererDiscoveryItemAdded;
+ event.u.renderer_discovery_item_added.p_new_item = p_item;
+
+ vlc_event_send(&p_rd->event_manager, &event);
+}
+
+void
+vlc_rd_remove_item(vlc_renderer_discovery * p_rd, vlc_renderer_item * p_item)
+{
+ vlc_event_t event;
+ event.type = vlc_RendererDiscoveryItemRemoved;
+ event.u.renderer_discovery_item_removed.p_item = p_item;
+
+ vlc_event_send(&p_rd->event_manager, &event);
+}
--
2.8.0.rc3
More information about the vlc-devel
mailing list