audio.c 19.3 KB
Newer Older
1 2 3
/*****************************************************************************
 * libvlc_audio.c: New libvlc audio control API
 *****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2006 VLC authors and VideoLAN
Filippo Carone's avatar
Filippo Carone committed
5
 * $Id$
6 7
 *
 * Authors: Filippo Carone <filippo@carone.org>
8
 *          Jean-Paul Saman <jpsaman _at_ m2x _dot_ nl>
9
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
10 11 12
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
13 14 15 16
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
17 18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
19
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
20 21 22
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 24
 *****************************************************************************/

25 26 27 28
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

29
#include <assert.h>
30
#include <math.h>
31

32
#include <vlc/libvlc.h>
33
#include <vlc/libvlc_renderer_discoverer.h>
34 35
#include <vlc/libvlc_media.h>
#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 43
#include "libvlc_internal.h"
#include "media_player_internal.h"
44

45
/*
46
 * Remember to release the returned audio_output_t since it is locked at
47 48
 * the end of this function.
 */
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 57 58
    return p_aout;
}

59 60 61
/*****************************************
 * Get the list of available audio outputs
 *****************************************/
62
libvlc_audio_output_t *
63
        libvlc_audio_output_list_get( libvlc_instance_t *p_instance )
64
{
65 66
    size_t count;
    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 74 75 76 77
        if( !module_provides( module, "audio output" ) )
            continue;

        libvlc_audio_output_t *item = malloc( sizeof( *item ) );
        if( unlikely(item == NULL) )
78
        {
79 80 81 82 83
    error:
            libvlc_printerr( "Not enough memory" );
            libvlc_audio_output_list_release( list );
            list = NULL;
            break;
84 85
        }

86 87 88 89
        item->psz_name = strdup( module_get_object( module ) );
        item->psz_description = strdup( module_get_name( module, true ) );
        if( unlikely(item->psz_name == NULL || item->psz_description == NULL) )
        {
90 91
            free( item->psz_name );
            free( item->psz_description );
92 93 94 95 96 97
            free( item );
            goto error;
        }
        item->p_next = list;
        list = item;
    }
98 99
    module_list_free( module_list );

100
    VLC_UNUSED( p_instance );
101
    return list;
102 103 104 105 106
}

/********************************************
 * Free the list of available audio outputs
 ***********************************************/
107
void libvlc_audio_output_list_release( libvlc_audio_output_t *list )
108
{
109
    while( list != NULL )
110
    {
111 112 113 114 115 116
        libvlc_audio_output_t *next = list->p_next;

        free( list->psz_name );
        free( list->psz_description );
        free( list );
        list = next;
117 118 119 120 121 122 123
    }
}


/***********************
 * Set the audio output.
 ***********************/
124
int libvlc_audio_output_set( libvlc_media_player_t *mp, const char *psz_name )
125
{
126 127 128 129
    char *value;

    if( !module_exists( psz_name )
     || asprintf( &value, "%s,none", psz_name ) == -1 )
130
        return -1;
131 132
    var_SetString( mp, "aout", value );
    free( value );
133 134 135 136

    /* Forget the existing audio output */
    input_resource_ResetAout(mp->input.p_resource);

137 138 139 140 141
    /* Create a new audio output */
    audio_output_t *aout = input_resource_GetAout(mp->input.p_resource);
    if( aout != NULL )
        input_resource_PutAout(mp->input.p_resource, aout);

142
    return 0;
143 144
}

145 146 147 148 149 150 151
libvlc_audio_output_device_t *
libvlc_audio_output_device_enum( libvlc_media_player_t *mp )
{
    audio_output_t *aout = GetAOut( mp );
    if( aout == NULL )
        return NULL;

152
    libvlc_audio_output_device_t *list, **pp = &list;
153 154 155
    char **values, **texts;

    int n = aout_DevicesList( aout, &values, &texts );
156
    vlc_object_release( aout );
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
    if( n < 0 )
        goto err;

    for (int i = 0; i < n; i++)
    {
        libvlc_audio_output_device_t *item = malloc( sizeof(*item) );
        if( unlikely(item == NULL) )
        {
            free( texts[i] );
            free( values[i] );
            continue;
        }

        *pp = item;
        pp = &item->p_next;
        item->psz_device = values[i];
        item->psz_description = texts[i];
    }

    free( texts );
    free( values );
err:
179
    *pp = NULL;
180 181 182
    return list;
}

