]> git.sesse.net Git - vlc/commitdiff
aout: decouple mixer from audio output
authorRémi Denis-Courmont <remi@remlab.net>
Mon, 1 Aug 2011 19:08:37 +0000 (22:08 +0300)
committerRémi Denis-Courmont <remi@remlab.net>
Mon, 1 Aug 2011 19:44:19 +0000 (22:44 +0300)
include/vlc_aout.h
include/vlc_aout_mixer.h
modules/audio_mixer/fixed32.c
modules/audio_mixer/float32.c
modules/audio_mixer/trivial.c
src/audio_output/aout_internal.h
src/audio_output/common.c
src/audio_output/dec.c
src/audio_output/intf.c
src/audio_output/mixer.c

index aec1d4b216fb7da53750d8a1c1a5f5ba2cc6d2d6..7ecbe4262e4e1f5650ea23ccc25908d089e5e7e1 100644 (file)
@@ -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) */
index 5b7c2da8b7b4a052312651cff7271a0e56476255..8ea5dca649f7b161359cd2871094fab90379d9f9 100644 (file)
 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
index 7f3c96b32bec00bcf75be70c72597a73e4d312a7..67f345d840b0d423264a81c95ce5ca997805bd65 100644 (file)
@@ -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;
 
index aa23ee8db12f2e2dd72263d26a53ff51b4a1fe94..2bec603cf12708daa3758af0f5b628d0b29efc83 100644 (file)
@@ -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 )
index 7fb0ea8ae5a4a8ec053503841983afe91ab47546..2619c5aa8b0403df710680cf1520fd0a6316eb46 100644 (file)
@@ -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;
index d18c6bad78b10f0f3f8223e4efc07630f4554bc5..2a48a530466f8319bce4e3cfd7c08113b60f1717 100644 (file)
@@ -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,
index bc82617208a14640e9643e6f574ff7d7aeab52ae..6029d0599544bd81bf1be27eea1225201e4d0571 100644 (file)
@@ -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 );
index ee46b99497dd7ddcbd970f28da52f1d3895f7816..7cf79aa0a611337dcf559b8e5755da757b929049 100644 (file)
@@ -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;
 }
index 375093a39a247d9b972eb070120ecadb990a02f9..3ab3bc69b7f032fa64db456d25725d0d9a8c15c3 100644 (file)
@@ -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 );
index 1a601f9789108162e02bb72c366169b185efb601..d22578083c3274eed7a0a6ba3aa8a44cfb9a3728 100644 (file)
 #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;
 }