]> git.sesse.net Git - vlc/blobdiff - src/audio_output/dec.c
aout: lack of software mixer is non fatal
[vlc] / src / audio_output / dec.c
index 5a83978669f4e31cd7eaf3c9255dae354cc37300..f60fa4d81fa645ae588b056e800b5dab54cba67d 100644 (file)
@@ -103,11 +103,9 @@ int aout_DecNew( audio_output_t *p_aout,
 
     assert (owner->volume.mixer == NULL);
     owner->volume.mixer = aout_MixerNew (p_aout, owner->mixer_format.i_format);
-    if (owner->volume.mixer == NULL)
-    {
-        aout_OutputDelete( p_aout );
-        goto error;
-    }
+
+    date_Init (&owner->sync.date, owner->mixer_format.i_rate, 1);
+    date_Set (&owner->sync.date, VLC_TS_INVALID);
 
     owner->input = p_input;
     aout_InputNew( p_aout, p_input, p_request_vout );
@@ -165,17 +163,11 @@ static void aout_CheckRestart (audio_output_t *aout)
 
     if (aout_OutputNew (aout, &input->input))
     {
-error:
         input->b_error = true;
         return; /* we are officially screwed */
     }
 
     owner->volume.mixer = aout_MixerNew (aout, owner->mixer_format.i_format);
-    if (owner->volume.mixer == NULL)
-    {
-        aout_OutputDelete (aout);
-        goto error;
-    }
 
     if (aout_InputNew (aout, input, &input->request_vout))
         assert (input->b_error);
@@ -244,10 +236,12 @@ int aout_DecPlay (audio_output_t *p_aout, block_t *p_buffer, int i_input_rate)
     aout_InputCheckAndRestart( p_aout, p_input );
 
     /* Input */
-    p_buffer = aout_InputPlay( p_aout, p_input, p_buffer, i_input_rate );
-
+    p_buffer = aout_InputPlay (p_aout, p_input, p_buffer, i_input_rate,
+                               &owner->sync.date);
     if( p_buffer != NULL )
     {
+        date_Increment (&owner->sync.date, p_buffer->i_nb_samples);
+
         /* Mixer */
         float amp = owner->volume.multiplier * p_input->multiplier;
         aout_MixerRun (owner->volume.mixer, p_buffer, amp);
@@ -277,12 +271,10 @@ int aout_DecGetResetLost (audio_output_t *aout)
 void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
 {
     aout_owner_t *owner = aout_owner (aout);
-    aout_input_t *p_input = owner->input;
 
     aout_lock (aout);
-
-    /* XXX: Should the input date be offset by the pause duration instead? */
-    date_Set (&p_input->date, VLC_TS_INVALID);
+    /* XXX: Should the date be offset by the pause duration instead? */
+    date_Set (&owner->sync.date, VLC_TS_INVALID);
     aout_OutputPause (aout, paused, date);
     aout_unlock (aout);
 }
@@ -290,10 +282,9 @@ void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
 void aout_DecFlush (audio_output_t *aout)
 {
     aout_owner_t *owner = aout_owner (aout);
-    aout_input_t *input = owner->input;
 
     aout_lock (aout);
-    date_Set (&input->date, VLC_TS_INVALID);
+    date_Set (&owner->sync.date, VLC_TS_INVALID);
     aout_OutputFlush (aout, false);
     aout_unlock (aout);
 }
@@ -301,12 +292,54 @@ void aout_DecFlush (audio_output_t *aout)
 bool aout_DecIsEmpty (audio_output_t *aout)
 {
     aout_owner_t *owner = aout_owner (aout);
-    aout_input_t *input = owner->input;
     mtime_t end_date;
 
     aout_lock (aout);
     /* FIXME: tell output to drain */
-    end_date = date_Get (&input->date);
+    end_date = date_Get (&owner->sync.date);
     aout_unlock (aout);
     return end_date == VLC_TS_INVALID || end_date <= mdate();
 }
+
+/**
+ * Notifies the audio input of the drift from the requested audio
+ * playback timestamp (@ref block_t.i_pts) to the anticipated playback time
+ * as reported by the audio output hardware.
+ * Depending on the drift amplitude, the input core may ignore the drift
+ * trigger upsampling or downsampling, or even discard samples.
+ * Future VLC versions may instead adjust the input decoding speed.
+ *
+ * The audio output plugin is responsible for estimating the ideal current
+ * playback time defined as follows:
+ *  ideal time = buffer timestamp - (output latency + pending buffer duration)
+ *
+ * Practically, this is the PTS (block_t.i_pts) of the current buffer minus
+ * the latency reported by the output programming interface.
+ * Computing the estimated drift directly would probably be more intuitive.
+ * However the use of an absolute time value does not introduce extra
+ * measurement errors due to the CPU scheduling jitter and clock resolution.
+ * Furthermore, the ideal while it is an abstract value, is easy for most
+ * audio output plugins to compute.
+ * The following definition is equivalent but depends on the clock time:
+ *  ideal time = real time + drift
+
+ * @note If aout_LatencyReport() is never called, the core will assume that
+ * there is no drift.
+ *
+ * @param ideal estimated ideal time as defined above.
+ */
+void aout_TimeReport (audio_output_t *aout, mtime_t ideal)
+{
+    mtime_t delta = mdate() - ideal /* = -drift */;
+
+    aout_assert_locked (aout);
+    if (delta < -AOUT_MAX_PTS_ADVANCE || +AOUT_MAX_PTS_DELAY < delta)
+    {
+        aout_owner_t *owner = aout_owner (aout);
+
+        msg_Warn (aout, "not synchronized (%"PRId64" us), resampling",
+                  delta);
+        if (date_Get (&owner->sync.date) != VLC_TS_INVALID)
+            date_Move (&owner->sync.date, delta);
+    }
+}