audio_output.c 12.9 KB
Newer Older
1
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
2
 * audio_output.c : audio output thread
3
 *****************************************************************************
4
 * Copyright (C) 1999-2001 VideoLAN
Cyril Deguet's avatar
 
Cyril Deguet committed
5
 * $Id: audio_output.c,v 1.72 2002/01/14 19:54:36 asmax Exp $
6
 *
Renaud Dartus's avatar
 
Renaud Dartus committed
7
 * Authors: Michel Kaempf <maxx@via.ecp.fr>
8
 *          Cyril Deguet <asmax@via.ecp.fr>
9 10 11 12 13
 *
 * 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.
14
 * 
15 16
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
19
 *
20 21 22
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
24

25
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
26
 * Preamble
27
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
28 29 30 31 32
#include <stdio.h>                                           /* "intf_msg.h" */
#include <stdlib.h>                            /* calloc(), malloc(), free() */
#include <string.h>

#include <videolan/vlc.h>
33

Sam Hocevar's avatar
 
Sam Hocevar committed
34
#ifdef HAVE_UNISTD_H
Sam Hocevar's avatar
 
Sam Hocevar committed
35
#   include <unistd.h>                                           /* getpid() */
Sam Hocevar's avatar
 
Sam Hocevar committed
36 37
#endif

Sam Hocevar's avatar
 
Sam Hocevar committed
38
#ifdef WIN32                   /* getpid() for win32 is located in process.h */
Sam Hocevar's avatar
 
Sam Hocevar committed
39
#   include <process.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
40
#endif
Michel Kaempf's avatar
Michel Kaempf committed
41 42

#include "audio_output.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
43 44
#include "aout_common.h"

45
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
46
 * Local prototypes
47
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
48 49
static int aout_SpawnThread( aout_thread_t * p_aout );

Sam Hocevar's avatar
 
Sam Hocevar committed
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
/*****************************************************************************
 * aout_InitBank: initialize the audio output bank.
 *****************************************************************************/
void aout_InitBank ( void )
{
    p_aout_bank->i_count = 0;

    vlc_mutex_init( &p_aout_bank->lock );
}

/*****************************************************************************
 * aout_EndBank: empty the audio output bank.
 *****************************************************************************
 * This function ends all unused audio outputs and empties the bank in
 * case of success.
 *****************************************************************************/
void aout_EndBank ( void )
{
    /* Ask all remaining audio outputs to die */
    while( p_aout_bank->i_count )
    {
        aout_DestroyThread(
                p_aout_bank->pp_aout[ --p_aout_bank->i_count ], NULL );
    }

    vlc_mutex_destroy( &p_aout_bank->lock );
}

78
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
79
 * aout_CreateThread: initialize audio thread
80
 *****************************************************************************/
