]> git.sesse.net Git - vlc/blob - lib/audio.c
libvlc: thread-safe and more straight-forward audio devices API
[vlc] / lib / audio.c
1 /*****************************************************************************
2  * libvlc_audio.c: New libvlc audio control API
3  *****************************************************************************
4  * Copyright (C) 2006 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Filippo Carone <filippo@carone.org>
8  *          Jean-Paul Saman <jpsaman _at_ m2x _dot_ nl>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <assert.h>
30 #include <math.h>
31
32 #include <vlc/libvlc.h>
33 #include <vlc/libvlc_media.h>
34 #include <vlc/libvlc_media_player.h>
35
36 #include <vlc_common.h>
37 #include <vlc_input.h>
38 #include <vlc_aout_intf.h>
39 #include <vlc_aout.h>
40 #include <vlc_modules.h>
41
42 #include "libvlc_internal.h"
43 #include "media_player_internal.h"
44
45 /*
46  * Remember to release the returned audio_output_t since it is locked at
47  * the end of this function.
48  */
49 static audio_output_t *GetAOut( libvlc_media_player_t *mp )
50 {
51     assert( mp != NULL );
52
53     input_thread_t *p_input = libvlc_get_input_thread( mp );
54     if( p_input == NULL )
55         return NULL;
56
57     audio_output_t * p_aout = input_GetAout( p_input );
58     vlc_object_release( p_input );
59     if( p_aout == NULL )
60         libvlc_printerr( "No active audio output" );
61     return p_aout;
62 }
63
64 /*****************************************
65  * Get the list of available audio outputs
66  *****************************************/
67 libvlc_audio_output_t *
68         libvlc_audio_output_list_get( libvlc_instance_t *p_instance )
69 {
70     VLC_UNUSED( p_instance );
71     libvlc_audio_output_t *list = NULL;
72     module_t **module_list = module_list_get( NULL );
73
74     for (size_t i = 0; module_list[i]; i++)
75     {
76         module_t *module = module_list[i];
77
78         if( !module_provides( module, "audio output" ) )
79             continue;
80
81         libvlc_audio_output_t *item = malloc( sizeof( *item ) );
82         if( unlikely(item == NULL) )
83         {
84     error:
85             libvlc_printerr( "Not enough memory" );
86             libvlc_audio_output_list_release( list );
87             list = NULL;
88             break;
89         }
90
91         item->psz_name = strdup( module_get_object( module ) );
92         item->psz_description = strdup( module_get_name( module, true ) );
93         if( unlikely(item->psz_name == NULL || item->psz_description == NULL) )
94         {
95             free( item );
96             goto error;
97         }
98         item->p_next = list;
99         list = item;
100     }
101     module_list_free( module_list );
102
103     return list;
104 }
105
106 /********************************************
107  * Free the list of available audio outputs
108  ***********************************************/
109 void libvlc_audio_output_list_release( libvlc_audio_output_t *list )
110 {
111     while( list != NULL )
112     {
113         libvlc_audio_output_t *next = list->p_next;
114
115         free( list->psz_name );
116         free( list->psz_description );
117         free( list );
118         list = next;
119     }
120 }
121
122
123 /***********************
124  * Set the audio output.
125  ***********************/
126 int libvlc_audio_output_set( libvlc_media_player_t *mp, const char *psz_name )
127 {
128     char *value;
129
130     if( !module_exists( psz_name )
131      || asprintf( &value, "%s,none", psz_name ) == -1 )
132         return -1;
133     var_SetString( mp, "aout", value );
134     free( value );
135     return 0;
136 }
137
138 libvlc_audio_output_device_t *
139 libvlc_audio_output_device_list_get( libvlc_instance_t *p_instance,
140                                      const char *aout )
141 {
142     char varname[32];
143     if( (size_t)snprintf( varname, sizeof(varname), "%s-output-device", aout )
144                                                            >= sizeof(varname) )
145         return NULL;
146
147     libvlc_audio_output_device_t *list = NULL, **pp = &list;
148     char **values, **texts;
149     ssize_t count = config_GetPszChoices( VLC_OBJECT(p_instance->p_libvlc_int),
150                                           varname, &values, &texts );
151     for( ssize_t i = 0; i < count; i++ )
152     {
153         libvlc_audio_output_device_t *item = malloc( sizeof(*item) );
154         if( unlikely(item == NULL) )
155             break;
156
157         *pp = item;
158         pp = &item->p_next;
159         item->psz_device = values[i];
160         item->psz_description = texts[i];
161     }
162
163     *pp = NULL;
164     free( texts );
165     free( values );
166     (void) p_instance;
167     return list;
168 }
169
170 void libvlc_audio_output_device_list_release( libvlc_audio_output_device_t *l )
171 {
172     while( l != NULL )
173     {
174         libvlc_audio_output_device_t *next = l->p_next;
175
176         free( l->psz_description );
177         free( l->psz_device );
178         free( l );
179         l = next;
180     }
181 }
182
183 int libvlc_audio_output_device_count( libvlc_instance_t *p_instance,
184                                       const char *psz_audio_output )
185 {
186     (void) p_instance; (void) psz_audio_output;
187     return 0;
188 }
189
190 char *libvlc_audio_output_device_longname( libvlc_instance_t *p_instance,
191                                            const char *psz_audio_output,
192                                            int i_device )
193 {
194     (void) p_instance; (void) psz_audio_output; (void) i_device;
195     return NULL;
196 }
197
198 char *libvlc_audio_output_device_id( libvlc_instance_t *p_instance,
199                                      const char *psz_audio_output,
200                                      int i_device )
201 {
202     (void) p_instance; (void) psz_audio_output; (void) i_device;
203     return NULL;
204 }
205
206 /*****************************
207  * Set device for using
208  *****************************/
209 void libvlc_audio_output_device_set( libvlc_media_player_t *mp,
210                                      const char *psz_audio_output,
211                                      const char *psz_device_id )
212 {
213     char *psz_config_name;
214     if( !psz_audio_output || !psz_device_id )
215         return;
216     if( asprintf( &psz_config_name, "%s-audio-device", psz_audio_output ) == -1 )
217         return;
218     if( !var_Type( mp, psz_config_name ) )
219         /* Don't recreate the same variable over and over and over... */
220         var_Create( mp, psz_config_name, VLC_VAR_STRING );
221     var_SetString( mp, psz_config_name, psz_device_id );
222     free( psz_config_name );
223 }
224
225 /*****************************************************************************
226  * libvlc_audio_output_get_device_type : Get the current audio device type
227  *****************************************************************************/
228 int libvlc_audio_output_get_device_type( libvlc_media_player_t *mp )
229 {
230     audio_output_t *p_aout = GetAOut( mp );
231     if( p_aout )
232     {
233         int i_device_type = var_GetInteger( p_aout, "audio-device" );
234         vlc_object_release( p_aout );
235         return i_device_type;
236     }
237     return libvlc_AudioOutputDevice_Error;
238 }
239
240 /*****************************************************************************
241  * libvlc_audio_output_set_device_type : Set the audio device type
242  *****************************************************************************/
243 void libvlc_audio_output_set_device_type( libvlc_media_player_t *mp,
244                                           int device_type )
245 {
246     audio_output_t *p_aout = GetAOut( mp );
247     if( !p_aout )
248         return;
249     if( var_SetInteger( p_aout, "audio-device", device_type ) < 0 )
250         libvlc_printerr( "Error setting audio device" );
251     vlc_object_release( p_aout );
252 }
253
254 void libvlc_audio_toggle_mute( libvlc_media_player_t *mp )
255 {
256     aout_MuteToggle( mp );
257 }
258
259 int libvlc_audio_get_mute( libvlc_media_player_t *mp )
260 {
261     return aout_MuteGet( mp );
262 }
263
264 void libvlc_audio_set_mute( libvlc_media_player_t *mp, int mute )
265 {
266     aout_MuteSet( VLC_OBJECT(mp), mute != 0 );
267 }
268
269 int libvlc_audio_get_volume( libvlc_media_player_t *mp )
270 {
271     float vol = aout_VolumeGet( mp );
272     return ( vol >= 0.f ) ? lroundf( vol * 100.f ) : -1;
273 }
274
275 int libvlc_audio_set_volume( libvlc_media_player_t *mp, int volume )
276 {
277     float vol = volume / 100.f;
278     if (vol < 0.f)
279     {
280         libvlc_printerr( "Volume out of range" );
281         return -1;
282     }
283     aout_VolumeSet (mp, vol);
284     return 0;
285 }
286
287 /*****************************************************************************
288  * libvlc_audio_get_track_count : Get the number of available audio tracks
289  *****************************************************************************/
290 int libvlc_audio_get_track_count( libvlc_media_player_t *p_mi )
291 {
292     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
293     int i_track_count;
294
295     if( !p_input_thread )
296         return -1;
297
298     i_track_count = var_CountChoices( p_input_thread, "audio-es" );
299
300     vlc_object_release( p_input_thread );
301     return i_track_count;
302 }
303
304 /*****************************************************************************
305  * libvlc_audio_get_track_description : Get the description of available audio tracks
306  *****************************************************************************/
307 libvlc_track_description_t *
308         libvlc_audio_get_track_description( libvlc_media_player_t *p_mi )
309 {
310     return libvlc_get_track_description( p_mi, "audio-es" );
311 }
312
313 /*****************************************************************************
314  * libvlc_audio_get_track : Get the current audio track
315  *****************************************************************************/
316 int libvlc_audio_get_track( libvlc_media_player_t *p_mi )
317 {
318     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
319     vlc_value_t val_list;
320     vlc_value_t val;
321     int i_track = -1;
322     int i;
323
324     if( !p_input_thread )
325         return -1;
326
327     if( var_Get( p_input_thread, "audio-es", &val ) < 0 )
328     {
329         vlc_object_release( p_input_thread );
330         libvlc_printerr( "Audio track information not found" );
331         return -1;
332     }
333
334     var_Change( p_input_thread, "audio-es", VLC_VAR_GETCHOICES, &val_list, NULL );
335     for( i = 0; i < val_list.p_list->i_count; i++ )
336     {
337         if( val_list.p_list->p_values[i].i_int == val.i_int )
338         {
339             i_track = i;
340             break;
341         }
342     }
343     var_FreeList( &val_list, NULL );
344     vlc_object_release( p_input_thread );
345     return i_track;
346 }
347
348 /*****************************************************************************
349  * libvlc_audio_set_track : Set the current audio track
350  *****************************************************************************/
351 int libvlc_audio_set_track( libvlc_media_player_t *p_mi, int i_track )
352 {
353     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
354     vlc_value_t val_list;
355     vlc_value_t newval;
356     int i_ret;
357
358     if( !p_input_thread )
359         return -1;
360
361     var_Change( p_input_thread, "audio-es", VLC_VAR_GETCHOICES, &val_list, NULL );
362     if( (i_track < 0) || (i_track > val_list.p_list->i_count) )
363     {
364         libvlc_printerr( "Audio track out of range" );
365         i_ret = -1;
366         goto end;
367     }
368
369     newval = val_list.p_list->p_values[i_track];
370     i_ret = var_Set( p_input_thread, "audio-es", newval );
371     if( i_ret < 0 )
372     {
373         libvlc_printerr( "Audio track out of range" ); /* Race... */
374         i_ret = -1;
375         goto end;
376     }
377     i_ret = 0;
378
379 end:
380     var_FreeList( &val_list, NULL );
381     vlc_object_release( p_input_thread );
382     return i_ret;
383 }
384
385 /*****************************************************************************
386  * libvlc_audio_get_channel : Get the current audio channel
387  *****************************************************************************/
388 int libvlc_audio_get_channel( libvlc_media_player_t *mp )
389 {
390     audio_output_t *p_aout = GetAOut( mp );
391     if( !p_aout )
392         return 0;
393
394     int val = var_GetInteger( p_aout, "audio-channels" );
395     vlc_object_release( p_aout );
396     return val;
397 }
398
399 /*****************************************************************************
400  * libvlc_audio_set_channel : Set the current audio channel
401  *****************************************************************************/
402 int libvlc_audio_set_channel( libvlc_media_player_t *mp, int channel )
403 {
404     audio_output_t *p_aout = GetAOut( mp );
405     int ret = 0;
406
407     if( !p_aout )
408         return -1;
409
410     if( var_SetInteger( p_aout, "audio-channels", channel ) < 0 )
411     {
412         libvlc_printerr( "Audio channel out of range" );
413         ret = -1;
414     }
415     vlc_object_release( p_aout );
416     return ret;
417 }
418
419 /*****************************************************************************
420  * libvlc_audio_get_delay : Get the current audio delay
421  *****************************************************************************/
422 int64_t libvlc_audio_get_delay( libvlc_media_player_t *p_mi )
423 {
424     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
425     int64_t val = 0;
426     if( p_input_thread != NULL )
427     {
428       val = var_GetTime( p_input_thread, "audio-delay" );
429       vlc_object_release( p_input_thread );
430     }
431     return val;
432 }
433
434 /*****************************************************************************
435  * libvlc_audio_set_delay : Set the current audio delay
436  *****************************************************************************/
437 int libvlc_audio_set_delay( libvlc_media_player_t *p_mi, int64_t i_delay )
438 {
439     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
440     int ret = 0;
441     if( p_input_thread != NULL )
442     {
443       var_SetTime( p_input_thread, "audio-delay", i_delay );
444       vlc_object_release( p_input_thread );
445     }
446     else
447     {
448       ret = -1;
449     }
450     return ret;
451 }