[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