[vlc-devel] [PATCH v3 19/19] audio_output: Add PPAPI plugin

Thomas Guillem thomas at gllm.fr
Tue Mar 21 09:30:11 CET 2017



On Tue, Mar 21, 2017, at 09:18, Julian Scheel wrote:
> On 21.03.2017 08:33, Thomas Guillem wrote:
> >
> >
> > On Tue, Mar 21, 2017, at 07:27, Rémi Denis-Courmont wrote:
> >> On March 20, 2017 6:57:36 PM GMT+02:00, Dennis Hamester
> >> <dhamester at jusst.de> wrote:
> >>> From: Julian Scheel <julian at jusst.de>
> >>>
> >>> Audio output using PPAPI to allow audio output when running as
> >>> NativeClient.
> >>>
> >>> Signed-off-by: Julian Scheel <julian at jusst.de>
> >>> ---
> >>> modules/audio_output/Makefile.am |   7 ++
> >>> modules/audio_output/ppapi.c     | 261
> >>> +++++++++++++++++++++++++++++++++++++++
> >>> 2 files changed, 268 insertions(+)
> >>> create mode 100644 modules/audio_output/ppapi.c
> >>>
> >>> diff --git a/modules/audio_output/Makefile.am
> >>> b/modules/audio_output/Makefile.am
> >>> index 9006c257cb..744621e54c 100644
> >>> --- a/modules/audio_output/Makefile.am
> >>> +++ b/modules/audio_output/Makefile.am
> >>> @@ -12,6 +12,13 @@ if HAVE_ANDROID
> >>> aout_LTLIBRARIES += libandroid_audiotrack_plugin.la
> >>> libopensles_android_plugin.la
> >>> endif
> >>>
> >>> +libppapi_audio_plugin_la_SOURCES = audio_output/ppapi.c
> >>> +libppapi_audio_plugin_la_LIBADD = $(LIBS_nacl)
> >>> +
> >>> +if HAVE_NACL
> >>> +aout_LTLIBRARIES += libppapi_audio_plugin.la
> >>> +endif
> >>> +
> >>> libadummy_plugin_la_SOURCES = audio_output/adummy.c
> >>>
> >>> libafile_plugin_la_SOURCES = audio_output/file.c
> >>> diff --git a/modules/audio_output/ppapi.c
> >>> b/modules/audio_output/ppapi.c
> >>> new file mode 100644
> >>> index 0000000000..16aa08cc98
> >>> --- /dev/null
> >>> +++ b/modules/audio_output/ppapi.c
> >>> @@ -0,0 +1,261 @@
> >>> +/*****************************************************************************
> >>> + * ppapi.c: Audio output using PPAPI on NativeClient
> >>> +
> >>> *****************************************************************************
> >>> + * Copyright © 2017 VLC authors and VideoLAN
> >>> + *
> >>> + * Authors: Julian Scheel <julian at jusst.de>
> >>> + *
> >>> + * 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 <vlc_common.h>
> >>> +#include <vlc_atomic.h>
> >>> +#include <vlc_plugin.h>
> >>> +#include <vlc_aout.h>
> >>> +#include <vlc_block_helper.h>
> >>> +#include <vlc_plugin.h>
> >>> +#include <vlc_threads.h>
> >>> +
> >>> +#include <ppapi/c/pp_instance.h>
> >>> +#include <ppapi/c/ppb_audio_config.h>
> >>> +#include <ppapi/c/ppb_audio.h>
> >>> +#include <ppapi/c/ppb_core.h>
> >>> +#include <ppapi/c/ppb.h>
> >>> +
> >>> +/*****************************************************************************
> >>> + * Module descriptor
> >>> +
> >>> *****************************************************************************/
> >>> +static int Open(vlc_object_t *);
> >>> +static void Close(vlc_object_t *);
> >>> +
> >>> +vlc_module_begin()
> >>> +    set_shortname("PPAPI aout")
> >>> +    set_description(N_("PPAPI based audio output"))
> >>> +    set_category(CAT_AUDIO)
> >>> +    set_subcategory(SUBCAT_AUDIO_AOUT)
> >>> +
> >>> +    set_capability("audio output", 50)
> >>> +    set_callbacks(Open, Close)
> >>> +vlc_module_end()
> >>> +
> >>> +/*****************************************************************************
> >>> + * Local prototypes.
> >>> +
> >>> *****************************************************************************/
> >>> +struct aout_sys_t
> >>> +{
> >>> +    block_bytestream_t data;
> >>> +
> >>> +    atomic_bool flushing;
> >>> +    vlc_cond_t flushed_signal;
> >>> +    vlc_mutex_t mutex;
> >>> +
> >>> +    vlc_atomic_float latency;
> >>> +    unsigned samplerate;
> >>> +
> >>> +    PP_Instance instance;
> >>> +    PP_Resource config;
> >>> +    PP_Resource context;
> >>> +
> >>> +    PPB_AudioConfig *audioconfig;
> >>> +    PPB_Audio *audio;
> >>> +    PPB_Core *core;
> >>> +};
> >>> +
> >>> +/*****************************************************************************
> >>> + * Implementation
> >>> +
> >>> *****************************************************************************/
> >>> +static void ppapi_audio_callback(void *sample_buffer,
> >>> +        uint32_t buffer_size_in_bytes, PP_TimeDelta latency, void*
> >>> user_data)
> >>> +{
> >>> +    audio_output_t *aout = user_data;
> >>> +    aout_sys_t *sys = aout->sys;
> >>> +
> >>> +    vlc_atomic_store_float(&sys->latency, latency);
> >>> +
> >>> +    if (block_GetBytes(&sys->data, sample_buffer,
> >>> buffer_size_in_bytes) != VLC_SUCCESS) {
> >>> +        if (atomic_load(&sys->flushing)) {
> >>> +            block_BytestreamEmpty(&sys->data);
> >>> +            vlc_mutex_lock(&sys->mutex);
> >>> +            vlc_cond_signal(&sys->flushed_signal);
> >>> +            vlc_mutex_unlock(&sys->mutex);
> >>> +        } else {
> >>> +            memset(sample_buffer, 0x00, buffer_size_in_bytes);
> >>> +        }
> >>> +    }
> >>> +
> >>> +    block_BytestreamFlush(&sys->data);
> >>> +}
> >>> +
> >>> +static int Start(audio_output_t *aout, audio_sample_format_t *restrict
> >>> fmt)
> >>> +{
> >>> +    aout_sys_t *sys = aout->sys;
> >>> +
> >>> +    sys->samplerate = fmt->i_rate;
> >>> +
> >>> +    /* Create audio config */
> >>> +    uint32_t sample_frame_count =
> >>> sys->audioconfig->RecommendSampleFrameCount(
> >>> +            sys->instance, sys->samplerate, 512);
> >>> +
> >>> +    msg_Dbg(aout, "Using sample_frame_count of %u",
> >>> sample_frame_count);
> >>> +
> >>> +    sys->config = sys->audioconfig->CreateStereo16Bit(sys->instance,
> >>> +            sys->samplerate, sample_frame_count);
> >>> +    if (unlikely(sys->config) == 0) {
> >>> +        msg_Err(aout, "Could not create PPAPI audio config");
> >>> +        goto error;
> >>> +    }
> >>> +
> >>> +    /* Create audio context */
> >>> +    sys->context = sys->audio->Create(sys->instance, sys->config,
> >>> +            ppapi_audio_callback, aout);
> >>> +    if (unlikely(sys->context) == 0) {
> >>> +        msg_Err(aout, "Could not create PPAPI audio resource");
> >>> +        goto error;
> >>> +    }
> >>> +
> >>> +    /* Enforce stereo output S16N output */
> >>> +    fmt->i_format = VLC_CODEC_S16N;
> >>> +    fmt->i_original_channels = fmt->i_physical_channels =
> >>> AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
> >>> +
> >>> +    sys->audio->StartPlayback(sys->context);
> >>> +
> >>> +    return VLC_SUCCESS;
> >>> +
> >>> +error:
> >>> +    if (sys->config != 0)
> >>> +        sys->core->ReleaseResource(sys->config);
> >>> +
> >>> +    return VLC_EGENERIC;
> >>> +}
> >>> +
> >>> +static void Stop(audio_output_t *aout)
> >>> +{
> >>> +    aout_sys_t *sys = aout->sys;
> >>> +
> >>> +    if (unlikely(sys->context == 0))
> >>> +        return;
> >>> +
> >>> +    if (sys->audio->StopPlayback(sys->context) != PP_TRUE)
> >>> +        msg_Warn(aout, "Failed to stop playback");
> >>> +
> >>> +    sys->core->ReleaseResource(sys->context);
> >>> +    sys->context = 0;
> >>> +}
> >>> +
> >>> +static int TimeGet(audio_output_t *aout, mtime_t *delay)
> >>> +{
> >>> +    aout_sys_t *sys = aout->sys;
> >>> +
> >>> +    *delay = vlc_atomic_load_float(&sys->latency) * CLOCK_FREQ +
> >>> +        (block_BytestreamRemaining(&sys->data) / 4) * CLOCK_FREQ /
> >>> sys->samplerate;
> >>> +
> >>> +    return VLC_SUCCESS;
> >>> +}
> >>> +
> >>> +static void Play(audio_output_t *aout, block_t *block)
> >>> +{
> >>> +    aout_sys_t *sys = aout->sys;
> >>> +
> >>> +    block_BytestreamPush(&sys->data, block);
> >>> +}
> >>> +
> >>> +static void Flush(audio_output_t *aout, bool wait)
> >>> +{
> >>> +    aout_sys_t *sys = aout->sys;
> >>> +
> >>> +    if (wait) {
> >>> +        atomic_store(&sys->flushing, true);
> >>> +        vlc_mutex_lock(&sys->mutex);
> >>> +        vlc_cond_wait(&sys->flushed_signal, &sys->mutex);
> >>> +        vlc_mutex_unlock(&sys->mutex);
> >>> +        atomic_store(&sys->flushing, false);
> >>> +    } else {
> >>> +        block_BytestreamEmpty(&sys->data);
> >>> +    }
> >>> +}
> >>> +
> >>> +static int Open(vlc_object_t *obj)
> >>> +{
> >>> +    audio_output_t *aout = (audio_output_t *)obj;
> >>> +    aout_sys_t *sys;
> >>> +
> >>> +    sys = calloc(1, sizeof(*sys));
> >>> +    if (unlikely(sys == NULL))
> >>> +        return VLC_ENOMEM;
> >>> +    aout->sys = sys;
> >>> +
> >>> +    PPB_GetInterface ppb_get_interface = var_InheritAddress(obj,
> >>> "ppapi-ppb-get-interface");
> >>> +    if (ppb_get_interface == NULL) {
> >>> +        msg_Err(aout, "Variable ppapi-ppb-get-interface is not set");
> >>> +        goto error;
> >>> +    }
> >>> +
> >>> +    sys->instance = (int)var_InheritInteger(obj, "ppapi-instance");
> >>> +    if (unlikely(sys->instance == 0)) {
> >>> +        msg_Err(aout, "Variable ppapi-instance is not set");
> >>> +        goto error;
> >>> +    }
> >>> +
> >>> +    sys->core = (PPB_Core*)ppb_get_interface(PPB_CORE_INTERFACE);
> >>> +    if (sys->core == NULL) {
> >>> +        msg_Err(aout, "Failed to get PPB_CORE_INTERFACE");
> >>> +        goto error;
> >>> +    }
> >>> +
> >>> +    sys->audio = (PPB_Audio*)ppb_get_interface(PPB_AUDIO_INTERFACE);
> >>> +    if (unlikely(sys->audio == NULL)) {
> >>> +        msg_Err(aout, "Failed to get PPB_AUDIO_INTERFACE");
> >>> +        goto error;
> >>> +    }
> >>> +
> >>> +    sys->audioconfig =
> >>> (PPB_AudioConfig*)ppb_get_interface(PPB_AUDIO_CONFIG_INTERFACE);
> >>> +    if (unlikely(sys->audioconfig == NULL)) {
> >>> +        msg_Err(aout, "Failed to get PPB_AUDIO_CONFIG_INTERFACE");
> >>> +        goto error;
> >>> +    }
> >>> +
> >>> +    block_BytestreamInit(&sys->data);
> >>> +
> >>> +    aout->start = Start;
> >>> +    aout->stop = Stop;
> >>> +    aout->time_get = TimeGet;
> >>> +    aout->play = Play;
> >>> +    aout->flush = Flush;
> >>> +
> >>> +    return VLC_SUCCESS;
> >>> +
> >>> +error:
> >>> +    Close(obj);
> >>> +    return VLC_EGENERIC;
> >>> +}
> >>> +
> >>> +static void Close(vlc_object_t *obj)
> >>> +{
> >>> +    audio_output_t *aout = (audio_output_t *)obj;
> >>> +    aout_sys_t *sys = aout->sys;
> >>> +
> >>> +    block_BytestreamRelease(&sys->data);
> >>> +
> >>> +    if (sys->context != 0)
> >>> +        sys->core->ReleaseResource(sys->context);
> >>> +
> >>> +    if (sys->config != 0)
> >>> +        sys->core->ReleaseResource(sys->config);
> >>> +
> >>> +    free(sys);
> >>> +}
> >>> --
> >>> 2.12.0
> >>>
> >>> _______________________________________________
> >>> vlc-devel mailing list
> >>> To unsubscribe or modify your subscription options:
> >>> https://mailman.videolan.org/listinfo/vlc-devel
> >>
> >> Nack, thread synchronizatio' is totally broken here.
> >
> > Indeed, sys->data block_* call should be locked with a mutex in Play()
> > and ppapi_audio_callback(). Locking from the audio callback may cause a
> > real-time issue. Maybe we should implement a lock free 1 producer 1
> > consumer queue. Or we don't care for now and remove every atomic and
> > protect everything with mutexes.
> 
> Right, I was somehow under the impression that block_Bytestream had 
> internal locking implemented. But that's obviously wrong. Sorry for 
> missing that.
> To avoid making this patch series even bigger I'd prefer to change this 
> to use simple mutex locking for now.
> In a second step we could think about porting to a lockfree queue. Would 
> this be ok for you guys?

Fine with me. We would also need a lockfree queue for the Apple aout, so
maybe it should be a core feature, but let's focus on that later (after
3.0).

> 
> -Julian
> 
> >> --
> >> Rémi Denis-Courmont
> >> _______________________________________________
> >> vlc-devel mailing list
> >> To unsubscribe or modify your subscription options:
> >> https://mailman.videolan.org/listinfo/vlc-devel
> > _______________________________________________
> > vlc-devel mailing list
> > To unsubscribe or modify your subscription options:
> > https://mailman.videolan.org/listinfo/vlc-devel
> >
> 
> _______________________________________________
> 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