1
mirror of https://code.videolan.org/videolan/vlc synced 2024-07-21 07:24:15 +02:00

aout: use a separate drain callback

This callback is not mandatory. If it is NULL, the core will wait for the delay
returned by time_get(). This was already the case for most aout plugins:
PulseAudio, coreaudio, Android, DirectSound, Wasapi, and Jack.
This commit is contained in:
Thomas Guillem 2019-03-12 14:42:08 +01:00
parent 9bfddfd1eb
commit 2049d40876
21 changed files with 145 additions and 190 deletions

View File

@ -212,14 +212,20 @@ struct audio_output
* \note This callback cannot be called in stopped state.
*/
void (*flush)( audio_output_t *, bool wait);
/**< Flushes or drains the playback buffers (mandatory, cannot be NULL).
void (*flush)( audio_output_t *);
/**< Flushes the playback buffers (mandatory, cannot be NULL).
*
* \param wait true to wait for playback of pending buffers (drain),
* false to discard pending buffers (flush)
*
* \note This callback cannot be called in stopped state.
*/
void (*drain)(audio_output_t *);
/**< Drain the playback buffers (can be NULL).
*
* If NULL, the caller will wait for the delay returned by time_get before
* calling stop().
*/
int (*volume_set)(audio_output_t *, float volume);
/**< Changes playback volume (optional, may be NULL).
@ -456,7 +462,7 @@ static inline void aout_PauseDefault(audio_output_t *aout, bool paused,
vlc_tick_t date)
{
if (paused && aout->flush != NULL)
aout->flush(aout, false);
aout->flush(aout);
(void) date;
}

View File

@ -52,9 +52,9 @@ static void Pause(audio_output_t *aout, bool paused, vlc_tick_t date)
(void) aout; (void) paused; (void) date;
}
static void Flush(audio_output_t *aout, bool wait)
static void Flush(audio_output_t *aout)
{
(void) aout; (void) wait;
(void) aout;
}
static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)

View File

@ -294,7 +294,8 @@ static int TimeGet (audio_output_t *aout, vlc_tick_t *);
static void Play(audio_output_t *, block_t *, vlc_tick_t);
static void Pause (audio_output_t *, bool, vlc_tick_t);
static void PauseDummy (audio_output_t *, bool, vlc_tick_t);
static void Flush (audio_output_t *, bool);
static void Flush (audio_output_t *);
static void Drain (audio_output_t *);
/** Initializes an ALSA playback stream */
static int Start (audio_output_t *aout, audio_sample_format_t *restrict fmt)
@ -714,20 +715,26 @@ static void PauseDummy (audio_output_t *aout, bool pause, vlc_tick_t date)
}
/**
* Flushes/drains the audio playback buffer.
* Flushes the audio playback buffer.
*/
static void Flush (audio_output_t *aout, bool wait)
static void Flush (audio_output_t *aout)
{
aout_sys_t *p_sys = aout->sys;
snd_pcm_t *pcm = p_sys->pcm;
if (wait)
snd_pcm_drain (pcm);
else
snd_pcm_drop (pcm);
snd_pcm_drop (pcm);
snd_pcm_prepare (pcm);
}
/**
* Drains the audio playback buffer.
*/
static void Drain (audio_output_t *aout)
{
aout_sys_t *p_sys = aout->sys;
snd_pcm_t *pcm = p_sys->pcm;
snd_pcm_drain (pcm);
snd_pcm_prepare (pcm);
}
/**
* Releases the audio output.
@ -851,6 +858,7 @@ static int Open(vlc_object_t *obj)
aout->time_get = TimeGet;
aout->play = Play;
aout->flush = Flush;
aout->drain = Drain;
return VLC_SUCCESS;
error:

View File

@ -104,19 +104,27 @@ static void Pause (audio_output_t *aout, bool paused, vlc_tick_t date)
}
}
static void Flush (audio_output_t *aout, bool wait)
static void Flush (audio_output_t *aout)
{
aout_sys_t *sys = aout->sys;
void (*cb) (void *) = wait ? sys->drain : sys->flush;
if (cb != NULL)
if (sys->flush != NULL)
{
vlc_mutex_lock(&sys->lock);
cb (sys->opaque);
sys->flush (sys->opaque);
vlc_mutex_unlock(&sys->lock);
}
}
static void Drain (audio_output_t *aout)
{
aout_sys_t *sys = aout->sys;
vlc_mutex_lock(&sys->lock);
sys->drain (sys->opaque);
vlc_mutex_unlock(&sys->lock);
}
static int VolumeSet (audio_output_t *aout, float vol)
{
aout_sys_t *sys = aout->sys;
@ -313,6 +321,7 @@ static int Open (vlc_object_t *obj)
aout->play = Play;
aout->pause = Pause;
aout->flush = Flush;
aout->drain = sys->drain ? Drain : NULL;
if (sys->set_volume != NULL)
{
aout->volume_set = VolumeSet;

View File

@ -2040,7 +2040,7 @@ bailout:
}
static void
Flush( audio_output_t *p_aout, bool b_wait )
Flush( audio_output_t *p_aout )
{
aout_sys_t *p_sys = p_aout->sys;
JNIEnv *env;
@ -2061,25 +2061,10 @@ Flush( audio_output_t *p_aout, bool b_wait )
* that has not been played back will be discarded. No-op if not stopped
* or paused, or if the track's creation mode is not MODE_STREAM.
*/
if( b_wait )
{
/* Wait for the thread to process the circular buffer */
while( !p_sys->b_error
&& p_sys->circular.i_read != p_sys->circular.i_write )
vlc_cond_wait( &p_sys->aout_cond, &p_sys->lock );
if( p_sys->b_error )
goto bailout;
JNI_AT_CALL_VOID( stop );
if( CHECK_AT_EXCEPTION( "stop" ) )
goto bailout;
} else
{
JNI_AT_CALL_VOID( pause );
if( CHECK_AT_EXCEPTION( "pause" ) )
goto bailout;
JNI_AT_CALL_VOID( flush );
}
JNI_AT_CALL_VOID( pause );
if( CHECK_AT_EXCEPTION( "pause" ) )
goto bailout;
JNI_AT_CALL_VOID( flush );
p_sys->circular.i_read = p_sys->circular.i_write = 0;
/* HACK: Before Android 4.4, the head position is not reset to zero and is

View File

@ -409,15 +409,7 @@ Pause (audio_output_t *p_aout, bool pause, vlc_tick_t date)
* that we loose 1-2 sec of audio when resuming. The order is important
* here, ca_Flush need to be called when paused. */
if (pause)
ca_Flush(p_aout, false);
}
static void
Flush(audio_output_t *p_aout, bool wait)
{
aout_sys_t * p_sys = p_aout->sys;
ca_Flush(p_aout, wait);
ca_Flush(p_aout);
}
static int
@ -430,7 +422,7 @@ MuteSet(audio_output_t *p_aout, bool mute)
{
Pause(p_aout, mute, 0);
if (mute)
ca_Flush(p_aout, false);
ca_Flush(p_aout);
}
return VLC_SUCCESS;
@ -562,7 +554,6 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
fmt->channel_type = AUDIO_CHANNEL_TYPE_BITMAP;
p_aout->mute_set = MuteSet;
p_aout->pause = Pause;
p_aout->flush = Flush;
aout_SoftVolumeStart( p_aout );

