[vlc-devel] [RFC PATCH 1/8] add a new type of module: vlc_renderer

Thomas Guillem thomas at gllm.fr
Thu Feb 18 17:33:11 CET 2016


This new type of module will be used by renderers (chromecast, UPnP Renderer,
miracast, airplay, DIAL, ConeCast) to configure a VLC input_thread for
rendering, like configuring a sout according to the renderer ip and
capabilities.

This API is experimental and has been tested only for chromecast, it may move
in the future when implementing others renderers.

There is an unique vlc_renderer object attached to the libvlc instance, that is
initialized from libvlc_InternalInit() (only the object is allocated, a module
is loaded only if specified from command line).

Also-by: Steve Lhomme <robux4 at videolabs.io>
---
 include/vlc_common.h   |   2 +
 include/vlc_renderer.h | 256 +++++++++++++++++++++++++++
 src/Makefile.am        |   2 +
 src/libvlc-module.c    |   8 +
 src/libvlc.c           |  10 ++
 src/libvlc.h           |   1 +
 src/libvlccore.sym     |  18 ++
 src/misc/renderer.c    | 461 +++++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 758 insertions(+)
 create mode 100644 include/vlc_renderer.h
 create mode 100644 src/misc/renderer.c

diff --git a/include/vlc_common.h b/include/vlc_common.h
index 296439e..431fbb4 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_item vlc_renderer_item;
+typedef struct vlc_renderer vlc_renderer;
 
 /* Modules */
 typedef struct module_t module_t;
diff --git a/include/vlc_renderer.h b/include/vlc_renderer.h
new file mode 100644
index 0000000..c8e7257
--- /dev/null
+++ b/include/vlc_renderer.h
@@ -0,0 +1,256 @@
+/*****************************************************************************
+ * vlc_renderer.h: VLC renderer
+ *****************************************************************************
+ * 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_H
+#define VLC_RENDERER_H 1
+
+/* Called from src/libvlc.c */
+int
+libvlc_renderer_init(libvlc_int_t *p_libvlc);
+
+/* Called from src/libvlc.c */
+void
+libvlc_renderer_deinit(libvlc_int_t *p_libvlc);
+
+/**
+ * @defgroup vlc_renderer VLC renderer
+ * @{
+ * @file
+ * This file declares VLC renderer structures and functions
+ * @defgroup vlc_renderer_item VLC renderer items
+ * @{
+ */
+
+typedef struct vlc_renderer_item vlc_renderer_item;
+
+/** Renderer flags */
+typedef enum {
+    RENDERER_CAN_AUDIO         = 0x0001,  /**< Renderer can render audio */
+    RENDERER_CAN_VIDEO         = 0x0002,  /**< Renderer can render video */
+} renderer_item_flags;
+
+/**
+ * Create a new renderer item
+ *
+ * @param psz_module name of the module to use with this renderer, must be valid
+ * @param psz_host Host or IP of the item, must be valid
+ * @param i_port TCP/UDP port of the item, 0 for unknown port
+ * @param psz_name name of the item
+ * @param e_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_module, const char *psz_host,
+                      uint16_t i_port, const char *psz_name,
+                      renderer_item_flags e_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);
+
+/**
+  * Compare two renderer items and return true if they're equal
+  */
+VLC_API bool vlc_renderer_item_equals(const vlc_renderer_item *p_item1,
+                                      const vlc_renderer_item *p_item2);
+
+/**
+ * Get the name of a renderer item
+ */
+VLC_API const char *
+vlc_renderer_item_name(const vlc_renderer_item *p_item);
+
+/**
+ * Get the name of the module that can handle this renderer item
+ */
+VLC_API const char *
+vlc_renderer_item_module_name(const vlc_renderer_item *p_item);
+
+/**
+ * Get the host of a renderer item
+ */
+VLC_API const char *
+vlc_renderer_item_host(const vlc_renderer_item *p_item);
+
+/**
+ * Get the port of a renderer item
+ */
+VLC_API uint16_t
+vlc_renderer_item_port(const vlc_renderer_item *p_item);
+
+/**
+ * Get the flags of a renderer item
+ */
+VLC_API renderer_item_flags
+vlc_renderer_item_flags(const vlc_renderer_item *p_item);
+
+/**
+ * @}
+ * @defgroup vlc_renderer_service VLC renderer functions
+ * @{
+ */
+
+/**
+ * Load a renderer module via a renderer item
+ *
+ * @param p_item the renderer item, must be valid
+ * @return VLC_SUCCESS on success, or a VLC error code on error. On success,
+ * the item must be unloaded with vlc_renderer_unload()
+ */
+VLC_API int
+vlc_renderer_load(vlc_object_t *p_obj, vlc_renderer_item *p_item);
+#define vlc_renderer_load(a, b) vlc_renderer_load(VLC_OBJECT(a), b)
+
+/**
+ * Unload the current renderer module
+ *
+ * This does nothing if no module is loaded
+ */
+VLC_API void
+vlc_renderer_unload(vlc_object_t *p_obj);
+#define vlc_renderer_unload(a) vlc_renderer_unload(VLC_OBJECT(a))
+
+/**
+ * Get the loaded renderer item
+ *
+ * @return the current renderer item, to be released with
+ * vlc_renderer_item_release(), or NULL if no item is loaded
+ */
+VLC_API vlc_renderer_item *
+vlc_renderer_get_item(vlc_object_t *p_obj);
+#define vlc_renderer_get_item(a) vlc_renderer_get_item(VLC_OBJECT(a))
+
+/**
+ * Start rendering an input
+ *
+ * This does nothing if no module is loaded
+ *
+ * @param p_input, a newly created input_thread_t
+ */
+VLC_API int
+vlc_renderer_start(vlc_object_t *p_obj, input_thread_t *p_input);
+#define vlc_renderer_start(a, b) vlc_renderer_start(VLC_OBJECT(a), b)
+
+/**
+ * Stop rendering an input
+ *
+ * This does nothing if no module is loaded
+ */
+VLC_API void
+vlc_renderer_stop(vlc_object_t *p_obj);
+#define vlc_renderer_stop(a) vlc_renderer_stop(VLC_OBJECT(a))
+
+/**
+ * Get the volume of the loaded renderer
+ *
+ * @param pf_volume a pointer to the volume (0.0 to 1.0)
+ * @return VLC_SUCCESS on success, VLC_ENOOBJ if no module is loaded, or an
+ * other VLC error code
+ */
+VLC_API int
+vlc_renderer_volume_get(vlc_object_t *p_obj, float *pf_volume);
+#define vlc_renderer_volume_get(a, b) vlc_renderer_volume_get(VLC_OBJECT(a), b)
+
+/**
+ * Set the volume of the loaded renderer
+ *
+ * @param f_volume the volume (0.0 to 1.0)
+ * @return VLC_SUCCESS on success, VLC_ENOOBJ if no module is loaded, or an
+ * other VLC error code
+ */
+VLC_API int
+vlc_renderer_volume_set(vlc_object_t *p_obj, float f_volume);
+#define vlc_renderer_volume_set(a, b) vlc_renderer_volume_set(VLC_OBJECT(a), b)
+
+/**
+ * Get the mute state of the loaded renderer
+ *
+ * @return VLC_SUCCESS on success, VLC_ENOOBJ if no module is loaded, or an
+ * other VLC error code
+ */
+VLC_API int
+vlc_renderer_mute_get(vlc_object_t *p_obj, bool *b_mute);
+#define vlc_renderer_mute_get(a, b) vlc_renderer_mute_get(VLC_OBJECT(a), b)
+
+/**
+ * Get the mute state of the loaded renderer
+ *
+ * @return VLC_SUCCESS on success, VLC_ENOOBJ if no module is loaded, or an
+ * other VLC error code
+ */
+VLC_API int
+vlc_renderer_mute_set(vlc_object_t *p_obj, bool b_mute);
+#define vlc_renderer_mute_set(a, b) vlc_renderer_mute_set(VLC_OBJECT(a), b)
+
+/**
+ * @}
+ * @defgroup vlc_renderer_module VLC renderer module
+ * @{
+ */
+
+typedef struct vlc_renderer vlc_renderer;
+typedef struct vlc_renderer_sys vlc_renderer_sys;
+struct vlc_renderer
+{
+    VLC_COMMON_MEMBERS
+    /**
+     */
+    module_t            *p_module;
+    vlc_renderer_sys    *p_sys;
+
+    const vlc_renderer_item *p_item;
+
+    /**
+     * Called on vlc_renderer_start()
+     */
+    int     (*pf_start)(vlc_renderer *p_renderer, input_thread_t *p_input);
+    /**
+     * Called on vlc_renderer_stop()
+     */
+    void    (*pf_stop)(vlc_renderer *p_renderer);
+    /**
+     * Called on vlc_renderer_volume_get()
+     */
+    int     (*pf_volume_get)(vlc_renderer *p_renderer, float *pf_volume);
+    /**
+     * Called on vlc_renderer_volume_set()
+     */
+    int     (*pf_volume_set)(vlc_renderer *p_renderer, float f_volume);
+    /**
+     * Called on vlc_renderer_mute_get()
+     */
+    int     (*pf_mute_get)(vlc_renderer *p_renderer, bool *pb_mute);
+    /**
+     * Called on vlc_renderer_mute_set()
+     */
+    int     (*pf_mute_set)(vlc_renderer *p_renderer, bool b_mute);
+};
+
+/** @} @} */
+
+#endif
diff --git a/src/Makefile.am b/src/Makefile.am
index c21dd78..77da315 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.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.c \
 	modules/modules.h \
 	modules/modules.c \
 	modules/bank.c \
