]> git.sesse.net Git - vlc/blob - src/audio_output/mixer.c
Debug audio output lock ordering
[vlc] / src / audio_output / mixer.c
1 /*****************************************************************************
2  * mixer.c : audio output mixing operations
3  *****************************************************************************
4  * Copyright (C) 2002-2004 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 #include <assert.h>
31
32 #include <stddef.h>
33 #include <vlc_common.h>
34 #include <libvlc.h>
35
36 #include <vlc_aout.h>
37 #include "aout_internal.h"
38 /*****************************************************************************
39  * aout_MixerNew: prepare a mixer plug-in
40  *****************************************************************************
41  * Please note that you must hold the mixer lock.
42  *****************************************************************************/
43 int aout_MixerNew( aout_instance_t * p_aout )
44 {
45     assert( !p_aout->p_mixer );
46     vlc_assert_locked( &p_aout->input_fifos_lock );
47
48     aout_mixer_t *p_mixer = vlc_object_create( p_aout, sizeof(*p_mixer) );
49     if( !p_mixer )
50         return VLC_EGENERIC;
51
52     p_mixer->fmt = p_aout->mixer_format;
53     p_mixer->allocation = p_aout->mixer_allocation;
54     p_mixer->multiplier = p_aout->mixer_multiplier;
55     p_mixer->input_count = p_aout->i_nb_inputs;
56     p_mixer->input = calloc( p_mixer->input_count, sizeof(*p_mixer->input) );
57     for( int i = 0; i < p_aout->i_nb_inputs; i++ )
58         p_mixer->input[i] = &p_aout->pp_inputs[i]->mixer;
59     p_mixer->mix = NULL;
60     p_mixer->sys = NULL;
61
62     vlc_object_attach( p_mixer, p_aout );
63
64     p_mixer->module = module_need( p_mixer, "audio mixer", NULL, false );
65     if( !p_mixer->module )
66     {
67         msg_Err( p_aout, "no suitable audio mixer" );
68         vlc_object_detach( p_mixer );
69         free( p_mixer->input );
70         vlc_object_release( p_mixer );
71         return VLC_EGENERIC;
72     }
73
74     /* */
75     p_aout->p_mixer = p_mixer;
76     return VLC_SUCCESS;
77 }
78
79 /*****************************************************************************
80  * aout_MixerDelete: delete the mixer
81  *****************************************************************************
82  * Please note that you must hold the mixer lock.
83  *****************************************************************************/
84 void aout_MixerDelete( aout_instance_t * p_aout )
85 {
86     if( !p_aout->p_mixer )
87         return;
88
89     vlc_object_detach( p_aout->p_mixer );
90
91     module_unneed( p_aout->p_mixer, p_aout->p_mixer->module );
92
93     free( p_aout->p_mixer->input );
94     vlc_object_release( p_aout->p_mixer );
95
96     /* */
97     p_aout->p_mixer = NULL;
98 }
99
100 /*****************************************************************************
101  * MixBuffer: try to prepare one output buffer
102  *****************************************************************************
103  * Please note that you must hold the mixer lock.
104  *****************************************************************************/
105 static int MixBuffer( aout_instance_t * p_aout )
106 {
107     int             i, i_first_input = 0;
108     aout_buffer_t * p_output_buffer;
109     mtime_t start_date, end_date;
110     date_t  exact_start_date;
111
112     if( !p_aout->p_mixer )
113     {
114         /* Free all incoming buffers. */
115         aout_lock_input_fifos( p_aout );
116         for ( i = 0; i < p_aout->i_nb_inputs; i++ )
117         {
118             aout_input_t * p_input = p_aout->pp_inputs[i];
119             aout_buffer_t * p_buffer = p_input->mixer.fifo.p_first;
120             if ( p_input->b_error ) continue;
121             while ( p_buffer != NULL )
122             {
123                 aout_buffer_t * p_next = p_buffer->p_next;
124                 aout_BufferFree( p_buffer );
125                 p_buffer = p_next;
126             }
127         }
128         aout_unlock_input_fifos( p_aout );
129         return -1;
130     }
131
132
133     aout_lock_output_fifo( p_aout );
134     aout_lock_input_fifos( p_aout );
135
136     /* Retrieve the date of the next buffer. */
137     exact_start_date = p_aout->output.fifo.end_date;
138     start_date = date_Get( &exact_start_date );
139
140     if ( start_date != 0 && start_date < mdate() )
141     {
142         /* The output is _very_ late. This can only happen if the user
143          * pauses the stream (or if the decoder is buggy, which cannot
144          * happen :). */
145         msg_Warn( p_aout, "output PTS is out of range (%"PRId64"), clearing out",
146                   mdate() - start_date );
147         aout_FifoSet( p_aout, &p_aout->output.fifo, 0 );
148         date_Set( &exact_start_date, 0 );
149         start_date = 0;
150     }
151
152     aout_unlock_output_fifo( p_aout );
153
154     /* See if we have enough data to prepare a new buffer for the audio
155      * output. First : start date. */
156     if ( !start_date )
157     {
158         /* Find the latest start date available. */
159         for ( i = 0; i < p_aout->i_nb_inputs; i++ )
160         {
161             aout_input_t * p_input = p_aout->pp_inputs[i];
162             aout_fifo_t * p_fifo = &p_input->mixer.fifo;
163             aout_buffer_t * p_buffer;
164
165             if ( p_input->b_error || p_input->b_paused )
166                 continue;
167
168             p_buffer = p_fifo->p_first;
169             while ( p_buffer != NULL && p_buffer->i_pts < mdate() )
170             {
171                 msg_Warn( p_aout, "input PTS is out of range (%"PRId64"), "
172                           "trashing", mdate() - p_buffer->i_pts );
173                 p_buffer = aout_FifoPop( p_aout, p_fifo );
174                 aout_BufferFree( p_buffer );
175                 p_buffer = p_fifo->p_first;
176                 p_input->mixer.begin = NULL;
177             }
178
179             if ( p_buffer == NULL )
180             {
181                 break;
182             }
183
184             if ( !start_date || start_date < p_buffer->i_pts )
185             {
186                 date_Set( &exact_start_date, p_buffer->i_pts );
187                 start_date = p_buffer->i_pts;
188             }
189         }
190
191         if ( i < p_aout->i_nb_inputs )
192         {
193             /* Interrupted before the end... We can't run. */
194             aout_unlock_input_fifos( p_aout );
195             return -1;
196         }
197     }
198     date_Increment( &exact_start_date, p_aout->output.i_nb_samples );
199     end_date = date_Get( &exact_start_date );
200
201     /* Check that start_date and end_date are available for all input
202      * streams. */
203     for ( i = 0; i < p_aout->i_nb_inputs; i++ )
204     {
205         aout_input_t * p_input = p_aout->pp_inputs[i];
206         aout_fifo_t * p_fifo = &p_input->mixer.fifo;
207         aout_buffer_t * p_buffer;
208         mtime_t prev_date;
209         bool b_drop_buffers;
210
211         p_input->mixer.is_invalid = p_input->b_error || p_input->b_paused;
212         if ( p_input->mixer.is_invalid )
213         {
214             if ( i_first_input == i ) i_first_input++;
215             continue;
216         }
217
218         p_buffer = p_fifo->p_first;
219         if ( p_buffer == NULL )
220         {
221             break;
222         }
223
224         /* Check for the continuity of start_date */
225         while ( p_buffer != NULL
226              && p_buffer->i_pts + p_buffer->i_length < start_date - 1 )
227         {
228             /* We authorize a +-1 because rounding errors get compensated
229              * regularly. */
230             aout_buffer_t * p_next = p_buffer->p_next;
231             msg_Warn( p_aout, "the mixer got a packet in the past (%"PRId64")",
232                       start_date - (p_buffer->i_pts + p_buffer->i_length) );
233             aout_BufferFree( p_buffer );
234             p_fifo->p_first = p_buffer = p_next;
235             p_input->mixer.begin = NULL;
236         }
237         if ( p_buffer == NULL )
238         {
239             p_fifo->pp_last = &p_fifo->p_first;
240             break;
241         }
242
243         /* Check that we have enough samples. */
244         for ( ; ; )
245         {
246             p_buffer = p_fifo->p_first;
247             if ( p_buffer == NULL ) break;
248             if ( p_buffer->i_pts + p_buffer->i_length >= end_date ) break;
249
250             /* Check that all buffers are contiguous. */
251             prev_date = p_fifo->p_first->i_pts + p_fifo->p_first->i_length;
252             p_buffer = p_buffer->p_next;
253             b_drop_buffers = 0;
254             for ( ; p_buffer != NULL; p_buffer = p_buffer->p_next )
255             {
256                 if ( prev_date != p_buffer->i_pts )
257                 {
258                     msg_Warn( p_aout,
259                               "buffer hole, dropping packets (%"PRId64")",
260                               p_buffer->i_pts - prev_date );
261                     b_drop_buffers = 1;
262                     break;
263                 }
264                 if ( p_buffer->i_pts + p_buffer->i_length >= end_date ) break;
265                 prev_date = p_buffer->i_pts + p_buffer->i_length;
266             }
267             if ( b_drop_buffers )
268             {
269                 aout_buffer_t * p_deleted = p_fifo->p_first;
270                 while ( p_deleted != NULL && p_deleted != p_buffer )
271                 {
272                     aout_buffer_t * p_next = p_deleted->p_next;
273                     aout_BufferFree( p_deleted );
274                     p_deleted = p_next;
275                 }
276                 p_fifo->p_first = p_deleted; /* == p_buffer */
277             }
278             else break;
279         }
280         if ( p_buffer == NULL ) break;
281
282         p_buffer = p_fifo->p_first;
283         if ( !AOUT_FMT_NON_LINEAR( &p_aout->p_mixer->fmt ) )
284         {
285             /* Additionally check that p_first_byte_to_mix is well
286              * located. */
287             mtime_t i_buffer = (start_date - p_buffer->i_pts)
288                             * p_aout->p_mixer->fmt.i_bytes_per_frame
289                             * p_aout->p_mixer->fmt.i_rate
290                             / p_aout->p_mixer->fmt.i_frame_length
291                             / 1000000;
292             ptrdiff_t mixer_nb_bytes;
293
294             if ( p_input->mixer.begin == NULL )
295             {
296                 p_input->mixer.begin = p_buffer->p_buffer;
297             }
298             mixer_nb_bytes = p_input->mixer.begin - p_buffer->p_buffer;
299
300             if ( !((i_buffer + p_aout->p_mixer->fmt.i_bytes_per_frame
301                      > mixer_nb_bytes) &&
302                    (i_buffer < p_aout->p_mixer->fmt.i_bytes_per_frame
303                      + mixer_nb_bytes)) )
304             {
305                 msg_Warn( p_aout, "mixer start isn't output start (%"PRId64")",
306                           i_buffer - mixer_nb_bytes );
307
308                 /* Round to the nearest multiple */
309                 i_buffer /= p_aout->p_mixer->fmt.i_bytes_per_frame;
310                 i_buffer *= p_aout->p_mixer->fmt.i_bytes_per_frame;
311                 if( i_buffer < 0 )
312                 {
313                     /* Is it really the best way to do it ? */
314                     aout_lock_output_fifo( p_aout );
315                     aout_FifoSet( p_aout, &p_aout->output.fifo, 0 );
316                     date_Set( &exact_start_date, 0 );
317                     aout_unlock_output_fifo( p_aout );
318                     break;
319                 }
320
321                 p_input->mixer.begin = p_buffer->p_buffer + i_buffer;
322             }
323         }
324     }
325
326     if ( i < p_aout->i_nb_inputs || i_first_input == p_aout->i_nb_inputs )
327     {
328         /* Interrupted before the end... We can't run. */
329         aout_unlock_input_fifos( p_aout );
330         return -1;
331     }
332
333     /* Run the mixer. */
334     p_output_buffer = aout_BufferAlloc( &p_aout->p_mixer->allocation,
335                           ((uint64_t)p_aout->output.i_nb_samples * 1000000)
336                             / p_aout->output.output.i_rate,
337                           /* This is a bit kludgy, but is actually only used
338                            * for the S/PDIF dummy mixer : */
339                           p_aout->pp_inputs[i_first_input]->mixer.fifo.p_first);
340     if ( p_output_buffer == NULL )
341     {
342         aout_unlock_input_fifos( p_aout );
343         return -1;
344     }
345     /* This is again a bit kludgy - for the S/PDIF mixer. */
346     if ( p_aout->p_mixer->allocation.b_alloc )
347     {
348         p_output_buffer->i_nb_samples = p_aout->output.i_nb_samples;
349         p_output_buffer->i_buffer = p_aout->output.i_nb_samples
350                               * p_aout->p_mixer->fmt.i_bytes_per_frame
351                               / p_aout->p_mixer->fmt.i_frame_length;
352     }
353     p_output_buffer->i_pts = start_date;
354     p_output_buffer->i_length = end_date - start_date;
355
356     p_aout->p_mixer->mix( p_aout->p_mixer, p_output_buffer );
357
358     aout_unlock_input_fifos( p_aout );
359
360     aout_OutputPlay( p_aout, p_output_buffer );
361
362     return 0;
363 }
364
365 /*****************************************************************************
366  * aout_MixerRun: entry point for the mixer & post-filters processing
367  *****************************************************************************
368  * Please note that you must hold the mixer lock.
369  *****************************************************************************/
370 void aout_MixerRun( aout_instance_t * p_aout )
371 {
372     while( MixBuffer( p_aout ) != -1 );
373 }
374
375 /*****************************************************************************
376  * aout_MixerMultiplierSet: set p_aout->mixer.f_multiplier
377  *****************************************************************************
378  * Please note that we assume that you own the mixer lock when entering this
379  * function. This function returns -1 on error.
380  *****************************************************************************/
381 int aout_MixerMultiplierSet( aout_instance_t * p_aout, float f_multiplier )
382 {
383     float f_old = p_aout->mixer_multiplier;
384     bool b_new_mixer = false;
385
386     if ( p_aout->p_mixer )
387     {
388         aout_MixerDelete( p_aout );
389         b_new_mixer = true;
390     }
391
392     p_aout->mixer_multiplier = f_multiplier;
393
394     if ( b_new_mixer && aout_MixerNew( p_aout ) )
395     {
396         p_aout->mixer_multiplier = f_old;
397         aout_MixerNew( p_aout );
398         return -1;
399     }
400
401     return 0;
402 }
403
404 /*****************************************************************************
405  * aout_MixerMultiplierGet: get p_aout->mixer.f_multiplier
406  *****************************************************************************
407  * Please note that we assume that you own the mixer lock when entering this
408  * function. This function returns -1 on error.
409  *****************************************************************************/
410 int aout_MixerMultiplierGet( aout_instance_t * p_aout, float * pf_multiplier )
411 {
412     *pf_multiplier = p_aout->mixer_multiplier;
413     return 0;
414 }
415