81
aout_thread_t *aout_CreateThread( int *pi_status, int i_channels, long l_rate )
Michel Kaempf's avatar
Michel Kaempf committed
82
{
83
    aout_thread_t * p_aout;                             /* thread descriptor */
84
#if 0
85
    int             i_status;                               /* thread status */
86
#endif
87

Vincent Seguin's avatar
Vincent Seguin committed
88 89 90
    /* Allocate descriptor */
    p_aout = (aout_thread_t *) malloc( sizeof(aout_thread_t) );
    if( p_aout == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
91
    {
Vincent Seguin's avatar
Vincent Seguin committed
92
        return( NULL );
Michel Kaempf's avatar
Michel Kaempf committed
93 94
    }

95
    /* Choose the best module */
Sam Hocevar's avatar
 
Sam Hocevar committed
96 97 98
    p_aout->p_module = module_Need( MODULE_CAPABILITY_AOUT,
                           main_GetPszVariable( AOUT_METHOD_VAR, NULL ), 
                           NULL );
99

100
    if( p_aout->p_module == NULL )
101
    {
102
        intf_ErrMsg( "aout error: no suitable aout module" );
103 104 105 106
        free( p_aout );
        return( NULL );
    }

107
#define aout_functions p_aout->p_module->p_functions->aout.functions.aout
Sam Hocevar's avatar
 
Sam Hocevar committed
108 109 110 111 112
    p_aout->pf_open       = aout_functions.pf_open;
    p_aout->pf_setformat  = aout_functions.pf_setformat;
    p_aout->pf_getbufinfo = aout_functions.pf_getbufinfo;
    p_aout->pf_play       = aout_functions.pf_play;
    p_aout->pf_close      = aout_functions.pf_close;
113
#undef aout_functions
114

115
    /*
116
     * Initialize audio device
Vincent Seguin's avatar
Vincent Seguin committed
117
     */
Sam Hocevar's avatar
 
Sam Hocevar committed
118
    if ( p_aout->pf_open( p_aout ) )
Vincent Seguin's avatar
Vincent Seguin committed
119
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
120
        module_Unneed( p_aout->p_module );
Vincent Seguin's avatar
Vincent Seguin committed
121 122 123
        free( p_aout );
        return( NULL );
    }
124

125 126
    p_aout->l_rate = l_rate;
    p_aout->i_channels = i_channels;
Sam Hocevar's avatar
 
Sam Hocevar committed
127

128
    /* special setting for ac3 pass-through mode */
129
    /* FIXME is it necessary ? (cf ac3_adec.c) */
130
    if( main_GetIntVariable( AOUT_SPDIF_VAR, 0 ) && p_main->b_ac3 )
131
    {
132 133
        intf_WarnMsg( 4, "aout info: setting ac3 spdif" );
        p_aout->i_format = AOUT_FMT_AC3;
134 135 136
        p_aout->l_rate = 48000;
    }

137 138 139 140 141 142 143 144 145
    if( p_aout->l_rate == 0 )
    {
        intf_ErrMsg( "aout error: null sample rate" );
        p_aout->pf_close( p_aout );
        module_Unneed( p_aout->p_module );
        free( p_aout );
        return( NULL );
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
146 147
    /* FIXME: only works for i_channels == 1 or 2 ?? */
    p_aout->b_stereo = ( p_aout->i_channels == 2 ) ? 1 : 0;
148

Sam Hocevar's avatar
 
Sam Hocevar committed
149
    if ( p_aout->pf_setformat( p_aout ) )
Michel Kaempf's avatar
Michel Kaempf committed
150
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
151
        p_aout->pf_close( p_aout );
Sam Hocevar's avatar
 
Sam Hocevar committed
152
        module_Unneed( p_aout->p_module );
153 154
        free( p_aout );
        return( NULL );
Michel Kaempf's avatar
Michel Kaempf committed
155
    }
156

Renaud Dartus's avatar
Renaud Dartus committed
157
    /* Initialize the volume level */
158
    p_aout->i_volume = main_GetIntVariable( AOUT_VOLUME_VAR, VOLUME_DEFAULT );
Sam Hocevar's avatar
 
Sam Hocevar committed
159
    p_aout->i_savedvolume = 0;
Renaud Dartus's avatar
 
Renaud Dartus committed
160
    
161 162 163
    /* FIXME: maybe it would be cleaner to change SpawnThread prototype
     * see vout to handle status correctly ?? however, it is not critical since
     * this thread is only called in main and all calls are blocking */
Vincent Seguin's avatar
Vincent Seguin committed
164 165
    if( aout_SpawnThread( p_aout ) )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
166
        p_aout->pf_close( p_aout );
Sam Hocevar's avatar
 
Sam Hocevar committed
167
        module_Unneed( p_aout->p_module );
168 169
        free( p_aout );
        return( NULL );
Vincent Seguin's avatar
Vincent Seguin committed
170 171 172
    }

    return( p_aout );
Michel Kaempf's avatar
Michel Kaempf committed
173 174
}

Cyril Deguet's avatar
 
Cyril Deguet committed
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195

/*****************************************************************************
 * Declare the different aout thread fucntions
 *****************************************************************************/
 DECLARE_AOUT_THREAD( S16, s16, ( p_aout->s32_buffer[l_buffer] / 
        AOUT_MAX_FIFOS ) * p_aout->i_volume / 256 )

 DECLARE_AOUT_THREAD( U8, u8, (( p_aout->s32_buffer[l_buffer] / 
        AOUT_MAX_FIFOS / 256) + 128 ) * p_aout->i_volume / 256 )

