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