]> git.sesse.net Git - vlc/blob - src/audio_output/intf.c
* ALL: More hooks for audio volume management.
[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.2 2002/09/18 21:21:24 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_low_soft                          pi_high_soft       1024
46  *
47  * Between pi_low_soft and pi_high_soft, the volume is done in hardware
48  * by the output module. Outside, the output module will change
49  * p_aout->mixer.i_multiplier (done in software). This scaling may result
50  * in cropping errors and should be avoided as much as possible.
51  *
52  * It is legal to have *pi_low_soft == *pi_high_soft, and do everything in
53  * software. In that case, it is recommended to use *pi_low_soft == 256,
54  * along with the utility functions provided in this file.
55  *
56  * It is also legal to have *pi_low_soft == 0 and *pi_high_soft == 1024, and
57  * completely avoid software scaling. However, some streams (esp. A/52)
58  * are encoded with a very low volume and users may complain.
59  */
60
61 /*****************************************************************************
62  * aout_VolumeGet : get the volume of the output device
63  *****************************************************************************/
64 int aout_VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
65 {
66     int i_result;
67
68     vlc_mutex_lock( &p_aout->mixer_lock );
69
70     if ( p_aout->i_nb_inputs == 0 )
71     {
72         /* The output module is destroyed. */
73         vlc_mutex_unlock( &p_aout->mixer_lock );
74         msg_Err( p_aout, "VolumeGet called without output module" );
75         return -1;
76     }
77
78     i_result = p_aout->output.pf_volume_get( p_aout, pi_volume );
79
80     vlc_mutex_lock( &p_aout->mixer_lock );
81     return i_result;
82 }
83
84 /*****************************************************************************
85  * aout_VolumeSet : set the volume of the output device
86  *****************************************************************************/
87 int aout_VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
88 {
89     int i_result;
90
91     vlc_mutex_lock( &p_aout->mixer_lock );
92
93     if ( p_aout->i_nb_inputs == 0 )
94     {
95         /* The output module is destroyed. */
96         vlc_mutex_unlock( &p_aout->mixer_lock );
97         msg_Err( p_aout, "VolumeSet called without output module" );
98         return -1;
99     }
100
101     i_result = p_aout->output.pf_volume_set( p_aout, i_volume );
102
103     vlc_mutex_lock( &p_aout->mixer_lock );
104     return i_result;
105 }
106
107 /*****************************************************************************
108  * aout_VolumeInfos : get the boundaries pi_low_soft and pi_high_soft
109  *****************************************************************************/
110 int aout_VolumeInfos( aout_instance_t * p_aout, audio_volume_t * pi_low_soft,
111                       audio_volume_t * pi_high_soft )
112 {
113     int i_result;
114
115     vlc_mutex_lock( &p_aout->mixer_lock );
116
117     if ( p_aout->i_nb_inputs == 0 )
118     {
119         /* The output module is destroyed. */
120         vlc_mutex_unlock( &p_aout->mixer_lock );
121         msg_Err( p_aout, "VolumeInfos called without output module" );
122         return -1;
123     }
124
125     i_result = p_aout->output.pf_volume_infos( p_aout, pi_low_soft,
126                                                pi_high_soft );
127
128     vlc_mutex_lock( &p_aout->mixer_lock );
129     return i_result;
130 }
131
132 /*****************************************************************************
133  * aout_VolumeUp : raise the output volume
134  *****************************************************************************
135  * If pi_volume != NULL, *pi_volume will contain the volume at the end of the
136  * function.
137  *****************************************************************************/
138 int aout_VolumeUp( aout_instance_t * p_aout, int i_nb_steps,
139                    audio_volume_t * pi_volume )
140 {
141     int i_result;
142     audio_volume_t i_volume;
143
144     vlc_mutex_lock( &p_aout->mixer_lock );
145
146     if ( p_aout->i_nb_inputs == 0 )
147     {
148         /* The output module is destroyed. */
149         vlc_mutex_unlock( &p_aout->mixer_lock );
150         msg_Err( p_aout, "VolumeUp called without output module" );
151         return -1;
152     }
153
154     if ( p_aout->output.pf_volume_get( p_aout, &i_volume ) )
155     {
156         vlc_mutex_unlock( &p_aout->mixer_lock );
157         return -1;
158     }
159
160     i_volume += AOUT_VOLUME_STEP * i_nb_steps;
161     if ( i_volume > 1024 ) i_volume = 1024;
162
163     i_result = p_aout->output.pf_volume_set( p_aout, i_volume );
164
165     vlc_mutex_lock( &p_aout->mixer_lock );
166
167     if ( pi_volume != NULL ) *pi_volume = i_volume;
168     return i_result;
169 }
170
171 /*****************************************************************************
172  * aout_VolumeDown : lower the output volume
173  *****************************************************************************
174  * If pi_volume != NULL, *pi_volume will contain the volume at the end of the
175  * function.
176  *****************************************************************************/
177 int aout_VolumeDown( aout_instance_t * p_aout, int i_nb_steps,
178                      audio_volume_t * pi_volume )
179 {
180     int i_result;
181     audio_volume_t i_volume;
182
183     vlc_mutex_lock( &p_aout->mixer_lock );
184
185     if ( p_aout->i_nb_inputs == 0 )
186     {
187         /* The output module is destroyed. */
188         vlc_mutex_unlock( &p_aout->mixer_lock );
189         msg_Err( p_aout, "VolumeUp called without output module" );
190         return -1;
191     }
192
193     if ( p_aout->output.pf_volume_get( p_aout, &i_volume ) )
194     {
195         vlc_mutex_unlock( &p_aout->mixer_lock );
196         return -1;
197     }
198
199     if ( i_volume < AOUT_VOLUME_STEP * i_nb_steps )
200         i_volume = 0;
201     else
202         i_volume -= AOUT_VOLUME_STEP * i_nb_steps;
203
204     i_result = p_aout->output.pf_volume_set( p_aout, i_volume );
205
206     vlc_mutex_lock( &p_aout->mixer_lock );
207
208     if ( pi_volume != NULL ) *pi_volume = i_volume;
209     return i_result;
210 }
211
212 /*
213  * The next functions are not supposed to be called by the interface, but
214  * are placeholders for software-only scaling.
215  */
216
217 /* Meant to be called by the output plug-in's Open(). */
218 void aout_VolumeSoftInit( aout_instance_t * p_aout )
219 {
220     int i_volume;
221
222     i_volume = config_GetInt( p_aout, "volume" );
223     if ( i_volume == -1 )
224     {
225         p_aout->output.i_volume = AOUT_VOLUME_DEFAULT;
226     }
227     else
228     {
229         p_aout->output.i_volume = i_volume;
230     }
231
232     p_aout->output.pf_volume_infos = aout_VolumeSoftInfos;
233     p_aout->output.pf_volume_get = aout_VolumeSoftGet;
234     p_aout->output.pf_volume_set = aout_VolumeSoftSet;
235 }
236
237 /* Placeholder for pf_volume_infos(). */
238 int aout_VolumeSoftInfos( aout_instance_t * p_aout,
239                           audio_volume_t * pi_low_soft,
240                           audio_volume_t * pi_high_soft )
241 {
242     *pi_low_soft = *pi_high_soft = AOUT_VOLUME_DEFAULT;
243     return 0;
244 }
245
246 /* Placeholder for pf_volume_get(). */
247 int aout_VolumeSoftGet( aout_instance_t * p_aout,
248                         audio_volume_t * pi_volume )
249 {
250     *pi_volume = p_aout->output.i_volume;
251     return 0;
252 }
253
254
255 /* Placeholder for pf_volume_set(). */
256 int aout_VolumeSoftSet( aout_instance_t * p_aout,
257                         audio_volume_t i_volume )
258 {
259     aout_MixerMultiplierSet( p_aout, (float)(i_volume / AOUT_VOLUME_DEFAULT) );
260     return 0;
261 }
262
263 /*
264  * The next functions are not supposed to be called by the interface, but
265  * are placeholders for unsupported scaling.
266  */
267
268 /* Meant to be called by the output plug-in's Open(). */
269 void aout_VolumeNoneInit( aout_instance_t * p_aout )
270 {
271     p_aout->output.pf_volume_infos = aout_VolumeNoneInfos;
272     p_aout->output.pf_volume_get = aout_VolumeNoneGet;
273     p_aout->output.pf_volume_set = aout_VolumeNoneSet;
274 }
275
276 /* Placeholder for pf_volume_infos(). */
277 int aout_VolumeNoneInfos( aout_instance_t * p_aout,
278                           audio_volume_t * pi_low_soft,
279                           audio_volume_t * pi_high_soft )
280 {
281     return -1;
282 }
283
284 /* Placeholder for pf_volume_get(). */
285 int aout_VolumeNoneGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
286 {
287     return -1;
288 }
289
290
291 /* Placeholder for pf_volume_set(). */
292 int aout_VolumeNoneSet( aout_instance_t * p_aout, audio_volume_t i_volume )
293 {
294     return -1;
295 }
296