183 184 185
libvlc_audio_output_device_t *
libvlc_audio_output_device_list_get( libvlc_instance_t *p_instance,
                                     const char *aout )
186
{
187
    char varname[32];
188
    if( (size_t)snprintf( varname, sizeof(varname), "%s-audio-device", aout )
189 190
                                                           >= sizeof(varname) )
        return NULL;
191

192 193 194 195 196
    libvlc_audio_output_device_t *list = NULL, **pp = &list;
    char **values, **texts;
    ssize_t count = config_GetPszChoices( VLC_OBJECT(p_instance->p_libvlc_int),
                                          varname, &values, &texts );
    for( ssize_t i = 0; i < count; i++ )
197
    {
198 199 200
        libvlc_audio_output_device_t *item = malloc( sizeof(*item) );
        if( unlikely(item == NULL) )
            break;
201

202 203 204 205
        *pp = item;
        pp = &item->p_next;
        item->psz_device = values[i];
        item->psz_description = texts[i];
206 207
    }

208 209 210 211 212
    *pp = NULL;
    free( texts );
    free( values );
    (void) p_instance;
    return list;
213 214
}

215
void libvlc_audio_output_device_list_release( libvlc_audio_output_device_t *l )
216
{
217
    while( l != NULL )
218
    {
219
        libvlc_audio_output_device_t *next = l->p_next;
220

221 222 223 224
        free( l->psz_description );
        free( l->psz_device );
        free( l );
        l = next;
225 226 227
    }
}

228 229
int libvlc_audio_output_device_count( libvlc_instance_t *p_instance,
                                      const char *psz_audio_output )
230
{
231 232 233
    (void) p_instance; (void) psz_audio_output;
    return 0;
}
234

235 236 237 238 239 240 241
char *libvlc_audio_output_device_longname( libvlc_instance_t *p_instance,
                                           const char *psz_audio_output,
                                           int i_device )
{
    (void) p_instance; (void) psz_audio_output; (void) i_device;
    return NULL;
}
242

243 244 245 246 247
char *libvlc_audio_output_device_id( libvlc_instance_t *p_instance,
                                     const char *psz_audio_output,
                                     int i_device )
{
    (void) p_instance; (void) psz_audio_output; (void) i_device;
248 249 250 251 252 253
    return NULL;
}

/*****************************
 * Set device for using
 *****************************/
254
void libvlc_audio_output_device_set( libvlc_media_player_t *mp,
255
                                     const char *module, const char *devid )
256
{
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
    if( devid == NULL )
        return;

    if( module != NULL )
    {
        char *cfg_name;

        if( asprintf( &cfg_name, "%s-audio-device", module ) == -1 )
            return;

        if( !var_Type( mp, cfg_name ) )
            /* Don't recreate the same variable over and over and over... */
            var_Create( mp, cfg_name, VLC_VAR_STRING );
        var_SetString( mp, cfg_name, devid );
        free( cfg_name );
272
        return;
273 274 275
    }

    audio_output_t *aout = GetAOut( mp );
276
    if( aout == NULL )
277
        return;
278 279 280

    aout_DeviceSet( aout, devid );
    vlc_object_release( aout );
281 282
}

283 284 285 286 287 288 289 290 291 292 293 294 295
char *libvlc_audio_output_device_get( libvlc_media_player_t *mp )
{
    audio_output_t *aout = GetAOut( mp );
    if( aout == NULL )
        return NULL;

    char *devid = aout_DeviceGet( aout );

    vlc_object_release( aout );

    return devid;
}

296
int libvlc_audio_output_get_device_type( libvlc_media_player_t *mp )
297
{
298
    (void) mp;
299 300 301
    return libvlc_AudioOutputDevice_Error;
}

