]> git.sesse.net Git - vlc/blob - src/audio_output/output.c
0a0a6031af0684cb3c3d4a637b175b9ec7e42421
[vlc] / src / audio_output / output.c
1 /*****************************************************************************
2  * output.c : internal management of output streams for the audio output
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: output.c,v 1.15 2002/09/26 22:40:25 massiot 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 #include "audio_output.h"
33 #include "aout_internal.h"
34
35 /*****************************************************************************
36  * aout_OutputNew : allocate a new output and rework the filter pipeline
37  *****************************************************************************
38  * This function is entered with the mixer lock.
39  *****************************************************************************/
40 int aout_OutputNew( aout_instance_t * p_aout,
41                     audio_sample_format_t * p_format )
42 {
43     /* Retrieve user defaults. */
44     char * psz_name = config_GetPsz( p_aout, "aout" );
45     int i_rate = config_GetInt( p_aout, "aout-rate" );
46     int i_channels = config_GetInt( p_aout, "aout-channels" );
47
48     memcpy( &p_aout->output.output, p_format, sizeof(audio_sample_format_t) );
49     if ( i_rate != -1 ) p_aout->output.output.i_rate = i_rate;
50     if ( i_channels != -1 ) p_aout->output.output.i_channels = i_channels;
51     if ( AOUT_FMT_NON_LINEAR(&p_aout->output.output) )
52     {
53         p_aout->output.output.i_format = AOUT_FMT_SPDIF;
54     }
55     else
56     {
57         /* Non-S/PDIF mixer only deals with float32 or fixed32. */
58         p_aout->output.output.i_format
59                      = (p_aout->p_vlc->i_cpu & CPU_CAPABILITY_FPU) ?
60                         AOUT_FMT_FLOAT32 : AOUT_FMT_FIXED32;
61     }
62     aout_FormatPrepare( &p_aout->output.output );
63
64     vlc_mutex_lock( &p_aout->output_fifo_lock );
65
66     /* Find the best output plug-in. */
67     p_aout->output.p_module = module_Need( p_aout, "audio output",
68                                            psz_name );
69     if ( psz_name != NULL ) free( psz_name );
70     if ( p_aout->output.p_module == NULL )
71     {
72         msg_Err( p_aout, "no suitable aout module" );
73         vlc_mutex_unlock( &p_aout->output_fifo_lock );
74         return -1;
75     }
76     aout_FormatPrepare( &p_aout->output.output );
77
78     /* Prepare FIFO. */
79     aout_FifoInit( p_aout, &p_aout->output.fifo, p_aout->output.output.i_rate );
80
81     vlc_mutex_unlock( &p_aout->output_fifo_lock );
82
83     msg_Dbg( p_aout, "output format=%d rate=%d channels=%d",
84              p_aout->output.output.i_format, p_aout->output.output.i_rate,
85              p_aout->output.output.i_channels );
86
87     /* Calculate the resulting mixer output format. */
88     memcpy( &p_aout->mixer.mixer, &p_aout->output.output,
89             sizeof(audio_sample_format_t) );
90     if ( !AOUT_FMT_NON_LINEAR(&p_aout->output.output) )
91     {
92         /* Non-S/PDIF mixer only deals with float32 or fixed32. */
93         p_aout->mixer.mixer.i_format
94                      = (p_aout->p_vlc->i_cpu & CPU_CAPABILITY_FPU) ?
95                         AOUT_FMT_FLOAT32 : AOUT_FMT_FIXED32;
96         aout_FormatPrepare( &p_aout->mixer.mixer );
97     }
98     else
99     {
100         p_aout->mixer.mixer.i_format = p_format->i_format;
101     }
102
103     msg_Dbg( p_aout, "mixer format=%d rate=%d channels=%d",
104              p_aout->mixer.mixer.i_format, p_aout->mixer.mixer.i_rate,
105              p_aout->mixer.mixer.i_channels );
106
107     /* Create filters. */
108     if ( aout_FiltersCreatePipeline( p_aout, p_aout->output.pp_filters,
109                                      &p_aout->output.i_nb_filters,
110                                      &p_aout->mixer.mixer,
111                                      &p_aout->output.output ) < 0 )
112     {
113         msg_Err( p_aout, "couldn't set an output pipeline" );
114         module_Unneed( p_aout, p_aout->output.p_module );
115         return -1;
116     }
117
118     /* Prepare hints for the buffer allocator. */
119     p_aout->mixer.output_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
120     p_aout->mixer.output_alloc.i_bytes_per_sec
121                         = p_aout->mixer.mixer.i_bytes_per_frame
122                            * p_aout->mixer.mixer.i_rate
123                            / p_aout->mixer.mixer.i_frame_length;
124
125     aout_FiltersHintBuffers( p_aout, p_aout->output.pp_filters,
126                              p_aout->output.i_nb_filters,
127                              &p_aout->mixer.output_alloc );
128
129     return 0;
130 }
131
132 /*****************************************************************************
133  * aout_OutputDelete : delete the output
134  *****************************************************************************
135  * This function is entered with the mixer lock.
136  *****************************************************************************/
137 void aout_OutputDelete( aout_instance_t * p_aout )
138 {
139     module_Unneed( p_aout, p_aout->output.p_module );
140
141     aout_FiltersDestroyPipeline( p_aout, p_aout->output.pp_filters,
142                                  p_aout->output.i_nb_filters );
143     aout_FifoDestroy( p_aout, &p_aout->output.fifo );
144 }
145
146 /*****************************************************************************
147  * aout_OutputPlay : play a buffer
148  *****************************************************************************
149  * This function is entered with the mixer lock.
150  *****************************************************************************/
151 void aout_OutputPlay( aout_instance_t * p_aout, aout_buffer_t * p_buffer )
152 {
153     aout_FiltersPlay( p_aout, p_aout->output.pp_filters,
154                       p_aout->output.i_nb_filters,
155                       &p_buffer );
156
157     vlc_mutex_lock( &p_aout->output_fifo_lock );
158     aout_FifoPush( p_aout, &p_aout->output.fifo, p_buffer );
159     p_aout->output.pf_play( p_aout );
160     vlc_mutex_unlock( &p_aout->output_fifo_lock );
161 }
162
163 /*****************************************************************************
164  * aout_OutputNextBuffer : give the audio output plug-in the right buffer
165  *****************************************************************************
166  * If b_can_sleek is 1, the aout core functions won't try to resample
167  * new buffers to catch up - that is we suppose that the output plug-in can
168  * compensate it by itself. S/PDIF outputs should always set b_can_sleek = 1.
169  * This function is entered with no lock at all :-).
170  *****************************************************************************/
171 aout_buffer_t * aout_OutputNextBuffer( aout_instance_t * p_aout,
172                                        mtime_t start_date,
173                                        vlc_bool_t b_can_sleek )
174 {
175     aout_buffer_t * p_buffer;
176
177     vlc_mutex_lock( &p_aout->output_fifo_lock );
178
179     p_buffer = p_aout->output.fifo.p_first;
180     while ( p_buffer && p_buffer->start_date < start_date )
181     {
182         msg_Dbg( p_aout, "audio output is too slow (%lld), trashing %lldus",
183                  start_date - p_buffer->start_date,
184                  p_buffer->end_date - p_buffer->start_date );
185         p_buffer = p_buffer->p_next;
186     }
187
188     p_aout->output.fifo.p_first = p_buffer;
189     if ( p_buffer == NULL )
190     {
191         p_aout->output.fifo.pp_last = &p_aout->output.fifo.p_first;
192         /* Set date to 0, to allow the mixer to send a new buffer ASAP */
193         aout_FifoSet( p_aout, &p_aout->output.fifo, 0 );
194         vlc_mutex_unlock( &p_aout->output_fifo_lock );
195         msg_Dbg( p_aout,
196                  "audio output is starving (no input), playing silence" );
197         return NULL;
198     }
199
200     /* Here we suppose that all buffers have the same duration - this is
201      * generally true, and anyway if it's wrong it won't be a disaster. */
202     if ( p_buffer->start_date > start_date
203                          + (p_buffer->end_date - p_buffer->start_date) )
204     {
205         vlc_mutex_unlock( &p_aout->output_fifo_lock );
206         msg_Dbg( p_aout, "audio output is starving (%lld), playing silence",
207                  p_buffer->start_date - start_date );
208         return NULL;
209     }
210
211     if ( !b_can_sleek &&
212           ( (p_buffer->start_date - start_date > AOUT_PTS_TOLERANCE)
213              || (start_date - p_buffer->start_date > AOUT_PTS_TOLERANCE) ) )
214     {
215         /* Try to compensate the drift by doing some resampling. */
216         int i;
217         mtime_t difference = p_buffer->start_date - start_date;
218         msg_Warn( p_aout, "output date isn't PTS date, resampling (%lld)",
219                   difference );
220
221         vlc_mutex_lock( &p_aout->input_fifos_lock );
222         for ( i = 0; i < p_aout->i_nb_inputs; i++ )
223         {
224             aout_fifo_t * p_fifo = &p_aout->pp_inputs[i]->fifo;
225
226             aout_FifoMoveDates( p_aout, p_fifo, difference );
227         }
228
229         aout_FifoMoveDates( p_aout, &p_aout->output.fifo, difference );
230         vlc_mutex_unlock( &p_aout->input_fifos_lock );
231     }
232
233     p_aout->output.fifo.p_first = p_buffer->p_next;
234     if ( p_buffer->p_next == NULL )
235     {
236         p_aout->output.fifo.pp_last = &p_aout->output.fifo.p_first;
237     }
238
239     vlc_mutex_unlock( &p_aout->output_fifo_lock );
240     return p_buffer;
241 }