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

Julian Scheel julian at jusst.de
Tue Mar 21 09:18:49 CET 2017


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?

-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
>



More information about the vlc-devel mailing list