X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Faudio_output%2Fintf.c;h=e8fff115b27c63579ad0651c3200a08c4bfd34e1;hb=36ab287e77e9df059f261ed1cfb13fc4674182ec;hp=55fcec8711beb9d606e221a6931dd0adc13fa74e;hpb=f485214f09dd284cbb85674e937fbbb0a6032a2e;p=vlc diff --git a/src/audio_output/intf.c b/src/audio_output/intf.c index 55fcec8711..e8fff115b2 100644 --- a/src/audio_output/intf.c +++ b/src/audio_output/intf.c @@ -1,338 +1,231 @@ /***************************************************************************** * intf.c : audio output API towards the interface modules ***************************************************************************** - * Copyright (C) 2002-2004 the VideoLAN team + * Copyright (C) 2002-2007 VLC authors and VideoLAN * $Id$ * * Authors: Christophe Massiot * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software 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_result = 0; - aout_instance_t * p_aout = vlc_object_find( p_object, VLC_OBJECT_AOUT, - FIND_ANYWHERE ); + input_thread_t *(*pf_find_input) (vlc_object_t *); - if ( pi_volume == NULL ) return -1; + pf_find_input = var_GetAddress (obj, "find-input-callback"); + if (unlikely(pf_find_input == NULL)) + return NULL; - if ( p_aout == NULL ) - { - *pi_volume = (audio_volume_t)config_GetInt( p_object, "volume" ); - return 0; - } + input_thread_t *p_input = pf_find_input (obj); + if (p_input == NULL) + return NULL; - vlc_mutex_lock( &p_aout->mixer_lock ); - if ( !p_aout->mixer.b_error ) - { - i_result = p_aout->output.pf_volume_get( p_aout, pi_volume ); - } - else - { - *pi_volume = (audio_volume_t)config_GetInt( p_object, "volume" ); - } - vlc_mutex_unlock( &p_aout->mixer_lock ); - - vlc_object_release( p_aout ); - return i_result; + 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) { - vlc_value_t val; - aout_instance_t *p_aout = vlc_object_find( p_object, VLC_OBJECT_AOUT, FIND_ANYWHERE ); - int i_result = 0; + audio_output_t *aout = findAout (obj); - config_PutInt( p_object, "volume", i_volume ); - - val.b_bool = VLC_TRUE; - var_Set( p_object->p_libvlc, "volume-change", val ); - - if ( p_aout == NULL ) return 0; - - vlc_mutex_lock( &p_aout->mixer_lock ); - if ( !p_aout->mixer.b_error ) + /* FIXME: we need interlocking even if aout does not exist! */ + *aoutp = aout; + if (aout != NULL) { - i_result = p_aout->output.pf_volume_set( p_aout, i_volume ); + obj = VLC_OBJECT(aout); /* use aout volume if aout exists */ + aout_lock_volume (aout); } - vlc_mutex_unlock( &p_aout->mixer_lock ); - - var_Set( p_aout, "intf-change", val ); - vlc_object_release( p_aout ); - return i_result; + if (volp != NULL) + *volp = var_InheritInteger (obj, "volume"); + if (mutep != NULL) + *mutep = var_InheritBool (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; + /* update caller (input manager) volume */ + 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 ); + aout_owner_t *owner = aout_owner (aout); + float vol = volume / (float)AOUT_VOLUME_DEFAULT; + + /* apply volume to the pipeline */ + aout_lock (aout); + if (owner->module != NULL) + ret = aout->pf_volume_set (aout, vol, mute); + aout_unlock (aout); + + /* update aout volume if it maintains its own */ + var_SetInteger (aout, "volume", volume); + var_SetBool (aout, "mute", mute); + aout_unlock_volume (aout); + + if (ret == 0) + var_TriggerCallback (aout, "intf-change"); + 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 ) +/** 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_volume = 0, i_volume_step = 0; - - i_volume_step = config_GetInt( p_object->p_libvlc, "volume-step" ); - i_volume = config_GetInt( p_object, "volume" ); - i_volume += i_volume_step * i_nb_steps; - if ( i_volume > AOUT_VOLUME_MAX ) + (void) obj; + if (aout != NULL) { - i_volume = AOUT_VOLUME_MAX; + aout_unlock_volume (aout); + vlc_object_release (aout); } - config_PutInt( p_object, "volume", i_volume ); - var_Create( p_object->p_libvlc_global, "saved-volume", VLC_VAR_INTEGER ); - var_SetInteger( p_object->p_libvlc_global, "saved-volume" , - (audio_volume_t) i_volume ); - if ( pi_volume != NULL ) *pi_volume = (audio_volume_t) 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, - (audio_volume_t) i_volume ); - } - vlc_mutex_unlock( &p_aout->mixer_lock ); - - vlc_object_release( p_aout ); - return i_result; -} - -/***************************************************************************** - * 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 ) -{ - aout_instance_t * p_aout = vlc_object_find( p_object, VLC_OBJECT_AOUT, - FIND_ANYWHERE ); - int i_result = 0, i_volume = 0, i_volume_step = 0; - - i_volume_step = config_GetInt( p_object->p_libvlc, "volume-step" ); - i_volume = config_GetInt( p_object, "volume" ); - i_volume -= i_volume_step * i_nb_steps; - if ( i_volume < AOUT_VOLUME_MIN ) - { - i_volume = AOUT_VOLUME_MIN; - } - config_PutInt( p_object, "volume", i_volume ); - var_Create( p_object->p_libvlc_global, "saved-volume", VLC_VAR_INTEGER ); - var_SetInteger( p_object->p_libvlc_global, "saved-volume", (audio_volume_t) i_volume ); - if ( pi_volume != NULL ) *pi_volume = (audio_volume_t) 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, (audio_volume_t) i_volume ); - } - vlc_mutex_unlock( &p_aout->mixer_lock ); - - vlc_object_release( p_aout ); - return i_result; } -/***************************************************************************** - * 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_VolumeGet +/** + * Gets the volume of the output device (independent of mute). + */ +audio_volume_t aout_VolumeGet (vlc_object_t *obj) { - 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 ); - var_Create( p_object->p_libvlc_global, "saved-volume", VLC_VAR_INTEGER ); - var_SetInteger( p_object->p_libvlc_global, "saved-volume", (int)i_volume ); - if ( pi_volume != NULL ) *pi_volume = AOUT_VOLUME_MIN; - } - else - { - /* Un-mute */ - var_Create( p_object->p_libvlc_global, "saved-volume", VLC_VAR_INTEGER ); - i_volume = (audio_volume_t)var_GetInteger( p_object->p_libvlc_global, - "saved-volume" ); - i_result = aout_VolumeSet( p_object, i_volume ); - if ( pi_volume != NULL ) *pi_volume = i_volume; - } + audio_output_t *aout; + audio_volume_t volume; - return i_result; + prepareVolume (obj, &aout, &volume, NULL); + cancelVolume (obj, aout); + return volume; } -/* - * The next functions are not supposed to be called by the interface, but - * are placeholders for software-only scaling. +#undef aout_VolumeSet +/** + * Sets the volume of the output device. + * The mute status is not changed. */ - -/* Meant to be called by the output plug-in's Open(). */ -void aout_VolumeSoftInit( aout_instance_t * p_aout ) +int aout_VolumeSet (vlc_object_t *obj, audio_volume_t volume) { - int i_volume; - - p_aout->output.pf_volume_infos = aout_VolumeSoftInfos; - 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; - } + audio_output_t *aout; + bool mute; - aout_VolumeSoftSet( p_aout, (audio_volume_t)i_volume ); + prepareVolume (obj, &aout, NULL, &mute); + return commitVolume (obj, aout, volume, mute); } -/* Placeholder for pf_volume_infos(). */ -int aout_VolumeSoftInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft ) +#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 + */ +int aout_VolumeUp (vlc_object_t *obj, int value, audio_volume_t *volp) { - *pi_soft = 0; - return 0; -} - -/* Placeholder for pf_volume_get(). */ -int aout_VolumeSoftGet( aout_instance_t * p_aout, audio_volume_t * pi_volume ) -{ - *pi_volume = p_aout->output.i_volume; - return 0; -} + audio_output_t *aout; + int ret; + audio_volume_t volume; + bool mute; + value *= var_InheritInteger (obj, "volume-step"); -/* Placeholder for pf_volume_set(). */ -int aout_VolumeSoftSet( aout_instance_t * p_aout, audio_volume_t i_volume ) -{ - aout_MixerMultiplierSet( p_aout, (float)i_volume / AOUT_VOLUME_DEFAULT ); - p_aout->output.i_volume = i_volume; - return 0; + prepareVolume (obj, &aout, &volume, &mute); + value += volume; + if (value < 0) + volume = 0; + 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; } -/* - * The next functions are not supposed to be called by the interface, but - * are placeholders for unsupported scaling. +#undef aout_ToggleMute +/** + * Toggles the mute state. */ - -/* Meant to be called by the output plug-in's Open(). */ -void aout_VolumeNoneInit( aout_instance_t * p_aout ) +int aout_ToggleMute (vlc_object_t *obj, audio_volume_t *volp) { - p_aout->output.pf_volume_infos = aout_VolumeNoneInfos; - p_aout->output.pf_volume_get = aout_VolumeNoneGet; - p_aout->output.pf_volume_set = aout_VolumeNoneSet; + 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 ? 0 : volume; + return ret; } -/* Placeholder for pf_volume_infos(). */ -int aout_VolumeNoneInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft ) +/** + * Gets the output mute status. + */ +bool aout_IsMuted (vlc_object_t *obj) { - return -1; -} + audio_output_t *aout; + bool mute; -/* Placeholder for pf_volume_get(). */ -int aout_VolumeNoneGet( aout_instance_t * p_aout, audio_volume_t * pi_volume ) -{ - return -1; + prepareVolume (obj, &aout, NULL, &mute); + cancelVolume (obj, aout); + return mute; } -/* Placeholder for pf_volume_set(). */ -int aout_VolumeNoneSet( 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) { - return -1; + 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 ? 0 : volume; + return ret; } @@ -340,192 +233,43 @@ int aout_VolumeNoneSet( aout_instance_t * p_aout, audio_volume_t i_volume ) * Pipelines management */ -/***************************************************************************** - * aout_Restart : re-open the output device and rebuild the input and output - * pipelines - ***************************************************************************** - * 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 ) -{ - int i; - vlc_bool_t b_error = 0; - - vlc_mutex_lock( &p_aout->mixer_lock ); - - if ( p_aout->i_nb_inputs == 0 ) - { - vlc_mutex_unlock( &p_aout->mixer_lock ); - 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] ); - } - - 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 ) - { - /* 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 ); - 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 ); - 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->b_changed = 1; - vlc_mutex_unlock( &p_input->lock ); - } - - vlc_mutex_unlock( &p_aout->mixer_lock ); - - 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 val, void *p_data ) -{ - aout_instance_t * p_aout = vlc_object_find( p_this, VLC_OBJECT_AOUT, - FIND_ANYWHERE ); - - if ( p_aout == NULL ) return VLC_SUCCESS; - - if ( var_Type( p_aout, "audio-device" ) != 0 ) - { - var_Destroy( p_aout, "audio-device" ); - } - if ( var_Type( p_aout, "audio-channels" ) != 0 ) - { - 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 *****************************************************************************/ int aout_ChannelsRestart( vlc_object_t * p_this, const char * psz_variable, - vlc_value_t old_value, vlc_value_t new_value, - void * unused ) + vlc_value_t oldval, vlc_value_t newval, + void *p_data ) { - aout_instance_t * p_aout = (aout_instance_t *)p_this; + audio_output_t * p_aout = (audio_output_t *)p_this; + (void)oldval; (void)newval; (void)p_data; if ( !strcmp( psz_variable, "audio-device" ) ) { /* 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" ); - } + var_Destroy( p_aout, "audio-channels" ); } - aout_Restart( p_aout ); + aout_RequestRestart (p_aout); return 0; } +#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, - vlc_bool_t b_add ) + bool b_add ) { - char *psz_parser, *psz_string; - aout_instance_t * p_aout = vlc_object_find( p_this, VLC_OBJECT_AOUT, - FIND_ANYWHERE ); - - if( p_aout ) - psz_string = var_GetString( p_aout, "audio-filter" ); - else - psz_string = config_GetPsz( p_this, "audio-filter" ); + audio_output_t *p_aout = findAout( p_this ); - if( !psz_string ) psz_string = strdup(""); - - psz_parser = strstr( psz_string, psz_name ); - - if( b_add ) - { - if( !psz_parser ) - { - psz_parser = psz_string; - asprintf( &psz_string, (*psz_string) ? "%s:%s" : "%s%s", - psz_string, psz_name ); - free( psz_parser ); - } - else - { - vlc_object_release( p_aout ); - return; - } - } - else + if( aout_ChangeFilterString( p_this, VLC_OBJECT(p_aout), "audio-filter", psz_name, b_add ) ) { - if( psz_parser ) - { - memmove( psz_parser, psz_parser + strlen(psz_name) + - (*(psz_parser + strlen(psz_name)) == ':' ? 1 : 0 ), - strlen(psz_parser + strlen(psz_name)) + 1 ); - - if( *(psz_string+strlen(psz_string ) -1 ) == ':' ) - { - *(psz_string+strlen(psz_string ) -1 ) = '\0'; - } - } - else - { - free( psz_string ); - return; - } + if( p_aout ) + aout_InputRequestRestart( p_aout ); } - if( p_aout == NULL ) - config_PutPsz( p_this, "audio-filter", psz_string ); - else - { - var_SetString( p_aout, "audio-filter", psz_string ); - for( int i = 0; i < p_aout->i_nb_inputs; i++ ) - p_aout->pp_inputs[i]->b_restart = VLC_TRUE; + if( p_aout ) vlc_object_release( p_aout ); - } - free( psz_string ); }