[vlc-devel] [PATCH 6/6] aout: make the drain implementation asynchronous
Thomas Guillem
thomas at gllm.fr
Tue Mar 12 16:23:54 CET 2019
Yes, only the waveout plugin can do an asynchronous drain (for now).
Only the plugin implementation is asynchronous (for now), aout_DecDrain() is
still synchronous since it will wait for drain end from this call. The goal is
to make aout plugins non-blocking so that we can easily change the aout core
implementation in the future.
---
include/vlc_aout.h | 16 +++++++++++++++-
modules/audio_output/waveout.c | 23 ++++++++++++++++++-----
src/audio_output/aout_internal.h | 2 ++
src/audio_output/dec.c | 9 +++++++++
src/audio_output/output.c | 3 +++
5 files changed, 47 insertions(+), 6 deletions(-)
diff --git a/include/vlc_aout.h b/include/vlc_aout.h
index d25abd874b..4441a42a82 100644
--- a/include/vlc_aout.h
+++ b/include/vlc_aout.h
@@ -112,6 +112,7 @@
#include <vlc_block.h>
struct vlc_audio_output_events {
+ void (*drained_report)(audio_output_t *);
void (*timing_report)(audio_output_t *, vlc_tick_t system_now, vlc_tick_t pts);
void (*volume_report)(audio_output_t *, float);
void (*mute_report)(audio_output_t *, bool);
@@ -221,7 +222,7 @@ struct audio_output
* \note This callback cannot be called in stopped state.
*/
void (*drain)(audio_output_t *);
- /**< Drain the playback buffers (can be NULL).
+ /**< Drain the playback buffers asynchronously (can be NULL).
*
* The implementation can invalidate the stream since this is generally
* the last call before a stop(). However, a flush() could also be called
@@ -230,6 +231,9 @@ struct audio_output
*
* If NULL, the caller will wait for the delay returned by time_get before
* calling stop().
+ *
+ * \note The implementation must call aout_DrainedReport() from or after
+ * this callback.
*/
int (*volume_set)(audio_output_t *, float volume);
@@ -446,6 +450,16 @@ static inline void aout_RestartRequest(audio_output_t *aout, unsigned mode)
aout->events->restart_request(aout, mode);
}
+/**
+ * Report that the stream is drained
+ *
+ * This function can only be called one time after or from aout->drain().
+ */
+static inline void aout_DrainedReport(audio_output_t *aout)
+{
+ aout->events->drained_report(aout);
+}
+
/**
* Default implementation for audio_output_t.time_get
*/
diff --git a/modules/audio_output/waveout.c b/modules/audio_output/waveout.c
index 3c9884ce01..495fe519bc 100644
--- a/modules/audio_output/waveout.c
+++ b/modules/audio_output/waveout.c
@@ -119,6 +119,8 @@ struct aout_sys_t
bool b_soft; /* Use software gain */
uint8_t chans_to_reorder; /* do we need channel reordering */
+ bool b_draining;
+
uint8_t chan_table[AOUT_CHAN_MAX];
vlc_fourcc_t format;
@@ -332,6 +334,7 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
sys->i_frames = 0;
sys->i_played_length = 0;
sys->p_free_list = NULL;
+ sys->b_draining = false;
fmt->channel_type = AUDIO_CHANNEL_TYPE_BITMAP;
@@ -395,7 +398,11 @@ static void Stop( audio_output_t *p_aout )
MMRESULT result = waveOutReset( p_sys->h_waveout );
/* wait for the frames to be queued in cleaning list */
- WaveOutDrain( p_aout );
+ vlc_mutex_lock( &p_sys->lock );
+ while( p_sys->i_frames )
+ vlc_cond_wait( &p_sys->cond, &p_sys->lock );
+ vlc_mutex_unlock( &p_sys->lock );
+
WaveOutClean( p_sys );
/* now we can Close the device */
@@ -650,6 +657,11 @@ static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
p_waveheader->p_next = sys->p_free_list;
sys->p_free_list = p_waveheader;
sys->i_frames--;
+ if (sys->b_draining)
+ {
+ sys->b_draining = false;
+ aout_DrainedReport((audio_output_t *)_p_aout);
+ }
vlc_cond_broadcast( &sys->cond );
vlc_mutex_unlock( &sys->lock );
}
@@ -863,11 +875,12 @@ static void WaveOutFlush( audio_output_t *p_aout)
static void WaveOutDrain( audio_output_t *p_aout)
{
+ aout_sys_t *sys = p_aout->sys;
vlc_mutex_lock( &sys->lock );
- while( sys->i_frames )
- {
- vlc_cond_wait( &sys->cond, &sys->lock );
- }
+ if( sys->i_frames )
+ sys->b_draining = true;
+ else
+ aout_DrainedReport( p_aout );
vlc_mutex_unlock( &sys->lock );
}
diff --git a/src/audio_output/aout_internal.h b/src/audio_output/aout_internal.h
index ed72cff0f8..669c81b67f 100644
--- a/src/audio_output/aout_internal.h
+++ b/src/audio_output/aout_internal.h
@@ -85,6 +85,7 @@ typedef struct
atomic_uint buffers_played;
atomic_uchar restart;
+ vlc_sem_t drain_sem;
bool drained;
} aout_owner_t;
@@ -147,6 +148,7 @@ void aout_DecDrain(audio_output_t *);
void aout_RequestRestart (audio_output_t *, unsigned);
void aout_RequestRetiming(audio_output_t *aout, vlc_tick_t system_ts,
vlc_tick_t audio_ts);
+void aout_Drained(audio_output_t *);
static inline void aout_InputRequestRestart(audio_output_t *aout)
{
diff --git a/src/audio_output/dec.c b/src/audio_output/dec.c
index 683f181f9f..91bfb4f147 100644
--- a/src/audio_output/dec.c
+++ b/src/audio_output/dec.c
@@ -531,6 +531,12 @@ void aout_DecFlush(audio_output_t *aout)
owner->drained = false;
}
+void aout_Drained(audio_output_t *aout)
+{
+ aout_owner_t *owner = aout_owner (aout);
+ vlc_sem_post(&owner->drain_sem);
+}
+
void aout_DecDrain(audio_output_t *aout)
{
aout_owner_t *owner = aout_owner (aout);
@@ -544,7 +550,10 @@ void aout_DecDrain(audio_output_t *aout)
aout->play(aout, block, vlc_tick_now());
if (aout->drain)
+ {
aout->drain(aout);
+ vlc_sem_wait(&owner->drain_sem);
+ }
else
{
vlc_tick_t delay;
diff --git a/src/audio_output/output.c b/src/audio_output/output.c
index cfc786f4a1..3f1cfbcbbc 100644
--- a/src/audio_output/output.c
+++ b/src/audio_output/output.c
@@ -165,6 +165,7 @@ static int aout_GainNotify (audio_output_t *aout, float gain)
}
static const struct vlc_audio_output_events aout_events = {
+ aout_Drained,
aout_TimingNotify,
aout_VolumeNotify,
aout_MuteNotify,
@@ -242,6 +243,7 @@ audio_output_t *aout_New (vlc_object_t *parent)
vlc_mutex_init (&owner->lock);
vlc_mutex_init (&owner->dev.lock);
vlc_mutex_init (&owner->vp.lock);
+ vlc_sem_init(&owner->drain_sem, 0);
vlc_viewpoint_init (&owner->vp.value);
atomic_init (&owner->vp.update, false);
@@ -397,6 +399,7 @@ static void aout_Destructor (vlc_object_t *obj)
audio_output_t *aout = (audio_output_t *)obj;
aout_owner_t *owner = aout_owner (aout);
+ vlc_sem_destroy(&owner->drain_sem);
vlc_mutex_destroy (&owner->dev.lock);
for (aout_dev_t *dev = owner->dev.list, *next; dev != NULL; dev = next)
{
--
2.20.1
More information about the vlc-devel
mailing list