- le coup de gr�ce: all the code in audio output is now factorized (except
[vlc.git] / src / audio_output / aout_common.c
1 /*****************************************************************************
2  * aout_common.c: generic audio output functions
3  *****************************************************************************
4  * Copyright (C) 1999-2002 VideoLAN
5  * $Id: aout_common.c,v 1.2 2002/01/14 19:54:36 asmax Exp $
6  *
7  * Authors: Michel Kaempf <maxx@via.ecp.fr>
8  *          Cyril Deguet <asmax@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdio.h>                                           /* "intf_msg.h" */
29 #include <stdlib.h>                            /* calloc(), malloc(), free() */
30 #include <string.h>
31
32 #include <videolan/vlc.h>
33
34 #include "audio_output.h"
35 #include "aout_common.h"
36
37
38 /*****************************************************************************
39  * Local prototypes
40  *****************************************************************************/
41 static int NextFrame( aout_thread_t * p_aout, aout_fifo_t * p_fifo,
42         mtime_t aout_date );
43  
44 /*****************************************************************************
45  * Functions
46  *****************************************************************************/
47
48 /* Read data from decoder fifo, and put it in S32_buffer */
49 void aout_FillBuffer( aout_thread_t * p_aout, aout_fifo_t * p_fifo )
50 {
51     long l_buffer = 0;
52     long l_buffer_limit, l_units;
53
54     switch ( p_fifo->i_type )
55     {
56     case AOUT_EMPTY_FIFO:
57
58         break;
59
60     case AOUT_ADEC_MONO_FIFO:
61     case AOUT_ADEC_STEREO_FIFO:
62
63         l_units = p_aout->l_units;
64         while ( l_units > 0 )
65         {
66             if( !p_fifo->b_next_frame )
67             {
68                 if( NextFrame(p_aout, p_fifo, p_aout->date + 
69                         ((((mtime_t)(l_buffer >> 1)) * 1000000) / 
70                         ((mtime_t)p_aout->l_rate))) )
71                 {
72                     break;
73                 }
74             }
75             l_buffer_limit = p_aout->l_units << p_aout->b_stereo;
76
77             while ( l_buffer < l_buffer_limit )
78             {
79                 if( p_aout->b_stereo )
80                 {
81                     p_aout->s32_buffer[l_buffer++] +=
82                         (s32)( ((s16 *)p_fifo->buffer)[2*p_fifo->l_unit] );
83                     p_aout->s32_buffer[l_buffer++] +=
84                         (s32)( ((s16 *)p_fifo->buffer)[2*p_fifo->l_unit+1] );
85                 }
86                 else
87                 {
88                     p_aout->s32_buffer[l_buffer++] +=
89                         (s32)( ((s16 *)p_fifo->buffer)[p_fifo->l_unit] );
90                 }
91
92                 UpdateIncrement(&p_fifo->unit_increment, &p_fifo->l_unit);
93
94                 if( p_fifo->l_unit >= ((AOUT_FIFO_SIZE + 1) * 
95                         (p_fifo->l_frame_size >> p_fifo->b_stereo)) )
96                 {
97                     p_fifo->l_unit -= ((AOUT_FIFO_SIZE + 1) * 
98                             (p_fifo->l_frame_size >> p_fifo->b_stereo));
99                 }
100             }
101  
102             if( p_fifo->l_units > l_units )
103             {
104                 p_fifo->l_units -= l_units;
105                 break;
106             }
107             else
108             {
109                 l_units -= p_fifo->l_units;
110
111                 vlc_mutex_lock( &p_fifo->data_lock );
112                 p_fifo->l_start_frame = p_fifo->l_next_frame;
113                 vlc_cond_signal( &p_fifo->data_wait );
114                 vlc_mutex_unlock( &p_fifo->data_lock );
115
116                 /* p_fifo->b_start_frame = 1; */
117                 p_fifo->l_next_frame += 1;
118                 p_fifo->l_next_frame &= AOUT_FIFO_SIZE;
119                 p_fifo->b_next_frame = 0;
120             }
121         }
122         break;
123
124     default:
125
126         intf_DbgMsg("aout debug: unknown fifo type (%i)", p_fifo->i_type);
127         break;
128     }
129 }
130
131 /* Following functions are local */
132
133 static int NextFrame( aout_thread_t * p_aout, aout_fifo_t * p_fifo,
134         mtime_t aout_date )
135 {
136     long l_units, l_rate;
137     u64 l_delta;    
138
139     /* We take the lock */
140     vlc_mutex_lock( &p_fifo->data_lock );
141
142     /* Are we looking for a dated start frame ? */
143     if ( !p_fifo->b_start_frame )
144     {
145         while ( p_fifo->l_start_frame != p_fifo->l_end_frame )
146         {
147             if ( p_fifo->date[p_fifo->l_start_frame] != LAST_MDATE )
148             {
149                 p_fifo->b_start_frame = 1;
150                 p_fifo->l_next_frame = (p_fifo->l_start_frame + 1) & 
151                         AOUT_FIFO_SIZE;
152                 p_fifo->l_unit = p_fifo->l_start_frame * 
153                         (p_fifo->l_frame_size >> (p_fifo->b_stereo));
154                 break;
155             }
156             p_fifo->l_start_frame = (p_fifo->l_start_frame + 1) & 
157                     AOUT_FIFO_SIZE;
158         }
159
160         if ( p_fifo->l_start_frame == p_fifo->l_end_frame )
161         {
162             vlc_mutex_unlock( &p_fifo->data_lock );
163             return( -1 );
164         }
165     }
166
167     /* We are looking for the next dated frame */
168     /* FIXME : is the output fifo full ?? */
169     while ( !p_fifo->b_next_frame )
170     {
171         while ( p_fifo->l_next_frame != p_fifo->l_end_frame )
172         {
173             if ( p_fifo->date[p_fifo->l_next_frame] != LAST_MDATE )
174             {
175                 p_fifo->b_next_frame = 1;
176                 break;
177             }
178             p_fifo->l_next_frame = (p_fifo->l_next_frame + 1) & AOUT_FIFO_SIZE;
179         }
180
181         while ( p_fifo->l_next_frame == p_fifo->l_end_frame )
182         {
183             vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
184             if ( p_fifo->b_die )
185             {
186                 vlc_mutex_unlock( &p_fifo->data_lock );
187                 return( -1 );
188             }
189         }
190     }
191
192     l_units = ((p_fifo->l_next_frame - p_fifo->l_start_frame) & 
193             AOUT_FIFO_SIZE) * (p_fifo->l_frame_size >> (p_fifo->b_stereo));
194
195     l_delta = aout_date - p_fifo->date[p_fifo->l_start_frame];
196
197 /* Resample if delta is too long */
198     if( abs(l_delta) > MAX_DELTA )
199     {
200         l_rate = p_fifo->l_rate + (l_delta / 256);
201     }
202     else
203     {
204         l_rate = p_fifo->l_rate;
205     }
206
207     intf_DbgMsg( "aout debug: %lli (%li);", aout_date - 
208             p_fifo->date[p_fifo->l_start_frame], l_rate );
209
210     InitializeIncrement( &p_fifo->unit_increment, l_rate, p_aout->l_rate );
211
212     p_fifo->l_units = (((l_units - (p_fifo->l_unit -
213             (p_fifo->l_start_frame * (p_fifo->l_frame_size >> 
214             (p_fifo->b_stereo))))) * p_aout->l_rate) / l_rate) + 1;
215
216     /* We release the lock before leaving */
217     vlc_mutex_unlock( &p_fifo->data_lock );
218     return( 0 );
219 }
220