Commit cfca8bcd authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont
Browse files

aout: split out packet-oriented output support code

This provides aout_PacketPlay(), aout_PacketPause() and
aout_PacketFlush() helpers for legacy audio outputs. They conveniently
match the callback prototypes of pf_play, pf_pause and pf_flush
respectively.
parent cbd0c5c4
......@@ -153,14 +153,6 @@ typedef int32_t vlc_fixed_t;
/* Number of samples in an A/52 frame. */
#define A52_FRAME_NB 1536
/** audio output buffer FIFO */
struct aout_fifo_t
{
aout_buffer_t * p_first;
aout_buffer_t ** pp_last;
date_t end_date;
};
/* FIXME to remove once aout.h is cleaned a bit more */
#include <vlc_block.h>
......@@ -176,8 +168,6 @@ struct audio_output
audio_sample_format_t format; /**< Output format (plugin can modify it
only when succesfully probed and not afterward) */
aout_fifo_t fifo;
struct aout_sys_t *sys; /**< Output plugin private data */
void (*pf_play)(audio_output_t *, block_t *); /**< Audio buffer callback */
void (* pf_pause)( audio_output_t *, bool, mtime_t ); /**< Pause/resume
......@@ -266,4 +256,33 @@ VLC_API int aout_ChannelsRestart( vlc_object_t *, const char *, vlc_value_t, vlc
/* */
VLC_API vout_thread_t * aout_filter_RequestVout( filter_t *, vout_thread_t *p_vout, video_format_t *p_fmt ) VLC_USED;
/** Audio output buffer FIFO */
struct aout_fifo_t
{
aout_buffer_t * p_first;
aout_buffer_t ** pp_last;
date_t end_date;
};
/* Legacy packet-oriented audio output helpers */
typedef struct
{
aout_fifo_t partial; /**< Audio blocks before packetization */
aout_fifo_t fifo; /**< Packetized audio blocks */
mtime_t pause_date; /**< Date when paused or VLC_TS_INVALID */
unsigned samples; /**< Samples per packet */
bool starving;
/* Indicates whether the audio output is currently starving, to avoid
* printing a 1,000 "output is starving" messages. */
} aout_packet_t;
VLC_API void aout_PacketInit(audio_output_t *, aout_packet_t *, unsigned);
VLC_API void aout_PacketDestroy(audio_output_t *);
VLC_API void aout_PacketPlay(audio_output_t *, block_t *);
VLC_API void aout_PacketPause(audio_output_t *, bool, mtime_t);
VLC_API void aout_PacketFlush(audio_output_t *, bool);
VLC_API block_t *aout_PacketNext(audio_output_t *, mtime_t, bool) VLC_USED;
#endif /* VLC_AOUT_H */
......@@ -361,8 +361,8 @@ static int Open (vlc_object_t *obj)
}
p_aout->pf_play = Play;
p_aout->pf_pause = NULL;
p_aout->pf_flush = NULL;
p_aout->pf_pause = aout_PacketPause;
p_aout->pf_flush = aout_PacketFlush;
snd_pcm_hw_params_t *p_hw;
snd_pcm_sw_params_t *p_sw;
......@@ -522,21 +522,16 @@ error:
return VLC_EGENERIC;
}
static void PlayIgnore( audio_output_t *p_aout, block_t *block )
{
aout_FifoPush( &p_aout->fifo, block );
}
/*****************************************************************************
* Play: start playback
*****************************************************************************/
static void Play( audio_output_t *p_aout, block_t *block )
{
p_aout->pf_play = PlayIgnore;
/* get the playing date of the first aout buffer */
p_aout->sys->start_date = block->i_pts;
aout_FifoPush( &p_aout->fifo, block );
aout_PacketPlay( p_aout, block );
p_aout->pf_play = aout_PacketPlay;
/* wake up the audio output thread */
sem_post( &p_aout->sys->wait );
......
......@@ -122,9 +122,9 @@ static int Open ( vlc_object_t *p_this )
p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
p_aout->format.i_rate = 44100;
p_aout->format.i_nb_samples = FRAME_SIZE;
p_aout->format.pf_play = Play;
p_aout->format.pf_pause = NULL;
p_aout->pf_flush = NULL;
p_aout->pf_play = aout_PacketPlay;
p_aout->pf_pause = aout_PacketPause;
p_aout->pf_flush = aout_PacketFlush;
msg_Dbg(p_aout, "Starting AudioQueue (status = %i)", status);
status = AudioQueueStart(p_sys->audioQueue, NULL);
......@@ -132,14 +132,6 @@ static int Open ( vlc_object_t *p_this )
return VLC_SUCCESS;
}
/*****************************************************************************
* Play: play a sound samples buffer
*****************************************************************************/
static void Play( audio_output_t * p_aout, block_t *block )
{
aout_FifoPush( &p_aout->fifo, block );
}
/*****************************************************************************
* Close: close the audio device
*****************************************************************************/
......
......@@ -187,9 +187,9 @@ static int Open( vlc_object_t * p_this )
p_sys->b_changed_mixing = false;
memset( p_sys->p_remainder_buffer, 0, sizeof(uint8_t) * BUFSIZE );
p_aout->pf_play = Play;
p_aout->pf_pause = NULL;
p_aout->pf_flush = NULL;
p_aout->pf_play = aout_PacketPlay;
p_aout->pf_pause = aout_PacketPause;
p_aout->pf_flush = aout_PacketFlush;
aout_FormatPrint( p_aout, "VLC is looking for:", &p_aout->format );
......@@ -907,15 +907,6 @@ static void Close( vlc_object_t * p_this )
free( p_sys );
}
/*****************************************************************************
* Play: nothing to do
*****************************************************************************/
static void Play( audio_output_t * p_aout, block_t *block )
{
aout_FifoPush( &p_aout->fifo, block );
}
/*****************************************************************************
* Probe: Check which devices the OS has, and add them to our audio-device menu
*****************************************************************************/
......
......@@ -76,8 +76,6 @@ struct aout_sys_t
notification_thread_t *p_notif; /* DirectSoundThread id */
int b_playing; /* playing status */
int i_frame_size; /* Size in bytes of one frame */
int i_speaker_setup; /* Speaker setup override */
......@@ -171,11 +169,10 @@ static int OpenAudio( vlc_object_t *p_this )
p_aout->sys->p_dsobject = NULL;
p_aout->sys->p_dsbuffer = NULL;
p_aout->sys->p_notif = NULL;
p_aout->sys->b_playing = 0;
p_aout->pf_play = Play;
p_aout->pf_pause = NULL;
p_aout->pf_flush = NULL;
p_aout->pf_pause = aout_PacketPause;
p_aout->pf_flush = aout_PacketFlush;
aout_VolumeSoftInit( p_aout );
/* Retrieve config values */
......@@ -571,21 +568,17 @@ static void Probe( audio_output_t * p_aout )
*****************************************************************************/
static void Play( audio_output_t *p_aout, block_t *p_buffer )
{
if( !p_aout->sys->b_playing )
{
p_aout->sys->b_playing = 1;
/* get the playing date of the first aout buffer */
p_aout->sys->p_notif->start_date = p_buffer->i_pts;
/* get the playing date of the first aout buffer */
p_aout->sys->p_notif->start_date = p_buffer->i_pts;
/* fill in the first samples (zeroes) */
FillBuffer( p_aout, 0, NULL );
/* fill in the first samples */
FillBuffer( p_aout, 0, p_buffer );
/* wake up the audio output thread */
SetEvent( p_aout->sys->p_notif->event );
/* wake up the audio output thread */
SetEvent( p_aout->sys->p_notif->event );
}
else
aout_FifoPush( &p_aout->fifo, p_buffer );
aout_PacketPlay( p_aout, p_buffer );
p_aout->pf_play = aout_PacketPlay;
}
/*****************************************************************************
......@@ -603,7 +596,8 @@ static void CloseAudio( vlc_object_t *p_this )
{
vlc_atomic_set(&p_aout->sys->p_notif->abort, 1);
/* wake up the audio thread if needed */
if( !p_sys->b_playing ) SetEvent( p_sys->p_notif->event );
if( p_aout->pf_play == Play )
SetEvent( p_sys->p_notif->event );
vlc_join( p_sys->p_notif->thread, NULL );
free( p_sys->p_notif );
......
......@@ -133,9 +133,9 @@ static int Open( vlc_object_t *p_this )
jack_set_process_callback( p_sys->p_jack_client, Process, p_aout );
jack_set_graph_order_callback ( p_sys->p_jack_client, GraphChange, p_aout );
p_aout->pf_play = Play;
p_aout->pf_pause = NULL;
p_aout->pf_flush = NULL;
p_aout->pf_play = aout_PacketPlay;
p_aout->pf_pause = aout_PacketPause;
p_aout->pf_flush = aout_PacketFlush;
aout_VolumeSoftInit( p_aout );
/* JACK only supports fl32 format */
......@@ -331,14 +331,6 @@ static int GraphChange( void *p_arg )
return 0;
}
/*****************************************************************************
* Play: nothing to do
*****************************************************************************/
static void Play( audio_output_t *p_aout, block_t *block )
{
aout_FifoPush( &p_aout->fifo, block );
}
/*****************************************************************************
* Close: close the JACK client
*****************************************************************************/
......
......@@ -298,9 +298,9 @@ static int Open( vlc_object_t *p_this )
free( psz_device );
p_aout->pf_play = Play;
p_aout->pf_pause = NULL;
p_aout->pf_flush = NULL;
p_aout->pf_play = aout_PacketPlay;
p_aout->pf_pause = aout_PacketPause;
p_aout->pf_flush = aout_PacketFlush;
if ( var_Type( p_aout, "audio-device" ) == 0 )
{
......@@ -517,14 +517,6 @@ static int Open( vlc_object_t *p_this )
return VLC_SUCCESS;
}
/*****************************************************************************
* Play: nothing to do
*****************************************************************************/
static void Play( audio_output_t *p_aout, block_t *block )
{
aout_FifoPush( &p_aout->fifo, block );
}
/*****************************************************************************
* Close: close the DSP audio device
*****************************************************************************/
......
......@@ -182,9 +182,9 @@ static int Open( vlc_object_t * p_this )
p_sys->p_aout = p_aout;
p_sys->p_stream = 0;
p_aout->sys = p_sys;
p_aout->pf_play = Play;
p_aout->pf_pause = NULL;
p_aout->pf_flush = NULL;
p_aout->pf_play = aout_PacketPlay;
p_aout->pf_pause = aout_PacketPause;
p_aout->pf_flush = aout_PacketFlush;
/* Retrieve output device id from config */
p_sys->i_device_id = var_CreateGetInteger( p_aout, "portaudio-audio-device" );
......@@ -556,14 +556,6 @@ static int PAOpenStream( audio_output_t *p_aout )
return VLC_SUCCESS;
}
/*****************************************************************************
* Play: play sound
*****************************************************************************/
static void Play( audio_output_t * p_aout, block_t *block )
{
aout_FifoPush( &p_aout->fifo, block );
}
#ifdef PORTAUDIO_IS_SERIOUSLY_BROKEN
/*****************************************************************************
* PORTAUDIOThread: all interactions with libportaudio.a are handled
......
......@@ -155,8 +155,8 @@ static int Open( vlc_object_t *p_this )
return VLC_ENOMEM;
p_aout->pf_play = Play;
p_aout->pf_pause = NULL;
p_aout->pf_flush = NULL;
p_aout->pf_pause = aout_PacketPause;
p_aout->pf_flush = aout_PacketFlush;
/*
initialize/update Device selection List
......@@ -475,8 +475,6 @@ static void Probe( audio_output_t * p_aout )
*****************************************************************************/
static void Play( audio_output_t *_p_aout, block_t *block )
{
aout_FifoPush( &_p_aout->fifo, block );
if( !_p_aout->sys->b_playing )
{
_p_aout->sys->b_playing = 1;
......@@ -491,6 +489,8 @@ static void Play( audio_output_t *_p_aout, block_t *block )
} else {
SetEvent( _p_aout->sys->new_buffer_event );
}
aout_PacketPlay( _p_aout, block );
}
/*****************************************************************************
......@@ -939,7 +939,6 @@ static void* WaveOutThread( void *data )
#endif
// means we are too early to request a new buffer?
waveout_warn("waiting...")
next_date = aout_FifoFirstDate( &p_aout->fifo );
mwait( next_date - AOUT_MAX_PTS_ADVANCE/4 );
next_date = mdate();
p_buffer = aout_OutputNextBuffer( p_aout, next_date,
......
......@@ -41,7 +41,7 @@
/*****************************************************************************
* Local prototypes.
*****************************************************************************/
static void Play ( audio_output_t * );
static void Play( audio_output_t *, block_t * );
/*****************************************************************************
* OpenAudio: open a dummy audio device
......@@ -75,9 +75,9 @@ int OpenAudio ( vlc_object_t * p_this )
/*****************************************************************************
* Play: pretend to play a sound
*****************************************************************************/
static void Play( audio_output_t * p_aout )
static void Play( audio_output_t *aout, block_t *block )
{
aout_buffer_t * p_buffer = aout_FifoPop( &p_aout->fifo );
aout_BufferFree( p_buffer );
block_Release( block );
(void) aout;
}
......@@ -108,12 +108,7 @@ typedef struct
filter_t *filters[AOUT_MAX_FILTERS];
int nb_filters;
/* Indicates whether the audio output is currently starving, to avoid
* printing a 1,000 "output is starving" messages. */
bool b_starving;
mtime_t pause_date;
aout_fifo_t partial;
aout_packet_t packet;
} aout_owner_t;
typedef struct
......
......@@ -162,10 +162,7 @@ int aout_OutputNew( audio_output_t *p_aout,
aout_FormatPrint( p_aout, "output", &p_aout->format );
/* Prepare FIFO. */
aout_FifoInit (p_aout, &p_aout->fifo, p_aout->format.i_rate);
aout_FifoInit (p_aout, &owner->partial, p_aout->format.i_rate);
owner->pause_date = VLC_TS_INVALID;
owner->b_starving = true;
aout_PacketInit (p_aout, &owner->packet, p_aout->i_nb_samples);
/* Choose the mixer format. */
owner->mixer_format = p_aout->format;
......@@ -221,36 +218,30 @@ void aout_OutputDelete( audio_output_t * p_aout )
aout_VolumeNoneInit( p_aout ); /* clear volume callback */
owner->module = NULL;
aout_FiltersDestroyPipeline (owner->filters, owner->nb_filters);
aout_FifoDestroy (&p_aout->fifo);
aout_FifoDestroy (&owner->partial);
aout_PacketDestroy (p_aout);
}
static block_t *aout_OutputSlice( audio_output_t *, aout_fifo_t * );
/*****************************************************************************
* aout_OutputPlay : play a buffer
*****************************************************************************
* This function is entered with the mixer lock.
*****************************************************************************/
void aout_OutputPlay( audio_output_t * p_aout, aout_buffer_t * p_buffer )
void aout_OutputPlay (audio_output_t *aout, block_t *block)
{
aout_owner_t *owner = aout_owner (p_aout);
aout_owner_t *owner = aout_owner (aout);
vlc_assert_locked( &p_aout->lock );
vlc_assert_locked (&aout->lock);
aout_FiltersPlay (owner->filters, owner->nb_filters, &p_buffer);
if( !p_buffer )
aout_FiltersPlay (owner->filters, owner->nb_filters, &block);
if (block == NULL)
return;
if( p_buffer->i_buffer == 0 )
if (block->i_buffer == 0)
{
block_Release( p_buffer );
block_Release (block);
return;
}
aout_FifoPush (&owner->partial, p_buffer );
while ((p_buffer = aout_OutputSlice (p_aout, &owner->partial)) != NULL)
p_aout->pf_play (p_aout, p_buffer);
aout->pf_play (aout, block);
}
/**
......@@ -263,22 +254,6 @@ void aout_OutputPause( audio_output_t *aout, bool pause, mtime_t date )
vlc_assert_locked( &aout->lock );
if( aout->pf_pause != NULL )
aout->pf_pause( aout, pause, date );
aout_owner_t *owner = aout_owner (aout);
if (pause)
{
owner->pause_date = date;
}
else
{
assert (owner->pause_date != VLC_TS_INVALID);
mtime_t duration = date - owner->pause_date;
owner->pause_date = VLC_TS_INVALID;
aout_FifoMoveDates (&owner->partial, duration);
aout_FifoMoveDates (&aout->fifo, duration);
}
}
/**
......@@ -293,10 +268,6 @@ void aout_OutputFlush( audio_output_t *aout, bool wait )
if( aout->pf_flush != NULL )
aout->pf_flush( aout, wait );
aout_owner_t *owner = aout_owner (aout);
aout_FifoReset (&aout->fifo);
aout_FifoReset (&owner->partial);
}
......@@ -395,15 +366,84 @@ void aout_VolumeHardSet (audio_output_t *aout, float volume, bool mute)
}
/*** Buffer management ***/
/*** Packet-oriented audio output support ***/
static inline aout_packet_t *aout_packet (audio_output_t *aout)
{
aout_owner_t *owner = aout_owner (aout);
return &owner->packet;
}
void aout_PacketInit (audio_output_t *aout, aout_packet_t *p, unsigned samples)
{
assert (p == aout_packet (aout));
aout_FifoInit (aout, &p->partial, aout->format.i_rate);
aout_FifoInit (aout, &p->fifo, aout->format.i_rate);
p->pause_date = VLC_TS_INVALID;
p->samples = samples;
p->starving = true;
}
void aout_PacketDestroy (audio_output_t *aout)
{
aout_packet_t *p = aout_packet (aout);
aout_FifoDestroy (&p->partial);
aout_FifoDestroy (&p->fifo);
}
static block_t *aout_OutputSlice (audio_output_t *);
void aout_PacketPlay (audio_output_t *aout, block_t *block)
{
aout_packet_t *p = aout_packet (aout);
aout_FifoPush (&p->partial, block);
while ((block = aout_OutputSlice (aout)) != NULL)
aout_FifoPush (&p->fifo, block);
}
void aout_PacketPause (audio_output_t *aout, bool pause, mtime_t date)
{
aout_packet_t *p = aout_packet (aout);
if (pause)
{
assert (p->pause_date == VLC_TS_INVALID);
p->pause_date = date;
}
else
{
assert (p->pause_date != VLC_TS_INVALID);
mtime_t duration = date - p->pause_date;
p->pause_date = VLC_TS_INVALID;
aout_FifoMoveDates (&p->partial, duration);
aout_FifoMoveDates (&p->fifo, duration);
}
}
void aout_PacketFlush (audio_output_t *aout, bool drain)
{
aout_packet_t *p = aout_packet (aout);
aout_FifoReset (&p->partial);
aout_FifoReset (&p->fifo);
(void) drain; /* TODO */
}
/**
* Rearranges audio blocks in correct number of samples.
* @note (FIXME) This is left here for historical reasons. It belongs in the
* output code. Besides, this operation should be avoided if possible.
*/
static block_t *aout_OutputSlice (audio_output_t *p_aout, aout_fifo_t *p_fifo)
static block_t *aout_OutputSlice (audio_output_t *p_aout)
{
aout_packet_t *p = aout_packet (p_aout);
aout_fifo_t *p_fifo = &p->partial;
const unsigned samples = p_aout->i_nb_samples;
/* FIXME: Remove this silly constraint. Just pass buffers as they come to
* "smart" audio outputs. */
......@@ -412,7 +452,7 @@ static block_t *aout_OutputSlice (audio_output_t *p_aout, aout_fifo_t *p_fifo)
vlc_assert_locked( &p_aout->lock );
/* Retrieve the date of the next buffer. */
date_t exact_start_date = p_aout->fifo.end_date;
date_t exact_start_date = p->fifo.end_date;
mtime_t start_date = date_Get( &exact_start_date );
/* See if we have enough data to prepare a new buffer for the audio output. */
......@@ -483,7 +523,7 @@ static block_t *aout_OutputSlice (audio_output_t *p_aout, aout_fifo_t *p_fifo)
if( delta < 0 )
{
/* Is it really the best way to do it ? */
aout_FifoReset( &p_aout->fifo );
aout_FifoReset (&p->fifo);
return NULL;
}
if( delta > 0 )
......@@ -559,8 +599,8 @@ aout_buffer_t * aout_OutputNextBuffer( audio_output_t * p_aout,
mtime_t start_date,
bool b_can_sleek )
{
aout_owner_t *owner = aout_owner (p_aout);
aout_fifo_t *p_fifo = &p_aout->fifo;
aout_packet_t *p = aout_packet (p_aout);
aout_fifo_t *p_fifo = &p->fifo;
aout_buffer_t * p_buffer;
mtime_t now = mdate();
......@@ -585,11 +625,11 @@ aout_buffer_t * aout_OutputNextBuffer( audio_output_t * p_aout,
* to deal with this kind of starvation. */
/* Set date to 0, to allow the mixer to send a new buffer ASAP */
aout_FifoReset( &p_aout->fifo );
if ( !p_aout->b_starving )
aout_FifoReset( &p->fifo );
if ( !p->starving )
msg_Dbg( p_aout,
"audio output is starving (no input), playing silence" );
p_aout->b_starving = true;
p_aout->starving = true;
#endif
goto out;
}
......@@ -600,15 +640,15 @@ aout_buffer_t * aout_OutputNextBuffer( audio_output_t * p_aout,
*/
if ( 0 > delta + p_buffer->i_length )
{
if (!owner->b_starving)
if (!p->starving)
msg_Dbg( p_aout, "audio output is starving (%"PRId64"), "
"playing silence", -delta );
owner->b_starving = true;
p->starving = true;
p_buffer = NULL;
goto out;
}
owner->b_starving = false;
p->starving = false;
p_buffer = aout_FifoPop( p_fifo );
if( !b_can_sleek
......@@ -618,7 +658,7 @@ aout_buffer_t * aout_OutputNextBuffer( audio_output_t * p_aout,
msg_Warn( p_aout, "output date isn't PTS date, requesting "
"resampling (%"PRId64")", delta );
aout_FifoMoveDates (&owner->partial, delta);
aout_FifoMoveDates (&p->partial, delta);
aout_FifoMoveDates (p_fifo, delta);
}
out: