075a5e3ae0e5cc689edaf9da7b5df635a5d8a9c2
[vlc.git] / src / audio_output / aout_s16.c
1 /*****************************************************************************
2  * aout_s16.c: 16 bit signed audio output functions
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  *
6  * Authors: Michel Kaempf <maxx@via.ecp.fr>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  * 
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26 #include <stdio.h>                                           /* "intf_msg.h" */
27 #include <stdlib.h>                            /* calloc(), malloc(), free() */
28 #include <string.h>
29
30 #include <videolan/vlc.h>
31
32 #include "audio_output.h"
33 #include "aout_common.h"
34
35 /*****************************************************************************
36  * Local prototypes
37  *****************************************************************************/
38 static void S16StereoPlay( aout_thread_t * p_aout, aout_fifo_t * p_fifo );
39
40 /*****************************************************************************
41  * Functions
42  *****************************************************************************/
43 void aout_S16MonoThread( aout_thread_t * p_aout )
44 {
45     intf_ErrMsg( "aout error: 16 bit signed mono thread unsupported" );
46 }
47
48 void aout_S16StereoThread( aout_thread_t * p_aout )
49 {
50     int  i_fifo;
51     long l_buffer, l_buffer_limit, l_bytes;
52
53     /* As the s32_buffer was created with calloc(), we don't have to set this
54      * memory to zero and we can immediately jump into the thread's loop */
55     while ( ! p_aout->b_die )
56     {
57         vlc_mutex_lock( &p_aout->fifos_lock );
58
59         for ( i_fifo = 0; i_fifo < AOUT_MAX_FIFOS; i_fifo++ )
60         {
61             if( p_aout->fifo[i_fifo].b_die )
62             {
63                 aout_FreeFifo( &p_aout->fifo[i_fifo] );
64             }
65             else
66             {
67                 S16StereoPlay( p_aout, &p_aout->fifo[i_fifo] );
68             }
69         }
70
71         vlc_mutex_unlock( &p_aout->fifos_lock );
72
73         l_buffer_limit = p_aout->l_units << 1; /* p_aout->b_stereo == 1 */
74
75         for ( l_buffer = 0; l_buffer < l_buffer_limit; l_buffer++ )
76         {
77             ((s16 *)p_aout->buffer)[l_buffer] =
78                      (s16)( ( p_aout->s32_buffer[l_buffer] / AOUT_MAX_FIFOS )
79                             * p_aout->i_volume / 256 ) ;
80             p_aout->s32_buffer[l_buffer] = 0;
81         }
82
83         l_bytes = p_aout->pf_getbufinfo( p_aout, l_buffer_limit );
84
85         /* sizeof(s16) << (p_aout->b_stereo) == 4 */
86         p_aout->date = mdate() + ((((mtime_t)((l_bytes + 4 * p_aout->i_latency) / 4)) * 1000000)
87                                    / ((mtime_t)p_aout->l_rate))
88                         + p_main->i_desync;
89         p_aout->pf_play( p_aout, (byte_t *)p_aout->buffer,
90                          l_buffer_limit * sizeof(s16) );
91
92         if ( l_bytes > (l_buffer_limit * sizeof(s16)) )
93         {
94             msleep( p_aout->l_msleep );
95         }
96     }
97
98     vlc_mutex_lock( &p_aout->fifos_lock );
99
100     for ( i_fifo = 0; i_fifo < AOUT_MAX_FIFOS; i_fifo++ )
101     {
102         aout_FreeFifo( &p_aout->fifo[i_fifo] );
103     }
104
105     vlc_mutex_unlock( &p_aout->fifos_lock );
106 }
107
108 /* Following functions are local */
109
110 static void S16StereoPlay( aout_thread_t * p_aout, aout_fifo_t * p_fifo )
111 {
112     long l_buffer = 0;
113     long l_buffer_limit, l_units;
114
115     switch ( p_fifo->i_type )
116     {
117     case AOUT_EMPTY_FIFO:
118
119         break;
120
121     case AOUT_INTF_MONO_FIFO:
122
123         if ( p_fifo->l_units > p_aout->l_units )
124         {
125             /* p_aout->b_stereo == 1 */
126             while ( l_buffer < (p_aout->l_units << 1) )
127             {
128                 p_aout->s32_buffer[l_buffer++] +=
129                     (s32)( ((s16 *)p_fifo->buffer)[p_fifo->l_unit] );
130                 p_aout->s32_buffer[l_buffer++] +=
131                     (s32)( ((s16 *)p_fifo->buffer)[p_fifo->l_unit] );
132                 UPDATE_INCREMENT( p_fifo->unit_increment, p_fifo->l_unit )
133             }
134             p_fifo->l_units -= p_aout->l_units;
135         }
136         else /* p_fifo->l_units <= p_aout->l_units */
137         {
138             /* p_aout->b_stereo == 1 */
139             while ( l_buffer < (p_fifo->l_units << 1) )
140             {
141                 p_aout->s32_buffer[l_buffer++] +=
142                     (s32)( ((s16 *)p_fifo->buffer)[p_fifo->l_unit] );
143                 p_aout->s32_buffer[l_buffer++] +=
144                     (s32)( ((s16 *)p_fifo->buffer)[p_fifo->l_unit] );
145                 UPDATE_INCREMENT( p_fifo->unit_increment, p_fifo->l_unit )
146             }
147             free( p_fifo->buffer ); /* !! */
148             p_fifo->i_type = AOUT_EMPTY_FIFO; /* !! */
149         }
150         break;
151
152     case AOUT_INTF_STEREO_FIFO:
153
154         if ( p_fifo->l_units > p_aout->l_units )
155         {
156             /* p_aout->b_stereo == 1 */
157             while ( l_buffer < (p_aout->l_units << 1) )
158             {
159                 p_aout->s32_buffer[l_buffer++] +=
160                     (s32)( ((s16 *)p_fifo->buffer)[2*p_fifo->l_unit] );
161                 p_aout->s32_buffer[l_buffer++] +=
162                     (s32)( ((s16 *)p_fifo->buffer)[2*p_fifo->l_unit+1] );
163                 UPDATE_INCREMENT( p_fifo->unit_increment, p_fifo->l_unit )
164             }
165             p_fifo->l_units -= p_aout->l_units;
166         }
167         else /* p_fifo->l_units <= p_aout->l_units */
168         {
169             /* p_aout->b_stereo == 1 */
170             while ( l_buffer < (p_fifo->l_units << 1) )
171             {
172                 p_aout->s32_buffer[l_buffer++] +=
173                     (s32)( ((s16 *)p_fifo->buffer)[2*p_fifo->l_unit] );
174                 p_aout->s32_buffer[l_buffer++] +=
175                     (s32)( ((s16 *)p_fifo->buffer)[2*p_fifo->l_unit+1] );
176                 UPDATE_INCREMENT( p_fifo->unit_increment, p_fifo->l_unit )
177             }
178             free( p_fifo->buffer );
179             p_fifo->i_type = AOUT_EMPTY_FIFO;
180         }
181         break;
182
183     case AOUT_ADEC_MONO_FIFO:
184
185         l_units = p_aout->l_units;
186         while ( l_units > 0 )
187         {
188             if ( !p_fifo->b_next_frame )
189             {
190                 if ( NextFrame(p_aout, p_fifo, p_aout->date + ((((mtime_t)(l_buffer >> 1)) * 1000000) / ((mtime_t)p_aout->l_rate))) )
191                 {
192                     break;
193                 }
194             }
195
196             if ( p_fifo->l_units > l_units )
197             {
198                 /* p_aout->b_stereo == 1 */
199                 l_buffer_limit = p_aout->l_units << 1;
200
201                 while ( l_buffer < l_buffer_limit )
202                 {
203                     p_aout->s32_buffer[l_buffer++] +=
204                         (s32)( ((s16 *)p_fifo->buffer)[p_fifo->l_unit] );
205                     p_aout->s32_buffer[l_buffer++] +=
206                         (s32)( ((s16 *)p_fifo->buffer)[p_fifo->l_unit] );
207
208                     UPDATE_INCREMENT( p_fifo->unit_increment, p_fifo->l_unit )
209                     if ( p_fifo->l_unit >= /* p_fifo->b_stereo == 0 */
210                          ((AOUT_FIFO_SIZE + 1) * (p_fifo->l_frame_size >> 0)) )
211                     {
212                         p_fifo->l_unit -= /* p_fifo->b_stereo == 0 */
213                             ((AOUT_FIFO_SIZE + 1) * (p_fifo->l_frame_size >> 0));
214                     }
215                 }
216                 p_fifo->l_units -= l_units;
217                 break;
218             }
219             else /* p_fifo->l_units <= l_units */
220             {
221                 /* p_aout->b_stereo == 1 */
222                 l_buffer_limit = p_fifo->l_units << 1;
223
224                 while ( l_buffer < l_buffer_limit )
225                 {
226                     p_aout->s32_buffer[l_buffer++] +=
227                         (s32)( ((s16 *)p_fifo->buffer)[p_fifo->l_unit] );
228                     p_aout->s32_buffer[l_buffer++] +=
229                         (s32)( ((s16 *)p_fifo->buffer)[p_fifo->l_unit] );
230
231                     UPDATE_INCREMENT( p_fifo->unit_increment, p_fifo->l_unit )
232                     if ( p_fifo->l_unit >= /* p_fifo->b_stereo == 0 */
233                          ((AOUT_FIFO_SIZE + 1) * (p_fifo->l_frame_size >> 0)) )
234                     {
235                         p_fifo->l_unit -= /* p_fifo->b_stereo == 0 */
236                             ((AOUT_FIFO_SIZE + 1) * (p_fifo->l_frame_size >> 0));
237                     }
238                 }
239                 l_units -= p_fifo->l_units;
240
241                 vlc_mutex_lock( &p_fifo->data_lock );
242                 p_fifo->l_start_frame = p_fifo->l_next_frame;
243                 vlc_cond_signal( &p_fifo->data_wait );
244                 vlc_mutex_unlock( &p_fifo->data_lock );
245
246                 /* p_fifo->b_start_frame = 1; */
247                 p_fifo->l_next_frame += 1;
248                 p_fifo->l_next_frame &= AOUT_FIFO_SIZE;
249                 p_fifo->b_next_frame = 0;
250             }
251         }
252         break;
253
254     case AOUT_ADEC_STEREO_FIFO:
255
256         l_units = p_aout->l_units;
257         while ( l_units > 0 )
258         {
259             if ( !p_fifo->b_next_frame )
260             {
261                 if ( NextFrame(p_aout, p_fifo, p_aout->date + ((((mtime_t)(l_buffer >> 1)) * 1000000) / ((mtime_t)p_aout->l_rate))) )
262                 {
263                     break;
264                 }
265             }
266
267             if ( p_fifo->l_units > l_units )
268             {
269                 /* p_aout->b_stereo == 1 */
270                 l_buffer_limit = p_aout->l_units << 1;
271
272                 while ( l_buffer < l_buffer_limit )
273                 {
274                     p_aout->s32_buffer[l_buffer++] +=
275                         (s32)( ((s16 *)p_fifo->buffer)[2*p_fifo->l_unit] );
276                     p_aout->s32_buffer[l_buffer++] +=
277                         (s32)( ((s16 *)p_fifo->buffer)[2*p_fifo->l_unit+1] );
278
279                     UPDATE_INCREMENT( p_fifo->unit_increment, p_fifo->l_unit )
280                     if ( p_fifo->l_unit >= /* p_fifo->b_stereo == 1 */
281                          ((AOUT_FIFO_SIZE + 1) * (p_fifo->l_frame_size >> 1)) )
282                     {
283                         p_fifo->l_unit -= /* p_fifo->b_stereo == 1 */
284                             ((AOUT_FIFO_SIZE + 1) * (p_fifo->l_frame_size >> 1));
285                     }
286                 }
287                 p_fifo->l_units -= l_units;
288                 break;
289             }
290             else /* p_fifo->l_units <= l_units */
291             {
292                 /* p_aout->b_stereo == 1 */
293                 l_buffer_limit = p_fifo->l_units << 1;
294
295                 while ( l_buffer < l_buffer_limit )
296                 {
297                     p_aout->s32_buffer[l_buffer++] +=
298                         (s32)( ((s16 *)p_fifo->buffer)[2*p_fifo->l_unit] );
299                     p_aout->s32_buffer[l_buffer++] +=
300                         (s32)( ((s16 *)p_fifo->buffer)[2*p_fifo->l_unit+1] );
301
302                     UPDATE_INCREMENT( p_fifo->unit_increment, p_fifo->l_unit )
303                     if ( p_fifo->l_unit >= /* p_fifo->b_stereo == 1 */
304                          ((AOUT_FIFO_SIZE + 1) * (p_fifo->l_frame_size >> 1)) )
305                     {
306                         p_fifo->l_unit -= /* p_fifo->b_stereo == 1 */
307                             ((AOUT_FIFO_SIZE + 1) * (p_fifo->l_frame_size >> 1));
308                     }
309                 }
310                 l_units -= p_fifo->l_units;
311
312                 vlc_mutex_lock( &p_fifo->data_lock );
313                 p_fifo->l_start_frame = p_fifo->l_next_frame;
314                 vlc_cond_signal( &p_fifo->data_wait );
315                 vlc_mutex_unlock( &p_fifo->data_lock );
316
317                 /* p_fifo->b_start_frame = 1; */
318                 p_fifo->l_next_frame += 1;
319                 p_fifo->l_next_frame &= AOUT_FIFO_SIZE;
320                 p_fifo->b_next_frame = 0;
321             }
322         }
323         break;
324
325     default:
326
327         intf_DbgMsg("aout debug: unknown fifo type (%i)", p_fifo->i_type);
328         break;
329     }
330 }
331