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