View File

@ -230,42 +230,21 @@ ca_TimeGet(audio_output_t *p_aout, vlc_tick_t *delay)
}
void
ca_Flush(audio_output_t *p_aout, bool wait)
ca_Flush(audio_output_t *p_aout)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
lock_lock(p_sys);
if (wait)
{
while (p_sys->i_out_size > 0)
{
if (p_sys->b_paused)
{
ca_ClearOutBuffers(p_aout);
break;
}
/* Calculate the duration of the circular buffer, in order to wait
* for the render thread to play it all */
const vlc_tick_t i_frame_us =
FramesToUs(p_sys, BytesToFrames(p_sys, p_sys->i_out_size)) + VLC_TICK_FROM_MS(10);
lock_unlock(p_sys);
vlc_tick_sleep(i_frame_us);
lock_lock(p_sys);
}
}
assert(!p_sys->b_do_flush);
if (p_sys->b_paused)
ca_ClearOutBuffers(p_aout);
else
{
assert(!p_sys->b_do_flush);
if (p_sys->b_paused)
ca_ClearOutBuffers(p_aout);
else
{
p_sys->b_do_flush = true;
lock_unlock(p_sys);
vlc_sem_wait(&p_sys->flush_sem);
lock_lock(p_sys);
}
p_sys->b_do_flush = true;
lock_unlock(p_sys);
vlc_sem_wait(&p_sys->flush_sem);
lock_lock(p_sys);
}
p_sys->i_render_host_time = 0;