302 303
void libvlc_audio_output_set_device_type( libvlc_media_player_t *mp,
                                          int device_type )
304
{
305
    (void) mp; (void) device_type;
306
}
307

308
void libvlc_audio_toggle_mute( libvlc_media_player_t *mp )
Clément Stenac's avatar
Clément Stenac committed
309
{
310 311 312
    int mute = libvlc_audio_get_mute( mp );
    if( mute != -1 )
        libvlc_audio_set_mute( mp, !mute );
Clément Stenac's avatar
Clément Stenac committed
313 314
}

315
int libvlc_audio_get_mute( libvlc_media_player_t *mp )
316
{
317 318 319 320 321 322 323 324 325
    int mute = -1;

    audio_output_t *aout = GetAOut( mp );
    if( aout != NULL )
    {
        mute = aout_MuteGet( aout );
        vlc_object_release( aout );
    }
    return mute;
326 327
}

328
void libvlc_audio_set_mute( libvlc_media_player_t *mp, int mute )
329
{
330 331 332 333 334 335
    audio_output_t *aout = GetAOut( mp );
    if( aout != NULL )
    {
        mute = aout_MuteSet( aout, mute );
        vlc_object_release( aout );
    }
336 337
}

338
int libvlc_audio_get_volume( libvlc_media_player_t *mp )
339
{
340 341 342 343 344 345 346 347 348 349
    int volume = -1;

    audio_output_t *aout = GetAOut( mp );
    if( aout != NULL )
    {
        float vol = aout_VolumeGet( aout );
        vlc_object_release( aout );
        volume = lroundf( vol * 100.f );
    }
    return volume;
350 351
}

352
int libvlc_audio_set_volume( libvlc_media_player_t *mp, int volume )
353
{
354
    float vol = volume / 100.f;
355
    if (!isgreaterequal(vol, 0.f))
356
    {
357
        libvlc_printerr( "Volume out of range" );
358
        return -1;
Clément Stenac's avatar
Clément Stenac committed
359
    }
360 361 362 363 364 365 366 367 368

    int ret = -1;
    audio_output_t *aout = GetAOut( mp );
    if( aout != NULL )
    {
        ret = aout_VolumeSet( aout, vol );
        vlc_object_release( aout );
    }
    return ret;
369 370
}

371 372 373
/*****************************************************************************
 * libvlc_audio_get_track_count : Get the number of available audio tracks
 *****************************************************************************/
374
int libvlc_audio_get_track_count( libvlc_media_player_t *p_mi )
375
{
376
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
377
    int i_track_count;
378 379 380 381

    if( !p_input_thread )
        return -1;

382
    i_track_count = var_CountChoices( p_input_thread, "audio-es" );
383

384
    vlc_object_release( p_input_thread );
385
    return i_track_count;
386 387
}

388 389 390 391
/*****************************************************************************
 * libvlc_audio_get_track_description : Get the description of available audio tracks
 *****************************************************************************/
libvlc_track_description_t *
392
        libvlc_audio_get_track_description( libvlc_media_player_t *p_mi )
393
{
394
    return libvlc_get_track_description( p_mi, "audio-es" );
395 396
}

397 398 399
/*****************************************************************************
 * libvlc_audio_get_track : Get the current audio track
 *****************************************************************************/
400
int libvlc_audio_get_track( libvlc_media_player_t *p_mi )
401
{
402
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
403 404 405
    if( !p_input_thread )
        return -1;

406
    int id = var_GetInteger( p_input_thread, "audio-es" );
407
    vlc_object_release( p_input_thread );
408
    return id;
409 410 411 412 413
}

/*****************************************************************************
 * libvlc_audio_set_track : Set the current audio track
 *****************************************************************************/