diff --git a/src/libvlc-module.c b/src/libvlc-module.c
index c3e4a01..1e5e2ab 100644
--- a/src/libvlc-module.c
+++ b/src/libvlc-module.c
@@ -80,6 +80,10 @@ static const char *const ppsz_snap_formats[] =
 #define CONTROL_LONGTEXT N_( \
     "You can select control interfaces for VLC.")
 
+#define RENDERER_TEXT N_("Renderer modules")
+#define RENDERER_LONGTEXT N_( \
+    "You can select a device to render audio/video from VLC.")
+
 #define VERBOSE_TEXT N_("Verbosity (0,1,2)")
 #define VERBOSE_LONGTEXT N_( \
     "This is the verbosity level (0=only errors and " \
@@ -2076,6 +2080,10 @@ vlc_module_begin ()
     add_module_list_cat( "control", SUBCAT_INTERFACE_CONTROL, NULL,
                          CONTROL_TEXT, CONTROL_LONGTEXT, false )
 
+    set_subcategory( SUBCAT_ADVANCED_RENDERER )
+    add_module_list_cat( "renderer", SUBCAT_ADVANCED_RENDERER, NULL,
+                         RENDERER_TEXT, RENDERER_LONGTEXT, true )
+
 /* Hotkey options*/
     set_subcategory( SUBCAT_INTERFACE_HOTKEYS )
     add_category_hint( N_("Hot keys"), HOTKEY_CAT_LONGTEXT , false )
diff --git a/src/libvlc.c b/src/libvlc.c
index fc4a59d..ac552a3 100644
--- a/src/libvlc.c
+++ b/src/libvlc.c
@@ -62,6 +62,7 @@
 
 #include <vlc_charset.h>
 #include <vlc_dialog.h>
+#include <vlc_renderer.h>
 #include <vlc_fs.h>
 #include <vlc_cpu.h>
 #include <vlc_url.h>
@@ -242,6 +243,14 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
         return VLC_ENOMEM;
     }
 
+    if (libvlc_renderer_init( p_libvlc ) != VLC_SUCCESS )
+    {
+        libvlc_dialog_provider_deinit( p_libvlc );
+        vlc_LogDeinit (p_libvlc);
+        module_EndBank (true);
+        return VLC_ENOMEM;
+    }
+
 /* FIXME: could be replaced by using Unix sockets */
 #ifdef HAVE_DBUS
 
@@ -511,6 +520,7 @@ void libvlc_InternalCleanup( libvlc_int_t *p_libvlc )
     intf_DestroyAll( p_libvlc );
 
     libvlc_dialog_provider_deinit( p_libvlc );