View File

@ -89,7 +89,7 @@ void ca_Render(audio_output_t *p_aout, uint32_t i_nb_samples, uint64_t i_host_ti
int ca_TimeGet(audio_output_t *p_aout, vlc_tick_t *delay);
void ca_Flush(audio_output_t *p_aout, bool wait);
void ca_Flush(audio_output_t *p_aout);
void ca_Pause(audio_output_t * p_aout, bool pause, vlc_tick_t date);

View File

@ -360,19 +360,10 @@ static HRESULT StreamFlush( aout_stream_t *s )
return Flush( s->sys );
}
static void OutputFlush( audio_output_t *aout, bool drain )
static void OutputFlush( audio_output_t *aout )
{
aout_sys_t *sys = aout->sys;
if (drain)
{ /* Loosy drain emulation */
vlc_tick_t delay;
if( OutputTimeGet( aout, &delay ) == 0 &&
delay <= VLC_TICK_FROM_SEC( 5 ) )
Sleep( MS_FROM_VLC_TICK( delay ) + 1 );
}
else
Flush( &sys->s );
Flush( &sys->s );
}
/**

View File

@ -75,7 +75,7 @@ static const int pi_channels_maps[CHANNELS_MAX+1] =
static int Open ( vlc_object_t * );
static void Play ( audio_output_t *, block_t *, vlc_tick_t );
static void Pause ( audio_output_t *, bool, vlc_tick_t );
static void Flush ( audio_output_t *, bool );
static void Flush ( audio_output_t * );
/*****************************************************************************
* Module descriptor
@ -339,12 +339,11 @@ static void Pause( audio_output_t *aout, bool paused, vlc_tick_t date )
(void) aout; (void) paused; (void) date;
}
static void Flush( audio_output_t *aout, bool wait )
static void Flush( audio_output_t *aout )
{
aout_sys_t *p_sys = aout->sys;
if( fflush( p_sys->p_file ) )
msg_Err( aout, "flush error: %s", vlc_strerror_c(errno) );
(void) wait;
}
static int Open(vlc_object_t *obj)

View File

@ -71,7 +71,7 @@ static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * );
static void Play ( audio_output_t * p_aout, block_t *, vlc_tick_t );
static void Pause ( audio_output_t *aout, bool paused, vlc_tick_t date );
static void Flush ( audio_output_t *p_aout, bool wait );
static void Flush ( audio_output_t *p_aout );
static int TimeGet ( audio_output_t *, vlc_tick_t * );
static int Process ( jack_nframes_t i_frames, void *p_arg );
static int GraphChange ( void *p_arg );
@ -328,19 +328,11 @@ static void Pause(audio_output_t *aout, bool paused, vlc_tick_t date)
}
}
static void Flush(audio_output_t *p_aout, bool wait)
static void Flush(audio_output_t *p_aout)
{
aout_sys_t * p_sys = p_aout->sys;
jack_ringbuffer_t *rb = p_sys->p_jack_ringbuffer;
/* Sleep if wait was requested */
if( wait )
{
vlc_tick_t delay;
if (!TimeGet(p_aout, &delay))
vlc_tick_sleep(delay);
}
/* reset ringbuffer read and write pointers */
jack_ringbuffer_reset(rb);
}

View File

