audio: support for enumerating devices of current aoout (fixes #10720)
[vlc.git] / 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.h>
39 #include <vlc_modules.h>
40
41 #include "libvlc_internal.h"
42 #include "media_player_internal.h"
43
44 /*
45  * Remember to release the returned audio_output_t since it is locked at
46  * the end of this function.
47  */
48 static audio_output_t *GetAOut( libvlc_media_player_t *mp )
49 {
50     assert( mp != NULL );
51
52     audio_output_t *p_aout = input_resource_HoldAout( mp->input.p_resource );
53     if( p_aout == NULL )
54         libvlc_printerr( "No active audio output" );
55     return p_aout;
56 }
57
58 /*****************************************
59  * Get the list of available audio outputs
60  *****************************************/
61 libvlc_audio_output_t *
62         libvlc_audio_output_list_get( libvlc_instance_t *p_instance )
63 {
64     size_t count;
65     module_t **module_list = module_list_get( &count );
66     libvlc_audio_output_t *list = NULL;
67
68     for (size_t i = 0; i < count; i++)
69     {
70         module_t *module = module_list[i];
71
72         if( !module_provides( module, "audio output" ) )
73             continue;
74
75         libvlc_audio_output_t *item = malloc( sizeof( *item ) );
76         if( unlikely(item == NULL) )
77         {
78     error:
79             libvlc_printerr( "Not enough memory" );
80             libvlc_audio_output_list_release( list );
81             list = NULL;
82             break;
83         }
84
85         item->psz_name = strdup( module_get_object( module ) );
86         item->psz_description = strdup( module_get_name( module, true ) );
87         if( unlikely(item->psz_name == NULL || item->psz_description == NULL) )
88         {
89             free( item );
90             goto error;
91         }
92         item->p_next = list;
93         list = item;
94     }
95     module_list_free( module_list );
96
97     VLC_UNUSED( p_instance );
98     return list;
99 }
100
101 /********************************************
102  * Free the list of available audio outputs
103  ***********************************************/
104 void libvlc_audio_output_list_release( libvlc_audio_output_t *list )
105 {
106     while( list != NULL )
107     {
108         libvlc_audio_output_t *next = list->p_next;
109
110         free( list->psz_name );
111         free( list->psz_description );
112         free( list );
113         list = next;
114     }
115 }
116
117
118 /***********************
119  * Set the audio output.
120  ***********************/
121 int libvlc_audio_output_set( libvlc_media_player_t *mp, const char *psz_name )
122 {
123     char *value;
124
125     if( !module_exists( psz_name )
126      || asprintf( &value, "%s,none", psz_name ) == -1 )
127         return -1;
128     var_SetString( mp, "aout", value );
129     free( value );
130
131     /* Forget the existing audio output */
132     input_resource_ResetAout(mp->input.p_resource);
133
134     /* Create a new audio output */
135     audio_output_t *aout = input_resource_GetAout(mp->input.p_resource);
136     if( aout != NULL )
137         input_resource_PutAout(mp->input.p_resource, aout);
138
139     return 0;
140 }
141
142 libvlc_audio_output_device_t *
143 libvlc_audio_output_device_enum( libvlc_media_player_t *mp )
144 {
145     audio_output_t *aout = GetAOut( mp );
146     if( aout == NULL )
147         return NULL;
148
149     libvlc_audio_output_device_t *list = NULL, **pp = &list;
150     char **values, **texts;
151
152     int n = aout_DevicesList( aout, &values, &texts );
153     if( n < 0 )
154         goto err;
155
156     for (int i = 0; i < n; i++)
157     {
158         libvlc_audio_output_device_t *item = malloc( sizeof(*item) );
159         if( unlikely(item == NULL) )
160         {
161             free( texts[i] );
162             free( values[i] );
163             continue;
164         }
165
166         *pp = item;
167         pp = &item->p_next;
168         item->psz_device = values[i];
169         item->psz_description = texts[i];
170     }
171
172     free( texts );
173     free( values );
174 err:
175     return list;
176 }
177
178 libvlc_audio_output_device_t *
179 libvlc_audio_output_device_list_get( libvlc_instance_t *p_instance,
180                                      const char *aout )
181 {
182     char varname[32];
183     if( (size_t)snprintf( varname, sizeof(varname), "%s-audio-device", aout )
184                                                            >= sizeof(varname) )
185         return NULL;
186
187     libvlc_audio_output_device_t *list = NULL, **pp = &list;
188     char **values, **texts;
189     ssize_t count = config_GetPszChoices( VLC_OBJECT(p_instance->p_libvlc_int),
190                                           varname, &values, &texts );
191     for( ssize_t i = 0; i < count; i++ )
192     {
193         libvlc_audio_output_device_t *item = malloc( sizeof(*item) );
194         if( unlikely(item == NULL) )
195             break;
196
197         *pp = item;
198         pp = &item->p_next;
199         item->psz_device = values[i];
200         item->psz_description = texts[i];
201     }
202
203     *pp = NULL;
204     free( texts );
205     free( values );
206     (void) p_instance;
207     return list;
208 }
209
210 void libvlc_audio_output_device_list_release( libvlc_audio_output_device_t *l )
211 {
212     while( l != NULL )
213     {
214         libvlc_audio_output_device_t *next = l->p_next;
215
216         free( l->psz_description );
217         free( l->psz_device );
218         free( l );
219         l = next;
220     }
221 }
222
223 int libvlc_audio_output_device_count( libvlc_instance_t *p_instance,
224                                       const char *psz_audio_output )
225 {
226     (void) p_instance; (void) psz_audio_output;
227     return 0;
228 }
229
230 char *libvlc_audio_output_device_longname( libvlc_instance_t *p_instance,
231                                            const char *psz_audio_output,
232                                            int i_device )
233 {
234     (void) p_instance; (void) psz_audio_output; (void) i_device;
235     return NULL;
236 }
237
238 char *libvlc_audio_output_device_id( libvlc_instance_t *p_instance,
239                                      const char *psz_audio_output,
240                                      int i_device )
241 {
242     (void) p_instance; (void) psz_audio_output; (void) i_device;
243     return NULL;
244 }
245
246 /*****************************
247  * Set device for using
248  *****************************/
249 void libvlc_audio_output_device_set( libvlc_media_player_t *mp,
250                                      const char *module, const char *devid )
251 {
252     if( devid == NULL )
253         return;
254
255     if( module != NULL )
256     {
257         char *cfg_name;
258
259         if( asprintf( &cfg_name, "%s-audio-device", module ) == -1 )
260             return;
261
262         if( !var_Type( mp, cfg_name ) )
263             /* Don't recreate the same variable over and over and over... */
264             var_Create( mp, cfg_name, VLC_VAR_STRING );
265         var_SetString( mp, cfg_name, devid );
266         free( cfg_name );
267         return;
268     }
269
270     audio_output_t *aout = GetAOut( mp );
271     if( aout != NULL )
272         return;
273
274     aout_DeviceSet( aout, devid );
275     vlc_object_release( aout );
276 }
277
278 int libvlc_audio_output_get_device_type( libvlc_media_player_t *mp )
279 {
280     (void) mp;
281     return libvlc_AudioOutputDevice_Error;
282 }
283
284 void libvlc_audio_output_set_device_type( libvlc_media_player_t *mp,
285                                           int device_type )
286 {
287     (void) mp; (void) device_type;
288 }
289
290 void libvlc_audio_toggle_mute( libvlc_media_player_t *mp )
291 {
292     int mute = libvlc_audio_get_mute( mp );
293     if( mute != -1 )
294         libvlc_audio_set_mute( mp, !mute );
295 }
296
297 int libvlc_audio_get_mute( libvlc_media_player_t *mp )
298 {
299     int mute = -1;
300
301     audio_output_t *aout = GetAOut( mp );
302     if( aout != NULL )
303     {
304         mute = aout_MuteGet( aout );
305         vlc_object_release( aout );
306     }
307     return mute;
308 }
309
310 void libvlc_audio_set_mute( libvlc_media_player_t *mp, int mute )
311 {
312     audio_output_t *aout = GetAOut( mp );
313     if( aout != NULL )
314     {
315         mute = aout_MuteSet( aout, mute );
316         vlc_object_release( aout );
317     }
318 }
319
320 int libvlc_audio_get_volume( libvlc_media_player_t *mp )
321 {
322     int volume = -1;
323
324     audio_output_t *aout = GetAOut( mp );
325     if( aout != NULL )
326     {
327         float vol = aout_VolumeGet( aout );
328         vlc_object_release( aout );
329         volume = lroundf( vol * 100.f );
330     }
331     return volume;
332 }
333
334 int libvlc_audio_set_volume( libvlc_media_player_t *mp, int volume )
335 {
336     float vol = volume / 100.f;
337     if (vol < 0.f)
338     {
339         libvlc_printerr( "Volume out of range" );
340         return -1;
341     }
342
343     int ret = -1;
344     audio_output_t *aout = GetAOut( mp );
345     if( aout != NULL )
346     {
347         ret = aout_VolumeSet( aout, vol );
348         vlc_object_release( aout );
349     }
350     return ret;
351 }
352
353 /*****************************************************************************
354  * libvlc_audio_get_track_count : Get the number of available audio tracks
355  *****************************************************************************/
356 int libvlc_audio_get_track_count( libvlc_media_player_t *p_mi )
357 {
358     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
359     int i_track_count;
360
361     if( !p_input_thread )
362         return -1;
363
364     i_track_count = var_CountChoices( p_input_thread, "audio-es" );
365
366     vlc_object_release( p_input_thread );
367     return i_track_count;
368 }
369
370 /*****************************************************************************
371  * libvlc_audio_get_track_description : Get the description of available audio tracks
372  *****************************************************************************/
373 libvlc_track_description_t *
374         libvlc_audio_get_track_description( libvlc_media_player_t *p_mi )
375 {
376     return libvlc_get_track_description( p_mi, "audio-es" );
377 }
378
379 /*****************************************************************************
380  * libvlc_audio_get_track : Get the current audio track
381  *****************************************************************************/
382 int libvlc_audio_get_track( libvlc_media_player_t *p_mi )
383 {
384     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
385     if( !p_input_thread )
386         return -1;
387
388     int id = var_GetInteger( p_input_thread, "audio-es" );
389     vlc_object_release( p_input_thread );
390     return id;
391 }
392
393 /*****************************************************************************
394  * libvlc_audio_set_track : Set the current audio track
395  *****************************************************************************/
396 int libvlc_audio_set_track( libvlc_media_player_t *p_mi, int i_track )
397 {
398     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
399     vlc_value_t val_list;
400     int i_ret = -1;
401
402     if( !p_input_thread )
403         return -1;
404
405     var_Change( p_input_thread, "audio-es", VLC_VAR_GETCHOICES, &val_list, NULL );
406     for( int i = 0; i < val_list.p_list->i_count; i++ )
407     {
408         if( i_track == val_list.p_list->p_values[i].i_int )
409         {
410             if( var_SetInteger( p_input_thread, "audio-es", i_track ) < 0 )
411                 break;
412             i_ret = 0;
413             goto end;
414         }
415     }
416     libvlc_printerr( "Track identifier not found" );
417 end:
418     var_FreeList( &val_list, NULL );
419     vlc_object_release( p_input_thread );
420     return i_ret;
421 }
422
423 /*****************************************************************************
424  * libvlc_audio_get_channel : Get the current audio channel
425  *****************************************************************************/
426 int libvlc_audio_get_channel( libvlc_media_player_t *mp )
427 {
428     audio_output_t *p_aout = GetAOut( mp );
429     if( !p_aout )
430         return 0;
431
432     int val = var_GetInteger( p_aout, "stereo-mode" );
433     vlc_object_release( p_aout );
434     return val;
435 }
436
437 /*****************************************************************************
438  * libvlc_audio_set_channel : Set the current audio channel
439  *****************************************************************************/
440 int libvlc_audio_set_channel( libvlc_media_player_t *mp, int channel )
441 {
442     audio_output_t *p_aout = GetAOut( mp );
443     int ret = 0;
444
445     if( !p_aout )
446         return -1;
447
448     if( var_SetInteger( p_aout, "stereo-mode", channel ) < 0 )
449     {
450         libvlc_printerr( "Audio channel out of range" );
451         ret = -1;
452     }
453     vlc_object_release( p_aout );
454     return ret;
455 }
456
457 /*****************************************************************************
458  * libvlc_audio_get_delay : Get the current audio delay
459  *****************************************************************************/
460 int64_t libvlc_audio_get_delay( libvlc_media_player_t *p_mi )
461 {
462     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
463     int64_t val = 0;
464     if( p_input_thread != NULL )
465     {
466       val = var_GetTime( p_input_thread, "audio-delay" );
467       vlc_object_release( p_input_thread );
468     }
469     return val;
470 }
471
472 /*****************************************************************************
473  * libvlc_audio_set_delay : Set the current audio delay
474  *****************************************************************************/
475 int libvlc_audio_set_delay( libvlc_media_player_t *p_mi, int64_t i_delay )
476 {
477     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
478     int ret = 0;
479     if( p_input_thread != NULL )
480     {
481       var_SetTime( p_input_thread, "audio-delay", i_delay );
482       vlc_object_release( p_input_thread );
483     }
484     else
485     {
486       ret = -1;
487     }
488     return ret;
489 }
490
491 /*****************************************************************************
492  * libvlc_audio_equalizer_get_preset_count : Get the number of equalizer presets
493  *****************************************************************************/
494 unsigned libvlc_audio_equalizer_get_preset_count( void )
495 {
496     return NB_PRESETS;
497 }
498
499 /*****************************************************************************
500  * libvlc_audio_equalizer_get_preset_name : Get the name for a preset
501  *****************************************************************************/
502 const char *libvlc_audio_equalizer_get_preset_name( unsigned u_index )
503 {
504     if ( u_index >= NB_PRESETS )
505         return NULL;
506
507     return preset_list_text[ u_index ];
508 }
509
510 /*****************************************************************************
511  * libvlc_audio_equalizer_get_band_count : Get the number of equalizer frequency bands
512  *****************************************************************************/
513 unsigned libvlc_audio_equalizer_get_band_count( void )
514 {
515     return EQZ_BANDS_MAX;
516 }
517
518 /*****************************************************************************
519  * libvlc_audio_equalizer_get_band_frequency : Get the frequency for a band
520  *****************************************************************************/
521 float libvlc_audio_equalizer_get_band_frequency( unsigned u_index )
522 {
523     if ( u_index >= EQZ_BANDS_MAX )
524         return -1.f;
525
526     return f_iso_frequency_table_10b[ u_index ];
527 }
528
529 /*****************************************************************************
530  * libvlc_audio_equalizer_new : Create a new audio equalizer with zeroed values
531  *****************************************************************************/
532 libvlc_equalizer_t *libvlc_audio_equalizer_new( void )
533 {
534     libvlc_equalizer_t *p_equalizer;
535     p_equalizer = malloc( sizeof( *p_equalizer ) );
536     if ( unlikely( p_equalizer == NULL ) )
537         return NULL;
538
539     p_equalizer->f_preamp = 0.f;
540     for ( unsigned i = 0; i < EQZ_BANDS_MAX; i++ )
541         p_equalizer->f_amp[ i ] = 0.f;
542
543     return p_equalizer;
544 }
545
546 /*****************************************************************************
547  * libvlc_audio_equalizer_new_from_preset : Create a new audio equalizer based on a preset
548  *****************************************************************************/
549 libvlc_equalizer_t *libvlc_audio_equalizer_new_from_preset( unsigned u_index )
550 {
551     libvlc_equalizer_t *p_equalizer;
552
553     if ( u_index >= NB_PRESETS )
554         return NULL;
555
556     p_equalizer = malloc( sizeof( *p_equalizer ) );
557     if ( unlikely( p_equalizer == NULL ) )
558         return NULL;
559
560     p_equalizer->f_preamp = eqz_preset_10b[ u_index ].f_preamp;
561
562     for ( unsigned i = 0; i < EQZ_BANDS_MAX; i++ )
563         p_equalizer->f_amp[ i ] = eqz_preset_10b[ u_index ].f_amp[ i ];
564
565     return p_equalizer;
566 }
567
568 /*****************************************************************************
569  * libvlc_audio_equalizer_release : Release a previously created equalizer
570  *****************************************************************************/
571 void libvlc_audio_equalizer_release( libvlc_equalizer_t *p_equalizer )
572 {
573     free( p_equalizer );
574 }
575
576 /*****************************************************************************
577  * libvlc_audio_equalizer_set_preamp : Set the preamp value for an equalizer
578  *****************************************************************************/
579 int libvlc_audio_equalizer_set_preamp( libvlc_equalizer_t *p_equalizer, float f_preamp )
580 {
581     if ( f_preamp < -20.0f )
582         f_preamp = -20.0f;
583     else if ( f_preamp > 20.0f )
584         f_preamp = 20.0f;
585
586     p_equalizer->f_preamp = f_preamp;
587     return 0;
588 }
589
590 /*****************************************************************************
591  * libvlc_audio_equalizer_get_preamp : Get the preamp value for an equalizer
592  *****************************************************************************/
593 float libvlc_audio_equalizer_get_preamp( libvlc_equalizer_t *p_equalizer )
594 {
595     return p_equalizer->f_preamp;
596 }
597
598 /*****************************************************************************
599  * libvlc_audio_equalizer_set_amp_at_index : Set the amplification value for an equalizer band
600  *****************************************************************************/
601 int libvlc_audio_equalizer_set_amp_at_index( libvlc_equalizer_t *p_equalizer, float f_amp, unsigned u_band )
602 {
603     if ( u_band >= EQZ_BANDS_MAX )
604         return -1;
605
606     if ( f_amp < -20.0f )
607         f_amp = -20.0f;
608     else if ( f_amp > 20.0f )
609         f_amp = 20.0f;
610
611     p_equalizer->f_amp[ u_band ] = f_amp;
612     return 0;
613 }
614
615 /*****************************************************************************
616  * libvlc_audio_equalizer_get_amp_at_index : Get the amplification value for an equalizer band
617  *****************************************************************************/
618 float libvlc_audio_equalizer_get_amp_at_index( libvlc_equalizer_t *p_equalizer, unsigned u_band )
619 {
620     if ( u_band >= EQZ_BANDS_MAX )
621         return 0.f;
622
623     return p_equalizer->f_amp[ u_band ];
624 }