intf.c 10.1 KB
Newer Older
1 2 3
/*****************************************************************************
 * intf.c : audio output API towards the interface modules
 *****************************************************************************
4
 * Copyright (C) 2002-2007 the VideoLAN team
5
 * $Id$
6 7 8 9 10 11 12
 *
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
13
 *
14 15 16 17 18 19 20
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 23 24 25 26
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
27

28 29 30 31
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

32
#include <vlc_common.h>
33
#include <vlc_aout_intf.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
34

35
#include <stdio.h>
36 37 38
#include <stdlib.h>                            /* calloc(), malloc(), free() */
#include <string.h>

Clément Stenac's avatar
Clément Stenac committed
39
#include <vlc_aout.h>
40 41
#include "aout_internal.h"

42 43 44 45
#include <vlc_playlist.h>

static aout_instance_t *findAout (vlc_object_t *obj)
{
46 47 48 49 50 51 52
    input_thread_t *(*pf_find_input) (vlc_object_t *);

    pf_find_input = var_GetAddress (obj, "find-input-callback");
    if (unlikely(pf_find_input == NULL))
        return NULL;

    input_thread_t *p_input = pf_find_input (obj);
53 54 55 56 57 58 59
    if (p_input == NULL)
       return NULL;

    aout_instance_t *p_aout = input_GetAout (p_input);
    vlc_object_release (p_input);
    return p_aout;
}
60
#define findAout(o) findAout(VLC_OBJECT(o))
61

62 63 64
/** Start a volume change transaction. */
static void prepareVolume (vlc_object_t *obj, aout_instance_t **aoutp,
                           audio_volume_t *volp, bool *mutep)
65
{
66 67 68 69 70 71 72
    aout_instance_t *aout = findAout (obj);

    /* FIXME: we need interlocking even if aout does not exist! */
    *aoutp = aout;
    if (aout != NULL)
        aout_lock_volume (aout);
    if (volp != NULL)
73
        *volp = var_GetInteger (obj, "volume");
74
    if (mutep != NULL)
75
        *mutep = var_GetBool (obj, "mute");
76
}
77

78 79
/** Commit a volume change transaction. */
static int commitVolume (vlc_object_t *obj, aout_instance_t *aout,
80
                         audio_volume_t volume, bool mute)
81 82
{
    int ret = 0;
83

84
    var_SetInteger (obj, "volume", volume);
85
    var_SetBool (obj, "mute", mute);
86

87
    if (aout != NULL)
88
    {
89 90
        aout_lock (aout);
#warning FIXME: wrong test. Need to check that aout_output is ready.
91
        if (aout->p_mixer != NULL)
92
            ret = aout->output.pf_volume_set (aout, volume, mute);
93
        aout_unlock (aout);
94 95

        if (ret == 0)
96
            var_TriggerCallback (aout, "intf-change");
97 98
        aout_unlock_volume (aout);
        vlc_object_release (aout);
99
    }
100
    return ret;
101 102
}

103 104 105
#if 0
/** Cancel a volume change transaction. */
static void cancelVolume (vlc_object_t *obj, aout_instance_t *aout)
106
{
107 108
    (void) obj;
    if (aout != NULL)
109
    {
110 111
        aout_unlock_volume (aout);
        vlc_object_release (aout);
112
    }
113 114
}
#endif
115

116 117 118 119
#undef aout_VolumeGet
/**
 * Gets the volume of the output device (independent of mute).
 */
120
audio_volume_t aout_VolumeGet (vlc_object_t *obj)
121 122 123 124 125
{
#if 0
    aout_instance_t *aout;
    audio_volume_t volume;

126
    prepareVolume (obj, &aout, &volume, NULL);
127 128
    cancelVolume (obj, aout);
    return 0;
129
#else
130
    return var_GetInteger (obj, "volume");
131
#endif
132 133
}

134
#undef aout_VolumeSet
135 136 137 138 139
/**
 * Sets the volume of the output device.
 * The mute status is not changed.
 */