@ -74,7 +74,7 @@ static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * );
static void Play ( audio_output_t *_p_aout, block_t *block, vlc_tick_t );
static void Pause ( audio_output_t *, bool, vlc_tick_t );
static void Flush ( audio_output_t *, bool );
static void Flush ( audio_output_t * );
static int TimeGet ( audio_output_t *, vlc_tick_t *restrict );
static ULONG APIENTRY KaiCallback ( PVOID, PVOID, ULONG );
@ -310,23 +310,15 @@ static void Pause( audio_output_t *aout, bool pause, vlc_tick_t date )
kaiResume( sys->hkai );
}
static void Flush( audio_output_t *aout, bool drain )
static void Flush( audio_output_t *aout )
{
aout_sys_t *sys = aout->sys;
audio_buffer_t *buffer = sys->buffer;
vlc_mutex_lock( &buffer->mutex );
if( drain )
{
while( buffer->length > 0 )
vlc_cond_wait( &buffer->cond, &buffer->mutex );
}
else
{
buffer->read_pos = buffer->write_pos;
buffer->length = 0;
}
buffer->read_pos = buffer->write_pos;
buffer->length = 0;
vlc_mutex_unlock( &buffer->mutex );
}

View File

@ -162,13 +162,13 @@ static void Pause(audio_output_t *aout, bool paused, vlc_tick_t date)
(void) date;
}
static void Flush(audio_output_t *aout, bool wait)
static void Flush(audio_output_t *aout)
{
aout_sys_t *sys = aout->sys;
HRESULT hr;
EnterMTA();
hr = aout_stream_Flush(sys->stream, wait);
hr = aout_stream_Flush(sys->stream);
LeaveMTA();
vlc_FromHR(aout, hr);

View File

@ -77,19 +77,9 @@ static inline HRESULT aout_stream_Pause(aout_stream_t *s, bool paused)
return (s->pause)(s, paused);
}
static inline HRESULT aout_stream_Flush(aout_stream_t *s, bool wait)
static inline HRESULT aout_stream_Flush(aout_stream_t *s)
{
if (wait)
{ /* Loosy drain emulation */
vlc_tick_t delay;
if (SUCCEEDED(aout_stream_TimeGet(s, &delay)) &&
delay <= VLC_TICK_FROM_SEC(5))
Sleep(MS_FROM_VLC_TICK( delay ) + 1);
return S_OK;
}
else
return (s->flush)(s);
return (s->flush)(s);
}
static inline

View File

@ -177,30 +177,24 @@ static int TimeGet(audio_output_t* aout, vlc_tick_t* restrict drift)
return 0;
}
static void Flush(audio_output_t *aout, bool drain)
static void Flush(audio_output_t *aout)
{
aout_sys_t *sys = aout->sys;
if (drain) {
vlc_tick_t delay;
if (!TimeGet(aout, &delay))
vlc_tick_sleep(delay);
} else {
vlc_mutex_lock(&sys->lock);
SetPlayState(sys->playerPlay, SL_PLAYSTATE_STOPPED);
Clear(sys->playerBufferQueue);
SetPlayState(sys->playerPlay, SL_PLAYSTATE_PLAYING);
vlc_mutex_lock(&sys->lock);
SetPlayState(sys->playerPlay, SL_PLAYSTATE_STOPPED);
Clear(sys->playerBufferQueue);
SetPlayState(sys->playerPlay, SL_PLAYSTATE_PLAYING);
/* release audio data not yet written to opensles */
block_ChainRelease(sys->p_buffer_chain);
sys->p_buffer_chain = NULL;
sys->pp_buffer_last = &sys->p_buffer_chain;
/* release audio data not yet written to opensles */
block_ChainRelease(sys->p_buffer_chain);
sys->p_buffer_chain = NULL;
sys->pp_buffer_last = &sys->p_buffer_chain;
sys->samples = 0;
sys->started = false;
sys->samples = 0;
sys->started = false;
vlc_mutex_unlock(&sys->lock);
}
vlc_mutex_unlock(&sys->lock);
}
static int VolumeSet(audio_output_t *aout, float vol)

View File

