/* 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>
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
/* */
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 */
}
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;
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 );
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);
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
*****************************************************************************/
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 );
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
*****************************************************************************/
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 */
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 */
*****************************************************************************/
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;
}
/*****************************************************************************
{
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 );
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 */
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
*****************************************************************************/
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 )
{
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
*****************************************************************************/
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" );
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
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
*****************************************************************************/
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;
} else {
SetEvent( _p_aout->sys->new_buffer_event );
}
+
+ aout_PacketPlay( _p_aout, block );
}
/*****************************************************************************
#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,
/*****************************************************************************
* Local prototypes.
*****************************************************************************/
-static void Play ( audio_output_t * );
+static void Play( audio_output_t *, block_t * );
/*****************************************************************************
* OpenAudio: open a dummy audio device
/*****************************************************************************
* 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;
}
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
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;
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);
}
/**
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);
- }
}
/**
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);
}
}
-/*** 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. */
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. */
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 )
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();
* 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;
}
*/
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
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:
aout_FormatPrint
aout_FormatPrintChannels
aout_OutputNextBuffer
+aout_PacketPlay
+aout_PacketPause
+aout_PacketFlush
aout_VolumeGet
aout_VolumeSet
aout_VolumeUp