]> git.sesse.net Git - vlc/blob - src/audio_output/output.c
Merge all audio output locks except volume control
[vlc] / src / audio_output / output.c
1 /*****************************************************************************
2  * output.c : internal management of output streams for the audio output
3  *****************************************************************************
4  * Copyright (C) 2002-2004 the VideoLAN team
5  * $Id$
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_aout.h>
33 #include <vlc_cpu.h>
34 #include <vlc_modules.h>
35
36 #include "libvlc.h"
37 #include "aout_internal.h"
38
39 /*****************************************************************************
40  * aout_OutputNew : allocate a new output and rework the filter pipeline
41  *****************************************************************************
42  * This function is entered with the mixer lock.
43  *****************************************************************************/
44 int aout_OutputNew( aout_instance_t * p_aout,
45                     const audio_sample_format_t * p_format )
46 {
47     vlc_assert_locked( &p_aout->lock );
48     p_aout->output.output = *p_format;
49
50     /* Retrieve user defaults. */
51     int i_rate = var_InheritInteger( p_aout, "aout-rate" );
52     if ( i_rate != 0 )
53         p_aout->output.output.i_rate = i_rate;
54     aout_FormatPrepare( &p_aout->output.output );
55
56     /* Find the best output plug-in. */
57     p_aout->output.p_module = module_need( p_aout, "audio output", "$aout", false );
58     if ( p_aout->output.p_module == NULL )
59     {
60         msg_Err( p_aout, "no suitable audio output module" );
61         return -1;
62     }
63
64     if ( var_Type( p_aout, "audio-channels" ) ==
65              (VLC_VAR_INTEGER | VLC_VAR_HASCHOICE) )
66     {
67         /* The user may have selected a different channels configuration. */
68         switch( var_InheritInteger( p_aout, "audio-channels" ) )
69         {
70             case AOUT_VAR_CHAN_RSTEREO:
71                 p_aout->output.output.i_original_channels |=
72                                                        AOUT_CHAN_REVERSESTEREO;
73                 break;
74             case AOUT_VAR_CHAN_STEREO:
75                 p_aout->output.output.i_original_channels =
76                                               AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
77                 break;
78             case AOUT_VAR_CHAN_LEFT:
79                 p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT;
80                 break;
81             case AOUT_VAR_CHAN_RIGHT:
82                 p_aout->output.output.i_original_channels = AOUT_CHAN_RIGHT;
83                 break;
84             case AOUT_VAR_CHAN_DOLBYS:
85                 p_aout->output.output.i_original_channels =
86                       AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_DOLBYSTEREO;
87                 break;
88         }
89     }
90     else if ( p_aout->output.output.i_physical_channels == AOUT_CHAN_CENTER
91               && (p_aout->output.output.i_original_channels
92                    & AOUT_CHAN_PHYSMASK) == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) )
93     {
94         vlc_value_t val, text;
95
96         /* Mono - create the audio-channels variable. */
97         var_Create( p_aout, "audio-channels",
98                     VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
99         text.psz_string = _("Audio Channels");
100         var_Change( p_aout, "audio-channels", VLC_VAR_SETTEXT, &text, NULL );
101
102         val.i_int = AOUT_VAR_CHAN_STEREO; text.psz_string = _("Stereo");
103         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
104         val.i_int = AOUT_VAR_CHAN_LEFT; text.psz_string = _("Left");
105         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
106         val.i_int = AOUT_VAR_CHAN_RIGHT; text.psz_string = _("Right");
107         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
108         if ( p_aout->output.output.i_original_channels & AOUT_CHAN_DUALMONO )
109         {
110             /* Go directly to the left channel. */
111             p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT;
112             var_SetInteger( p_aout, "audio-channels", AOUT_VAR_CHAN_LEFT );
113         }
114         var_AddCallback( p_aout, "audio-channels", aout_ChannelsRestart,
115                          NULL );
116     }
117     else if ( p_aout->output.output.i_physical_channels ==
118                (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)
119                 && (p_aout->output.output.i_original_channels &
120                      (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
121     {
122         vlc_value_t val, text;
123
124         /* Stereo - create the audio-channels variable. */
125         var_Create( p_aout, "audio-channels",
126                     VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
127         text.psz_string = _("Audio Channels");
128         var_Change( p_aout, "audio-channels", VLC_VAR_SETTEXT, &text, NULL );
129
130         if ( p_aout->output.output.i_original_channels & AOUT_CHAN_DOLBYSTEREO )
131         {
132             val.i_int = AOUT_VAR_CHAN_DOLBYS;
133             text.psz_string = _("Dolby Surround");
134         }
135         else
136         {
137             val.i_int = AOUT_VAR_CHAN_STEREO;
138             text.psz_string = _("Stereo");
139         }
140         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
141         val.i_int = AOUT_VAR_CHAN_LEFT; text.psz_string = _("Left");
142         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
143         val.i_int = AOUT_VAR_CHAN_RIGHT; text.psz_string = _("Right");
144         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
145         val.i_int = AOUT_VAR_CHAN_RSTEREO; text.psz_string=_("Reverse stereo");
146         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
147         if ( p_aout->output.output.i_original_channels & AOUT_CHAN_DUALMONO )
148         {
149             /* Go directly to the left channel. */
150             p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT;
151             var_SetInteger( p_aout, "audio-channels", AOUT_VAR_CHAN_LEFT );
152         }
153         var_AddCallback( p_aout, "audio-channels", aout_ChannelsRestart,
154                          NULL );
155     }
156     var_TriggerCallback( p_aout, "intf-change" );
157
158     aout_FormatPrepare( &p_aout->output.output );
159
160     /* Prepare FIFO. */
161     aout_FifoInit( p_aout, &p_aout->output.fifo, p_aout->output.output.i_rate );
162     aout_FormatPrint( p_aout, "output", &p_aout->output.output );
163
164     /* Calculate the resulting mixer output format. */
165     p_aout->mixer_format = p_aout->output.output;
166     if ( !AOUT_FMT_NON_LINEAR(&p_aout->output.output) )
167     {
168         /* Non-S/PDIF mixer only deals with float32 or fixed32. */
169         p_aout->mixer_format.i_format
170                      = HAVE_FPU ? VLC_CODEC_FL32 : VLC_CODEC_FI32;
171         aout_FormatPrepare( &p_aout->mixer_format );
172     }
173     else
174     {
175         p_aout->mixer_format.i_format = p_format->i_format;
176     }
177
178     aout_FormatPrint( p_aout, "mixer", &p_aout->mixer_format );
179
180     /* Create filters. */
181     p_aout->output.i_nb_filters = 0;
182     if ( aout_FiltersCreatePipeline( p_aout, p_aout->output.pp_filters,
183                                      &p_aout->output.i_nb_filters,
184                                      &p_aout->mixer_format,
185                                      &p_aout->output.output ) < 0 )
186     {
187         msg_Err( p_aout, "couldn't create audio output pipeline" );
188         module_unneed( p_aout, p_aout->output.p_module );
189         p_aout->output.p_module = NULL;
190         return -1;
191     }
192     return 0;
193 }
194
195 /*****************************************************************************
196  * aout_OutputDelete : delete the output
197  *****************************************************************************
198  * This function is entered with the mixer lock.
199  *****************************************************************************/
200 void aout_OutputDelete( aout_instance_t * p_aout )
201 {
202     vlc_assert_locked( &p_aout->lock );
203
204     if( p_aout->output.p_module == NULL )
205         return;
206
207     module_unneed( p_aout, p_aout->output.p_module );
208     p_aout->output.p_module = NULL;
209     aout_FiltersDestroyPipeline( p_aout->output.pp_filters,
210                                  p_aout->output.i_nb_filters );
211     aout_FifoDestroy( &p_aout->output.fifo );
212 }
213
214 /*****************************************************************************
215  * aout_OutputPlay : play a buffer
216  *****************************************************************************
217  * This function is entered with the mixer lock.
218  *****************************************************************************/
219 void aout_OutputPlay( aout_instance_t * p_aout, aout_buffer_t * p_buffer )
220 {
221     vlc_assert_locked( &p_aout->lock );
222
223     aout_FiltersPlay( p_aout->output.pp_filters, p_aout->output.i_nb_filters,
224                       &p_buffer );
225     if( !p_buffer )
226         return;
227     if( p_buffer->i_buffer == 0 )
228     {
229         block_Release( p_buffer );
230         return;
231     }
232
233     aout_FifoPush( &p_aout->output.fifo, p_buffer );
234     p_aout->output.pf_play( p_aout );
235 }
236
237 /**
238  * Notifies the audio output (if any) of pause/resume events.
239  * This enables the output to expedite pause, instead of waiting for its
240  * buffers to drain.
241  */
242 void aout_OutputPause( aout_instance_t *aout, bool pause, mtime_t date )
243 {
244     vlc_assert_locked( &aout->lock );
245
246     if( aout->output.pf_pause != NULL )
247         aout->output.pf_pause( aout, pause, date );
248 }
249
250 /*****************************************************************************
251  * aout_OutputNextBuffer : give the audio output plug-in the right buffer
252  *****************************************************************************
253  * If b_can_sleek is 1, the aout core functions won't try to resample
254  * new buffers to catch up - that is we suppose that the output plug-in can
255  * compensate it by itself. S/PDIF outputs should always set b_can_sleek = 1.
256  * This function is entered with no lock at all :-).
257  *****************************************************************************/
258 aout_buffer_t * aout_OutputNextBuffer( aout_instance_t * p_aout,
259                                        mtime_t start_date,
260                                        bool b_can_sleek )
261 {
262     aout_fifo_t *p_fifo = &p_aout->output.fifo;
263     aout_buffer_t * p_buffer;
264     mtime_t now = mdate();
265
266     aout_lock( p_aout );
267
268     /* Drop the audio sample if the audio output is really late.
269      * In the case of b_can_sleek, we don't use a resampler so we need to be
270      * a lot more severe. */
271     while( ((p_buffer = p_fifo->p_first) != NULL)
272      && p_buffer->i_pts < (b_can_sleek ? start_date : now) - AOUT_PTS_TOLERANCE )
273     {
274         msg_Dbg( p_aout, "audio output is too slow (%"PRId64"), "
275                  "trashing %"PRId64"us", now - p_buffer->i_pts,
276                  p_buffer->i_length );
277         aout_BufferFree( aout_FifoPop( p_fifo ) );
278     }
279
280     if( p_buffer == NULL )
281     {
282 #if 0 /* This is bad because the audio output might just be trying to fill
283        * in its internal buffers. And anyway, it's up to the audio output
284        * to deal with this kind of starvation. */
285
286         /* Set date to 0, to allow the mixer to send a new buffer ASAP */
287         aout_FifoSet( &p_aout->output.fifo, 0 );
288         if ( !p_aout->output.b_starving )
289             msg_Dbg( p_aout,
290                  "audio output is starving (no input), playing silence" );
291         p_aout->output.b_starving = true;
292 #endif
293         goto out;
294     }
295
296     mtime_t delta = start_date - p_buffer->i_pts;
297     /* Here we suppose that all buffers have the same duration - this is
298      * generally true, and anyway if it's wrong it won't be a disaster.
299      */
300     if ( 0 > delta + p_buffer->i_length )
301     /*
302      *                   + AOUT_PTS_TOLERANCE )
303      * There is no reason to want that, it just worsen the scheduling of
304      * an audio sample after an output starvation (ie. on start or on resume)
305      * --Gibalou
306      */
307     {
308         if ( !p_aout->output.b_starving )
309             msg_Dbg( p_aout, "audio output is starving (%"PRId64"), "
310                      "playing silence", -delta );
311         p_aout->output.b_starving = true;
312         p_buffer = NULL;
313         goto out;
314     }
315
316     p_aout->output.b_starving = false;
317     p_buffer = aout_FifoPop( p_fifo );
318
319     if( !b_can_sleek )
320     {
321         if( delta > AOUT_PTS_TOLERANCE || delta < -AOUT_PTS_TOLERANCE )
322         {
323             /* Try to compensate the drift by doing some resampling. */
324             msg_Warn( p_aout, "output date isn't PTS date, requesting "
325                       "resampling (%"PRId64")", delta );
326
327             aout_FifoMoveDates( &p_aout->p_input->mixer.fifo, delta );
328             aout_FifoMoveDates( p_fifo, delta );
329         }
330     }
331 out:
332     aout_unlock( p_aout );
333     return p_buffer;
334 }