X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Faudio_output%2Fintf.c;h=9b6afa52a6f554c38162bdde85d3d9324fe37380;hb=749fa2f4d2f6cc7f7a03a64708fba6a2eacce001;hp=d5e0ba78d488d4e5e9ca9b8419b09a3904c3b2c2;hpb=2932220e9ed7d99f8b8397f1b578c9f0a3a1aa3b;p=vlc diff --git a/src/audio_output/intf.c b/src/audio_output/intf.c index d5e0ba78d4..9b6afa52a6 100644 --- a/src/audio_output/intf.c +++ b/src/audio_output/intf.c @@ -58,310 +58,223 @@ static aout_instance_t *findAout (vlc_object_t *obj) } #define findAout(o) findAout(VLC_OBJECT(o)) -/* - * 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. - */ - -enum { - SET_MUTE=1, - SET_VOLUME=2, - INCREMENT_VOLUME=4, - TOGGLE_MUTE=8 -}; - -/***************************************************************************** - * doVolumeChanges : handle all volume changes. Internal use only to ease - * variables locking. - *****************************************************************************/ -static -int doVolumeChanges( unsigned action, vlc_object_t * p_object, int i_nb_steps, - audio_volume_t i_volume, audio_volume_t * i_return_volume, - bool b_mute ) +/** Start a volume change transaction. */ +static void prepareVolume (vlc_object_t *obj, aout_instance_t **aoutp, + audio_volume_t *volp, bool *mutep) { - int i_result = VLC_SUCCESS; - int i_volume_step = 1, i_new_volume = 0; - bool b_var_mute = false; - aout_instance_t *p_aout = findAout( p_object ); - - if ( p_aout ) aout_lock_volume( p_aout ); - - b_var_mute = var_GetBool( p_object, "volume-muted"); - - const bool b_unmute_condition = ( /* Also unmute on increments */ - ( action == INCREMENT_VOLUME ) - || /* On explicit unmute */ - ( ( action == SET_MUTE ) && ( b_var_mute && !b_mute ) ) - || /* On toggle from muted */ - ( ( action == TOGGLE_MUTE ) && b_var_mute ) ); - - const bool b_mute_condition = ( !b_var_mute - && ( /* explicit */ - ( ( action == SET_MUTE ) && b_mute ) - || /* or toggle */ - ( action == TOGGLE_MUTE ) - )); - - /* On UnMute */ - if ( b_unmute_condition ) - { - /* Restore saved volume */ - i_volume = var_GetInteger( p_object, "saved-volume" ); - var_SetBool( p_object, "volume-muted", false ); - } - else if ( b_mute_condition ) - { - /* We need an initial value to backup later */ - i_volume = config_GetInt( p_object, "volume" ); - } - - if ( action == INCREMENT_VOLUME ) - { - i_volume_step = var_InheritInteger( p_object, "volume-step" ); - - if ( !b_unmute_condition ) - i_volume = config_GetInt( p_object, "volume" ); - - i_new_volume = (int) i_volume + i_volume_step * i_nb_steps; - - if ( i_new_volume > AOUT_VOLUME_MAX ) - i_volume = AOUT_VOLUME_MAX; - else if ( i_new_volume < AOUT_VOLUME_MIN ) - i_volume = AOUT_VOLUME_MIN; - else - i_volume = i_new_volume; - } - - var_SetInteger( p_object, "saved-volume" , i_volume ); + aout_instance_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"); +} - /* On Mute */ - if ( b_mute_condition ) - { - i_volume = AOUT_VOLUME_MIN; - var_SetBool( p_object, "volume-muted", true ); - } +/** Commit a volume change transaction. */ +static int commitVolume (vlc_object_t *obj, aout_instance_t *aout, + audio_volume_t volume, bool mute) +{ + int ret = 0; - /* Commit volume changes */ - config_PutInt( p_object, "volume", i_volume ); + var_SetInteger (obj, "volume", volume); + var_SetBool (obj, "mute", mute); - if ( p_aout ) + if (aout != NULL) { - aout_lock_mixer( p_aout ); - aout_lock_input_fifos( p_aout ); - if ( p_aout->p_mixer ) - i_result = p_aout->output.pf_volume_set( p_aout, i_volume ); - aout_unlock_input_fifos( p_aout ); - aout_unlock_mixer( p_aout ); + aout_lock_mixer (aout); + aout_lock_input_fifos (aout); + if (aout->p_mixer != NULL) + ret = aout->output.pf_volume_set (aout, volume, mute); + aout_unlock_input_fifos (aout); + aout_unlock_mixer (aout); + + if (ret == 0) + var_TriggerCallback (aout, "intf-change"); + aout_unlock_volume (aout); + vlc_object_release (aout); } + return ret; +} - /* trigger callbacks */ - var_TriggerCallback( p_object, "volume-change" ); - if ( p_aout ) +#if 0 +/** Cancel a volume change transaction. */ +static void cancelVolume (vlc_object_t *obj, aout_instance_t *aout) +{ + (void) obj; + if (aout != NULL) { - var_SetBool( p_aout, "intf-change", true ); - aout_unlock_volume( p_aout ); - vlc_object_release( p_aout ); + aout_unlock_volume (aout); + vlc_object_release (aout); } - - if ( i_return_volume != NULL ) - *i_return_volume = i_volume; - return i_result; } +#endif #undef aout_VolumeGet -/***************************************************************************** - * aout_VolumeGet : get the volume of the output device - *****************************************************************************/ -int aout_VolumeGet( vlc_object_t * p_object, audio_volume_t * pi_volume ) +/** + * Gets the volume of the output device (independent of mute). + */ +audio_volume_t aout_VolumeGet (vlc_object_t *obj) { - int i_result = 0; - aout_instance_t * p_aout = findAout( p_object ); - - if ( pi_volume == NULL ) return -1; - - if ( p_aout == NULL ) - { - *pi_volume = (audio_volume_t)config_GetInt( p_object, "volume" ); - return 0; - } - - aout_lock_volume( p_aout ); - aout_lock_mixer( p_aout ); - if ( p_aout->p_mixer ) - { - i_result = p_aout->output.pf_volume_get( p_aout, pi_volume ); - } - else - { - *pi_volume = (audio_volume_t)config_GetInt( p_object, "volume" ); - } - aout_unlock_mixer( p_aout ); - aout_unlock_volume( p_aout ); +#if 0 + aout_instance_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 } #undef aout_VolumeSet -/***************************************************************************** - * aout_VolumeSet : set the volume of the output device - *****************************************************************************/ -int aout_VolumeSet( vlc_object_t * p_object, audio_volume_t i_volume ) +/** + * Sets the volume of the output device. + * The mute status is not changed. + */ +int aout_VolumeSet (vlc_object_t *obj, audio_volume_t volume) { - return doVolumeChanges( SET_VOLUME, p_object, 1, i_volume, NULL, true ); + aout_instance_t *aout; + bool mute; + + prepareVolume (obj, &aout, NULL, &mute); + return commitVolume (obj, aout, volume, mute); } #undef aout_VolumeUp -/***************************************************************************** - * 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 ) +/** + * 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 + */ +int aout_VolumeUp (vlc_object_t *obj, int value, audio_volume_t *volp) { - return doVolumeChanges( INCREMENT_VOLUME, p_object, i_nb_steps, 0, pi_volume, true ); + aout_instance_t *aout; + int ret; + audio_volume_t volume; + bool mute; + + value *= var_InheritInteger (obj, "volume-step"); + + 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; } #undef aout_VolumeDown -/***************************************************************************** - * 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 ) +/** + * Lowers the volume. See aout_VolumeUp(). + */ +int aout_VolumeDown (vlc_object_t *obj, int steps, audio_volume_t *volp) { - return aout_VolumeUp( p_object, -i_nb_steps, pi_volume ); + return aout_VolumeUp (obj, -steps, volp); } #undef aout_ToggleMute -/***************************************************************************** - * aout_ToggleMute : 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_ToggleMute( vlc_object_t * p_object, audio_volume_t * pi_volume ) +/** + * Toggles the mute state. + */ +int aout_ToggleMute (vlc_object_t *obj, audio_volume_t *volp) { - return doVolumeChanges( TOGGLE_MUTE, p_object, 1, 0, pi_volume, true ); + aout_instance_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; } -/***************************************************************************** - * aout_IsMuted : Get the output volume mute status - *****************************************************************************/ -bool aout_IsMuted( vlc_object_t * p_object ) +/** + * Gets the output mute status. + */ +bool aout_IsMuted (vlc_object_t *obj) { - bool b_return_val; - aout_instance_t * p_aout = findAout( p_object ); - if ( p_aout ) aout_lock_volume( p_aout ); - b_return_val = var_GetBool( p_object, "volume-muted"); - if ( p_aout ) - { - aout_unlock_volume( p_aout ); - vlc_object_release( p_aout ); - } - return b_return_val; +#if 0 + aout_instance_t *aout; + bool mute; + + prepareVolume (obj, &aout, NULL, &mute); + cancelVolume (obj, aout); + return mute; +#else + return var_GetBool (obj, "mute"); +#endif } -/***************************************************************************** - * aout_SetMute : Sets mute status - ***************************************************************************** - * If pi_volume != NULL, *pi_volume will contain the volume at the end of the - * function (muted => 0). - *****************************************************************************/ -int aout_SetMute( vlc_object_t * p_object, audio_volume_t * pi_volume, - bool b_mute ) +/** + * Sets mute status. + */ +int aout_SetMute (vlc_object_t *obj, audio_volume_t *volp, bool mute) { - return doVolumeChanges( SET_MUTE, p_object, 1, 0, pi_volume, b_mute ); + aout_instance_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 software-only scaling. */ - -/* Meant to be called by the output plug-in's Open(). */ -void aout_VolumeSoftInit( aout_instance_t * p_aout ) -{ - int i_volume; - - p_aout->output.pf_volume_get = aout_VolumeSoftGet; - p_aout->output.pf_volume_set = aout_VolumeSoftSet; - - 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 ); -} - -/* Placeholder for pf_volume_get(). */ -int aout_VolumeSoftGet( aout_instance_t * p_aout, audio_volume_t * pi_volume ) +static int aout_VolumeSoftSet (aout_instance_t *aout, audio_volume_t volume, + bool mute) { - *pi_volume = p_aout->output.i_volume; + float f = mute ? 0. : (volume / (float)AOUT_VOLUME_DEFAULT); + aout->mixer_multiplier = f; return 0; } - -/* Placeholder for pf_volume_set(). */ -int aout_VolumeSoftSet( aout_instance_t * p_aout, audio_volume_t i_volume ) +/* Meant to be called by the output plug-in's Open(). */ +void aout_VolumeSoftInit (aout_instance_t *aout) { - aout_MixerMultiplierSet( p_aout, (float)i_volume / AOUT_VOLUME_DEFAULT ); - p_aout->output.i_volume = i_volume; - return 0; + audio_volume_t volume = var_InheritInteger (aout, "volume"); + bool mute = var_InheritBool (aout, "mute"); + + aout->output.pf_volume_set = aout_VolumeSoftSet; + aout_VolumeSoftSet (aout, volume, mute); } + /* * The next functions are not supposed to be called by the interface, but * are placeholders for unsupported scaling. */ - -/* Meant to be called by the output plug-in's Open(). */ -void aout_VolumeNoneInit( aout_instance_t * p_aout ) -{ - p_aout->output.pf_volume_get = aout_VolumeNoneGet; - p_aout->output.pf_volume_set = aout_VolumeNoneSet; -} - -/* Placeholder for pf_volume_get(). */ -int aout_VolumeNoneGet( aout_instance_t * p_aout, audio_volume_t * pi_volume ) +static int aout_VolumeNoneSet (aout_instance_t *aout, audio_volume_t volume, + bool mute) { - (void)p_aout; (void)pi_volume; + (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( aout_instance_t * p_aout ) { - (void)p_aout; (void)i_volume; - return -1; + p_aout->output.pf_volume_set = aout_VolumeNoneSet; } @@ -378,25 +291,21 @@ int aout_VolumeNoneSet( aout_instance_t * p_aout, audio_volume_t i_volume ) *****************************************************************************/ static int aout_Restart( aout_instance_t * p_aout ) { - int i; bool b_error = 0; aout_lock_mixer( p_aout ); - if ( p_aout->i_nb_inputs == 0 ) + if( p_aout->p_input == NULL ) { aout_unlock_mixer( p_aout ); msg_Err( p_aout, "no decoder thread" ); return -1; } - for ( i = 0; i < p_aout->i_nb_inputs; i++ ) - { - aout_lock_input( p_aout, p_aout->pp_inputs[i] ); - aout_lock_input_fifos( p_aout ); - aout_InputDelete( p_aout, p_aout->pp_inputs[i] ); - aout_unlock_input_fifos( p_aout ); - } + aout_lock_input( p_aout, p_aout->p_input ); + aout_lock_input_fifos( p_aout ); + aout_InputDelete( p_aout, p_aout->p_input ); + aout_unlock_input_fifos( p_aout ); /* Lock all inputs. */ aout_lock_input_fifos( p_aout ); @@ -405,13 +314,12 @@ static int aout_Restart( aout_instance_t * 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_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->p_input->lock ); aout_unlock_input_fifos( p_aout ); aout_unlock_mixer( p_aout ); return -1; @@ -420,23 +328,16 @@ static int aout_Restart( aout_instance_t * p_aout ) 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->p_input->lock ); aout_unlock_input_fifos( p_aout ); aout_unlock_mixer( p_aout ); return -1; } - /* Re-open all inputs. */ - for ( i = 0; i < p_aout->i_nb_inputs; i++ ) - { - aout_input_t * p_input = p_aout->pp_inputs[i]; - b_error |= aout_InputNew( p_aout, p_input, &p_input->request_vout ); - p_input->b_changed = 1; - aout_unlock_input( p_aout, p_input ); - } + /* Re-open the input. */ + aout_input_t * p_input = p_aout->p_input; + b_error |= aout_InputNew( p_aout, p_input, &p_input->request_vout ); + aout_unlock_input( p_aout, p_input ); aout_unlock_input_fifos( p_aout ); aout_unlock_mixer( p_aout ); @@ -444,30 +345,6 @@ static int aout_Restart( aout_instance_t * p_aout ) return b_error; } -/***************************************************************************** - * 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. - *****************************************************************************/ -int aout_FindAndRestart( vlc_object_t * p_this, const char *psz_name, - vlc_value_t oldval, vlc_value_t newval, void *p_data ) -{ - aout_instance_t * p_aout = findAout( pl_Get(p_this) ); - - (void)psz_name; (void)oldval; (void)newval; (void)p_data; - if ( p_aout == NULL ) return VLC_SUCCESS; - - var_Destroy( p_aout, "audio-device" ); - var_Destroy( p_aout, "audio-channels" ); - - aout_Restart( p_aout ); - vlc_object_release( p_aout ); - - return VLC_SUCCESS; -} - /***************************************************************************** * aout_ChannelsRestart : change the audio device or channels and restart *****************************************************************************/ @@ -499,7 +376,7 @@ void aout_EnableFilter( vlc_object_t *p_this, const char *psz_name, { aout_instance_t *p_aout = findAout( p_this ); - if( AoutChangeFilterString( p_this, p_aout, "audio-filter", psz_name, b_add ) ) + if( aout_ChangeFilterString( p_this, p_aout, "audio-filter", psz_name, b_add ) ) { if( p_aout ) AoutInputsMarkToRestart( p_aout );