]> git.sesse.net Git - vlc/blob - src/audio_output/common.c
libvlc: disable audio mute on VolumeUp/Down
[vlc] / src / audio_output / common.c
1 /*****************************************************************************
2  * common.c : audio output management of common data structures
3  *****************************************************************************
4  * Copyright (C) 2002-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <assert.h>
32
33 #include <vlc_common.h>
34 #include <vlc_aout.h>
35 #include "aout_internal.h"
36 #include "libvlc.h"
37
38 /*
39  * Instances management (internal and external)
40  */
41
42 #define AOUT_ASSERT_FIFO_LOCKED aout_assert_fifo_locked(p_aout, p_fifo)
43 static inline void aout_assert_fifo_locked( aout_instance_t * p_aout, aout_fifo_t * p_fifo )
44 {
45 #ifndef NDEBUG
46     if( !p_aout )
47         return;
48
49     if( p_fifo == &p_aout->output.fifo )
50         vlc_assert_locked( &p_aout->output_fifo_lock );
51     else
52     {
53         int i;
54         for( i = 0; i < p_aout->i_nb_inputs; i++ )
55         {
56             if( p_fifo == &p_aout->pp_inputs[i]->mixer.fifo)
57             {
58                 vlc_assert_locked( &p_aout->input_fifos_lock );
59                 break;
60             }
61         }
62         if( i == p_aout->i_nb_inputs )
63             vlc_assert_locked( &p_aout->mixer_lock );
64     }
65 #else
66     (void)p_aout;
67     (void)p_fifo;
68 #endif
69 }
70
71 /* Local functions */
72 static void aout_Destructor( vlc_object_t * p_this );
73
74 /*****************************************************************************
75  * aout_New: initialize aout structure
76  *****************************************************************************/
77 aout_instance_t * __aout_New( vlc_object_t * p_parent )
78 {
79     aout_instance_t * p_aout;
80
81     /* Allocate descriptor. */
82     p_aout = vlc_object_create( p_parent, VLC_OBJECT_AOUT );
83     if( p_aout == NULL )
84     {
85         return NULL;
86     }
87
88     /* Initialize members. */
89     vlc_mutex_init( &p_aout->input_fifos_lock );
90     vlc_mutex_init( &p_aout->mixer_lock );
91     vlc_mutex_init( &p_aout->output_fifo_lock );
92     p_aout->i_nb_inputs = 0;
93     p_aout->mixer_multiplier = 1.0;
94     p_aout->p_mixer = NULL;
95     p_aout->output.b_error = 1;
96     p_aout->output.b_starving = 1;
97
98     var_Create( p_aout, "intf-change", VLC_VAR_BOOL );
99     var_SetBool( p_aout, "intf-change", true );
100
101     vlc_object_set_destructor( p_aout, aout_Destructor );
102
103     return p_aout;
104 }
105
106 /*****************************************************************************
107  * aout_Destructor: destroy aout structure
108  *****************************************************************************/
109 static void aout_Destructor( vlc_object_t * p_this )
110 {
111     aout_instance_t * p_aout = (aout_instance_t *)p_this;
112     vlc_mutex_destroy( &p_aout->input_fifos_lock );
113     vlc_mutex_destroy( &p_aout->mixer_lock );
114     vlc_mutex_destroy( &p_aout->output_fifo_lock );
115 }
116
117 /* Lock ordering rules:
118  *
119  *            Mixer Input IFIFO OFIFO (< Inner lock)
120  * Mixer       No!   Yes   Yes   Yes
121  * Input       No!   No!   Yes   Yes
122  * In FIFOs    No!   No!   No!   Yes
123  * Out FIFOs   No!   No!   No!   No!
124  * (^ Outer lock)
125  */
126 #ifdef AOUT_DEBUG
127 /* Lock debugging */
128 static __thread unsigned aout_locks = 0;
129
130 void aout_lock (unsigned i)
131 {
132     unsigned allowed;
133     switch (i)
134     {
135         case MIXER_LOCK:
136             allowed = 0;
137             break;
138         case INPUT_LOCK:
139             allowed = MIXER_LOCK;
140             break;
141         case INPUT_FIFO_LOCK:
142             allowed = MIXER_LOCK|INPUT_LOCK;
143             break;
144         case OUTPUT_FIFO_LOCK:
145             allowed = MIXER_LOCK|INPUT_LOCK|INPUT_FIFO_LOCK;
146             break;
147         default:
148             abort ();
149     }
150
151     if (aout_locks & ~allowed)
152     {
153         fprintf (stderr, "Illegal audio lock transition (%x -> %x)\n",
154                  aout_locks, aout_locks|i);
155         vlc_backtrace ();
156         abort ();
157     }
158     aout_locks |= i;
159 }
160
161 void aout_unlock (unsigned i)
162 {
163     assert (aout_locks & i);
164     aout_locks &= ~i;
165 }
166 #endif
167
168 /*
169  * Formats management (internal and external)
170  */
171
172 /*****************************************************************************
173  * aout_FormatNbChannels : return the number of channels
174  *****************************************************************************/
175 unsigned int aout_FormatNbChannels( const audio_sample_format_t * p_format )
176 {
177     static const uint32_t pi_channels[] =
178         { AOUT_CHAN_CENTER, AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
179           AOUT_CHAN_REARCENTER, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
180           AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT, AOUT_CHAN_LFE };
181     unsigned int i_nb = 0, i;
182
183     for ( i = 0; i < sizeof(pi_channels)/sizeof(uint32_t); i++ )
184     {
185         if ( p_format->i_physical_channels & pi_channels[i] ) i_nb++;
186     }
187
188     return i_nb;
189 }
190
191 /*****************************************************************************
192  * aout_BitsPerSample : get the number of bits per sample
193  *****************************************************************************/
194 unsigned int aout_BitsPerSample( vlc_fourcc_t i_format )
195 {
196     switch( i_format )
197     {
198     case VLC_CODEC_U8:
199     case VLC_CODEC_S8:
200         return 8;
201
202     case VLC_CODEC_U16L:
203     case VLC_CODEC_S16L:
204     case VLC_CODEC_U16B:
205     case VLC_CODEC_S16B:
206         return 16;
207
208     case VLC_CODEC_U24L:
209     case VLC_CODEC_S24L:
210     case VLC_CODEC_U24B:
211     case VLC_CODEC_S24B:
212         return 24;
213
214     case VLC_CODEC_S32L:
215     case VLC_CODEC_S32B:
216     case VLC_CODEC_FL32:
217     case VLC_CODEC_FI32:
218         return 32;
219
220     case VLC_CODEC_FL64:
221         return 64;
222
223     default:
224         /* For these formats the caller has to indicate the parameters
225          * by hand. */
226         return 0;
227     }
228 }
229
230 /*****************************************************************************
231  * aout_FormatPrepare : compute the number of bytes per frame & frame length
232  *****************************************************************************/
233 void aout_FormatPrepare( audio_sample_format_t * p_format )
234 {
235     p_format->i_bitspersample = aout_BitsPerSample( p_format->i_format );
236     if( p_format->i_bitspersample > 0 )
237     {
238         p_format->i_bytes_per_frame = ( p_format->i_bitspersample / 8 )
239                                     * aout_FormatNbChannels( p_format );
240         p_format->i_frame_length = 1;
241     }
242 }
243
244 /*****************************************************************************
245  * aout_FormatPrintChannels : print a channel in a human-readable form
246  *****************************************************************************/
247 const char * aout_FormatPrintChannels( const audio_sample_format_t * p_format )
248 {
249     switch ( p_format->i_physical_channels & AOUT_CHAN_PHYSMASK )
250     {
251     case AOUT_CHAN_LEFT:
252     case AOUT_CHAN_RIGHT:
253     case AOUT_CHAN_CENTER:
254         if ( (p_format->i_original_channels & AOUT_CHAN_CENTER)
255               || (p_format->i_original_channels
256                    & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
257             return "Mono";
258         else if ( p_format->i_original_channels & AOUT_CHAN_LEFT )
259             return "Left";
260         return "Right";
261     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT:
262         if ( p_format->i_original_channels & AOUT_CHAN_REVERSESTEREO )
263         {
264             if ( p_format->i_original_channels & AOUT_CHAN_DOLBYSTEREO )
265                 return "Dolby/Reverse";
266             return "Stereo/Reverse";
267         }
268         else
269         {
270             if ( p_format->i_original_channels & AOUT_CHAN_DOLBYSTEREO )
271                 return "Dolby";
272             else if ( p_format->i_original_channels & AOUT_CHAN_DUALMONO )
273                 return "Dual-mono";
274             else if ( p_format->i_original_channels == AOUT_CHAN_CENTER )
275                 return "Stereo/Mono";
276             else if ( !(p_format->i_original_channels & AOUT_CHAN_RIGHT) )
277                 return "Stereo/Left";
278             else if ( !(p_format->i_original_channels & AOUT_CHAN_LEFT) )
279                 return "Stereo/Right";
280             return "Stereo";
281         }
282     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER:
283         return "3F";
284     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARCENTER:
285         return "2F1R";
286     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
287           | AOUT_CHAN_REARCENTER:
288         return "3F1R";
289     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
290           | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT:
291         return "2F2R";
292     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
293           | AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT:
294         return "2F2M";
295     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
296           | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT:
297         return "3F2R";
298     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
299           | AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT:
300         return "3F2M";
301
302     case AOUT_CHAN_CENTER | AOUT_CHAN_LFE:
303         if ( (p_format->i_original_channels & AOUT_CHAN_CENTER)
304               || (p_format->i_original_channels
305                    & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
306             return "Mono/LFE";
307         else if ( p_format->i_original_channels & AOUT_CHAN_LEFT )
308             return "Left/LFE";
309         return "Right/LFE";
310     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_LFE:
311         if ( p_format->i_original_channels & AOUT_CHAN_DOLBYSTEREO )
312             return "Dolby/LFE";
313         else if ( p_format->i_original_channels & AOUT_CHAN_DUALMONO )
314             return "Dual-mono/LFE";
315         else if ( p_format->i_original_channels == AOUT_CHAN_CENTER )
316             return "Mono/LFE";
317         else if ( !(p_format->i_original_channels & AOUT_CHAN_RIGHT) )
318             return "Stereo/Left/LFE";
319         else if ( !(p_format->i_original_channels & AOUT_CHAN_LEFT) )
320             return "Stereo/Right/LFE";
321          return "Stereo/LFE";
322     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_LFE:
323         return "3F/LFE";
324     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARCENTER
325           | AOUT_CHAN_LFE:
326         return "2F1R/LFE";
327     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
328           | AOUT_CHAN_REARCENTER | AOUT_CHAN_LFE:
329         return "3F1R/LFE";
330     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
331           | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE:
332         return "2F2R/LFE";
333     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
334           | AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_LFE:
335         return "2F2M/LFE";
336     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
337           | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE:
338         return "3F2R/LFE";
339     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
340           | AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_LFE:
341         return "3F2M/LFE";
342     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
343           | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_MIDDLELEFT
344           | AOUT_CHAN_MIDDLERIGHT:
345         return "3F2M2R";
346     case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
347           | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_MIDDLELEFT
348           | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_LFE:
349         return "3F2M2R/LFE";
350     }
351
352     return "ERROR";
353 }
354
355 /*****************************************************************************
356  * aout_FormatPrint : print a format in a human-readable form
357  *****************************************************************************/
358 void aout_FormatPrint( aout_instance_t * p_aout, const char * psz_text,
359                        const audio_sample_format_t * p_format )
360 {
361     msg_Dbg( p_aout, "%s '%4.4s' %d Hz %s frame=%d samples/%d bytes", psz_text,
362              (char *)&p_format->i_format, p_format->i_rate,
363              aout_FormatPrintChannels( p_format ),
364              p_format->i_frame_length, p_format->i_bytes_per_frame );
365 }
366
367 /*****************************************************************************
368  * aout_FormatsPrint : print two formats in a human-readable form
369  *****************************************************************************/
370 void aout_FormatsPrint( aout_instance_t * p_aout, const char * psz_text,
371                         const audio_sample_format_t * p_format1,
372                         const audio_sample_format_t * p_format2 )
373 {
374     msg_Dbg( p_aout, "%s '%4.4s'->'%4.4s' %d Hz->%d Hz %s->%s",
375              psz_text,
376              (char *)&p_format1->i_format, (char *)&p_format2->i_format,
377              p_format1->i_rate, p_format2->i_rate,
378              aout_FormatPrintChannels( p_format1 ),
379              aout_FormatPrintChannels( p_format2 ) );
380 }
381
382
383 /*
384  * FIFO management (internal) - please understand that solving race conditions
385  * is _your_ job, ie. in the audio output you should own the mixer lock
386  * before calling any of these functions.
387  */
388
389 /*****************************************************************************
390  * aout_FifoInit : initialize the members of a FIFO
391  *****************************************************************************/
392 void aout_FifoInit( aout_instance_t * p_aout, aout_fifo_t * p_fifo,
393                     uint32_t i_rate )
394 {
395     AOUT_ASSERT_FIFO_LOCKED;
396
397     if( i_rate == 0 )
398     {
399         msg_Err( p_aout, "initialising fifo with zero divider" );
400     }
401
402     p_fifo->p_first = NULL;
403     p_fifo->pp_last = &p_fifo->p_first;
404     date_Init( &p_fifo->end_date, i_rate, 1 );
405 }
406
407 /*****************************************************************************
408  * aout_FifoPush : push a packet into the FIFO
409  *****************************************************************************/
410 void aout_FifoPush( aout_instance_t * p_aout, aout_fifo_t * p_fifo,
411                     aout_buffer_t * p_buffer )
412 {
413     (void)p_aout;
414     AOUT_ASSERT_FIFO_LOCKED;
415
416     *p_fifo->pp_last = p_buffer;
417     p_fifo->pp_last = &p_buffer->p_next;
418     *p_fifo->pp_last = NULL;
419     /* Enforce the continuity of the stream. */
420     if ( date_Get( &p_fifo->end_date ) )
421     {
422         p_buffer->i_pts = date_Get( &p_fifo->end_date );
423         p_buffer->i_length = date_Increment( &p_fifo->end_date,
424                                              p_buffer->i_nb_samples );
425         p_buffer->i_length -= p_buffer->i_pts;
426     }
427     else
428     {
429         date_Set( &p_fifo->end_date, p_buffer->i_pts + p_buffer->i_length );
430     }
431 }
432
433 /*****************************************************************************
434  * aout_FifoSet : set end_date and trash all buffers (because they aren't
435  * properly dated)
436  *****************************************************************************/
437 void aout_FifoSet( aout_instance_t * p_aout, aout_fifo_t * p_fifo,
438                    mtime_t date )
439 {
440     aout_buffer_t * p_buffer;
441     (void)p_aout;
442     AOUT_ASSERT_FIFO_LOCKED;
443
444     date_Set( &p_fifo->end_date, date );
445     p_buffer = p_fifo->p_first;
446     while ( p_buffer != NULL )
447     {
448         aout_buffer_t * p_next = p_buffer->p_next;
449         aout_BufferFree( p_buffer );
450         p_buffer = p_next;
451     }
452     p_fifo->p_first = NULL;
453     p_fifo->pp_last = &p_fifo->p_first;
454 }
455
456 /*****************************************************************************
457  * aout_FifoMoveDates : Move forwards or backwards all dates in the FIFO
458  *****************************************************************************/
459 void aout_FifoMoveDates( aout_instance_t * p_aout, aout_fifo_t * p_fifo,
460                          mtime_t difference )
461 {
462     aout_buffer_t * p_buffer;
463     (void)p_aout;
464     AOUT_ASSERT_FIFO_LOCKED;
465
466     date_Move( &p_fifo->end_date, difference );
467     p_buffer = p_fifo->p_first;
468     while ( p_buffer != NULL )
469     {
470         p_buffer->i_pts += difference;
471         p_buffer = p_buffer->p_next;
472     }
473 }
474
475 /*****************************************************************************
476  * aout_FifoNextStart : return the current end_date
477  *****************************************************************************/
478 mtime_t aout_FifoNextStart( aout_instance_t * p_aout, aout_fifo_t * p_fifo )
479 {
480     (void)p_aout;
481     AOUT_ASSERT_FIFO_LOCKED;
482     return date_Get( &p_fifo->end_date );
483 }
484
485 /*****************************************************************************
486  * aout_FifoFirstDate : return the playing date of the first buffer in the
487  * FIFO
488  *****************************************************************************/
489 mtime_t aout_FifoFirstDate( aout_instance_t * p_aout, aout_fifo_t * p_fifo )
490 {
491     (void)p_aout;
492     AOUT_ASSERT_FIFO_LOCKED;
493     return p_fifo->p_first ?  p_fifo->p_first->i_pts : 0;
494 }
495
496 /*****************************************************************************
497  * aout_FifoPop : get the next buffer out of the FIFO
498  *****************************************************************************/
499 aout_buffer_t * aout_FifoPop( aout_instance_t * p_aout, aout_fifo_t * p_fifo )
500 {
501     aout_buffer_t * p_buffer;
502     (void)p_aout;
503     AOUT_ASSERT_FIFO_LOCKED;
504
505     p_buffer = p_fifo->p_first;
506     if ( p_buffer == NULL ) return NULL;
507     p_fifo->p_first = p_buffer->p_next;
508     if ( p_fifo->p_first == NULL )
509     {
510         p_fifo->pp_last = &p_fifo->p_first;
511     }
512
513     return p_buffer;
514 }
515
516 /*****************************************************************************
517  * aout_FifoDestroy : destroy a FIFO and its buffers
518  *****************************************************************************/
519 void aout_FifoDestroy( aout_instance_t * p_aout, aout_fifo_t * p_fifo )
520 {
521     aout_buffer_t * p_buffer;
522     (void)p_aout;
523     AOUT_ASSERT_FIFO_LOCKED;
524
525     p_buffer = p_fifo->p_first;
526     while ( p_buffer != NULL )
527     {
528         aout_buffer_t * p_next = p_buffer->p_next;
529         aout_BufferFree( p_buffer );
530         p_buffer = p_next;
531     }
532
533     p_fifo->p_first = NULL;
534     p_fifo->pp_last = &p_fifo->p_first;
535 }
536
537 /*****************************************************************************
538  * aout_CheckChannelReorder : Check if we need to do some channel re-ordering
539  *****************************************************************************/
540 int aout_CheckChannelReorder( const uint32_t *pi_chan_order_in,
541                               const uint32_t *pi_chan_order_out,
542                               uint32_t i_channel_mask,
543                               int i_channels, int *pi_chan_table )
544 {
545     bool b_chan_reorder = false;
546     int i, j, k, l;
547
548     if( i_channels > AOUT_CHAN_MAX )
549         return false;
550
551     if( pi_chan_order_in == NULL )
552         pi_chan_order_in = pi_vlc_chan_order_wg4;
553     if( pi_chan_order_out == NULL )
554         pi_chan_order_out = pi_vlc_chan_order_wg4;
555
556     for( i = 0, j = 0; pi_chan_order_in[i]; i++ )
557     {
558         if( !(i_channel_mask & pi_chan_order_in[i]) ) continue;
559
560         for( k = 0, l = 0; pi_chan_order_in[i] != pi_chan_order_out[k]; k++ )
561         {
562             if( i_channel_mask & pi_chan_order_out[k] ) l++;
563         }
564
565         pi_chan_table[j++] = l;
566     }
567
568     for( i = 0; i < i_channels; i++ )
569     {
570         if( pi_chan_table[i] != i ) b_chan_reorder = true;
571     }
572
573     return b_chan_reorder;
574 }
575
576 /*****************************************************************************
577  * aout_ChannelReorder :
578  *****************************************************************************/
579 void aout_ChannelReorder( uint8_t *p_buf, int i_buffer,
580                           int i_channels, const int *pi_chan_table,
581                           int i_bits_per_sample )
582 {
583     uint8_t p_tmp[AOUT_CHAN_MAX * 4];
584     int i, j;
585
586     if( i_bits_per_sample == 8 )
587     {
588         for( i = 0; i < i_buffer / i_channels; i++ )
589         {
590             for( j = 0; j < i_channels; j++ )
591             {
592                 p_tmp[pi_chan_table[j]] = p_buf[j];
593             }
594
595             memcpy( p_buf, p_tmp, i_channels );
596             p_buf += i_channels;
597         }
598     }
599     else if( i_bits_per_sample == 16 )
600     {
601         for( i = 0; i < i_buffer / i_channels / 2; i++ )
602         {
603             for( j = 0; j < i_channels; j++ )
604             {
605                 p_tmp[2 * pi_chan_table[j]]     = p_buf[2 * j];
606                 p_tmp[2 * pi_chan_table[j] + 1] = p_buf[2 * j + 1];
607             }
608
609             memcpy( p_buf, p_tmp, 2 * i_channels );
610             p_buf += 2 * i_channels;
611         }
612     }
613     else if( i_bits_per_sample == 24 )
614     {
615         for( i = 0; i < i_buffer / i_channels / 3; i++ )
616         {
617             for( j = 0; j < i_channels; j++ )
618             {
619                 p_tmp[3 * pi_chan_table[j]]     = p_buf[3 * j];
620                 p_tmp[3 * pi_chan_table[j] + 1] = p_buf[3 * j + 1];
621                 p_tmp[3 * pi_chan_table[j] + 2] = p_buf[3 * j + 2];
622             }
623
624             memcpy( p_buf, p_tmp, 3 * i_channels );
625             p_buf += 3 * i_channels;
626         }
627     }
628     else if( i_bits_per_sample == 32 )
629     {
630         for( i = 0; i < i_buffer / i_channels / 4; i++ )
631         {
632             for( j = 0; j < i_channels; j++ )
633             {
634                 p_tmp[4 * pi_chan_table[j]]     = p_buf[4 * j];
635                 p_tmp[4 * pi_chan_table[j] + 1] = p_buf[4 * j + 1];
636                 p_tmp[4 * pi_chan_table[j] + 2] = p_buf[4 * j + 2];
637                 p_tmp[4 * pi_chan_table[j] + 3] = p_buf[4 * j + 3];
638             }
639
640             memcpy( p_buf, p_tmp, 4 * i_channels );
641             p_buf += 4 * i_channels;
642         }
643     }
644 }
645
646 /*****************************************************************************
647  * aout_ChannelExtract:
648  *****************************************************************************/
649 static inline void ExtractChannel( uint8_t *pi_dst, int i_dst_channels,
650                                    const uint8_t *pi_src, int i_src_channels,
651                                    int i_sample_count,
652                                    const int *pi_selection, int i_bytes )
653 {
654     for( int i = 0; i < i_sample_count; i++ )
655     {
656         for( int j = 0; j < i_dst_channels; j++ )
657             memcpy( &pi_dst[j * i_bytes], &pi_src[pi_selection[j] * i_bytes], i_bytes );
658         pi_dst += i_dst_channels * i_bytes;
659         pi_src += i_src_channels * i_bytes;
660     }
661 }
662
663 void aout_ChannelExtract( void *p_dst, int i_dst_channels,
664                           const void *p_src, int i_src_channels,
665                           int i_sample_count, const int *pi_selection, int i_bits_per_sample )
666 {
667     /* It does not work in place */
668     assert( p_dst != p_src );
669
670     /* Force the compiler to inline for the specific cases so it can optimize */
671     if( i_bits_per_sample == 8 )
672         ExtractChannel( p_dst, i_dst_channels, p_src, i_src_channels, i_sample_count, pi_selection, 1 );
673     else  if( i_bits_per_sample == 16 )
674         ExtractChannel( p_dst, i_dst_channels, p_src, i_src_channels, i_sample_count, pi_selection, 2 );
675     else  if( i_bits_per_sample == 24 )
676         ExtractChannel( p_dst, i_dst_channels, p_src, i_src_channels, i_sample_count, pi_selection, 3 );
677     else  if( i_bits_per_sample == 32 )
678         ExtractChannel( p_dst, i_dst_channels, p_src, i_src_channels, i_sample_count, pi_selection, 4 );
679     else  if( i_bits_per_sample == 64 )
680         ExtractChannel( p_dst, i_dst_channels, p_src, i_src_channels, i_sample_count, pi_selection, 8 );
681 }
682
683 bool aout_CheckChannelExtraction( int *pi_selection,
684                                   uint32_t *pi_layout, int *pi_channels,
685                                   const uint32_t pi_order_dst[AOUT_CHAN_MAX],
686                                   const uint32_t *pi_order_src, int i_channels )
687 {
688     const uint32_t pi_order_dual_mono[] = { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT };
689     uint32_t i_layout = 0;
690     int i_out = 0;
691     int pi_index[AOUT_CHAN_MAX];
692
693     /* */
694     if( !pi_order_dst )
695         pi_order_dst = pi_vlc_chan_order_wg4;
696
697     /* Detect special dual mono case */
698     if( i_channels == 2 &&
699         pi_order_src[0] == AOUT_CHAN_CENTER && pi_order_src[1] == AOUT_CHAN_CENTER )
700     {
701         i_layout |= AOUT_CHAN_DUALMONO;
702         pi_order_src = pi_order_dual_mono;
703     }
704
705     /* */
706     for( int i = 0; i < i_channels; i++ )
707     {
708         /* Ignore unknown or duplicated channels or not present in output */
709         if( !pi_order_src[i] || (i_layout & pi_order_src[i]) )
710             continue;
711
712         for( int j = 0; j < AOUT_CHAN_MAX; j++ )
713         {
714             if( pi_order_dst[j] == pi_order_src[i] )
715             {
716                 assert( i_out < AOUT_CHAN_MAX );
717                 pi_index[i_out++] = i;
718                 i_layout |= pi_order_src[i];
719                 break;
720             }
721         }
722     }
723
724     /* */
725     for( int i = 0, j = 0; i < AOUT_CHAN_MAX; i++ )
726     {
727         for( int k = 0; k < i_out; k++ )
728         {
729             if( pi_order_dst[i] == pi_order_src[pi_index[k]] )
730             {
731                 pi_selection[j++] = pi_index[k];
732                 break;
733             }
734         }
735     }
736
737     *pi_layout = i_layout;
738     *pi_channels = i_out;
739
740     for( int i = 0; i < i_out; i++ )
741     {
742         if( pi_selection[i] != i )
743             return true;
744     }
745     return i_out == i_channels;
746 }
747
748 /*****************************************************************************
749  * aout_BufferAlloc:
750  *****************************************************************************/
751
752 aout_buffer_t *aout_BufferAlloc(aout_alloc_t *allocation, mtime_t microseconds,
753         aout_buffer_t *old_buffer)
754 {
755     if ( !allocation->b_alloc )
756     {
757         return old_buffer;
758     }
759
760     size_t i_alloc_size = (int)( (uint64_t)allocation->i_bytes_per_sec
761                                         * (microseconds) / 1000000 + 1 );
762
763     return block_Alloc( i_alloc_size );
764 }