1 /*****************************************************************************
2 * input.c : internal management of input streams for the audio output
3 *****************************************************************************
4 * Copyright (C) 2002-2007 the VideoLAN team
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
34 #include <vlc_common.h>
41 #include <vlc_input.h>
42 #include <vlc_vout.h> /* for vout_Request */
43 #include <vlc_modules.h>
45 #include <vlc_filter.h>
46 #include <vlc_atomic.h>
49 #include "aout_internal.h"
51 static void inputFailure( audio_output_t *, aout_input_t *, const char * );
52 static void inputDrop( aout_input_t *, aout_buffer_t * );
53 static void inputResamplingStop( aout_input_t *p_input );
55 static int VisualizationCallback( vlc_object_t *, char const *,
56 vlc_value_t, vlc_value_t, void * );
57 static int EqualizerCallback( vlc_object_t *, char const *,
58 vlc_value_t, vlc_value_t, void * );
59 static int ReplayGainCallback( vlc_object_t *, char const *,
60 vlc_value_t, vlc_value_t, void * );
61 static float ReplayGainSelect(vlc_object_t *, const char *,
62 const audio_replay_gain_t *);
64 static vout_thread_t *RequestVout( void *,
65 vout_thread_t *, video_format_t *, bool );
67 /*****************************************************************************
68 * aout_InputNew : allocate a new input and rework the filter pipeline
69 *****************************************************************************/
70 int aout_InputNew( audio_output_t * p_aout,
71 const audio_sample_format_t *restrict infmt,
72 const audio_sample_format_t *restrict outfmt,
73 aout_input_t * p_input,
74 const aout_request_vout_t *p_request_vout )
76 audio_sample_format_t chain_input_format;
77 audio_sample_format_t chain_output_format;
78 vlc_value_t val, text;
79 char *psz_filters, *psz_visual, *psz_scaletempo;
82 aout_FormatPrint( p_aout, "input", infmt );
83 p_input->samplerate = infmt->i_rate;
85 p_input->i_nb_resamplers = p_input->i_nb_filters = 0;
90 p_input->request_vout = *p_request_vout;
94 p_input->request_vout.pf_request_vout = RequestVout;
95 p_input->request_vout.p_private = p_aout;
98 /* Prepare format structure */
99 chain_input_format = *infmt;
100 chain_output_format = *outfmt;
101 chain_output_format.i_rate = infmt->i_rate;
102 aout_FormatPrepare( &chain_output_format );
104 /* Now add user filters */
105 if( var_Type( p_aout, "visual" ) == 0 )
107 var_Create( p_aout, "visual", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
108 text.psz_string = _("Visualizations");
109 var_Change( p_aout, "visual", VLC_VAR_SETTEXT, &text, NULL );
110 val.psz_string = (char*)""; text.psz_string = _("Disable");
111 var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
112 val.psz_string = (char*)"spectrometer"; text.psz_string = _("Spectrometer");
113 var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
114 val.psz_string = (char*)"scope"; text.psz_string = _("Scope");
115 var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
116 val.psz_string = (char*)"spectrum"; text.psz_string = _("Spectrum");
117 var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
118 val.psz_string = (char*)"vuMeter"; text.psz_string = _("Vu meter");
119 var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
121 /* Look for goom plugin */
122 if( module_exists( "goom" ) )
124 val.psz_string = (char*)"goom"; text.psz_string = (char*)"Goom";
125 var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
128 /* Look for libprojectM plugin */
129 if( module_exists( "projectm" ) )
131 val.psz_string = (char*)"projectm"; text.psz_string = (char*)"projectM";
132 var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
135 if( var_Get( p_aout, "effect-list", &val ) == VLC_SUCCESS )
137 var_SetString( p_aout, "visual", val.psz_string );
138 free( val.psz_string );
141 var_AddCallback( p_aout, "visual", VisualizationCallback, p_input );
143 if( var_Type( p_aout, "equalizer" ) == 0 )
145 module_config_t *p_config;
148 var_Create( p_aout, "equalizer",
149 VLC_VAR_STRING | VLC_VAR_HASCHOICE );
150 p_config = config_FindConfig( VLC_OBJECT(p_aout), "equalizer-preset" );
151 if( p_config && p_config->i_list )
153 text.psz_string = _("Equalizer");
154 var_Change( p_aout, "equalizer", VLC_VAR_SETTEXT, &text, NULL );
156 val.psz_string = (char*)""; text.psz_string = _("Disable");
157 var_Change( p_aout, "equalizer", VLC_VAR_ADDCHOICE, &val, &text );
159 for( i = 0; i < p_config->i_list; i++ )
161 val.psz_string = (char *)p_config->ppsz_list[i];
162 text.psz_string = (char *)p_config->ppsz_list_text[i];
163 var_Change( p_aout, "equalizer", VLC_VAR_ADDCHOICE,
169 var_AddCallback( p_aout, "equalizer", EqualizerCallback, p_input );
171 if( var_Type( p_aout, "audio-filter" ) == 0 )
173 var_Create( p_aout, "audio-filter",
174 VLC_VAR_STRING | VLC_VAR_DOINHERIT );
175 text.psz_string = _("Audio filters");
176 var_Change( p_aout, "audio-filter", VLC_VAR_SETTEXT, &text, NULL );
178 if( var_Type( p_aout, "audio-visual" ) == 0 )
180 var_Create( p_aout, "audio-visual",
181 VLC_VAR_STRING | VLC_VAR_DOINHERIT );
182 text.psz_string = _("Audio visualizations");
183 var_Change( p_aout, "audio-visual", VLC_VAR_SETTEXT, &text, NULL );
186 if( var_Type( p_aout, "audio-replay-gain-mode" ) == 0 )
188 module_config_t *p_config;
191 p_config = config_FindConfig( VLC_OBJECT(p_aout), "audio-replay-gain-mode" );
192 if( p_config && p_config->i_list )
194 var_Create( p_aout, "audio-replay-gain-mode",
195 VLC_VAR_STRING | VLC_VAR_DOINHERIT );
197 text.psz_string = _("Replay gain");
198 var_Change( p_aout, "audio-replay-gain-mode", VLC_VAR_SETTEXT, &text, NULL );
200 for( i = 0; i < p_config->i_list; i++ )
202 val.psz_string = (char *)p_config->ppsz_list[i];
203 text.psz_string = (char *)p_config->ppsz_list_text[i];
204 var_Change( p_aout, "audio-replay-gain-mode", VLC_VAR_ADDCHOICE,
209 var_AddCallback( p_aout, "audio-replay-gain-mode", ReplayGainCallback, p_input );
211 char *gain = var_InheritString (p_aout, "audio-replay-gain-mode");
212 vlc_atomic_setf (&p_input->multiplier,
213 ReplayGainSelect (VLC_OBJECT(p_aout), gain,
214 &p_input->replay_gain));
217 if( var_Type( p_aout, "audio-replay-gain-preamp" ) == 0 )
219 var_Create( p_aout, "audio-replay-gain-preamp",
220 VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
222 if( var_Type( p_aout, "audio-replay-gain-default" ) == 0 )
224 var_Create( p_aout, "audio-replay-gain-default",
225 VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
227 if( var_Type( p_aout, "audio-replay-gain-peak-protection" ) == 0 )
229 var_Create( p_aout, "audio-replay-gain-peak-protection",
230 VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
233 psz_filters = var_GetString( p_aout, "audio-filter" );
234 psz_visual = var_GetString( p_aout, "audio-visual");
235 psz_scaletempo = var_InheritBool( p_aout, "audio-time-stretch" ) ? strdup( "scaletempo" ) : NULL;
237 p_input->b_recycle_vout = psz_visual && *psz_visual;
239 /* parse user filter lists */
240 char *const ppsz_array[] = { psz_scaletempo, psz_filters, psz_visual };
241 p_input->p_playback_rate_filter = NULL;
243 for( i_visual = 0; i_visual < 3 && AOUT_FMT_LINEAR(&chain_output_format); i_visual++ )
245 char *psz_next = NULL;
246 char *psz_parser = ppsz_array[i_visual];
248 if( psz_parser == NULL || !*psz_parser )
251 while( psz_parser && *psz_parser )
253 filter_t * p_filter = NULL;
255 if( p_input->i_nb_filters >= AOUT_MAX_FILTERS )
257 msg_Dbg( p_aout, "max filters reached (%d)", AOUT_MAX_FILTERS );
261 while( *psz_parser == ' ' && *psz_parser == ':' )
265 if( ( psz_next = strchr( psz_parser , ':' ) ) )
269 if( *psz_parser =='\0' )
274 /* Create a VLC object */
275 p_filter = vlc_custom_create( p_aout, sizeof(*p_filter),
277 if( p_filter == NULL )
279 msg_Err( p_aout, "cannot add user filter %s (skipped)",
281 psz_parser = psz_next;
285 p_filter->p_owner = malloc( sizeof(*p_filter->p_owner) );
286 p_filter->p_owner->p_aout = p_aout;
287 p_filter->p_owner->p_input = p_input;
290 memcpy( &p_filter->fmt_in.audio, &chain_output_format,
291 sizeof(audio_sample_format_t) );
292 p_filter->fmt_in.i_codec = chain_output_format.i_format;
293 memcpy( &p_filter->fmt_out.audio, &chain_output_format,
294 sizeof(audio_sample_format_t) );
295 p_filter->fmt_out.i_codec = chain_output_format.i_format;
296 p_filter->pf_audio_buffer_new = aout_FilterBufferNew;
298 /* try to find the requested filter */
299 if( i_visual == 2 ) /* this can only be a visualization module */
301 p_filter->p_module = module_need( p_filter, "visualization2",
304 else /* this can be a audio filter module as well as a visualization module */
306 p_filter->p_module = module_need( p_filter, "audio filter",
309 if ( p_filter->p_module == NULL )
311 /* if the filter requested a special format, retry */
312 if ( !( AOUT_FMTS_IDENTICAL( &p_filter->fmt_in.audio,
313 &chain_input_format )
314 && AOUT_FMTS_IDENTICAL( &p_filter->fmt_out.audio,
315 &chain_output_format ) ) )
317 aout_FormatPrepare( &p_filter->fmt_in.audio );
318 aout_FormatPrepare( &p_filter->fmt_out.audio );
319 p_filter->p_module = module_need( p_filter,
323 /* try visual filters */
326 memcpy( &p_filter->fmt_in.audio, &chain_output_format,
327 sizeof(audio_sample_format_t) );
328 memcpy( &p_filter->fmt_out.audio, &chain_output_format,
329 sizeof(audio_sample_format_t) );
330 p_filter->p_module = module_need( p_filter,
338 if ( p_filter->p_module == NULL )
340 msg_Err( p_aout, "cannot add user filter %s (skipped)",
343 free( p_filter->p_owner );
344 vlc_object_release( p_filter );
346 psz_parser = psz_next;
350 /* complete the filter chain if necessary */
351 if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
352 &p_input->i_nb_filters,
354 &p_filter->fmt_in.audio ) < 0 )
356 msg_Err( p_aout, "cannot add user filter %s (skipped)",
359 module_unneed( p_filter, p_filter->p_module );
360 free( p_filter->p_owner );
361 vlc_object_release( p_filter );
363 psz_parser = psz_next;
368 p_input->pp_filters[p_input->i_nb_filters++] = p_filter;
369 memcpy( &chain_input_format, &p_filter->fmt_out.audio,
370 sizeof( audio_sample_format_t ) );
372 if( i_visual == 0 ) /* scaletempo */
373 p_input->p_playback_rate_filter = p_filter;
375 /* next filter if any */
376 psz_parser = psz_next;
381 free( psz_scaletempo );
383 /* complete the filter chain if necessary */
384 if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
385 &p_input->i_nb_filters,
387 &chain_output_format ) < 0 )
389 inputFailure( p_aout, p_input, "couldn't set an input pipeline" );
393 /* Create resamplers. */
394 if (AOUT_FMT_LINEAR(outfmt))
396 chain_output_format.i_rate = (__MAX(p_input->samplerate,
398 * (100 + AOUT_MAX_RESAMPLING)) / 100;
399 if ( chain_output_format.i_rate == outfmt->i_rate )
401 /* Just in case... */
402 chain_output_format.i_rate++;
404 if (aout_FiltersCreatePipeline (p_aout, p_input->pp_resamplers,
405 &p_input->i_nb_resamplers,
406 &chain_output_format, outfmt) < 0)
408 inputFailure( p_aout, p_input, "couldn't set a resampler pipeline");
412 /* Setup the initial rate of the resampler */
413 p_input->pp_resamplers[0]->fmt_in.audio.i_rate = p_input->samplerate;
415 p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
417 if( ! p_input->p_playback_rate_filter && p_input->i_nb_resamplers > 0 )
419 p_input->p_playback_rate_filter = p_input->pp_resamplers[0];
423 p_input->b_error = false;
424 p_input->i_last_input_rate = INPUT_RATE_DEFAULT;
429 /*****************************************************************************
430 * aout_InputDelete : delete an input
431 *****************************************************************************
432 * This function must be entered with the mixer lock.
433 *****************************************************************************/
434 int aout_InputDelete( audio_output_t * p_aout, aout_input_t * p_input )
436 aout_assert_locked( p_aout );
437 if ( p_input->b_error )
440 var_DelCallback (p_aout, "audio-replay-gain-mode", ReplayGainCallback,
442 var_DelCallback (p_aout, "equalizer", EqualizerCallback, p_input);
443 var_DelCallback (p_aout, "visual", VisualizationCallback, p_input);
445 /* XXX We need to update b_recycle_vout before calling aout_FiltersDestroyPipeline.
446 * FIXME They can be a race condition if audio-visual is updated between
447 * aout_InputDelete and aout_InputNew.
449 char *psz_visual = var_GetString( p_aout, "audio-visual");
450 p_input->b_recycle_vout = psz_visual && *psz_visual;
453 aout_FiltersDestroyPipeline( p_input->pp_filters, p_input->i_nb_filters );
454 p_input->i_nb_filters = 0;
455 aout_FiltersDestroyPipeline( p_input->pp_resamplers,
456 p_input->i_nb_resamplers );
457 p_input->i_nb_resamplers = 0;
462 /*****************************************************************************
463 * aout_InputPlay : play a buffer
464 *****************************************************************************
465 * This function must be entered with the input lock.
466 *****************************************************************************/
467 /* XXX Do not activate it !! */
468 //#define AOUT_PROCESS_BEFORE_CHEKS
469 block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
470 block_t *p_buffer, int i_input_rate, date_t *date )
474 aout_assert_locked( p_aout );
476 if( i_input_rate != INPUT_RATE_DEFAULT && p_input->p_playback_rate_filter == NULL )
478 inputDrop( p_input, p_buffer );
482 #ifdef AOUT_PROCESS_BEFORE_CHEKS
483 /* Run pre-filters. */
484 aout_FiltersPlay( p_aout, p_input->pp_filters, p_input->i_nb_filters,
489 /* Actually run the resampler now. */
490 if ( p_input->i_nb_resamplers > 0 )
492 const mtime_t i_date = p_buffer->i_pts;
493 aout_FiltersPlay( p_aout, p_input->pp_resamplers,
494 p_input->i_nb_resamplers,
500 if( p_buffer->i_nb_samples <= 0 )
502 block_Release( p_buffer );
507 /* Handle input rate change, but keep drift correction */
508 if( i_input_rate != p_input->i_last_input_rate )
510 unsigned int * const pi_rate = &p_input->p_playback_rate_filter->fmt_in.audio.i_rate;
511 #define F(r,ir) ( INPUT_RATE_DEFAULT * (r) / (ir) )
512 const int i_delta = *pi_rate - F(p_input->samplerate,p_input->i_last_input_rate);
513 *pi_rate = F(p_input->samplerate + i_delta, i_input_rate);
515 p_input->i_last_input_rate = i_input_rate;
518 mtime_t now = mdate();
520 /* We don't care if someone changes the start date behind our back after
521 * this. We'll deal with that when pushing the buffer, and compensate
522 * with the next incoming buffer. */
523 start_date = date_Get (date);
525 if ( start_date != VLC_TS_INVALID && start_date < now )
527 /* The decoder is _very_ late. This can only happen if the user
528 * pauses the stream (or if the decoder is buggy, which cannot
530 msg_Warn( p_aout, "computed PTS is out of range (%"PRId64"), "
531 "clearing out", now - start_date );
532 aout_OutputFlush( p_aout, false );
533 if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
534 msg_Warn( p_aout, "timing screwed, stopping resampling" );
535 inputResamplingStop( p_input );
536 p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
537 start_date = VLC_TS_INVALID;
540 if ( p_buffer->i_pts < now + AOUT_MIN_PREPARE_TIME )
542 /* The decoder gives us f*cked up PTS. It's its business, but we
543 * can't present it anyway, so drop the buffer. */
544 msg_Warn( p_aout, "PTS is out of range (%"PRId64"), dropping buffer",
545 now - p_buffer->i_pts );
546 inputDrop( p_input, p_buffer );
547 inputResamplingStop( p_input );
551 /* If the audio drift is too big then it's not worth trying to resample
553 if( start_date == VLC_TS_INVALID )
555 start_date = p_buffer->i_pts;
556 date_Set (date, start_date);
559 mtime_t drift = start_date - p_buffer->i_pts;
561 if( drift < -i_input_rate * 3 * AOUT_MAX_PTS_ADVANCE / INPUT_RATE_DEFAULT )
563 msg_Warn( p_aout, "buffer way too early (%"PRId64"), clearing queue",
565 aout_OutputFlush( p_aout, false );
566 if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
567 msg_Warn( p_aout, "timing screwed, stopping resampling" );
568 inputResamplingStop( p_input );
569 p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
570 start_date = p_buffer->i_pts;
571 date_Set (date, start_date);
575 if( drift > +i_input_rate * 3 * AOUT_MAX_PTS_DELAY / INPUT_RATE_DEFAULT )
577 msg_Warn( p_aout, "buffer way too late (%"PRId64"), dropping buffer",
579 inputDrop( p_input, p_buffer );
583 #ifndef AOUT_PROCESS_BEFORE_CHEKS
584 /* Run pre-filters. */
585 aout_FiltersPlay( p_input->pp_filters, p_input->i_nb_filters, &p_buffer );
590 /* Run the resampler if needed.
591 * We first need to calculate the output rate of this resampler. */
592 if ( ( p_input->i_resampling_type == AOUT_RESAMPLING_NONE ) &&
593 ( drift < -AOUT_MAX_PTS_ADVANCE || drift > +AOUT_MAX_PTS_DELAY ) &&
594 p_input->i_nb_resamplers > 0 )
596 /* Can happen in several circumstances :
597 * 1. A problem at the input (clock drift)
598 * 2. A small pause triggered by the user
599 * 3. Some delay in the output stage, causing a loss of lip
601 * Solution : resample the buffer to avoid a scratch.
603 p_input->i_resamp_start_date = now;
604 p_input->i_resamp_start_drift = (int)-drift;
605 p_input->i_resampling_type = (drift < 0) ? AOUT_RESAMPLING_DOWN
606 : AOUT_RESAMPLING_UP;
607 msg_Warn( p_aout, (drift < 0)
608 ? "buffer too early (%"PRId64"), down-sampling"
609 : "buffer too late (%"PRId64"), up-sampling", drift );
612 if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
614 /* Resampling has been triggered previously (because of dates
615 * mismatch). We want the resampling to happen progressively so
616 * it isn't too audible to the listener. */
618 if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
619 p_input->pp_resamplers[0]->fmt_in.audio.i_rate += 2; /* Hz */
621 p_input->pp_resamplers[0]->fmt_in.audio.i_rate -= 2; /* Hz */
623 /* Check if everything is back to normal, in which case we can stop the
625 unsigned int i_nominal_rate =
626 (p_input->pp_resamplers[0] == p_input->p_playback_rate_filter)
627 ? INPUT_RATE_DEFAULT * p_input->samplerate / i_input_rate
628 : p_input->samplerate;
629 if( p_input->pp_resamplers[0]->fmt_in.audio.i_rate == i_nominal_rate )
631 p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
632 msg_Warn( p_aout, "resampling stopped after %"PRIi64" usec "
633 "(drift: %"PRIi64")",
634 now - p_input->i_resamp_start_date,
635 p_buffer->i_pts - start_date);
637 else if( abs( (int)(p_buffer->i_pts - start_date) ) <
638 abs( p_input->i_resamp_start_drift ) / 2 )
640 /* if we reduced the drift from half, then it is time to switch
641 * back the resampling direction. */
642 if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
643 p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
645 p_input->i_resampling_type = AOUT_RESAMPLING_UP;
646 p_input->i_resamp_start_drift = 0;
648 else if( p_input->i_resamp_start_drift &&
649 ( abs( (int)(p_buffer->i_pts - start_date) ) >
650 abs( p_input->i_resamp_start_drift ) * 3 / 2 ) )
652 /* If the drift is increasing and not decreasing, than something
653 * is bad. We'd better stop the resampling right now. */
654 msg_Warn( p_aout, "timing screwed, stopping resampling" );
655 inputResamplingStop( p_input );
656 p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
660 #ifndef AOUT_PROCESS_BEFORE_CHEKS
661 /* Actually run the resampler now. */
662 if ( p_input->i_nb_resamplers > 0 )
664 aout_FiltersPlay( p_input->pp_resamplers, p_input->i_nb_resamplers,
670 if( p_buffer->i_nb_samples <= 0 )
672 block_Release( p_buffer );
677 p_buffer->i_pts = start_date;
681 /*****************************************************************************
683 *****************************************************************************/
685 static void inputFailure( audio_output_t * p_aout, aout_input_t * p_input,
686 const char * psz_error_message )
689 msg_Err( p_aout, "%s", psz_error_message );
692 aout_FiltersDestroyPipeline( p_input->pp_filters, p_input->i_nb_filters );
693 aout_FiltersDestroyPipeline( p_input->pp_resamplers,
694 p_input->i_nb_resamplers );
695 var_Destroy( p_aout, "visual" );
696 var_Destroy( p_aout, "equalizer" );
697 var_Destroy( p_aout, "audio-filter" );
698 var_Destroy( p_aout, "audio-visual" );
700 var_Destroy( p_aout, "audio-replay-gain-mode" );
701 var_Destroy( p_aout, "audio-replay-gain-default" );
702 var_Destroy( p_aout, "audio-replay-gain-preamp" );
703 var_Destroy( p_aout, "audio-replay-gain-peak-protection" );
706 p_input->b_error = 1;
709 static void inputDrop( aout_input_t *p_input, aout_buffer_t *p_buffer )
711 aout_BufferFree( p_buffer );
713 p_input->i_buffer_lost++;
716 static void inputResamplingStop( aout_input_t *p_input )
718 p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
719 if( p_input->i_nb_resamplers != 0 )
721 p_input->pp_resamplers[0]->fmt_in.audio.i_rate =
722 ( p_input->pp_resamplers[0] == p_input->p_playback_rate_filter )
723 ? INPUT_RATE_DEFAULT * p_input->samplerate / p_input->i_last_input_rate
724 : p_input->samplerate;
728 static vout_thread_t *RequestVout( void *p_private,
729 vout_thread_t *p_vout, video_format_t *p_fmt, bool b_recycle )
731 audio_output_t *p_aout = p_private;
732 VLC_UNUSED(b_recycle);
733 vout_configuration_t cfg = {
740 return vout_Request( p_aout, &cfg );
743 vout_thread_t *aout_filter_RequestVout( filter_t *p_filter,
744 vout_thread_t *p_vout, video_format_t *p_fmt )
746 aout_input_t *p_input = p_filter->p_owner->p_input;
747 aout_request_vout_t *p_request = &p_input->request_vout;
749 /* XXX: this only works from audio input */
750 /* If you want to use visualization filters from another place, you will
751 * need to add a new pf_aout_request_vout callback or store a pointer
752 * to aout_request_vout_t inside filter_t (i.e. a level of indirection). */
754 return p_request->pf_request_vout( p_request->p_private,
755 p_vout, p_fmt, p_input->b_recycle_vout );
758 static inline bool ChangeFiltersString (vlc_object_t *aout, const char *var,
759 const char *filter, bool add)
761 return aout_ChangeFilterString (aout, aout, var, filter, add);
764 static int VisualizationCallback (vlc_object_t *obj, char const *var,
765 vlc_value_t oldval, vlc_value_t newval,
768 const char *mode = newval.psz_string;
769 //aout_input_t *input = data;
774 ChangeFiltersString (obj, "audio-visual", "goom", false);
775 ChangeFiltersString (obj, "audio-visual", "visual", false);
776 ChangeFiltersString (obj, "audio-visual", "projectm", false);
778 else if (!strcmp ("goom", mode))
780 ChangeFiltersString (obj, "audio-visual", "visual", false );
781 ChangeFiltersString (obj, "audio-visual", "goom", true );
782 ChangeFiltersString (obj, "audio-visual", "projectm", false );
784 else if (!strcmp ("projectm", mode))
786 ChangeFiltersString (obj, "audio-visual", "visual", false);
787 ChangeFiltersString (obj, "audio-visual", "goom", false);
788 ChangeFiltersString (obj, "audio-visual", "projectm", true);
792 var_Create (obj, "effect-list", VLC_VAR_STRING);
793 var_SetString (obj, "effect-list", mode);
795 ChangeFiltersString (obj, "audio-visual", "goom", false);
796 ChangeFiltersString (obj, "audio-visual", "visual", true);
797 ChangeFiltersString (obj, "audio-visual", "projectm", false);
800 /* That sucks FIXME: use "input" instead of cast */
801 aout_InputRequestRestart ((audio_output_t *)obj);
803 (void) var; (void) oldval;
807 static int EqualizerCallback (vlc_object_t *obj, char const *cmd,
808 vlc_value_t oldval, vlc_value_t newval,
811 char *mode = newval.psz_string;
812 //aout_input_t *input = data;
816 (void) cmd; (void) oldval;
818 ret = ChangeFiltersString (obj, "audio-filter", "equalizer", false);
821 var_Create (obj, "equalizer-preset", VLC_VAR_STRING);
822 var_SetString (obj, "equalizer-preset", mode);
823 ret = ChangeFiltersString (obj, "audio-filter", "equalizer", true);
828 aout_InputRequestRestart ((audio_output_t *)obj);
832 float aout_InputGetMultiplier (const aout_input_t *input)
834 return vlc_atomic_getf (&input->multiplier);
837 static int ReplayGainCallback (vlc_object_t *obj, char const *var,
838 vlc_value_t oldval, vlc_value_t val, void *data)
840 aout_input_t *input = data;
841 float multiplier = ReplayGainSelect (obj, val.psz_string,
842 &input->replay_gain);
844 vlc_atomic_setf (&input->multiplier, multiplier);
846 VLC_UNUSED(var); VLC_UNUSED(oldval);
850 static float ReplayGainSelect (vlc_object_t *obj, const char *str,
851 const audio_replay_gain_t *replay_gain)
854 unsigned mode = AUDIO_REPLAY_GAIN_MAX;
856 if (likely(str != NULL))
857 { /* Find selectrf mode */
858 if (!strcmp (str, "track"))
859 mode = AUDIO_REPLAY_GAIN_TRACK;
861 if (!strcmp (str, "album"))
862 mode = AUDIO_REPLAY_GAIN_ALBUM;
864 /* If the selectrf mode is not available, prefer the other one */
865 if (mode != AUDIO_REPLAY_GAIN_MAX && !replay_gain->pb_gain[mode])
867 if (replay_gain->pb_gain[!mode])
873 if (mode == AUDIO_REPLAY_GAIN_MAX)
876 if (replay_gain->pb_gain[mode])
877 gain = replay_gain->pf_gain[mode]
878 + var_InheritFloat (obj, "audio-replay-gain-preamp");
880 gain = var_InheritFloat (obj, "audio-replay-gain-default");
882 float multiplier = pow (10., gain / 20.);
884 if (replay_gain->pb_peak[mode]
885 && var_InheritBool (obj, "audio-replay-gain-peak-protection")
886 && replay_gain->pf_peak[mode] * multiplier > 1.0)
887 multiplier = 1.0f / replay_gain->pf_peak[mode];