@ -90,7 +90,7 @@ vlc_module_end ()
static int TimeGet (audio_output_t *, vlc_tick_t *);
static void Play(audio_output_t *, block_t *, vlc_tick_t);
static void Pause (audio_output_t *, bool, vlc_tick_t);
static void Flush (audio_output_t *, bool);
static void Flush (audio_output_t *);
static int Start (audio_output_t *aout, audio_sample_format_t *restrict fmt)
{
@ -302,15 +302,13 @@ static void Pause (audio_output_t *aout, bool pause, vlc_tick_t date)
}
/**
* Flushes/drains the audio playback buffer.
* Flushes the audio playback buffer.
*/
static void Flush (audio_output_t *aout, bool wait)
static void Flush (audio_output_t *aout)
{
aout_sys_t *sys = aout->sys;
int fd = sys->fd;
if (wait)
return; /* drain is implicit with OSS */
ioctl (fd, SNDCTL_DSP_HALT, NULL);
}

View File

@ -533,26 +533,14 @@ static void Pause(audio_output_t *aout, bool paused, vlc_tick_t date)
/**
* Flush or drain the playback stream
*/
static void Flush(audio_output_t *aout, bool wait)
static void Flush(audio_output_t *aout)
{
aout_sys_t *sys = aout->sys;
pa_stream *s = sys->stream;
pa_operation *op;
pa_threaded_mainloop_lock(sys->mainloop);
if (wait)
{
op = pa_stream_drain(s, NULL, NULL);
/* XXX: Loosy drain emulation.
* See #18141: drain callback is never received */
vlc_tick_t delay;
if (TimeGet(aout, &delay) == 0 && delay <= VLC_TICK_FROM_SEC(5))
vlc_tick_sleep(delay);
}
else
op = pa_stream_flush(s, NULL, NULL);
pa_operation *op = pa_stream_flush(s, NULL, NULL);
if (op != NULL)
pa_operation_unref(op);
sys->last_date = VLC_TICK_INVALID;
@ -561,6 +549,24 @@ static void Flush(audio_output_t *aout, bool wait)
pa_threaded_mainloop_unlock(sys->mainloop);
}
static void Drain(audio_output_t *aout)
{
aout_sys_t *sys = aout->sys;
pa_stream *s = sys->stream;
pa_threaded_mainloop_lock(sys->mainloop);
pa_operation *op = pa_stream_drain(s, NULL, NULL);
if (op != NULL)
pa_operation_unref(op);
pa_threaded_mainloop_unlock(sys->mainloop);
/* XXX: Loosy drain emulation.
* See #18141: drain callback is never received */
vlc_tick_t delay;
if (TimeGet(aout, &delay) == 0 && delay <= VLC_TICK_FROM_SEC(5))
vlc_tick_sleep(delay);
}
static int VolumeSet(audio_output_t *aout, float vol)
{
aout_sys_t *sys = aout->sys;
@ -1006,6 +1012,7 @@ static int Open(vlc_object_t *obj)
aout->play = Play;
aout->pause = Pause;
aout->flush = Flush;
aout->drain = Drain;
aout->volume_set = VolumeSet;
aout->mute_set = MuteSet;
aout->device_select = StreamMove;

View File

@ -45,7 +45,7 @@ vlc_module_end ()
static int TimeGet (audio_output_t *, vlc_tick_t *);
static void Play(audio_output_t *, block_t *, vlc_tick_t);
static void Flush (audio_output_t *, bool);
static void Flush (audio_output_t *);
static int VolumeSet (audio_output_t *, float);
static int MuteSet (audio_output_t *, bool);
static void VolumeChanged (void *, unsigned);
@ -240,7 +240,7 @@ static void Play(audio_output_t *aout, block_t *block, vlc_tick_t date)
(void) date;
}
static void Flush (audio_output_t *aout, bool wait)
static void Flush (audio_output_t *aout)
{
aout_sys_t *sys = aout->sys;
@ -248,7 +248,6 @@ static void Flush (audio_output_t *aout, bool wait)
sys->started = 0;
sys->delay = 0;
sio_start (sys->hdl);
(void)wait;
}
static void VolumeChanged (void *arg, unsigned volume)

View File

