]> git.sesse.net Git - vlc/blob - src/audio_output/audio_output.c
* audio_output/audio_output.c :
[vlc] / src / audio_output / audio_output.c
1 /******************************************************************************
2  * audio_output.c : audio output thread
3  * (c)1999 VideoLAN
4  ******************************************************************************/
5
6 /* TODO:
7  *
8  * - Passer un certain nombre de "fonctions" (genre add_samples) en macro ou
9  *   inline
10  * - Faire les optimisations dans les fonctions threads :
11  *   = Stocker les "petits calculs" dans des variables au lieu de les refaire
12  *     à chaque boucle
13  *   = Utiliser des tables pour les gros calculs
14  * - Faire une structure différente pour intf/adec fifo
15  *
16  */
17
18 /******************************************************************************
19  * Preamble
20  ******************************************************************************/
21 #include <unistd.h>
22
23 #include <sys/soundcard.h>
24 #include <stdio.h>                                            /* "intf_msg.h" */
25 #include <stdlib.h>                             /* calloc(), malloc(), free() */
26
27 #include "common.h"
28 #include "config.h"
29 #include "mtime.h"                              /* mtime_t, mdate(), msleep() */
30 #include "vlc_thread.h"
31
32 #include "intf_msg.h"                         /* intf_DbgMsg(), intf_ErrMsg() */
33
34 #include "audio_output.h"
35 #include "audio_dsp.h"
36 #include "main.h"
37
38 /******************************************************************************
39  * Local prototypes
40  ******************************************************************************/
41
42 static int aout_SpawnThread( aout_thread_t * p_aout );
43
44 /* Creating as much aout_Thread functions as configurations is one solution,
45  * examining the different cases in the Thread loop of an unique function is
46  * another. I chose the first solution. */
47 void aout_Thread_S8_Mono        ( aout_thread_t * p_aout );
48 void aout_Thread_U8_Mono        ( aout_thread_t * p_aout );
49 void aout_Thread_S16_Mono       ( aout_thread_t * p_aout );
50 void aout_Thread_U16_Mono       ( aout_thread_t * p_aout );
51 void aout_Thread_S8_Stereo      ( aout_thread_t * p_aout );
52 void aout_Thread_U8_Stereo      ( aout_thread_t * p_aout );
53 void aout_Thread_S16_Stereo     ( aout_thread_t * p_aout );
54 void aout_Thread_U16_Stereo     ( aout_thread_t * p_aout );
55
56 static __inline__ void InitializeIncrement( aout_increment_t * p_increment, long l_numerator, long l_denominator );
57 static __inline__ int NextFrame( aout_thread_t * p_aout, aout_fifo_t * p_fifo, mtime_t aout_date );
58
59 /******************************************************************************
60  * aout_CreateThread: initialize audio thread
61  ******************************************************************************/
62 aout_thread_t *aout_CreateThread( int *pi_status )
63 {
64     aout_thread_t * p_aout;                               /* thread descriptor */
65     int             i_status;                                 /* thread status */
66    
67     /* Allocate descriptor */
68     p_aout = (aout_thread_t *) malloc( sizeof(aout_thread_t) );
69     if( p_aout == NULL )
70     {
71         return( NULL );
72     }
73
74     //???? kludge to initialize some audio parameters - place this section somewhere
75     //???? else
76     p_aout->dsp.i_format = AOUT_DEFAULT_FORMAT;
77     p_aout->dsp.psz_device = main_GetPszVariable( AOUT_DSP_VAR, AOUT_DSP_DEFAULT );
78     p_aout->dsp.b_stereo   = main_GetIntVariable( AOUT_STEREO_VAR, AOUT_STEREO_DEFAULT );
79     p_aout->dsp.l_rate     = main_GetIntVariable( AOUT_RATE_VAR, AOUT_RATE_DEFAULT );    
80     // ???? end of kludge
81
82     /* 
83      * Initialize DSP 
84      */
85     if ( aout_dspOpen( &p_aout->dsp ) )
86     {
87         free( p_aout );
88         return( NULL );
89     }
90     if ( aout_dspReset( &p_aout->dsp ) )
91     {
92         aout_dspClose( &p_aout->dsp );
93         free( p_aout );
94         return( NULL );
95     }
96     if ( aout_dspSetFormat( &p_aout->dsp ) )
97     {
98         aout_dspClose( &p_aout->dsp );
99         free( p_aout );
100         return( NULL );
101     }
102     if ( aout_dspSetChannels( &p_aout->dsp ) )
103     {
104         aout_dspClose( &p_aout->dsp );
105         free( p_aout );
106         return( NULL );
107     }
108     if ( aout_dspSetRate( &p_aout->dsp ) )
109     {
110         aout_dspClose( &p_aout->dsp );
111         free( p_aout );
112         return( NULL );
113     }
114     intf_DbgMsg("aout debug: audio device (%s) opened (format=%i, stereo=%i, rate=%li)\n",
115         p_aout->dsp.psz_device,
116         p_aout->dsp.i_format,
117         p_aout->dsp.b_stereo, p_aout->dsp.l_rate);
118
119     //?? maybe it would be cleaner to change SpawnThread prototype
120     //?? see vout to handle status correctly - however, it is not critical since
121     //?? this thread is only called in main is all calls are blocking
122     if( aout_SpawnThread( p_aout ) )
123     {
124         aout_dspClose( &p_aout->dsp );
125         free( p_aout );
126         return( NULL );
127     }
128
129     return( p_aout );
130 }
131
132 /******************************************************************************
133  * aout_SpawnThread
134  ******************************************************************************/
135 static int aout_SpawnThread( aout_thread_t * p_aout )
136 {
137     int             i_fifo;
138     long            l_bytes;
139     void *          aout_thread = NULL;
140
141     intf_DbgMsg("aout debug: spawning audio output thread (%p)\n", p_aout);
142
143     /* We want the audio output thread to live */
144     p_aout->b_die = 0;
145
146     /* Initialize the fifos lock */
147     vlc_mutex_init( &p_aout->fifos_lock );
148     /* Initialize audio fifos : set all fifos as empty and initialize locks */
149     for ( i_fifo = 0; i_fifo < AOUT_MAX_FIFOS; i_fifo++ )
150     {
151         p_aout->fifo[i_fifo].i_type = AOUT_EMPTY_FIFO;
152         vlc_mutex_init( &p_aout->fifo[i_fifo].data_lock );
153         vlc_cond_init( &p_aout->fifo[i_fifo].data_wait );
154     }
155
156     /* Compute the size (in audio units) of the audio output buffer. Although
157      * AOUT_BUFFER_DURATION is given in microseconds, the output rate is given
158      * in Hz, that's why we need to divide by 10^6 microseconds (1 second) */
159     p_aout->l_units = (long)( ((s64)p_aout->dsp.l_rate * AOUT_BUFFER_DURATION) / 1000000 );
160     p_aout->l_msleep = (long)( ((s64)p_aout->l_units * 1000000) / (s64)p_aout->dsp.l_rate );
161
162     /* Make aout_thread point to the right thread function, and compute the
163      * byte size of the audio output buffer */
164     switch ( p_aout->dsp.b_stereo )
165     {
166         /* Audio output is mono */
167         case 0:
168             switch ( p_aout->dsp.i_format )
169             {
170                 case AFMT_U8:
171                     l_bytes = 1 * sizeof(u8) * p_aout->l_units;
172                     aout_thread = (void *)aout_Thread_U8_Mono;
173                     break;
174
175                 case AFMT_S8:
176                     l_bytes = 1 * sizeof(s8) * p_aout->l_units;
177                     aout_thread = (void *)aout_Thread_S8_Mono;
178                     break;
179
180                 case AFMT_U16_LE:
181                 case AFMT_U16_BE:
182                     l_bytes = 1 * sizeof(u16) * p_aout->l_units;
183                     aout_thread = (void *)aout_Thread_U16_Mono;
184                     break;
185
186                 case AFMT_S16_LE:
187                 case AFMT_S16_BE:
188                     l_bytes = 1 * sizeof(s16) * p_aout->l_units;
189                     aout_thread = (void *)aout_Thread_S16_Mono;
190                     break;
191
192                 default:
193                     intf_ErrMsg("aout error: unknown audio output format (%i)\n",
194                         p_aout->dsp.i_format);
195                     return( -1 );
196             }
197             break;
198
199         /* Audio output is stereo */
200         case 1:
201             switch ( p_aout->dsp.i_format )
202             {
203                 case AFMT_U8:
204                     l_bytes = 2 * sizeof(u8) * p_aout->l_units;
205                     aout_thread = (void *)aout_Thread_U8_Stereo;
206                     break;
207
208                 case AFMT_S8:
209                     l_bytes = 2 * sizeof(s8) * p_aout->l_units;
210                     aout_thread = (void *)aout_Thread_S8_Stereo;
211                     break;
212
213                 case AFMT_U16_LE:
214                 case AFMT_U16_BE:
215                     l_bytes = 2 * sizeof(u16) * p_aout->l_units;
216                     aout_thread = (void *)aout_Thread_U16_Stereo;
217                     break;
218
219                 case AFMT_S16_LE:
220                 case AFMT_S16_BE:
221                     l_bytes = 2 * sizeof(s16) * p_aout->l_units;
222                     aout_thread = (void *)aout_Thread_S16_Stereo;
223                     break;
224
225                 default:
226                     intf_ErrMsg("aout error: unknown audio output format (%i)\n",
227                         p_aout->dsp.i_format);
228                     return( -1 );
229             }
230             break;
231
232         default:
233             intf_ErrMsg("aout error: unknown number of audio channels (%i)\n",
234                 p_aout->dsp.b_stereo + 1);
235             return( -1 );
236     }
237
238     /* Allocate the memory needed by the audio output buffers, and set to zero
239      * the s32 buffer's memory */
240     if ( (p_aout->buffer = malloc(l_bytes)) == NULL )
241     {
242         intf_ErrMsg("aout error: not enough memory to create the output buffer\n");
243         return( -1 );
244     }
245     if ( (p_aout->s32_buffer = (s32 *)calloc(p_aout->l_units, sizeof(s32) << p_aout->dsp.b_stereo)) == NULL )
246     {
247         intf_ErrMsg("aout error: not enough memory to create the s32 output buffer\n");
248         free( p_aout->buffer );
249         return( -1 );
250     }
251
252     /* Before launching the thread, we try to predict the date of the first
253      * audio unit in the first output buffer */
254     p_aout->date = mdate();
255
256     /* Launch the thread */
257     if ( vlc_thread_create( &p_aout->thread_id, "audio output", (vlc_thread_func_t)aout_thread, p_aout ) )
258     {
259         intf_ErrMsg("aout error: can't spawn audio output thread (%p)\n", p_aout);
260         free( p_aout->buffer );
261         free( p_aout->s32_buffer );
262         return( -1 );
263     }
264
265     intf_DbgMsg("aout debug: audio output thread (%p) spawned\n", p_aout);
266     return( 0 );
267 }
268
269 /******************************************************************************
270  * aout_DestroyThread
271  ******************************************************************************/
272 void aout_DestroyThread( aout_thread_t * p_aout, int *pi_status )
273 {
274     //???? pi_status is not handled correctly: check vout how to do! 
275
276     intf_DbgMsg("aout debug: requesting termination of audio output thread (%p)\n", p_aout);
277
278     /* Ask thread to kill itself and wait until it's done */
279     p_aout->b_die = 1;
280     vlc_thread_join( p_aout->thread_id ); // only if pi_status is NULL
281
282     /* Free the allocated memory */
283     free( p_aout->buffer );
284     free( p_aout->s32_buffer );
285
286     /* Free the structure */
287     aout_dspClose( &p_aout->dsp );
288     intf_DbgMsg("aout debug: audio device (%s) closed\n", p_aout->dsp.psz_device);
289     free( p_aout );
290 }
291
292 /******************************************************************************
293  * aout_CreateFifo
294  ******************************************************************************/
295 aout_fifo_t * aout_CreateFifo( aout_thread_t * p_aout, aout_fifo_t * p_fifo )
296 {
297     int i_fifo;
298
299     /* Take the fifos lock */
300     vlc_mutex_lock( &p_aout->fifos_lock );
301
302     /* Looking for a free fifo structure */
303     for ( i_fifo = 0; i_fifo < AOUT_MAX_FIFOS; i_fifo++ )
304     {
305         if ( p_aout->fifo[i_fifo].i_type == AOUT_EMPTY_FIFO)
306         {
307             break;
308         }
309     }
310     if ( i_fifo == AOUT_MAX_FIFOS )
311     {
312         intf_ErrMsg("aout error: no empty fifo available\n");
313         vlc_mutex_unlock( &p_aout->fifos_lock );
314         return( NULL );
315     }
316
317     /* Initialize the new fifo structure */
318     switch ( p_aout->fifo[i_fifo].i_type = p_fifo->i_type )
319     {
320         case AOUT_INTF_MONO_FIFO:
321         case AOUT_INTF_STEREO_FIFO:
322             p_aout->fifo[i_fifo].b_die = 0;
323
324             p_aout->fifo[i_fifo].b_stereo = p_fifo->b_stereo;
325             p_aout->fifo[i_fifo].l_rate = p_fifo->l_rate;
326
327             p_aout->fifo[i_fifo].buffer = p_fifo->buffer;
328
329             p_aout->fifo[i_fifo].l_unit = 0;
330             InitializeIncrement( &p_aout->fifo[i_fifo].unit_increment, p_fifo->l_rate, p_aout->dsp.l_rate );
331             p_aout->fifo[i_fifo].l_units = p_fifo->l_units;
332             break;
333
334         case AOUT_ADEC_MONO_FIFO:
335         case AOUT_ADEC_STEREO_FIFO:
336             p_aout->fifo[i_fifo].b_die = 0;
337
338             p_aout->fifo[i_fifo].b_stereo = p_fifo->b_stereo;
339             p_aout->fifo[i_fifo].l_rate = p_fifo->l_rate;
340
341             p_aout->fifo[i_fifo].l_frame_size = p_fifo->l_frame_size;
342             /* Allocate the memory needed to store the audio frames. As the
343              * fifo is a rotative fifo, we must be able to find out whether the
344              * fifo is full or empty, that's why we must in fact allocate memory
345              * for (AOUT_FIFO_SIZE+1) audio frames. */
346             if ( (p_aout->fifo[i_fifo].buffer = malloc( sizeof(s16)*(AOUT_FIFO_SIZE+1)*p_fifo->l_frame_size )) == NULL )
347             {
348                 intf_ErrMsg("aout error: not enough memory to create the frames buffer\n");
349                 p_aout->fifo[i_fifo].i_type = AOUT_EMPTY_FIFO;
350                 vlc_mutex_unlock( &p_aout->fifos_lock );
351                 return( NULL );
352             }
353
354             /* Allocate the memory needed to store the dates of the frames */
355             if ( (p_aout->fifo[i_fifo].date = (mtime_t *)malloc( sizeof(mtime_t)*(AOUT_FIFO_SIZE+1) )) == NULL )
356             {
357                 intf_ErrMsg("aout error: not enough memory to create the dates buffer\n");
358                 free( p_aout->fifo[i_fifo].buffer );
359                 p_aout->fifo[i_fifo].i_type = AOUT_EMPTY_FIFO;
360                 vlc_mutex_unlock( &p_aout->fifos_lock );
361                 return( NULL );
362             }
363
364             /* Set the fifo's buffer as empty (the first frame that is to be
365              * played is also the first frame that is not to be played) */
366             p_aout->fifo[i_fifo].l_start_frame = 0;
367             /* p_aout->fifo[i_fifo].l_next_frame = 0; */
368             p_aout->fifo[i_fifo].l_end_frame = 0;
369
370             /* Waiting for the audio decoder to compute enough frames to work
371              * out the fifo's current rate (as soon as the decoder has decoded
372              * enough frames, the members of the fifo structure that are not
373              * initialized now will be calculated) */
374             p_aout->fifo[i_fifo].b_start_frame = 0;
375             p_aout->fifo[i_fifo].b_next_frame = 0;
376             break;
377
378         default:
379             intf_ErrMsg("aout error: unknown fifo type (%i)\n", p_aout->fifo[i_fifo].i_type);
380             p_aout->fifo[i_fifo].i_type = AOUT_EMPTY_FIFO;
381             vlc_mutex_unlock( &p_aout->fifos_lock );
382             return( NULL );
383     }
384
385     /* Release the fifos lock */
386     vlc_mutex_unlock( &p_aout->fifos_lock );
387
388     /* Return the pointer to the fifo structure */
389     intf_DbgMsg("aout debug: audio output fifo (%p) allocated\n", &p_aout->fifo[i_fifo]);
390     return( &p_aout->fifo[i_fifo] );
391 }
392
393 /******************************************************************************
394  * aout_DestroyFifo
395  ******************************************************************************/
396 void aout_DestroyFifo( aout_fifo_t * p_fifo )
397 {
398     intf_DbgMsg("aout debug: requesting destruction of audio output fifo (%p)\n", p_fifo);
399     p_fifo->b_die = 1;
400 }
401
402 /* Here are the local macros */
403
404 #define UPDATE_INCREMENT( increment, integer ) \
405     if ( ((increment).l_remainder += (increment).l_euclidean_remainder) >= 0 ) \
406     { \
407         (integer) += (increment).l_euclidean_integer + 1; \
408         (increment).l_remainder -= (increment).l_euclidean_denominator; \
409     } \
410     else \
411     { \
412         (integer) += (increment).l_euclidean_integer; \
413     }
414
415 /* Following functions are local */
416
417 /******************************************************************************
418  * InitializeIncrement
419  ******************************************************************************/
420 static __inline__ void InitializeIncrement( aout_increment_t * p_increment, long l_numerator, long l_denominator )
421 {
422     p_increment->l_remainder = -l_denominator;
423
424     p_increment->l_euclidean_integer = 0;
425     while ( l_numerator >= l_denominator )
426     {
427         p_increment->l_euclidean_integer++;
428         l_numerator -= l_denominator;
429     }
430
431     p_increment->l_euclidean_remainder = l_numerator;
432
433     p_increment->l_euclidean_denominator = l_denominator;
434 }
435
436 /******************************************************************************
437  * NextFrame
438  ******************************************************************************/
439 static __inline__ int NextFrame( aout_thread_t * p_aout, aout_fifo_t * p_fifo, mtime_t aout_date )
440 {
441     long l_units, l_rate;
442
443     /* We take the lock */
444     vlc_mutex_lock( &p_fifo->data_lock );
445
446     /* Are we looking for a dated start frame ? */
447     if ( !p_fifo->b_start_frame )
448     {
449         while ( p_fifo->l_start_frame != p_fifo->l_end_frame )
450         {
451             if ( p_fifo->date[p_fifo->l_start_frame] != LAST_MDATE )
452             {
453                 p_fifo->b_start_frame = 1;
454                 p_fifo->l_next_frame = (p_fifo->l_start_frame + 1) & AOUT_FIFO_SIZE;
455                 p_fifo->l_unit = p_fifo->l_start_frame * (p_fifo->l_frame_size >> p_fifo->b_stereo);
456                 break;
457             }
458             p_fifo->l_start_frame = (p_fifo->l_start_frame + 1) & AOUT_FIFO_SIZE;
459         }
460         if ( p_fifo->l_start_frame == p_fifo->l_end_frame )
461         {
462             vlc_mutex_unlock( &p_fifo->data_lock );
463             return( -1 );
464         }
465     }
466
467     /* We are looking for the next dated frame */
468     while ( 1 )
469     {
470         while ( p_fifo->l_next_frame != p_fifo->l_end_frame )
471         {
472             if ( p_fifo->date[p_fifo->l_next_frame] != LAST_MDATE )
473             {
474                 p_fifo->b_next_frame = 1;
475                 break;
476             }
477             else
478             {
479                 p_fifo->l_next_frame = (p_fifo->l_next_frame + 1) & AOUT_FIFO_SIZE;
480             }
481         }
482
483         if ( p_fifo->b_next_frame == 1 )
484         {
485             break;
486         }
487         else
488         {
489             if ( (((p_fifo->l_end_frame + 1) - p_fifo->l_start_frame) & AOUT_FIFO_SIZE) == 0 )
490             {
491                 p_fifo->l_start_frame = 0;
492                 p_fifo->b_start_frame = 0;
493                 /* p_fifo->l_next_frame = 0; */
494                 /* p_fifo->b_next_frame = 0; */
495                 p_fifo->l_end_frame = 0;
496                 vlc_mutex_unlock( &p_fifo->data_lock );
497                 return( -1 );
498             }
499             else
500             {
501                 while ( p_fifo->l_next_frame == p_fifo->l_end_frame )
502                 {
503                     vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
504                 }
505             }
506         }
507     }
508
509     l_units = ((p_fifo->l_next_frame - p_fifo->l_start_frame) & AOUT_FIFO_SIZE) * (p_fifo->l_frame_size >> p_fifo->b_stereo);
510
511     l_rate = p_fifo->l_rate + ((aout_date - p_fifo->date[p_fifo->l_start_frame]) / 256);
512 //    fprintf( stderr, "aout debug: %lli (%li);\n", aout_date - p_fifo->date[p_fifo->l_start_frame], l_rate );
513
514     InitializeIncrement( &p_fifo->unit_increment, l_rate, p_aout->dsp.l_rate );
515
516     p_fifo->l_units = (((l_units - (p_fifo->l_unit -
517         (p_fifo->l_start_frame * (p_fifo->l_frame_size >> p_fifo->b_stereo))))
518         * p_aout->dsp.l_rate) / l_rate) + 1;
519
520     /* We release the lock before leaving */
521     vlc_mutex_unlock( &p_fifo->data_lock );
522     return( 0 );
523 }
524
525 void aout_Thread_S8_Mono( aout_thread_t * p_aout )
526 {
527 }
528
529 void aout_Thread_S8_Stereo( aout_thread_t * p_aout )
530 {
531 }
532
533 void aout_Thread_U8_Mono( aout_thread_t * p_aout )
534 {
535 }
536
537 void aout_Thread_U8_Stereo( aout_thread_t * p_aout )
538 {
539 }
540
541 void aout_Thread_S16_Mono( aout_thread_t * p_aout )
542 {
543 }
544
545 void aout_Thread_S16_Stereo( aout_thread_t * p_aout )
546 {
547     int i_fifo;
548     long l_buffer, l_buffer_limit;
549     long l_units, l_bytes;
550
551     intf_DbgMsg("adec debug: running audio output thread (%p) (pid == %i)\n", p_aout, getpid());
552
553     /* As the s32_buffer was created with calloc(), we don't have to set this
554      * memory to zero and we can immediately jump into the thread's loop */
555     while ( !p_aout->b_die )
556     {
557         vlc_mutex_lock( &p_aout->fifos_lock );
558         for ( i_fifo = 0; i_fifo < AOUT_MAX_FIFOS; i_fifo++ )
559         {
560             switch ( p_aout->fifo[i_fifo].i_type )
561             {
562                 case AOUT_EMPTY_FIFO:
563                     break;
564
565                 case AOUT_INTF_MONO_FIFO:
566                     if ( p_aout->fifo[i_fifo].l_units > p_aout->l_units )
567                     {
568                         l_buffer = 0;
569                         while ( l_buffer < (p_aout->l_units << 1) ) /* p_aout->dsp.b_stereo == 1 */
570                         {
571                             p_aout->s32_buffer[l_buffer++] +=
572                                 (s32)( ((s16 *)p_aout->fifo[i_fifo].buffer)[p_aout->fifo[i_fifo].l_unit] );
573                             p_aout->s32_buffer[l_buffer++] +=
574                                 (s32)( ((s16 *)p_aout->fifo[i_fifo].buffer)[p_aout->fifo[i_fifo].l_unit] );
575                             UPDATE_INCREMENT( p_aout->fifo[i_fifo].unit_increment, p_aout->fifo[i_fifo].l_unit )
576                         }
577                         p_aout->fifo[i_fifo].l_units -= p_aout->l_units;
578                     }
579                     else
580                     {
581                         l_buffer = 0;
582                         while ( l_buffer < (p_aout->fifo[i_fifo].l_units << 1) ) /* p_aout->dsp.b_stereo == 1 */
583                         {
584                             p_aout->s32_buffer[l_buffer++] +=
585                                 (s32)( ((s16 *)p_aout->fifo[i_fifo].buffer)[p_aout->fifo[i_fifo].l_unit] );
586                             p_aout->s32_buffer[l_buffer++] +=
587                                 (s32)( ((s16 *)p_aout->fifo[i_fifo].buffer)[p_aout->fifo[i_fifo].l_unit] );
588                             UPDATE_INCREMENT( p_aout->fifo[i_fifo].unit_increment, p_aout->fifo[i_fifo].l_unit )
589                         }
590                         free( p_aout->fifo[i_fifo].buffer ); /* !! */
591                         p_aout->fifo[i_fifo].i_type = AOUT_EMPTY_FIFO; /* !! */
592                         intf_DbgMsg("aout debug: audio output fifo (%p) destroyed\n", &p_aout->fifo[i_fifo]); /* !! */
593                     }
594                     break;
595
596                 case AOUT_INTF_STEREO_FIFO:
597                     if ( p_aout->fifo[i_fifo].l_units > p_aout->l_units )
598                     {
599                         l_buffer = 0;
600                         while ( l_buffer < (p_aout->l_units << 1) ) /* p_aout->dsp.b_stereo == 1 */
601                         {
602                             p_aout->s32_buffer[l_buffer++] +=
603                                 (s32)( ((s16 *)p_aout->fifo[i_fifo].buffer)[2*p_aout->fifo[i_fifo].l_unit] );
604                             p_aout->s32_buffer[l_buffer++] +=
605                                 (s32)( ((s16 *)p_aout->fifo[i_fifo].buffer)[2*p_aout->fifo[i_fifo].l_unit+1] );
606                             UPDATE_INCREMENT( p_aout->fifo[i_fifo].unit_increment, p_aout->fifo[i_fifo].l_unit )
607                         }
608                         p_aout->fifo[i_fifo].l_units -= p_aout->l_units;
609                     }
610                     else
611                     {
612                         l_buffer = 0;
613                         while ( l_buffer < (p_aout->fifo[i_fifo].l_units << 1) ) /* p_aout->dsp.b_stereo */
614                         {
615                             p_aout->s32_buffer[l_buffer++] +=
616                                 (s32)( ((s16 *)p_aout->fifo[i_fifo].buffer)[2*p_aout->fifo[i_fifo].l_unit] );
617                             p_aout->s32_buffer[l_buffer++] +=
618                                 (s32)( ((s16 *)p_aout->fifo[i_fifo].buffer)[2*p_aout->fifo[i_fifo].l_unit+1] );
619                             UPDATE_INCREMENT( p_aout->fifo[i_fifo].unit_increment, p_aout->fifo[i_fifo].l_unit )
620                         }
621                         free( p_aout->fifo[i_fifo].buffer ); /* !! */
622                         p_aout->fifo[i_fifo].i_type = AOUT_EMPTY_FIFO; /* !! */
623                         intf_DbgMsg("aout debug: audio output fifo (%p) destroyed\n", &p_aout->fifo[i_fifo]); /* !! */
624                     }
625                     break;
626
627                 case AOUT_ADEC_MONO_FIFO:
628                     if ( p_aout->fifo[i_fifo].b_die )
629                     {
630                         free( p_aout->fifo[i_fifo].buffer );
631                         free( p_aout->fifo[i_fifo].date );
632                         p_aout->fifo[i_fifo].i_type = AOUT_EMPTY_FIFO; /* !! */
633                         intf_DbgMsg("aout debug: audio output fifo (%p) destroyed\n", &p_aout->fifo[i_fifo]);
634                         continue;
635                     }
636
637                     l_units = p_aout->l_units;
638                     l_buffer = 0;
639                     while ( l_units > 0 )
640                     {
641                         if ( !p_aout->fifo[i_fifo].b_next_frame )
642                         {
643                             if ( NextFrame(p_aout, &p_aout->fifo[i_fifo], p_aout->date + ((((mtime_t)(l_buffer >> 1)) * 1000000) / ((mtime_t)p_aout->dsp.l_rate))) )
644                             {
645                                 break;
646                             }
647                         }
648
649                         if ( p_aout->fifo[i_fifo].l_units > l_units )
650                         {
651                             l_buffer_limit = p_aout->l_units << 1; /* p_aout->dsp.b_stereo == 1 */
652                             while ( l_buffer < l_buffer_limit )
653                             {
654                                 p_aout->s32_buffer[l_buffer++] +=
655                                     (s32)( ((s16 *)p_aout->fifo[i_fifo].buffer)[p_aout->fifo[i_fifo].l_unit] );
656                                 p_aout->s32_buffer[l_buffer++] +=
657                                     (s32)( ((s16 *)p_aout->fifo[i_fifo].buffer)[p_aout->fifo[i_fifo].l_unit] );
658
659                                 UPDATE_INCREMENT( p_aout->fifo[i_fifo].unit_increment, p_aout->fifo[i_fifo].l_unit )
660                                 if ( p_aout->fifo[i_fifo].l_unit >= /* p_aout->fifo[i_fifo].b_stereo == 0 */
661                                      ((AOUT_FIFO_SIZE + 1) * (p_aout->fifo[i_fifo].l_frame_size >> 0)) )
662                                 {
663                                     p_aout->fifo[i_fifo].l_unit -= /* p_aout->fifo[i_fifo].b_stereo == 0 */
664                                         ((AOUT_FIFO_SIZE + 1) * (p_aout->fifo[i_fifo].l_frame_size >> 0));
665                                 }
666                             }
667                             p_aout->fifo[i_fifo].l_units -= l_units;
668                             break;
669                         }
670                         else
671                         {
672                             l_buffer_limit = l_buffer + (p_aout->fifo[i_fifo].l_units << 1);
673                             /* p_aout->dsp.b_stereo == 1 */
674                             while ( l_buffer < l_buffer_limit )
675                             {
676                                 p_aout->s32_buffer[l_buffer++] +=
677                                     (s32)( ((s16 *)p_aout->fifo[i_fifo].buffer)[p_aout->fifo[i_fifo].l_unit] );
678                                 p_aout->s32_buffer[l_buffer++] +=
679                                     (s32)( ((s16 *)p_aout->fifo[i_fifo].buffer)[p_aout->fifo[i_fifo].l_unit] );
680
681                                 UPDATE_INCREMENT( p_aout->fifo[i_fifo].unit_increment, p_aout->fifo[i_fifo].l_unit )
682                                 if ( p_aout->fifo[i_fifo].l_unit >= /* p_aout->fifo[i_fifo].b_stereo == 0 */
683                                      ((AOUT_FIFO_SIZE + 1) * (p_aout->fifo[i_fifo].l_frame_size >> 0)) )
684                                 {
685                                     p_aout->fifo[i_fifo].l_unit -= /* p_aout->fifo[i_fifo].b_stereo == 0 */
686                                         ((AOUT_FIFO_SIZE + 1) * (p_aout->fifo[i_fifo].l_frame_size >> 0));
687                                 }
688                             }
689                             l_units -= p_aout->fifo[i_fifo].l_units;
690
691                             vlc_mutex_lock( &p_aout->fifo[i_fifo].data_lock );
692                             p_aout->fifo[i_fifo].l_start_frame = p_aout->fifo[i_fifo].l_next_frame;
693                             vlc_cond_signal( &p_aout->fifo[i_fifo].data_wait );
694                             vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
695
696                             /* p_aout->fifo[i_fifo].b_start_frame = 1; */
697                             p_aout->fifo[i_fifo].l_next_frame += 1;
698                             p_aout->fifo[i_fifo].l_next_frame &= AOUT_FIFO_SIZE;
699                             p_aout->fifo[i_fifo].b_next_frame = 0;
700                         }
701                     }
702                     break;
703
704                 case AOUT_ADEC_STEREO_FIFO:
705                     if ( p_aout->fifo[i_fifo].b_die )
706                     {
707                         free( p_aout->fifo[i_fifo].buffer );
708                         free( p_aout->fifo[i_fifo].date );
709                         p_aout->fifo[i_fifo].i_type = AOUT_EMPTY_FIFO; /* !! */
710                         intf_DbgMsg("aout debug: audio output fifo (%p) destroyed\n", &p_aout->fifo[i_fifo]);
711                         continue;
712                     }
713
714                     l_units = p_aout->l_units;
715                     l_buffer = 0;
716                     while ( l_units > 0 )
717                     {
718                         if ( !p_aout->fifo[i_fifo].b_next_frame )
719                         {
720                             if ( NextFrame(p_aout, &p_aout->fifo[i_fifo], p_aout->date + ((((mtime_t)(l_buffer >> 1)) * 1000000) / ((mtime_t)p_aout->dsp.l_rate))) )
721                             {
722                                 break;
723                             }
724                         }
725
726                         if ( p_aout->fifo[i_fifo].l_units > l_units )
727                         {
728                             l_buffer_limit = p_aout->l_units << 1; /* p_aout->dsp.b_stereo == 1 */
729                             while ( l_buffer < l_buffer_limit )
730                             {
731                                 p_aout->s32_buffer[l_buffer++] +=
732                                     (s32)( ((s16 *)p_aout->fifo[i_fifo].buffer)[2*p_aout->fifo[i_fifo].l_unit] );
733                                 p_aout->s32_buffer[l_buffer++] +=
734                                     (s32)( ((s16 *)p_aout->fifo[i_fifo].buffer)[2*p_aout->fifo[i_fifo].l_unit+1] );
735
736                                 UPDATE_INCREMENT( p_aout->fifo[i_fifo].unit_increment, p_aout->fifo[i_fifo].l_unit )
737                                 if ( p_aout->fifo[i_fifo].l_unit >= /* p_aout->fifo[i_fifo].b_stereo == 1 */
738                                      ((AOUT_FIFO_SIZE + 1) * (p_aout->fifo[i_fifo].l_frame_size >> 1)) )
739                                 {
740                                     p_aout->fifo[i_fifo].l_unit -= /* p_aout->fifo[i_fifo].b_stereo == 1 */
741                                         ((AOUT_FIFO_SIZE + 1) * (p_aout->fifo[i_fifo].l_frame_size >> 1));
742                                 }
743                             }
744                             p_aout->fifo[i_fifo].l_units -= l_units;
745                             break;
746                         }
747                         else
748                         {
749                             l_buffer_limit = l_buffer + (p_aout->fifo[i_fifo].l_units << 1);
750                             /* p_aout->dsp.b_stereo == 1 */
751                             while ( l_buffer < l_buffer_limit )
752                             {
753                                 p_aout->s32_buffer[l_buffer++] +=
754                                     (s32)( ((s16 *)p_aout->fifo[i_fifo].buffer)[2*p_aout->fifo[i_fifo].l_unit] );
755                                 p_aout->s32_buffer[l_buffer++] +=
756                                     (s32)( ((s16 *)p_aout->fifo[i_fifo].buffer)[2*p_aout->fifo[i_fifo].l_unit+1] );
757
758                                 UPDATE_INCREMENT( p_aout->fifo[i_fifo].unit_increment, p_aout->fifo[i_fifo].l_unit )
759                                 if ( p_aout->fifo[i_fifo].l_unit >= /* p_aout->fifo[i_fifo].b_stereo == 1 */
760                                      ((AOUT_FIFO_SIZE + 1) * (p_aout->fifo[i_fifo].l_frame_size >> 1)) )
761                                 {
762                                     p_aout->fifo[i_fifo].l_unit -= /* p_aout->fifo[i_fifo].b_stereo == 1 */
763                                         ((AOUT_FIFO_SIZE + 1) * (p_aout->fifo[i_fifo].l_frame_size >> 1));
764                                 }
765                             }
766                             l_units -= p_aout->fifo[i_fifo].l_units;
767
768                             vlc_mutex_lock( &p_aout->fifo[i_fifo].data_lock );
769                             p_aout->fifo[i_fifo].l_start_frame = p_aout->fifo[i_fifo].l_next_frame;
770                             vlc_cond_signal( &p_aout->fifo[i_fifo].data_wait );
771                             vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
772
773                             /* p_aout->fifo[i_fifo].b_start_frame = 1; */
774                             p_aout->fifo[i_fifo].l_next_frame += 1;
775                             p_aout->fifo[i_fifo].l_next_frame &= AOUT_FIFO_SIZE;
776                             p_aout->fifo[i_fifo].b_next_frame = 0;
777                         }
778                     }
779                     break;
780
781                 default:
782                     intf_DbgMsg("aout debug: unknown fifo type (%i)\n", p_aout->fifo[i_fifo].i_type);
783                     break;
784             }
785         }
786         vlc_mutex_unlock( &p_aout->fifos_lock );
787
788         l_buffer_limit = p_aout->l_units << 1; /* p_aout->dsp.b_stereo == 1 */
789
790         for ( l_buffer = 0; l_buffer < l_buffer_limit; l_buffer++ )
791         {
792             ((s16 *)p_aout->buffer)[l_buffer] = (s16)( p_aout->s32_buffer[l_buffer] / AOUT_MAX_FIFOS );
793             p_aout->s32_buffer[l_buffer] = 0;
794         }
795
796         aout_dspGetBufInfo( &p_aout->dsp );
797         l_bytes = (p_aout->dsp.buf_info.fragstotal * p_aout->dsp.buf_info.fragsize) - p_aout->dsp.buf_info.bytes;
798         p_aout->date = mdate() + ((((mtime_t)(l_bytes / 4)) * 1000000) / ((mtime_t)p_aout->dsp.l_rate)); /* sizeof(s16) << p_aout->dsp.b_stereo == 4 */
799         aout_dspPlaySamples( &p_aout->dsp, (byte_t *)p_aout->buffer, l_buffer_limit * sizeof(s16) );
800         if ( l_bytes > (l_buffer_limit * sizeof(s16)) )
801         {
802             msleep( p_aout->l_msleep );
803         }
804     }
805
806     vlc_mutex_lock( &p_aout->fifos_lock );
807     for ( i_fifo = 0; i_fifo < AOUT_MAX_FIFOS; i_fifo++ )
808     {
809         switch ( p_aout->fifo[i_fifo].i_type )
810         {
811             case AOUT_EMPTY_FIFO:
812                 break;
813
814             case AOUT_INTF_MONO_FIFO:
815             case AOUT_INTF_STEREO_FIFO:
816                 free( p_aout->fifo[i_fifo].buffer ); /* !! */
817                 p_aout->fifo[i_fifo].i_type = AOUT_EMPTY_FIFO; /* !! */
818                 intf_DbgMsg("aout debug: audio output fifo (%p) destroyed\n", &p_aout->fifo[i_fifo]);
819                 break;
820
821             case AOUT_ADEC_MONO_FIFO:
822             case AOUT_ADEC_STEREO_FIFO:
823                 free( p_aout->fifo[i_fifo].buffer );
824                 free( p_aout->fifo[i_fifo].date );
825                 p_aout->fifo[i_fifo].i_type = AOUT_EMPTY_FIFO; /* !! */
826                 intf_DbgMsg("aout debug: audio output fifo (%p) destroyed\n", &p_aout->fifo[i_fifo]);
827                 break;
828
829             default:
830                 break;
831         }
832     }
833     vlc_mutex_unlock( &p_aout->fifos_lock );
834 }
835
836 void aout_Thread_U16_Mono( aout_thread_t * p_aout )
837 {
838 }
839
840 void aout_Thread_U16_Stereo( aout_thread_t * p_aout )
841 {
842 }