]> git.sesse.net Git - vlc/blob - src/audio_output/input.c
- new headphone channel mixer with virtual spatialization effect : This
[vlc] / src / audio_output / input.c
1 /*****************************************************************************
2  * input.c : internal management of input streams for the audio output
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: input.c,v 1.27 2002/12/09 00:52:42 babal Exp $
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                            /* calloc(), malloc(), free() */
28 #include <string.h>
29
30 #include <vlc/vlc.h>
31
32 #ifdef HAVE_ALLOCA_H
33 #   include <alloca.h>
34 #endif
35
36 #include "audio_output.h"
37 #include "aout_internal.h"
38
39 /*****************************************************************************
40  * aout_InputNew : allocate a new input and rework the filter pipeline
41  *****************************************************************************/
42 int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input )
43 {
44     audio_sample_format_t intermediate_format, headphone_intermediate_format;
45     aout_filter_t * p_headphone_filter;
46
47     aout_FormatPrint( p_aout, "input", &p_input->input );
48
49     /* Prepare FIFO. */
50     aout_FifoInit( p_aout, &p_input->fifo, p_aout->mixer.mixer.i_rate );
51     p_input->p_first_byte_to_mix = NULL;
52
53     /* Create filters. */
54     memcpy( &intermediate_format, &p_aout->mixer.mixer,
55             sizeof(audio_sample_format_t) );
56     memcpy( &headphone_intermediate_format, &p_aout->mixer.mixer,
57             sizeof(audio_sample_format_t) );
58     if ( config_GetInt( p_aout , "headphone" ) )
59     {
60         headphone_intermediate_format.i_physical_channels = p_input->input.i_physical_channels;
61         headphone_intermediate_format.i_original_channels = p_input->input.i_original_channels;
62         headphone_intermediate_format.i_bytes_per_frame =
63                 headphone_intermediate_format.i_bytes_per_frame
64                 * aout_FormatNbChannels( &headphone_intermediate_format )
65                 / aout_FormatNbChannels( &intermediate_format );
66     }
67
68     intermediate_format.i_rate = p_input->input.i_rate;
69     headphone_intermediate_format.i_rate = p_input->input.i_rate;
70     if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
71                                      &p_input->i_nb_filters, &p_input->input,
72                                      &headphone_intermediate_format ) < 0 )
73     {
74         msg_Err( p_aout, "couldn't set an input pipeline" );
75
76         aout_FifoDestroy( p_aout, &p_input->fifo );
77         p_input->b_error = 1;
78
79         return -1;
80     }
81
82     if ( config_GetInt( p_aout , "headphone" ) )
83     {
84         /* create a vlc object */
85         p_headphone_filter = vlc_object_create( p_aout
86                 , sizeof(aout_filter_t) );
87         if ( p_headphone_filter == NULL )
88         {
89             msg_Err( p_aout, "couldn't open the headphone virtual spatialization module" );
90             aout_FifoDestroy( p_aout, &p_input->fifo );
91             p_input->b_error = 1;
92             return -1;
93         }
94         vlc_object_attach( p_headphone_filter, p_aout );
95
96         /* find the headphone filter */
97         memcpy( &p_headphone_filter->input, &headphone_intermediate_format
98                 , sizeof(audio_sample_format_t) );
99         memcpy( &p_headphone_filter->output, &intermediate_format
100                 , sizeof(audio_sample_format_t) );
101         p_headphone_filter->p_module = module_Need( p_headphone_filter, "audio filter"
102                 , "headphone" );
103         if ( p_headphone_filter->p_module == NULL )
104         {
105             vlc_object_detach( p_headphone_filter );
106             vlc_object_destroy( p_headphone_filter );
107
108             msg_Err( p_aout, "couldn't open the headphone virtual spatialization module" );
109             aout_FifoDestroy( p_aout, &p_input->fifo );
110             p_input->b_error = 1;
111             return -1;
112         }
113
114         /* success */
115         p_headphone_filter->b_reinit = VLC_TRUE;
116         p_input->pp_filters[p_input->i_nb_filters++] = p_headphone_filter;
117     }
118
119     /* Prepare hints for the buffer allocator. */
120     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
121     p_input->input_alloc.i_bytes_per_sec = -1;
122
123     if ( AOUT_FMT_NON_LINEAR( &p_aout->mixer.mixer ) )
124     {
125         p_input->i_nb_resamplers = 0;
126     }
127     else
128     {
129         /* Create resamplers. */
130         intermediate_format.i_rate = (p_input->input.i_rate
131                                  * (100 + AOUT_MAX_RESAMPLING)) / 100;
132         if ( intermediate_format.i_rate == p_aout->mixer.mixer.i_rate )
133         {
134             /* Just in case... */
135             intermediate_format.i_rate++;
136         }
137         if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_resamplers,
138                                          &p_input->i_nb_resamplers,
139                                          &intermediate_format,
140                                          &p_aout->mixer.mixer ) < 0 )
141         {
142             msg_Err( p_aout, "couldn't set a resampler pipeline" );
143
144             aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
145                                          p_input->i_nb_filters );
146             aout_FifoDestroy( p_aout, &p_input->fifo );
147             p_input->b_error = 1;
148
149             return -1;
150         }
151
152         aout_FiltersHintBuffers( p_aout, p_input->pp_resamplers,
153                                  p_input->i_nb_resamplers,
154                                  &p_input->input_alloc );
155
156         /* Setup the initial rate of the resampler */
157         p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
158     }
159     p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
160
161     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
162     p_input->input_alloc.i_bytes_per_sec = -1;
163     aout_FiltersHintBuffers( p_aout, p_input->pp_filters,
164                              p_input->i_nb_filters,
165                              &p_input->input_alloc );
166
167     /* i_bytes_per_sec is still == -1 if no filters */
168     p_input->input_alloc.i_bytes_per_sec = __MAX(
169                                     p_input->input_alloc.i_bytes_per_sec,
170                                     (int)(p_input->input.i_bytes_per_frame
171                                      * p_input->input.i_rate
172                                      / p_input->input.i_frame_length) );
173     /* Allocate in the heap, it is more convenient for the decoder. */
174     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
175
176     p_input->b_error = 0;
177
178     return 0;
179 }
180
181 /*****************************************************************************
182  * aout_InputDelete : delete an input
183  *****************************************************************************
184  * This function must be entered with the mixer lock.
185  *****************************************************************************/
186 int aout_InputDelete( aout_instance_t * p_aout, aout_input_t * p_input )
187 {
188     if ( p_input->b_error ) return 0;
189
190     aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
191                                  p_input->i_nb_filters );
192     aout_FiltersDestroyPipeline( p_aout, p_input->pp_resamplers,
193                                  p_input->i_nb_resamplers );
194     aout_FifoDestroy( p_aout, &p_input->fifo );
195
196     return 0;
197 }
198
199 /*****************************************************************************
200  * aout_InputPlay : play a buffer
201  *****************************************************************************
202  * This function must be entered with the input lock.
203  *****************************************************************************/
204 int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
205                     aout_buffer_t * p_buffer )
206 {
207     mtime_t start_date;
208
209     /* We don't care if someone changes the start date behind our back after
210      * this. We'll deal with that when pushing the buffer, and compensate
211      * with the next incoming buffer. */
212     vlc_mutex_lock( &p_aout->input_fifos_lock );
213     start_date = aout_FifoNextStart( p_aout, &p_input->fifo );
214     vlc_mutex_unlock( &p_aout->input_fifos_lock );
215
216     if ( start_date != 0 && start_date < mdate() )
217     {
218         /* The decoder is _very_ late. This can only happen if the user
219          * pauses the stream (or if the decoder is buggy, which cannot
220          * happen :). */
221         msg_Warn( p_aout, "computed PTS is out of range ("I64Fd"), "
222                   "clearing out", mdate() - start_date );
223         vlc_mutex_lock( &p_aout->input_fifos_lock );
224         aout_FifoSet( p_aout, &p_input->fifo, 0 );
225         vlc_mutex_unlock( &p_aout->input_fifos_lock );
226         if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
227             msg_Warn( p_aout, "timing screwed, stopping resampling" );
228         p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
229         if ( p_input->i_nb_resamplers != 0 )
230         {
231             p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
232             p_input->pp_resamplers[0]->b_reinit = VLC_TRUE;
233         }
234         start_date = 0;
235     }
236
237     if ( p_buffer->start_date < mdate() + AOUT_MIN_PREPARE_TIME )
238     {
239         /* The decoder gives us f*cked up PTS. It's its business, but we
240          * can't present it anyway, so drop the buffer. */
241         msg_Warn( p_aout, "PTS is out of range ("I64Fd"), dropping buffer",
242                   mdate() - p_buffer->start_date );
243         aout_BufferFree( p_buffer );
244
245         return 0;
246     }
247
248     if ( start_date == 0 ) start_date = p_buffer->start_date;
249
250     /* Run pre-filters. */
251     aout_FiltersPlay( p_aout, p_input->pp_filters, p_input->i_nb_filters,
252                       &p_buffer );
253
254     /* Run the resampler if needed.
255      * We first need to calculate the output rate of this resampler. */
256     if ( ( p_input->i_resampling_type == AOUT_RESAMPLING_NONE ) &&
257          ( start_date < p_buffer->start_date - AOUT_PTS_TOLERANCE
258            || start_date > p_buffer->start_date + AOUT_PTS_TOLERANCE ) &&
259          p_input->i_nb_resamplers > 0 )
260     {
261         /* Can happen in several circumstances :
262          * 1. A problem at the input (clock drift)
263          * 2. A small pause triggered by the user
264          * 3. Some delay in the output stage, causing a loss of lip
265          *    synchronization
266          * Solution : resample the buffer to avoid a scratch.
267          */
268         mtime_t drift = p_buffer->start_date - start_date;
269
270         p_input->i_resamp_start_date = mdate();
271         p_input->i_resamp_start_drift = (int)drift;
272
273         if ( drift > 0 )
274             p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
275         else
276             p_input->i_resampling_type = AOUT_RESAMPLING_UP;
277
278         msg_Warn( p_aout, "buffer is "I64Fd" %s, triggering %ssampling",
279                           drift > 0 ? drift : -drift,
280                           drift > 0 ? "in advance" : "late",
281                           drift > 0 ? "down" : "up");
282     }
283
284     if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
285     {
286         /* Resampling has been triggered previously (because of dates
287          * mismatch). We want the resampling to happen progressively so
288          * it isn't too audible to the listener. */
289
290         if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
291         {
292             p_input->pp_resamplers[0]->input.i_rate += 10; /* Hz */
293         }
294         else
295         {
296             p_input->pp_resamplers[0]->input.i_rate -= 10; /* Hz */
297         }
298
299         /* Check if everything is back to normal, in which case we can stop the
300          * resampling */
301         if( p_input->pp_resamplers[0]->input.i_rate ==
302               p_input->input.i_rate )
303         {
304             p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
305             msg_Warn( p_aout, "resampling stopped after "I64Fi" usec",
306                       mdate() - p_input->i_resamp_start_date );
307         }
308         else if( abs( (int)(p_buffer->start_date - start_date) ) <
309                  abs( p_input->i_resamp_start_drift ) / 2 )
310         {
311             /* if we reduced the drift from half, then it is time to switch
312              * back the resampling direction. */
313             if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
314                 p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
315             else
316                 p_input->i_resampling_type = AOUT_RESAMPLING_UP;
317             p_input->i_resamp_start_drift = 0;
318         }
319         else if( p_input->i_resamp_start_drift &&
320                  ( abs( (int)(p_buffer->start_date - start_date) ) >
321                    abs( p_input->i_resamp_start_drift ) * 3 / 2 ) )
322         {
323             /* If the drift is increasing and not decreasing, than something
324              * is bad. We'd better stop the resampling right now. */
325             msg_Warn( p_aout, "timing screwed, stopping resampling" );
326             p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
327             p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
328         }
329
330     }
331
332     /* Adding the start date will be managed by aout_FifoPush(). */
333     p_buffer->start_date = start_date;
334     p_buffer->end_date = start_date +
335         (p_buffer->end_date - p_buffer->start_date);
336
337     /* Actually run the resampler now. */
338     if ( p_input->i_nb_resamplers > 0 && p_aout->mixer.mixer.i_rate !=
339          p_input->pp_resamplers[0]->input.i_rate )
340     {
341         aout_FiltersPlay( p_aout, p_input->pp_resamplers,
342                           p_input->i_nb_resamplers,
343                           &p_buffer );
344     }
345
346     vlc_mutex_lock( &p_aout->input_fifos_lock );
347     aout_FifoPush( p_aout, &p_input->fifo, p_buffer );
348     vlc_mutex_unlock( &p_aout->input_fifos_lock );
349
350     return 0;
351 }