X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Faudio_output%2Fintf.c;h=73cf2f276834871c419b2b435e816240d2b82f08;hb=2516061e583b6789c403bb9c8d73e5197c76b0f0;hp=850a5fce76e3ac983b4a19b2ee08e852ba6400f4;hpb=e27abe75a1d2017799af345709d0db0bcb172a36;p=vlc diff --git a/src/audio_output/intf.c b/src/audio_output/intf.c index 850a5fce76..73cf2f2768 100644 --- a/src/audio_output/intf.c +++ b/src/audio_output/intf.c @@ -1,8 +1,8 @@ /***************************************************************************** * intf.c : audio output API towards the interface modules ***************************************************************************** - * Copyright (C) 2002 VideoLAN - * $Id: intf.c,v 1.17 2003/02/12 14:22:23 hartman Exp $ + * Copyright (C) 2002-2007 the VideoLAN team + * $Id$ * * Authors: Christophe Massiot * @@ -18,289 +18,262 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include #include /* calloc(), malloc(), free() */ #include -#include - -#include "audio_output.h" +#include #include "aout_internal.h" +#include -/* - * Volume management - * - * The hardware volume cannot be set if the output module gets deleted, so - * we must take the mixer lock. The software volume cannot be set while the - * mixer is running, so we need the mixer lock (too). - * - * Here is a schematic of the i_volume range : - * - * |------------------------------+---------------------------------------| - * 0 pi_soft 1024 - * - * Between 0 and pi_soft, the volume is done in hardware by the output - * module. Above, the output module will change p_aout->mixer.i_multiplier - * (done in software). This scaling may result * in cropping errors and - * should be avoided as much as possible. - * - * It is legal to have *pi_soft == 0, and do everything in software. - * It is also legal to have *pi_soft == 1024, and completely avoid - * software scaling. However, some streams (esp. A/52) are encoded with - * a very low volume and users may complain. - */ - -/***************************************************************************** - * aout_VolumeGet : get the volume of the output device - *****************************************************************************/ -int __aout_VolumeGet( vlc_object_t * p_object, audio_volume_t * pi_volume ) +static audio_output_t *findAout (vlc_object_t *obj) { - int i; + input_thread_t *(*pf_find_input) (vlc_object_t *); - i = config_GetInt( p_object, "volume" ); - if ( pi_volume != NULL ) *pi_volume = (audio_volume_t)i; + pf_find_input = var_GetAddress (obj, "find-input-callback"); + if (unlikely(pf_find_input == NULL)) + return NULL; - return 0; + input_thread_t *p_input = pf_find_input (obj); + if (p_input == NULL) + return NULL; + + audio_output_t *p_aout = input_GetAout (p_input); + vlc_object_release (p_input); + return p_aout; } +#define findAout(o) findAout(VLC_OBJECT(o)) -/***************************************************************************** - * aout_VolumeSet : set the volume of the output device - *****************************************************************************/ -int __aout_VolumeSet( vlc_object_t * p_object, audio_volume_t i_volume ) +/** Start a volume change transaction. */ +static void prepareVolume (vlc_object_t *obj, audio_output_t **aoutp, + audio_volume_t *volp, bool *mutep) { - aout_instance_t * p_aout = vlc_object_find( p_object, VLC_OBJECT_AOUT, - FIND_ANYWHERE ); - int i_result = 0; - - config_PutInt( p_object, "volume", i_volume ); - - if ( p_aout == NULL ) return 0; - - vlc_mutex_lock( &p_aout->mixer_lock ); - if ( !p_aout->mixer.b_error ) - { - i_result = p_aout->output.pf_volume_set( p_aout, i_volume ); - } - vlc_mutex_unlock( &p_aout->mixer_lock ); - - vlc_object_release( p_aout ); - return i_result; + audio_output_t *aout = findAout (obj); + + /* FIXME: we need interlocking even if aout does not exist! */ + *aoutp = aout; + if (aout != NULL) + aout_lock_volume (aout); + if (volp != NULL) + *volp = var_GetInteger (obj, "volume"); + if (mutep != NULL) + *mutep = var_GetBool (obj, "mute"); } -/***************************************************************************** - * aout_VolumeInfos : get the boundary pi_soft - *****************************************************************************/ -int __aout_VolumeInfos( vlc_object_t * p_object, audio_volume_t * pi_soft ) +/** Commit a volume change transaction. */ +static int commitVolume (vlc_object_t *obj, audio_output_t *aout, + audio_volume_t volume, bool mute) { - aout_instance_t * p_aout = vlc_object_find( p_object, VLC_OBJECT_AOUT, - FIND_ANYWHERE ); - int i_result; + int ret = 0; - if ( p_aout == NULL ) return 0; + var_SetInteger (obj, "volume", volume); + var_SetBool (obj, "mute", mute); - vlc_mutex_lock( &p_aout->mixer_lock ); - if ( p_aout->mixer.b_error ) - { - /* The output module is destroyed. */ - i_result = -1; - } - else + if (aout != NULL) { - i_result = p_aout->output.pf_volume_infos( p_aout, pi_soft ); + float vol = volume / (float)AOUT_VOLUME_DEFAULT; + + aout_lock (aout); +#warning FIXME: wrong test. Need to check that aout_output is ready. + if (aout->p_mixer != NULL) + ret = aout->pf_volume_set (aout, vol, mute); + aout_unlock (aout); + + if (ret == 0) + var_TriggerCallback (aout, "intf-change"); + aout_unlock_volume (aout); + vlc_object_release (aout); } - vlc_mutex_unlock( &p_aout->mixer_lock ); - - vlc_object_release( p_aout ); - return i_result; + return ret; } -/***************************************************************************** - * aout_VolumeUp : raise the output volume - ***************************************************************************** - * If pi_volume != NULL, *pi_volume will contain the volume at the end of the - * function. - *****************************************************************************/ -int __aout_VolumeUp( vlc_object_t * p_object, int i_nb_steps, - audio_volume_t * pi_volume ) +#if 0 +/** Cancel a volume change transaction. */ +static void cancelVolume (vlc_object_t *obj, audio_output_t *aout) { - aout_instance_t * p_aout = vlc_object_find( p_object, VLC_OBJECT_AOUT, - FIND_ANYWHERE ); - int i_result = 0, i; - - i = config_GetInt( p_object, "volume" ); - i += AOUT_VOLUME_STEP * i_nb_steps; - if ( i > AOUT_VOLUME_MAX ) - { - i = AOUT_VOLUME_MAX; - } - config_PutInt( p_object, "volume", i ); - config_PutInt( p_object, "saved-volume", i ); - if ( pi_volume != NULL ) *pi_volume = (audio_volume_t)i; - - if ( p_aout == NULL ) return 0; - - vlc_mutex_lock( &p_aout->mixer_lock ); - if ( !p_aout->mixer.b_error ) + (void) obj; + if (aout != NULL) { - i_result = p_aout->output.pf_volume_set( p_aout, (audio_volume_t)i ); + aout_unlock_volume (aout); + vlc_object_release (aout); } - vlc_mutex_unlock( &p_aout->mixer_lock ); - - vlc_object_release( p_aout ); - return i_result; } +#endif -/***************************************************************************** - * aout_VolumeDown : lower the output volume - ***************************************************************************** - * If pi_volume != NULL, *pi_volume will contain the volume at the end of the - * function. - *****************************************************************************/ -int __aout_VolumeDown( vlc_object_t * p_object, int i_nb_steps, - audio_volume_t * pi_volume ) +#undef aout_VolumeGet +/** + * Gets the volume of the output device (independent of mute). + */ +audio_volume_t aout_VolumeGet (vlc_object_t *obj) { - aout_instance_t * p_aout = vlc_object_find( p_object, VLC_OBJECT_AOUT, - FIND_ANYWHERE ); - int i_result = 0, i; - - i = config_GetInt( p_object, "volume" ); - i -= AOUT_VOLUME_STEP * i_nb_steps; - if ( i < AOUT_VOLUME_MIN ) - { - i = AOUT_VOLUME_MIN; - } - config_PutInt( p_object, "volume", i ); - config_PutInt( p_object, "saved-volume", i ); - if ( pi_volume != NULL ) *pi_volume = (audio_volume_t)i; - - if ( p_aout == NULL ) return 0; - - vlc_mutex_lock( &p_aout->mixer_lock ); - if ( !p_aout->mixer.b_error ) - { - i_result = p_aout->output.pf_volume_set( p_aout, (audio_volume_t)i ); - } - vlc_mutex_unlock( &p_aout->mixer_lock ); +#if 0 + audio_output_t *aout; + audio_volume_t volume; - vlc_object_release( p_aout ); - return i_result; + prepareVolume (obj, &aout, &volume, NULL); + cancelVolume (obj, aout); + return 0; +#else + return var_GetInteger (obj, "volume"); +#endif } -/***************************************************************************** - * aout_VolumeMute : Mute/un-mute the output volume - ***************************************************************************** - * If pi_volume != NULL, *pi_volume will contain the volume at the end of the - * function (muted => 0). - *****************************************************************************/ -int __aout_VolumeMute( vlc_object_t * p_object, audio_volume_t * pi_volume ) +#undef aout_VolumeSet +/** + * Sets the volume of the output device. + * The mute status is not changed. + */ +int aout_VolumeSet (vlc_object_t *obj, audio_volume_t volume) { - int i_result; - audio_volume_t i_volume; - - i_volume = (audio_volume_t)config_GetInt( p_object, "volume" ); - if ( i_volume != 0 ) - { - /* Mute */ - i_result = aout_VolumeSet( p_object, AOUT_VOLUME_MIN ); - config_PutInt( p_object, "saved-volume", (int)i_volume ); - if ( pi_volume != NULL ) *pi_volume = AOUT_VOLUME_MIN; - } - else - { - /* Un-mute */ - i_volume = (audio_volume_t)config_GetInt( p_object, "saved-volume" ); - i_result = aout_VolumeSet( p_object, i_volume ); - if ( pi_volume != NULL ) *pi_volume = i_volume; - } + audio_output_t *aout; + bool mute; - return i_result; + prepareVolume (obj, &aout, NULL, &mute); + return commitVolume (obj, aout, volume, mute); } -/* - * The next functions are not supposed to be called by the interface, but - * are placeholders for software-only scaling. +#undef aout_VolumeUp +/** + * Raises the volume. + * \param value how much to increase (> 0) or decrease (< 0) the volume + * \param volp if non-NULL, will contain contain the resulting volume */ - -/* Meant to be called by the output plug-in's Open(). */ -void aout_VolumeSoftInit( aout_instance_t * p_aout ) +int aout_VolumeUp (vlc_object_t *obj, int value, audio_volume_t *volp) { - int i_volume; + audio_output_t *aout; + int ret; + audio_volume_t volume; + bool mute; - p_aout->output.pf_volume_infos = aout_VolumeSoftInfos; - p_aout->output.pf_volume_get = aout_VolumeSoftGet; - p_aout->output.pf_volume_set = aout_VolumeSoftSet; + value *= var_InheritInteger (obj, "volume-step"); - i_volume = config_GetInt( p_aout, "volume" ); - if ( i_volume < AOUT_VOLUME_MIN ) - { - i_volume = AOUT_VOLUME_DEFAULT; - } - else if ( i_volume > AOUT_VOLUME_MAX ) - { - i_volume = AOUT_VOLUME_MAX; - } - - aout_VolumeSoftSet( p_aout, (audio_volume_t)i_volume ); + prepareVolume (obj, &aout, &volume, &mute); + value += volume; + if (value < AOUT_VOLUME_MIN) + volume = AOUT_VOLUME_MIN; + else + if (value > AOUT_VOLUME_MAX) + volume = AOUT_VOLUME_MAX; + else + volume = value; + ret = commitVolume (obj, aout, volume, mute); + if (volp != NULL) + *volp = volume; + return ret; } -/* Placeholder for pf_volume_infos(). */ -int aout_VolumeSoftInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft ) +#undef aout_VolumeDown +/** + * Lowers the volume. See aout_VolumeUp(). + */ +int aout_VolumeDown (vlc_object_t *obj, int steps, audio_volume_t *volp) { - *pi_soft = 0; - return 0; + return aout_VolumeUp (obj, -steps, volp); } -/* Placeholder for pf_volume_get(). */ -int aout_VolumeSoftGet( aout_instance_t * p_aout, audio_volume_t * pi_volume ) +#undef aout_ToggleMute +/** + * Toggles the mute state. + */ +int aout_ToggleMute (vlc_object_t *obj, audio_volume_t *volp) { - *pi_volume = p_aout->output.i_volume; - return 0; + audio_output_t *aout; + int ret; + audio_volume_t volume; + bool mute; + + prepareVolume (obj, &aout, &volume, &mute); + mute = !mute; + ret = commitVolume (obj, aout, volume, mute); + if (volp != NULL) + *volp = mute ? AOUT_VOLUME_MIN : volume; + return ret; } +/** + * Gets the output mute status. + */ +bool aout_IsMuted (vlc_object_t *obj) +{ +#if 0 + audio_output_t *aout; + bool mute; + + prepareVolume (obj, &aout, NULL, &mute); + cancelVolume (obj, aout); + return mute; +#else + return var_GetBool (obj, "mute"); +#endif +} -/* Placeholder for pf_volume_set(). */ -int aout_VolumeSoftSet( aout_instance_t * p_aout, audio_volume_t i_volume ) +/** + * Sets mute status. + */ +int aout_SetMute (vlc_object_t *obj, audio_volume_t *volp, bool mute) { - aout_MixerMultiplierSet( p_aout, (float)i_volume / AOUT_VOLUME_DEFAULT ); - p_aout->output.i_volume = i_volume; - return 0; + audio_output_t *aout; + int ret; + audio_volume_t volume; + + prepareVolume (obj, &aout, &volume, NULL); + ret = commitVolume (obj, aout, volume, mute); + if (volp != NULL) + *volp = mute ? AOUT_VOLUME_MIN : volume; + return ret; } + /* * The next functions are not supposed to be called by the interface, but - * are placeholders for unsupported scaling. + * are placeholders for software-only scaling. */ - -/* Meant to be called by the output plug-in's Open(). */ -void aout_VolumeNoneInit( aout_instance_t * p_aout ) +static int aout_VolumeSoftSet (audio_output_t *aout, float volume, bool mute) { - p_aout->output.pf_volume_infos = aout_VolumeNoneInfos; - p_aout->output.pf_volume_get = aout_VolumeNoneGet; - p_aout->output.pf_volume_set = aout_VolumeNoneSet; + aout->mixer_multiplier = mute ? 0. : volume; + return 0; } -/* Placeholder for pf_volume_infos(). */ -int aout_VolumeNoneInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft ) +/* Meant to be called by the output plug-in's Open(). */ +void aout_VolumeSoftInit (audio_output_t *aout) { - return -1; + audio_volume_t volume = var_InheritInteger (aout, "volume"); + bool mute = var_InheritBool (aout, "mute"); + + aout->pf_volume_set = aout_VolumeSoftSet; + aout_VolumeSoftSet (aout, volume / (float)AOUT_VOLUME_DEFAULT, mute); } -/* Placeholder for pf_volume_get(). */ -int aout_VolumeNoneGet( aout_instance_t * p_aout, audio_volume_t * pi_volume ) + +/* + * The next functions are not supposed to be called by the interface, but + * are placeholders for unsupported scaling. + */ +static int aout_VolumeNoneSet (audio_output_t *aout, float volume, bool mute) { + (void)aout; (void)volume; (void)mute; return -1; } -/* Placeholder for pf_volume_set(). */ -int aout_VolumeNoneSet( aout_instance_t * p_aout, audio_volume_t i_volume ) +/* Meant to be called by the output plug-in's Open(). */ +void aout_VolumeNoneInit( audio_output_t * p_aout ) { - return -1; + p_aout->pf_volume_set = aout_VolumeNoneSet; } @@ -315,114 +288,87 @@ int aout_VolumeNoneSet( aout_instance_t * p_aout, audio_volume_t i_volume ) * This function is used whenever the parameters of the output plug-in are * changed (eg. selecting S/PDIF or PCM). *****************************************************************************/ -int aout_Restart( aout_instance_t * p_aout ) +static int aout_Restart( audio_output_t * p_aout ) { - int i; - vlc_bool_t b_error = 0; + aout_input_t *p_input; - vlc_mutex_lock( &p_aout->mixer_lock ); - - if ( p_aout->i_nb_inputs == 0 ) + aout_lock( p_aout ); + p_input = p_aout->p_input; + if( p_input == NULL ) { - vlc_mutex_unlock( &p_aout->mixer_lock ); + aout_unlock( p_aout ); msg_Err( p_aout, "no decoder thread" ); return -1; } - /* Lock all inputs. */ - for ( i = 0; i < p_aout->i_nb_inputs; i++ ) - { - vlc_mutex_lock( &p_aout->pp_inputs[i]->lock ); - aout_InputDelete( p_aout, p_aout->pp_inputs[i] ); - } - + /* Reinitializes the output */ + aout_InputDelete( p_aout, p_input ); aout_MixerDelete( p_aout ); - - /* Re-open the output plug-in. */ aout_OutputDelete( p_aout ); - if ( aout_OutputNew( p_aout, &p_aout->pp_inputs[0]->input ) == -1 ) + /* FIXME: This function is notoriously dangerous/unsafe. + * By the way, if OutputNew or MixerNew fails, we are totally screwed. */ + if ( aout_OutputNew( p_aout, &p_input->input ) == -1 ) { /* Release all locks and report the error. */ - for ( i = 0; i < p_aout->i_nb_inputs; i++ ) - { - vlc_mutex_unlock( &p_aout->pp_inputs[i]->lock ); - } - vlc_mutex_unlock( &p_aout->mixer_lock ); + aout_unlock( p_aout ); return -1; } if ( aout_MixerNew( p_aout ) == -1 ) { aout_OutputDelete( p_aout ); - for ( i = 0; i < p_aout->i_nb_inputs; i++ ) - { - vlc_mutex_unlock( &p_aout->pp_inputs[i]->lock ); - } - vlc_mutex_unlock( &p_aout->mixer_lock ); + aout_unlock( p_aout ); return -1; } - /* Re-open all inputs. */ - for ( i = 0; i < p_aout->i_nb_inputs; i++ ) + if( aout_InputNew( p_aout, p_input, &p_input->request_vout ) ) { - aout_input_t * p_input = p_aout->pp_inputs[i]; - - b_error |= aout_InputNew( p_aout, p_input ); - p_input->b_changed = 1; - vlc_mutex_unlock( &p_input->lock ); +#warning FIXME: deal with errors + aout_unlock( p_aout ); + return -1; } - - vlc_mutex_unlock( &p_aout->mixer_lock ); - - return b_error; + aout_unlock( p_aout ); + return 0; } /***************************************************************************** - * aout_FindAndRestart : find the audio output instance and restart - ***************************************************************************** - * This is used for callbacks of the configuration variables, and we believe - * that when those are changed, it is a significant change which implies - * rebuilding the audio-device and audio-channels variables. + * aout_ChannelsRestart : change the audio device or channels and restart *****************************************************************************/ -void aout_FindAndRestart( vlc_object_t * p_this ) +int aout_ChannelsRestart( vlc_object_t * p_this, const char * psz_variable, + vlc_value_t oldval, vlc_value_t newval, + void *p_data ) { - aout_instance_t * p_aout = vlc_object_find( p_this, VLC_OBJECT_AOUT, - FIND_ANYWHERE ); - - if ( p_aout == NULL ) return; + audio_output_t * p_aout = (audio_output_t *)p_this; + (void)oldval; (void)newval; (void)p_data; - if ( var_Type( p_aout, "audio-device" ) != 0 ) - { - var_Destroy( p_aout, "audio-device" ); - } - if ( var_Type( p_aout, "audio-channels" ) != 0 ) + if ( !strcmp( psz_variable, "audio-device" ) ) { + /* This is supposed to be a significant change and supposes + * rebuilding the channel choices. */ var_Destroy( p_aout, "audio-channels" ); } - aout_Restart( p_aout ); - vlc_object_release( p_aout ); + return 0; } -/***************************************************************************** - * aout_ChannelsRestart : change the audio device or channels and restart - *****************************************************************************/ -int aout_ChannelsRestart( vlc_object_t * p_this, const char * psz_variable, - vlc_value_t old_value, vlc_value_t new_value, - void * unused ) +#undef aout_EnableFilter +/** Enable or disable an audio filter + * \param p_this a vlc object + * \param psz_name name of the filter + * \param b_add are we adding or removing the filter ? + */ +void aout_EnableFilter( vlc_object_t *p_this, const char *psz_name, + bool b_add ) { - aout_instance_t * p_aout = (aout_instance_t *)p_this; + audio_output_t *p_aout = findAout( p_this ); - if ( !strcmp( psz_variable, "audio-device" ) ) + if( aout_ChangeFilterString( p_this, p_aout, "audio-filter", psz_name, b_add ) ) { - /* This is supposed to be a significant change and supposes - * rebuilding the channel choices. */ - if ( var_Type( p_aout, "audio-channels" ) >= 0 ) - { - var_Destroy( p_aout, "audio-channels" ); - } + if( p_aout ) + AoutInputsMarkToRestart( p_aout ); } - aout_Restart( p_aout ); - return 0; + + if( p_aout ) + vlc_object_release( p_aout ); }