add a new type of module: vlc_renderer_discovery
authorThomas Guillem <thomas@gllm.fr>
Tue, 19 Apr 2016 15:39:11 +0000 (17:39 +0200)
committerThomas Guillem <thomas@gllm.fr>
Mon, 25 Apr 2016 08:08:56 +0000 (10:08 +0200)
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@videolabs.io>
include/vlc_common.h
include/vlc_events.h
include/vlc_plugin.h
include/vlc_renderer_discovery.h [new file with mode: 0644]
src/Makefile.am
src/libvlccore.sym
src/misc/renderer_discovery.c [new file with mode: 0644]

index 296439e..f05d9c6 100644 (file)
@@ -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;
index 9ca571a..328e2bd 100644 (file)
@@ -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
         {
index e73ab91..42c3288 100644 (file)
@@ -173,6 +173,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 (file)
index 0000000..504bea0
--- /dev/null
@@ -0,0 +1,226 @@
+/*****************************************************************************
+ * 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.
+ *****************************************************************************/
+
+#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
+ * @{
+ *
+ * @file
+ * This file declares VLC renderer discvoery structures and functions
+ *
+ * @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
index 5ee185f..94b317b 100644 (file)
@@ -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 \
index 5cde08e..32dbaad 100644 (file)
@@ -734,3 +734,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 (file)
index 0000000..96010d2
--- /dev/null
@@ -0,0 +1,302 @@
+/*****************************************************************************
+ * 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.
+ *****************************************************************************/
+
+#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,port=%d%s%s}",
+                 url.psz_protocol, url.psz_host, url.i_port,
+                 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);
+}