]> git.sesse.net Git - vlc/blob - src/audio_output/dec.c
aout: do not use aout_owner() from input
[vlc] / src / audio_output / dec.c
1 /*****************************************************************************
2  * dec.c : audio output API towards decoders
3  *****************************************************************************
4  * Copyright (C) 2002-2007 the VideoLAN team
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
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, 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
35 #include <vlc_aout.h>
36 #include <vlc_input.h>
37
38 #include "aout_internal.h"
39 #include "libvlc.h"
40
41 /**
42  * Creates an audio output
43  */
44 int aout_DecNew( audio_output_t *p_aout,
45                  const audio_sample_format_t *p_format,
46                  const audio_replay_gain_t *p_replay_gain,
47                  const aout_request_vout_t *p_request_vout )
48 {
49     /* Sanitize audio format */
50     if( p_format->i_channels > 32 )
51     {
52         msg_Err( p_aout, "too many audio channels (%u)",
53                  p_format->i_channels );
54         return -1;
55     }
56     if( p_format->i_channels <= 0 )
57     {
58         msg_Err( p_aout, "no audio channels" );
59         return -1;
60     }
61     if( p_format->i_channels != aout_FormatNbChannels( p_format ) )
62     {
63         msg_Err( p_aout, "incompatible audio channels count with layout mask" );
64         return -1;
65     }
66
67     if( p_format->i_rate > 192000 )
68     {
69         msg_Err( p_aout, "excessive audio sample frequency (%u)",
70                  p_format->i_rate );
71         return -1;
72     }
73     if( p_format->i_rate < 4000 )
74     {
75         msg_Err( p_aout, "too low audio sample frequency (%u)",
76                  p_format->i_rate );
77         return -1;
78     }
79
80     aout_input_t *p_input = calloc( 1, sizeof(aout_input_t));
81     if( !p_input )
82         return -1;
83
84     p_input->b_error = true;
85
86     if( p_replay_gain )
87         p_input->replay_gain = *p_replay_gain;
88
89     /* We can only be called by the decoder, so no need to lock
90      * p_input->lock. */
91     aout_owner_t *owner = aout_owner(p_aout);
92     aout_lock( p_aout );
93     assert (owner->input == NULL);
94
95     var_Destroy( p_aout, "audio-device" );
96     var_Destroy( p_aout, "audio-channels" );
97
98     /* Recreate the output using the new format. */
99     owner->input_format = *p_format;
100     if( aout_OutputNew( p_aout, p_format ) < 0 )
101         goto error;
102
103     assert (owner->volume.mixer == NULL);
104     owner->volume.mixer = aout_MixerNew (p_aout, owner->mixer_format.i_format);
105
106     date_Init (&owner->sync.date, owner->mixer_format.i_rate, 1);
107     date_Set (&owner->sync.date, VLC_TS_INVALID);
108
109     owner->input = p_input;
110     aout_InputNew( p_aout, p_format, &owner->mixer_format, p_input,
111                    p_request_vout );
112     aout_unlock( p_aout );
113     return 0;
114 error:
115     aout_unlock( p_aout );
116     free( p_input );
117     return -1;
118 }
119
120 /*****************************************************************************
121  * aout_DecDelete : delete a decoder
122  *****************************************************************************/
123 void aout_DecDelete( audio_output_t * p_aout )
124 {
125     aout_owner_t *owner = aout_owner (p_aout);
126     aout_input_t *input;
127     struct audio_mixer *mixer;
128
129     aout_lock( p_aout );
130     /* Remove the input. */
131     input = owner->input;
132     aout_InputDelete (p_aout, input);
133     owner->input = NULL;
134
135     aout_OutputDelete( p_aout );
136     mixer = owner->volume.mixer;
137     owner->volume.mixer = NULL;
138     var_Destroy( p_aout, "audio-device" );
139     var_Destroy( p_aout, "audio-channels" );
140
141     aout_unlock( p_aout );
142
143     aout_MixerDelete (mixer);
144     free (input);
145 }
146
147 static void aout_CheckRestart (audio_output_t *aout)
148 {
149     aout_owner_t *owner = aout_owner (aout);
150     aout_input_t *input = owner->input;
151
152     aout_assert_locked (aout);
153
154     if (likely(!owner->need_restart))
155         return;
156     owner->need_restart = false;
157
158     /* Reinitializes the output */
159     aout_InputDelete (aout, owner->input);
160     aout_MixerDelete (owner->volume.mixer);
161     owner->volume.mixer = NULL;
162     aout_OutputDelete (aout);
163
164     if (aout_OutputNew (aout, &owner->input_format))
165     {
166         input->b_error = true;
167         return; /* we are officially screwed */
168     }
169
170     owner->volume.mixer = aout_MixerNew (aout, owner->mixer_format.i_format);
171
172     if (aout_InputNew (aout, &owner->input_format, &owner->mixer_format, input,
173                        &input->request_vout))
174         assert (input->b_error);
175     else
176         assert (!input->b_error);
177 }
178
179 /**
180  * Restarts the audio filter chain if needed.
181  */
182 static void aout_InputCheckAndRestart (audio_output_t *aout)
183 {
184     aout_owner_t *owner = aout_owner (aout);
185     aout_input_t *input = owner->input;
186
187     aout_assert_locked (aout);
188
189     if (!input->b_restart)
190         return;
191     input->b_restart = false;
192
193     aout_InputDelete (aout, input);
194     aout_InputNew (aout, &owner->input_format, &owner->mixer_format,
195                    input, &input->request_vout);
196 }
197
198 /**
199  * This function will safely mark aout input to be restarted as soon as
200  * possible to take configuration changes into account
201  */
202 void aout_InputRequestRestart (audio_output_t *aout)
203 {
204     aout_lock (aout);
205     if (aout_owner (aout)->input != NULL)
206         aout_owner (aout)->input->b_restart = true;
207     aout_unlock (aout);
208 }
209
210
211 /*
212  * Buffer management
213  */
214
215 /*****************************************************************************
216  * aout_DecNewBuffer : ask for a new empty buffer
217  *****************************************************************************/
218 block_t *aout_DecNewBuffer (audio_output_t *aout, size_t samples)
219 {
220     /* NOTE: the caller is responsible for serializing input change */
221     aout_owner_t *owner = aout_owner (aout);
222
223     size_t length = samples * owner->input_format.i_bytes_per_frame
224                             / owner->input_format.i_frame_length;
225     block_t *block = block_Alloc( length );
226     if( likely(block != NULL) )
227     {
228         block->i_nb_samples = samples;
229         block->i_pts = block->i_length = 0;
230     }
231     return block;
232 }
233
234 /*****************************************************************************
235  * aout_DecDeleteBuffer : destroy an undecoded buffer
236  *****************************************************************************/
237 void aout_DecDeleteBuffer (audio_output_t *aout, block_t *block)
238 {
239     (void) aout;
240     aout_BufferFree (block);
241 }
242
243 /*****************************************************************************
244  * aout_DecPlay : filter & mix the decoded buffer
245  *****************************************************************************/
246 int aout_DecPlay (audio_output_t *p_aout, block_t *p_buffer, int i_input_rate)
247 {
248     aout_owner_t *owner = aout_owner (p_aout);
249     aout_input_t *p_input = owner->input;
250
251     assert( i_input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE &&
252             i_input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE );
253     assert( p_buffer->i_pts > 0 );
254
255     p_buffer->i_length = (mtime_t)p_buffer->i_nb_samples * 1000000
256                                 / owner->input_format.i_rate;
257
258     aout_lock( p_aout );
259     if( p_input->b_error )
260     {
261         aout_unlock( p_aout );
262         aout_BufferFree( p_buffer );
263         return -1;
264     }
265
266     aout_CheckRestart( p_aout );
267     aout_InputCheckAndRestart (p_aout);
268
269     /* Input */
270     p_buffer = aout_InputPlay (p_aout, p_input, p_buffer, i_input_rate,
271                                &owner->sync.date);
272     if( p_buffer != NULL )
273     {
274         date_Increment (&owner->sync.date, p_buffer->i_nb_samples);
275
276         /* Mixer */
277         float amp = owner->volume.multiplier * p_input->multiplier;
278         aout_MixerRun (owner->volume.mixer, p_buffer, amp);
279
280         /* Output */
281         aout_OutputPlay( p_aout, p_buffer );
282     }
283
284     aout_unlock( p_aout );
285     return 0;
286 }
287
288 int aout_DecGetResetLost (audio_output_t *aout)
289 {
290     aout_owner_t *owner = aout_owner (aout);
291     aout_input_t *input = owner->input;
292     int val;
293
294     aout_lock (aout);
295     val = input->i_buffer_lost;
296     input->i_buffer_lost = 0;
297     aout_unlock (aout);
298
299     return val;
300 }
301
302 void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
303 {
304     aout_owner_t *owner = aout_owner (aout);
305
306     aout_lock (aout);
307     /* XXX: Should the date be offset by the pause duration instead? */
308     date_Set (&owner->sync.date, VLC_TS_INVALID);
309     aout_OutputPause (aout, paused, date);
310     aout_unlock (aout);
311 }
312
313 void aout_DecFlush (audio_output_t *aout)
314 {
315     aout_owner_t *owner = aout_owner (aout);
316
317     aout_lock (aout);
318     date_Set (&owner->sync.date, VLC_TS_INVALID);
319     aout_OutputFlush (aout, false);
320     aout_unlock (aout);
321 }
322
323 bool aout_DecIsEmpty (audio_output_t *aout)
324 {
325     aout_owner_t *owner = aout_owner (aout);
326     mtime_t end_date;
327
328     aout_lock (aout);
329     /* FIXME: tell output to drain */
330     end_date = date_Get (&owner->sync.date);
331     aout_unlock (aout);
332     return end_date == VLC_TS_INVALID || end_date <= mdate();
333 }
334
335 /**
336  * Notifies the audio input of the drift from the requested audio
337  * playback timestamp (@ref block_t.i_pts) to the anticipated playback time
338  * as reported by the audio output hardware.
339  * Depending on the drift amplitude, the input core may ignore the drift
340  * trigger upsampling or downsampling, or even discard samples.
341  * Future VLC versions may instead adjust the input decoding speed.
342  *
343  * The audio output plugin is responsible for estimating the ideal current
344  * playback time defined as follows:
345  *  ideal time = buffer timestamp - (output latency + pending buffer duration)
346  *
347  * Practically, this is the PTS (block_t.i_pts) of the current buffer minus
348  * the latency reported by the output programming interface.
349  * Computing the estimated drift directly would probably be more intuitive.
350  * However the use of an absolute time value does not introduce extra
351  * measurement errors due to the CPU scheduling jitter and clock resolution.
352  * Furthermore, the ideal while it is an abstract value, is easy for most
353  * audio output plugins to compute.
354  * The following definition is equivalent but depends on the clock time:
355  *  ideal time = real time + drift
356
357  * @note If aout_LatencyReport() is never called, the core will assume that
358  * there is no drift.
359  *
360  * @param ideal estimated ideal time as defined above.
361  */
362 void aout_TimeReport (audio_output_t *aout, mtime_t ideal)
363 {
364     mtime_t delta = mdate() - ideal /* = -drift */;
365
366     aout_assert_locked (aout);
367     if (delta < -AOUT_MAX_PTS_ADVANCE || +AOUT_MAX_PTS_DELAY < delta)
368     {
369         aout_owner_t *owner = aout_owner (aout);
370
371         msg_Warn (aout, "not synchronized (%"PRId64" us), resampling",
372                   delta);
373         if (date_Get (&owner->sync.date) != VLC_TS_INVALID)
374             date_Move (&owner->sync.date, delta);
375     }
376 }