]> git.sesse.net Git - vlc/blob - src/audio_output/intf.c
* Audio volume management now works properly. See src/audio_output/intf.c
[vlc] / src / audio_output / intf.c
1 /*****************************************************************************
2  * intf.c : audio output API towards the interface modules
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: intf.c,v 1.3 2002/09/19 21:56:40 massiot Exp $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *
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.
13  * 
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.
18  *
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                            /* calloc(), malloc(), free() */
28 #include <string.h>
29
30 #include <vlc/vlc.h>
31
32 #include "audio_output.h"
33 #include "aout_internal.h"
34
35 /*
36  * Volume management
37  *
38  * The hardware volume cannot be set if the output module gets deleted, so
39  * we must take the mixer lock. The software volume cannot be set while the
40  * mixer is running, so we need the mixer lock (too).
41  *
42  * Here is a schematic of the i_volume range :
43  * 
44  * |------------------------------+---------------------------------------|
45  * 0                           pi_soft                                   1024
46  *
47  * Between 0 and pi_soft, the volume is done in hardware by the output
48  * module. Above, the output module will change p_aout->mixer.i_multiplier
49  * (done in software). This scaling may result * in cropping errors and
50  * should be avoided as much as possible.
51  *
52  * It is legal to have *pi_soft == 0, and do everything in software.
53  * It is also legal to have *pi_soft == 1024, and completely avoid
54  * software scaling. However, some streams (esp. A/52) are encoded with
55  * a very low volume and users may complain.
56  */
57
58 /*****************************************************************************
59  * aout_VolumeGet : get the volume of the output device
60  *****************************************************************************/
61 int aout_VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
62 {
63     int i_result;
64
65     vlc_mutex_lock( &p_aout->mixer_lock );
66
67     if ( p_aout->i_nb_inputs == 0 )
68     {
69         /* The output module is destroyed. */
70         vlc_mutex_unlock( &p_aout->mixer_lock );
71         msg_Err( p_aout, "VolumeGet called without output module" );
72         return -1;
73     }
74
75     i_result = p_aout->output.pf_volume_get( p_aout, pi_volume );
76
77     vlc_mutex_unlock( &p_aout->mixer_lock );
78     return i_result;
79 }
80
81 /*****************************************************************************
82  * aout_VolumeSet : set the volume of the output device
83  *****************************************************************************/
84 int aout_VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
85 {
86     int i_result;
87
88     vlc_mutex_lock( &p_aout->mixer_lock );
89
90     if ( p_aout->i_nb_inputs == 0 )
91     {
92         /* The output module is destroyed. */
93         vlc_mutex_unlock( &p_aout->mixer_lock );
94         msg_Err( p_aout, "VolumeSet called without output module" );
95         return -1;
96     }
97
98     i_result = p_aout->output.pf_volume_set( p_aout, i_volume );
99
100     vlc_mutex_unlock( &p_aout->mixer_lock );
101     return i_result;
102 }
103
104 /*****************************************************************************
105  * aout_VolumeInfos : get the boundaries pi_low_soft and pi_high_soft
106  *****************************************************************************/
107 int aout_VolumeInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
108 {
109     int i_result;
110
111     vlc_mutex_lock( &p_aout->mixer_lock );
112
113     if ( p_aout->i_nb_inputs == 0 )
114     {
115         /* The output module is destroyed. */
116         vlc_mutex_unlock( &p_aout->mixer_lock );
117         msg_Err( p_aout, "VolumeInfos called without output module" );
118         return -1;
119     }
120
121     i_result = p_aout->output.pf_volume_infos( p_aout, pi_soft );
122
123     vlc_mutex_unlock( &p_aout->mixer_lock );
124     return i_result;
125 }
126
127 /*****************************************************************************
128  * aout_VolumeUp : raise the output volume
129  *****************************************************************************
130  * If pi_volume != NULL, *pi_volume will contain the volume at the end of the
131  * function.
132  *****************************************************************************/
133 int aout_VolumeUp( aout_instance_t * p_aout, int i_nb_steps,
134                    audio_volume_t * pi_volume )
135 {
136     int i_result;
137     audio_volume_t i_volume;
138
139     vlc_mutex_lock( &p_aout->mixer_lock );
140
141     if ( p_aout->i_nb_inputs == 0 )
142     {
143         /* The output module is destroyed. */
144         vlc_mutex_unlock( &p_aout->mixer_lock );
145         msg_Err( p_aout, "VolumeUp called without output module" );
146         return -1;
147     }
148
149     if ( p_aout->output.pf_volume_get( p_aout, &i_volume ) )
150     {
151         vlc_mutex_unlock( &p_aout->mixer_lock );
152         return -1;
153     }
154
155     i_volume += AOUT_VOLUME_STEP * i_nb_steps;
156     if ( i_volume > 1024 ) i_volume = 1024;
157
158     i_result = p_aout->output.pf_volume_set( p_aout, i_volume );
159
160     vlc_mutex_unlock( &p_aout->mixer_lock );
161
162     if ( pi_volume != NULL ) *pi_volume = i_volume;
163     return i_result;
164 }
165
166 /*****************************************************************************
167  * aout_VolumeDown : lower the output volume
168  *****************************************************************************
169  * If pi_volume != NULL, *pi_volume will contain the volume at the end of the
170  * function.
171  *****************************************************************************/
172 int aout_VolumeDown( aout_instance_t * p_aout, int i_nb_steps,
173                      audio_volume_t * pi_volume )
174 {
175     int i_result;
176     audio_volume_t i_volume;
177
178     vlc_mutex_lock( &p_aout->mixer_lock );
179
180     if ( p_aout->i_nb_inputs == 0 )
181     {
182         /* The output module is destroyed. */
183         vlc_mutex_unlock( &p_aout->mixer_lock );
184         msg_Err( p_aout, "VolumeUp called without output module" );
185         return -1;
186     }
187
188     if ( p_aout->output.pf_volume_get( p_aout, &i_volume ) )
189     {
190         vlc_mutex_unlock( &p_aout->mixer_lock );
191         return -1;
192     }
193
194     if ( i_volume < AOUT_VOLUME_STEP * i_nb_steps )
195         i_volume = 0;
196     else
197         i_volume -= AOUT_VOLUME_STEP * i_nb_steps;
198
199     i_result = p_aout->output.pf_volume_set( p_aout, i_volume );
200
201     vlc_mutex_unlock( &p_aout->mixer_lock );
202
203     if ( pi_volume != NULL ) *pi_volume = i_volume;
204     return i_result;
205 }
206
207 /*
208  * The next functions are not supposed to be called by the interface, but
209  * are placeholders for software-only scaling.
210  */
211
212 /* Meant to be called by the output plug-in's Open(). */
213 void aout_VolumeSoftInit( aout_instance_t * p_aout )
214 {
215     int i_volume;
216
217     p_aout->output.pf_volume_infos = aout_VolumeSoftInfos;
218     p_aout->output.pf_volume_get = aout_VolumeSoftGet;
219     p_aout->output.pf_volume_set = aout_VolumeSoftSet;
220
221     i_volume = config_GetInt( p_aout, "volume" );
222     if ( i_volume == -1 )
223     {
224         i_volume = AOUT_VOLUME_DEFAULT;
225     }
226
227     aout_VolumeSoftSet( p_aout, i_volume );
228 }
229
230 /* Placeholder for pf_volume_infos(). */
231 int aout_VolumeSoftInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
232 {
233     *pi_soft = 0;
234     return 0;
235 }
236
237 /* Placeholder for pf_volume_get(). */
238 int aout_VolumeSoftGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
239 {
240     *pi_volume = p_aout->output.i_volume;
241     return 0;
242 }
243
244
245 /* Placeholder for pf_volume_set(). */
246 int aout_VolumeSoftSet( aout_instance_t * p_aout, audio_volume_t i_volume )
247 {
248     aout_MixerMultiplierSet( p_aout, (float)i_volume / AOUT_VOLUME_DEFAULT );
249     p_aout->output.i_volume = i_volume;
250     return 0;
251 }
252
253 /*
254  * The next functions are not supposed to be called by the interface, but
255  * are placeholders for unsupported scaling.
256  */
257
258 /* Meant to be called by the output plug-in's Open(). */
259 void aout_VolumeNoneInit( aout_instance_t * p_aout )
260 {
261     p_aout->output.pf_volume_infos = aout_VolumeNoneInfos;
262     p_aout->output.pf_volume_get = aout_VolumeNoneGet;
263     p_aout->output.pf_volume_set = aout_VolumeNoneSet;
264 }
265
266 /* Placeholder for pf_volume_infos(). */
267 int aout_VolumeNoneInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
268 {
269     return -1;
270 }
271
272 /* Placeholder for pf_volume_get(). */
273 int aout_VolumeNoneGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
274 {
275     return -1;
276 }
277
278
279 /* Placeholder for pf_volume_set(). */
280 int aout_VolumeNoneSet( aout_instance_t * p_aout, audio_volume_t i_volume )
281 {
282     return -1;
283 }
284