[vlc-devel] [RFC PATCHv2 1/6] add a new type of module: vlc_renderer
Thomas Guillem
thomas at gllm.fr
Fri Mar 4 15:28:49 CET 2016
On Thu, Mar 3, 2016, at 21:18, Rémi Denis-Courmont wrote:
> Le 2016-03-02 16:58, Thomas Guillem a écrit :
> > This new type of module will be used by renderers (chromecast, UPnP
> > Renderer,
> > miracast, airport, 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.
> >
> > Also-by: Steve Lhomme <robux4 at videolabs.io>
> > ---
> > include/vlc_common.h | 2 +
> > include/vlc_renderer.h | 203 +++++++++++++++++++++++++++++++
> > src/Makefile.am | 2 +
> > src/libvlccore.sym | 13 ++
> > src/misc/renderer.c | 323
> > +++++++++++++++++++++++++++++++++++++++++++++++++
> > 5 files changed, 543 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..c084dcb
> > --- /dev/null
> > +++ b/include/vlc_renderer.h
> > @@ -0,0 +1,203 @@
> >
> > +/*****************************************************************************
> > + * 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
> > +
> > +/**
> > + * @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 {
> > + VLC_RENDERER_CAN_AUDIO = 0x0001, /**< Renderer can render
> > audio */
> > + VLC_RENDERER_CAN_VIDEO = 0x0002, /**< Renderer can render
> > video */
> > +} vlc_renderer_flags;
>
> Flags are not enumerations.
>
> C++ compilers don't like them that way.
OK,
>
> > +
> > +/**
> > + * 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,
> > + vlc_renderer_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);
> > +
> > +/**
> > + * Returns true if the renderer item has the same parameters
> > + */
> > +VLC_API bool
> > +vlc_renderer_item_equals(const vlc_renderer_item *p_item,
> > + const char *psz_module, const char
> > *psz_host,
> > + uint16_t i_port, vlc_renderer_flags
> > e_flags);
> > +/**
> > + * Get the name of a renderer item
> > + */
> > +VLC_API const char *
> > +vlc_renderer_item_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);
>
> For the umpteenth time, use URIs to identify resources.
OK, I will
>
> And don't rely on ever being able to compare them for (in)equality.
> We've tried and failed already with SD items.
>
> > +
> > +/**
> > + * Get the flags of a renderer item
> > + */
> > +VLC_API vlc_renderer_flags
> > +vlc_renderer_item_flags(const vlc_renderer_item *p_item);
> > +
> > +/**
> > + * Get the VLC option used to run this renderer
> > + */
> > +VLC_API const char *
> > +vlc_renderer_item_option(const vlc_renderer_item *p_item);
> > +
> > +/**
> > + * @}
> > + * @defgroup vlc_renderer_service VLC renderer functions
> > + * @{
> > + */
> > +
> > +/**
> > + * 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_renderer *p_renderer, float *pf_volume);
>
> That and the rest below seems completely out of place.
>
> On the one hand, it's not a consistent/sufficient interface for volume
> control. On the other hand, it seems to be limited to volume control in
> a completely arbitrary way: there are indeed plenty of properties that a
> render target can potentially have, and yet we don't want to end up with
> The Renderer as a God Object.
We agree, I'm not happy with it either.
I think the first version of vlc_renderer won't handle volume/mute
change.
>
> And also, audio volume is a property of the render target (what you
> called "vlc_renderer_item"), not the render target enumerator (what you
> called "vlc_renderer").
>
> > +
> > +/**
> > + * 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_renderer *p_renderer, float f_volume);
> > +
> > +/**
> > + * 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_renderer *p_renderer, bool *b_mute);
> > +
> > +/**
> > + * 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_renderer *p_renderer, bool b_mute);
> > +
> > +/**
> > + * @}
> > + * @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_set_input()
> > + */
> > + int (*pf_set_input)(vlc_renderer *p_renderer, input_thread_t
> > *p_input);
> > + /**
> > + * 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);
> > +};
> > +
> > +/** @} @} */
> > +
> > +/* Release with vlc_object_release */
> > +vlc_renderer *
> > +vlc_renderer_new(vlc_object_t *p_obj, const char *psz_renderer);
> > +#define vlc_renderer_new(a, b) vlc_renderer_new(VLC_OBJECT(a), b)
> > +
> > +/* Returns true if the renderer is created from this string option
> > */
> > +bool
> > +vlc_renderer_equals(const vlc_renderer *p_renderer, const char
> > *psz_renderer);
> > +
> > +int
> > +vlc_renderer_set_input(vlc_renderer *p_renderer, input_thread_t
> > *p_input);
> > +
> > +#endif
> > diff --git a/src/Makefile.am b/src/Makefile.am
> > index 5ee185f..4d5fd6c 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/libvlccore.sym b/src/libvlccore.sym
> > index 0d69d14..572e293 100644
> > --- a/src/libvlccore.sym
> > +++ b/src/libvlccore.sym
> > @@ -734,3 +734,16 @@ 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_host
> > +vlc_renderer_item_port
> > +vlc_renderer_item_flags
> > +vlc_renderer_item_option
> > +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..f6ffbd9
> > --- /dev/null
> > +++ b/src/misc/renderer.c
> > @@ -0,0 +1,323 @@
> >
> > +/*****************************************************************************
> > + * 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;
> > + vlc_renderer_flags e_flags;
> > + char *psz_name;
> > + char *psz_option;
> > + atomic_uint refs;
> > +};
> > +
> > +struct renderer_priv
> > +{
> > + vlc_renderer s;
> > + bool b_has_input;
> > + 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,
> > + vlc_renderer_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
> > + || asprintf(&p_item->psz_option,
> > "%s{host=%s,port=%u,name=%s,flags=%d}",
> > + psz_module, psz_host, i_port, psz_name, e_flags) ==
> > -1)
> > + {
> > + free(p_item->psz_module);
> > + free(p_item->psz_host);
> > + free(p_item->psz_name);
> > + 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;
> > +}
> > +
> > +static vlc_renderer_item *
> > +renderer_item_new_from_option(const char *psz_renderer)
> > +{
> > + config_chain_t *p_cfg = NULL;
> > + char *psz_module, *psz_host = NULL, *psz_name = NULL;
> > + vlc_renderer_flags e_flags = 0;
> > + 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;
> > + else if (!strcmp(p_cfg->psz_name, "name"))
> > + psz_name = p_cfg->psz_value;
> > + else 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;
> > + }
> > + else if (!strcmp(p_cfg->psz_name, "flags"))
> > + e_flags = atoi(p_cfg->psz_value);
> > + p_read_cfg = p_read_cfg->p_next;
> > + }
> > +
> > + vlc_renderer_item *p_item = NULL;
> > + if (psz_module != NULL && psz_host != NULL)
> > + p_item = vlc_renderer_item_new(psz_module, psz_host, i_port,
> > psz_name,
> > + e_flags);
> > + free(psz_module);
> > + config_ChainDestroy( p_cfg );
> > +
> > + return p_item;
> > +}
> > +
> > +const char *
> > +vlc_renderer_item_name(const vlc_renderer_item *p_item)
> > +{
> > + assert(p_item != NULL);
> > +
> > + return p_item->psz_name != NULL ? p_item->psz_name :
> > p_item->psz_module;
> > +}
> > +
> > +bool
> > +vlc_renderer_item_equals(const vlc_renderer_item *p_item,
> > + const char *psz_module, const char
> > *psz_host,
> > + uint16_t i_port, vlc_renderer_flags
> > e_flags)
> > +{
> > + assert(p_item != NULL);
> > + return (p_item->i_port == i_port || !p_item->i_port || !i_port)
> > + && !strcmp(p_item->psz_host, psz_host)
> > + && !strcmp(p_item->psz_module, psz_module)
> > + && p_item->e_flags == e_flags;
> > +}
> > +
> > +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;
> > +}
> > +
> > +vlc_renderer_flags
> > +vlc_renderer_item_flags(const vlc_renderer_item *p_item)
> > +{
> > + assert(p_item != NULL);
> > +
> > + return p_item->e_flags;
> > +}
> > +
> > +const char *
> > +vlc_renderer_item_option(const vlc_renderer_item *p_item)
> > +{
> > + assert(p_item != NULL);
> > +
> > + return p_item->psz_option;
> > +}
> > +
> > +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->psz_option);
> > + free(p_item);
> > +}
> > +
> > +static inline struct renderer_priv *
> > +renderer_priv(vlc_renderer *p_renderer)
> > +{
> > + return (struct renderer_priv *)p_renderer;
> > +}
> > +
> > +static void
> > +renderer_destructor(vlc_object_t *p_obj)
> > +{
> > + vlc_renderer *p_renderer = (vlc_renderer *)p_obj;
> > + struct renderer_priv *p_priv = renderer_priv(p_renderer);
> > +
> > + if (p_priv->b_has_input)
> > + vlc_renderer_set_input(p_renderer, NULL);
> > +
> > + module_unneed(p_renderer, p_renderer->p_module);
> > +
> > + vlc_renderer_item_release(p_priv->p_item);
> > +}
> > +
> > +#undef vlc_renderer_new
> > +vlc_renderer *
> > +vlc_renderer_new(vlc_object_t *p_obj, const char *psz_renderer)
> > +{
> > + assert(p_obj != NULL && psz_renderer != NULL);
> > + struct renderer_priv *p_priv =
> > + vlc_custom_create(p_obj, sizeof (*p_priv), "renderer");
> > + if (p_priv == NULL)
> > + return NULL;
> > + vlc_renderer *p_renderer = &p_priv->s;
> > +
> > + p_priv->p_item = renderer_item_new_from_option(psz_renderer);
> > + if (p_priv->p_item == NULL)
> > + {
> > + vlc_object_release(p_obj);
> > + return NULL;
> > + }
> > + p_renderer->p_item = p_priv->p_item;
> > +
> > + p_renderer->p_module = module_need(p_renderer, "renderer",
> > + p_priv->p_item->psz_module,
> > true);
> > + if (p_renderer->p_module == NULL)
> > + {
> > + vlc_renderer_item_release(p_priv->p_item);
> > + vlc_object_release(p_obj);
> > + return NULL;
> > + }
> > + assert(p_renderer->pf_set_input);
> > + vlc_object_set_destructor(p_renderer, renderer_destructor);
> > +
> > + return p_renderer;
> > +}
> > +
> > +bool vlc_renderer_equals(const vlc_renderer *p_renderer,
> > + const char *psz_renderer)
> > +{
> > + vlc_renderer_item *p_item =
> > renderer_item_new_from_option(psz_renderer);
> > + if (p_item == NULL)
> > + return NULL;
> > + else
> > + {
> > + bool b_ret = !strcmp(p_renderer->p_item->psz_option,
> > p_item->psz_option);
> > + vlc_renderer_item_release(p_item);
> > + return b_ret;
> > + }
> > +}
> > +
> > +int
> > +vlc_renderer_set_input(vlc_renderer *p_renderer, input_thread_t
> > *p_input)
> > +{
> > + assert(p_renderer != NULL);
> > + struct renderer_priv *p_priv = renderer_priv(p_renderer);
> > +
> > + int i_ret = p_renderer->pf_set_input(p_renderer, p_input);
> > + if (i_ret == VLC_SUCCESS)
> > + p_priv->b_has_input = p_input != NULL;
> > + else
> > + p_priv->b_has_input = false;
> > +
> > + return i_ret;
> > +}
> > +
> > +int
> > +vlc_renderer_volume_get(vlc_renderer *p_renderer, float *pf_volume)
> > +{
> > + assert(p_renderer != NULL);
> > +
> > + if (!pf_volume)
> > + return VLC_EGENERIC;
> > +
> > + if (p_renderer->pf_volume_get == NULL)
> > + return VLC_ENOOBJ;
> > +
> > + return p_renderer->pf_volume_get(p_renderer, pf_volume);
> > +}
> > +
> > +int
> > +vlc_renderer_volume_set(vlc_renderer *p_renderer, float f_volume)
> > +{
> > + assert(p_renderer != NULL);
> > +
> > + if (p_renderer->pf_volume_set == NULL)
> > + return VLC_ENOOBJ;
> > +
> > + return p_renderer->pf_volume_set(p_renderer, f_volume);
> > +}
> > +
> > +int
> > +vlc_renderer_mute_get(vlc_renderer *p_renderer, bool *pb_mute)
> > +{
> > + assert(p_renderer != NULL && pb_mute != NULL);
> > +
> > + if (p_renderer->pf_mute_get == NULL)
> > + return VLC_ENOOBJ;
> > +
> > + return p_renderer->pf_mute_get(p_renderer, pb_mute);
> > +}
> > +
> > +int
> > +vlc_renderer_mute_set(vlc_renderer *p_renderer, bool b_mute)
> > +{
> > + assert(p_renderer != NULL);
> > +
> > + if (p_renderer->pf_mute_set == NULL)
> > + return VLC_ENOOBJ;
> > +
> > + return p_renderer->pf_mute_set(p_renderer, b_mute);
> > +}
>
> --
> Rémi Denis-Courmont
> http://www.remlab.net/
> _______________________________________________
> 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