@ -79,7 +79,8 @@ static void WaveOutClearBuffer( HWAVEOUT, WAVEHDR *);
static int ReloadWaveoutDevices( const char *, char ***, char *** );
static uint32_t findDeviceID(char *);
static int WaveOutTimeGet(audio_output_t * , vlc_tick_t *);
static void WaveOutFlush( audio_output_t *, bool);
static void WaveOutFlush( audio_output_t *);
static void WaveOutDrain( audio_output_t *);
static void WaveOutPause( audio_output_t *, bool, vlc_tick_t);
static int WaveoutVolumeSet(audio_output_t * p_aout, float volume);
static int WaveoutMuteSet(audio_output_t * p_aout, bool mute);
@ -177,6 +178,7 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
p_aout->play = Play;
p_aout->pause = WaveOutPause;
p_aout->flush = WaveOutFlush;
p_aout->drain = WaveOutDrain;
aout_sys_t *sys = p_aout->sys;
@ -393,7 +395,7 @@ static void Stop( audio_output_t *p_aout )
waveOutReset( p_sys->h_waveout );
/* wait for the frames to be queued in cleaning list */
WaveOutFlush( p_aout, true );
WaveOutDrain( p_aout );
WaveOutClean( p_sys );
/* now we can Close the device */
@ -848,27 +850,27 @@ static int WaveOutTimeGet(audio_output_t * p_aout, vlc_tick_t *delay)
return 0;
}
static void WaveOutFlush( audio_output_t *p_aout, bool wait)
static void WaveOutFlush( audio_output_t *p_aout)
{
MMRESULT res;
aout_sys_t *sys = p_aout->sys;
if( !wait )
res = waveOutReset( sys->h_waveout );
sys->i_played_length = 0;
if( res != MMSYSERR_NOERROR )
msg_Err( p_aout, "waveOutReset failed");
}
static void WaveOutDrain( audio_output_t *p_aout)
{
aout_sys_t *sys = p_aout->sys;
vlc_mutex_lock( &sys->lock );
while( sys->i_frames )
{
res = waveOutReset( sys->h_waveout );
sys->i_played_length = 0;
if( res != MMSYSERR_NOERROR )
msg_Err( p_aout, "waveOutReset failed");
}
else
{
vlc_mutex_lock( &sys->lock );
while( sys->i_frames )
{
vlc_cond_wait( &sys->cond, &sys->lock );
}
vlc_mutex_unlock( &sys->lock );
vlc_cond_wait( &sys->cond, &sys->lock );
}
vlc_mutex_unlock( &sys->lock );
}
static void WaveOutPause( audio_output_t * p_aout, bool pause, vlc_tick_t date)

View File

@ -178,14 +178,14 @@ static void Pause(audio_output_t *aout, bool paused, vlc_tick_t date)
vlc_FromHR(aout, hr);
}
static void Flush(audio_output_t *aout, bool wait)
static void Flush(audio_output_t *aout)
{
aout_sys_t *sys = aout->sys;
if( unlikely( sys->client == NULL ) )
return;
EnterMTA();
HRESULT hr = aout_stream_Flush(sys->stream, wait);
HRESULT hr = aout_stream_Flush(sys->stream);
LeaveMTA();
vlc_FromHR(aout, hr);

View File

@ -38,6 +38,18 @@
#include "clock/clock.h"
#include "libvlc.h"
static void aout_Drain(audio_output_t *aout)
{
if (aout->drain)
aout->drain(aout);
else
{
vlc_tick_t delay;
if (aout->time_get(aout, &delay) == 0)
vlc_tick_sleep(delay);
}
}
/**
* Creates an audio output
*/
@ -481,7 +493,7 @@ void aout_DecChangePause (audio_output_t *aout, bool paused, vlc_tick_t date)
if (aout->pause != NULL)
aout->pause(aout, paused, date);
else if (paused)
aout->flush(aout, false);
aout->flush(aout);
}
}
@ -507,7 +519,7 @@ void aout_DecFlush(audio_output_t *aout)
{
aout_FiltersFlush (owner->filters);
aout->flush(aout, false);
aout->flush(aout);
vlc_clock_Reset(owner->sync.clock);
aout_FiltersResetClock(owner->filters);
@ -539,7 +551,8 @@ void aout_DecDrain(audio_output_t *aout)
block_t *block = aout_FiltersDrain (owner->filters);
if (block)
aout->play(aout, block, vlc_tick_now());
aout->flush(aout, true);
aout_Drain(aout);
vlc_clock_Reset(owner->sync.clock);
aout_FiltersResetClock(owner->filters);