]> git.sesse.net Git - vlc/blob - src/audio_output/intf.c
4fb85ae3eedf828041a062e4743deaf19e6cf2d2
[vlc] / src / audio_output / intf.c
1 /*****************************************************************************
2  * intf.c : audio output API towards the interface modules
3  *****************************************************************************
4  * Copyright (C) 2002-2007 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33
34 #include <stdio.h>
35 #include <stdlib.h>                            /* calloc(), malloc(), free() */
36 #include <string.h>
37
38 #include <vlc_aout.h>
39 #include "aout_internal.h"
40
41 #include <vlc_playlist.h>
42
43 static aout_instance_t *findAout (vlc_object_t *obj)
44 {
45     input_thread_t *(*pf_find_input) (vlc_object_t *);
46
47     pf_find_input = var_GetAddress (obj, "find-input-callback");
48     if (unlikely(pf_find_input == NULL))
49         return NULL;
50
51     input_thread_t *p_input = pf_find_input (obj);
52     if (p_input == NULL)
53        return NULL;
54
55     aout_instance_t *p_aout = input_GetAout (p_input);
56     vlc_object_release (p_input);
57     return p_aout;
58 }
59 #define findAout(o) findAout(VLC_OBJECT(o))
60
61 /** Start a volume change transaction. */
62 static void prepareVolume (vlc_object_t *obj, aout_instance_t **aoutp,
63                            audio_volume_t *volp, bool *mutep)
64 {
65     aout_instance_t *aout = findAout (obj);
66
67     /* FIXME: we need interlocking even if aout does not exist! */
68     *aoutp = aout;
69     if (aout != NULL)
70         aout_lock_volume (aout);
71     if (volp != NULL)
72         *volp = config_GetInt (obj, "volume");
73     if (mutep != NULL)
74         *mutep = var_GetBool (obj, "volume-muted");
75 }
76
77 /** Commit a volume change transaction. */
78 static int commitVolume (vlc_object_t *obj, aout_instance_t *aout,
79                          audio_volume_t volume, bool mute)
80 {
81     int ret = 0;
82
83     config_PutInt (obj, "volume", volume);
84     if (mute)
85         volume = AOUT_VOLUME_MIN;
86     var_SetBool (obj, "volume-muted", mute);
87
88     if (aout != NULL)
89     {
90         aout_lock_mixer (aout);
91         aout_lock_input_fifos (aout);
92         if (aout->p_mixer != NULL)
93             ret = aout->output.pf_volume_set (aout, volume);
94         aout_unlock_input_fifos (aout);
95         aout_unlock_mixer (aout);
96
97         if (ret == 0)
98             var_SetBool (aout, "intf-change", true);
99         aout_unlock_volume (aout);
100         vlc_object_release (aout);
101     }
102
103     /* trigger callbacks */
104     var_TriggerCallback (obj, "volume-change");
105
106     return ret;
107 }
108
109 #if 0
110 /** Cancel a volume change transaction. */
111 static void cancelVolume (vlc_object_t *obj, aout_instance_t *aout)
112 {
113     (void) obj;
114     if (aout != NULL)
115     {
116         aout_unlock_volume (aout);
117         vlc_object_release (aout);
118     }
119 }
120 #endif
121
122 #undef aout_VolumeGet
123 /**
124  * Gets the volume of the output device (independent of mute).
125  */
126 int aout_VolumeGet (vlc_object_t *obj, audio_volume_t *volp)
127 {
128 #if 0
129     aout_instance_t *aout;
130     int ret;
131     audio_volume_t volume;
132     bool mute;
133
134     prepareVolume (obj, &aout, &volume, &mute);
135     cancelVolume (obj, aout);
136     mute = !mute;
137     ret = commitVolume (obj, aout, volume, mute);
138     if (volp != NULL)
139         *volp = mute ? AOUT_VOLUME_MIN : volume;
140     return ret;
141 #else
142     *volp = config_GetInt (obj, "volume");
143     return 0;
144 #endif
145 }
146
147 #undef aout_VolumeSet
148 /**
149  * Sets the volume of the output device.
150  * The mute status is not changed.
151  */
152 int aout_VolumeSet (vlc_object_t *obj, audio_volume_t volume)
153 {
154     aout_instance_t *aout;
155     bool mute;
156
157     prepareVolume (obj, &aout, NULL, &mute);
158     return commitVolume (obj, aout, volume, mute);
159 }
160
161 #undef aout_VolumeUp
162 /**
163  * Raises the volume.
164  * \param volp if non-NULL, will contain contain the resulting volume
165  */
166 int aout_VolumeUp (vlc_object_t *obj, int steps, audio_volume_t *volp)
167 {
168     aout_instance_t *aout;
169     int ret;
170     int stepsize = var_InheritInteger (obj, "volume-step");
171     audio_volume_t volume;
172     bool mute;
173
174     prepareVolume (obj, &aout, &volume, &mute);
175     volume += stepsize * steps;
176     ret = commitVolume (obj, aout, volume, mute);
177     if (volp != NULL)
178         *volp = volume;
179     return ret;
180 }
181
182 #undef aout_VolumeDown
183 /**
184  * Lowers the volume. See aout_VolumeUp().
185  */
186 int aout_VolumeDown (vlc_object_t *obj, int steps, audio_volume_t *volp)
187 {
188     return aout_VolumeUp (obj, -steps, volp);
189 }
190
191 #undef aout_ToggleMute
192 /**
193  * Toggles the mute state.
194  */
195 int aout_ToggleMute (vlc_object_t *obj, audio_volume_t *volp)
196 {
197     aout_instance_t *aout;
198     int ret;
199     audio_volume_t volume;
200     bool mute;
201
202     prepareVolume (obj, &aout, &volume, &mute);
203     mute = !mute;
204     ret = commitVolume (obj, aout, volume, mute);
205     if (volp != NULL)
206         *volp = mute ? AOUT_VOLUME_MIN : volume;
207     return ret;
208 }
209
210 /**
211  * Gets the output mute status.
212  */
213 bool aout_IsMuted (vlc_object_t *obj)
214 {
215 #if 0
216     aout_instance_t *aout;
217     bool mute;
218
219     prepareVolume (obj, &aout, NULL, &mute);
220     cancelVolume (obj, aout);
221     return mute;
222 #else
223     return var_GetBool (obj, "volume-muted");
224 #endif
225 }
226
227 /**
228  * Sets mute status.
229  */
230 int aout_SetMute (vlc_object_t *obj, audio_volume_t *volp, bool mute)
231 {
232     aout_instance_t *aout;
233     int ret;
234     audio_volume_t volume;
235
236     prepareVolume (obj, &aout, &volume, NULL);
237     ret = commitVolume (obj, aout, volume, mute);
238     if (volp != NULL)
239         *volp = mute ? AOUT_VOLUME_MIN : volume;
240     return ret;
241 }
242
243 /*
244  * The next functions are not supposed to be called by the interface, but
245  * are placeholders for software-only scaling.
246  */
247
248 /* Meant to be called by the output plug-in's Open(). */
249 void aout_VolumeSoftInit( aout_instance_t * p_aout )
250 {
251     int i_volume;
252
253     p_aout->output.pf_volume_get = aout_VolumeSoftGet;
254     p_aout->output.pf_volume_set = aout_VolumeSoftSet;
255
256     i_volume = config_GetInt( p_aout, "volume" );
257     if ( i_volume < AOUT_VOLUME_MIN )
258     {
259         i_volume = AOUT_VOLUME_DEFAULT;
260     }
261     else if ( i_volume > AOUT_VOLUME_MAX )
262     {
263         i_volume = AOUT_VOLUME_MAX;
264     }
265
266     aout_VolumeSoftSet( p_aout, (audio_volume_t)i_volume );
267 }
268
269 /* Placeholder for pf_volume_get(). */
270 int aout_VolumeSoftGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
271 {
272     *pi_volume = p_aout->output.i_volume;
273     return 0;
274 }
275
276
277 /* Placeholder for pf_volume_set(). */
278 int aout_VolumeSoftSet( aout_instance_t * p_aout, audio_volume_t i_volume )
279 {
280     aout_MixerMultiplierSet( p_aout, (float)i_volume / AOUT_VOLUME_DEFAULT );
281     p_aout->output.i_volume = i_volume;
282     return 0;
283 }
284
285 /*
286  * The next functions are not supposed to be called by the interface, but
287  * are placeholders for unsupported scaling.
288  */
289
290 /* Meant to be called by the output plug-in's Open(). */
291 void aout_VolumeNoneInit( aout_instance_t * p_aout )
292 {
293     p_aout->output.pf_volume_get = aout_VolumeNoneGet;
294     p_aout->output.pf_volume_set = aout_VolumeNoneSet;
295 }
296
297 /* Placeholder for pf_volume_get(). */
298 int aout_VolumeNoneGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
299 {
300     (void)p_aout; (void)pi_volume;
301     return -1;
302 }
303
304 /* Placeholder for pf_volume_set(). */
305 int aout_VolumeNoneSet( aout_instance_t * p_aout, audio_volume_t i_volume )
306 {
307     (void)p_aout; (void)i_volume;
308     return -1;
309 }
310
311
312 /*
313  * Pipelines management
314  */
315
316 /*****************************************************************************
317  * aout_Restart : re-open the output device and rebuild the input and output
318  *                pipelines
319  *****************************************************************************
320  * This function is used whenever the parameters of the output plug-in are
321  * changed (eg. selecting S/PDIF or PCM).
322  *****************************************************************************/
323 static int aout_Restart( aout_instance_t * p_aout )
324 {
325     int i;
326     bool b_error = 0;
327
328     aout_lock_mixer( p_aout );
329
330     if ( p_aout->i_nb_inputs == 0 )
331     {
332         aout_unlock_mixer( p_aout );
333         msg_Err( p_aout, "no decoder thread" );
334         return -1;
335     }
336
337     for ( i = 0; i < p_aout->i_nb_inputs; i++ )
338     {
339         aout_lock_input( p_aout, p_aout->pp_inputs[i] );
340         aout_lock_input_fifos( p_aout );
341         aout_InputDelete( p_aout, p_aout->pp_inputs[i] );
342         aout_unlock_input_fifos( p_aout );
343     }
344
345     /* Lock all inputs. */
346     aout_lock_input_fifos( p_aout );
347     aout_MixerDelete( p_aout );
348
349     /* Re-open the output plug-in. */
350     aout_OutputDelete( p_aout );
351
352     if ( aout_OutputNew( p_aout, &p_aout->pp_inputs[0]->input ) == -1 )
353     {
354         /* Release all locks and report the error. */
355         for ( i = 0; i < p_aout->i_nb_inputs; i++ )
356         {
357             vlc_mutex_unlock( &p_aout->pp_inputs[i]->lock );
358         }
359         aout_unlock_input_fifos( p_aout );
360         aout_unlock_mixer( p_aout );
361         return -1;
362     }
363
364     if ( aout_MixerNew( p_aout ) == -1 )
365     {
366         aout_OutputDelete( p_aout );
367         for ( i = 0; i < p_aout->i_nb_inputs; i++ )
368         {
369             vlc_mutex_unlock( &p_aout->pp_inputs[i]->lock );
370         }
371         aout_unlock_input_fifos( p_aout );
372         aout_unlock_mixer( p_aout );
373         return -1;
374     }
375
376     /* Re-open all inputs. */
377     for ( i = 0; i < p_aout->i_nb_inputs; i++ )
378     {
379         aout_input_t * p_input = p_aout->pp_inputs[i];
380         b_error |= aout_InputNew( p_aout, p_input, &p_input->request_vout );
381         p_input->b_changed = 1;
382         aout_unlock_input( p_aout, p_input );
383     }
384
385     aout_unlock_input_fifos( p_aout );
386     aout_unlock_mixer( p_aout );
387
388     return b_error;
389 }
390
391 /*****************************************************************************
392  * aout_ChannelsRestart : change the audio device or channels and restart
393  *****************************************************************************/
394 int aout_ChannelsRestart( vlc_object_t * p_this, const char * psz_variable,
395                           vlc_value_t oldval, vlc_value_t newval,
396                           void *p_data )
397 {
398     aout_instance_t * p_aout = (aout_instance_t *)p_this;
399     (void)oldval; (void)newval; (void)p_data;
400
401     if ( !strcmp( psz_variable, "audio-device" ) )
402     {
403         /* This is supposed to be a significant change and supposes
404          * rebuilding the channel choices. */
405         var_Destroy( p_aout, "audio-channels" );
406     }
407     aout_Restart( p_aout );
408     return 0;
409 }
410
411 #undef aout_EnableFilter
412 /** Enable or disable an audio filter
413  * \param p_this a vlc object
414  * \param psz_name name of the filter
415  * \param b_add are we adding or removing the filter ?
416  */
417 void aout_EnableFilter( vlc_object_t *p_this, const char *psz_name,
418                         bool b_add )
419 {
420     aout_instance_t *p_aout = findAout( p_this );
421
422     if( aout_ChangeFilterString( p_this, p_aout, "audio-filter", psz_name, b_add ) )
423     {
424         if( p_aout )
425             AoutInputsMarkToRestart( p_aout );
426     }
427
428     if( p_aout )
429         vlc_object_release( p_aout );
430 }