+    libvlc_renderer_deinit( p_libvlc );
 
 #ifdef ENABLE_VLM
     /* Destroy VLM if created in libvlc_InternalInit */
diff --git a/src/libvlc.h b/src/libvlc.h
index fc57c2a..3411719 100644
--- a/src/libvlc.h
+++ b/src/libvlc.h
@@ -145,6 +145,7 @@ typedef struct libvlc_priv_t
     /* Singleton objects */
     vlc_logger_t      *logger;
     vlm_t             *p_vlm;  ///< the VLM singleton (or NULL)
+    vlc_object_t      *p_renderer;
     vlc_dialog_provider *p_dialog_provider; ///< dialog provider
     struct playlist_t *playlist; ///< Playlist for interfaces
     struct playlist_preparser_t *parser; ///< Input item meta data handler
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 9491a18..a504467 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -732,3 +732,21 @@ 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_equals
+vlc_renderer_item_name
+vlc_renderer_item_module_name
+vlc_renderer_item_host
+vlc_renderer_item_port
+vlc_renderer_item_flags
+vlc_renderer_load
+vlc_renderer_unload
+vlc_renderer_get_item
+vlc_renderer_start
+vlc_renderer_stop
+vlc_renderer_volume_get
+vlc_renderer_volume_set
+vlc_renderer_mute_get
+vlc_renderer_mute_set
diff --git a/src/misc/renderer.c b/src/misc/renderer.c
new file mode 100644
index 0000000..40aaf5b
--- /dev/null
+++ b/src/misc/renderer.c
@@ -0,0 +1,461 @@
+/*****************************************************************************
+ * renderer.c: Renderers
+ *****************************************************************************
+ * 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 <stdint.h>
+
+#include <vlc_common.h>
+#include <vlc_atomic.h>
+#include <vlc_renderer.h>
+#include <vlc_modules.h>
+#include <libvlc.h>
+#include "../lib/libvlc_internal.h"
+
+struct vlc_renderer_item
+{
+    char *psz_module;
+    char *psz_host;
+    uint16_t i_port;
+    renderer_item_flags e_flags;
+    char *psz_name;
+    atomic_uint refs;
+};
+
+struct renderer_priv
+{
+    vlc_renderer        s;
+    vlc_mutex_t         lock;
+    bool                b_started;
+    vlc_renderer_item * p_item;
+};
+
+vlc_renderer_item *
+vlc_renderer_item_new(const char *psz_module, const char *psz_host,
+                      uint16_t i_port, const char *psz_name,
+                      renderer_item_flags e_flags)
+{
+    assert(psz_module != NULL && psz_host != NULL);
+
+    vlc_renderer_item *p_item = calloc(1, sizeof(vlc_renderer_item));
+    if (p_item == NULL)
+        return NULL;
+
+    if (psz_name == NULL)
+        psz_name = "";
+    if ((p_item->psz_module = strdup(psz_module)) == NULL
+            || (p_item->psz_host = strdup(psz_host)) == NULL
+            || (p_item->psz_name = strdup(psz_name)) == NULL)
+    {
+        free(p_item->psz_module);
+        free(p_item->psz_host);
+        free(p_item);
+        return NULL;
+    }
+    p_item->i_port = i_port;
+    p_item->e_flags = e_flags;
+    atomic_init(&p_item->refs, 1);
+    return p_item;
+}
+
+const char *
+vlc_renderer_item_name(const vlc_renderer_item *p_item)
+{
+    assert(p_item != NULL);
+
+    return p_item->psz_name;
+}
+
+bool vlc_renderer_item_equals(const vlc_renderer_item *p_item1,
+                              const vlc_renderer_item *p_item2)
+{
+    return p_item1 && p_item2
+            && (p_item1->i_port == p_item2->i_port || !p_item1->i_port || !p_item2->i_port)
+            && !strcmp(p_item1->psz_host, p_item2->psz_host)
+            && !strcmp(p_item1->psz_module, p_item2->psz_module);
+}
+
+const char *
+vlc_renderer_item_module_name(const vlc_renderer_item *p_item)
+{
+    assert(p_item != NULL);
+
+    return p_item->psz_module;
+}
+
+const char *
+vlc_renderer_item_host(const vlc_renderer_item *p_item)
+{
+    assert(p_item != NULL);
+
+    return p_item->psz_host;
+}
+
+uint16_t
+vlc_renderer_item_port(const vlc_renderer_item *p_item)
+{
+    assert(p_item != NULL);
+
+    return p_item->i_port;
+}
+
+renderer_item_flags
+vlc_renderer_item_flags(const vlc_renderer_item *p_item)
+{
+    assert(p_item != NULL);
+
+    return p_item->e_flags;
+}
+
+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_module);
+    free(p_item->psz_host);
+    free(p_item->psz_name);
+    free(p_item);
+}
+
+static inline struct renderer_priv *
+renderer_priv(vlc_object_t *p_obj)
+{
+    struct renderer_priv *p_priv =
+        (struct renderer_priv *)libvlc_priv(p_obj->p_libvlc)->p_renderer;
+    assert(p_priv != NULL);
+    return p_priv;
+}
+
+static void
+renderer_unload_locked(struct renderer_priv *p_priv)
+{
+    vlc_renderer *p_renderer = &p_priv->s;
+    if (p_renderer->p_module == NULL)
+        return;
+
+    if (p_priv->b_started)
+        vlc_renderer_stop(p_renderer);
+
+    module_unneed(p_renderer, p_renderer->p_module);
+    p_renderer->p_module = NULL;
+
+    vlc_renderer_item_release(p_priv->p_item);
+    p_priv->p_item = NULL;
+    p_renderer->p_item = NULL;
+
+    p_renderer->pf_start = NULL;
+    p_renderer->pf_stop = NULL;
+    p_renderer->pf_volume_set = NULL;
+    p_renderer->pf_volume_get = NULL;
+    p_renderer->pf_mute_set = NULL;
+    p_renderer->pf_mute_get = NULL;
+}
+
+#undef vlc_renderer_unload
+void
+vlc_renderer_unload(vlc_object_t *p_obj)
+{
+    assert(p_obj != NULL);
+    struct renderer_priv *p_priv = renderer_priv(p_obj);
+
+    vlc_mutex_lock(&p_priv->lock);
+    renderer_unload_locked(p_priv);
+    vlc_mutex_unlock(&p_priv->lock);
+}
+
+static int
+renderer_load_locked(struct renderer_priv *p_priv, vlc_renderer_item *p_item)
+{
+    vlc_renderer *p_renderer = &p_priv->s;
+
+    renderer_unload_locked(p_priv);
+
+    p_priv->p_item = vlc_renderer_item_hold(p_item);
+    p_renderer->p_item = p_priv->p_item;
+
+    p_renderer->p_module = module_need(p_renderer, "renderer",
+                                       p_item->psz_module, true);
+    if (p_renderer->p_module == NULL)
+    {
+        vlc_renderer_item_release(p_priv->p_item);
+        p_priv->p_item = NULL;
+        p_renderer->p_item = NULL;
+        return VLC_EGENERIC;
+    }
+
+    assert(p_renderer->pf_start);
+    assert(p_renderer->pf_stop);
+
+    return VLC_SUCCESS;
+}
+
+#undef vlc_renderer_load
+int
+vlc_renderer_load(vlc_object_t *p_obj, vlc_renderer_item *p_item)
+{
+    assert(p_obj != NULL && p_item != NULL);
+    struct renderer_priv *p_priv = renderer_priv(p_obj);
+
+    vlc_mutex_lock(&p_priv->lock);
+    int i_ret = renderer_load_locked(p_priv, p_item);
+    vlc_mutex_unlock(&p_priv->lock);
+
+    return i_ret;
+}
+
+#undef vlc_renderer_get_item
+vlc_renderer_item *
+vlc_renderer_get_item(vlc_object_t *p_obj)
+{
+    assert(p_obj != NULL);
+    struct renderer_priv *p_priv = renderer_priv(p_obj);
+
+    vlc_mutex_lock(&p_priv->lock);
+    vlc_renderer_item *p_item = p_priv->p_item ?
+        vlc_renderer_item_hold(p_priv->p_item) : NULL;
+    vlc_mutex_unlock(&p_priv->lock);
+
+    return p_item;
+}
+
+#undef vlc_renderer_start
+int
+vlc_renderer_start(vlc_object_t *p_obj, input_thread_t *p_input)
+{
+    assert(p_obj != NULL && p_input != NULL);
+    struct renderer_priv *p_priv = renderer_priv(p_obj);
+    vlc_renderer *p_renderer = &p_priv->s;
+
+    vlc_mutex_lock(&p_priv->lock);
+    if (p_renderer->p_module == NULL || p_priv->b_started)
+    {
+        vlc_mutex_unlock(&p_priv->lock);
+        return VLC_EGENERIC;
+    }
+
+    int i_ret = p_renderer->pf_start(p_renderer, p_input);
+    if (i_ret == VLC_SUCCESS)
+        p_priv->b_started = true;
+
+    vlc_mutex_unlock(&p_priv->lock);
+    return i_ret;
+}
+
+#undef vlc_renderer_stop
+void
+vlc_renderer_stop(vlc_object_t *p_obj)
+{
+    assert(p_obj != NULL);
+    struct renderer_priv *p_priv = renderer_priv(p_obj);
+    vlc_renderer *p_renderer = &p_priv->s;
+
+    vlc_mutex_lock(&p_priv->lock);
+    if (p_renderer->p_module == NULL || !p_priv->b_started)
+    {
+        vlc_mutex_unlock(&p_priv->lock);
+        return;
+    }
+
+    p_renderer->pf_stop(p_renderer);
+    p_priv->b_started = false;
+
+    vlc_mutex_unlock(&p_priv->lock);
+}
+
+#undef vlc_renderer_volume_get
+int
+vlc_renderer_volume_get(vlc_object_t *p_obj, float *pf_volume)
+{
+    assert(p_obj != NULL);
+    struct renderer_priv *p_priv = renderer_priv(p_obj);
+    vlc_renderer *p_renderer = &p_priv->s;
+
+    if (!pf_volume)
+        return VLC_EGENERIC;
+
+    vlc_mutex_lock(&p_priv->lock);
+    if (p_renderer->pf_volume_get == NULL)
+    {
+        vlc_mutex_unlock(&p_priv->lock);
+        return VLC_ENOOBJ;
+    }
+
+    int i_ret = p_renderer->pf_volume_get(p_renderer, pf_volume);
+    vlc_mutex_unlock(&p_priv->lock);
+    return i_ret;
+}
+
+#undef vlc_renderer_volume_set
+int
+vlc_renderer_volume_set(vlc_object_t *p_obj, float f_volume)
+{
+    assert(p_obj != NULL);
+    struct renderer_priv *p_priv = renderer_priv(p_obj);
+    vlc_renderer *p_renderer = &p_priv->s;
+
+    vlc_mutex_lock(&p_priv->lock);
+    if (p_renderer->pf_volume_set == NULL)
+    {
+        vlc_mutex_unlock(&p_priv->lock);
+        return VLC_ENOOBJ;
+    }
+
+    int i_ret = p_renderer->pf_volume_set(p_renderer, f_volume);
+    vlc_mutex_unlock(&p_priv->lock);
+    return i_ret;
+}
+
+#undef vlc_renderer_mute_get
+int
+vlc_renderer_mute_get(vlc_object_t *p_obj, bool *pb_mute)
+{
+    assert(p_obj != NULL);
+    struct renderer_priv *p_priv = renderer_priv(p_obj);
+    vlc_renderer *p_renderer = &p_priv->s;
+
+    if (!pb_mute)
+        return VLC_EGENERIC;
+
+    vlc_mutex_lock(&p_priv->lock);
+    if (p_renderer->pf_mute_get == NULL)
+    {
+        vlc_mutex_unlock(&p_priv->lock);
+        return VLC_ENOOBJ;
+    }
+
+    int i_ret = p_renderer->pf_mute_get(p_renderer, pb_mute);
+    vlc_mutex_unlock(&p_priv->lock);
+    return i_ret;
+}
+
+#undef vlc_renderer_mute_set
+int
+vlc_renderer_mute_set(vlc_object_t *p_obj, bool b_mute)
+{
+    assert(p_obj != NULL);
+    struct renderer_priv *p_priv = renderer_priv(p_obj);
+    vlc_renderer *p_renderer = &p_priv->s;
+
+    vlc_mutex_lock(&p_priv->lock);
+    if (p_renderer->pf_mute_set == NULL)
+    {
+        vlc_mutex_unlock(&p_priv->lock);
+        return VLC_ENOOBJ;
+    }
+
+    int i_ret = p_renderer->pf_mute_set(p_renderer, b_mute);
+    vlc_mutex_unlock(&p_priv->lock);
+    return i_ret;
+}
+
+void
+libvlc_renderer_deinit(libvlc_int_t *p_libvlc)
+{
+    struct renderer_priv *p_priv =
+        (struct renderer_priv *) libvlc_priv(p_libvlc)->p_renderer;
+    vlc_renderer *p_renderer = &p_priv->s;
+
+    vlc_mutex_lock(&p_priv->lock);
+    renderer_unload_locked(p_priv);
+    vlc_mutex_unlock(&p_priv->lock);
+
+    vlc_mutex_destroy(&p_priv->lock);
+    vlc_object_release(p_renderer);
+    libvlc_priv(p_libvlc)->p_renderer = NULL;
+}
+
+static int
+libvlc_renderer_load(struct renderer_priv *p_priv, const char *psz_renderer)
+{
+    config_chain_t *p_cfg = NULL;
+    char *psz_module, *psz_host = NULL, *psz_name = NULL;
+    uint16_t i_port = 0;
+    free(config_ChainCreate(&psz_module, &p_cfg, psz_renderer));
+
+    config_chain_t *p_read_cfg = p_cfg;
+    while (p_read_cfg != NULL)
+    {
+        if (!strcmp(p_cfg->psz_name, "host"))
+            psz_host = p_cfg->psz_value;
+        if (!strcmp(p_cfg->psz_name, "name"))
+            psz_name = p_cfg->psz_value;
+        if (!strcmp(p_cfg->psz_name, "port"))
+        {
+            int i_val = atoi(p_cfg->psz_value);
+            if (i_val >= 0 && i_val <= UINT16_MAX)
+                i_port = i_val;
+        }
+        p_read_cfg = p_read_cfg->p_next;
+    }
+
+    if (psz_module == NULL || psz_host == NULL)
+    {
+        free(psz_module);
+        config_ChainDestroy(p_cfg);
+        return VLC_EGENERIC;
+    }
+
+    vlc_renderer_item *p_renderer_item =
+        vlc_renderer_item_new(psz_module, psz_host, i_port, psz_name, 0);
+    free(psz_module);
+    config_ChainDestroy( p_cfg );
+
+    if (p_renderer_item == NULL)
+        return VLC_EGENERIC;
+
+    return renderer_load_locked(p_priv, p_renderer_item);
+}
+
+int
+libvlc_renderer_init(libvlc_int_t *p_libvlc)
+{
+    struct renderer_priv *p_priv =
+        vlc_custom_create(p_libvlc, sizeof (*p_priv), "renderer");
+    if (p_priv == NULL)
+        return VLC_EGENERIC;
+
+    vlc_mutex_init(&p_priv->lock);
+
+    char *psz_renderer = var_CreateGetNonEmptyString(p_libvlc, "renderer");
+    if (psz_renderer != NULL)
+    {
+        if (libvlc_renderer_load(p_priv, psz_renderer) != VLC_SUCCESS)
+            msg_Warn(p_libvlc, "renderer '%s' loading failed", psz_renderer);
+        free(psz_renderer);
+    }
+    libvlc_priv(p_libvlc)->p_renderer = (vlc_object_t *) p_priv;
+
+    return VLC_SUCCESS;
+}
-- 
2.7.0



More information about the vlc-devel mailing list