]> git.sesse.net Git - vlc/blob - lib/audio.c
libvlc_audio_output_list: simplify and add missing error handling
[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 /****************************
139  * Get count of devices.
140  *****************************/
141 int libvlc_audio_output_device_count( libvlc_instance_t *p_instance,
142                                       const char *psz_audio_output )
143 {
144     char *psz_config_name;
145     if( !psz_audio_output )
146         return 0;
147     if( asprintf( &psz_config_name, "%s-audio-device", psz_audio_output ) == -1 )
148         return 0;
149
150     module_config_t *p_module_config = config_FindConfig(
151         VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name );
152
153     if( p_module_config && p_module_config->pf_update_list )
154     {
155         vlc_value_t val;
156         val.psz_string = strdup( p_module_config->value.psz );
157
158         p_module_config->pf_update_list(
159             VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name, val, val, NULL );
160         free( val.psz_string );
161         free( psz_config_name );
162
163         return p_module_config->i_list;
164     }
165
166     free( psz_config_name );
167     return 0;
168 }
169
170 /********************************
171  * Get long name of device
172  *********************************/
173 char * libvlc_audio_output_device_longname( libvlc_instance_t *p_instance,
174                                             const char *psz_audio_output,
175                                             int i_device )
176 {
177     char *psz_config_name;
178     if( !psz_audio_output )
179         return NULL;
180     if( asprintf( &psz_config_name, "%s-audio-device", psz_audio_output ) == -1 )
181         return NULL;
182
183     module_config_t *p_module_config = config_FindConfig(
184         VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name );
185
186     if( p_module_config )
187     {
188         // refresh if there arent devices
189         if( p_module_config->i_list < 2 && p_module_config->pf_update_list )
190         {
191             vlc_value_t val;
192             val.psz_string = strdup( p_module_config->value.psz );
193
194             p_module_config->pf_update_list(
195                 VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name, val, val, NULL );
196             free( val.psz_string );
197         }
198
199         if( i_device >= 0 && i_device < p_module_config->i_list )
200         {
201             free( psz_config_name );
202
203             if( p_module_config->ppsz_list_text[i_device] )
204                 return strdup( p_module_config->ppsz_list_text[i_device] );
205             else
206                 return strdup( p_module_config->ppsz_list[i_device] );
207         }
208     }
209
210     free( psz_config_name );
211     return NULL;
212 }
213
214 /********************************
215  * Get id name of device
216  *********************************/
217 char * libvlc_audio_output_device_id( libvlc_instance_t *p_instance,
218                                       const char *psz_audio_output,
219                                       int i_device )
220 {
221     char *psz_config_name;
222     if( !psz_audio_output )
223         return NULL;
224     if( asprintf( &psz_config_name, "%s-audio-device", psz_audio_output ) == -1)
225         return NULL;
226
227     module_config_t *p_module_config = config_FindConfig(
228         VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name );
229
230     if( p_module_config )
231     {
232         // refresh if there arent devices
233         if( p_module_config->i_list < 2 && p_module_config->pf_update_list )
234         {
235             vlc_value_t val;
236             val.psz_string = strdup( p_module_config->value.psz );
237
238             p_module_config->pf_update_list(
239                 VLC_OBJECT( p_instance->p_libvlc_int ), psz_config_name, val, val, NULL );
240             free( val.psz_string );
241         }
242
243         if( i_device >= 0 && i_device < p_module_config->i_list )
244         {
245             free( psz_config_name );
246             return strdup( p_module_config->ppsz_list[i_device] );
247         }
248     }
249
250     free( psz_config_name );
251     return NULL;
252 }
253
254 /*****************************
255  * Set device for using
256  *****************************/
257 void libvlc_audio_output_device_set( libvlc_media_player_t *mp,
258                                      const char *psz_audio_output,
259                                      const char *psz_device_id )
260 {
261     char *psz_config_name;
262     if( !psz_audio_output || !psz_device_id )
263         return;
264     if( asprintf( &psz_config_name, "%s-audio-device", psz_audio_output ) == -1 )
265         return;
266     if( !var_Type( mp, psz_config_name ) )
267         /* Don't recreate the same variable over and over and over... */
268         var_Create( mp, psz_config_name, VLC_VAR_STRING );
269     var_SetString( mp, psz_config_name, psz_device_id );
270     free( psz_config_name );
271 }
272
273 /*****************************************************************************
274  * libvlc_audio_output_get_device_type : Get the current audio device type
275  *****************************************************************************/
276 int libvlc_audio_output_get_device_type( libvlc_media_player_t *mp )
277 {
278     audio_output_t *p_aout = GetAOut( mp );
279     if( p_aout )
280     {
281         int i_device_type = var_GetInteger( p_aout, "audio-device" );
282         vlc_object_release( p_aout );
283         return i_device_type;
284     }
285     return libvlc_AudioOutputDevice_Error;
286 }
287
288 /*****************************************************************************
289  * libvlc_audio_output_set_device_type : Set the audio device type
290  *****************************************************************************/
291 void libvlc_audio_output_set_device_type( libvlc_media_player_t *mp,
292                                           int device_type )
293 {
294     audio_output_t *p_aout = GetAOut( mp );
295     if( !p_aout )
296         return;
297     if( var_SetInteger( p_aout, "audio-device", device_type ) < 0 )
298         libvlc_printerr( "Error setting audio device" );
299     vlc_object_release( p_aout );
300 }
301
302 void libvlc_audio_toggle_mute( libvlc_media_player_t *mp )
303 {
304     aout_MuteToggle( mp );
305 }
306
307 int libvlc_audio_get_mute( libvlc_media_player_t *mp )
308 {
309     return aout_MuteGet( mp );
310 }
311
312 void libvlc_audio_set_mute( libvlc_media_player_t *mp, int mute )
313 {
314     aout_MuteSet( VLC_OBJECT(mp), mute != 0 );
315 }
316
317 int libvlc_audio_get_volume( libvlc_media_player_t *mp )
318 {
319     float vol = aout_VolumeGet( mp );
320     return ( vol >= 0.f ) ? lroundf( vol * 100.f ) : -1;
321 }
322
323 int libvlc_audio_set_volume( libvlc_media_player_t *mp, int volume )
324 {
325     float vol = volume / 100.f;
326     if (vol < 0.f)
327     {
328         libvlc_printerr( "Volume out of range" );
329         return -1;
330     }
331     aout_VolumeSet (mp, vol);
332     return 0;
333 }
334
335 /*****************************************************************************
336  * libvlc_audio_get_track_count : Get the number of available audio tracks
337  *****************************************************************************/
338 int libvlc_audio_get_track_count( libvlc_media_player_t *p_mi )
339 {
340     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
341     int i_track_count;
342
343     if( !p_input_thread )
344         return -1;
345
346     i_track_count = var_CountChoices( p_input_thread, "audio-es" );
347
348     vlc_object_release( p_input_thread );
349     return i_track_count;
350 }
351
352 /*****************************************************************************
353  * libvlc_audio_get_track_description : Get the description of available audio tracks
354  *****************************************************************************/
355 libvlc_track_description_t *
356         libvlc_audio_get_track_description( libvlc_media_player_t *p_mi )
357 {
358     return libvlc_get_track_description( p_mi, "audio-es" );
359 }
360
361 /*****************************************************************************
362  * libvlc_audio_get_track : Get the current audio track
363  *****************************************************************************/
364 int libvlc_audio_get_track( libvlc_media_player_t *p_mi )
365 {
366     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
367     vlc_value_t val_list;
368     vlc_value_t val;
369     int i_track = -1;
370     int i;
371
372     if( !p_input_thread )
373         return -1;
374
375     if( var_Get( p_input_thread, "audio-es", &val ) < 0 )
376     {
377         vlc_object_release( p_input_thread );
378         libvlc_printerr( "Audio track information not found" );
379         return -1;
380     }
381
382     var_Change( p_input_thread, "audio-es", VLC_VAR_GETCHOICES, &val_list, NULL );
383     for( i = 0; i < val_list.p_list->i_count; i++ )
384     {
385         if( val_list.p_list->p_values[i].i_int == val.i_int )
386         {
387             i_track = i;
388             break;
389         }
390     }
391     var_FreeList( &val_list, NULL );
392     vlc_object_release( p_input_thread );
393     return i_track;
394 }
395
396 /*****************************************************************************
397  * libvlc_audio_set_track : Set the current audio track
398  *****************************************************************************/
399 int libvlc_audio_set_track( libvlc_media_player_t *p_mi, int i_track )
400 {
401     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
402     vlc_value_t val_list;
403     vlc_value_t newval;
404     int i_ret;
405
406     if( !p_input_thread )
407         return -1;
408
409     var_Change( p_input_thread, "audio-es", VLC_VAR_GETCHOICES, &val_list, NULL );
410     if( (i_track < 0) || (i_track > val_list.p_list->i_count) )
411     {
412         libvlc_printerr( "Audio track out of range" );
413         i_ret = -1;
414         goto end;
415     }
416
417     newval = val_list.p_list->p_values[i_track];
418     i_ret = var_Set( p_input_thread, "audio-es", newval );
419     if( i_ret < 0 )
420     {
421         libvlc_printerr( "Audio track out of range" ); /* Race... */
422         i_ret = -1;
423         goto end;
424     }
425     i_ret = 0;
426
427 end:
428     var_FreeList( &val_list, NULL );
429     vlc_object_release( p_input_thread );
430     return i_ret;
431 }
432
433 /*****************************************************************************
434  * libvlc_audio_get_channel : Get the current audio channel
435  *****************************************************************************/
436 int libvlc_audio_get_channel( libvlc_media_player_t *mp )
437 {
438     audio_output_t *p_aout = GetAOut( mp );
439     if( !p_aout )
440         return 0;
441
442     int val = var_GetInteger( p_aout, "audio-channels" );
443     vlc_object_release( p_aout );
444     return val;
445 }
446
447 /*****************************************************************************
448  * libvlc_audio_set_channel : Set the current audio channel
449  *****************************************************************************/
450 int libvlc_audio_set_channel( libvlc_media_player_t *mp, int channel )
451 {
452     audio_output_t *p_aout = GetAOut( mp );
453     int ret = 0;
454
455     if( !p_aout )
456         return -1;
457
458     if( var_SetInteger( p_aout, "audio-channels", channel ) < 0 )
459     {
460         libvlc_printerr( "Audio channel out of range" );
461         ret = -1;
462     }
463     vlc_object_release( p_aout );
464     return ret;
465 }
466
467 /*****************************************************************************
468  * libvlc_audio_get_delay : Get the current audio delay
469  *****************************************************************************/
470 int64_t libvlc_audio_get_delay( libvlc_media_player_t *p_mi )
471 {
472     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
473     int64_t val = 0;
474     if( p_input_thread != NULL )
475     {
476       val = var_GetTime( p_input_thread, "audio-delay" );
477       vlc_object_release( p_input_thread );
478     }
479     return val;
480 }
481
482 /*****************************************************************************
483  * libvlc_audio_set_delay : Set the current audio delay
484  *****************************************************************************/
485 int libvlc_audio_set_delay( libvlc_media_player_t *p_mi, int64_t i_delay )
486 {
487     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
488     int ret = 0;
489     if( p_input_thread != NULL )
490     {
491       var_SetTime( p_input_thread, "audio-delay", i_delay );
492       vlc_object_release( p_input_thread );
493     }
494     else
495     {
496       ret = -1;
497     }
498     return ret;
499 }