414
int libvlc_audio_set_track( libvlc_media_player_t *p_mi, int i_track )
415
{
416
    input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
417
    vlc_value_t val_list;
418
    int i_ret = -1;
419

420
    if( !p_input_thread )
421
        return -1;
422

423
    var_Change( p_input_thread, "audio-es", VLC_VAR_GETCHOICES, &val_list, NULL );
424
    for( int i = 0; i < val_list.p_list->i_count; i++ )
425
    {
426 427 428 429 430 431 432
        if( i_track == val_list.p_list->p_values[i].i_int )
        {
            if( var_SetInteger( p_input_thread, "audio-es", i_track ) < 0 )
                break;
            i_ret = 0;
            goto end;
        }
433
    }
434
    libvlc_printerr( "Track identifier not found" );
435
end:
436
    var_FreeList( &val_list, NULL );
437
    vlc_object_release( p_input_thread );
438
    return i_ret;
439 440 441 442 443
}

/*****************************************************************************
 * libvlc_audio_get_channel : Get the current audio channel
 *****************************************************************************/
444
int libvlc_audio_get_channel( libvlc_media_player_t *mp )
445
{
446
    audio_output_t *p_aout = GetAOut( mp );
447 448
    if( !p_aout )
        return 0;
449

450
    int val = var_GetInteger( p_aout, "stereo-mode" );
451 452
    vlc_object_release( p_aout );
    return val;
453 454 455 456 457
}

/*****************************************************************************
 * libvlc_audio_set_channel : Set the current audio channel
 *****************************************************************************/
458
int libvlc_audio_set_channel( libvlc_media_player_t *mp, int channel )
459
{
460
    audio_output_t *p_aout = GetAOut( mp );
461 462
    int ret = 0;

463
    if( !p_aout )
464
        return -1;
465

466
    if( var_SetInteger( p_aout, "stereo-mode", channel ) < 0 )
467 468
    {
        libvlc_printerr( "Audio channel out of range" );
469
        ret = -1;
470
    }
471
    vlc_object_release( p_aout );
472
    return ret;
473
}
474 475 476 477 478 479 480 481 482 483

/*****************************************************************************
 * libvlc_audio_get_delay : Get the current audio delay
 *****************************************************************************/
int64_t libvlc_audio_get_delay( libvlc_media_player_t *p_mi )
{
    input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
    int64_t val = 0;
    if( p_input_thread != NULL )
    {
484
      val = var_GetInteger( p_input_thread, "audio-delay" );
485 486 487 488 489 490 491 492 493 494 495 496 497 498
      vlc_object_release( p_input_thread );
    }
    return val;
}

/*****************************************************************************
 * libvlc_audio_set_delay : Set the current audio delay
 *****************************************************************************/
int libvlc_audio_set_delay( libvlc_media_player_t *p_mi, int64_t i_delay )
{
    input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
    int ret = 0;
    if( p_input_thread != NULL )
    {
499
      var_SetInteger( p_input_thread, "audio-delay", i_delay );
500 501 502 503 504 505 506 507
      vlc_object_release( p_input_thread );
    }
    else
    {
      ret = -1;
    }
    return ret;
}
Mark Lee's avatar
Mark Lee committed
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543

/*****************************************************************************
 * libvlc_audio_equalizer_get_preset_count : Get the number of equalizer presets
 *****************************************************************************/
unsigned libvlc_audio_equalizer_get_preset_count( void )
{
    return NB_PRESETS;
}

/*****************************************************************************
 * libvlc_audio_equalizer_get_preset_name : Get the name for a preset
 *****************************************************************************/
const char *libvlc_audio_equalizer_get_preset_name( unsigned u_index )
{
    if ( u_index >= NB_PRESETS )
        return NULL;

    return preset_list_text[ u_index ];
}

/*****************************************************************************
 * libvlc_audio_equalizer_get_band_count : Get the number of equalizer frequency bands
 *****************************************************************************/
unsigned libvlc_audio_equalizer_get_band_count( void )
{
    return EQZ_BANDS_MAX;
}

/*****************************************************************************
 * libvlc_audio_equalizer_get_band_frequency : Get the frequency for a band
 *****************************************************************************/
float libvlc_audio_equalizer_get_band_frequency( unsigned u_index )
{
    if ( u_index >= EQZ_BANDS_MAX )
        return -1.f;

544
    return f_iso_frequency_table_10b[ u_index ];
Mark Lee's avatar
Mark Lee committed
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
}

