audio: support setting device of current audio output (refs #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_list_get( libvlc_instance_t *p_instance,
144                                      const char *aout )
145 {
146     char varname[32];
147     if( (size_t)snprintf( varname, sizeof(varname), "%s-audio-device", aout )
148                                                            >= sizeof(varname) )
149         return NULL;
150
151     libvlc_audio_output_device_t *list = NULL, **pp = &list;
152     char **values, **texts;
153     ssize_t count = config_GetPszChoices( VLC_OBJECT(p_instance->p_libvlc_int),
154                                           varname, &values, &texts );
155     for( ssize_t i = 0; i < count; i++ )
156     {
157         libvlc_audio_output_device_t *item = malloc( sizeof(*item) );
158         if( unlikely(item == NULL) )
159             break;
160
161         *pp = item;
162         pp = &item->p_next;
163         item->psz_device = values[i];
164         item->psz_description = texts[i];
165     }
166
167     *pp = NULL;
168     free( texts );
169     free( values );
170     (void) p_instance;
171     return list;
172 }
173
174 void libvlc_audio_output_device_list_release( libvlc_audio_output_device_t *l )
175 {
176     while( l != NULL )
177     {
178         libvlc_audio_output_device_t *next = l->p_next;
179
180         free( l->psz_description );
181         free( l->psz_device );
182         free( l );
183         l = next;
184     }
185 }
186
187 int libvlc_audio_output_device_count( libvlc_instance_t *p_instance,
188                                       const char *psz_audio_output )
189 {
190     (void) p_instance; (void) psz_audio_output;
191     return 0;
192 }
193
194 char *libvlc_audio_output_device_longname( libvlc_instance_t *p_instance,
195                                            const char *psz_audio_output,
196                                            int i_device )
197 {
198     (void) p_instance; (void) psz_audio_output; (void) i_device;
199     return NULL;
200 }
201
202 char *libvlc_audio_output_device_id( libvlc_instance_t *p_instance,
203                                      const char *psz_audio_output,
204                                      int i_device )
205 {
206     (void) p_instance; (void) psz_audio_output; (void) i_device;
207     return NULL;
208 }
209
210 /*****************************
211  * Set device for using
212  *****************************/
213 void libvlc_audio_output_device_set( libvlc_media_player_t *mp,
214                                      const char *module, const char *devid )
215 {
216     if( devid == NULL )
217         return;
218
219     if( module != NULL )
220     {
221         char *cfg_name;
222
223         if( asprintf( &cfg_name, "%s-audio-device", module ) == -1 )
224             return;
225
226         if( !var_Type( mp, cfg_name ) )
227             /* Don't recreate the same variable over and over and over... */
228             var_Create( mp, cfg_name, VLC_VAR_STRING );
229         var_SetString( mp, cfg_name, devid );
230         free( cfg_name );
231         return;
232     }
233
234     audio_output_t *aout = GetAOut( mp );
235     if( aout != NULL )
236         return;
237
238     aout_DeviceSet( aout, devid );
239     vlc_object_release( aout );
240 }
241
242 int libvlc_audio_output_get_device_type( libvlc_media_player_t *mp )
243 {
244     (void) mp;
245     return libvlc_AudioOutputDevice_Error;
246 }
247
248 void libvlc_audio_output_set_device_type( libvlc_media_player_t *mp,
249                                           int device_type )
250 {
251     (void) mp; (void) device_type;
252 }
253
254 void libvlc_audio_toggle_mute( libvlc_media_player_t *mp )
255 {
256     int mute = libvlc_audio_get_mute( mp );
257     if( mute != -1 )
258         libvlc_audio_set_mute( mp, !mute );
259 }
260
261 int libvlc_audio_get_mute( libvlc_media_player_t *mp )
262 {
263     int mute = -1;
264
265     audio_output_t *aout = GetAOut( mp );
266     if( aout != NULL )
267     {
268         mute = aout_MuteGet( aout );
269         vlc_object_release( aout );
270     }
271     return mute;
272 }
273
274 void libvlc_audio_set_mute( libvlc_media_player_t *mp, int mute )
275 {
276     audio_output_t *aout = GetAOut( mp );
277     if( aout != NULL )
278     {
279         mute = aout_MuteSet( aout, mute );
280         vlc_object_release( aout );
281     }
282 }
283
284 int libvlc_audio_get_volume( libvlc_media_player_t *mp )
285 {
286     int volume = -1;
287
288     audio_output_t *aout = GetAOut( mp );
289     if( aout != NULL )
290     {
291         float vol = aout_VolumeGet( aout );
292         vlc_object_release( aout );
293         volume = lroundf( vol * 100.f );
294     }
295     return volume;
296 }
297
298 int libvlc_audio_set_volume( libvlc_media_player_t *mp, int volume )
299 {
300     float vol = volume / 100.f;
301     if (vol < 0.f)
302     {
303         libvlc_printerr( "Volume out of range" );
304         return -1;
305     }
306
307     int ret = -1;
308     audio_output_t *aout = GetAOut( mp );
309     if( aout != NULL )
310     {
311         ret = aout_VolumeSet( aout, vol );
312         vlc_object_release( aout );
313     }
314     return ret;
315 }
316
317 /*****************************************************************************
318  * libvlc_audio_get_track_count : Get the number of available audio tracks
319  *****************************************************************************/
320 int libvlc_audio_get_track_count( libvlc_media_player_t *p_mi )
321 {
322     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
323     int i_track_count;
324
325     if( !p_input_thread )
326         return -1;
327
328     i_track_count = var_CountChoices( p_input_thread, "audio-es" );
329
330     vlc_object_release( p_input_thread );
331     return i_track_count;
332 }
333
334 /*****************************************************************************
335  * libvlc_audio_get_track_description : Get the description of available audio tracks
336  *****************************************************************************/
337 libvlc_track_description_t *
338         libvlc_audio_get_track_description( libvlc_media_player_t *p_mi )
339 {
340     return libvlc_get_track_description( p_mi, "audio-es" );
341 }
342
343 /*****************************************************************************
344  * libvlc_audio_get_track : Get the current audio track
345  *****************************************************************************/
346 int libvlc_audio_get_track( libvlc_media_player_t *p_mi )
347 {
348     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
349     if( !p_input_thread )
350         return -1;
351
352     int id = var_GetInteger( p_input_thread, "audio-es" );
353     vlc_object_release( p_input_thread );
354     return id;
355 }
356
357 /*****************************************************************************
358  * libvlc_audio_set_track : Set the current audio track
359  *****************************************************************************/
360 int libvlc_audio_set_track( libvlc_media_player_t *p_mi, int i_track )
361 {
362     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
363     vlc_value_t val_list;
364     int i_ret = -1;
365
366     if( !p_input_thread )
367         return -1;
368
369     var_Change( p_input_thread, "audio-es", VLC_VAR_GETCHOICES, &val_list, NULL );
370     for( int i = 0; i < val_list.p_list->i_count; i++ )
371     {
372         if( i_track == val_list.p_list->p_values[i].i_int )
373         {
374             if( var_SetInteger( p_input_thread, "audio-es", i_track ) < 0 )
375                 break;
376             i_ret = 0;
377             goto end;
378         }
379     }
380     libvlc_printerr( "Track identifier not found" );
381 end:
382     var_FreeList( &val_list, NULL );
383     vlc_object_release( p_input_thread );
384     return i_ret;
385 }
386
387 /*****************************************************************************
388  * libvlc_audio_get_channel : Get the current audio channel
389  *****************************************************************************/
390 int libvlc_audio_get_channel( libvlc_media_player_t *mp )
391 {
392     audio_output_t *p_aout = GetAOut( mp );
393     if( !p_aout )
394         return 0;
395
396     int val = var_GetInteger( p_aout, "stereo-mode" );
397     vlc_object_release( p_aout );
398     return val;
399 }
400
401 /*****************************************************************************
402  * libvlc_audio_set_channel : Set the current audio channel
403  *****************************************************************************/
404 int libvlc_audio_set_channel( libvlc_media_player_t *mp, int channel )
405 {
406     audio_output_t *p_aout = GetAOut( mp );
407     int ret = 0;
408
409     if( !p_aout )
410         return -1;
411
412     if( var_SetInteger( p_aout, "stereo-mode", channel ) < 0 )
413     {
414         libvlc_printerr( "Audio channel out of range" );
415         ret = -1;
416     }
417     vlc_object_release( p_aout );
418     return ret;
419 }
420
421 /*****************************************************************************
422  * libvlc_audio_get_delay : Get the current audio delay
423  *****************************************************************************/
424 int64_t libvlc_audio_get_delay( libvlc_media_player_t *p_mi )
425 {
426     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
427     int64_t val = 0;
428     if( p_input_thread != NULL )
429     {
430       val = var_GetTime( p_input_thread, "audio-delay" );
431       vlc_object_release( p_input_thread );
432     }
433     return val;
434 }
435
436 /*****************************************************************************
437  * libvlc_audio_set_delay : Set the current audio delay
438  *****************************************************************************/
439 int libvlc_audio_set_delay( libvlc_media_player_t *p_mi, int64_t i_delay )
440 {
441     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
442     int ret = 0;
443     if( p_input_thread != NULL )
444     {
445       var_SetTime( p_input_thread, "audio-delay", i_delay );
446       vlc_object_release( p_input_thread );
447     }
448     else
449     {
450       ret = -1;
451     }
452     return ret;
453 }
454
455 /*****************************************************************************
456  * libvlc_audio_equalizer_get_preset_count : Get the number of equalizer presets
457  *****************************************************************************/
458 unsigned libvlc_audio_equalizer_get_preset_count( void )
459 {
460     return NB_PRESETS;
461 }
462
463 /*****************************************************************************
464  * libvlc_audio_equalizer_get_preset_name : Get the name for a preset
465  *****************************************************************************/
466 const char *libvlc_audio_equalizer_get_preset_name( unsigned u_index )
467 {
468     if ( u_index >= NB_PRESETS )
469         return NULL;
470
471     return preset_list_text[ u_index ];
472 }
473
474 /*****************************************************************************
475  * libvlc_audio_equalizer_get_band_count : Get the number of equalizer frequency bands
476  *****************************************************************************/
477 unsigned libvlc_audio_equalizer_get_band_count( void )
478 {
479     return EQZ_BANDS_MAX;
480 }
481
482 /*****************************************************************************
483  * libvlc_audio_equalizer_get_band_frequency : Get the frequency for a band
484  *****************************************************************************/
485 float libvlc_audio_equalizer_get_band_frequency( unsigned u_index )
486 {
487     if ( u_index >= EQZ_BANDS_MAX )
488         return -1.f;
489
490     return f_iso_frequency_table_10b[ u_index ];
491 }
492
493 /*****************************************************************************
494  * libvlc_audio_equalizer_new : Create a new audio equalizer with zeroed values
495  *****************************************************************************/
496 libvlc_equalizer_t *libvlc_audio_equalizer_new( void )
497 {
498     libvlc_equalizer_t *p_equalizer;
499     p_equalizer = malloc( sizeof( *p_equalizer ) );
500     if ( unlikely( p_equalizer == NULL ) )
501         return NULL;
502
503     p_equalizer->f_preamp = 0.f;
504     for ( unsigned i = 0; i < EQZ_BANDS_MAX; i++ )
505         p_equalizer->f_amp[ i ] = 0.f;
506
507     return p_equalizer;
508 }
509
510 /*****************************************************************************
511  * libvlc_audio_equalizer_new_from_preset : Create a new audio equalizer based on a preset
512  *****************************************************************************/
513 libvlc_equalizer_t *libvlc_audio_equalizer_new_from_preset( unsigned u_index )
514 {
515     libvlc_equalizer_t *p_equalizer;
516
517     if ( u_index >= NB_PRESETS )
518         return NULL;
519
520     p_equalizer = malloc( sizeof( *p_equalizer ) );
521     if ( unlikely( p_equalizer == NULL ) )
522         return NULL;
523
524     p_equalizer->f_preamp = eqz_preset_10b[ u_index ].f_preamp;
525
526     for ( unsigned i = 0; i < EQZ_BANDS_MAX; i++ )
527         p_equalizer->f_amp[ i ] = eqz_preset_10b[ u_index ].f_amp[ i ];
528
529     return p_equalizer;
530 }
531
532 /*****************************************************************************
533  * libvlc_audio_equalizer_release : Release a previously created equalizer
534  *****************************************************************************/
535 void libvlc_audio_equalizer_release( libvlc_equalizer_t *p_equalizer )
536 {
537     free( p_equalizer );
538 }
539
540 /*****************************************************************************
541  * libvlc_audio_equalizer_set_preamp : Set the preamp value for an equalizer
542  *****************************************************************************/
543 int libvlc_audio_equalizer_set_preamp( libvlc_equalizer_t *p_equalizer, float f_preamp )
544 {
545     if ( f_preamp < -20.0f )
546         f_preamp = -20.0f;
547     else if ( f_preamp > 20.0f )
548         f_preamp = 20.0f;
549
550     p_equalizer->f_preamp = f_preamp;
551     return 0;
552 }
553
554 /*****************************************************************************
555  * libvlc_audio_equalizer_get_preamp : Get the preamp value for an equalizer
556  *****************************************************************************/
557 float libvlc_audio_equalizer_get_preamp( libvlc_equalizer_t *p_equalizer )
558 {
559     return p_equalizer->f_preamp;
560 }
561
562 /*****************************************************************************
563  * libvlc_audio_equalizer_set_amp_at_index : Set the amplification value for an equalizer band
564  *****************************************************************************/
565 int libvlc_audio_equalizer_set_amp_at_index( libvlc_equalizer_t *p_equalizer, float f_amp, unsigned u_band )
566 {
567     if ( u_band >= EQZ_BANDS_MAX )
568         return -1;
569
570     if ( f_amp < -20.0f )
571         f_amp = -20.0f;
572     else if ( f_amp > 20.0f )
573         f_amp = 20.0f;
574
575     p_equalizer->f_amp[ u_band ] = f_amp;
576     return 0;
577 }
578
579 /*****************************************************************************
580  * libvlc_audio_equalizer_get_amp_at_index : Get the amplification value for an equalizer band
581  *****************************************************************************/
582 float libvlc_audio_equalizer_get_amp_at_index( libvlc_equalizer_t *p_equalizer, unsigned u_band )
583 {
584     if ( u_band >= EQZ_BANDS_MAX )
585         return 0.f;
586
587     return p_equalizer->f_amp[ u_band ];
588 }