]> git.sesse.net Git - vlc/blob - src/audio_output/dec.c
7d0316fb9040690723d017fa9820aec2041c4f4e
[vlc] / src / audio_output / dec.c
1 /*****************************************************************************
2  * dec.c : audio output API towards decoders
3  *****************************************************************************
4  * Copyright (C) 2002-2007 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <assert.h>
32
33 #include <vlc_common.h>
34 #include <vlc_aout.h>
35 #include <vlc_input.h>
36 #include <vlc_atomic.h>
37
38 #include "aout_internal.h"
39 #include "libvlc.h"
40
41 static int ReplayGainCallback (vlc_object_t *, char const *,
42                                vlc_value_t, vlc_value_t, void *);
43
44 /**
45  * Creates an audio output
46  */
47 int aout_DecNew( audio_output_t *p_aout,
48                  const audio_sample_format_t *p_format,
49                  const audio_replay_gain_t *p_replay_gain,
50                  const aout_request_vout_t *p_request_vout )
51 {
52     /* Sanitize audio format */
53     if( p_format->i_channels > 32 )
54     {
55         msg_Err( p_aout, "too many audio channels (%u)",
56                  p_format->i_channels );
57         return -1;
58     }
59     if( p_format->i_channels <= 0 )
60     {
61         msg_Err( p_aout, "no audio channels" );
62         return -1;
63     }
64     if( p_format->i_channels != aout_FormatNbChannels( p_format ) )
65     {
66         msg_Err( p_aout, "incompatible audio channels count with layout mask" );
67         return -1;
68     }
69
70     if( p_format->i_rate > 192000 )
71     {
72         msg_Err( p_aout, "excessive audio sample frequency (%u)",
73                  p_format->i_rate );
74         return -1;
75     }
76     if( p_format->i_rate < 4000 )
77     {
78         msg_Err( p_aout, "too low audio sample frequency (%u)",
79                  p_format->i_rate );
80         return -1;
81     }
82
83     aout_owner_t *owner = aout_owner(p_aout);
84 #ifdef RECYCLE
85     /* Calling decoder is responsible for serializing aout_DecNew() and
86      * aout_DecDelete(). So no need to lock to _read_ those properties. */
87     if (owner->module != NULL) /* <- output exists */
88     {   /* Check if we can recycle the existing output and pipelines */
89         if (AOUT_FMTS_IDENTICAL(&owner->input_format, p_format))
90             return 0;
91
92         /* TODO? If the new input format is closer to the output format than
93          * the old input format was, then the output could be recycled. The
94          * input pipeline however would need to be restarted. */
95
96         /* No recycling: delete everything and restart from scratch */
97         aout_Shutdown (p_aout);
98     }
99 #endif
100     int ret = -1;
101
102     /* TODO: reduce lock scope depending on decoder's real need */
103     aout_lock( p_aout );
104     assert (owner->module == NULL);
105
106     /* Create the audio output stream */
107     var_Destroy( p_aout, "audio-device" );
108     var_Destroy( p_aout, "audio-channels" );
109
110     owner->input_format = *p_format;
111     vlc_atomic_set (&owner->restart, 0);
112     if( aout_OutputNew( p_aout, p_format ) < 0 )
113         goto error;
114
115     /* Allocate a software mixer */
116     assert (owner->volume.mixer == NULL);
117     owner->volume.mixer = aout_MixerNew (p_aout, owner->mixer_format.i_format);
118
119     aout_ReplayGainInit (&owner->gain.data, p_replay_gain);
120     var_AddCallback (p_aout, "audio-replay-gain-mode",
121                      ReplayGainCallback, owner);
122     var_TriggerCallback (p_aout, "audio-replay-gain-mode");
123
124     /* Create the audio filtering "input" pipeline */
125     date_Init (&owner->sync.date, owner->mixer_format.i_rate, 1);
126     date_Set (&owner->sync.date, VLC_TS_INVALID);
127
128     assert (owner->input == NULL);
129     owner->input = aout_InputNew (p_aout, p_format, &owner->mixer_format,
130                                   p_request_vout);
131     if (owner->input == NULL)
132         aout_OutputDelete (p_aout);
133     else
134         ret = 0;
135 error:
136     aout_unlock( p_aout );
137     return ret;
138 }
139
140 /**
141  * Stops all plugins involved in the audio output.
142  */
143 void aout_Shutdown (audio_output_t *p_aout)
144 {
145     aout_owner_t *owner = aout_owner (p_aout);
146     aout_input_t *input;
147     struct audio_mixer *mixer;
148
149     aout_lock( p_aout );
150     /* Remove the input. */
151     input = owner->input;
152     if (likely(input != NULL))
153         aout_InputDelete (p_aout, input);
154     owner->input = NULL;
155
156     mixer = owner->volume.mixer;
157     owner->volume.mixer = NULL;
158
159     var_DelCallback (p_aout, "audio-replay-gain-mode",
160                      ReplayGainCallback, owner);
161
162     aout_OutputDelete( p_aout );
163     var_Destroy( p_aout, "audio-device" );
164     var_Destroy( p_aout, "audio-channels" );
165
166     aout_unlock( p_aout );
167
168     aout_MixerDelete (mixer);
169     free (input);
170 }
171
172 /**
173  * Stops the decoded audio input.
174  * @note Due to output recycling, this function is esssentially a stub.
175  */
176 void aout_DecDelete (audio_output_t *aout)
177 {
178 #ifdef RECYCLE
179     (void) aout;
180 #else
181     aout_Shutdown (aout);
182 #endif
183 }
184
185 #define AOUT_RESTART_OUTPUT 1
186 #define AOUT_RESTART_INPUT  2
187 static void aout_CheckRestart (audio_output_t *aout)
188 {
189     aout_owner_t *owner = aout_owner (aout);
190
191     aout_assert_locked (aout);
192
193     int restart = vlc_atomic_swap (&owner->restart, 0);
194     if (likely(restart == 0))
195         return;
196
197     assert (restart & AOUT_RESTART_INPUT);
198
199     const aout_request_vout_t request_vout = owner->input->request_vout;
200
201     if (likely(owner->input != NULL))
202         aout_InputDelete (aout, owner->input);
203     owner->input = NULL;
204
205     /* Reinitializes the output */
206     if (restart & AOUT_RESTART_OUTPUT)
207     {
208         aout_MixerDelete (owner->volume.mixer);
209         owner->volume.mixer = NULL;
210         aout_OutputDelete (aout);
211
212         if (aout_OutputNew (aout, &owner->input_format))
213             return; /* we are officially screwed */
214         owner->volume.mixer = aout_MixerNew (aout,
215                                              owner->mixer_format.i_format);
216     }
217
218     owner->input = aout_InputNew (aout, &owner->input_format,
219                                   &owner->mixer_format, &request_vout);
220 }
221
222 /**
223  * Marks the audio output for restart, to update any parameter of the output
224  * plug-in (e.g. output device or channel mapping).
225  */
226 void aout_RequestRestart (audio_output_t *aout)
227 {
228     aout_owner_t *owner = aout_owner (aout);
229
230     /* DO NOT remove AOUT_RESTART_INPUT. You need to change the atomic ops. */
231     vlc_atomic_set (&owner->restart, AOUT_RESTART_OUTPUT|AOUT_RESTART_INPUT);
232 }
233
234 /**
235  * This function will safely mark aout input to be restarted as soon as
236  * possible to take configuration changes into account
237  */
238 void aout_InputRequestRestart (audio_output_t *aout)
239 {
240     aout_owner_t *owner = aout_owner (aout);
241
242     vlc_atomic_compare_swap (&owner->restart, 0, AOUT_RESTART_INPUT);
243 }
244
245
246 /*
247  * Buffer management
248  */
249
250 /*****************************************************************************
251  * aout_DecNewBuffer : ask for a new empty buffer
252  *****************************************************************************/
253 block_t *aout_DecNewBuffer (audio_output_t *aout, size_t samples)
254 {
255     /* NOTE: the caller is responsible for serializing input change */
256     aout_owner_t *owner = aout_owner (aout);
257
258     size_t length = samples * owner->input_format.i_bytes_per_frame
259                             / owner->input_format.i_frame_length;
260     block_t *block = block_Alloc( length );
261     if( likely(block != NULL) )
262     {
263         block->i_nb_samples = samples;
264         block->i_pts = block->i_length = 0;
265     }
266     return block;
267 }
268
269 /*****************************************************************************
270  * aout_DecDeleteBuffer : destroy an undecoded buffer
271  *****************************************************************************/
272 void aout_DecDeleteBuffer (audio_output_t *aout, block_t *block)
273 {
274     (void) aout;
275     aout_BufferFree (block);
276 }
277
278 /*****************************************************************************
279  * aout_DecPlay : filter & mix the decoded buffer
280  *****************************************************************************/
281 int aout_DecPlay (audio_output_t *p_aout, block_t *p_buffer, int i_input_rate)
282 {
283     aout_owner_t *owner = aout_owner (p_aout);
284     aout_input_t *input;
285
286     assert( i_input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE &&
287             i_input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE );
288     assert( p_buffer->i_pts > 0 );
289
290     p_buffer->i_length = (mtime_t)p_buffer->i_nb_samples * 1000000
291                                 / owner->input_format.i_rate;
292
293     aout_lock( p_aout );
294     aout_CheckRestart( p_aout );
295
296     input = owner->input;
297     if (unlikely(input == NULL)) /* can happen due to restart */
298     {
299         aout_unlock( p_aout );
300         aout_BufferFree( p_buffer );
301         return -1;
302     }
303
304     /* Input */
305     p_buffer = aout_InputPlay (p_aout, input, p_buffer, i_input_rate,
306                                &owner->sync.date);
307     if( p_buffer != NULL )
308     {
309         date_Increment (&owner->sync.date, p_buffer->i_nb_samples);
310
311         /* Mixer */
312         if (owner->volume.mixer != NULL)
313         {
314             float amp = owner->volume.multiplier
315                       * vlc_atomic_getf (&owner->gain.multiplier);
316             aout_MixerRun (owner->volume.mixer, p_buffer, amp);
317         }
318
319         /* Output */
320         aout_OutputPlay( p_aout, p_buffer );
321     }
322
323     aout_unlock( p_aout );
324     return 0;
325 }
326
327 int aout_DecGetResetLost (audio_output_t *aout)
328 {
329     aout_owner_t *owner = aout_owner (aout);
330     aout_input_t *input = owner->input;
331     int val;
332
333     aout_lock (aout);
334     if (likely(input != NULL))
335     {
336         val = input->i_buffer_lost;
337         input->i_buffer_lost = 0;
338     }
339     else
340         val = 0; /* if aout_CheckRestart() failed */
341     aout_unlock (aout);
342
343     return val;
344 }
345
346 void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
347 {
348     aout_owner_t *owner = aout_owner (aout);
349
350     aout_lock (aout);
351     /* XXX: Should the date be offset by the pause duration instead? */
352     date_Set (&owner->sync.date, VLC_TS_INVALID);
353     aout_OutputPause (aout, paused, date);
354     aout_unlock (aout);
355 }
356
357 void aout_DecFlush (audio_output_t *aout)
358 {
359     aout_owner_t *owner = aout_owner (aout);
360
361     aout_lock (aout);
362     date_Set (&owner->sync.date, VLC_TS_INVALID);
363     aout_OutputFlush (aout, false);
364     aout_unlock (aout);
365 }
366
367 bool aout_DecIsEmpty (audio_output_t *aout)
368 {
369     aout_owner_t *owner = aout_owner (aout);
370     mtime_t end_date, now = mdate ();
371     bool empty;
372
373     aout_lock (aout);
374     end_date = date_Get (&owner->sync.date);
375     empty = end_date == VLC_TS_INVALID || end_date <= now;
376     if (empty)
377         /* The last PTS has elapsed already. So the underlying audio output
378          * buffer should be empty or almost. Thus draining should be fast
379          * and will not block the caller too long. */
380         aout_OutputFlush (aout, true);
381     aout_unlock (aout);
382     return empty;
383 }
384
385 /**
386  * Notifies the audio input of the drift from the requested audio
387  * playback timestamp (@ref block_t.i_pts) to the anticipated playback time
388  * as reported by the audio output hardware.
389  * Depending on the drift amplitude, the input core may ignore the drift
390  * trigger upsampling or downsampling, or even discard samples.
391  * Future VLC versions may instead adjust the input decoding speed.
392  *
393  * The audio output plugin is responsible for estimating the ideal current
394  * playback time defined as follows:
395  *  ideal time = buffer timestamp - (output latency + pending buffer duration)
396  *
397  * Practically, this is the PTS (block_t.i_pts) of the current buffer minus
398  * the latency reported by the output programming interface.
399  * Computing the estimated drift directly would probably be more intuitive.
400  * However the use of an absolute time value does not introduce extra
401  * measurement errors due to the CPU scheduling jitter and clock resolution.
402  * Furthermore, the ideal while it is an abstract value, is easy for most
403  * audio output plugins to compute.
404  * The following definition is equivalent but depends on the clock time:
405  *  ideal time = real time + drift
406
407  * @note If aout_LatencyReport() is never called, the core will assume that
408  * there is no drift.
409  *
410  * @param ideal estimated ideal time as defined above.
411  */
412 void aout_TimeReport (audio_output_t *aout, mtime_t ideal)
413 {
414     mtime_t delta = mdate() - ideal /* = -drift */;
415
416     aout_assert_locked (aout);
417     if (delta < -AOUT_MAX_PTS_ADVANCE || +AOUT_MAX_PTS_DELAY < delta)
418     {
419         aout_owner_t *owner = aout_owner (aout);
420
421         msg_Warn (aout, "not synchronized (%"PRId64" us), resampling",
422                   delta);
423         if (date_Get (&owner->sync.date) != VLC_TS_INVALID)
424             date_Move (&owner->sync.date, delta);
425     }
426 }
427
428 static int ReplayGainCallback (vlc_object_t *obj, char const *var,
429                                vlc_value_t oldval, vlc_value_t val, void *data)
430 {
431     aout_owner_t *owner = data;
432     float multiplier = aout_ReplayGainSelect (obj, val.psz_string,
433                                               &owner->gain.data);
434     vlc_atomic_setf (&owner->gain.multiplier, multiplier);
435     VLC_UNUSED(var); VLC_UNUSED(oldval);
436     return VLC_SUCCESS;
437 }