portaudio.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:21k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * portaudio.c : portaudio (v19) audio output plugin
  3.  *****************************************************************************
  4.  * Copyright (C) 2002 VideoLAN
  5.  * $Id: portaudio.c 9287 2004-11-12 08:06:26Z gbazin $
  6.  *
  7.  * Authors: Frederic Ruget <frederic.ruget@free.fr>
  8.  *          Gildas Bazin <gbazin@videolan.org>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  * 
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  23.  *****************************************************************************/
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #include <string.h>
  28. #include <stdlib.h>
  29. #include <vlc/vlc.h>
  30. #include <vlc/aout.h>
  31. #include <portaudio.h>
  32. #include "aout_internal.h"
  33. #define FRAME_SIZE 1024              /* The size is in samples, not in bytes */
  34. #ifdef WIN32
  35. #   define PORTAUDIO_IS_SERIOUSLY_BROKEN 1
  36. #endif
  37. /*****************************************************************************
  38.  * aout_sys_t: portaudio audio output method descriptor
  39.  *****************************************************************************/
  40. typedef struct pa_thread_t
  41. {
  42.     VLC_COMMON_MEMBERS
  43.     aout_instance_t *p_aout;
  44.     vlc_cond_t  wait;
  45.     vlc_mutex_t lock_wait;
  46.     vlc_bool_t  b_wait;
  47.     vlc_cond_t  signal;
  48.     vlc_mutex_t lock_signal;
  49.     vlc_bool_t  b_signal;
  50. } pa_thread_t;
  51. struct aout_sys_t
  52. {
  53.     aout_instance_t *p_aout;
  54.     PaStream *p_stream;
  55.     PaDeviceIndex i_devices;
  56.     int i_sample_size;
  57.     PaDeviceIndex i_device_id;
  58.     const PaDeviceInfo *deviceInfo;
  59.     vlc_bool_t b_chan_reorder;              /* do we need channel reordering */
  60.     int pi_chan_table[AOUT_CHAN_MAX];
  61.     uint32_t i_channel_mask;
  62.     uint32_t i_bits_per_sample;
  63.     uint32_t i_channels;
  64. };
  65. static const uint32_t pi_channels_in[] =
  66.     { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
  67.       AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
  68.       AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
  69.       AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
  70. static const uint32_t pi_channels_out[] =
  71.     { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
  72.       AOUT_CHAN_CENTER, AOUT_CHAN_LFE,
  73.       AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
  74.       AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT, 0 };
  75. #ifdef PORTAUDIO_IS_SERIOUSLY_BROKEN
  76. static vlc_bool_t b_init = 0;
  77. static pa_thread_t *pa_thread;
  78. static void PORTAUDIOThread( pa_thread_t * );
  79. #endif
  80. /*****************************************************************************
  81.  * Local prototypes.
  82.  *****************************************************************************/
  83. static int  Open        ( vlc_object_t * );
  84. static void Close       ( vlc_object_t * );
  85. static void Play        ( aout_instance_t * );
  86. static int PAOpenDevice( aout_instance_t * );
  87. static int PAOpenStream( aout_instance_t * );
  88. /*****************************************************************************
  89.  * Module descriptor
  90.  *****************************************************************************/
  91. #define DEVICE_TEXT N_("Output device")
  92. #define DEVICE_LONGTEXT N_("Portaudio identifier for the output device")
  93. vlc_module_begin();
  94.     set_description( N_("PORTAUDIO audio output") );
  95.     add_integer( "portaudio-device", 0, NULL,
  96.                  DEVICE_TEXT, DEVICE_LONGTEXT, VLC_FALSE );
  97.     set_capability( "audio output", 0 );
  98.     set_callbacks( Open, Close );
  99. vlc_module_end();
  100. /* This routine will be called by the PortAudio engine when audio is needed.
  101.  * It may called at interrupt level on some machines so don't do anything
  102.  * that could mess up the system like calling malloc() or free().
  103.  */
  104. static int paCallback( const void *inputBuffer, void *outputBuffer,
  105.                        unsigned long framesPerBuffer,
  106.                        const PaStreamCallbackTimeInfo *paDate,
  107.                        PaStreamCallbackFlags statusFlags, void *p_cookie )
  108. {
  109.     struct aout_sys_t *p_sys = (struct aout_sys_t*) p_cookie;
  110.     aout_instance_t   *p_aout = p_sys->p_aout;
  111.     aout_buffer_t     *p_buffer;
  112.     mtime_t out_date;
  113.     out_date = mdate() + (mtime_t) ( 1000000 *
  114.         ( paDate->outputBufferDacTime - paDate->currentTime ) );
  115.     p_buffer = aout_OutputNextBuffer( p_aout, out_date, VLC_TRUE );
  116.     if ( p_buffer != NULL )
  117.     {
  118.         if( p_sys->b_chan_reorder )
  119.         {
  120.             /* Do the channel reordering here */
  121.             aout_ChannelReorder( p_buffer->p_buffer, p_buffer->i_nb_bytes,
  122.                                  p_sys->i_channels, p_sys->pi_chan_table,
  123.                                  p_sys->i_bits_per_sample );
  124.         }
  125.         p_aout->p_vlc->pf_memcpy( outputBuffer, p_buffer->p_buffer,
  126.                                   framesPerBuffer * p_sys->i_sample_size );
  127.         /* aout_BufferFree may be dangereous here, but then so is
  128.          * aout_OutputNextBuffer (calls aout_BufferFree internally).
  129.          * one solution would be to link the no longer useful buffers
  130.          * in a second fifo (in aout_OutputNextBuffer too) and to
  131.          * wait until we are in Play to do the actual free.
  132.          */
  133.         aout_BufferFree( p_buffer );
  134.     }
  135.     else
  136.         /* Audio output buffer shortage -> stop the fill process and wait */
  137.     {
  138.         p_aout->p_vlc->pf_memset( outputBuffer, 0,
  139.                                   framesPerBuffer * p_sys->i_sample_size );
  140.     }
  141.     return 0;
  142. }
  143. /*****************************************************************************
  144.  * Open: open the audio device
  145.  *****************************************************************************/
  146. static int Open( vlc_object_t * p_this )
  147. {
  148.     aout_instance_t *p_aout = (aout_instance_t *)p_this;
  149.     struct aout_sys_t * p_sys;
  150.     vlc_value_t val;
  151.     int i_err;
  152.     msg_Dbg( p_aout, "Entering Open()");
  153.     /* Allocate p_sys structure */
  154.     p_sys = (aout_sys_t *)malloc( sizeof(aout_sys_t) );
  155.     if( p_sys == NULL )
  156.     {
  157.         msg_Err( p_aout, "out of memory" );
  158.         return VLC_ENOMEM;
  159.     }
  160.     p_sys->p_aout = p_aout;
  161.     p_sys->p_stream = 0;
  162.     p_aout->output.p_sys = p_sys;
  163.     p_aout->output.pf_play = Play;
  164.     /* Retrieve output device id from config */
  165.     var_Create( p_aout, "portaudio-device", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT);
  166.     var_Get( p_aout, "portaudio-device", &val );
  167.     p_sys->i_device_id = val.i_int;
  168. #ifdef PORTAUDIO_IS_SERIOUSLY_BROKEN
  169.     if( !b_init )
  170.     {
  171.         /* Test device */
  172.         if( PAOpenDevice( p_aout ) != VLC_SUCCESS )
  173.         {
  174.             msg_Err( p_aout, "cannot open portaudio device" );
  175.             free( p_sys );
  176.             return VLC_EGENERIC;
  177.         }
  178.         /* Close device for now. We'll re-open it later on */
  179.         if( ( i_err = Pa_Terminate() ) != paNoError )
  180.         {
  181.             msg_Err( p_aout, "Pa_Terminate returned %d", i_err );
  182.         }
  183.         b_init = VLC_TRUE;
  184.         /* Now we need to setup our DirectSound play notification structure */
  185.         pa_thread = vlc_object_create( p_aout, sizeof(pa_thread_t) );
  186.         pa_thread->p_aout = p_aout;
  187.         pa_thread->b_error = VLC_FALSE;
  188.         vlc_mutex_init( p_aout, &pa_thread->lock_wait );
  189.         vlc_cond_init( p_aout, &pa_thread->wait );
  190.         pa_thread->b_wait = VLC_FALSE;
  191.         vlc_mutex_init( p_aout, &pa_thread->lock_signal );
  192.         vlc_cond_init( p_aout, &pa_thread->signal );
  193.         pa_thread->b_signal = VLC_FALSE;
  194.         /* Create PORTAUDIOThread */
  195.         if( vlc_thread_create( pa_thread, "aout", PORTAUDIOThread,
  196.                                VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
  197.         {
  198.             msg_Err( p_aout, "cannot create PORTAUDIO thread" );
  199.             return VLC_EGENERIC;
  200.         }
  201.     }
  202.     else
  203.     {
  204.         pa_thread->p_aout = p_aout;
  205.         pa_thread->b_wait = VLC_FALSE;
  206.         pa_thread->b_signal = VLC_FALSE;
  207.         pa_thread->b_error = VLC_FALSE;
  208.     }
  209.     /* Signal start of stream */
  210.     vlc_mutex_lock( &pa_thread->lock_signal );
  211.     pa_thread->b_signal = VLC_TRUE;
  212.     vlc_cond_signal( &pa_thread->signal );
  213.     vlc_mutex_unlock( &pa_thread->lock_signal );
  214.     /* Wait until thread is ready */
  215.     vlc_mutex_lock( &pa_thread->lock_wait );
  216.     if( !pa_thread->b_wait )
  217.         vlc_cond_wait( &pa_thread->wait, &pa_thread->lock_wait );
  218.     vlc_mutex_unlock( &pa_thread->lock_wait );
  219.     pa_thread->b_wait = VLC_FALSE;
  220.     if( pa_thread->b_error )
  221.     {
  222.         msg_Err( p_aout, "PORTAUDIO thread failed" );
  223.         Close( p_this );
  224.         return VLC_EGENERIC;
  225.     }
  226.     return VLC_SUCCESS;
  227. #else
  228.     if( PAOpenDevice( p_aout ) != VLC_SUCCESS )
  229.     {
  230.         msg_Err( p_aout, "cannot open portaudio device" );
  231.         free( p_sys );
  232.         return VLC_EGENERIC;
  233.     }
  234.     if( PAOpenStream( p_aout ) != VLC_SUCCESS )
  235.     {
  236.         msg_Err( p_aout, "cannot open portaudio device" );
  237.     }
  238.     return VLC_SUCCESS;
  239. #endif
  240. }
  241. /*****************************************************************************
  242.  * Close: close the audio device
  243.  *****************************************************************************/
  244. static void Close ( vlc_object_t *p_this )
  245. {
  246.     aout_instance_t *p_aout = (aout_instance_t *)p_this;
  247.     aout_sys_t *p_sys = p_aout->output.p_sys;
  248.     int i_err;
  249.     msg_Dbg( p_aout, "closing portaudio");
  250. #ifdef PORTAUDIO_IS_SERIOUSLY_BROKEN
  251.     /* Signal end of stream */
  252.     vlc_mutex_lock( &pa_thread->lock_signal );
  253.     pa_thread->b_signal = VLC_TRUE;
  254.     vlc_cond_signal( &pa_thread->signal );
  255.     vlc_mutex_unlock( &pa_thread->lock_signal );
  256.     /* Wait until thread is ready */
  257.     vlc_mutex_lock( &pa_thread->lock_wait );
  258.     if( !pa_thread->b_wait )
  259.         vlc_cond_wait( &pa_thread->wait, &pa_thread->lock_wait );
  260.     vlc_mutex_unlock( &pa_thread->lock_wait );
  261.     pa_thread->b_wait = VLC_FALSE;
  262. #else
  263.     i_err = Pa_StopStream( p_sys->p_stream );
  264.     if( i_err != paNoError )
  265.     {
  266.         msg_Err( p_aout, "Pa_StopStream: %d (%s)", i_err,
  267.                  Pa_GetErrorText( i_err ) );
  268.     }
  269.     i_err = Pa_CloseStream( p_sys->p_stream );
  270.     if( i_err != paNoError )
  271.     {
  272.         msg_Err( p_aout, "Pa_CloseStream: %d (%s)", i_err,
  273.                  Pa_GetErrorText( i_err ) );
  274.     }
  275.     i_err = Pa_Terminate();
  276.     if( i_err != paNoError )
  277.     {
  278.         msg_Err( p_aout, "Pa_Terminate: %d (%s)", i_err,
  279.                  Pa_GetErrorText( i_err ) );
  280.     }
  281. #endif
  282.     msg_Dbg( p_aout, "portaudio closed");
  283.     free( p_sys );
  284. }
  285. static int PAOpenDevice( aout_instance_t *p_aout )
  286. {
  287.     aout_sys_t *p_sys = p_aout->output.p_sys;
  288.     const PaDeviceInfo *p_pdi;
  289.     PaError i_err;
  290.     vlc_value_t val, text;
  291.     int i;
  292.     /* Initialize portaudio */
  293.     i_err = Pa_Initialize();
  294.     if( i_err != paNoError )
  295.     {
  296.         msg_Err( p_aout, "Pa_Initialize returned %d : %s",
  297.                  i_err, Pa_GetErrorText( i_err ) );
  298.         return VLC_EGENERIC;
  299.     }
  300.     p_sys->i_devices = Pa_GetDeviceCount();
  301.     if( p_sys->i_devices < 0 )
  302.     {
  303.         i_err = p_sys->i_devices;
  304.         msg_Err( p_aout, "Pa_GetDeviceCount returned %d : %s", i_err,
  305.                  Pa_GetErrorText( i_err ) );
  306.         goto error;
  307.     }
  308.     /* Display all devices info */
  309.     msg_Dbg( p_aout, "number of devices = %d", p_sys->i_devices );
  310.     for( i = 0; i < p_sys->i_devices; i++ )
  311.     {
  312.         p_pdi = Pa_GetDeviceInfo( i );
  313.         msg_Dbg( p_aout, "------------------------------------- #%d", i );
  314.         msg_Dbg( p_aout, "Name         = %s", p_pdi->name );
  315.         msg_Dbg( p_aout, "Max Inputs   = %d, Max Outputs = %d",
  316.                   p_pdi->maxInputChannels, p_pdi->maxOutputChannels );
  317.     }
  318.     msg_Dbg( p_aout, "-------------------------------------" );
  319.     msg_Dbg( p_aout, "requested device is #%d", p_sys->i_device_id );
  320.     if( p_sys->i_device_id >= p_sys->i_devices )
  321.     {
  322.         msg_Err( p_aout, "device %d does not exist", p_sys->i_device_id );
  323.         goto error;
  324.     }
  325.     p_sys->deviceInfo = Pa_GetDeviceInfo( p_sys->i_device_id );
  326.     if( p_sys->deviceInfo->maxOutputChannels < 1 )
  327.     {
  328.         msg_Err( p_aout, "no channel available" );
  329.         goto error;
  330.     }
  331.     if( var_Type( p_aout, "audio-device" ) == 0 )
  332.     {
  333.         var_Create( p_aout, "audio-device", VLC_VAR_INTEGER|VLC_VAR_HASCHOICE);
  334.         text.psz_string = _("Audio Device");
  335.         var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
  336.         if( p_sys->deviceInfo->maxOutputChannels >= 1 )
  337.         {
  338.             val.i_int = AOUT_VAR_MONO;
  339.             text.psz_string = N_("Mono");
  340.             var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE,
  341.                         &val, &text );
  342.             msg_Dbg( p_aout, "device supports 1 channel" );
  343.         }
  344.         if( p_sys->deviceInfo->maxOutputChannels >= 2 )
  345.         {
  346.             val.i_int = AOUT_VAR_STEREO;
  347.             text.psz_string = N_("Stereo");
  348.             var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE,
  349.                         &val, &text );
  350.             var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT,
  351.                         &val, NULL );
  352.             var_Set( p_aout, "audio-device", val );
  353.             msg_Dbg( p_aout, "device supports 2 channels" );
  354.         }
  355.         if( p_sys->deviceInfo->maxOutputChannels >= 4 )
  356.         {
  357.             val.i_int = AOUT_VAR_2F2R;
  358.             text.psz_string = N_("2 Front 2 Rear");
  359.             var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE,
  360.                         &val, &text );
  361.             msg_Dbg( p_aout, "device supports 4 channels" );
  362.         }
  363.         if( p_sys->deviceInfo->maxOutputChannels >= 5 )
  364.         {
  365.             val.i_int = AOUT_VAR_3F2R;
  366.             text.psz_string = N_("3 Front 2 Rear");
  367.             var_Change( p_aout, "audio-device",
  368.                         VLC_VAR_ADDCHOICE, &val, &text );
  369.             msg_Dbg( p_aout, "device supports 5 channels" );
  370.         }
  371.         if( p_sys->deviceInfo->maxOutputChannels >= 6 )
  372.         {
  373.             val.i_int = AOUT_VAR_5_1;
  374.             text.psz_string = N_("5.1");
  375.             var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE,
  376.                         &val, &text );
  377.             msg_Dbg( p_aout, "device supports 5.1 channels" );
  378.         }
  379.         var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
  380.         val.b_bool = VLC_TRUE;
  381.         var_Set( p_aout, "intf-change", val );
  382.     }
  383.     /* Audio format is paFloat32 (always supported by portaudio v19) */
  384.     p_aout->output.output.i_format = VLC_FOURCC('f','l','3','2');
  385.     return VLC_SUCCESS;
  386.  error:
  387.     if( ( i_err = Pa_Terminate() ) != paNoError )
  388.     {
  389.         msg_Err( p_aout, "Pa_Terminate returned %d", i_err );
  390.     }
  391.     return VLC_EGENERIC;
  392. }
  393. static int PAOpenStream( aout_instance_t *p_aout )
  394. {
  395.     aout_sys_t *p_sys = p_aout->output.p_sys;
  396.     const PaHostErrorInfo* paLastHostErrorInfo = Pa_GetLastHostErrorInfo();
  397.     PaStreamParameters paStreamParameters;
  398.     vlc_value_t val;
  399.     int i_channels, i_err;
  400.     uint32_t i_channel_mask;
  401.     if( var_Get( p_aout, "audio-device", &val ) < 0 )
  402.     {
  403.         return VLC_EGENERIC;
  404.     }
  405.     if( val.i_int == AOUT_VAR_5_1 )
  406.     {
  407.         p_aout->output.output.i_physical_channels
  408.             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
  409.               | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
  410.               | AOUT_CHAN_LFE;
  411.     }
  412.     else if( val.i_int == AOUT_VAR_3F2R )
  413.     {
  414.         p_aout->output.output.i_physical_channels
  415.             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
  416.             | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
  417.     }
  418.     else if( val.i_int == AOUT_VAR_2F2R )
  419.     {
  420.         p_aout->output.output.i_physical_channels
  421.             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
  422.             | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
  423.     }
  424.     else if( val.i_int == AOUT_VAR_MONO )
  425.     {
  426.         p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
  427.     }
  428.     else
  429.     {
  430.         p_aout->output.output.i_physical_channels
  431.             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
  432.     }
  433.     i_channels = aout_FormatNbChannels( &p_aout->output.output );
  434.     msg_Dbg( p_aout, "nb_channels requested = %d", i_channels );
  435.     i_channel_mask = p_aout->output.output.i_physical_channels;
  436.     /* Calculate the frame size in bytes */
  437.     p_sys->i_sample_size = 4 * i_channels;
  438.     p_aout->output.i_nb_samples = FRAME_SIZE;
  439.     aout_FormatPrepare( &p_aout->output.output );
  440.     aout_VolumeSoftInit( p_aout );
  441.     /* Check for channel reordering */
  442.     p_aout->output.p_sys->i_channel_mask = i_channel_mask;
  443.     p_aout->output.p_sys->i_bits_per_sample = 32; /* forced to paFloat32 */
  444.     p_aout->output.p_sys->i_channels = i_channels;
  445.     p_aout->output.p_sys->b_chan_reorder =
  446.         aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
  447.                                   i_channel_mask, i_channels,
  448.                                   p_aout->output.p_sys->pi_chan_table );
  449.     if( p_aout->output.p_sys->b_chan_reorder )
  450.     {
  451.         msg_Dbg( p_aout, "channel reordering needed" );
  452.     }
  453.     paStreamParameters.device = p_sys->i_device_id;
  454.     paStreamParameters.channelCount = i_channels;
  455.     paStreamParameters.sampleFormat = paFloat32;
  456.     paStreamParameters.suggestedLatency =
  457.         p_sys->deviceInfo->defaultLowOutputLatency;
  458.     paStreamParameters.hostApiSpecificStreamInfo = NULL;
  459.     i_err = Pa_OpenStream( &p_sys->p_stream, NULL /* no input */,
  460.                 &paStreamParameters, (double)p_aout->output.output.i_rate,
  461.                 FRAME_SIZE, paClipOff, paCallback, p_sys );
  462.     if( i_err != paNoError )
  463.     {
  464.         msg_Err( p_aout, "Pa_OpenStream returns %d : %s", i_err,
  465.                  Pa_GetErrorText( i_err ) );
  466.         if( i_err == paUnanticipatedHostError )
  467.         {
  468.             msg_Err( p_aout, "type %d code %ld : %s",
  469.                      paLastHostErrorInfo->hostApiType,
  470.                      paLastHostErrorInfo->errorCode,
  471.                      paLastHostErrorInfo->errorText );
  472.         }
  473.         p_sys->p_stream = 0;
  474.         return VLC_EGENERIC;
  475.     }
  476.     i_err = Pa_StartStream( p_sys->p_stream );
  477.     if( i_err != paNoError )
  478.     {
  479.         msg_Err( p_aout, "Pa_StartStream() failed" );
  480.         Pa_CloseStream( p_sys->p_stream );
  481.         return VLC_EGENERIC;
  482.     }
  483.     return VLC_SUCCESS;
  484. }
  485. /*****************************************************************************
  486.  * Play: play sound
  487.  *****************************************************************************/
  488. static void Play( aout_instance_t * p_aout )
  489. {
  490. }
  491. #ifdef PORTAUDIO_IS_SERIOUSLY_BROKEN
  492. /*****************************************************************************
  493.  * PORTAUDIOThread: all interactions with libportaudio.a are handled
  494.  * in this single thread.  Otherwise libportaudio.a is _not_ happy :-(
  495.  *****************************************************************************/
  496. static void PORTAUDIOThread( pa_thread_t *pa_thread )
  497. {
  498.     aout_instance_t *p_aout;
  499.     aout_sys_t *p_sys;
  500.     int i_err;
  501.     while( !pa_thread->b_die )
  502.     {
  503.         /* Wait for start of stream */
  504.         vlc_mutex_lock( &pa_thread->lock_signal );
  505.         if( !pa_thread->b_signal )
  506.             vlc_cond_wait( &pa_thread->signal, &pa_thread->lock_signal );
  507.         vlc_mutex_unlock( &pa_thread->lock_signal );
  508.         pa_thread->b_signal = VLC_FALSE;
  509.         p_aout = pa_thread->p_aout;
  510.         p_sys = p_aout->output.p_sys;
  511.         if( PAOpenDevice( p_aout ) != VLC_SUCCESS )
  512.         {
  513.             msg_Err( p_aout, "cannot open portaudio device" );
  514.             pa_thread->b_error = VLC_TRUE;
  515.         }
  516.         if( !pa_thread->b_error && PAOpenStream( p_aout ) != VLC_SUCCESS )
  517.         {
  518.             msg_Err( p_aout, "cannot open portaudio device" );
  519.             pa_thread->b_error = VLC_TRUE;
  520.             i_err = Pa_Terminate();
  521.             if( i_err != paNoError )
  522.             {
  523.                 msg_Err( p_aout, "Pa_Terminate: %d (%s)", i_err,
  524.                          Pa_GetErrorText( i_err ) );
  525.             }
  526.         }
  527.         /* Tell the main thread that we are ready */
  528.         vlc_mutex_lock( &pa_thread->lock_wait );
  529.         pa_thread->b_wait = VLC_TRUE;
  530.         vlc_cond_signal( &pa_thread->wait );
  531.         vlc_mutex_unlock( &pa_thread->lock_wait );
  532.         /* Wait for end of stream */
  533.         vlc_mutex_lock( &pa_thread->lock_signal );
  534.         if( !pa_thread->b_signal )
  535.             vlc_cond_wait( &pa_thread->signal, &pa_thread->lock_signal );
  536.         vlc_mutex_unlock( &pa_thread->lock_signal );
  537.         pa_thread->b_signal = VLC_FALSE;
  538.         if( pa_thread->b_error ) continue;
  539.         i_err = Pa_StopStream( p_sys->p_stream );
  540.         if( i_err != paNoError )
  541.         {
  542.             msg_Err( p_aout, "Pa_StopStream: %d (%s)", i_err,
  543.                      Pa_GetErrorText( i_err ) );
  544.         }
  545.         i_err = Pa_CloseStream( p_sys->p_stream );
  546.         if( i_err != paNoError )
  547.         {
  548.             msg_Err( p_aout, "Pa_CloseStream: %d (%s)", i_err,
  549.                      Pa_GetErrorText( i_err ) );
  550.         }
  551.         i_err = Pa_Terminate();
  552.         if( i_err != paNoError )
  553.         {
  554.             msg_Err( p_aout, "Pa_Terminate: %d (%s)", i_err,
  555.                      Pa_GetErrorText( i_err ) );
  556.         }
  557.         /* Tell the main thread that we are ready */
  558.         vlc_mutex_lock( &pa_thread->lock_wait );
  559.         pa_thread->b_wait = VLC_TRUE;
  560.         vlc_cond_signal( &pa_thread->wait );
  561.         vlc_mutex_unlock( &pa_thread->lock_wait );
  562.     }
  563. }
  564. #endif