LGPL
[vlc.git] / src / audio_output / intf.c
1 /*****************************************************************************
2  * intf.c : audio output API towards the interface modules
3  *****************************************************************************
4  * Copyright (C) 2002-2007 VLC authors and VideoLAN
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 it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * 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 #include <vlc_aout_intf.h>
34
35 #include <stdio.h>
36 #include <stdlib.h>                            /* calloc(), malloc(), free() */
37 #include <string.h>
38
39 #include <vlc_aout.h>
40 #include "aout_internal.h"
41
42 #include <vlc_playlist.h>
43
44 static audio_output_t *findAout (vlc_object_t *obj)
45 {
46     input_thread_t *(*pf_find_input) (vlc_object_t *);
47
48     pf_find_input = var_GetAddress (obj, "find-input-callback");
49     if (unlikely(pf_find_input == NULL))
50         return NULL;
51
52     input_thread_t *p_input = pf_find_input (obj);
53     if (p_input == NULL)
54        return NULL;
55
56     audio_output_t *p_aout = input_GetAout (p_input);
57     vlc_object_release (p_input);
58     return p_aout;
59 }
60 #define findAout(o) findAout(VLC_OBJECT(o))
61
62 /** Start a volume change transaction. */
63 static void prepareVolume (vlc_object_t *obj, audio_output_t **aoutp,
64                            audio_volume_t *volp, bool *mutep)
65 {
66     audio_output_t *aout = findAout (obj);
67
68     /* FIXME: we need interlocking even if aout does not exist! */
69     *aoutp = aout;
70     if (aout != NULL)
71     {
72         obj = VLC_OBJECT(aout); /* use aout volume if aout exists */
73         aout_lock_volume (aout);
74     }
75     if (volp != NULL)
76         *volp = var_InheritInteger (obj, "volume");
77     if (mutep != NULL)
78         *mutep = var_InheritBool (obj, "mute");
79 }
80
81 /** Commit a volume change transaction. */
82 static int commitVolume (vlc_object_t *obj, audio_output_t *aout,
83                          audio_volume_t volume, bool mute)
84 {
85     int ret = 0;
86
87     /* update caller (input manager) volume */
88     var_SetInteger (obj, "volume", volume);
89     var_SetBool (obj, "mute", mute);
90
91     if (aout != NULL)
92     {
93         aout_owner_t *owner = aout_owner (aout);
94         float vol = volume / (float)AOUT_VOLUME_DEFAULT;
95
96         /* apply volume to the pipeline */
97         aout_lock (aout);
98         if (owner->module != NULL)
99             ret = aout->pf_volume_set (aout, vol, mute);
100         aout_unlock (aout);
101
102         /* update aout volume if it maintains its own */
103         var_SetInteger (aout, "volume", volume);
104         var_SetBool (aout, "mute", mute);
105         aout_unlock_volume (aout);
106
107         if (ret == 0)
108             var_TriggerCallback (aout, "intf-change");
109         vlc_object_release (aout);
110     }
111     return ret;
112 }
113
114 /** Cancel a volume change transaction. */
115 static void cancelVolume (vlc_object_t *obj, audio_output_t *aout)
116 {
117     (void) obj;
118     if (aout != NULL)
119     {
120         aout_unlock_volume (aout);
121         vlc_object_release (aout);
122     }
123 }
124
125 #undef aout_VolumeGet
126 /**
127  * Gets the volume of the output device (independent of mute).
128  */
129 audio_volume_t aout_VolumeGet (vlc_object_t *obj)
130 {
131     audio_output_t *aout;
132     audio_volume_t volume;
133
134     prepareVolume (obj, &aout, &volume, NULL);
135     cancelVolume (obj, aout);
136     return volume;
137 }
138
139 #undef aout_VolumeSet
140 /**
141  * Sets the volume of the output device.
142  * The mute status is not changed.
143  */
144 int aout_VolumeSet (vlc_object_t *obj, audio_volume_t volume)
145 {
146     audio_output_t *aout;
147     bool mute;
148
149     prepareVolume (obj, &aout, NULL, &mute);
150     return commitVolume (obj, aout, volume, mute);
151 }
152
153 #undef aout_VolumeUp
154 /**
155  * Raises the volume.
156  * \param value how much to increase (> 0) or decrease (< 0) the volume
157  * \param volp if non-NULL, will contain contain the resulting volume
158  */
159 int aout_VolumeUp (vlc_object_t *obj, int value, audio_volume_t *volp)
160 {
161     audio_output_t *aout;
162     int ret;
163     audio_volume_t volume;
164     bool mute;
165
166     value *= var_InheritInteger (obj, "volume-step");
167
168     prepareVolume (obj, &aout, &volume, &mute);
169     value += volume;
170     if (value < 0)
171         volume = 0;
172     else
173     if (value > AOUT_VOLUME_MAX)
174         volume = AOUT_VOLUME_MAX;
175     else
176         volume = value;
177     ret = commitVolume (obj, aout, volume, mute);
178     if (volp != NULL)
179         *volp = volume;
180     return ret;
181 }
182
183 #undef aout_ToggleMute
184 /**
185  * Toggles the mute state.
186  */
187 int aout_ToggleMute (vlc_object_t *obj, audio_volume_t *volp)
188 {
189     audio_output_t *aout;
190     int ret;
191     audio_volume_t volume;
192     bool mute;
193
194     prepareVolume (obj, &aout, &volume, &mute);
195     mute = !mute;
196     ret = commitVolume (obj, aout, volume, mute);
197     if (volp != NULL)
198         *volp = mute ? 0 : volume;
199     return ret;
200 }
201
202 /**
203  * Gets the output mute status.
204  */
205 bool aout_IsMuted (vlc_object_t *obj)
206 {
207     audio_output_t *aout;
208     bool mute;
209
210     prepareVolume (obj, &aout, NULL, &mute);
211     cancelVolume (obj, aout);
212     return mute;
213 }
214
215 /**
216  * Sets mute status.
217  */
218 int aout_SetMute (vlc_object_t *obj, audio_volume_t *volp, bool mute)
219 {
220     audio_output_t *aout;
221     int ret;
222     audio_volume_t volume;
223
224     prepareVolume (obj, &aout, &volume, NULL);
225     ret = commitVolume (obj, aout, volume, mute);
226     if (volp != NULL)
227         *volp = mute ? 0 : volume;
228     return ret;
229 }
230
231
232 /*
233  * Pipelines management
234  */
235
236 /*****************************************************************************
237  * aout_ChannelsRestart : change the audio device or channels and restart
238  *****************************************************************************/
239 int aout_ChannelsRestart( vlc_object_t * p_this, const char * psz_variable,
240                           vlc_value_t oldval, vlc_value_t newval,
241                           void *p_data )
242 {
243     audio_output_t * p_aout = (audio_output_t *)p_this;
244     (void)oldval; (void)newval; (void)p_data;
245
246     if ( !strcmp( psz_variable, "audio-device" ) )
247     {
248         /* This is supposed to be a significant change and supposes
249          * rebuilding the channel choices. */
250         var_Destroy( p_aout, "audio-channels" );
251     }
252     aout_RequestRestart (p_aout);
253     return 0;
254 }
255
256 #undef aout_EnableFilter
257 /** Enable or disable an audio filter
258  * \param p_this a vlc object
259  * \param psz_name name of the filter
260  * \param b_add are we adding or removing the filter ?
261  */
262 void aout_EnableFilter( vlc_object_t *p_this, const char *psz_name,
263                         bool b_add )
264 {
265     audio_output_t *p_aout = findAout( p_this );
266
267     if( aout_ChangeFilterString( p_this, VLC_OBJECT(p_aout), "audio-filter", psz_name, b_add ) )
268     {
269         if( p_aout )
270             aout_InputRequestRestart( p_aout );
271     }
272
273     if( p_aout )
274         vlc_object_release( p_aout );
275 }