]> git.sesse.net Git - vlc/blob - src/audio_output/intf.c
Fixed p_aout was used after the object was released.
[vlc] / src / audio_output / intf.c
1 /*****************************************************************************
2  * intf.c : audio output API towards the interface modules
3  *****************************************************************************
4  * Copyright (C) 2002-2004 the VideoLAN team
5  * $Id$
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 /*
37  * Volume management
38  *
39  * The hardware volume cannot be set if the output module gets deleted, so
40  * we must take the mixer lock. The software volume cannot be set while the
41  * mixer is running, so we need the mixer lock (too).
42  *
43  * Here is a schematic of the i_volume range :
44  *
45  * |------------------------------+---------------------------------------|
46  * 0                           pi_soft                                   1024
47  *
48  * Between 0 and pi_soft, the volume is done in hardware by the output
49  * module. Above, the output module will change p_aout->mixer.i_multiplier
50  * (done in software). This scaling may result * in cropping errors and
51  * should be avoided as much as possible.
52  *
53  * It is legal to have *pi_soft == 0, and do everything in software.
54  * It is also legal to have *pi_soft == 1024, and completely avoid
55  * software scaling. However, some streams (esp. A/52) are encoded with
56  * a very low volume and users may complain.
57  */
58
59 /*****************************************************************************
60  * aout_VolumeGet : get the volume of the output device
61  *****************************************************************************/
62 int __aout_VolumeGet( vlc_object_t * p_object, audio_volume_t * pi_volume )
63 {
64     int i_volume, i_result = 0;
65     aout_instance_t * p_aout = vlc_object_find( p_object, VLC_OBJECT_AOUT,
66                                                 FIND_ANYWHERE );
67
68     i_volume = config_GetInt( p_object, "volume" );
69     if ( pi_volume != NULL ) *pi_volume = (audio_volume_t)i_volume;
70
71     if ( p_aout == NULL ) return 0;
72
73     vlc_mutex_lock( &p_aout->mixer_lock );
74     if ( !p_aout->mixer.b_error )
75     {
76         i_result = p_aout->output.pf_volume_get( p_aout, pi_volume );
77     }
78     vlc_mutex_unlock( &p_aout->mixer_lock );
79
80     vlc_object_release( p_aout );
81     return i_result;
82 }
83
84 /*****************************************************************************
85  * aout_VolumeSet : set the volume of the output device
86  *****************************************************************************/
87 int __aout_VolumeSet( vlc_object_t * p_object, audio_volume_t i_volume )
88 {
89     vlc_value_t val;
90     aout_instance_t * p_aout = vlc_object_find( p_object, VLC_OBJECT_AOUT,
91                                                 FIND_ANYWHERE );
92     int i_result = 0;
93
94     config_PutInt( p_object, "volume", i_volume );
95
96     if ( p_aout == NULL ) return 0;
97
98     vlc_mutex_lock( &p_aout->mixer_lock );
99     if ( !p_aout->mixer.b_error )
100     {
101         i_result = p_aout->output.pf_volume_set( p_aout, i_volume );
102     }
103     vlc_mutex_unlock( &p_aout->mixer_lock );
104
105     val.b_bool = VLC_TRUE;
106     var_Set( p_aout, "intf-change", val );
107     vlc_object_release( p_aout );
108     return i_result;
109 }
110
111 /*****************************************************************************
112  * aout_VolumeInfos : get the boundary pi_soft
113  *****************************************************************************/
114 int __aout_VolumeInfos( vlc_object_t * p_object, audio_volume_t * pi_soft )
115 {
116     aout_instance_t * p_aout = vlc_object_find( p_object, VLC_OBJECT_AOUT,
117                                                 FIND_ANYWHERE );
118     int i_result;
119
120     if ( p_aout == NULL ) return 0;
121
122     vlc_mutex_lock( &p_aout->mixer_lock );
123     if ( p_aout->mixer.b_error )
124     {
125         /* The output module is destroyed. */
126         i_result = -1;
127     }
128     else
129     {
130         i_result = p_aout->output.pf_volume_infos( p_aout, pi_soft );
131     }
132     vlc_mutex_unlock( &p_aout->mixer_lock );
133
134     vlc_object_release( p_aout );
135     return i_result;
136 }
137
138 /*****************************************************************************
139  * aout_VolumeUp : raise the output volume
140  *****************************************************************************
141  * If pi_volume != NULL, *pi_volume will contain the volume at the end of the
142  * function.
143  *****************************************************************************/
144 int __aout_VolumeUp( vlc_object_t * p_object, int i_nb_steps,
145                    audio_volume_t * pi_volume )
146 {
147     aout_instance_t * p_aout = vlc_object_find( p_object, VLC_OBJECT_AOUT,
148                                                 FIND_ANYWHERE );
149     int i_result = 0, i_volume = 0, i_volume_step = 0;
150
151     i_volume_step = config_GetInt( p_object->p_vlc, "volume-step" );
152     i_volume = config_GetInt( p_object, "volume" );
153     i_volume += i_volume_step * i_nb_steps;
154     if ( i_volume > AOUT_VOLUME_MAX )
155     {
156         i_volume = AOUT_VOLUME_MAX;
157     }
158     config_PutInt( p_object, "volume", i_volume );
159     var_Create( p_object->p_libvlc, "saved-volume", VLC_VAR_INTEGER );
160     var_SetInteger( p_object->p_libvlc, "saved-volume" , (audio_volume_t) i_volume );
161     if ( pi_volume != NULL ) *pi_volume = (audio_volume_t) i_volume;
162
163     if ( p_aout == NULL ) return 0;
164
165     vlc_mutex_lock( &p_aout->mixer_lock );
166     if ( !p_aout->mixer.b_error )
167     {
168         i_result = p_aout->output.pf_volume_set( p_aout, (audio_volume_t) i_volume );
169     }
170     vlc_mutex_unlock( &p_aout->mixer_lock );
171
172     vlc_object_release( p_aout );
173     return i_result;
174 }
175
176 /*****************************************************************************
177  * aout_VolumeDown : lower the output volume
178  *****************************************************************************
179  * If pi_volume != NULL, *pi_volume will contain the volume at the end of the
180  * function.
181  *****************************************************************************/
182 int __aout_VolumeDown( vlc_object_t * p_object, int i_nb_steps,
183                      audio_volume_t * pi_volume )
184 {
185     aout_instance_t * p_aout = vlc_object_find( p_object, VLC_OBJECT_AOUT,
186                                                 FIND_ANYWHERE );
187     int i_result = 0, i_volume = 0, i_volume_step = 0;
188
189     i_volume_step = config_GetInt( p_object->p_vlc, "volume-step" );
190     i_volume = config_GetInt( p_object, "volume" );
191     i_volume -= i_volume_step * i_nb_steps;
192     if ( i_volume < AOUT_VOLUME_MIN )
193     {
194         i_volume = AOUT_VOLUME_MIN;
195     }
196     config_PutInt( p_object, "volume", i_volume );
197     var_Create( p_object->p_libvlc, "saved-volume", VLC_VAR_INTEGER );
198     var_SetInteger( p_object->p_libvlc, "saved-volume", (audio_volume_t) i_volume );
199     if ( pi_volume != NULL ) *pi_volume = (audio_volume_t) i_volume;
200
201     if ( p_aout == NULL ) return 0;
202
203     vlc_mutex_lock( &p_aout->mixer_lock );
204     if ( !p_aout->mixer.b_error )
205     {
206         i_result = p_aout->output.pf_volume_set( p_aout, (audio_volume_t) i_volume );
207     }
208     vlc_mutex_unlock( &p_aout->mixer_lock );
209
210     vlc_object_release( p_aout );
211     return i_result;
212 }
213
214 /*****************************************************************************
215  * aout_VolumeMute : Mute/un-mute the output volume
216  *****************************************************************************
217  * If pi_volume != NULL, *pi_volume will contain the volume at the end of the
218  * function (muted => 0).
219  *****************************************************************************/
220 int __aout_VolumeMute( vlc_object_t * p_object, audio_volume_t * pi_volume )
221 {
222     int i_result;
223     audio_volume_t i_volume;
224
225     i_volume = (audio_volume_t)config_GetInt( p_object, "volume" );
226     if ( i_volume != 0 )
227     {
228         /* Mute */
229         i_result = aout_VolumeSet( p_object, AOUT_VOLUME_MIN );
230         var_Create( p_object->p_libvlc, "saved-volume", VLC_VAR_INTEGER );
231         var_SetInteger( p_object->p_libvlc, "saved-volume", (int)i_volume );
232         if ( pi_volume != NULL ) *pi_volume = AOUT_VOLUME_MIN;
233     }
234     else
235     {
236         /* Un-mute */
237         var_Create( p_object->p_libvlc, "saved-volume", VLC_VAR_INTEGER );
238         i_volume = (audio_volume_t)var_GetInteger( p_object->p_libvlc,
239                                                    "saved-volume" );
240         i_result = aout_VolumeSet( p_object, i_volume );
241         if ( pi_volume != NULL ) *pi_volume = i_volume;
242     }
243
244     return i_result;
245 }
246
247 /*
248  * The next functions are not supposed to be called by the interface, but
249  * are placeholders for software-only scaling.
250  */
251
252 /* Meant to be called by the output plug-in's Open(). */
253 void aout_VolumeSoftInit( aout_instance_t * p_aout )
254 {
255     int i_volume;
256
257     p_aout->output.pf_volume_infos = aout_VolumeSoftInfos;
258     p_aout->output.pf_volume_get = aout_VolumeSoftGet;
259     p_aout->output.pf_volume_set = aout_VolumeSoftSet;
260
261     i_volume = config_GetInt( p_aout, "volume" );
262     if ( i_volume < AOUT_VOLUME_MIN )
263     {
264         i_volume = AOUT_VOLUME_DEFAULT;
265     }
266     else if ( i_volume > AOUT_VOLUME_MAX )
267     {
268         i_volume = AOUT_VOLUME_MAX;
269     }
270
271     aout_VolumeSoftSet( p_aout, (audio_volume_t)i_volume );
272 }
273
274 /* Placeholder for pf_volume_infos(). */
275 int aout_VolumeSoftInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
276 {
277     *pi_soft = 0;
278     return 0;
279 }
280
281 /* Placeholder for pf_volume_get(). */
282 int aout_VolumeSoftGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
283 {
284     *pi_volume = p_aout->output.i_volume;
285     return 0;
286 }
287
288
289 /* Placeholder for pf_volume_set(). */
290 int aout_VolumeSoftSet( aout_instance_t * p_aout, audio_volume_t i_volume )
291 {
292     aout_MixerMultiplierSet( p_aout, (float)i_volume / AOUT_VOLUME_DEFAULT );
293     p_aout->output.i_volume = i_volume;
294     return 0;
295 }
296
297 /*
298  * The next functions are not supposed to be called by the interface, but
299  * are placeholders for unsupported scaling.
300  */
301
302 /* Meant to be called by the output plug-in's Open(). */
303 void aout_VolumeNoneInit( aout_instance_t * p_aout )
304 {
305     p_aout->output.pf_volume_infos = aout_VolumeNoneInfos;
306     p_aout->output.pf_volume_get = aout_VolumeNoneGet;
307     p_aout->output.pf_volume_set = aout_VolumeNoneSet;
308 }
309
310 /* Placeholder for pf_volume_infos(). */
311 int aout_VolumeNoneInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
312 {
313     return -1;
314 }
315
316 /* Placeholder for pf_volume_get(). */
317 int aout_VolumeNoneGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
318 {
319     return -1;
320 }
321
322 /* Placeholder for pf_volume_set(). */
323 int aout_VolumeNoneSet( aout_instance_t * p_aout, audio_volume_t i_volume )
324 {
325     return -1;
326 }
327
328
329 /*
330  * Pipelines management
331  */
332
333 /*****************************************************************************
334  * aout_Restart : re-open the output device and rebuild the input and output
335  *                pipelines
336  *****************************************************************************
337  * This function is used whenever the parameters of the output plug-in are
338  * changed (eg. selecting S/PDIF or PCM).
339  *****************************************************************************/
340 int aout_Restart( aout_instance_t * p_aout )
341 {
342     int i;
343     vlc_bool_t b_error = 0;
344
345     vlc_mutex_lock( &p_aout->mixer_lock );
346
347     if ( p_aout->i_nb_inputs == 0 )
348     {
349         vlc_mutex_unlock( &p_aout->mixer_lock );
350         msg_Err( p_aout, "no decoder thread" );
351         return -1;
352     }
353
354     /* Lock all inputs. */
355     for ( i = 0; i < p_aout->i_nb_inputs; i++ )
356     {
357         vlc_mutex_lock( &p_aout->pp_inputs[i]->lock );
358         aout_InputDelete( p_aout, p_aout->pp_inputs[i] );
359     }
360
361     aout_MixerDelete( p_aout );
362
363     /* Re-open the output plug-in. */
364     aout_OutputDelete( p_aout );
365
366     if ( aout_OutputNew( p_aout, &p_aout->pp_inputs[0]->input ) == -1 )
367     {
368         /* Release all locks and report the error. */
369         for ( i = 0; i < p_aout->i_nb_inputs; i++ )
370         {
371             vlc_mutex_unlock( &p_aout->pp_inputs[i]->lock );
372         }
373         vlc_mutex_unlock( &p_aout->mixer_lock );
374         return -1;
375     }
376
377     if ( aout_MixerNew( p_aout ) == -1 )
378     {
379         aout_OutputDelete( p_aout );
380         for ( i = 0; i < p_aout->i_nb_inputs; i++ )
381         {
382             vlc_mutex_unlock( &p_aout->pp_inputs[i]->lock );
383         }
384         vlc_mutex_unlock( &p_aout->mixer_lock );
385         return -1;
386     }
387
388     /* Re-open all inputs. */
389     for ( i = 0; i < p_aout->i_nb_inputs; i++ )
390     {
391         aout_input_t * p_input = p_aout->pp_inputs[i];
392
393         b_error |= aout_InputNew( p_aout, p_input );
394         p_input->b_changed = 1;
395         vlc_mutex_unlock( &p_input->lock );
396     }
397
398     vlc_mutex_unlock( &p_aout->mixer_lock );
399
400     return b_error;
401 }
402
403 /*****************************************************************************
404  * aout_FindAndRestart : find the audio output instance and restart
405  *****************************************************************************
406  * This is used for callbacks of the configuration variables, and we believe
407  * that when those are changed, it is a significant change which implies
408  * rebuilding the audio-device and audio-channels variables.
409  *****************************************************************************/
410 int aout_FindAndRestart( vlc_object_t * p_this, const char *psz_name,
411                          vlc_value_t oldval, vlc_value_t val, void *p_data )
412 {
413     aout_instance_t * p_aout = vlc_object_find( p_this, VLC_OBJECT_AOUT,
414                                                 FIND_ANYWHERE );
415
416     if ( p_aout == NULL ) return VLC_SUCCESS;
417
418     if ( var_Type( p_aout, "audio-device" ) != 0 )
419     {
420         var_Destroy( p_aout, "audio-device" );
421     }
422     if ( var_Type( p_aout, "audio-channels" ) != 0 )
423     {
424         var_Destroy( p_aout, "audio-channels" );
425     }
426
427     aout_Restart( p_aout );
428     vlc_object_release( p_aout );
429
430     return VLC_SUCCESS;
431 }
432
433 /*****************************************************************************
434  * aout_ChannelsRestart : change the audio device or channels and restart
435  *****************************************************************************/
436 int aout_ChannelsRestart( vlc_object_t * p_this, const char * psz_variable,
437                           vlc_value_t old_value, vlc_value_t new_value,
438                           void * unused )
439 {
440     aout_instance_t * p_aout = (aout_instance_t *)p_this;
441
442     if ( !strcmp( psz_variable, "audio-device" ) )
443     {
444         /* This is supposed to be a significant change and supposes
445          * rebuilding the channel choices. */
446         if ( var_Type( p_aout, "audio-channels" ) >= 0 )
447         {
448             var_Destroy( p_aout, "audio-channels" );
449         }
450     }
451     aout_Restart( p_aout );
452     return 0;
453 }