Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

portaudio.c

00001 /*****************************************************************************
00002  * portaudio.c : portaudio (v19) audio output plugin
00003  *****************************************************************************
00004  * Copyright (C) 2002 the VideoLAN team
00005  * $Id: portaudio.c 11664 2005-07-09 06:17:09Z courmisch $
00006  *
00007  * Authors: Frederic Ruget <[email protected]>
00008  *          Gildas Bazin <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  * 
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 /*****************************************************************************
00026  * Preamble
00027  *****************************************************************************/
00028 #include <string.h>
00029 #include <stdlib.h>
00030 
00031 #include <vlc/vlc.h>
00032 #include <vlc/aout.h>
00033 #include <portaudio.h>
00034 
00035 #include "aout_internal.h"
00036 
00037 #define FRAME_SIZE 1024              /* The size is in samples, not in bytes */
00038 
00039 #ifdef WIN32
00040 #   define PORTAUDIO_IS_SERIOUSLY_BROKEN 1
00041 #endif
00042 
00043 /*****************************************************************************
00044  * aout_sys_t: portaudio audio output method descriptor
00045  *****************************************************************************/
00046 typedef struct pa_thread_t
00047 {
00048     VLC_COMMON_MEMBERS
00049     aout_instance_t *p_aout;
00050 
00051     vlc_cond_t  wait;
00052     vlc_mutex_t lock_wait;
00053     vlc_bool_t  b_wait;
00054     vlc_cond_t  signal;
00055     vlc_mutex_t lock_signal;
00056     vlc_bool_t  b_signal;
00057 
00058 } pa_thread_t;
00059 
00060 struct aout_sys_t
00061 {
00062     aout_instance_t *p_aout;
00063     PaStream *p_stream;
00064 
00065     PaDeviceIndex i_devices;
00066     int i_sample_size;
00067     PaDeviceIndex i_device_id;
00068     const PaDeviceInfo *deviceInfo;
00069 
00070     vlc_bool_t b_chan_reorder;              /* do we need channel reordering */
00071     int pi_chan_table[AOUT_CHAN_MAX];
00072     uint32_t i_channel_mask;
00073     uint32_t i_bits_per_sample;
00074     uint32_t i_channels;
00075 };
00076 
00077 static const uint32_t pi_channels_in[] =
00078     { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
00079       AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
00080       AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
00081       AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
00082 static const uint32_t pi_channels_out[] =
00083     { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
00084       AOUT_CHAN_CENTER, AOUT_CHAN_LFE,
00085       AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
00086       AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT, 0 };
00087 
00088 #ifdef PORTAUDIO_IS_SERIOUSLY_BROKEN
00089 static vlc_bool_t b_init = 0;
00090 static pa_thread_t *pa_thread;
00091 static void PORTAUDIOThread( pa_thread_t * );
00092 #endif
00093 
00094 /*****************************************************************************
00095  * Local prototypes.
00096  *****************************************************************************/
00097 static int  Open        ( vlc_object_t * );
00098 static void Close       ( vlc_object_t * );
00099 static void Play        ( aout_instance_t * );
00100 
00101 static int PAOpenDevice( aout_instance_t * );
00102 static int PAOpenStream( aout_instance_t * );
00103 
00104 /*****************************************************************************
00105  * Module descriptor
00106  *****************************************************************************/
00107 #define DEVICE_TEXT N_("Output device")
00108 #define DEVICE_LONGTEXT N_("Portaudio identifier for the output device")
00109 
00110 vlc_module_begin();
00111     set_shortname( "PortAudio" );
00112     set_description( N_("PORTAUDIO audio output") );
00113     set_category( CAT_AUDIO );
00114     set_subcategory( SUBCAT_AUDIO_AOUT );
00115     add_integer( "portaudio-device", 0, NULL,
00116                  DEVICE_TEXT, DEVICE_LONGTEXT, VLC_FALSE );
00117     set_capability( "audio output", 0 );
00118     set_callbacks( Open, Close );
00119 vlc_module_end();
00120 
00121 /* This routine will be called by the PortAudio engine when audio is needed.
00122  * It may called at interrupt level on some machines so don't do anything
00123  * that could mess up the system like calling malloc() or free().
00124  */
00125 static int paCallback( const void *inputBuffer, void *outputBuffer,
00126                        unsigned long framesPerBuffer,
00127                        const PaStreamCallbackTimeInfo *paDate,
00128                        PaStreamCallbackFlags statusFlags, void *p_cookie )
00129 {
00130     struct aout_sys_t *p_sys = (struct aout_sys_t*) p_cookie;
00131     aout_instance_t   *p_aout = p_sys->p_aout;
00132     aout_buffer_t     *p_buffer;
00133     mtime_t out_date;
00134 
00135     out_date = mdate() + (mtime_t) ( 1000000 *
00136         ( paDate->outputBufferDacTime - paDate->currentTime ) );
00137     p_buffer = aout_OutputNextBuffer( p_aout, out_date, VLC_TRUE );
00138 
00139     if ( p_buffer != NULL )
00140     {
00141         if( p_sys->b_chan_reorder )
00142         {
00143             /* Do the channel reordering here */
00144             aout_ChannelReorder( p_buffer->p_buffer, p_buffer->i_nb_bytes,
00145                                  p_sys->i_channels, p_sys->pi_chan_table,
00146                                  p_sys->i_bits_per_sample );
00147         }
00148         p_aout->p_vlc->pf_memcpy( outputBuffer, p_buffer->p_buffer,
00149                                   framesPerBuffer * p_sys->i_sample_size );
00150         /* aout_BufferFree may be dangereous here, but then so is
00151          * aout_OutputNextBuffer (calls aout_BufferFree internally).
00152          * one solution would be to link the no longer useful buffers
00153          * in a second fifo (in aout_OutputNextBuffer too) and to
00154          * wait until we are in Play to do the actual free.
00155          */
00156         aout_BufferFree( p_buffer );
00157     }
00158     else
00159         /* Audio output buffer shortage -> stop the fill process and wait */
00160     {
00161         p_aout->p_vlc->pf_memset( outputBuffer, 0,
00162                                   framesPerBuffer * p_sys->i_sample_size );
00163     }
00164     return 0;
00165 }
00166 
00167 /*****************************************************************************
00168  * Open: open the audio device
00169  *****************************************************************************/
00170 static int Open( vlc_object_t * p_this )
00171 {
00172     aout_instance_t *p_aout = (aout_instance_t *)p_this;
00173     struct aout_sys_t * p_sys;
00174     vlc_value_t val;
00175     int i_err;
00176 
00177     msg_Dbg( p_aout, "Entering Open()");
00178 
00179     /* Allocate p_sys structure */
00180     p_sys = (aout_sys_t *)malloc( sizeof(aout_sys_t) );
00181     if( p_sys == NULL )
00182     {
00183         msg_Err( p_aout, "out of memory" );
00184         return VLC_ENOMEM;
00185     }
00186     p_sys->p_aout = p_aout;
00187     p_sys->p_stream = 0;
00188     p_aout->output.p_sys = p_sys;
00189     p_aout->output.pf_play = Play;
00190 
00191     /* Retrieve output device id from config */
00192     var_Create( p_aout, "portaudio-device", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT);
00193     var_Get( p_aout, "portaudio-device", &val );
00194     p_sys->i_device_id = val.i_int;
00195 
00196 #ifdef PORTAUDIO_IS_SERIOUSLY_BROKEN
00197     if( !b_init )
00198     {
00199         /* Test device */
00200         if( PAOpenDevice( p_aout ) != VLC_SUCCESS )
00201         {
00202             msg_Err( p_aout, "cannot open portaudio device" );
00203             free( p_sys );
00204             return VLC_EGENERIC;
00205         }
00206 
00207         /* Close device for now. We'll re-open it later on */
00208         if( ( i_err = Pa_Terminate() ) != paNoError )
00209         {
00210             msg_Err( p_aout, "Pa_Terminate returned %d", i_err );
00211         }
00212 
00213         b_init = VLC_TRUE;
00214 
00215         /* Now we need to setup our DirectSound play notification structure */
00216         pa_thread = vlc_object_create( p_aout, sizeof(pa_thread_t) );
00217         pa_thread->p_aout = p_aout;
00218         pa_thread->b_error = VLC_FALSE;
00219         vlc_mutex_init( p_aout, &pa_thread->lock_wait );
00220         vlc_cond_init( p_aout, &pa_thread->wait );
00221         pa_thread->b_wait = VLC_FALSE;
00222         vlc_mutex_init( p_aout, &pa_thread->lock_signal );
00223         vlc_cond_init( p_aout, &pa_thread->signal );
00224         pa_thread->b_signal = VLC_FALSE;
00225 
00226         /* Create PORTAUDIOThread */
00227         if( vlc_thread_create( pa_thread, "aout", PORTAUDIOThread,
00228                                VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
00229         {
00230             msg_Err( p_aout, "cannot create PORTAUDIO thread" );
00231             return VLC_EGENERIC;
00232         }
00233     }
00234     else
00235     {
00236         pa_thread->p_aout = p_aout;
00237         pa_thread->b_wait = VLC_FALSE;
00238         pa_thread->b_signal = VLC_FALSE;
00239         pa_thread->b_error = VLC_FALSE;
00240     }
00241 
00242     /* Signal start of stream */
00243     vlc_mutex_lock( &pa_thread->lock_signal );
00244     pa_thread->b_signal = VLC_TRUE;
00245     vlc_cond_signal( &pa_thread->signal );
00246     vlc_mutex_unlock( &pa_thread->lock_signal );
00247 
00248     /* Wait until thread is ready */
00249     vlc_mutex_lock( &pa_thread->lock_wait );
00250     if( !pa_thread->b_wait )
00251         vlc_cond_wait( &pa_thread->wait, &pa_thread->lock_wait );
00252     vlc_mutex_unlock( &pa_thread->lock_wait );
00253     pa_thread->b_wait = VLC_FALSE;
00254 
00255     if( pa_thread->b_error )
00256     {
00257         msg_Err( p_aout, "PORTAUDIO thread failed" );
00258         Close( p_this );
00259         return VLC_EGENERIC;
00260     }
00261 
00262     return VLC_SUCCESS;
00263 
00264 #else
00265 
00266     if( PAOpenDevice( p_aout ) != VLC_SUCCESS )
00267     {
00268         msg_Err( p_aout, "cannot open portaudio device" );
00269         free( p_sys );
00270         return VLC_EGENERIC;
00271     }
00272 
00273     if( PAOpenStream( p_aout ) != VLC_SUCCESS )
00274     {
00275         msg_Err( p_aout, "cannot open portaudio device" );
00276     }
00277 
00278     return VLC_SUCCESS;
00279 
00280 #endif
00281 }
00282 
00283 /*****************************************************************************
00284  * Close: close the audio device
00285  *****************************************************************************/
00286 static void Close ( vlc_object_t *p_this )
00287 {
00288     aout_instance_t *p_aout = (aout_instance_t *)p_this;
00289     aout_sys_t *p_sys = p_aout->output.p_sys;
00290     int i_err;
00291 
00292     msg_Dbg( p_aout, "closing portaudio");
00293 
00294 #ifdef PORTAUDIO_IS_SERIOUSLY_BROKEN
00295 
00296     /* Signal end of stream */
00297     vlc_mutex_lock( &pa_thread->lock_signal );
00298     pa_thread->b_signal = VLC_TRUE;
00299     vlc_cond_signal( &pa_thread->signal );
00300     vlc_mutex_unlock( &pa_thread->lock_signal );
00301 
00302     /* Wait until thread is ready */
00303     vlc_mutex_lock( &pa_thread->lock_wait );
00304     if( !pa_thread->b_wait )
00305         vlc_cond_wait( &pa_thread->wait, &pa_thread->lock_wait );
00306     vlc_mutex_unlock( &pa_thread->lock_wait );
00307     pa_thread->b_wait = VLC_FALSE;
00308 
00309 #else
00310 
00311     i_err = Pa_StopStream( p_sys->p_stream );
00312     if( i_err != paNoError )
00313     {
00314         msg_Err( p_aout, "Pa_StopStream: %d (%s)", i_err,
00315                  Pa_GetErrorText( i_err ) );
00316     }
00317     i_err = Pa_CloseStream( p_sys->p_stream );
00318     if( i_err != paNoError )
00319     {
00320         msg_Err( p_aout, "Pa_CloseStream: %d (%s)", i_err,
00321                  Pa_GetErrorText( i_err ) );
00322     }
00323 
00324     i_err = Pa_Terminate();
00325     if( i_err != paNoError )
00326     {
00327         msg_Err( p_aout, "Pa_Terminate: %d (%s)", i_err,
00328                  Pa_GetErrorText( i_err ) );
00329     }
00330 
00331 #endif
00332 
00333     msg_Dbg( p_aout, "portaudio closed");
00334     free( p_sys );
00335 }
00336 
00337 static int PAOpenDevice( aout_instance_t *p_aout )
00338 {
00339     aout_sys_t *p_sys = p_aout->output.p_sys;
00340     const PaDeviceInfo *p_pdi;
00341     PaError i_err;
00342     vlc_value_t val, text;
00343     int i;
00344 
00345     /* Initialize portaudio */
00346     i_err = Pa_Initialize();
00347     if( i_err != paNoError )
00348     {
00349         msg_Err( p_aout, "Pa_Initialize returned %d : %s",
00350                  i_err, Pa_GetErrorText( i_err ) );
00351 
00352         return VLC_EGENERIC;
00353     }
00354 
00355     p_sys->i_devices = Pa_GetDeviceCount();
00356     if( p_sys->i_devices < 0 )
00357     {
00358         i_err = p_sys->i_devices;
00359         msg_Err( p_aout, "Pa_GetDeviceCount returned %d : %s", i_err,
00360                  Pa_GetErrorText( i_err ) );
00361 
00362         goto error;
00363     }
00364 
00365     /* Display all devices info */
00366     msg_Dbg( p_aout, "number of devices = %d", p_sys->i_devices );
00367     for( i = 0; i < p_sys->i_devices; i++ )
00368     {
00369         p_pdi = Pa_GetDeviceInfo( i );
00370         msg_Dbg( p_aout, "------------------------------------- #%d", i );
00371         msg_Dbg( p_aout, "Name         = %s", p_pdi->name );
00372         msg_Dbg( p_aout, "Max Inputs   = %d, Max Outputs = %d",
00373                   p_pdi->maxInputChannels, p_pdi->maxOutputChannels );
00374     }
00375     msg_Dbg( p_aout, "-------------------------------------" );
00376 
00377     msg_Dbg( p_aout, "requested device is #%d", p_sys->i_device_id );
00378     if( p_sys->i_device_id >= p_sys->i_devices )
00379     {
00380         msg_Err( p_aout, "device %d does not exist", p_sys->i_device_id );
00381         goto error;
00382     }
00383     p_sys->deviceInfo = Pa_GetDeviceInfo( p_sys->i_device_id );
00384 
00385     if( p_sys->deviceInfo->maxOutputChannels < 1 )
00386     {
00387         msg_Err( p_aout, "no channel available" );
00388         goto error;
00389     }
00390 
00391     if( var_Type( p_aout, "audio-device" ) == 0 )
00392     {
00393         var_Create( p_aout, "audio-device", VLC_VAR_INTEGER|VLC_VAR_HASCHOICE);
00394         text.psz_string = _("Audio Device");
00395         var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
00396 
00397         if( p_sys->deviceInfo->maxOutputChannels >= 1 )
00398         {
00399             val.i_int = AOUT_VAR_MONO;
00400             text.psz_string = N_("Mono");
00401             var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE,
00402                         &val, &text );
00403             msg_Dbg( p_aout, "device supports 1 channel" );
00404         }
00405         if( p_sys->deviceInfo->maxOutputChannels >= 2 )
00406         {
00407             val.i_int = AOUT_VAR_STEREO;
00408             text.psz_string = N_("Stereo");
00409             var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE,
00410                         &val, &text );
00411             var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT,
00412                         &val, NULL );
00413             var_Set( p_aout, "audio-device", val );
00414             msg_Dbg( p_aout, "device supports 2 channels" );
00415         }
00416         if( p_sys->deviceInfo->maxOutputChannels >= 4 )
00417         {
00418             val.i_int = AOUT_VAR_2F2R;
00419             text.psz_string = N_("2 Front 2 Rear");
00420             var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE,
00421                         &val, &text );
00422             msg_Dbg( p_aout, "device supports 4 channels" );
00423         }
00424         if( p_sys->deviceInfo->maxOutputChannels >= 5 )
00425         {
00426             val.i_int = AOUT_VAR_3F2R;
00427             text.psz_string = N_("3 Front 2 Rear");
00428             var_Change( p_aout, "audio-device",
00429                         VLC_VAR_ADDCHOICE, &val, &text );
00430             msg_Dbg( p_aout, "device supports 5 channels" );
00431         }
00432         if( p_sys->deviceInfo->maxOutputChannels >= 6 )
00433         {
00434             val.i_int = AOUT_VAR_5_1;
00435             text.psz_string = N_("5.1");
00436             var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE,
00437                         &val, &text );
00438             msg_Dbg( p_aout, "device supports 5.1 channels" );
00439         }
00440 
00441         var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
00442 
00443         val.b_bool = VLC_TRUE;
00444         var_Set( p_aout, "intf-change", val );
00445     }
00446 
00447     /* Audio format is paFloat32 (always supported by portaudio v19) */
00448     p_aout->output.output.i_format = VLC_FOURCC('f','l','3','2');
00449 
00450     return VLC_SUCCESS;
00451 
00452  error:
00453     if( ( i_err = Pa_Terminate() ) != paNoError )
00454     {
00455         msg_Err( p_aout, "Pa_Terminate returned %d", i_err );
00456     }
00457     return VLC_EGENERIC;
00458 }
00459 
00460 static int PAOpenStream( aout_instance_t *p_aout )
00461 {
00462     aout_sys_t *p_sys = p_aout->output.p_sys;
00463     const PaHostErrorInfo* paLastHostErrorInfo = Pa_GetLastHostErrorInfo();
00464     PaStreamParameters paStreamParameters;
00465     vlc_value_t val;
00466     int i_channels, i_err;
00467     uint32_t i_channel_mask;
00468 
00469     if( var_Get( p_aout, "audio-device", &val ) < 0 )
00470     {
00471         return VLC_EGENERIC;
00472     }
00473 
00474     if( val.i_int == AOUT_VAR_5_1 )
00475     {
00476         p_aout->output.output.i_physical_channels
00477             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
00478               | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
00479               | AOUT_CHAN_LFE;
00480     }
00481     else if( val.i_int == AOUT_VAR_3F2R )
00482     {
00483         p_aout->output.output.i_physical_channels
00484             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
00485             | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
00486     }
00487     else if( val.i_int == AOUT_VAR_2F2R )
00488     {
00489         p_aout->output.output.i_physical_channels
00490             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
00491             | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
00492     }
00493     else if( val.i_int == AOUT_VAR_MONO )
00494     {
00495         p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
00496     }
00497     else
00498     {
00499         p_aout->output.output.i_physical_channels
00500             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
00501     }
00502 
00503     i_channels = aout_FormatNbChannels( &p_aout->output.output );
00504     msg_Dbg( p_aout, "nb_channels requested = %d", i_channels );
00505     i_channel_mask = p_aout->output.output.i_physical_channels;
00506 
00507     /* Calculate the frame size in bytes */
00508     p_sys->i_sample_size = 4 * i_channels;
00509     p_aout->output.i_nb_samples = FRAME_SIZE;
00510     aout_FormatPrepare( &p_aout->output.output );
00511     aout_VolumeSoftInit( p_aout );
00512 
00513     /* Check for channel reordering */
00514     p_aout->output.p_sys->i_channel_mask = i_channel_mask;
00515     p_aout->output.p_sys->i_bits_per_sample = 32; /* forced to paFloat32 */
00516     p_aout->output.p_sys->i_channels = i_channels;
00517 
00518     p_aout->output.p_sys->b_chan_reorder =
00519         aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
00520                                   i_channel_mask, i_channels,
00521                                   p_aout->output.p_sys->pi_chan_table );
00522 
00523     if( p_aout->output.p_sys->b_chan_reorder )
00524     {
00525         msg_Dbg( p_aout, "channel reordering needed" );
00526     }
00527 
00528     paStreamParameters.device = p_sys->i_device_id;
00529     paStreamParameters.channelCount = i_channels;
00530     paStreamParameters.sampleFormat = paFloat32;
00531     paStreamParameters.suggestedLatency =
00532         p_sys->deviceInfo->defaultLowOutputLatency;
00533     paStreamParameters.hostApiSpecificStreamInfo = NULL;
00534 
00535     i_err = Pa_OpenStream( &p_sys->p_stream, NULL /* no input */,
00536                 &paStreamParameters, (double)p_aout->output.output.i_rate,
00537                 FRAME_SIZE, paClipOff, paCallback, p_sys );
00538     if( i_err != paNoError )
00539     {
00540         msg_Err( p_aout, "Pa_OpenStream returns %d : %s", i_err,
00541                  Pa_GetErrorText( i_err ) );
00542         if( i_err == paUnanticipatedHostError )
00543         {
00544             msg_Err( p_aout, "type %d code %ld : %s",
00545                      paLastHostErrorInfo->hostApiType,
00546                      paLastHostErrorInfo->errorCode,
00547                      paLastHostErrorInfo->errorText );
00548         }
00549         p_sys->p_stream = 0;
00550         return VLC_EGENERIC;
00551     }
00552 
00553     i_err = Pa_StartStream( p_sys->p_stream );
00554     if( i_err != paNoError )
00555     {
00556         msg_Err( p_aout, "Pa_StartStream() failed" );
00557         Pa_CloseStream( p_sys->p_stream );
00558         return VLC_EGENERIC;
00559     }
00560 
00561     return VLC_SUCCESS;
00562 }
00563 
00564 /*****************************************************************************
00565  * Play: play sound
00566  *****************************************************************************/
00567 static void Play( aout_instance_t * p_aout )
00568 {
00569 }
00570 
00571 #ifdef PORTAUDIO_IS_SERIOUSLY_BROKEN
00572 /*****************************************************************************
00573  * PORTAUDIOThread: all interactions with libportaudio.a are handled
00574  * in this single thread.  Otherwise libportaudio.a is _not_ happy :-(
00575  *****************************************************************************/
00576 static void PORTAUDIOThread( pa_thread_t *pa_thread )
00577 {
00578     aout_instance_t *p_aout;
00579     aout_sys_t *p_sys;
00580     int i_err;
00581 
00582     while( !pa_thread->b_die )
00583     {
00584         /* Wait for start of stream */
00585         vlc_mutex_lock( &pa_thread->lock_signal );
00586         if( !pa_thread->b_signal )
00587             vlc_cond_wait( &pa_thread->signal, &pa_thread->lock_signal );
00588         vlc_mutex_unlock( &pa_thread->lock_signal );
00589         pa_thread->b_signal = VLC_FALSE;
00590 
00591         p_aout = pa_thread->p_aout;
00592         p_sys = p_aout->output.p_sys;
00593 
00594         if( PAOpenDevice( p_aout ) != VLC_SUCCESS )
00595         {
00596             msg_Err( p_aout, "cannot open portaudio device" );
00597             pa_thread->b_error = VLC_TRUE;
00598         }
00599 
00600         if( !pa_thread->b_error && PAOpenStream( p_aout ) != VLC_SUCCESS )
00601         {
00602             msg_Err( p_aout, "cannot open portaudio device" );
00603             pa_thread->b_error = VLC_TRUE;
00604 
00605             i_err = Pa_Terminate();
00606             if( i_err != paNoError )
00607             {
00608                 msg_Err( p_aout, "Pa_Terminate: %d (%s)", i_err,
00609                          Pa_GetErrorText( i_err ) );
00610             }
00611         }
00612 
00613         /* Tell the main thread that we are ready */
00614         vlc_mutex_lock( &pa_thread->lock_wait );
00615         pa_thread->b_wait = VLC_TRUE;
00616         vlc_cond_signal( &pa_thread->wait );
00617         vlc_mutex_unlock( &pa_thread->lock_wait );
00618 
00619         /* Wait for end of stream */
00620         vlc_mutex_lock( &pa_thread->lock_signal );
00621         if( !pa_thread->b_signal )
00622             vlc_cond_wait( &pa_thread->signal, &pa_thread->lock_signal );
00623         vlc_mutex_unlock( &pa_thread->lock_signal );
00624         pa_thread->b_signal = VLC_FALSE;
00625 
00626         if( pa_thread->b_error ) continue;
00627 
00628         i_err = Pa_StopStream( p_sys->p_stream );
00629         if( i_err != paNoError )
00630         {
00631             msg_Err( p_aout, "Pa_StopStream: %d (%s)", i_err,
00632                      Pa_GetErrorText( i_err ) );
00633         }
00634         i_err = Pa_CloseStream( p_sys->p_stream );
00635         if( i_err != paNoError )
00636         {
00637             msg_Err( p_aout, "Pa_CloseStream: %d (%s)", i_err,
00638                      Pa_GetErrorText( i_err ) );
00639         }
00640         i_err = Pa_Terminate();
00641         if( i_err != paNoError )
00642         {
00643             msg_Err( p_aout, "Pa_Terminate: %d (%s)", i_err,
00644                      Pa_GetErrorText( i_err ) );
00645         }
00646 
00647         /* Tell the main thread that we are ready */
00648         vlc_mutex_lock( &pa_thread->lock_wait );
00649         pa_thread->b_wait = VLC_TRUE;
00650         vlc_cond_signal( &pa_thread->wait );
00651         vlc_mutex_unlock( &pa_thread->lock_wait );
00652     }
00653 }
00654 #endif

Generated on Tue Dec 20 10:14:28 2005 for vlc-0.8.4a by  doxygen 1.4.2