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