]> git.sesse.net Git - vlc/blob - src/audio_output/input.c
Split out aout_mixer_t from aout_instance_t.
[vlc] / src / audio_output / input.c
1 /*****************************************************************************
2  * input.c : internal management of input streams for the audio output
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
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <math.h>
37 #include <assert.h>
38
39 #include <vlc_input.h>
40 #include <vlc_vout.h>                  /* for vout_Request */
41
42 #ifdef HAVE_ALLOCA_H
43 #   include <alloca.h>
44 #endif
45 #include <vlc_aout.h>
46 #include <libvlc.h>
47
48 #include "aout_internal.h"
49
50 #define AOUT_ASSERT_MIXER_LOCKED vlc_assert_locked( &p_aout->mixer_lock )
51 #define AOUT_ASSERT_INPUT_LOCKED vlc_assert_locked( &p_input->lock )
52
53 static void inputFailure( aout_instance_t *, aout_input_t *, const char * );
54 static void inputDrop( aout_input_t *, aout_buffer_t * );
55 static void inputResamplingStop( aout_input_t *p_input );
56
57 static int VisualizationCallback( vlc_object_t *, char const *,
58                                   vlc_value_t, vlc_value_t, void * );
59 static int EqualizerCallback( vlc_object_t *, char const *,
60                               vlc_value_t, vlc_value_t, void * );
61 static int ReplayGainCallback( vlc_object_t *, char const *,
62                                vlc_value_t, vlc_value_t, void * );
63 static void ReplayGainSelect( aout_instance_t *, aout_input_t * );
64
65 static vout_thread_t *RequestVout( void *,
66                                    vout_thread_t *, video_format_t *, bool );
67 static vout_thread_t *RequestVoutFromFilter( void *,
68                                              vout_thread_t *, video_format_t *, bool  );
69
70 /*****************************************************************************
71  * aout_InputNew : allocate a new input and rework the filter pipeline
72  *****************************************************************************/
73 int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input, const aout_request_vout_t *p_request_vout )
74 {
75     audio_sample_format_t chain_input_format;
76     audio_sample_format_t chain_output_format;
77     vlc_value_t val, text;
78     char *psz_filters, *psz_visual, *psz_scaletempo;
79     int i_visual;
80
81     aout_FormatPrint( p_aout, "input", &p_input->input );
82
83     p_input->i_nb_resamplers = p_input->i_nb_filters = 0;
84
85     /* Prepare FIFO. */
86     aout_FifoInit( p_aout, &p_input->mixer.fifo, p_aout->p_mixer->fmt.i_rate );
87     p_input->mixer.begin = NULL;
88
89     /* */
90     if( p_request_vout )
91     {
92         p_input->request_vout = *p_request_vout;
93     }
94     else
95     {
96         p_input->request_vout.pf_request_vout = RequestVout;
97         p_input->request_vout.p_private = p_aout;
98     }
99
100     /* Prepare format structure */
101     chain_input_format  = p_input->input;
102     chain_output_format = p_aout->p_mixer->fmt;
103     chain_output_format.i_rate = p_input->input.i_rate;
104     aout_FormatPrepare( &chain_output_format );
105
106     /* Now add user filters */
107     if( var_Type( p_aout, "visual" ) == 0 )
108     {
109         var_Create( p_aout, "visual", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
110         text.psz_string = _("Visualizations");
111         var_Change( p_aout, "visual", VLC_VAR_SETTEXT, &text, NULL );
112         val.psz_string = (char*)""; text.psz_string = _("Disable");
113         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
114         val.psz_string = (char*)"spectrometer"; text.psz_string = _("Spectrometer");
115         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
116         val.psz_string = (char*)"scope"; text.psz_string = _("Scope");
117         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
118         val.psz_string = (char*)"spectrum"; text.psz_string = _("Spectrum");
119         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
120         val.psz_string = (char*)"vuMeter"; text.psz_string = _("Vu meter");
121         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
122
123         /* Look for goom plugin */
124         if( module_exists( "goom" ) )
125         {
126             val.psz_string = (char*)"goom"; text.psz_string = (char*)"Goom";
127             var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
128         }
129
130         /* Look for galaktos plugin */
131         if( module_exists( "galaktos" ) )
132         {
133             val.psz_string = (char*)"galaktos"; text.psz_string = (char*)"GaLaktos";
134             var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
135         }
136
137         /* Look for libprojectM plugin */
138         if( module_exists( "projectm" ) )
139         {
140             val.psz_string = (char*)"projectm"; text.psz_string = (char*)"projectM";
141             var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
142         }
143
144         if( var_Get( p_aout, "effect-list", &val ) == VLC_SUCCESS )
145         {
146             var_SetString( p_aout, "visual", val.psz_string );
147             free( val.psz_string );
148         }
149         var_AddCallback( p_aout, "visual", VisualizationCallback, NULL );
150     }
151
152     if( var_Type( p_aout, "equalizer" ) == 0 )
153     {
154         module_config_t *p_config;
155         int i;
156
157         p_config = config_FindConfig( VLC_OBJECT(p_aout), "equalizer-preset" );
158         if( p_config && p_config->i_list )
159         {
160                var_Create( p_aout, "equalizer",
161                            VLC_VAR_STRING | VLC_VAR_HASCHOICE );
162             text.psz_string = _("Equalizer");
163             var_Change( p_aout, "equalizer", VLC_VAR_SETTEXT, &text, NULL );
164
165             val.psz_string = (char*)""; text.psz_string = _("Disable");
166             var_Change( p_aout, "equalizer", VLC_VAR_ADDCHOICE, &val, &text );
167
168             for( i = 0; i < p_config->i_list; i++ )
169             {
170                 val.psz_string = (char *)p_config->ppsz_list[i];
171                 text.psz_string = (char *)p_config->ppsz_list_text[i];
172                 var_Change( p_aout, "equalizer", VLC_VAR_ADDCHOICE,
173                             &val, &text );
174             }
175
176             var_AddCallback( p_aout, "equalizer", EqualizerCallback, NULL );
177         }
178     }
179
180     if( var_Type( p_aout, "audio-filter" ) == 0 )
181     {
182         var_Create( p_aout, "audio-filter",
183                     VLC_VAR_STRING | VLC_VAR_DOINHERIT );
184         text.psz_string = _("Audio filters");
185         var_Change( p_aout, "audio-filter", VLC_VAR_SETTEXT, &text, NULL );
186     }
187     if( var_Type( p_aout, "audio-visual" ) == 0 )
188     {
189         var_Create( p_aout, "audio-visual",
190                     VLC_VAR_STRING | VLC_VAR_DOINHERIT );
191         text.psz_string = _("Audio visualizations");
192         var_Change( p_aout, "audio-visual", VLC_VAR_SETTEXT, &text, NULL );
193     }
194
195     if( var_Type( p_aout, "audio-replay-gain-mode" ) == 0 )
196     {
197         module_config_t *p_config;
198         int i;
199
200         p_config = config_FindConfig( VLC_OBJECT(p_aout), "audio-replay-gain-mode" );
201         if( p_config && p_config->i_list )
202         {
203             var_Create( p_aout, "audio-replay-gain-mode",
204                         VLC_VAR_STRING | VLC_VAR_DOINHERIT );
205
206             text.psz_string = _("Replay gain");
207             var_Change( p_aout, "audio-replay-gain-mode", VLC_VAR_SETTEXT, &text, NULL );
208
209             for( i = 0; i < p_config->i_list; i++ )
210             {
211                 val.psz_string = (char *)p_config->ppsz_list[i];
212                 text.psz_string = (char *)p_config->ppsz_list_text[i];
213                 var_Change( p_aout, "audio-replay-gain-mode", VLC_VAR_ADDCHOICE,
214                             &val, &text );
215             }
216
217             var_AddCallback( p_aout, "audio-replay-gain-mode", ReplayGainCallback, NULL );
218         }
219     }
220     if( var_Type( p_aout, "audio-replay-gain-preamp" ) == 0 )
221     {
222         var_Create( p_aout, "audio-replay-gain-preamp",
223                     VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
224     }
225     if( var_Type( p_aout, "audio-replay-gain-default" ) == 0 )
226     {
227         var_Create( p_aout, "audio-replay-gain-default",
228                     VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
229     }
230     if( var_Type( p_aout, "audio-replay-gain-peak-protection" ) == 0 )
231     {
232         var_Create( p_aout, "audio-replay-gain-peak-protection",
233                     VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
234     }
235     if( var_Type( p_aout, "audio-time-stretch" ) == 0 )
236     {
237         var_Create( p_aout, "audio-time-stretch",
238                     VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
239     }
240
241     psz_filters = var_GetString( p_aout, "audio-filter" );
242     psz_visual = var_GetString( p_aout, "audio-visual");
243     psz_scaletempo = var_GetBool( p_aout, "audio-time-stretch" ) ? strdup( "scaletempo" ) : NULL;
244
245     p_input->b_recycle_vout = psz_visual && *psz_visual;
246
247     /* parse user filter lists */
248     char *const ppsz_array[] = { psz_scaletempo, psz_filters, psz_visual };
249     p_input->p_playback_rate_filter = NULL;
250
251     for( i_visual = 0; i_visual < 3 && !AOUT_FMT_NON_LINEAR(&chain_output_format); i_visual++ )
252     {
253         char *psz_next = NULL;
254         char *psz_parser = ppsz_array[i_visual];
255
256         if( psz_parser == NULL || !*psz_parser )
257             continue;
258
259         while( psz_parser && *psz_parser )
260         {
261             aout_filter_t * p_filter = NULL;
262
263             if( p_input->i_nb_filters >= AOUT_MAX_FILTERS )
264             {
265                 msg_Dbg( p_aout, "max filters reached (%d)", AOUT_MAX_FILTERS );
266                 break;
267             }
268
269             while( *psz_parser == ' ' && *psz_parser == ':' )
270             {
271                 psz_parser++;
272             }
273             if( ( psz_next = strchr( psz_parser , ':'  ) ) )
274             {
275                 *psz_next++ = '\0';
276             }
277             if( *psz_parser =='\0' )
278             {
279                 break;
280             }
281
282             /* Create a VLC object */
283             static const char typename[] = "audio filter";
284             p_filter = vlc_custom_create( p_aout, sizeof(*p_filter),
285                                           VLC_OBJECT_GENERIC, typename );
286             if( p_filter == NULL )
287             {
288                 msg_Err( p_aout, "cannot add user filter %s (skipped)",
289                          psz_parser );
290                 psz_parser = psz_next;
291                 continue;
292             }
293
294             vlc_object_set_name( p_filter, psz_parser );
295             vlc_object_attach( p_filter , p_aout );
296
297             p_filter->request_vout.pf_request_vout = RequestVoutFromFilter;
298             p_filter->request_vout.p_private = p_input;
299
300             p_filter->p_owner = malloc( sizeof(*p_filter->p_owner) );
301             p_filter->p_owner->p_aout  = p_aout;
302             p_filter->p_owner->p_input = p_input;
303
304             /* request format */
305             memcpy( &p_filter->input, &chain_output_format,
306                     sizeof(audio_sample_format_t) );
307             memcpy( &p_filter->output, &chain_output_format,
308                     sizeof(audio_sample_format_t) );
309
310
311             /* try to find the requested filter */
312             if( i_visual == 2 ) /* this can only be a visualization module */
313             {
314                 p_filter->p_module = module_need( p_filter, "visualization",
315                                                   psz_parser, true );
316             }
317             else /* this can be a audio filter module as well as a visualization module */
318             {
319                 p_filter->p_module = module_need( p_filter, "audio filter",
320                                               psz_parser, true );
321
322                 if ( p_filter->p_module == NULL )
323                 {
324                     /* if the filter requested a special format, retry */
325                     if ( !( AOUT_FMTS_IDENTICAL( &p_filter->input,
326                                                  &chain_input_format )
327                             && AOUT_FMTS_IDENTICAL( &p_filter->output,
328                                                     &chain_output_format ) ) )
329                     {
330                         aout_FormatPrepare( &p_filter->input );
331                         aout_FormatPrepare( &p_filter->output );
332                         p_filter->p_module = module_need( p_filter,
333                                                           "audio filter",
334                                                           psz_parser, true );
335                     }
336                     /* try visual filters */
337                     else
338                     {
339                         memcpy( &p_filter->input, &chain_output_format,
340                                 sizeof(audio_sample_format_t) );
341                         memcpy( &p_filter->output, &chain_output_format,
342                                 sizeof(audio_sample_format_t) );
343                         p_filter->p_module = module_need( p_filter,
344                                                           "visualization",
345                                                           psz_parser, true );
346                     }
347                 }
348             }
349
350             /* failure */
351             if ( p_filter->p_module == NULL )
352             {
353                 msg_Err( p_aout, "cannot add user filter %s (skipped)",
354                          psz_parser );
355
356                 free( p_filter->p_owner );
357                 vlc_object_detach( p_filter );
358                 vlc_object_release( p_filter );
359
360                 psz_parser = psz_next;
361                 continue;
362             }
363
364             /* complete the filter chain if necessary */
365             if ( !AOUT_FMTS_IDENTICAL( &chain_input_format, &p_filter->input ) )
366             {
367                 if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
368                                                  &p_input->i_nb_filters,
369                                                  &chain_input_format,
370                                                  &p_filter->input ) < 0 )
371                 {
372                     msg_Err( p_aout, "cannot add user filter %s (skipped)",
373                              psz_parser );
374
375                     module_unneed( p_filter, p_filter->p_module );
376                     free( p_filter->p_owner );
377                     vlc_object_detach( p_filter );
378                     vlc_object_release( p_filter );
379
380                     psz_parser = psz_next;
381                     continue;
382                 }
383             }
384
385             /* success */
386             p_filter->b_continuity = false;
387             p_input->pp_filters[p_input->i_nb_filters++] = p_filter;
388             memcpy( &chain_input_format, &p_filter->output,
389                     sizeof( audio_sample_format_t ) );
390
391             if( i_visual == 0 ) /* scaletempo */
392                 p_input->p_playback_rate_filter = p_filter;
393
394             /* next filter if any */
395             psz_parser = psz_next;
396         }
397     }
398     free( psz_visual );
399     free( psz_filters );
400     free( psz_scaletempo );
401
402     /* complete the filter chain if necessary */
403     if ( !AOUT_FMTS_IDENTICAL( &chain_input_format, &chain_output_format ) )
404     {
405         if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
406                                          &p_input->i_nb_filters,
407                                          &chain_input_format,
408                                          &chain_output_format ) < 0 )
409         {
410             inputFailure( p_aout, p_input, "couldn't set an input pipeline" );
411             return -1;
412         }
413     }
414
415     /* Prepare hints for the buffer allocator. */
416     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
417     p_input->input_alloc.i_bytes_per_sec = -1;
418
419     /* Create resamplers. */
420     if ( !AOUT_FMT_NON_LINEAR( &p_aout->p_mixer->fmt ) )
421     {
422         chain_output_format.i_rate = (__MAX(p_input->input.i_rate,
423                                             p_aout->p_mixer->fmt.i_rate)
424                                  * (100 + AOUT_MAX_RESAMPLING)) / 100;
425         if ( chain_output_format.i_rate == p_aout->p_mixer->fmt.i_rate )
426         {
427             /* Just in case... */
428             chain_output_format.i_rate++;
429         }
430         if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_resamplers,
431                                          &p_input->i_nb_resamplers,
432                                          &chain_output_format,
433                                          &p_aout->p_mixer->fmt ) < 0 )
434         {
435             inputFailure( p_aout, p_input, "couldn't set a resampler pipeline");
436             return -1;
437         }
438
439         aout_FiltersHintBuffers( p_aout, p_input->pp_resamplers,
440                                  p_input->i_nb_resamplers,
441                                  &p_input->input_alloc );
442         p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
443
444         /* Setup the initial rate of the resampler */
445         p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
446     }
447     p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
448
449     if( ! p_input->p_playback_rate_filter && p_input->i_nb_resamplers > 0 )
450     {
451         p_input->p_playback_rate_filter = p_input->pp_resamplers[0];
452     }
453
454     aout_FiltersHintBuffers( p_aout, p_input->pp_filters,
455                              p_input->i_nb_filters,
456                              &p_input->input_alloc );
457     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
458
459     /* i_bytes_per_sec is still == -1 if no filters */
460     p_input->input_alloc.i_bytes_per_sec = __MAX(
461                                     p_input->input_alloc.i_bytes_per_sec,
462                                     (int)(p_input->input.i_bytes_per_frame
463                                      * p_input->input.i_rate
464                                      / p_input->input.i_frame_length) );
465
466     ReplayGainSelect( p_aout, p_input );
467
468     /* Success */
469     p_input->b_error = false;
470     p_input->b_restart = false;
471     p_input->i_last_input_rate = INPUT_RATE_DEFAULT;
472
473     return 0;
474 }
475
476 /*****************************************************************************
477  * aout_InputDelete : delete an input
478  *****************************************************************************
479  * This function must be entered with the mixer lock.
480  *****************************************************************************/
481 int aout_InputDelete( aout_instance_t * p_aout, aout_input_t * p_input )
482 {
483     AOUT_ASSERT_MIXER_LOCKED;
484     if ( p_input->b_error )
485         return 0;
486
487     /* XXX We need to update b_recycle_vout before calling aout_FiltersDestroyPipeline.
488      * FIXME They can be a race condition if audio-visual is updated between
489      * aout_InputDelete and aout_InputNew.
490      */
491     char *psz_visual = var_GetString( p_aout, "audio-visual");
492     p_input->b_recycle_vout = psz_visual && *psz_visual;
493     free( psz_visual );
494
495     aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
496                                  p_input->i_nb_filters );
497     p_input->i_nb_filters = 0;
498     aout_FiltersDestroyPipeline( p_aout, p_input->pp_resamplers,
499                                  p_input->i_nb_resamplers );
500     p_input->i_nb_resamplers = 0;
501     aout_FifoDestroy( p_aout, &p_input->mixer.fifo );
502
503     return 0;
504 }
505
506 /*****************************************************************************
507  * aout_InputPlay : play a buffer
508  *****************************************************************************
509  * This function must be entered with the input lock.
510  *****************************************************************************/
511 /* XXX Do not activate it !! */
512 //#define AOUT_PROCESS_BEFORE_CHEKS
513 int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
514                     aout_buffer_t * p_buffer, int i_input_rate )
515 {
516     mtime_t start_date;
517     AOUT_ASSERT_INPUT_LOCKED;
518
519     if( p_input->b_restart )
520     {
521         aout_fifo_t fifo;
522         uint8_t     *p_first_byte_to_mix;
523         bool        b_paused;
524         mtime_t     i_pause_date;
525
526         aout_lock_mixer( p_aout );
527         aout_lock_input_fifos( p_aout );
528
529         /* A little trick to avoid loosing our input fifo and properties */
530
531         p_first_byte_to_mix = p_input->mixer.begin;
532         fifo = p_input->mixer.fifo;
533         b_paused = p_input->b_paused;
534         i_pause_date = p_input->i_pause_date;
535
536         aout_FifoInit( p_aout, &p_input->mixer.fifo, p_aout->p_mixer->fmt.i_rate );
537
538         aout_InputDelete( p_aout, p_input );
539
540         aout_InputNew( p_aout, p_input, &p_input->request_vout );
541         p_input->mixer.begin = p_first_byte_to_mix;
542         p_input->mixer.fifo = fifo;
543         p_input->b_paused = b_paused;
544         p_input->i_pause_date = i_pause_date;
545
546         aout_unlock_input_fifos( p_aout );
547         aout_unlock_mixer( p_aout );
548     }
549
550     if( i_input_rate != INPUT_RATE_DEFAULT && p_input->p_playback_rate_filter == NULL )
551     {
552         inputDrop( p_input, p_buffer );
553         return 0;
554     }
555
556 #ifdef AOUT_PROCESS_BEFORE_CHEKS
557     /* Run pre-filters. */
558     aout_FiltersPlay( p_aout, p_input->pp_filters, p_input->i_nb_filters,
559                       &p_buffer );
560
561     /* Actually run the resampler now. */
562     if ( p_input->i_nb_resamplers > 0 )
563     {
564         const mtime_t i_date = p_buffer->start_date;
565         aout_FiltersPlay( p_aout, p_input->pp_resamplers,
566                           p_input->i_nb_resamplers,
567                           &p_buffer );
568     }
569
570     if( p_buffer->i_nb_samples <= 0 )
571     {
572         aout_BufferFree( p_buffer );
573         return 0;
574     }
575 #endif
576
577     /* Handle input rate change, but keep drift correction */
578     if( i_input_rate != p_input->i_last_input_rate )
579     {
580         unsigned int * const pi_rate = &p_input->p_playback_rate_filter->input.i_rate;
581 #define F(r,ir) ( INPUT_RATE_DEFAULT * (r) / (ir) )
582         const int i_delta = *pi_rate - F(p_input->input.i_rate,p_input->i_last_input_rate);
583         *pi_rate = F(p_input->input.i_rate + i_delta, i_input_rate);
584 #undef F
585         p_input->i_last_input_rate = i_input_rate;
586     }
587
588     /* We don't care if someone changes the start date behind our back after
589      * this. We'll deal with that when pushing the buffer, and compensate
590      * with the next incoming buffer. */
591     aout_lock_input_fifos( p_aout );
592     start_date = aout_FifoNextStart( p_aout, &p_input->mixer.fifo );
593     aout_unlock_input_fifos( p_aout );
594
595     if ( start_date != 0 && start_date < mdate() )
596     {
597         /* The decoder is _very_ late. This can only happen if the user
598          * pauses the stream (or if the decoder is buggy, which cannot
599          * happen :). */
600         msg_Warn( p_aout, "computed PTS is out of range (%"PRId64"), "
601                   "clearing out", mdate() - start_date );
602         aout_lock_input_fifos( p_aout );
603         aout_FifoSet( p_aout, &p_input->mixer.fifo, 0 );
604         p_input->mixer.begin = NULL;
605         aout_unlock_input_fifos( p_aout );
606         if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
607             msg_Warn( p_aout, "timing screwed, stopping resampling" );
608         inputResamplingStop( p_input );
609         start_date = 0;
610     }
611
612     if ( p_buffer->start_date < mdate() + AOUT_MIN_PREPARE_TIME )
613     {
614         /* The decoder gives us f*cked up PTS. It's its business, but we
615          * can't present it anyway, so drop the buffer. */
616         msg_Warn( p_aout, "PTS is out of range (%"PRId64"), dropping buffer",
617                   mdate() - p_buffer->start_date );
618
619         inputDrop( p_input, p_buffer );
620         inputResamplingStop( p_input );
621         return 0;
622     }
623
624     /* If the audio drift is too big then it's not worth trying to resample
625      * the audio. */
626     mtime_t i_pts_tolerance = 3 * AOUT_PTS_TOLERANCE * i_input_rate / INPUT_RATE_DEFAULT;
627     if ( start_date != 0 &&
628          ( start_date < p_buffer->start_date - i_pts_tolerance ) )
629     {
630         msg_Warn( p_aout, "audio drift is too big (%"PRId64"), clearing out",
631                   start_date - p_buffer->start_date );
632         aout_lock_input_fifos( p_aout );
633         aout_FifoSet( p_aout, &p_input->mixer.fifo, 0 );
634         p_input->mixer.begin = NULL;
635         aout_unlock_input_fifos( p_aout );
636         if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
637             msg_Warn( p_aout, "timing screwed, stopping resampling" );
638         inputResamplingStop( p_input );
639         start_date = 0;
640     }
641     else if ( start_date != 0 &&
642               ( start_date > p_buffer->start_date + i_pts_tolerance) )
643     {
644         msg_Warn( p_aout, "audio drift is too big (%"PRId64"), dropping buffer",
645                   start_date - p_buffer->start_date );
646         inputDrop( p_input, p_buffer );
647         return 0;
648     }
649
650     if ( start_date == 0 ) start_date = p_buffer->start_date;
651
652 #ifndef AOUT_PROCESS_BEFORE_CHEKS
653     /* Run pre-filters. */
654     aout_FiltersPlay( p_aout, p_input->pp_filters, p_input->i_nb_filters,
655                       &p_buffer );
656 #endif
657
658     /* Run the resampler if needed.
659      * We first need to calculate the output rate of this resampler. */
660     if ( ( p_input->i_resampling_type == AOUT_RESAMPLING_NONE ) &&
661          ( start_date < p_buffer->start_date - AOUT_PTS_TOLERANCE
662            || start_date > p_buffer->start_date + AOUT_PTS_TOLERANCE ) &&
663          p_input->i_nb_resamplers > 0 )
664     {
665         /* Can happen in several circumstances :
666          * 1. A problem at the input (clock drift)
667          * 2. A small pause triggered by the user
668          * 3. Some delay in the output stage, causing a loss of lip
669          *    synchronization
670          * Solution : resample the buffer to avoid a scratch.
671          */
672         mtime_t drift = p_buffer->start_date - start_date;
673
674         p_input->i_resamp_start_date = mdate();
675         p_input->i_resamp_start_drift = (int)drift;
676
677         if ( drift > 0 )
678             p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
679         else
680             p_input->i_resampling_type = AOUT_RESAMPLING_UP;
681
682         msg_Warn( p_aout, "buffer is %"PRId64" %s, triggering %ssampling",
683                           drift > 0 ? drift : -drift,
684                           drift > 0 ? "in advance" : "late",
685                           drift > 0 ? "down" : "up");
686     }
687
688     if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
689     {
690         /* Resampling has been triggered previously (because of dates
691          * mismatch). We want the resampling to happen progressively so
692          * it isn't too audible to the listener. */
693
694         if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
695         {
696             p_input->pp_resamplers[0]->input.i_rate += 2; /* Hz */
697         }
698         else
699         {
700             p_input->pp_resamplers[0]->input.i_rate -= 2; /* Hz */
701         }
702
703         /* Check if everything is back to normal, in which case we can stop the
704          * resampling */
705         unsigned int i_nominal_rate =
706           (p_input->pp_resamplers[0] == p_input->p_playback_rate_filter)
707           ? INPUT_RATE_DEFAULT * p_input->input.i_rate / i_input_rate
708           : p_input->input.i_rate;
709         if( p_input->pp_resamplers[0]->input.i_rate == i_nominal_rate )
710         {
711             p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
712             msg_Warn( p_aout, "resampling stopped after %"PRIi64" usec "
713                       "(drift: %"PRIi64")",
714                       mdate() - p_input->i_resamp_start_date,
715                       p_buffer->start_date - start_date);
716         }
717         else if( abs( (int)(p_buffer->start_date - start_date) ) <
718                  abs( p_input->i_resamp_start_drift ) / 2 )
719         {
720             /* if we reduced the drift from half, then it is time to switch
721              * back the resampling direction. */
722             if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
723                 p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
724             else
725                 p_input->i_resampling_type = AOUT_RESAMPLING_UP;
726             p_input->i_resamp_start_drift = 0;
727         }
728         else if( p_input->i_resamp_start_drift &&
729                  ( abs( (int)(p_buffer->start_date - start_date) ) >
730                    abs( p_input->i_resamp_start_drift ) * 3 / 2 ) )
731         {
732             /* If the drift is increasing and not decreasing, than something
733              * is bad. We'd better stop the resampling right now. */
734             msg_Warn( p_aout, "timing screwed, stopping resampling" );
735             inputResamplingStop( p_input );
736         }
737     }
738
739 #ifndef AOUT_PROCESS_BEFORE_CHEKS
740     /* Actually run the resampler now. */
741     if ( p_input->i_nb_resamplers > 0 )
742     {
743         aout_FiltersPlay( p_aout, p_input->pp_resamplers,
744                           p_input->i_nb_resamplers,
745                           &p_buffer );
746     }
747
748     if( p_buffer->i_nb_samples <= 0 )
749     {
750         aout_BufferFree( p_buffer );
751         return 0;
752     }
753 #endif
754
755     /* Adding the start date will be managed by aout_FifoPush(). */
756     p_buffer->end_date = start_date +
757         (p_buffer->end_date - p_buffer->start_date);
758     p_buffer->start_date = start_date;
759
760     aout_lock_input_fifos( p_aout );
761     aout_FifoPush( p_aout, &p_input->mixer.fifo, p_buffer );
762     aout_unlock_input_fifos( p_aout );
763     return 0;
764 }
765
766 /*****************************************************************************
767  * static functions
768  *****************************************************************************/
769
770 static void inputFailure( aout_instance_t * p_aout, aout_input_t * p_input,
771                           const char * psz_error_message )
772 {
773     /* error message */
774     msg_Err( p_aout, "%s", psz_error_message );
775
776     /* clean up */
777     aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
778                                  p_input->i_nb_filters );
779     aout_FiltersDestroyPipeline( p_aout, p_input->pp_resamplers,
780                                  p_input->i_nb_resamplers );
781     aout_FifoDestroy( p_aout, &p_input->mixer.fifo );
782     var_Destroy( p_aout, "visual" );
783     var_Destroy( p_aout, "equalizer" );
784     var_Destroy( p_aout, "audio-filter" );
785     var_Destroy( p_aout, "audio-visual" );
786
787     var_Destroy( p_aout, "audio-replay-gain-mode" );
788     var_Destroy( p_aout, "audio-replay-gain-default" );
789     var_Destroy( p_aout, "audio-replay-gain-preamp" );
790     var_Destroy( p_aout, "audio-replay-gain-peak-protection" );
791
792     /* error flag */
793     p_input->b_error = 1;
794 }
795
796 static void inputDrop( aout_input_t *p_input, aout_buffer_t *p_buffer )
797 {
798     aout_BufferFree( p_buffer );
799
800     p_input->i_buffer_lost++;
801 }
802
803 static void inputResamplingStop( aout_input_t *p_input )
804 {
805     p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
806     if( p_input->i_nb_resamplers != 0 )
807     {
808         p_input->pp_resamplers[0]->input.i_rate =
809             ( p_input->pp_resamplers[0] == p_input->p_playback_rate_filter )
810             ? INPUT_RATE_DEFAULT * p_input->input.i_rate / p_input->i_last_input_rate
811             : p_input->input.i_rate;
812         p_input->pp_resamplers[0]->b_continuity = false;
813     }
814 }
815
816 static vout_thread_t *RequestVout( void *p_private,
817                                    vout_thread_t *p_vout, video_format_t *p_fmt, bool b_recycle )
818 {
819     aout_instance_t *p_aout = p_private;
820     VLC_UNUSED(b_recycle);
821     return vout_Request( p_aout, p_vout, p_fmt );
822 }
823
824 static vout_thread_t *RequestVoutFromFilter( void *p_private,
825                                             vout_thread_t *p_vout, video_format_t *p_fmt, bool b_recycle )
826 {
827     aout_input_t *p_input = p_private;
828     aout_request_vout_t *p_request = &p_input->request_vout;
829
830     return p_request->pf_request_vout( p_request->p_private,
831                                        p_vout, p_fmt, p_input->b_recycle_vout && b_recycle );
832 }
833
834 static int ChangeFiltersString( aout_instance_t * p_aout, const char* psz_variable,
835                                  const char *psz_name, bool b_add )
836 {
837     return AoutChangeFilterString( VLC_OBJECT(p_aout), p_aout,
838                                    psz_variable, psz_name, b_add ) ? 1 : 0;
839 }
840
841 static int VisualizationCallback( vlc_object_t *p_this, char const *psz_cmd,
842                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
843 {
844     aout_instance_t *p_aout = (aout_instance_t *)p_this;
845     char *psz_mode = newval.psz_string;
846     (void)psz_cmd; (void)oldval; (void)p_data;
847
848     if( !psz_mode || !*psz_mode )
849     {
850         ChangeFiltersString( p_aout, "audio-visual", "goom", false );
851         ChangeFiltersString( p_aout, "audio-visual", "visual", false );
852         ChangeFiltersString( p_aout, "audio-visual", "galaktos", false );
853         ChangeFiltersString( p_aout, "audio-visual", "projectm", false );
854     }
855     else
856     {
857         if( !strcmp( "goom", psz_mode ) )
858         {
859             ChangeFiltersString( p_aout, "audio-visual", "visual", false );
860             ChangeFiltersString( p_aout, "audio-visual", "goom", true );
861             ChangeFiltersString( p_aout, "audio-visual", "galaktos", false );
862             ChangeFiltersString( p_aout, "audio-visual", "projectm", false );
863         }
864         else if( !strcmp( "galaktos", psz_mode ) )
865         {
866             ChangeFiltersString( p_aout, "audio-visual", "visual", false );
867             ChangeFiltersString( p_aout, "audio-visual", "goom", false );
868             ChangeFiltersString( p_aout, "audio-visual", "galaktos", true );
869         }
870         else if( !strcmp( "projectm", psz_mode ) )
871         {
872             ChangeFiltersString( p_aout, "audio-visual", "visual", false );
873             ChangeFiltersString( p_aout, "audio-visual", "goom", false );
874             ChangeFiltersString( p_aout, "audio-visual", "galaktos", false );
875             ChangeFiltersString( p_aout, "audio-visual", "projectm", true );
876         }
877         else
878         {
879             var_Create( p_aout, "effect-list", VLC_VAR_STRING );
880             var_SetString( p_aout, "effect-list", psz_mode );
881
882             ChangeFiltersString( p_aout, "audio-visual", "goom", false );
883             ChangeFiltersString( p_aout, "audio-visual", "visual", true );
884             ChangeFiltersString( p_aout, "audio-visual", "galaktos", false );
885             ChangeFiltersString( p_aout, "audio-visual", "projectm", false );
886         }
887     }
888
889     /* That sucks */
890     AoutInputsMarkToRestart( p_aout );
891
892     return VLC_SUCCESS;
893 }
894
895 static int EqualizerCallback( vlc_object_t *p_this, char const *psz_cmd,
896                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
897 {
898     aout_instance_t *p_aout = (aout_instance_t *)p_this;
899     char *psz_mode = newval.psz_string;
900     int i_ret;
901     (void)psz_cmd; (void)oldval; (void)p_data;
902
903     if( !psz_mode || !*psz_mode )
904     {
905         i_ret = ChangeFiltersString( p_aout, "audio-filter", "equalizer",
906                                      false );
907     }
908     else
909     {
910         var_Create( p_aout, "equalizer-preset", VLC_VAR_STRING );
911         var_SetString( p_aout, "equalizer-preset", psz_mode );
912         i_ret = ChangeFiltersString( p_aout, "audio-filter", "equalizer",
913                                      true );
914     }
915
916     /* That sucks */
917     if( i_ret == 1 )
918         AoutInputsMarkToRestart( p_aout );
919     return VLC_SUCCESS;
920 }
921
922 static int ReplayGainCallback( vlc_object_t *p_this, char const *psz_cmd,
923                                vlc_value_t oldval, vlc_value_t newval, void *p_data )
924 {
925     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
926     VLC_UNUSED(newval); VLC_UNUSED(p_data);
927     aout_instance_t *p_aout = (aout_instance_t *)p_this;
928     int i;
929
930     aout_lock_mixer( p_aout );
931     for( i = 0; i < p_aout->i_nb_inputs; i++ )
932         ReplayGainSelect( p_aout, p_aout->pp_inputs[i] );
933
934     /* Restart the mixer (a trivial mixer may be in use) */
935     if( p_aout->p_mixer )
936         aout_MixerMultiplierSet( p_aout, p_aout->mixer_multiplier );
937     aout_unlock_mixer( p_aout );
938
939     return VLC_SUCCESS;
940 }
941
942 static void ReplayGainSelect( aout_instance_t *p_aout, aout_input_t *p_input )
943 {
944     char *psz_replay_gain = var_GetNonEmptyString( p_aout,
945                                                    "audio-replay-gain-mode" );
946     int i_mode;
947     int i_use;
948     float f_gain;
949
950     p_input->mixer.multiplier = 1.0;
951
952     if( !psz_replay_gain )
953         return;
954
955     /* Find select mode */
956     if( !strcmp( psz_replay_gain, "track" ) )
957         i_mode = AUDIO_REPLAY_GAIN_TRACK;
958     else if( !strcmp( psz_replay_gain, "album" ) )
959         i_mode = AUDIO_REPLAY_GAIN_ALBUM;
960     else
961         i_mode = AUDIO_REPLAY_GAIN_MAX;
962
963     /* If the select mode is not available, prefer the other one */
964     i_use = i_mode;
965     if( i_use != AUDIO_REPLAY_GAIN_MAX && !p_input->replay_gain.pb_gain[i_use] )
966     {
967         for( i_use = 0; i_use < AUDIO_REPLAY_GAIN_MAX; i_use++ )
968         {
969             if( p_input->replay_gain.pb_gain[i_use] )
970                 break;
971         }
972     }
973
974     /* */
975     if( i_use != AUDIO_REPLAY_GAIN_MAX )
976         f_gain = p_input->replay_gain.pf_gain[i_use] + var_GetFloat( p_aout, "audio-replay-gain-preamp" );
977     else if( i_mode != AUDIO_REPLAY_GAIN_MAX )
978         f_gain = var_GetFloat( p_aout, "audio-replay-gain-default" );
979     else
980         f_gain = 0.0;
981     p_input->mixer.multiplier = pow( 10.0, f_gain / 20.0 );
982
983     /* */
984     if( p_input->replay_gain.pb_peak[i_use] &&
985         var_GetBool( p_aout, "audio-replay-gain-peak-protection" ) &&
986         p_input->replay_gain.pf_peak[i_use] * p_input->mixer.multiplier > 1.0 )
987     {
988         p_input->mixer.multiplier = 1.0f / p_input->replay_gain.pf_peak[i_use];
989     }
990
991     free( psz_replay_gain );
992 }
993