void aout_S8Thread( aout_thread_t * p_aout )
{
    intf_ErrMsg( "aout error: 8 bit signed thread unsupported" );
}

void aout_U16Thread( aout_thread_t * p_aout )
{
    intf_ErrMsg( "aout error: 16 bit unsigned thread unsupported" );
}


196
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
197
 * aout_SpawnThread
198
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
199
static int aout_SpawnThread( aout_thread_t * p_aout )
Michel Kaempf's avatar
Michel Kaempf committed
200
{
Sam Hocevar's avatar
 
Sam Hocevar committed
201 202 203
    int     i_fifo;
    long    l_bytes;
    void (* pf_aout_thread)( aout_thread_t * ) = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
204 205 206

    /* We want the audio output thread to live */
    p_aout->b_die = 0;
Sam Hocevar's avatar
Sam Hocevar committed
207
    p_aout->b_active = 1;
Michel Kaempf's avatar
Michel Kaempf committed
208 209

    /* Initialize the fifos lock */
210
    vlc_mutex_init( &p_aout->fifos_lock );
Michel Kaempf's avatar
Michel Kaempf committed
211 212 213 214
    /* Initialize audio fifos : set all fifos as empty and initialize locks */
    for ( i_fifo = 0; i_fifo < AOUT_MAX_FIFOS; i_fifo++ )
    {
        p_aout->fifo[i_fifo].i_type = AOUT_EMPTY_FIFO;
215 216
        vlc_mutex_init( &p_aout->fifo[i_fifo].data_lock );
        vlc_cond_init( &p_aout->fifo[i_fifo].data_wait );
Michel Kaempf's avatar
Michel Kaempf committed
217 218 219 220 221
    }

    /* Compute the size (in audio units) of the audio output buffer. Although
     * AOUT_BUFFER_DURATION is given in microseconds, the output rate is given
     * in Hz, that's why we need to divide by 10^6 microseconds (1 second) */
222 223
    p_aout->l_units = (long)( ((s64)p_aout->l_rate * AOUT_BUFFER_DURATION) / 1000000 );
    p_aout->l_msleep = (long)( ((s64)p_aout->l_units * 1000000) / (s64)p_aout->l_rate );
Michel Kaempf's avatar
Michel Kaempf committed
224

Sam Hocevar's avatar
 
Sam Hocevar committed
225
    /* Make pf_aout_thread point to the right thread function, and compute the
Michel Kaempf's avatar
Michel Kaempf committed
226
     * byte size of the audio output buffer */
227
    switch ( p_aout->i_channels )
Michel Kaempf's avatar
Michel Kaempf committed
228
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
229 230 231 232 233 234 235
    /* Audio output is mono */
    case 1:
        switch ( p_aout->i_format )
        {
        case AOUT_FMT_U8:
            intf_WarnMsg( 2, "aout info: unsigned 8 bits mono thread" );
            l_bytes = 1 * sizeof(u8) * p_aout->l_units;
Cyril Deguet's avatar
 
Cyril Deguet committed
236
            pf_aout_thread = aout_U8Thread;
Sam Hocevar's avatar
 
Sam Hocevar committed
237
            break;
Michel Kaempf's avatar
Michel Kaempf committed
238

Sam Hocevar's avatar
 
Sam Hocevar committed
239 240 241
        case AOUT_FMT_S8:
            intf_WarnMsg( 2, "aout info: signed 8 bits mono thread" );
            l_bytes = 1 * sizeof(s8) * p_aout->l_units;
Cyril Deguet's avatar
 
Cyril Deguet committed
242
            pf_aout_thread = aout_S8Thread;
Sam Hocevar's avatar
 
Sam Hocevar committed
243
            break;
Michel Kaempf's avatar
Michel Kaempf committed
244

Sam Hocevar's avatar
 
Sam Hocevar committed
245 246 247 248
        case AOUT_FMT_U16_LE:
        case AOUT_FMT_U16_BE:
            intf_WarnMsg( 2, "aout info: unsigned 16 bits mono thread" );
            l_bytes = 1 * sizeof(u16) * p_aout->l_units;
Cyril Deguet's avatar
 
Cyril Deguet committed
249
            pf_aout_thread = aout_U16Thread;
Sam Hocevar's avatar
 
Sam Hocevar committed
250
            break;
Michel Kaempf's avatar
Michel Kaempf committed
251

Sam Hocevar's avatar
 
Sam Hocevar committed
252 253 254 255
        case AOUT_FMT_S16_LE:
        case AOUT_FMT_S16_BE:
            intf_WarnMsg( 2, "aout info: signed 16 bits mono thread" );
            l_bytes = 1 * sizeof(s16) * p_aout->l_units;
Cyril Deguet's avatar
 
Cyril Deguet committed
256
            pf_aout_thread = aout_S16Thread;
Michel Kaempf's avatar
Michel Kaempf committed
257
            break;
Sam Hocevar's avatar
 
Sam Hocevar committed
258

259
        default:
Sam Hocevar's avatar
 
Sam Hocevar committed
260 261 262 263 264
            intf_ErrMsg( "aout error: unknown audio output format (%i)",
                         p_aout->i_format );
            return( -1 );
        }
        break;
Michel Kaempf's avatar
Michel Kaempf committed
265

Sam Hocevar's avatar
 
Sam Hocevar committed
266 267 268 269 270 271 272
    /* Audio output is stereo */
    case 2:
        switch ( p_aout->i_format )
        {
        case AOUT_FMT_U8:
            intf_WarnMsg( 2, "aout info: unsigned 8 bits stereo thread" );
            l_bytes = 2 * sizeof(u8) * p_aout->l_units;
Cyril Deguet's avatar
 
Cyril Deguet committed
273
            pf_aout_thread = aout_U8Thread;
Sam Hocevar's avatar
 
Sam Hocevar committed
274
            break;
Michel Kaempf's avatar
Michel Kaempf committed
275

Sam Hocevar's avatar
 
Sam Hocevar committed
276 277 278
        case AOUT_FMT_S8:
            intf_WarnMsg( 2, "aout info: signed 8 bits stereo thread" );
            l_bytes = 2 * sizeof(s8) * p_aout->l_units;
Cyril Deguet's avatar
 
Cyril Deguet committed
279
            pf_aout_thread = aout_S8Thread;
Sam Hocevar's avatar
 
Sam Hocevar committed
280
            break;
Michel Kaempf's avatar
Michel Kaempf committed
281

Sam Hocevar's avatar
 
Sam Hocevar committed
282 283 284 285
        case AOUT_FMT_U16_LE:
        case AOUT_FMT_U16_BE:
            intf_WarnMsg( 2, "aout info: unsigned 16 bits stereo thread" );
            l_bytes = 2 * sizeof(u16) * p_aout->l_units;
Cyril Deguet's avatar
 
Cyril Deguet committed
286
            pf_aout_thread = aout_U16Thread;
Sam Hocevar's avatar
 
Sam Hocevar committed
287
            break;
Michel Kaempf's avatar
Michel Kaempf committed
288

Sam Hocevar's avatar
 
Sam Hocevar committed
289 290 291 292
        case AOUT_FMT_S16_LE:
        case AOUT_FMT_S16_BE:
            intf_WarnMsg( 2, "aout info: signed 16 bits stereo thread" );
            l_bytes = 2 * sizeof(s16) * p_aout->l_units;
Cyril Deguet's avatar
 
Cyril Deguet committed
293
            pf_aout_thread = aout_S16Thread;
Michel Kaempf's avatar
Michel Kaempf committed
294
            break;
295 296 297 298 299 300 301

        case AOUT_FMT_AC3:
            intf_WarnMsg( 2, "aout info: ac3 pass-through thread" );
            l_bytes = SPDIF_FRAME_SIZE;
            pf_aout_thread = aout_SpdifThread;
            break;

Michel Kaempf's avatar
Michel Kaempf committed
302
        default:
Sam Hocevar's avatar
 
Sam Hocevar committed
303 304
            intf_ErrMsg( "aout error: unknown audio output format %i",
                         p_aout->i_format );
Michel Kaempf's avatar
Michel Kaempf committed
305
            return( -1 );
Sam Hocevar's avatar
 
Sam Hocevar committed
306 307 308 309 310 311 312
        }
        break;

    default:
        intf_ErrMsg( "aout error: unknown number of audio channels (%i)",
                     p_aout->i_channels );
        return( -1 );
Michel Kaempf's avatar
Michel Kaempf committed
313 314 315 316
    }

    /* Allocate the memory needed by the audio output buffers, and set to zero
     * the s32 buffer's memory */
