]> git.sesse.net Git - vlc/blob - modules/audio_output/portaudio.c
PulseAudio: missing lock
[vlc] / modules / audio_output / portaudio.c
1 /*****************************************************************************
2  * portaudio.c : portaudio (v19) audio output plugin
3  *****************************************************************************
4  * Copyright (C) 2002, 2006 the VideoLAN team
5  * $Id$
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_aout.h>
36
37
38 #include <portaudio.h>
39
40 #define FRAME_SIZE 1024              /* The size is in samples, not in bytes */
41
42 #ifdef WIN32
43 #   define PORTAUDIO_IS_SERIOUSLY_BROKEN 1
44 #endif
45
46 /*****************************************************************************
47  * aout_sys_t: portaudio audio output method descriptor
48  *****************************************************************************/
49 typedef struct
50 {
51     audio_output_t *p_aout;
52
53     vlc_thread_t thread;
54     vlc_cond_t  wait;
55     vlc_mutex_t lock_wait;
56     bool  b_wait;
57     vlc_cond_t  signal;
58     vlc_mutex_t lock_signal;
59     bool  b_signal;
60     bool  b_error;
61
62 } pa_thread_t;
63
64 struct aout_sys_t
65 {
66     aout_packet_t packet;
67     audio_output_t *p_aout;
68     PaStream *p_stream;
69
70     PaDeviceIndex i_devices;
71     int i_sample_size;
72     PaDeviceIndex i_device_id;
73     const PaDeviceInfo *deviceInfo;
74
75     bool b_chan_reorder;              /* do we need channel reordering */
76     int pi_chan_table[AOUT_CHAN_MAX];
77     uint32_t i_channel_mask;
78     uint32_t i_bits_per_sample;
79     uint32_t i_channels;
80 };
81
82 static const uint32_t pi_channels_out[] =
83     { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
84       AOUT_CHAN_CENTER, AOUT_CHAN_LFE,
85       AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_REARCENTER,
86       AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT, 0 };
87
88 #ifdef PORTAUDIO_IS_SERIOUSLY_BROKEN
89 static bool b_init = 0;
90 static pa_thread_t *pa_thread;
91 static void* PORTAUDIOThread( void * );
92 #endif
93
94 /*****************************************************************************
95  * Local prototypes.
96  *****************************************************************************/
97 static int  Open        ( vlc_object_t * );
98 static void Close       ( vlc_object_t * );
99 static void Play        ( audio_output_t *, block_t * );
100
101 static int PAOpenDevice( audio_output_t * );
102 static int PAOpenStream( audio_output_t * );
103
104 /*****************************************************************************
105  * Module descriptor
106  *****************************************************************************/
107 #define DEVICE_TEXT N_("Output device")
108 #define DEVICE_LONGTEXT N_("Portaudio identifier for the output device")
109
110 vlc_module_begin ()
111     set_shortname( "PortAudio" )
112     set_description( N_("PORTAUDIO audio output") )
113     set_category( CAT_AUDIO )
114     set_subcategory( SUBCAT_AUDIO_AOUT )
115     add_integer( "portaudio-audio-device", 0,
116                  DEVICE_TEXT, DEVICE_LONGTEXT, false )
117         add_deprecated_alias( "portaudio-device" )   /* deprecated since 0.9.3 */
118     set_capability( "audio output", 0 )
119     set_callbacks( Open, Close )
120 vlc_module_end ()
121
122 /* This routine will be called by the PortAudio engine when audio is needed.
123  * It may called at interrupt level on some machines so don't do anything
124  * that could mess up the system like calling malloc() or free().
125  */
126 static int paCallback( const void *inputBuffer, void *outputBuffer,
127                        unsigned long framesPerBuffer,
128                        const PaStreamCallbackTimeInfo *paDate,
129                        PaStreamCallbackFlags statusFlags, void *p_cookie )
130 {
131     VLC_UNUSED( inputBuffer ); VLC_UNUSED( statusFlags );
132
133     struct aout_sys_t *p_sys = (struct aout_sys_t*) p_cookie;
134     audio_output_t   *p_aout = p_sys->p_aout;
135     aout_buffer_t     *p_buffer;
136     mtime_t out_date;
137
138     out_date = mdate() + (mtime_t) ( 1000000 *
139         ( paDate->outputBufferDacTime - paDate->currentTime ) );
140     p_buffer = aout_PacketNext( p_aout, out_date );
141
142     if ( p_buffer != NULL )
143     {
144         if( p_sys->b_chan_reorder )
145         {
146             /* Do the channel reordering here */
147             aout_ChannelReorder( p_buffer->p_buffer, p_buffer->i_buffer,
148                                  p_sys->i_channels, p_sys->pi_chan_table,
149                                  p_sys->i_bits_per_sample );
150         }
151         vlc_memcpy( outputBuffer, p_buffer->p_buffer,
152                     framesPerBuffer * p_sys->i_sample_size );
153         aout_BufferFree( p_buffer );
154     }
155     else
156         /* Audio output buffer shortage -> stop the fill process and wait */
157     {
158         vlc_memset( outputBuffer, 0, framesPerBuffer * p_sys->i_sample_size );
159     }
160     return 0;
161 }
162
163 /*****************************************************************************
164  * Open: open the audio device
165  *****************************************************************************/
166 static int Open( vlc_object_t * p_this )
167 {
168     audio_output_t *p_aout = (audio_output_t *)p_this;
169     struct aout_sys_t * p_sys;
170
171     msg_Dbg( p_aout, "entering Open()");
172
173     /* Allocate p_sys structure */
174     p_sys = malloc( sizeof(aout_sys_t) );
175     if( p_sys == NULL )
176         return VLC_ENOMEM;
177     p_sys->p_aout = p_aout;
178     p_sys->p_stream = 0;
179     p_aout->sys = p_sys;
180     p_aout->pf_play = aout_PacketPlay;
181     p_aout->pf_pause = aout_PacketPause;
182     p_aout->pf_flush = aout_PacketFlush;
183
184     /* Retrieve output device id from config */
185     p_sys->i_device_id = var_CreateGetInteger( p_aout, "portaudio-audio-device" );
186
187 #ifdef PORTAUDIO_IS_SERIOUSLY_BROKEN
188     if( !b_init )
189     {
190         int i_err;
191
192         /* Test device */
193         if( PAOpenDevice( p_aout ) != VLC_SUCCESS )
194         {
195             msg_Err( p_aout, "cannot open portaudio device" );
196             free( p_sys );
197             return VLC_EGENERIC;
198         }
199
200         /* Close device for now. We'll re-open it later on */
201         if( ( i_err = Pa_Terminate() ) != paNoError )
202         {
203             msg_Err( p_aout, "closing the device returned %d", i_err );
204         }
205
206         b_init = true;
207
208         /* Now we need to setup our DirectSound play notification structure */
209         pa_thread = calloc( 1, sizeof(*pa_thread) );
210         pa_thread->p_aout = p_aout;
211         pa_thread->b_error = false;
212         vlc_mutex_init( &pa_thread->lock_wait );
213         vlc_cond_init( &pa_thread->wait );
214         pa_thread->b_wait = false;
215         vlc_mutex_init( &pa_thread->lock_signal );
216         vlc_cond_init( &pa_thread->signal );
217         pa_thread->b_signal = false;
218
219         /* Create PORTAUDIOThread */
220         if( vlc_clone( &pa_thread->thread, PORTAUDIOThread, pa_thread,
221                                VLC_THREAD_PRIORITY_OUTPUT ) )
222         {
223             msg_Err( p_aout, "cannot create PORTAUDIO thread" );
224             return VLC_EGENERIC;
225         }
226     }
227     else
228     {
229         pa_thread->p_aout = p_aout;
230         pa_thread->b_wait = false;
231         pa_thread->b_signal = false;
232         pa_thread->b_error = false;
233     }
234
235     /* Signal start of stream */
236     vlc_mutex_lock( &pa_thread->lock_signal );
237     pa_thread->b_signal = true;
238     vlc_cond_signal( &pa_thread->signal );
239     vlc_mutex_unlock( &pa_thread->lock_signal );
240
241     /* Wait until thread is ready */
242     vlc_mutex_lock( &pa_thread->lock_wait );
243     while( !pa_thread->b_wait )
244         vlc_cond_wait( &pa_thread->wait, &pa_thread->lock_wait );
245     vlc_mutex_unlock( &pa_thread->lock_wait );
246     pa_thread->b_wait = false;
247
248     if( pa_thread->b_error )
249     {
250         msg_Err( p_aout, "PORTAUDIO thread failed" );
251         Close( p_this );
252         return VLC_EGENERIC;
253     }
254
255     return VLC_SUCCESS;
256
257 #else
258
259     if( PAOpenDevice( p_aout ) != VLC_SUCCESS )
260     {
261         msg_Err( p_aout, "cannot open portaudio device" );
262         free( p_sys );
263         return VLC_EGENERIC;
264     }
265
266     if( PAOpenStream( p_aout ) != VLC_SUCCESS )
267     {
268         msg_Err( p_aout, "cannot open portaudio device" );
269     }
270
271     return VLC_SUCCESS;
272
273 #endif
274 }
275
276 /*****************************************************************************
277  * Close: close the audio device
278  *****************************************************************************/
279 static void Close ( vlc_object_t *p_this )
280 {
281     audio_output_t *p_aout = (audio_output_t *)p_this;
282     aout_sys_t *p_sys = p_aout->sys;
283
284     msg_Dbg( p_aout, "closing portaudio");
285
286 #ifdef PORTAUDIO_IS_SERIOUSLY_BROKEN
287
288     /* Signal end of stream */
289     vlc_mutex_lock( &pa_thread->lock_signal );
290     pa_thread->b_signal = true;
291     vlc_cond_signal( &pa_thread->signal );
292     vlc_mutex_unlock( &pa_thread->lock_signal );
293
294     /* Wait until thread is ready */
295     vlc_mutex_lock( &pa_thread->lock_wait );
296     while( !pa_thread->b_wait )
297         vlc_cond_wait( &pa_thread->wait, &pa_thread->lock_wait );
298     vlc_mutex_unlock( &pa_thread->lock_wait );
299     pa_thread->b_wait = false;
300
301 #else
302
303     int i_err = Pa_StopStream( p_sys->p_stream );
304     if( i_err != paNoError )
305     {
306         msg_Err( p_aout, "Pa_StopStream: %d (%s)", i_err,
307                  Pa_GetErrorText( i_err ) );
308     }
309     i_err = Pa_CloseStream( p_sys->p_stream );
310     if( i_err != paNoError )
311     {
312         msg_Err( p_aout, "Pa_CloseStream: %d (%s)", i_err,
313                  Pa_GetErrorText( i_err ) );
314     }
315
316     i_err = Pa_Terminate();
317     if( i_err != paNoError )
318     {
319         msg_Err( p_aout, "Pa_Terminate: %d (%s)", i_err,
320                  Pa_GetErrorText( i_err ) );
321     }
322
323 #endif
324
325     msg_Dbg( p_aout, "portaudio closed");
326     aout_PacketDestroy( p_aout );
327     free( p_sys );
328 }
329
330 static int PAOpenDevice( audio_output_t *p_aout )
331 {
332     aout_sys_t *p_sys = p_aout->sys;
333     const PaDeviceInfo *p_pdi;
334     PaError i_err;
335     vlc_value_t val, text;
336     int i;
337
338     /* Initialize portaudio */
339     i_err = Pa_Initialize();
340     if( i_err != paNoError )
341     {
342         msg_Err( p_aout, "Pa_Initialize returned %d : %s",
343                  i_err, Pa_GetErrorText( i_err ) );
344
345         return VLC_EGENERIC;
346     }
347
348     p_sys->i_devices = Pa_GetDeviceCount();
349     if( p_sys->i_devices < 0 )
350     {
351         i_err = p_sys->i_devices;
352         msg_Err( p_aout, "Pa_GetDeviceCount returned %d : %s", i_err,
353                  Pa_GetErrorText( i_err ) );
354
355         goto error;
356     }
357
358     /* Display all devices info */
359     msg_Dbg( p_aout, "number of devices = %d", p_sys->i_devices );
360     for( i = 0; i < p_sys->i_devices; i++ )
361     {
362         p_pdi = Pa_GetDeviceInfo( i );
363         msg_Dbg( p_aout, "------------------------------------- #%d", i );
364         msg_Dbg( p_aout, "Name         = %s", p_pdi->name );
365         msg_Dbg( p_aout, "Max Inputs   = %d, Max Outputs = %d",
366                   p_pdi->maxInputChannels, p_pdi->maxOutputChannels );
367     }
368     msg_Dbg( p_aout, "-------------------------------------" );
369
370     msg_Dbg( p_aout, "requested device is #%d", p_sys->i_device_id );
371     if( p_sys->i_device_id >= p_sys->i_devices )
372     {
373         msg_Err( p_aout, "device %d does not exist", p_sys->i_device_id );
374         goto error;
375     }
376     p_sys->deviceInfo = Pa_GetDeviceInfo( p_sys->i_device_id );
377
378     if( p_sys->deviceInfo->maxOutputChannels < 1 )
379     {
380         msg_Err( p_aout, "no channel available" );
381         goto error;
382     }
383
384     if( var_Type( p_aout, "audio-device" ) == 0 )
385     {
386         var_Create( p_aout, "audio-device", VLC_VAR_INTEGER|VLC_VAR_HASCHOICE);
387         text.psz_string = _("Audio Device");
388         var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
389
390         if( p_sys->deviceInfo->maxOutputChannels >= 1 )
391         {
392             val.i_int = AOUT_VAR_MONO;
393             text.psz_string = _("Mono");
394             var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE,
395                         &val, &text );
396             msg_Dbg( p_aout, "device supports 1 channel" );
397         }
398         if( p_sys->deviceInfo->maxOutputChannels >= 2 )
399         {
400             val.i_int = AOUT_VAR_STEREO;
401             text.psz_string = _("Stereo");
402             var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE,
403                         &val, &text );
404             var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT,
405                         &val, NULL );
406             var_Set( p_aout, "audio-device", val );
407             msg_Dbg( p_aout, "device supports 2 channels" );
408         }
409         if( p_sys->deviceInfo->maxOutputChannels >= 4 )
410         {
411             val.i_int = AOUT_VAR_2F2R;
412             text.psz_string = _("2 Front 2 Rear");
413             var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE,
414                         &val, &text );
415             msg_Dbg( p_aout, "device supports 4 channels" );
416         }
417         if( p_sys->deviceInfo->maxOutputChannels >= 5 )
418         {
419             val.i_int = AOUT_VAR_3F2R;
420             text.psz_string = _("3 Front 2 Rear");
421             var_Change( p_aout, "audio-device",
422                         VLC_VAR_ADDCHOICE, &val, &text );
423             msg_Dbg( p_aout, "device supports 5 channels" );
424         }
425         if( p_sys->deviceInfo->maxOutputChannels >= 6 )
426         {
427             val.i_int = AOUT_VAR_5_1;
428             text.psz_string = _("5.1");
429             var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE,
430                         &val, &text );
431             msg_Dbg( p_aout, "device supports 5.1 channels" );
432         }
433
434         var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
435         var_TriggerCallback( p_aout, "intf-change" );
436     }
437
438     /* Audio format is paFloat32 (always supported by portaudio v19) */
439     p_aout->format.i_format = VLC_CODEC_FL32;
440
441     return VLC_SUCCESS;
442
443  error:
444     if( ( i_err = Pa_Terminate() ) != paNoError )
445     {
446         msg_Err( p_aout, "Pa_Terminate returned %d", i_err );
447     }
448     return VLC_EGENERIC;
449 }
450
451 static int PAOpenStream( audio_output_t *p_aout )
452 {
453     aout_sys_t *p_sys = p_aout->sys;
454     const PaHostErrorInfo* paLastHostErrorInfo = Pa_GetLastHostErrorInfo();
455     PaStreamParameters paStreamParameters;
456     vlc_value_t val;
457     int i_channels, i_err;
458     uint32_t i_channel_mask;
459
460     if( var_Get( p_aout, "audio-device", &val ) < 0 )
461     {
462         return VLC_EGENERIC;
463     }
464
465     if( val.i_int == AOUT_VAR_5_1 )
466     {
467         p_aout->format.i_physical_channels
468             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
469               | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
470               | AOUT_CHAN_LFE;
471     }
472     else if( val.i_int == AOUT_VAR_3F2R )
473     {
474         p_aout->format.i_physical_channels
475             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
476             | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
477     }
478     else if( val.i_int == AOUT_VAR_2F2R )
479     {
480         p_aout->format.i_physical_channels
481             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
482             | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
483     }
484     else if( val.i_int == AOUT_VAR_MONO )
485     {
486         p_aout->format.i_physical_channels = AOUT_CHAN_CENTER;
487     }
488     else
489     {
490         p_aout->format.i_physical_channels
491             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
492     }
493
494     i_channels = aout_FormatNbChannels( &p_aout->format );
495     msg_Dbg( p_aout, "nb_channels requested = %d", i_channels );
496     i_channel_mask = p_aout->format.i_physical_channels;
497
498     /* Calculate the frame size in bytes */
499     p_sys->i_sample_size = 4 * i_channels;
500     aout_FormatPrepare( &p_aout->format );
501     aout_PacketInit( p_aout, &p_sys->packet, FRAME_SIZE );
502     aout_VolumeSoftInit( p_aout );
503
504     /* Check for channel reordering */
505     p_aout->sys->i_channel_mask = i_channel_mask;
506     p_aout->sys->i_bits_per_sample = 32; /* forced to paFloat32 */
507     p_aout->sys->i_channels = i_channels;
508
509     p_aout->sys->b_chan_reorder =
510         aout_CheckChannelReorder( NULL, pi_channels_out,
511                                   i_channel_mask, i_channels,
512                                   p_aout->sys->pi_chan_table );
513
514     if( p_aout->sys->b_chan_reorder )
515     {
516         msg_Dbg( p_aout, "channel reordering needed" );
517     }
518
519     paStreamParameters.device = p_sys->i_device_id;
520     paStreamParameters.channelCount = i_channels;
521     paStreamParameters.sampleFormat = paFloat32;
522     paStreamParameters.suggestedLatency =
523         p_sys->deviceInfo->defaultLowOutputLatency;
524     paStreamParameters.hostApiSpecificStreamInfo = NULL;
525
526     i_err = Pa_OpenStream( &p_sys->p_stream, NULL /* no input */,
527                 &paStreamParameters, (double)p_aout->format.i_rate,
528                 FRAME_SIZE, paClipOff, paCallback, p_sys );
529     if( i_err != paNoError )
530     {
531         msg_Err( p_aout, "Pa_OpenStream returns %d : %s", i_err,
532                  Pa_GetErrorText( i_err ) );
533         if( i_err == paUnanticipatedHostError )
534         {
535             msg_Err( p_aout, "type %d code %ld : %s",
536                      paLastHostErrorInfo->hostApiType,
537                      paLastHostErrorInfo->errorCode,
538                      paLastHostErrorInfo->errorText );
539         }
540         p_sys->p_stream = 0;
541         aout_PacketDestroy( p_aout );
542         return VLC_EGENERIC;
543     }
544
545     i_err = Pa_StartStream( p_sys->p_stream );
546     if( i_err != paNoError )
547     {
548         msg_Err( p_aout, "Pa_StartStream() failed" );
549         Pa_CloseStream( p_sys->p_stream );
550         aout_PacketDestroy( p_aout );
551         return VLC_EGENERIC;
552     }
553
554     return VLC_SUCCESS;
555 }
556
557 #ifdef PORTAUDIO_IS_SERIOUSLY_BROKEN
558 /*****************************************************************************
559  * PORTAUDIOThread: all interactions with libportaudio.a are handled
560  * in this single thread.  Otherwise libportaudio.a is _not_ happy :-(
561  *****************************************************************************/
562 static void* PORTAUDIOThread( void *data )
563 {
564     pa_thread_t *pa_thread = (pa_thread_t*)data;
565     audio_output_t *p_aout;
566     aout_sys_t *p_sys;
567     int i_err;
568     int canc = vlc_savecancel ();
569
570     for( ;; )
571     {
572         /* Wait for start of stream */
573         vlc_mutex_lock( &pa_thread->lock_signal );
574         while( !pa_thread->b_signal )
575             vlc_cond_wait( &pa_thread->signal, &pa_thread->lock_signal );
576         vlc_mutex_unlock( &pa_thread->lock_signal );
577         pa_thread->b_signal = false;
578
579         p_aout = pa_thread->p_aout;
580         p_sys = p_aout->sys;
581
582         if( PAOpenDevice( p_aout ) != VLC_SUCCESS )
583         {
584             msg_Err( p_aout, "cannot open portaudio device" );
585             pa_thread->b_error = true;
586         }
587
588         if( !pa_thread->b_error && PAOpenStream( p_aout ) != VLC_SUCCESS )
589         {
590             msg_Err( p_aout, "cannot open portaudio device" );
591             pa_thread->b_error = true;
592
593             i_err = Pa_Terminate();
594             if( i_err != paNoError )
595             {
596                 msg_Err( p_aout, "Pa_Terminate: %d (%s)", i_err,
597                          Pa_GetErrorText( i_err ) );
598             }
599         }
600
601         /* Tell the main thread that we are ready */
602         vlc_mutex_lock( &pa_thread->lock_wait );
603         pa_thread->b_wait = true;
604         vlc_cond_signal( &pa_thread->wait );
605         vlc_mutex_unlock( &pa_thread->lock_wait );
606
607         /* Wait for end of stream */
608         vlc_mutex_lock( &pa_thread->lock_signal );
609         while( !pa_thread->b_signal )
610             vlc_cond_wait( &pa_thread->signal, &pa_thread->lock_signal );
611         vlc_mutex_unlock( &pa_thread->lock_signal );
612         pa_thread->b_signal = false;
613
614         if( pa_thread->b_error ) continue;
615
616         i_err = Pa_StopStream( p_sys->p_stream );
617         if( i_err != paNoError )
618         {
619             msg_Err( p_aout, "Pa_StopStream: %d (%s)", i_err,
620                      Pa_GetErrorText( i_err ) );
621         }
622         i_err = Pa_CloseStream( p_sys->p_stream );
623         if( i_err != paNoError )
624         {
625             msg_Err( p_aout, "Pa_CloseStream: %d (%s)", i_err,
626                      Pa_GetErrorText( i_err ) );
627         }
628         i_err = Pa_Terminate();
629         if( i_err != paNoError )
630         {
631             msg_Err( p_aout, "Pa_Terminate: %d (%s)", i_err,
632                      Pa_GetErrorText( i_err ) );
633         }
634
635         /* Tell the main thread that we are ready */
636         vlc_mutex_lock( &pa_thread->lock_wait );
637         pa_thread->b_wait = true;
638         vlc_cond_signal( &pa_thread->wait );
639         vlc_mutex_unlock( &pa_thread->lock_wait );
640     }
641     vlc_restorecancel (canc);
642     return NULL;
643 }
644 #endif