1 /*****************************************************************************
2 * intf.c : audio output API towards the interface modules
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 *****************************************************************************/
32 #include <vlc_common.h>
35 #include <stdlib.h> /* calloc(), malloc(), free() */
39 #include "aout_internal.h"
41 #include <vlc_playlist.h>
43 static aout_instance_t
*findAout (vlc_object_t
*obj
)
45 input_thread_t
*(*pf_find_input
) (vlc_object_t
*);
47 pf_find_input
= var_GetAddress (obj
, "find-input-callback");
48 if (unlikely(pf_find_input
== NULL
))
51 input_thread_t
*p_input
= pf_find_input (obj
);
55 aout_instance_t
*p_aout
= input_GetAout (p_input
);
56 vlc_object_release (p_input
);
59 #define findAout(o) findAout(VLC_OBJECT(o))
64 * The hardware volume cannot be set if the output module gets deleted, so
65 * we must take the mixer lock. The software volume cannot be set while the
66 * mixer is running, so we need the mixer lock (too).
68 * Here is a schematic of the i_volume range :
70 * |------------------------------+---------------------------------------|
73 * Between 0 and pi_soft, the volume is done in hardware by the output
74 * module. Above, the output module will change p_aout->mixer.i_multiplier
75 * (done in software). This scaling may result * in cropping errors and
76 * should be avoided as much as possible.
78 * It is legal to have *pi_soft == 0, and do everything in software.
79 * It is also legal to have *pi_soft == 1024, and completely avoid
80 * software scaling. However, some streams (esp. A/52) are encoded with
81 * a very low volume and users may complain.
91 /*****************************************************************************
92 * doVolumeChanges : handle all volume changes. Internal use only to ease
94 *****************************************************************************/
96 int doVolumeChanges( unsigned action
, vlc_object_t
* p_object
, int i_nb_steps
,
97 audio_volume_t i_volume
, audio_volume_t
* i_return_volume
,
100 int i_result
= VLC_SUCCESS
;
101 int i_volume_step
= 1, i_new_volume
= 0;
102 bool b_var_mute
= false;
103 aout_instance_t
*p_aout
= findAout( p_object
);
105 if ( p_aout
) aout_lock_volume( p_aout
);
107 b_var_mute
= var_GetBool( p_object
, "volume-muted");
109 const bool b_unmute_condition
= ( b_var_mute
110 && ( /* Unmute: on increments */
111 ( action
== INCREMENT_VOLUME
)
112 || /* On explicit unmute */
113 ( ( action
== SET_MUTE
) && !b_mute
)
114 || /* On toggle from muted */
115 ( action
== TOGGLE_MUTE
)
118 const bool b_mute_condition
= ( !b_var_mute
120 ( ( action
== SET_MUTE
) && b_mute
)
122 ( action
== TOGGLE_MUTE
)
125 /* If muting or unmuting when play hasn't started */
126 if ( action
== SET_MUTE
&& !b_unmute_condition
&& !b_mute_condition
)
130 aout_unlock_volume( p_aout
);
131 vlc_object_release( p_aout
);
137 if ( b_unmute_condition
)
139 /* Restore saved volume */
140 i_volume
= var_GetInteger( p_object
, "saved-volume" );
141 var_SetBool( p_object
, "volume-muted", false );
143 else if ( b_mute_condition
)
145 /* We need an initial value to backup later */
146 i_volume
= config_GetInt( p_object
, "volume" );
149 if ( action
== INCREMENT_VOLUME
)
151 i_volume_step
= var_InheritInteger( p_object
, "volume-step" );
153 if ( !b_unmute_condition
)
154 i_volume
= config_GetInt( p_object
, "volume" );
156 i_new_volume
= (int) i_volume
+ i_volume_step
* i_nb_steps
;
158 if ( i_new_volume
> AOUT_VOLUME_MAX
)
159 i_volume
= AOUT_VOLUME_MAX
;
160 else if ( i_new_volume
< AOUT_VOLUME_MIN
)
161 i_volume
= AOUT_VOLUME_MIN
;
163 i_volume
= i_new_volume
;
166 var_SetInteger( p_object
, "saved-volume" , i_volume
);
169 if ( b_mute_condition
)
171 i_volume
= AOUT_VOLUME_MIN
;
172 var_SetBool( p_object
, "volume-muted", true );
175 /* Commit volume changes */
176 config_PutInt( p_object
, "volume", i_volume
);
180 aout_lock_mixer( p_aout
);
181 aout_lock_input_fifos( p_aout
);
182 if ( p_aout
->p_mixer
)
183 i_result
= p_aout
->output
.pf_volume_set( p_aout
, i_volume
);
184 aout_unlock_input_fifos( p_aout
);
185 aout_unlock_mixer( p_aout
);
188 /* trigger callbacks */
189 var_TriggerCallback( p_object
, "volume-change" );
192 var_SetBool( p_aout
, "intf-change", true );
193 aout_unlock_volume( p_aout
);
194 vlc_object_release( p_aout
);
197 if ( i_return_volume
!= NULL
)
198 *i_return_volume
= i_volume
;
202 #undef aout_VolumeGet
203 /*****************************************************************************
204 * aout_VolumeGet : get the volume of the output device
205 *****************************************************************************/
206 int aout_VolumeGet( vlc_object_t
* p_object
, audio_volume_t
* pi_volume
)
209 aout_instance_t
* p_aout
= findAout( p_object
);
211 if ( pi_volume
== NULL
) return -1;
213 if ( p_aout
== NULL
)
215 *pi_volume
= (audio_volume_t
)config_GetInt( p_object
, "volume" );
219 aout_lock_volume( p_aout
);
220 aout_lock_mixer( p_aout
);
221 if ( p_aout
->p_mixer
)
223 i_result
= p_aout
->output
.pf_volume_get( p_aout
, pi_volume
);
227 *pi_volume
= (audio_volume_t
)config_GetInt( p_object
, "volume" );
229 aout_unlock_mixer( p_aout
);
230 aout_unlock_volume( p_aout
);
232 vlc_object_release( p_aout
);
236 #undef aout_VolumeSet
237 /*****************************************************************************
238 * aout_VolumeSet : set the volume of the output device
239 *****************************************************************************/
240 int aout_VolumeSet( vlc_object_t
* p_object
, audio_volume_t i_volume
)
242 return doVolumeChanges( SET_VOLUME
, p_object
, 1, i_volume
, NULL
, true );
246 /*****************************************************************************
247 * aout_VolumeUp : raise the output volume
248 *****************************************************************************
249 * If pi_volume != NULL, *pi_volume will contain the volume at the end of the
251 *****************************************************************************/
252 int aout_VolumeUp( vlc_object_t
* p_object
, int i_nb_steps
,
253 audio_volume_t
* pi_volume
)
255 return doVolumeChanges( INCREMENT_VOLUME
, p_object
, i_nb_steps
, 0, pi_volume
, true );
258 #undef aout_VolumeDown
259 /*****************************************************************************
260 * aout_VolumeDown : lower the output volume
261 *****************************************************************************
262 * If pi_volume != NULL, *pi_volume will contain the volume at the end of the
264 *****************************************************************************/
265 int aout_VolumeDown( vlc_object_t
* p_object
, int i_nb_steps
,
266 audio_volume_t
* pi_volume
)
268 return aout_VolumeUp( p_object
, -i_nb_steps
, pi_volume
);
271 #undef aout_ToggleMute
272 /*****************************************************************************
273 * aout_ToggleMute : Mute/un-mute the output volume
274 *****************************************************************************
275 * If pi_volume != NULL, *pi_volume will contain the volume at the end of the
276 * function (muted => 0).
277 *****************************************************************************/
278 int aout_ToggleMute( vlc_object_t
* p_object
, audio_volume_t
* pi_volume
)
280 return doVolumeChanges( TOGGLE_MUTE
, p_object
, 1, 0, pi_volume
, true );
283 /*****************************************************************************
284 * aout_IsMuted : Get the output volume mute status
285 *****************************************************************************/
286 bool aout_IsMuted( vlc_object_t
* p_object
)
289 aout_instance_t
* p_aout
= findAout( p_object
);
290 if ( p_aout
) aout_lock_volume( p_aout
);
291 b_return_val
= var_GetBool( p_object
, "volume-muted");
294 aout_unlock_volume( p_aout
);
295 vlc_object_release( p_aout
);
300 /*****************************************************************************
301 * aout_SetMute : Sets mute status
302 *****************************************************************************
303 * If pi_volume != NULL, *pi_volume will contain the volume at the end of the
304 * function (muted => 0).
305 *****************************************************************************/
306 int aout_SetMute( vlc_object_t
* p_object
, audio_volume_t
* pi_volume
,
309 return doVolumeChanges( SET_MUTE
, p_object
, 1, 0, pi_volume
, b_mute
);
313 * The next functions are not supposed to be called by the interface, but
314 * are placeholders for software-only scaling.
317 /* Meant to be called by the output plug-in's Open(). */
318 void aout_VolumeSoftInit( aout_instance_t
* p_aout
)
322 p_aout
->output
.pf_volume_get
= aout_VolumeSoftGet
;
323 p_aout
->output
.pf_volume_set
= aout_VolumeSoftSet
;
325 i_volume
= config_GetInt( p_aout
, "volume" );
326 if ( i_volume
< AOUT_VOLUME_MIN
)
328 i_volume
= AOUT_VOLUME_DEFAULT
;
330 else if ( i_volume
> AOUT_VOLUME_MAX
)
332 i_volume
= AOUT_VOLUME_MAX
;
335 aout_VolumeSoftSet( p_aout
, (audio_volume_t
)i_volume
);
338 /* Placeholder for pf_volume_get(). */
339 int aout_VolumeSoftGet( aout_instance_t
* p_aout
, audio_volume_t
* pi_volume
)
341 *pi_volume
= p_aout
->output
.i_volume
;
346 /* Placeholder for pf_volume_set(). */
347 int aout_VolumeSoftSet( aout_instance_t
* p_aout
, audio_volume_t i_volume
)
349 aout_MixerMultiplierSet( p_aout
, (float)i_volume
/ AOUT_VOLUME_DEFAULT
);
350 p_aout
->output
.i_volume
= i_volume
;
355 * The next functions are not supposed to be called by the interface, but
356 * are placeholders for unsupported scaling.
359 /* Meant to be called by the output plug-in's Open(). */
360 void aout_VolumeNoneInit( aout_instance_t
* p_aout
)
362 p_aout
->output
.pf_volume_get
= aout_VolumeNoneGet
;
363 p_aout
->output
.pf_volume_set
= aout_VolumeNoneSet
;
366 /* Placeholder for pf_volume_get(). */
367 int aout_VolumeNoneGet( aout_instance_t
* p_aout
, audio_volume_t
* pi_volume
)
369 (void)p_aout
; (void)pi_volume
;
373 /* Placeholder for pf_volume_set(). */
374 int aout_VolumeNoneSet( aout_instance_t
* p_aout
, audio_volume_t i_volume
)
376 (void)p_aout
; (void)i_volume
;
382 * Pipelines management
385 /*****************************************************************************
386 * aout_Restart : re-open the output device and rebuild the input and output
388 *****************************************************************************
389 * This function is used whenever the parameters of the output plug-in are
390 * changed (eg. selecting S/PDIF or PCM).
391 *****************************************************************************/
392 static int aout_Restart( aout_instance_t
* p_aout
)
397 aout_lock_mixer( p_aout
);
399 if ( p_aout
->i_nb_inputs
== 0 )
401 aout_unlock_mixer( p_aout
);
402 msg_Err( p_aout
, "no decoder thread" );
406 for ( i
= 0; i
< p_aout
->i_nb_inputs
; i
++ )
408 aout_lock_input( p_aout
, p_aout
->pp_inputs
[i
] );
409 aout_lock_input_fifos( p_aout
);
410 aout_InputDelete( p_aout
, p_aout
->pp_inputs
[i
] );
411 aout_unlock_input_fifos( p_aout
);
414 /* Lock all inputs. */
415 aout_lock_input_fifos( p_aout
);
416 aout_MixerDelete( p_aout
);
418 /* Re-open the output plug-in. */
419 aout_OutputDelete( p_aout
);
421 if ( aout_OutputNew( p_aout
, &p_aout
->pp_inputs
[0]->input
) == -1 )
423 /* Release all locks and report the error. */
424 for ( i
= 0; i
< p_aout
->i_nb_inputs
; i
++ )
426 vlc_mutex_unlock( &p_aout
->pp_inputs
[i
]->lock
);
428 aout_unlock_input_fifos( p_aout
);
429 aout_unlock_mixer( p_aout
);
433 if ( aout_MixerNew( p_aout
) == -1 )
435 aout_OutputDelete( p_aout
);
436 for ( i
= 0; i
< p_aout
->i_nb_inputs
; i
++ )
438 vlc_mutex_unlock( &p_aout
->pp_inputs
[i
]->lock
);
440 aout_unlock_input_fifos( p_aout
);
441 aout_unlock_mixer( p_aout
);
445 /* Re-open all inputs. */
446 for ( i
= 0; i
< p_aout
->i_nb_inputs
; i
++ )
448 aout_input_t
* p_input
= p_aout
->pp_inputs
[i
];
449 b_error
|= aout_InputNew( p_aout
, p_input
, &p_input
->request_vout
);
450 p_input
->b_changed
= 1;
451 aout_unlock_input( p_aout
, p_input
);
454 aout_unlock_input_fifos( p_aout
);
455 aout_unlock_mixer( p_aout
);
460 /*****************************************************************************
461 * aout_FindAndRestart : find the audio output instance and restart
462 *****************************************************************************
463 * This is used for callbacks of the configuration variables, and we believe
464 * that when those are changed, it is a significant change which implies
465 * rebuilding the audio-device and audio-channels variables.
466 *****************************************************************************/
467 int aout_FindAndRestart( vlc_object_t
* p_this
, const char *psz_name
,
468 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
470 aout_instance_t
* p_aout
= findAout( pl_Get(p_this
) );
472 (void)psz_name
; (void)oldval
; (void)newval
; (void)p_data
;
473 if ( p_aout
== NULL
) return VLC_SUCCESS
;
475 var_Destroy( p_aout
, "audio-device" );
476 var_Destroy( p_aout
, "audio-channels" );
478 aout_Restart( p_aout
);
479 vlc_object_release( p_aout
);
484 /*****************************************************************************
485 * aout_ChannelsRestart : change the audio device or channels and restart
486 *****************************************************************************/
487 int aout_ChannelsRestart( vlc_object_t
* p_this
, const char * psz_variable
,
488 vlc_value_t oldval
, vlc_value_t newval
,
491 aout_instance_t
* p_aout
= (aout_instance_t
*)p_this
;
492 (void)oldval
; (void)newval
; (void)p_data
;
494 if ( !strcmp( psz_variable
, "audio-device" ) )
496 /* This is supposed to be a significant change and supposes
497 * rebuilding the channel choices. */
498 var_Destroy( p_aout
, "audio-channels" );
500 aout_Restart( p_aout
);
504 #undef aout_EnableFilter
505 /** Enable or disable an audio filter
506 * \param p_this a vlc object
507 * \param psz_name name of the filter
508 * \param b_add are we adding or removing the filter ?
510 void aout_EnableFilter( vlc_object_t
*p_this
, const char *psz_name
,
513 aout_instance_t
*p_aout
= findAout( p_this
);
515 if( aout_ChangeFilterString( p_this
, p_aout
, "audio-filter", psz_name
, b_add
) )
518 AoutInputsMarkToRestart( p_aout
);
522 vlc_object_release( p_aout
);