Sam Hocevar's avatar
 
Sam Hocevar committed
317 318
    p_aout->buffer = malloc( l_bytes );
    if ( p_aout->buffer == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
319
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
320
        intf_ErrMsg( "aout error: cannot create output buffer" );
Michel Kaempf's avatar
Michel Kaempf committed
321 322
        return( -1 );
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
323 324 325 326

    p_aout->s32_buffer = (s32 *)calloc( p_aout->l_units,
                                        sizeof(s32) << ( p_aout->b_stereo ) );
    if ( p_aout->s32_buffer == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
327
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
328
        intf_ErrMsg( "aout error: cannot create the s32 output buffer" );
Michel Kaempf's avatar
Michel Kaempf committed
329 330 331 332
        free( p_aout->buffer );
        return( -1 );
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
333
    /* Rough estimate of the playing date */
334
    p_aout->date = mdate() + p_main->i_desync;
Michel Kaempf's avatar
Michel Kaempf committed
335 336

    /* Launch the thread */
Sam Hocevar's avatar
 
Sam Hocevar committed
337
    if ( vlc_thread_create( &p_aout->thread_id, "audio output",
Sam Hocevar's avatar
 
Sam Hocevar committed
338
                            (vlc_thread_func_t)pf_aout_thread, p_aout ) )
Michel Kaempf's avatar
Michel Kaempf committed
339
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
340
        intf_ErrMsg( "aout error: cannot spawn audio output thread" );
Michel Kaempf's avatar
Michel Kaempf committed
341 342 343 344 345
        free( p_aout->buffer );
        free( p_aout->s32_buffer );
        return( -1 );
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
346
    intf_WarnMsg( 2, "aout info: audio output thread %i spawned", getpid() );
Michel Kaempf's avatar
Michel Kaempf committed
347 348 349
    return( 0 );
}

350
/*****************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
351
 * aout_DestroyThread
352
 *****************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
353
void aout_DestroyThread( aout_thread_t * p_aout, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
354
{
Henri Fallon's avatar
 
Henri Fallon committed
355 356
    int i_fifo;
    
357
    /* FIXME: pi_status is not handled correctly: check vout how to do!?? */
Vincent Seguin's avatar
Vincent Seguin committed
358

Michel Kaempf's avatar
Michel Kaempf committed
359 360
    /* Ask thread to kill itself and wait until it's done */
    p_aout->b_die = 1;
361
    vlc_thread_join( p_aout->thread_id ); /* only if pi_status is NULL */
Michel Kaempf's avatar
Michel Kaempf committed
362 363 364 365 366

    /* Free the allocated memory */
    free( p_aout->buffer );
    free( p_aout->s32_buffer );

Henri Fallon's avatar
 
Henri Fallon committed
367 368 369 370 371 372
    /* Destroy the condition and mutex locks */
    for ( i_fifo = 0; i_fifo < AOUT_MAX_FIFOS; i_fifo++ )
    {
        vlc_mutex_destroy( &p_aout->fifo[i_fifo].data_lock );
        vlc_cond_destroy( &p_aout->fifo[i_fifo].data_wait );
    }
Henri Fallon's avatar
 
Henri Fallon committed
373
    vlc_mutex_destroy( &p_aout->fifos_lock );
Henri Fallon's avatar
 
Henri Fallon committed
374
    
Sam Hocevar's avatar
 
Sam Hocevar committed
375 376 377
    /* Free the plugin */
    p_aout->pf_close( p_aout );

378
    /* Release the aout module */
Sam Hocevar's avatar
 
Sam Hocevar committed
379
    module_Unneed( p_aout->p_module );
380

381
    /* Free structure */
Vincent Seguin's avatar
Vincent Seguin committed
382
    free( p_aout );
Michel Kaempf's avatar
Michel Kaempf committed
383 384
}