]> git.sesse.net Git - vlc/blobdiff - src/audio_output/dec.c
aout: add wait parameter to aout_DecFlush()
[vlc] / src / audio_output / dec.c
index 2ec340a33588d3f0f842269438f6547201039cd5..74440728958b99b98bfa0e09b5e0cd51c1455be4 100644 (file)
@@ -33,7 +33,6 @@
 #include <vlc_common.h>
 #include <vlc_aout.h>
 #include <vlc_input.h>
-#include <vlc_atomic.h>
 
 #include "aout_internal.h"
 #include "libvlc.h"
@@ -53,7 +52,7 @@ int aout_DecNew( audio_output_t *p_aout,
         return -1;
     }
 
-    if( p_format->i_rate > 192000 )
+    if( p_format->i_rate > 352800 )
     {
         msg_Err( p_aout, "excessive audio sample frequency (%u)",
                  p_format->i_rate );
@@ -69,36 +68,38 @@ int aout_DecNew( audio_output_t *p_aout,
     aout_owner_t *owner = aout_owner(p_aout);
 
     /* TODO: reduce lock scope depending on decoder's real need */
-    aout_lock( p_aout );
+    aout_OutputLock (p_aout);
 
     var_Destroy( p_aout, "stereo-mode" );
 
     /* Create the audio output stream */
     owner->volume = aout_volume_New (p_aout, p_replay_gain);
 
-    vlc_atomic_set (&owner->restart, 0);
+    atomic_store (&owner->restart, 0);
     owner->input_format = *p_format;
     owner->mixer_format = owner->input_format;
+    owner->request_vout = *p_request_vout;
 
     if (aout_OutputNew (p_aout, &owner->mixer_format))
         goto error;
     aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
 
     /* Create the audio filtering "input" pipeline */
-    if (aout_FiltersNew (p_aout, p_format, &owner->mixer_format,
-                         p_request_vout))
+    owner->filters = aout_FiltersNew (p_aout, p_format, &owner->mixer_format,
+                                      &owner->request_vout);
+    if (owner->filters == NULL)
     {
         aout_OutputDelete (p_aout);
 error:
         aout_volume_Delete (owner->volume);
-        aout_unlock (p_aout);
+        aout_OutputUnlock (p_aout);
         return -1;
     }
 
     owner->sync.end = VLC_TS_INVALID;
     owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
     owner->sync.discontinuity = true;
-    aout_unlock( p_aout );
+    aout_OutputUnlock (p_aout);
 
     atomic_init (&owner->buffers_lost, 0);
     return 0;
@@ -107,137 +108,86 @@ error:
 /**
  * Stops all plugins involved in the audio output.
  */
-void aout_DecDelete (audio_output_t *p_aout)
-{
-    aout_owner_t *owner = aout_owner (p_aout);
-
-    aout_lock( p_aout );
-    aout_FiltersDelete (p_aout);
-    aout_OutputDelete( p_aout );
-    aout_volume_Delete (owner->volume);
-
-    var_Destroy( p_aout, "stereo-mode" );
-
-    aout_unlock( p_aout );
-}
-
-#define AOUT_RESTART_OUTPUT 1
-#define AOUT_RESTART_INPUT  2
-static int aout_CheckRestart (audio_output_t *aout)
+void aout_DecDelete (audio_output_t *aout)
 {
     aout_owner_t *owner = aout_owner (aout);
 
-    aout_assert_locked (aout);
-
-    int restart = vlc_atomic_swap (&owner->restart, 0);
-    if (likely(restart == 0))
-        return 0;
-
-    assert (restart & AOUT_RESTART_INPUT);
-
-    const aout_request_vout_t request_vout = owner->request_vout;
-
-    aout_FiltersDelete (aout);
-
-    /* Reinitializes the output */
-    if (restart & AOUT_RESTART_OUTPUT)
+    aout_OutputLock (aout);
+    if (owner->mixer_format.i_format)
     {
+        aout_FiltersDelete (aout, owner->filters);
         aout_OutputDelete (aout);
-        owner->mixer_format = owner->input_format;
-        if (aout_OutputNew (aout, &owner->mixer_format))
-            abort (); /* FIXME we are officially screwed */
-        aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
     }
-
-    owner->sync.end = VLC_TS_INVALID;
-    owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
-
-    if (aout_FiltersNew (aout, &owner->input_format, &owner->mixer_format,
-                         &request_vout))
-    {
-        abort (); /* FIXME */
-    }
-    return 0;
+    aout_volume_Delete (owner->volume);
+    aout_OutputUnlock (aout);
+    var_Destroy (aout, "stereo-mode");
 }
 
-/**
- * Marks the audio output for restart, to update any parameter of the output
- * plug-in (e.g. output device or channel mapping).
- */
-static void aout_RequestRestart (audio_output_t *aout)
+static int aout_CheckReady (audio_output_t *aout)
 {
     aout_owner_t *owner = aout_owner (aout);
 
-    /* DO NOT remove AOUT_RESTART_INPUT. You need to change the atomic ops. */
-    vlc_atomic_set (&owner->restart, AOUT_RESTART_OUTPUT|AOUT_RESTART_INPUT);
-}
-
-int aout_ChannelsRestart (vlc_object_t *obj, const char *varname,
-                          vlc_value_t oldval, vlc_value_t newval, void *data)
-{
-    audio_output_t *aout = (audio_output_t *)obj;
-    (void)oldval; (void)newval; (void)data;
-
-    if (!strcmp (varname, "audio-device"))
+    int restart = atomic_exchange (&owner->restart, 0);
+    if (unlikely(restart))
     {
-        /* This is supposed to be a significant change and supposes
-         * rebuilding the channel choices. */
-        var_Destroy (aout, "stereo-mode");
+        if (owner->mixer_format.i_format)
+            aout_FiltersDelete (aout, owner->filters);
+
+        if (restart & AOUT_RESTART_OUTPUT)
+        {   /* Reinitializes the output */
+            msg_Dbg (aout, "restarting output...");
+            if (owner->mixer_format.i_format)
+                aout_OutputDelete (aout);
+            owner->mixer_format = owner->input_format;
+            if (aout_OutputNew (aout, &owner->mixer_format))
+                owner->mixer_format.i_format = 0;
+            aout_volume_SetFormat (owner->volume,
+                                   owner->mixer_format.i_format);
+        }
+
+        msg_Dbg (aout, "restarting filters...");
+        owner->sync.end = VLC_TS_INVALID;
+        owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
+
+        if (owner->mixer_format.i_format)
+        {
+            owner->filters = aout_FiltersNew (aout, &owner->input_format,
+                                              &owner->mixer_format,
+                                              &owner->request_vout);
+            if (owner->filters == NULL)
+            {
+                aout_OutputDelete (aout);
+                owner->mixer_format.i_format = 0;
+            }
+        }
+        /* TODO: This would be a good time to call clean up any video output
+         * left over by an audio visualization:
+        input_resource_TerminatVout(MAGIC HERE); */
     }
-    aout_RequestRestart (aout);
-    return 0;
+    return (owner->mixer_format.i_format) ? 0 : -1;
 }
 
 /**
- * This function will safely mark aout input to be restarted as soon as
- * possible to take configuration changes into account
+ * Marks the audio output for restart, to update any parameter of the output
+ * plug-in (e.g. output device or channel mapping).
  */
-void aout_InputRequestRestart (audio_output_t *aout)
+void aout_RequestRestart (audio_output_t *aout, unsigned mode)
 {
     aout_owner_t *owner = aout_owner (aout);
-
-    vlc_atomic_compare_swap (&owner->restart, 0, AOUT_RESTART_INPUT);
+    atomic_fetch_or (&owner->restart, mode);
+    msg_Dbg (aout, "restart requested (%u)", mode);
 }
 
-
 /*
  * Buffer management
  */
 
-/*****************************************************************************
- * aout_DecNewBuffer : ask for a new empty buffer
- *****************************************************************************/
-block_t *aout_DecNewBuffer (audio_output_t *aout, size_t samples)
-{
-    /* NOTE: the caller is responsible for serializing input change */
-    aout_owner_t *owner = aout_owner (aout);
-
-    size_t length = samples * owner->input_format.i_bytes_per_frame
-                            / owner->input_format.i_frame_length;
-    block_t *block = block_Alloc( length );
-    if( likely(block != NULL) )
-    {
-        block->i_nb_samples = samples;
-        block->i_pts = block->i_length = 0;
-    }
-    return block;
-}
-
-/*****************************************************************************
- * aout_DecDeleteBuffer : destroy an undecoded buffer
- *****************************************************************************/
-void aout_DecDeleteBuffer (audio_output_t *aout, block_t *block)
-{
-    (void) aout;
-    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_FiltersAdjustResampling (owner->filters, 0);
 }
 
 static void aout_DecSilence (audio_output_t *aout, mtime_t length, mtime_t pts)
@@ -267,7 +217,7 @@ static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts,
                                  int input_rate)
 {
     aout_owner_t *owner = aout_owner (aout);
-    mtime_t aout_pts, drift;
+    mtime_t drift;
 
     /**
      * Depending on the drift between the actual and intended playback times,
@@ -285,9 +235,9 @@ static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts,
      * all samples in the buffer will have been played. Then:
      *    pts = mdate() + delay
      */
-    if (aout_OutputTimeGet (aout, &aout_pts) != 0)
+    if (aout_OutputTimeGet (aout, &drift) != 0)
         return; /* nothing can be done if timing is unknown */
-    drift = aout_pts - dec_pts;
+    drift += mdate () - dec_pts;
 
     /* Late audio output.
      * This can happen due to insufficient caching, scheduling jitter
@@ -311,9 +261,9 @@ static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts,
         owner->sync.discontinuity = true;
 
         /* Now the output might be too early... Recheck. */
-        if (aout_OutputTimeGet (aout, &aout_pts) != 0)
+        if (aout_OutputTimeGet (aout, &drift) != 0)
             return; /* nothing can be done if timing is unknown */
-        drift = aout_pts - dec_pts;
+        drift += mdate () - dec_pts;
     }
 
     /* Early audio output.
@@ -371,7 +321,7 @@ static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts,
          * value, then it is time to switch back the resampling direction. */
         adj *= -1;
 
-    if (!aout_FiltersAdjustResampling (aout, adj))
+    if (!aout_FiltersAdjustResampling (owner->filters, adj))
     {   /* Everything is back to normal: stop resampling. */
         owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
         msg_Dbg (aout, "resampling stopped (drift: %"PRId64" us)", drift);
@@ -392,8 +342,8 @@ int aout_DecPlay (audio_output_t *aout, block_t *block, int input_rate)
     block->i_length = CLOCK_FREQ * block->i_nb_samples
                                  / owner->input_format.i_rate;
 
-    aout_lock (aout);
-    if (unlikely(aout_CheckRestart (aout)))
+    aout_OutputLock (aout);
+    if (unlikely(aout_CheckReady (aout)))
         goto drop; /* Pipeline is unrecoverably broken :-( */
 
     const mtime_t now = mdate (), advance = block->i_pts - now;
@@ -413,7 +363,7 @@ int aout_DecPlay (audio_output_t *aout, block_t *block, int input_rate)
     if (block->i_flags & BLOCK_FLAG_DISCONTINUITY)
         owner->sync.discontinuity = true;
 
-    block = aout_FiltersPlay (aout, block, input_rate);
+    block = aout_FiltersPlay (owner->filters, block, input_rate);
     if (block == NULL)
         goto lost;
 
@@ -428,7 +378,7 @@ int aout_DecPlay (audio_output_t *aout, block_t *block, int input_rate)
     owner->sync.discontinuity = false;
     aout_OutputPlay (aout, block);
 out:
-    aout_unlock (aout);
+    aout_OutputUnlock (aout);
     return 0;
 drop:
     owner->sync.discontinuity = true;
@@ -448,7 +398,7 @@ void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
 {
     aout_owner_t *owner = aout_owner (aout);
 
-    aout_lock (aout);
+    aout_OutputLock (aout);
     if (owner->sync.end != VLC_TS_INVALID)
     {
         if (paused)
@@ -456,18 +406,20 @@ void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
         else
             owner->sync.end += date;
     }
-    aout_OutputPause (aout, paused, date);
-    aout_unlock (aout);
+    if (owner->mixer_format.i_format)
+        aout_OutputPause (aout, paused, date);
+    aout_OutputUnlock (aout);
 }
 
-void aout_DecFlush (audio_output_t *aout)
+void aout_DecFlush (audio_output_t *aout, bool wait)
 {
     aout_owner_t *owner = aout_owner (aout);
 
-    aout_lock (aout);
+    aout_OutputLock (aout);
     owner->sync.end = VLC_TS_INVALID;
-    aout_OutputFlush (aout, false);
-    aout_unlock (aout);
+    if (owner->mixer_format.i_format)
+        aout_OutputFlush (aout, wait);
+    aout_OutputUnlock (aout);
 }
 
 bool aout_DecIsEmpty (audio_output_t *aout)
@@ -476,14 +428,14 @@ bool aout_DecIsEmpty (audio_output_t *aout)
     mtime_t now = mdate ();
     bool empty = true;
 
-    aout_lock (aout);
+    aout_OutputLock (aout);
     if (owner->sync.end != VLC_TS_INVALID)
         empty = owner->sync.end <= now;
-    if (empty)
+    if (empty && owner->mixer_format.i_format)
         /* The last PTS has elapsed already. So the underlying audio output
          * buffer should be empty or almost. Thus draining should be fast
          * and will not block the caller too long. */
         aout_OutputFlush (aout, true);
-    aout_unlock (aout);
+    aout_OutputUnlock (aout);
     return empty;
 }