Commit 1f62c264 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

aout: decouple mixer from audio output

parent 87009e4b
......@@ -183,7 +183,7 @@ struct audio_output
/* Mixer */
audio_sample_format_t mixer_format;
float mixer_multiplier;
struct aout_mixer_t *p_mixer;
struct audio_mixer *mixer;
audio_sample_format_t format; /**< Output format (plugin can modify it
only when succesfully probed and not afterward) */
......
......@@ -34,37 +34,18 @@
extern "C" {
#endif
//#include <vlc_aout.h>
/* */
typedef struct aout_mixer_sys_t aout_mixer_sys_t;
typedef struct aout_mixer_t aout_mixer_t;
typedef struct audio_mixer audio_mixer_t;
/**
* audio output mixer
*/
struct aout_mixer_t {
struct audio_mixer
{
VLC_COMMON_MEMBERS
/* Module */
module_t *module;
/* Mixer format.
*
* You cannot modify it.
*/
audio_sample_format_t fmt;
aout_fifo_t *fifo;
/* Mix buffer (mandatory) */
void (*mix)(aout_mixer_t *, aout_buffer_t *, float);
/* Private place holder for the aout_mixer_t module (optional)
*
* A module is free to use it as it wishes.
*/
aout_mixer_sys_t *sys;
module_t *module; /**< Module handle */
const audio_sample_format_t *fmt; /**< Audio format */
void (*mix)(audio_mixer_t *, block_t *, float); /**< Amplifier */
};
#ifdef __cplusplus
......
......@@ -37,14 +37,14 @@ vlc_module_begin ()
set_callbacks (Activate, NULL)
vlc_module_end ()
static void FilterFI32 (aout_mixer_t *, block_t *, float);
static void FilterS16N (aout_mixer_t *, block_t *, float);
static void FilterFI32 (audio_mixer_t *, block_t *, float);
static void FilterS16N (audio_mixer_t *, block_t *, float);
static int Activate (vlc_object_t *obj)
{
aout_mixer_t *mixer = (aout_mixer_t *)obj;
audio_mixer_t *mixer = (audio_mixer_t *)obj;
switch (mixer->fmt.i_format)
switch (mixer->fmt->i_format)
{
case VLC_CODEC_FI32:
mixer->mix = FilterFI32;
......@@ -58,7 +58,7 @@ static int Activate (vlc_object_t *obj)
return 0;
}
static void FilterFI32 (aout_mixer_t *mixer, block_t *block, float volume)
static void FilterFI32 (audio_mixer_t *mixer, block_t *block, float volume)
{
const int64_t mult = volume * FIXED32_ONE;
......@@ -76,7 +76,7 @@ static void FilterFI32 (aout_mixer_t *mixer, block_t *block, float volume)
(void) mixer;
}
static void FilterS16N (aout_mixer_t *mixer, block_t *block, float volume)
static void FilterS16N (audio_mixer_t *mixer, block_t *block, float volume)
{
const int32_t mult = volume * 0x10000;
......
......@@ -39,7 +39,7 @@
* Local prototypes
*****************************************************************************/
static int Create( vlc_object_t * );
static void DoWork( aout_mixer_t *, aout_buffer_t *, float );
static void DoWork( audio_mixer_t *, aout_buffer_t *, float );
/*****************************************************************************
* Module descriptor
......@@ -57,9 +57,9 @@ vlc_module_end ()
*/
static int Create( vlc_object_t *p_this )
{
aout_mixer_t * p_mixer = (aout_mixer_t *)p_this;
audio_mixer_t *p_mixer = (audio_mixer_t *)p_this;
if ( p_mixer->fmt.i_format != VLC_CODEC_FL32 )
if ( p_mixer->fmt->i_format != VLC_CODEC_FL32 )
return -1;
p_mixer->mix = DoWork;
......@@ -69,7 +69,7 @@ static int Create( vlc_object_t *p_this )
/**
* Mixes a new output buffer
*/
static void DoWork( aout_mixer_t * p_mixer, aout_buffer_t *p_buffer,
static void DoWork( audio_mixer_t * p_mixer, aout_buffer_t *p_buffer,
float f_multiplier )
{
if( f_multiplier == 1.0 )
......
......@@ -38,7 +38,7 @@
* Local prototypes
*****************************************************************************/
static int Create( vlc_object_t * );
static void DoNothing( aout_mixer_t *, aout_buffer_t *p_buffer, float );
static void DoNothing( audio_mixer_t *, aout_buffer_t *p_buffer, float );
/*****************************************************************************
* Module descriptor
......@@ -56,13 +56,13 @@ vlc_module_end ()
*****************************************************************************/
static int Create( vlc_object_t *p_this )
{
aout_mixer_t *p_mixer = (aout_mixer_t *)p_this;
audio_mixer_t *p_mixer = (audio_mixer_t *)p_this;
p_mixer->mix = DoNothing;
return 0;
}
static void DoNothing( aout_mixer_t *p_mixer, aout_buffer_t *p_buffer,
static void DoNothing( audio_mixer_t *p_mixer, aout_buffer_t *p_buffer,
float multiplier )
{
(void) p_mixer;
......
......@@ -114,9 +114,12 @@ void aout_FiltersDestroyPipeline( filter_t *const *, unsigned );
void aout_FiltersPlay( filter_t *const *, unsigned, aout_buffer_t ** );
/* From mixer.c : */
int aout_MixerNew( audio_output_t * p_aout );
void aout_MixerDelete( audio_output_t * p_aout );
void aout_MixerRun( audio_output_t * p_aout, float );
audio_mixer_t *aout_MixerNew(vlc_object_t *, const audio_sample_format_t * );
#define aout_MixerNew(o, f) aout_MixerNew(VLC_OBJECT(o), f)
void aout_MixerDelete(audio_mixer_t *);
void aout_MixerRun(audio_mixer_t *, block_t *, float);
block_t *aout_OutputSlice( audio_output_t *, aout_fifo_t * );
/* From output.c : */
int aout_OutputNew( audio_output_t * p_aout,
......
......@@ -63,7 +63,7 @@ audio_output_t *aout_New( vlc_object_t * p_parent )
vlc_mutex_init( &p_aout->lock );
p_aout->p_input = NULL;
p_aout->mixer_multiplier = 1.0;
p_aout->p_mixer = NULL;
p_aout->mixer = NULL;
p_aout->b_starving = true;
p_aout->module = NULL;
aout_VolumeNoneInit( p_aout );
......
......@@ -106,8 +106,9 @@ aout_input_t *aout_DecNew( audio_output_t *p_aout,
#warning Input without output and mixer = bad idea.
goto out;
assert( p_aout->p_mixer == NULL );
if( aout_MixerNew( p_aout ) == -1 )
assert( p_aout->mixer == NULL );
p_aout->mixer = aout_MixerNew( p_aout, &p_aout->mixer_format );
if( p_aout->mixer == NULL )
{
aout_OutputDelete( p_aout );
#warning Memory leak.
......@@ -133,7 +134,8 @@ void aout_DecDelete( audio_output_t * p_aout, aout_input_t * p_input )
aout_InputDelete( p_aout, p_input );
aout_OutputDelete( p_aout );
aout_MixerDelete( p_aout );
aout_MixerDelete( p_aout->mixer );
p_aout->mixer = NULL;
var_Destroy( p_aout, "audio-device" );
var_Destroy( p_aout, "audio-channels" );
......@@ -181,7 +183,6 @@ int aout_DecPlay( audio_output_t * p_aout, aout_input_t * p_input,
{
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 );
p_buffer->i_length = (mtime_t)p_buffer->i_nb_samples * 1000000
......@@ -197,8 +198,13 @@ int aout_DecPlay( audio_output_t * p_aout, aout_input_t * p_input,
aout_InputCheckAndRestart( p_aout, p_input );
aout_InputPlay( p_aout, p_input, p_buffer, i_input_rate );
/* Run the mixer if it is able to run. */
aout_MixerRun( p_aout, p_aout->mixer_multiplier * p_input->multiplier );
const float amp = p_aout->mixer_multiplier * p_input->multiplier;
while( (p_buffer = aout_OutputSlice( p_aout, &p_input->fifo ) ) != NULL )
{
aout_MixerRun( p_aout->mixer, p_buffer, amp );
aout_OutputPlay( p_aout, p_buffer );
}
aout_unlock( p_aout );
return 0;
}
......
......@@ -90,7 +90,7 @@ static int commitVolume (vlc_object_t *obj, audio_output_t *aout,
aout_lock (aout);
#warning FIXME: wrong test. Need to check that aout_output is ready.
if (aout->p_mixer != NULL)
if (aout->mixer != NULL)
ret = aout->pf_volume_set (aout, vol, mute);
aout_unlock (aout);
......@@ -256,7 +256,8 @@ static int aout_Restart( audio_output_t * p_aout )
/* Reinitializes the output */
aout_InputDelete( p_aout, p_input );
aout_MixerDelete( p_aout );
aout_MixerDelete( p_aout->mixer );
p_aout->mixer = NULL;
aout_OutputDelete( p_aout );
/* FIXME: This function is notoriously dangerous/unsafe.
......@@ -268,7 +269,8 @@ static int aout_Restart( audio_output_t * p_aout )
return -1;
}
if ( aout_MixerNew( p_aout ) == -1 )
p_aout->mixer = aout_MixerNew( p_aout, &p_aout->mixer_format );
if( p_aout->mixer == NULL )
{
aout_OutputDelete( p_aout );
aout_unlock( p_aout );
......
......@@ -33,68 +33,61 @@
#include <vlc_common.h>
#include <libvlc.h>
#include <vlc_modules.h>
#include <vlc_aout.h>
#include <vlc_aout_mixer.h>
#include "aout_internal.h"
/*****************************************************************************
* aout_MixerNew: prepare a mixer plug-in
*****************************************************************************
* Please note that you must hold the mixer lock.
*****************************************************************************/
int aout_MixerNew( audio_output_t * p_aout )
{
assert( !p_aout->p_mixer );
vlc_assert_locked( &p_aout->lock );
aout_mixer_t *p_mixer = vlc_custom_create( p_aout, sizeof(*p_mixer),
"audio mixer" );
if( !p_mixer )
return VLC_EGENERIC;
p_mixer->fmt = p_aout->mixer_format;
p_mixer->fifo = &p_aout->p_input->fifo;
p_mixer->mix = NULL;
p_mixer->sys = NULL;
p_mixer->module = module_need( p_mixer, "audio mixer", NULL, false );
if( !p_mixer->module )
#undef aout_MixerNew
/**
* Creates a software amplifier.
*/
audio_mixer_t *aout_MixerNew(vlc_object_t *obj,
const audio_sample_format_t *fmt)
{
audio_mixer_t *mixer = vlc_custom_create(obj, sizeof (*mixer), "mixer");
if (unlikely(mixer == NULL))
return NULL;
mixer->fmt = fmt;
mixer->mix = NULL;
mixer->module = module_need(mixer, "audio mixer", NULL, false);
if (mixer->module == NULL)
{
msg_Err( p_mixer, "no suitable audio mixer" );
vlc_object_release( p_mixer );
return VLC_EGENERIC;
msg_Err(mixer, "no suitable audio mixer");
vlc_object_release(mixer);
mixer = NULL;
}
/* */
p_aout->p_mixer = p_mixer;
return VLC_SUCCESS;
return mixer;
}
/*****************************************************************************
* aout_MixerDelete: delete the mixer
*****************************************************************************
* Please note that you must hold the mixer lock.
*****************************************************************************/
void aout_MixerDelete( audio_output_t * p_aout )
/**
* Destroys a software amplifier.
*/
void aout_MixerDelete(audio_mixer_t *mixer)
{
vlc_assert_locked( &p_aout->lock );
if( !p_aout->p_mixer )
if (mixer == NULL)
return;
module_unneed( p_aout->p_mixer, p_aout->p_mixer->module );
vlc_object_release( p_aout->p_mixer );
p_aout->p_mixer = NULL;
module_unneed(mixer, mixer->module);
vlc_object_release(mixer);
}
/*****************************************************************************
* MixBuffer: try to prepare one output buffer
*****************************************************************************
* Please note that you must hold the mixer lock.
*****************************************************************************/
static int MixBuffer( audio_output_t * p_aout, float volume )
/**
* Applies replay gain and software volume to an audio buffer.
*/
void aout_MixerRun(audio_mixer_t *mixer, block_t *block, float amp)
{
mixer->mix(mixer, block, amp);
}
/**
* 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.
*/
block_t *aout_OutputSlice( audio_output_t * p_aout, aout_fifo_t *p_fifo )
{
aout_mixer_t *p_mixer = p_aout->p_mixer;
aout_fifo_t *p_fifo = p_mixer->fifo;
const unsigned samples = p_aout->i_nb_samples;
/* FIXME: Remove this silly constraint. Just pass buffers as they come to
* "smart" audio outputs. */
......@@ -109,7 +102,7 @@ static int MixBuffer( audio_output_t * p_aout, float volume )
/* See if we have enough data to prepare a new buffer for the audio output. */
aout_buffer_t *p_buffer = p_fifo->p_first;
if( p_buffer == NULL )
return -1;
return NULL;
/* Find the earliest start date available. */
if ( start_date == VLC_TS_INVALID )
......@@ -130,13 +123,13 @@ static int MixBuffer( audio_output_t * p_aout, float volume )
break;
/* We authorize a +-1 because rounding errors get compensated
* regularly. */
msg_Warn( p_mixer, "got a packet in the past (%"PRId64")",
msg_Warn( p_aout, "got a packet in the past (%"PRId64")",
start_date - prev_date );
aout_BufferFree( aout_FifoPop( p_fifo ) );
p_buffer = p_fifo->p_first;
if( p_buffer == NULL )
return -1;
return NULL;
}
/* Check that we have enough samples. */
......@@ -144,12 +137,12 @@ static int MixBuffer( audio_output_t * p_aout, float volume )
{
p_buffer = p_buffer->p_next;
if( p_buffer == NULL )
return -1;
return NULL;
/* Check that all buffers are contiguous. */
if( prev_date != p_buffer->i_pts )
{
msg_Warn( p_mixer,
msg_Warn( p_aout,
"buffer hole, dropping packets (%"PRId64")",
p_buffer->i_pts - prev_date );
......@@ -161,27 +154,28 @@ static int MixBuffer( audio_output_t * p_aout, float volume )
prev_date = p_buffer->i_pts + p_buffer->i_length;
}
if( !AOUT_FMT_NON_LINEAR( &p_mixer->fmt ) )
if( !AOUT_FMT_NON_LINEAR( &p_aout->mixer_format ) )
{
p_buffer = p_fifo->p_first;
/* Additionally check that p_first_byte_to_mix is well located. */
const unsigned framesize = p_mixer->fmt.i_bytes_per_frame;
const unsigned framesize = p_aout->mixer_format.i_bytes_per_frame;
ssize_t delta = (start_date - p_buffer->i_pts)
* p_mixer->fmt.i_rate / CLOCK_FREQ;
* p_aout->mixer_format.i_rate / CLOCK_FREQ;
if( delta != 0 )
msg_Warn( p_mixer, "input start is not output end (%zd)", delta );
msg_Warn( p_aout, "input start is not output end (%zd)", delta );
if( delta < 0 )
{
/* Is it really the best way to do it ? */
aout_FifoReset( &p_aout->fifo );
return -1;
return NULL;
}
if( delta > 0 )
{
mtime_t t = delta * CLOCK_FREQ / p_aout->mixer_format.i_rate;
p_buffer->i_nb_samples -= delta;
p_buffer->i_pts += delta * CLOCK_FREQ / p_mixer->fmt.i_rate;
p_buffer->i_length -= delta * CLOCK_FREQ / p_mixer->fmt.i_rate;
p_buffer->i_pts += t;
p_buffer->i_length -= t;
delta *= framesize;
p_buffer->p_buffer += delta;
p_buffer->i_buffer -= delta;
......@@ -192,7 +186,7 @@ static int MixBuffer( audio_output_t * p_aout, float volume )
p_buffer = block_Alloc( needed );
if( unlikely(p_buffer == NULL) )
/* XXX: should free input buffers */
return -1;
return NULL;
p_buffer->i_nb_samples = samples;
for( uint8_t *p_out = p_buffer->p_buffer; needed > 0; )
......@@ -200,7 +194,7 @@ static int MixBuffer( audio_output_t * p_aout, float volume )
aout_buffer_t *p_inbuf = p_fifo->p_first;
if( unlikely(p_inbuf == NULL) )
{
msg_Err( p_mixer, "internal error" );
msg_Err( p_aout, "packetization error" );
vlc_memset( p_out, 0, needed );
break;
}
......@@ -214,8 +208,10 @@ static int MixBuffer( audio_output_t * p_aout, float volume )
p_fifo->p_first->i_buffer -= needed;
needed /= framesize;
p_fifo->p_first->i_nb_samples -= needed;
p_fifo->p_first->i_pts += needed * CLOCK_FREQ / p_mixer->fmt.i_rate;
p_fifo->p_first->i_length -= needed * CLOCK_FREQ / p_mixer->fmt.i_rate;
mtime_t t = needed * CLOCK_FREQ / p_aout->mixer_format.i_rate;
p_fifo->p_first->i_pts += t;
p_fifo->p_first->i_length -= t;
break;
}
......@@ -232,18 +228,5 @@ static int MixBuffer( audio_output_t * p_aout, float volume )
p_buffer->i_pts = start_date;
p_buffer->i_length = end_date - start_date;
/* Run the mixer. */
p_mixer->mix( p_mixer, p_buffer, volume );
aout_OutputPlay( p_aout, p_buffer );
return 0;
}
/*****************************************************************************
* aout_MixerRun: entry point for the mixer & post-filters processing
*****************************************************************************
* Please note that you must hold the mixer lock.
*****************************************************************************/
void aout_MixerRun( audio_output_t * p_aout, float volume )
{
while( MixBuffer( p_aout, volume ) != -1 );
return p_buffer;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment