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 34
#include <vlc/libvlc_media.h>
#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 42
#include "libvlc_internal.h"
#include "media_player_internal.h"
43

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

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

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

85 86 87 88
        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) )
        {
89 90
            free( item->psz_name );
            free( item->psz_description );
91 92 93 94 95 96
            free( item );
            goto error;
        }
        item->p_next = list;
        list = item;
    }
97 98
    module_list_free( module_list );

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

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

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


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

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

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

136 137 138 139 140
    /* 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);

141
    return 0;
142 143
}

144 145 146 147 148 149 150
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;

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

    int n = aout_DevicesList( aout, &values, &texts );
155
    vlc_object_release( aout );
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
    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:
178
    *pp = NULL;
179 180 181
    return list;
}

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

191 192 193 194 195
    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++ )
196
    {
197 198 199
        libvlc_audio_output_device_t *item = malloc( sizeof(*item) );
        if( unlikely(item == NULL) )
            break;
200

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

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

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

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

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

234 235 236 237 238 239 240
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;
}
241

242 243 244 245 246
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;
247 248 249 250 251 252
    return NULL;
}

/*****************************
 * Set device for using
 *****************************/
253
void libvlc_audio_output_device_set( libvlc_media_player_t *mp,
254
                                     const char *module, const char *devid )
255
{
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
    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 );
271
        return;
272 273 274
    }

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

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

282 283 284 285 286 287 288 289 290 291 292 293 294
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;
}

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

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

307
void libvlc_audio_toggle_mute( libvlc_media_player_t *mp )
Clément Stenac's avatar
Clément Stenac committed
308
{
309 310 311
    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
312 313
}

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

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

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

337
int libvlc_audio_get_volume( libvlc_media_player_t *mp )
338
{
339 340 341 342 343 344 345 346 347 348
    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;
349 350
}

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

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

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

    if( !p_input_thread )
        return -1;

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

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

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

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

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

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

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

422
    var_Change( p_input_thread, "audio-es", VLC_VAR_GETCHOICES, &val_list, NULL );
423
    for( int i = 0; i < val_list.p_list->i_count; i++ )
424
    {
425 426 427 428 429 430 431
        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;
        }
432
    }
433
    libvlc_printerr( "Track identifier not found" );
434
end:
435
    var_FreeList( &val_list, NULL );
436
    vlc_object_release( p_input_thread );
437
    return i_ret;
438 439 440 441 442
}

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

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

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

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

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

/*****************************************************************************
 * 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 )
    {
483
      val = var_GetInteger( p_input_thread, "audio-delay" );
484 485 486 487 488 489 490 491 492 493 494 495 496 497
      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 )
    {
498
      var_SetInteger( p_input_thread, "audio-delay", i_delay );
499 500 501 502 503 504 505 506
      vlc_object_release( p_input_thread );
    }
    else
    {
      ret = -1;
    }
    return ret;
}
Mark Lee's avatar
Mark Lee committed
507 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

/*****************************************************************************
 * 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;

543
    return f_iso_frequency_table_10b[ u_index ];
Mark Lee's avatar
Mark Lee committed
544 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
}

/*****************************************************************************
 * 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 )
{
598 599 600 601 602 603
    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
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621

    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 )
{
622
    if( u_band >= EQZ_BANDS_MAX || isnan(f_amp) )
Mark Lee's avatar
Mark Lee committed
623 624
        return -1;

625 626 627 628 629

    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
630 631 632 633 634 635 636 637 638 639 640

    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 )
641
        return nanf("");
Mark Lee's avatar
Mark Lee committed
642 643 644

    return p_equalizer->f_amp[ u_band ];
}