1 /*****************************************************************************
2 * output.c : internal management of output streams for the audio output
3 *****************************************************************************
4 * Copyright (C) 2002-2004 VLC authors and VideoLAN
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
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 Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
30 #include <vlc_common.h>
32 #include <vlc_aout_intf.h>
34 #include <vlc_modules.h>
37 #include "aout_internal.h"
40 * Notifies the audio input of the drift from the requested audio
41 * playback timestamp (@ref block_t.i_pts) to the anticipated playback time
42 * as reported by the audio output hardware.
43 * Depending on the drift amplitude, the input core may ignore the drift
44 * trigger upsampling or downsampling, or even discard samples.
45 * Future VLC versions may instead adjust the input decoding speed.
47 * The audio output plugin is responsible for estimating the ideal current
48 * playback time defined as follows:
49 * ideal time = buffer timestamp - (output latency + pending buffer duration)
51 * Practically, this is the PTS (block_t.i_pts) of the current buffer minus
52 * the latency reported by the output programming interface.
53 * Computing the estimated drift directly would probably be more intuitive.
54 * However the use of an absolute time value does not introduce extra
55 * measurement errors due to the CPU scheduling jitter and clock resolution.
56 * Furthermore, the ideal while it is an abstract value, is easy for most
57 * audio output plugins to compute.
58 * The following definition is equivalent but depends on the clock time:
59 * ideal time = real time + drift
61 * @note If aout_LatencyReport() is never called, the core will assume that
64 * @param ideal estimated ideal time as defined above.
66 static void aout_OutputTimeReport (audio_output_t *aout, mtime_t ideal)
68 mtime_t delta = mdate() - ideal /* = -drift */;
70 aout_assert_locked (aout);
71 if (delta < -AOUT_MAX_PTS_ADVANCE || +AOUT_MAX_PTS_DELAY < delta)
73 aout_owner_t *owner = aout_owner (aout);
75 msg_Warn (aout, "not synchronized (%"PRId64" us), resampling",
77 if (date_Get (&owner->sync.date) != VLC_TS_INVALID)
78 date_Move (&owner->sync.date, delta);
83 * Supply or update the current custom ("hardware") volume.
84 * @note This only makes sense after calling aout_VolumeHardInit().
85 * @param volume current custom volume
87 * @warning The caller (i.e. the audio output plug-in) is responsible for
88 * interlocking and synchronizing call to this function and to the
89 * audio_output_t.pf_volume_set callback. This ensures that VLC gets correct
90 * volume information (possibly with a latency).
92 static void aout_OutputVolumeReport (audio_output_t *aout, float volume)
94 long vol = lroundf (volume * (float)AOUT_VOLUME_DEFAULT);
96 /* We cannot acquire the volume lock as this gets called from the audio
97 * output plug-in (it would cause a lock inversion). */
98 var_SetInteger (aout, "volume", vol);
101 static void aout_OutputMuteReport (audio_output_t *aout, bool mute)
103 var_SetBool (aout, "mute", mute);
106 static int aout_OutputGainRequest (audio_output_t *aout, float gain)
108 aout_owner_t *owner = aout_owner (aout);
110 aout_assert_locked (aout);
111 aout_volume_SetVolume (owner->volume, gain);
112 /* XXX: ideally, return -1 if format cannot be amplified */
116 /*****************************************************************************
117 * aout_OutputNew : allocate a new output and rework the filter pipeline
118 *****************************************************************************
119 * This function is entered with the mixer lock.
120 *****************************************************************************/
121 int aout_OutputNew( audio_output_t *p_aout,
122 const audio_sample_format_t * p_format )
124 aout_owner_t *owner = aout_owner (p_aout);
126 aout_assert_locked( p_aout );
127 p_aout->format = *p_format;
128 aout_FormatPrepare( &p_aout->format );
130 p_aout->event.time_report = aout_OutputTimeReport;
131 p_aout->event.volume_report = aout_OutputVolumeReport;
132 p_aout->event.mute_report = aout_OutputMuteReport;
133 p_aout->event.gain_request = aout_OutputGainRequest;
135 /* Find the best output plug-in. */
136 owner->module = module_need (p_aout, "audio output", "$aout", false);
137 if (owner->module == NULL)
139 msg_Err( p_aout, "no suitable audio output module" );
143 if ( var_Type( p_aout, "audio-channels" ) ==
144 (VLC_VAR_INTEGER | VLC_VAR_HASCHOICE) )
146 /* The user may have selected a different channels configuration. */
147 switch( var_InheritInteger( p_aout, "audio-channels" ) )
149 case AOUT_VAR_CHAN_RSTEREO:
150 p_aout->format.i_original_channels |= AOUT_CHAN_REVERSESTEREO;
152 case AOUT_VAR_CHAN_STEREO:
153 p_aout->format.i_original_channels =
154 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
156 case AOUT_VAR_CHAN_LEFT:
157 p_aout->format.i_original_channels = AOUT_CHAN_LEFT;
159 case AOUT_VAR_CHAN_RIGHT:
160 p_aout->format.i_original_channels = AOUT_CHAN_RIGHT;
162 case AOUT_VAR_CHAN_DOLBYS:
163 p_aout->format.i_original_channels =
164 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_DOLBYSTEREO;
168 else if ( p_aout->format.i_physical_channels == AOUT_CHAN_CENTER
169 && (p_aout->format.i_original_channels
170 & AOUT_CHAN_PHYSMASK) == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) )
172 vlc_value_t val, text;
174 /* Mono - create the audio-channels variable. */
175 var_Create( p_aout, "audio-channels",
176 VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
177 text.psz_string = _("Audio Channels");
178 var_Change( p_aout, "audio-channels", VLC_VAR_SETTEXT, &text, NULL );
180 val.i_int = AOUT_VAR_CHAN_STEREO; text.psz_string = _("Stereo");
181 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
182 val.i_int = AOUT_VAR_CHAN_LEFT; text.psz_string = _("Left");
183 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
184 val.i_int = AOUT_VAR_CHAN_RIGHT; text.psz_string = _("Right");
185 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
186 if ( p_aout->format.i_original_channels & AOUT_CHAN_DUALMONO )
188 /* Go directly to the left channel. */
189 p_aout->format.i_original_channels = AOUT_CHAN_LEFT;
190 var_SetInteger( p_aout, "audio-channels", AOUT_VAR_CHAN_LEFT );
192 var_AddCallback( p_aout, "audio-channels", aout_ChannelsRestart,
195 else if ( p_aout->format.i_physical_channels ==
196 (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)
197 && (p_aout->format.i_original_channels &
198 (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
200 vlc_value_t val, text;
202 /* Stereo - create the audio-channels variable. */
203 var_Create( p_aout, "audio-channels",
204 VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
205 text.psz_string = _("Audio Channels");
206 var_Change( p_aout, "audio-channels", VLC_VAR_SETTEXT, &text, NULL );
208 if ( p_aout->format.i_original_channels & AOUT_CHAN_DOLBYSTEREO )
210 val.i_int = AOUT_VAR_CHAN_DOLBYS;
211 text.psz_string = _("Dolby Surround");
215 val.i_int = AOUT_VAR_CHAN_STEREO;
216 text.psz_string = _("Stereo");
218 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
219 val.i_int = AOUT_VAR_CHAN_LEFT; text.psz_string = _("Left");
220 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
221 val.i_int = AOUT_VAR_CHAN_RIGHT; text.psz_string = _("Right");
222 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
223 val.i_int = AOUT_VAR_CHAN_RSTEREO; text.psz_string=_("Reverse stereo");
224 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
225 if ( p_aout->format.i_original_channels & AOUT_CHAN_DUALMONO )
227 /* Go directly to the left channel. */
228 p_aout->format.i_original_channels = AOUT_CHAN_LEFT;
229 var_SetInteger( p_aout, "audio-channels", AOUT_VAR_CHAN_LEFT );
231 var_AddCallback( p_aout, "audio-channels", aout_ChannelsRestart,
235 aout_FormatPrepare( &p_aout->format );
236 aout_FormatPrint( p_aout, "output", &p_aout->format );
238 /* Choose the mixer format. */
239 owner->mixer_format = p_aout->format;
240 if (!AOUT_FMT_LINEAR(&p_aout->format))
241 owner->mixer_format.i_format = p_format->i_format;
243 /* Most audio filters can only deal with single-precision,
244 * so lets always use that when hardware supports floating point. */
246 owner->mixer_format.i_format = VLC_CODEC_FL32;
248 /* Fallback to 16-bits. This avoids pointless conversion to and from
249 * 32-bits samples for the sole purpose of software mixing. */
250 owner->mixer_format.i_format = VLC_CODEC_S16N;
252 aout_FormatPrepare (&owner->mixer_format);
253 aout_FormatPrint (p_aout, "mixer", &owner->mixer_format);
255 /* Create filters. */
256 owner->nb_filters = 0;
257 if (aout_FiltersCreatePipeline (p_aout, owner->filters,
258 &owner->nb_filters, &owner->mixer_format,
259 &p_aout->format) < 0)
261 msg_Err( p_aout, "couldn't create audio output pipeline" );
262 module_unneed (p_aout, owner->module);
263 owner->module = NULL;
270 * Destroys the audio output plug-in instance.
272 void aout_OutputDelete (audio_output_t *aout)
274 aout_owner_t *owner = aout_owner (aout);
276 aout_assert_locked (aout);
278 if (owner->module == NULL)
281 module_unneed (aout, owner->module);
282 /* Clear callbacks */
283 aout->pf_play = aout_DecDeleteBuffer; /* gruik */
284 aout->pf_pause = NULL;
285 aout->pf_flush = NULL;
286 aout->volume_set = NULL;
287 aout->mute_set = NULL;
288 owner->module = NULL;
289 aout_FiltersDestroyPipeline (owner->filters, owner->nb_filters);
293 * Plays a decoded audio buffer.
295 void aout_OutputPlay (audio_output_t *aout, block_t *block)
297 aout_owner_t *owner = aout_owner (aout);
299 aout_assert_locked (aout);
301 aout_FiltersPlay (owner->filters, owner->nb_filters, &block);
304 if (block->i_buffer == 0)
306 block_Release (block);
310 aout->pf_play (aout, block);
314 * Notifies the audio output (if any) of pause/resume events.
315 * This enables the output to expedite pause, instead of waiting for its
318 void aout_OutputPause( audio_output_t *aout, bool pause, mtime_t date )
320 aout_assert_locked( aout );
321 if( aout->pf_pause != NULL )
322 aout->pf_pause( aout, pause, date );
326 * Flushes or drains the audio output buffers.
327 * This enables the output to expedite seek and stop.
328 * @param wait if true, wait for buffer playback (i.e. drain),
329 * if false, discard the buffers immediately (i.e. flush)
331 void aout_OutputFlush( audio_output_t *aout, bool wait )
333 aout_assert_locked( aout );
335 if( aout->pf_flush != NULL )
336 aout->pf_flush( aout, wait );