src/audio_output/common.c
src/audio_output/dec.c
src/audio_output/filters.c
-src/audio_output/input.c
src/audio_output/output.c
src/config/chain.c
src/config/cmdline.c
audio_output/common.c \
audio_output/dec.c \
audio_output/filters.c \
- audio_output/input.c \
audio_output/output.c \
audio_output/volume.c \
network/getaddrinfo.c \
typedef struct aout_volume aout_volume_t;
-/** an input stream for the audio output */
-struct aout_input_t
-{
- int i_resampling_type;
- int i_resamp_start_drift;
-
- /* */
- int i_buffer_lost;
-};
-
typedef struct
{
vlc_mutex_t lock;
module_t *module; /**< Output plugin (or NULL if inactive) */
- aout_input_t *input;
aout_volume_t *volume;
struct
{
date_t date;
+ int resamp_type;
+ int resamp_start_drift;
} sync;
audio_sample_format_t input_format;
aout_request_vout_t request_vout;
bool recycle_vout;
+ unsigned buffers_lost;
+
vlc_atomic_t restart;
} aout_owner_t;
* Prototypes
*****************************************************************************/
-/* From input.c : */
-aout_input_t *aout_InputNew(void);
-void aout_InputDelete(aout_input_t *);
-block_t *aout_InputPlay( audio_output_t *p_aout, aout_input_t *p_input,
- block_t *p_buffer, int i_input_rate, date_t * );
-
/* From filters.c : */
int aout_FiltersPipelineCreate(vlc_object_t *, filter_t **, unsigned *,
unsigned, const audio_sample_format_t *, const audio_sample_format_t *);
date_Init (&owner->sync.date, owner->mixer_format.i_rate, 1);
date_Set (&owner->sync.date, VLC_TS_INVALID);
+ owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
+
+ owner->buffers_lost = 0;
- assert (owner->input == NULL);
- owner->input = aout_InputNew ();
aout_unlock( p_aout );
return ret;
}
void aout_DecDelete (audio_output_t *p_aout)
{
aout_owner_t *owner = aout_owner (p_aout);
- aout_input_t *input;
aout_lock( p_aout );
- /* Remove the input. */
- input = owner->input;
- aout_InputDelete (input);
- owner->input = NULL;
-
aout_FiltersDelete (p_aout);
aout_OutputDelete( p_aout );
aout_volume_Delete (owner->volume);
#define AOUT_RESTART_OUTPUT 1
#define AOUT_RESTART_INPUT 2
-static void aout_CheckRestart (audio_output_t *aout)
+static int aout_CheckRestart (audio_output_t *aout)
{
aout_owner_t *owner = aout_owner (aout);
int restart = vlc_atomic_swap (&owner->restart, 0);
if (likely(restart == 0))
- return;
+ return 0;
assert (restart & AOUT_RESTART_INPUT);
const aout_request_vout_t request_vout = owner->request_vout;
- aout_InputDelete (owner->input);
- owner->input = NULL;
-
aout_FiltersDelete (aout);
/* Reinitializes the output */
{
aout_OutputDelete (aout);
if (aout_OutputNew (aout, &owner->input_format))
- {
- aout_volume_Delete (owner->volume);
- return; /* we are officially screwed */
- }
+ abort (); /* FIXME we are officially screwed */
aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
}
+ owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
+
if (aout_FiltersNew (aout, &owner->input_format, &owner->mixer_format,
- &request_vout) == 0)
- owner->input = aout_InputNew ();
+ &request_vout))
+ {
+ abort (); /* FIXME */
+ }
+ return 0;
}
/**
block_Release (block);
}
+static void aout_StopResampling (audio_output_t *aout)
+{
+ aout_owner_t *owner = aout_owner (aout);
+
+ owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
+ aout_FiltersAdjustResampling (aout, 0);
+}
+
/*****************************************************************************
* aout_DecPlay : filter & mix the decoded buffer
*****************************************************************************/
-int aout_DecPlay (audio_output_t *p_aout, block_t *p_buffer, int i_input_rate)
+int aout_DecPlay (audio_output_t *aout, block_t *block, int input_rate)
{
- aout_owner_t *owner = aout_owner (p_aout);
- aout_input_t *input;
+ aout_owner_t *owner = aout_owner (aout);
- assert( i_input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE &&
- i_input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE );
- assert( p_buffer->i_pts > 0 );
+ assert (input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE);
+ assert (input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE);
+ assert (block->i_pts >= VLC_TS_0);
- p_buffer->i_length = (mtime_t)p_buffer->i_nb_samples * 1000000
- / owner->input_format.i_rate;
+ block->i_length = CLOCK_FREQ * block->i_nb_samples
+ / owner->input_format.i_rate;
- aout_lock( p_aout );
- aout_CheckRestart( p_aout );
+ aout_lock (aout);
+ if (unlikely(aout_CheckRestart (aout)))
+ goto drop; /* Pipeline is unrecoverably broken :-( */
+
+ /* We don't care if someone changes the start date behind our back after
+ * this. We'll deal with that when pushing the buffer, and compensate
+ * with the next incoming buffer. */
+ mtime_t start_date = date_Get (&owner->sync.date);
+ const mtime_t now = mdate ();
+
+ if (start_date != VLC_TS_INVALID && start_date < now)
+ { /* The decoder is _very_ late. This can only happen if the user
+ * pauses the stream (or if the decoder is buggy, which cannot
+ * happen :). */
+ msg_Warn (aout, "computed PTS is out of range (%"PRId64"), "
+ "clearing out", now - start_date);
+ aout_OutputFlush (aout, false);
+ if (owner->sync.resamp_type != AOUT_RESAMPLING_NONE)
+ msg_Warn (aout, "timing screwed, stopping resampling");
+ aout_StopResampling (aout);
+ block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
+ start_date = VLC_TS_INVALID;
+ }
+
+ if (block->i_pts < now + AOUT_MIN_PREPARE_TIME)
+ { /* The decoder gives us f*cked up PTS. It's its business, but we
+ * can't present it anyway, so drop the buffer. */
+ msg_Warn (aout, "PTS is out of range (%"PRId64"), dropping buffer",
+ now - block->i_pts);
+ aout_StopResampling (aout);
+ goto drop;
+ }
- input = owner->input;
- if (unlikely(input == NULL)) /* can happen due to restart */
+ /* If the audio drift is too big then it's not worth trying to resample
+ * the audio. */
+ if (start_date == VLC_TS_INVALID)
{
- aout_unlock( p_aout );
- block_Release( p_buffer );
- return -1;
+ start_date = block->i_pts;
+ date_Set (&owner->sync.date, start_date);
}
- /* Input */
- p_buffer = aout_InputPlay (p_aout, input, p_buffer, i_input_rate,
- &owner->sync.date);
- if( p_buffer != NULL )
+ mtime_t drift = start_date - block->i_pts;
+ if (drift < -input_rate * 3 * AOUT_MAX_PTS_ADVANCE / INPUT_RATE_DEFAULT)
{
- date_Increment (&owner->sync.date, p_buffer->i_nb_samples);
+ msg_Warn (aout, "buffer way too early (%"PRId64"), clearing queue",
+ drift);
+ aout_OutputFlush (aout, false);
+ if (owner->sync.resamp_type != AOUT_RESAMPLING_NONE)
+ msg_Warn (aout, "timing screwed, stopping resampling");
+ aout_StopResampling (aout);
+ block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
+ start_date = block->i_pts;
+ date_Set (&owner->sync.date, start_date);
+ drift = 0;
+ }
+ else
+ if (drift > +input_rate * 3 * AOUT_MAX_PTS_DELAY / INPUT_RATE_DEFAULT)
+ {
+ msg_Warn (aout, "buffer way too late (%"PRId64"), dropping buffer",
+ drift);
+ goto drop;
+ }
- /* Mixer */
- aout_volume_Amplify (owner->volume, p_buffer);
+ block = aout_FiltersPlay (aout, block, input_rate);
+ if (block == NULL)
+ {
+ owner->buffers_lost++;
+ goto out;
+ }
- /* Output */
- aout_OutputPlay( p_aout, p_buffer );
+ /* Adjust the resampler if needed.
+ * We first need to calculate the output rate of this resampler. */
+ if ((owner->sync.resamp_type == AOUT_RESAMPLING_NONE)
+ && (drift < -AOUT_MAX_PTS_ADVANCE || drift > +AOUT_MAX_PTS_DELAY))
+ { /* Can happen in several circumstances :
+ * 1. A problem at the input (clock drift)
+ * 2. A small pause triggered by the user
+ * 3. Some delay in the output stage, causing a loss of lip
+ * synchronization
+ * Solution : resample the buffer to avoid a scratch.
+ */
+ owner->sync.resamp_start_drift = (int)-drift;
+ owner->sync.resamp_type = (drift < 0) ? AOUT_RESAMPLING_DOWN
+ : AOUT_RESAMPLING_UP;
+ msg_Warn (aout, (drift < 0)
+ ? "buffer too early (%"PRId64"), down-sampling"
+ : "buffer too late (%"PRId64"), up-sampling", drift);
+ }
+ if (owner->sync.resamp_type != AOUT_RESAMPLING_NONE)
+ { /* Resampling has been triggered previously (because of dates
+ * mismatch). We want the resampling to happen progressively so
+ * it isn't too audible to the listener. */
+ const int adjust = (owner->sync.resamp_type == AOUT_RESAMPLING_UP)
+ ? +2 : -2;
+ /* Check if everything is back to normal, then stop resampling. */
+ if (!aout_FiltersAdjustResampling (aout, adjust))
+ {
+ owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
+ msg_Warn (aout, "resampling stopped (drift: %"PRIi64")",
+ block->i_pts - start_date);
+ }
+ else if (abs ((int)(block->i_pts - start_date))
+ < abs (owner->sync.resamp_start_drift) / 2)
+ { /* If we reduced the drift from half, then it is time to switch
+ * back the resampling direction. */
+ if (owner->sync.resamp_type == AOUT_RESAMPLING_UP)
+ owner->sync.resamp_type = AOUT_RESAMPLING_DOWN;
+ else
+ owner->sync.resamp_type = AOUT_RESAMPLING_UP;
+ owner->sync.resamp_start_drift = 0;
+ }
+ else if (owner->sync.resamp_start_drift
+ && (abs ((int)(block->i_pts - start_date))
+ > abs (owner->sync.resamp_start_drift) * 3 / 2))
+ { /* If the drift is increasing and not decreasing, than something
+ * is bad. We'd better stop the resampling right now. */
+ msg_Warn (aout, "timing screwed, stopping resampling");
+ aout_StopResampling (aout);
+ block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
+ }
}
- aout_unlock( p_aout );
+ block->i_pts = start_date;
+ date_Increment (&owner->sync.date, block->i_nb_samples);
+
+ /* Software volume */
+ aout_volume_Amplify (owner->volume, block);
+
+ /* Output */
+ aout_OutputPlay (aout, block);
+out:
+ aout_unlock (aout);
return 0;
+drop:
+ block_Release (block);
+ owner->buffers_lost++;
+ goto out;
}
int aout_DecGetResetLost (audio_output_t *aout)
{
aout_owner_t *owner = aout_owner (aout);
- aout_input_t *input = owner->input;
- int val;
+ unsigned val;
aout_lock (aout);
- if (likely(input != NULL))
- {
- val = input->i_buffer_lost;
- input->i_buffer_lost = 0;
- }
- else
- val = 0; /* if aout_CheckRestart() failed */
+ val = owner->buffers_lost;
+ owner->buffers_lost = 0;
aout_unlock (aout);
return val;
+++ /dev/null
-/*****************************************************************************
- * input.c : internal management of input streams for the audio output
- *****************************************************************************
- * Copyright (C) 2002-2007 VLC authors and VideoLAN
- * $Id$
- *
- * Authors: Christophe Massiot <massiot@via.ecp.fr>
- *
- * 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.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
- *****************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <vlc_common.h>
-#include <vlc_input.h>
-#include <vlc_aout.h>
-
-#include <libvlc.h>
-#include "aout_internal.h"
-
-static void inputDrop( aout_input_t *, block_t * );
-static void inputResamplingStop( audio_output_t *, aout_input_t * );
-
-/*****************************************************************************
- * aout_InputNew : allocate a new input and rework the filter pipeline
- *****************************************************************************/
-aout_input_t *aout_InputNew (void)
-{
- aout_input_t *p_input = xmalloc (sizeof (*p_input));
-
- p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
- p_input->i_buffer_lost = 0;
- return p_input;
-}
-
-/*****************************************************************************
- * aout_InputDelete : delete an input
- *****************************************************************************
- * This function must be entered with the mixer lock.
- *****************************************************************************/
-void aout_InputDelete (aout_input_t * p_input )
-{
- free (p_input);
-}
-
-/*****************************************************************************
- * aout_InputPlay : play a buffer
- *****************************************************************************
- * This function must be entered with the input lock.
- *****************************************************************************/
-block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
- block_t *p_buffer, int i_input_rate, date_t *date )
-{
- mtime_t start_date;
-
- aout_assert_locked( p_aout );
-
- mtime_t now = mdate();
-
- /* We don't care if someone changes the start date behind our back after
- * this. We'll deal with that when pushing the buffer, and compensate
- * with the next incoming buffer. */
- start_date = date_Get (date);
-
- if ( start_date != VLC_TS_INVALID && start_date < now )
- {
- /* The decoder is _very_ late. This can only happen if the user
- * pauses the stream (or if the decoder is buggy, which cannot
- * happen :). */
- msg_Warn( p_aout, "computed PTS is out of range (%"PRId64"), "
- "clearing out", now - start_date );
- aout_OutputFlush( p_aout, false );
- if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
- msg_Warn( p_aout, "timing screwed, stopping resampling" );
- inputResamplingStop( p_aout, p_input );
- p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
- start_date = VLC_TS_INVALID;
- }
-
- if ( p_buffer->i_pts < now + AOUT_MIN_PREPARE_TIME )
- {
- /* The decoder gives us f*cked up PTS. It's its business, but we
- * can't present it anyway, so drop the buffer. */
- msg_Warn( p_aout, "PTS is out of range (%"PRId64"), dropping buffer",
- now - p_buffer->i_pts );
- inputDrop( p_input, p_buffer );
- inputResamplingStop( p_aout, p_input );
- return NULL;
- }
-
- /* If the audio drift is too big then it's not worth trying to resample
- * the audio. */
- if( start_date == VLC_TS_INVALID )
- {
- start_date = p_buffer->i_pts;
- date_Set (date, start_date);
- }
-
- mtime_t drift = start_date - p_buffer->i_pts;
-
- if( drift < -i_input_rate * 3 * AOUT_MAX_PTS_ADVANCE / INPUT_RATE_DEFAULT )
- {
- msg_Warn( p_aout, "buffer way too early (%"PRId64"), clearing queue",
- drift );
- aout_OutputFlush( p_aout, false );
- if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
- msg_Warn( p_aout, "timing screwed, stopping resampling" );
- inputResamplingStop( p_aout, p_input );
- p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
- start_date = p_buffer->i_pts;
- date_Set (date, start_date);
- drift = 0;
- }
- else
- if( drift > +i_input_rate * 3 * AOUT_MAX_PTS_DELAY / INPUT_RATE_DEFAULT )
- {
- msg_Warn( p_aout, "buffer way too late (%"PRId64"), dropping buffer",
- drift );
- inputDrop( p_input, p_buffer );
- return NULL;
- }
-
- p_buffer = aout_FiltersPlay( p_aout, p_buffer, i_input_rate );
- if( !p_buffer )
- return NULL;
-
- /* Run the resampler if needed.
- * We first need to calculate the output rate of this resampler. */
- if ( ( p_input->i_resampling_type == AOUT_RESAMPLING_NONE ) &&
- ( drift < -AOUT_MAX_PTS_ADVANCE || drift > +AOUT_MAX_PTS_DELAY ) )
- {
- /* Can happen in several circumstances :
- * 1. A problem at the input (clock drift)
- * 2. A small pause triggered by the user
- * 3. Some delay in the output stage, causing a loss of lip
- * synchronization
- * Solution : resample the buffer to avoid a scratch.
- */
- p_input->i_resamp_start_drift = (int)-drift;
- p_input->i_resampling_type = (drift < 0) ? AOUT_RESAMPLING_DOWN
- : AOUT_RESAMPLING_UP;
- msg_Warn( p_aout, (drift < 0)
- ? "buffer too early (%"PRId64"), down-sampling"
- : "buffer too late (%"PRId64"), up-sampling", drift );
- }
-
- if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
- {
- /* Resampling has been triggered previously (because of dates
- * mismatch). We want the resampling to happen progressively so
- * it isn't too audible to the listener. */
- const int adjust = ( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
- ? +2 : -2;
-
- /* Check if everything is back to normal, in which case we can stop the
- * resampling */
- if( !aout_FiltersAdjustResampling( p_aout, adjust ) )
- {
- p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
- msg_Warn( p_aout, "resampling stopped (drift: %"PRIi64")",
- p_buffer->i_pts - start_date);
- }
- else if( abs( (int)(p_buffer->i_pts - start_date) ) <
- abs( p_input->i_resamp_start_drift ) / 2 )
- {
- /* if we reduced the drift from half, then it is time to switch
- * back the resampling direction. */
- if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
- p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
- else
- p_input->i_resampling_type = AOUT_RESAMPLING_UP;
- p_input->i_resamp_start_drift = 0;
- }
- else if( p_input->i_resamp_start_drift &&
- ( abs( (int)(p_buffer->i_pts - start_date) ) >
- abs( p_input->i_resamp_start_drift ) * 3 / 2 ) )
- {
- /* If the drift is increasing and not decreasing, than something
- * is bad. We'd better stop the resampling right now. */
- msg_Warn( p_aout, "timing screwed, stopping resampling" );
- inputResamplingStop( p_aout, p_input );
- p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
- }
- }
-
- p_buffer->i_pts = start_date;
- return p_buffer;
-}
-
-/*****************************************************************************
- * static functions
- *****************************************************************************/
-
-static void inputDrop( aout_input_t *p_input, block_t *p_buffer )
-{
- block_Release( p_buffer );
-
- p_input->i_buffer_lost++;
-}
-
-static void inputResamplingStop( audio_output_t *p_aout, aout_input_t *p_input )
-{
- p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
- aout_FiltersAdjustResampling( p_aout, 0 );
-}
vlc_mutex_init (&owner->lock);
vlc_object_set_destructor (aout, aout_Destructor);
- owner->input = NULL;
-
/* Audio output module callbacks */
var_Create (aout, "volume", VLC_VAR_FLOAT);
var_AddCallback (aout, "volume", var_Copy, parent);