X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Faudio_output%2Faudio_output.c;h=3f0e4b02faa0bdde7ad7adb71c877a3d9f346110;hb=123b3214ec0802b2c8d1ce6c693dd3b79e1ada31;hp=a19882e87b2fd149641a0da940ee4e501ac9b89d;hpb=5e21c13b22aefdec0ca33a469babf6b344262c6b;p=vlc diff --git a/src/audio_output/audio_output.c b/src/audio_output/audio_output.c index a19882e87b..3f0e4b02fa 100644 --- a/src/audio_output/audio_output.c +++ b/src/audio_output/audio_output.c @@ -1,11 +1,10 @@ /***************************************************************************** - * audio_output.c : audio output thread + * audio_output.c : audio output instance ***************************************************************************** - * Copyright (C) 1999-2001 VideoLAN - * $Id: audio_output.c,v 1.73 2002/01/15 11:51:11 asmax Exp $ + * Copyright (C) 2002 VideoLAN + * $Id: audio_output.c,v 1.90 2002/08/07 21:36:56 massiot Exp $ * - * Authors: Michel Kaempf - * Cyril Deguet + * Authors: Christophe Massiot * * 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 @@ -25,356 +24,175 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include /* "intf_msg.h" */ #include /* calloc(), malloc(), free() */ #include -#include +#include -#ifdef HAVE_UNISTD_H -# include /* getpid() */ -#endif - -#ifdef WIN32 /* getpid() for win32 is located in process.h */ -# include +#ifdef HAVE_ALLOCA_H +# include #endif #include "audio_output.h" -#include "aout_common.h" - -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -static int aout_SpawnThread( aout_thread_t * p_aout ); +#include "aout_internal.h" /***************************************************************************** - * aout_InitBank: initialize the audio output bank. + * aout_NewInstance: initialize aout structure *****************************************************************************/ -void aout_InitBank ( void ) +aout_instance_t * __aout_NewInstance( vlc_object_t * p_parent ) { - p_aout_bank->i_count = 0; + aout_instance_t * p_aout; + + /* Allocate descriptor. */ + p_aout = vlc_object_create( p_parent, VLC_OBJECT_AOUT ); + if( p_aout == NULL ) + { + return NULL; + } + + /* Initialize members. */ + vlc_mutex_init( p_parent, &p_aout->input_lock ); + vlc_cond_init( p_parent, &p_aout->input_signal ); + p_aout->i_inputs_active = 0; + p_aout->b_change_requested = 0; + p_aout->i_nb_inputs = 0; - vlc_mutex_init( &p_aout_bank->lock ); + vlc_mutex_init( p_parent, &p_aout->mixer_lock ); + vlc_cond_init( p_parent, &p_aout->mixer_signal ); + p_aout->b_mixer_active = 0; + + vlc_object_attach( p_aout, p_parent->p_vlc ); + + return p_aout; } /***************************************************************************** - * aout_EndBank: empty the audio output bank. - ***************************************************************************** - * This function ends all unused audio outputs and empties the bank in - * case of success. + * aout_DeleteInstance: destroy aout structure *****************************************************************************/ -void aout_EndBank ( void ) +void aout_DeleteInstance( aout_instance_t * p_aout ) { - /* 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 ); + vlc_mutex_destroy( &p_aout->input_lock ); + vlc_cond_destroy( &p_aout->input_signal ); + vlc_mutex_destroy( &p_aout->mixer_lock ); + vlc_cond_destroy( &p_aout->mixer_signal ); + + /* Free structure. */ + vlc_object_detach_all( p_aout ); + vlc_object_destroy( p_aout ); } /***************************************************************************** - * aout_CreateThread: initialize audio thread + * aout_BufferNew : ask for a new empty buffer *****************************************************************************/ -aout_thread_t *aout_CreateThread( int *pi_status, int i_channels, long l_rate ) +aout_buffer_t * aout_BufferNew( aout_instance_t * p_aout, + aout_input_t * p_input, + size_t i_nb_samples ) { - aout_thread_t * p_aout; /* thread descriptor */ -#if 0 - int i_status; /* thread status */ -#endif + aout_buffer_t * p_buffer; - /* Allocate descriptor */ - p_aout = (aout_thread_t *) malloc( sizeof(aout_thread_t) ); - if( p_aout == NULL ) - { - return( NULL ); - } - - /* Choose the best module */ - p_aout->p_module = module_Need( MODULE_CAPABILITY_AOUT, - main_GetPszVariable( AOUT_METHOD_VAR, NULL ), - NULL ); - - if( p_aout->p_module == NULL ) - { - intf_ErrMsg( "aout error: no suitable aout module" ); - free( p_aout ); - return( NULL ); - } - -#define aout_functions p_aout->p_module->p_functions->aout.functions.aout - 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; -#undef aout_functions - - /* - * Initialize audio device - */ - if ( p_aout->pf_open( p_aout ) ) - { - module_Unneed( p_aout->p_module ); - free( p_aout ); - return( NULL ); - } + /* This necessarily allocates in the heap. */ + aout_BufferAlloc( &p_input->input_alloc, (u64)(1000000 * i_nb_samples) + / p_input->input.i_rate, + NULL, p_buffer ); + p_buffer->i_nb_samples = i_nb_samples; - p_aout->l_rate = l_rate; - p_aout->i_channels = i_channels; - - /* special setting for ac3 pass-through mode */ - /* FIXME is it necessary ? (cf ac3_adec.c) */ - if( main_GetIntVariable( AOUT_SPDIF_VAR, 0 ) && p_main->b_ac3 ) + if ( p_buffer == NULL ) { - intf_WarnMsg( 4, "aout info: setting ac3 spdif" ); - p_aout->i_format = AOUT_FMT_AC3; - p_aout->l_rate = 48000; + msg_Err( p_aout, "NULL buffer !" ); } - - 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 ); - } - - /* FIXME: only works for i_channels == 1 or 2 ?? */ - p_aout->b_stereo = ( p_aout->i_channels == 2 ) ? 1 : 0; - - if ( p_aout->pf_setformat( p_aout ) ) - { - p_aout->pf_close( p_aout ); - module_Unneed( p_aout->p_module ); - free( p_aout ); - return( NULL ); - } - - /* Initialize the volume level */ - p_aout->i_volume = main_GetIntVariable( AOUT_VOLUME_VAR, VOLUME_DEFAULT ); - p_aout->i_savedvolume = 0; - - /* 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 */ - if( aout_SpawnThread( p_aout ) ) + else { - p_aout->pf_close( p_aout ); - module_Unneed( p_aout->p_module ); - free( p_aout ); - return( NULL ); + p_buffer->start_date = p_buffer->end_date = 0; } - return( p_aout ); + return p_buffer; } - /***************************************************************************** - * Declare the different aout thread functions + * aout_BufferDelete : destroy an undecoded buffer *****************************************************************************/ -DECLARE_AOUT_THREAD( S16, s16, ( p_aout->s32_buffer[l_buffer] / - AOUT_MAX_FIFOS ) ) - -DECLARE_AOUT_THREAD( U16, u16, (( p_aout->s32_buffer[l_buffer] / - AOUT_MAX_FIFOS) + 128) ) - -DECLARE_AOUT_THREAD( U8, u8, (( p_aout->s32_buffer[l_buffer] / - AOUT_MAX_FIFOS / 256) + 128 ) ) - -DECLARE_AOUT_THREAD( S8, s8, ( p_aout->s32_buffer[l_buffer] / - AOUT_MAX_FIFOS / 256) ) - +void aout_BufferDelete( aout_instance_t * p_aout, aout_input_t * p_input, + aout_buffer_t * p_buffer ) +{ + aout_BufferFree( p_buffer ); +} /***************************************************************************** - * aout_SpawnThread + * aout_BufferPlay : filter & mix the decoded buffer *****************************************************************************/ -static int aout_SpawnThread( aout_thread_t * p_aout ) +void aout_BufferPlay( aout_instance_t * p_aout, aout_input_t * p_input, + aout_buffer_t * p_buffer ) { - int i_fifo; - long l_bytes; - void (* pf_aout_thread)( aout_thread_t * ) = NULL; + vlc_bool_t b_run_mixer = 0; - /* We want the audio output thread to live */ - p_aout->b_die = 0; - p_aout->b_active = 1; - - /* Initialize the fifos lock */ - vlc_mutex_init( &p_aout->fifos_lock ); - /* Initialize audio fifos : set all fifos as empty and initialize locks */ - for ( i_fifo = 0; i_fifo < AOUT_MAX_FIFOS; i_fifo++ ) + if ( p_buffer->start_date == 0 ) { - p_aout->fifo[i_fifo].i_type = AOUT_EMPTY_FIFO; - vlc_mutex_init( &p_aout->fifo[i_fifo].data_lock ); - vlc_cond_init( &p_aout->fifo[i_fifo].data_wait ); + msg_Warn( p_aout, "non-dated buffer received" ); + aout_BufferFree( p_buffer ); } - - /* 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) */ - 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 ); - - /* Make pf_aout_thread point to the right thread function, and compute the - * byte size of the audio output buffer */ - switch ( p_aout->i_channels ) + else { - /* 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; - pf_aout_thread = aout_U8Thread; - break; - - case AOUT_FMT_S8: - intf_WarnMsg( 2, "aout info: signed 8 bits mono thread" ); - l_bytes = 1 * sizeof(s8) * p_aout->l_units; - pf_aout_thread = aout_S8Thread; - break; - - 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; - pf_aout_thread = aout_U16Thread; - break; - - 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; - pf_aout_thread = aout_S16Thread; - break; - - default: - intf_ErrMsg( "aout error: unknown audio output format (%i)", - p_aout->i_format ); - return( -1 ); - } - break; - - /* 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; - pf_aout_thread = aout_U8Thread; - break; - - case AOUT_FMT_S8: - intf_WarnMsg( 2, "aout info: signed 8 bits stereo thread" ); - l_bytes = 2 * sizeof(s8) * p_aout->l_units; - pf_aout_thread = aout_S8Thread; - break; - - 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; - pf_aout_thread = aout_U16Thread; - break; - - 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; - pf_aout_thread = aout_S16Thread; - break; - - case AOUT_FMT_AC3: - intf_WarnMsg( 2, "aout info: ac3 pass-through thread" ); - l_bytes = SPDIF_FRAME_SIZE; - pf_aout_thread = aout_SpdifThread; - break; - - default: - intf_ErrMsg( "aout error: unknown audio output format %i", - p_aout->i_format ); - return( -1 ); - } - break; - - default: - intf_ErrMsg( "aout error: unknown number of audio channels (%i)", - p_aout->i_channels ); - return( -1 ); + p_buffer->end_date = p_buffer->start_date + + (mtime_t)(p_buffer->i_nb_samples * 1000000) + / p_input->input.i_rate; } - /* Allocate the memory needed by the audio output buffers, and set to zero - * the s32 buffer's memory */ - p_aout->buffer = malloc( l_bytes ); - if ( p_aout->buffer == NULL ) - { - intf_ErrMsg( "aout error: cannot create output buffer" ); - return( -1 ); - } + aout_InputPlay( p_aout, p_input, p_buffer ); - p_aout->s32_buffer = (s32 *)calloc( p_aout->l_units, - sizeof(s32) << ( p_aout->b_stereo ) ); - if ( p_aout->s32_buffer == NULL ) + /* Run the mixer if it is able to run. */ + vlc_mutex_lock( &p_aout->mixer_lock ); + if ( !p_aout->b_mixer_active ) { - intf_ErrMsg( "aout error: cannot create the s32 output buffer" ); - free( p_aout->buffer ); - return( -1 ); + p_aout->b_mixer_active = 1; + b_run_mixer = 1; } + vlc_mutex_unlock( &p_aout->mixer_lock ); - /* Rough estimate of the playing date */ - p_aout->date = mdate() + p_main->i_desync; - - /* Launch the thread */ - if ( vlc_thread_create( &p_aout->thread_id, "audio output", - (vlc_thread_func_t)pf_aout_thread, p_aout ) ) + if ( b_run_mixer ) { - intf_ErrMsg( "aout error: cannot spawn audio output thread" ); - free( p_aout->buffer ); - free( p_aout->s32_buffer ); - return( -1 ); + aout_MixerRun( p_aout ); + vlc_mutex_lock( &p_aout->mixer_lock ); + p_aout->b_mixer_active = 0; + vlc_cond_broadcast( &p_aout->mixer_signal ); + vlc_mutex_unlock( &p_aout->mixer_lock ); } - - intf_WarnMsg( 2, "aout info: audio output thread %i spawned", getpid() ); - return( 0 ); } /***************************************************************************** - * aout_DestroyThread + * aout_FormatToBytes : return the number bytes/sample for format + * (didn't know where else to put it) *****************************************************************************/ -void aout_DestroyThread( aout_thread_t * p_aout, int *pi_status ) +int aout_FormatToBytes( audio_sample_format_t * p_format ) { - int i_fifo; - - /* FIXME: pi_status is not handled correctly: check vout how to do!?? */ + int i_result; + + switch ( p_format->i_format ) + { + case AOUT_FMT_U8: + case AOUT_FMT_S8: + i_result = 1; + break; - /* Ask thread to kill itself and wait until it's done */ - p_aout->b_die = 1; - vlc_thread_join( p_aout->thread_id ); /* only if pi_status is NULL */ + case AOUT_FMT_U16_LE: + case AOUT_FMT_U16_BE: + case AOUT_FMT_S16_LE: + case AOUT_FMT_S16_BE: + i_result = 2; + break; - /* Free the allocated memory */ - free( p_aout->buffer ); - free( p_aout->s32_buffer ); + case AOUT_FMT_FLOAT32: + case AOUT_FMT_FIXED32: + i_result = 4; + break; - /* 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 ); - } - vlc_mutex_destroy( &p_aout->fifos_lock ); - - /* Free the plugin */ - p_aout->pf_close( p_aout ); + case AOUT_FMT_A52: + i_result = 1; /* This is a bit special... sample == byte */ + break; - /* Release the aout module */ - module_Unneed( p_aout->p_module ); + default: + i_result = 0; /* will segfault much sooner... */ + } - /* Free structure */ - free( p_aout ); + return i_result * p_format->i_channels; }