int aout_VolumeSet (vlc_object_t *obj, audio_volume_t volume)
140
{
141 142 143 144
    aout_instance_t *aout;
    bool mute;

    prepareVolume (obj, &aout, NULL, &mute);
145
    return commitVolume (obj, aout, volume, mute);
146 147
}

148
#undef aout_VolumeUp
149 150
/**
 * Raises the volume.
151
 * \param value how much to increase (> 0) or decrease (< 0) the volume
152 153
 * \param volp if non-NULL, will contain contain the resulting volume
 */
154
int aout_VolumeUp (vlc_object_t *obj, int value, audio_volume_t *volp)
155
{
156 157
    aout_instance_t *aout;
    int ret;
158
    audio_volume_t volume;
159 160
    bool mute;

161
    value *= var_InheritInteger (obj, "volume-step");
162

163
    prepareVolume (obj, &aout, &volume, &mute);
164 165
    value += volume;
    if (value < AOUT_VOLUME_MIN)
166
        volume = AOUT_VOLUME_MIN;
167 168
    else
    if (value > AOUT_VOLUME_MAX)
169
        volume = AOUT_VOLUME_MAX;
170 171
    else
        volume = value;
172
    ret = commitVolume (obj, aout, volume, mute);
173 174 175
    if (volp != NULL)
        *volp = volume;
    return ret;
176 177
}

178
#undef aout_VolumeDown
179 180 181 182
/**
 * Lowers the volume. See aout_VolumeUp().
 */
int aout_VolumeDown (vlc_object_t *obj, int steps, audio_volume_t *volp)
183
{
184
    return aout_VolumeUp (obj, -steps, volp);
185 186
}

187
#undef aout_ToggleMute
188 189 190 191
/**
 * Toggles the mute state.
 */
int aout_ToggleMute (vlc_object_t *obj, audio_volume_t *volp)
192
{
193 194 195 196 197 198 199
    aout_instance_t *aout;
    int ret;
    audio_volume_t volume;
    bool mute;

    prepareVolume (obj, &aout, &volume, &mute);
    mute = !mute;
200
    ret = commitVolume (obj, aout, volume, mute);
201 202 203
    if (volp != NULL)
        *volp = mute ? AOUT_VOLUME_MIN : volume;
    return ret;
204 205
}

206 207 208 209
/**
 * Gets the output mute status.
 */
bool aout_IsMuted (vlc_object_t *obj)
210
{
211 212 213 214 215 216 217 218
#if 0
    aout_instance_t *aout;
    bool mute;

    prepareVolume (obj, &aout, NULL, &mute);
    cancelVolume (obj, aout);
    return mute;
#else
219
    return var_GetBool (obj, "mute");
220
#endif
221 222
}

223 224 225 226
/**
 * Sets mute status.
 */
int aout_SetMute (vlc_object_t *obj, audio_volume_t *volp, bool mute)
227
{
228 229 230 231 232
    aout_instance_t *aout;
    int ret;
    audio_volume_t volume;

    prepareVolume (obj, &aout, &volume, NULL);
233
    ret = commitVolume (obj, aout, volume, mute);
234 235 236
    if (volp != NULL)
        *volp = mute ? AOUT_VOLUME_MIN : volume;
    return ret;
237 238
}

239

240 241 242 243
/*
 * The next functions are not supposed to be called by the interface, but
 * are placeholders for software-only scaling.
 */
244 245 246 247
static int aout_VolumeSoftSet (aout_instance_t *aout, audio_volume_t volume,
                               bool mute)
{
    float f = mute ? 0. : (volume / (float)AOUT_VOLUME_DEFAULT);
248
    aout->mixer_multiplier = f;
249 250
    return 0;
}
251 252

/* Meant to be called by the output plug-in's Open(). */
253
void aout_VolumeSoftInit (aout_instance_t *aout)
254
{
255 256
    audio_volume_t volume = var_InheritInteger (aout, "volume");
    bool mute = var_InheritBool (aout, "mute");
257

258 259
    aout->output.pf_volume_set = aout_VolumeSoftSet;
    aout_VolumeSoftSet (aout, volume, mute);
260 261 262
}