/*****************************************************************************
 * libvlc_audio_equalizer_new : Create a new audio equalizer with zeroed values
 *****************************************************************************/
libvlc_equalizer_t *libvlc_audio_equalizer_new( void )
{
    libvlc_equalizer_t *p_equalizer;
    p_equalizer = malloc( sizeof( *p_equalizer ) );
    if ( unlikely( p_equalizer == NULL ) )
        return NULL;

    p_equalizer->f_preamp = 0.f;
    for ( unsigned i = 0; i < EQZ_BANDS_MAX; i++ )
        p_equalizer->f_amp[ i ] = 0.f;

    return p_equalizer;
}

/*****************************************************************************
 * libvlc_audio_equalizer_new_from_preset : Create a new audio equalizer based on a preset
 *****************************************************************************/
libvlc_equalizer_t *libvlc_audio_equalizer_new_from_preset( unsigned u_index )
{
    libvlc_equalizer_t *p_equalizer;

    if ( u_index >= NB_PRESETS )
        return NULL;

    p_equalizer = malloc( sizeof( *p_equalizer ) );
    if ( unlikely( p_equalizer == NULL ) )
        return NULL;

    p_equalizer->f_preamp = eqz_preset_10b[ u_index ].f_preamp;

    for ( unsigned i = 0; i < EQZ_BANDS_MAX; i++ )
        p_equalizer->f_amp[ i ] = eqz_preset_10b[ u_index ].f_amp[ i ];

    return p_equalizer;
}

/*****************************************************************************
 * libvlc_audio_equalizer_release : Release a previously created equalizer
 *****************************************************************************/
void libvlc_audio_equalizer_release( libvlc_equalizer_t *p_equalizer )
{
    free( p_equalizer );
}

/*****************************************************************************
 * libvlc_audio_equalizer_set_preamp : Set the preamp value for an equalizer
 *****************************************************************************/
int libvlc_audio_equalizer_set_preamp( libvlc_equalizer_t *p_equalizer, float f_preamp )
{
599 600 601 602 603 604
    if( isnan(f_preamp) )
        return -1;
    if( f_preamp < -20.f )
        f_preamp = -20.f;
    else if( f_preamp > 20.f )
        f_preamp = 20.f;
Mark Lee's avatar
Mark Lee committed
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622

    p_equalizer->f_preamp = f_preamp;
    return 0;
}

/*****************************************************************************
 * libvlc_audio_equalizer_get_preamp : Get the preamp value for an equalizer
 *****************************************************************************/
float libvlc_audio_equalizer_get_preamp( libvlc_equalizer_t *p_equalizer )
{
    return p_equalizer->f_preamp;
}

/*****************************************************************************
 * libvlc_audio_equalizer_set_amp_at_index : Set the amplification value for an equalizer band
 *****************************************************************************/
int libvlc_audio_equalizer_set_amp_at_index( libvlc_equalizer_t *p_equalizer, float f_amp, unsigned u_band )
{
623
    if( u_band >= EQZ_BANDS_MAX || isnan(f_amp) )
Mark Lee's avatar
Mark Lee committed
624 625
        return -1;

626 627 628 629 630

    if( f_amp < -20.f )
        f_amp = -20.f;
    else if( f_amp > 20.f )
        f_amp = 20.f;
Mark Lee's avatar
Mark Lee committed
631 632 633 634 635 636 637 638 639 640 641

    p_equalizer->f_amp[ u_band ] = f_amp;
    return 0;
}

/*****************************************************************************
 * libvlc_audio_equalizer_get_amp_at_index : Get the amplification value for an equalizer band
 *****************************************************************************/
float libvlc_audio_equalizer_get_amp_at_index( libvlc_equalizer_t *p_equalizer, unsigned u_band )
{
    if ( u_band >= EQZ_BANDS_MAX )
642
        return nanf("");
Mark Lee's avatar
Mark Lee committed
643 644 645

    return p_equalizer->f_amp[ u_band ];
}