e3f50144ee12b18e222569c33164c1bc46e5305f
[vlc.git] / 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.14 2002/08/30 23:27:06 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  *****************************************************************************/
170 aout_buffer_t * aout_OutputNextBuffer( aout_instance_t * p_aout,
171                                        mtime_t start_date,
172                                        vlc_bool_t b_can_sleek )
173 {
174     aout_buffer_t * p_buffer;
175
176     vlc_mutex_lock( &p_aout->output_fifo_lock );
177
178     p_buffer = p_aout->output.fifo.p_first;
179     while ( p_buffer && p_buffer->start_date < start_date )
180     {
181         msg_Dbg( p_aout, "audio output is too slow (%lld), trashing %lldus",
182                  start_date - p_buffer->start_date,
183                  p_buffer->end_date - p_buffer->start_date );
184         p_buffer = p_buffer->p_next;
185     }
186
187     p_aout->output.fifo.p_first = p_buffer;
188     if ( p_buffer == NULL )
189     {
190         p_aout->output.fifo.pp_last = &p_aout->output.fifo.p_first;
191         /* Set date to 0, to allow the mixer to send a new buffer ASAP */
192         aout_FifoSet( p_aout, &p_aout->output.fifo, 0 );
193         vlc_mutex_unlock( &p_aout->output_fifo_lock );
194         msg_Dbg( p_aout,
195                  "audio output is starving (no input), playing silence" );
196         return NULL;
197     }
198
199     /* Here we suppose that all buffers have the same duration - this is
200      * generally true, and anyway if it's wrong it won't be a disaster. */
201     if ( p_buffer->start_date > start_date
202                          + (p_buffer->end_date - p_buffer->start_date) )
203     {
204         vlc_mutex_unlock( &p_aout->output_fifo_lock );
205         msg_Dbg( p_aout, "audio output is starving (%lld), playing silence",
206                  p_buffer->start_date - start_date );
207         return NULL;
208     }
209
210     if ( !b_can_sleek &&
211           ( (p_buffer->start_date - start_date > AOUT_PTS_TOLERANCE)
212              || (start_date - p_buffer->start_date > AOUT_PTS_TOLERANCE) ) )
213     {
214         /* Try to compensate the drift by doing some resampling. */
215         int i;
216         mtime_t difference = p_buffer->start_date - start_date;
217         msg_Warn( p_aout, "output date isn't PTS date, resampling (%lld)",
218                   difference );
219
220         vlc_mutex_lock( &p_aout->input_fifos_lock );
221         for ( i = 0; i < p_aout->i_nb_inputs; i++ )
222         {
223             aout_fifo_t * p_fifo = &p_aout->pp_inputs[i]->fifo;
224
225             aout_FifoMoveDates( p_aout, p_fifo, difference );
226         }
227
228         aout_FifoMoveDates( p_aout, &p_aout->output.fifo, difference );
229         vlc_mutex_unlock( &p_aout->input_fifos_lock );
230     }
231
232     p_aout->output.fifo.p_first = p_buffer->p_next;
233     if ( p_buffer->p_next == NULL )
234     {
235         p_aout->output.fifo.pp_last = &p_aout->output.fifo.p_first;
236     }
237
238     vlc_mutex_unlock( &p_aout->output_fifo_lock );
239     return p_buffer;
240 }