263 264 265 266
/*
 * The next functions are not supposed to be called by the interface, but
 * are placeholders for unsupported scaling.
 */
267 268 269 270 271 272
static int aout_VolumeNoneSet (aout_instance_t *aout, audio_volume_t volume,
                               bool mute)
{
    (void)aout; (void)volume; (void)mute;
    return -1;
}
273 274 275 276 277 278 279

/* Meant to be called by the output plug-in's Open(). */
void aout_VolumeNoneInit( aout_instance_t * p_aout )
{
    p_aout->output.pf_volume_set = aout_VolumeNoneSet;
}

280 281 282 283 284 285 286 287 288 289 290 291

/*
 * Pipelines management
 */

/*****************************************************************************
 * aout_Restart : re-open the output device and rebuild the input and output
 *                pipelines
 *****************************************************************************
 * This function is used whenever the parameters of the output plug-in are
 * changed (eg. selecting S/PDIF or PCM).
 *****************************************************************************/
292
static int aout_Restart( aout_instance_t * p_aout )
293
{
294
    aout_input_t *p_input;
295

296 297 298
    aout_lock( p_aout );
    p_input = p_aout->p_input;
    if( p_input == NULL )
299
    {
300
        aout_unlock( p_aout );
301 302 303 304
        msg_Err( p_aout, "no decoder thread" );
        return -1;
    }

305 306
    /* Reinitializes the output */
    aout_InputDelete( p_aout, p_input );
307 308
    aout_MixerDelete( p_aout );
    aout_OutputDelete( p_aout );
309

310 311
    /* FIXME: This function is notoriously dangerous/unsafe.
     * By the way, if OutputNew or MixerNew fails, we are totally screwed. */
312
    if ( aout_OutputNew( p_aout, &p_input->input ) == -1 )
313 314
    {
        /* Release all locks and report the error. */
315
        aout_unlock( p_aout );
316 317 318 319 320 321
        return -1;
    }

    if ( aout_MixerNew( p_aout ) == -1 )
    {
        aout_OutputDelete( p_aout );
322
        aout_unlock( p_aout );
323 324 325
        return -1;
    }

326 327 328 329 330 331 332 333
    if( aout_InputNew( p_aout, p_input, &p_input->request_vout ) )
    {
#warning FIXME: deal with errors
        aout_unlock( p_aout );
        return -1;
    }
    aout_unlock( p_aout );
    return 0;
334 335
}

336 337 338 339
/*****************************************************************************
 * aout_ChannelsRestart : change the audio device or channels and restart
 *****************************************************************************/
int aout_ChannelsRestart( vlc_object_t * p_this, const char * psz_variable,
340 341
                          vlc_value_t oldval, vlc_value_t newval,
                          void *p_data )
342 343
{
    aout_instance_t * p_aout = (aout_instance_t *)p_this;
344
    (void)oldval; (void)newval; (void)p_data;
345 346 347 348 349

    if ( !strcmp( psz_variable, "audio-device" ) )
    {
        /* This is supposed to be a significant change and supposes
         * rebuilding the channel choices. */
350
        var_Destroy( p_aout, "audio-channels" );
351 352 353 354
    }
    aout_Restart( p_aout );
    return 0;
}
355

356
#undef aout_EnableFilter
357 358 359 360 361 362
/** Enable or disable an audio filter
 * \param p_this a vlc object
 * \param psz_name name of the filter
 * \param b_add are we adding or removing the filter ?
 */
void aout_EnableFilter( vlc_object_t *p_this, const char *psz_name,
363
                        bool b_add )
364
{
365
    aout_instance_t *p_aout = findAout( p_this );
366

367
    if( aout_ChangeFilterString( p_this, p_aout, "audio-filter", psz_name, b_add ) )
368
    {
369 370
        if( p_aout )
            AoutInputsMarkToRestart( p_aout );
371 372
    }

373
    if( p_aout )
374 375
        vlc_object_release( p_aout );
}