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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
34 #include <vlc_common.h>
36 #include <vlc_aout_intf.h>
38 #include <vlc_modules.h>
41 #include "aout_internal.h"
43 /*****************************************************************************
44 * aout_OutputNew : allocate a new output and rework the filter pipeline
45 *****************************************************************************
46 * This function is entered with the mixer lock.
47 *****************************************************************************/
48 int aout_OutputNew( audio_output_t *p_aout,
49 const audio_sample_format_t * p_format )
51 aout_owner_t *owner = aout_owner (p_aout);
53 aout_assert_locked( p_aout );
54 p_aout->format = *p_format;
56 aout_FormatPrepare( &p_aout->format );
58 /* Find the best output plug-in. */
59 owner->module = module_need (p_aout, "audio output", "$aout", false);
60 if (owner->module == NULL)
62 msg_Err( p_aout, "no suitable audio output module" );
66 if ( var_Type( p_aout, "audio-channels" ) ==
67 (VLC_VAR_INTEGER | VLC_VAR_HASCHOICE) )
69 /* The user may have selected a different channels configuration. */
70 switch( var_InheritInteger( p_aout, "audio-channels" ) )
72 case AOUT_VAR_CHAN_RSTEREO:
73 p_aout->format.i_original_channels |= AOUT_CHAN_REVERSESTEREO;
75 case AOUT_VAR_CHAN_STEREO:
76 p_aout->format.i_original_channels =
77 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
79 case AOUT_VAR_CHAN_LEFT:
80 p_aout->format.i_original_channels = AOUT_CHAN_LEFT;
82 case AOUT_VAR_CHAN_RIGHT:
83 p_aout->format.i_original_channels = AOUT_CHAN_RIGHT;
85 case AOUT_VAR_CHAN_DOLBYS:
86 p_aout->format.i_original_channels =
87 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_DOLBYSTEREO;
91 else if ( p_aout->format.i_physical_channels == AOUT_CHAN_CENTER
92 && (p_aout->format.i_original_channels
93 & AOUT_CHAN_PHYSMASK) == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) )
95 vlc_value_t val, text;
97 /* Mono - create the audio-channels variable. */
98 var_Create( p_aout, "audio-channels",
99 VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
100 text.psz_string = _("Audio Channels");
101 var_Change( p_aout, "audio-channels", VLC_VAR_SETTEXT, &text, NULL );
103 val.i_int = AOUT_VAR_CHAN_STEREO; text.psz_string = _("Stereo");
104 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
105 val.i_int = AOUT_VAR_CHAN_LEFT; text.psz_string = _("Left");
106 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
107 val.i_int = AOUT_VAR_CHAN_RIGHT; text.psz_string = _("Right");
108 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
109 if ( p_aout->format.i_original_channels & AOUT_CHAN_DUALMONO )
111 /* Go directly to the left channel. */
112 p_aout->format.i_original_channels = AOUT_CHAN_LEFT;
113 var_SetInteger( p_aout, "audio-channels", AOUT_VAR_CHAN_LEFT );
115 var_AddCallback( p_aout, "audio-channels", aout_ChannelsRestart,
118 else if ( p_aout->format.i_physical_channels ==
119 (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)
120 && (p_aout->format.i_original_channels &
121 (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
123 vlc_value_t val, text;
125 /* Stereo - create the audio-channels variable. */
126 var_Create( p_aout, "audio-channels",
127 VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
128 text.psz_string = _("Audio Channels");
129 var_Change( p_aout, "audio-channels", VLC_VAR_SETTEXT, &text, NULL );
131 if ( p_aout->format.i_original_channels & AOUT_CHAN_DOLBYSTEREO )
133 val.i_int = AOUT_VAR_CHAN_DOLBYS;
134 text.psz_string = _("Dolby Surround");
138 val.i_int = AOUT_VAR_CHAN_STEREO;
139 text.psz_string = _("Stereo");
141 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
142 val.i_int = AOUT_VAR_CHAN_LEFT; text.psz_string = _("Left");
143 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
144 val.i_int = AOUT_VAR_CHAN_RIGHT; text.psz_string = _("Right");
145 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
146 val.i_int = AOUT_VAR_CHAN_RSTEREO; text.psz_string=_("Reverse stereo");
147 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
148 if ( p_aout->format.i_original_channels & AOUT_CHAN_DUALMONO )
150 /* Go directly to the left channel. */
151 p_aout->format.i_original_channels = AOUT_CHAN_LEFT;
152 var_SetInteger( p_aout, "audio-channels", AOUT_VAR_CHAN_LEFT );
154 var_AddCallback( p_aout, "audio-channels", aout_ChannelsRestart,
157 var_TriggerCallback( p_aout, "intf-change" );
159 aout_FormatPrepare( &p_aout->format );
160 aout_FormatPrint( p_aout, "output", &p_aout->format );
162 /* Choose the mixer format. */
163 owner->mixer_format = p_aout->format;
164 if (!AOUT_FMT_LINEAR(&p_aout->format))
165 owner->mixer_format.i_format = p_format->i_format;
167 /* Most audio filters can only deal with single-precision,
168 * so lets always use that when hardware supports floating point. */
170 owner->mixer_format.i_format = VLC_CODEC_FL32;
172 /* Otherwise, audio filters will not work. Use fixed-point if the input has
173 * more than 16-bits depth. */
174 if( p_format->i_bitspersample > 16 || !AOUT_FMT_LINEAR(p_format))
175 owner->mixer_format.i_format = VLC_CODEC_FI32;
177 /* Fallback to 16-bits. This avoids pointless conversion to and from
178 * 32-bits samples for the sole purpose of software mixing. */
179 owner->mixer_format.i_format = VLC_CODEC_S16N;
181 aout_FormatPrepare (&owner->mixer_format);
182 aout_FormatPrint (p_aout, "mixer", &owner->mixer_format);
184 /* Create filters. */
185 owner->nb_filters = 0;
186 if (aout_FiltersCreatePipeline (p_aout, owner->filters,
187 &owner->nb_filters, &owner->mixer_format,
188 &p_aout->format) < 0)
190 msg_Err( p_aout, "couldn't create audio output pipeline" );
191 module_unneed (p_aout, owner->module);
192 owner->module = NULL;
199 * Destroys the audio output plug-in instance.
201 void aout_OutputDelete (audio_output_t *aout)
203 aout_owner_t *owner = aout_owner (aout);
205 aout_assert_locked (aout);
207 if (owner->module == NULL)
210 module_unneed (aout, owner->module);
211 /* Clear callbacks */
212 aout->pf_play = aout_DecDeleteBuffer; /* gruik */
213 aout->pf_pause = NULL;
214 aout->pf_flush = NULL;
215 aout_VolumeNoneInit (aout);
216 owner->module = NULL;
217 aout_FiltersDestroyPipeline (owner->filters, owner->nb_filters);
221 * Plays a decoded audio buffer.
223 void aout_OutputPlay (audio_output_t *aout, block_t *block)
225 aout_owner_t *owner = aout_owner (aout);
227 aout_assert_locked (aout);
229 aout_FiltersPlay (owner->filters, owner->nb_filters, &block);
232 if (block->i_buffer == 0)
234 block_Release (block);
238 aout->pf_play (aout, block);
242 * Notifies the audio output (if any) of pause/resume events.
243 * This enables the output to expedite pause, instead of waiting for its
246 void aout_OutputPause( audio_output_t *aout, bool pause, mtime_t date )
248 aout_assert_locked( aout );
249 if( aout->pf_pause != NULL )
250 aout->pf_pause( aout, pause, date );
254 * Flushes or drains the audio output buffers.
255 * This enables the output to expedite seek and stop.
256 * @param wait if true, wait for buffer playback (i.e. drain),
257 * if false, discard the buffers immediately (i.e. flush)
259 void aout_OutputFlush( audio_output_t *aout, bool wait )
261 aout_assert_locked( aout );
263 if( aout->pf_flush != NULL )
264 aout->pf_flush( aout, wait );
268 /*** Volume handling ***/
271 * Dummy volume setter. This is the default volume setter.
273 static int aout_VolumeNoneSet (audio_output_t *aout, float volume, bool mute)
275 (void)aout; (void)volume; (void)mute;
280 * Configures the dummy volume setter.
281 * @note Audio output plugins for which volume is irrelevant
282 * should call this function during activation.
284 void aout_VolumeNoneInit (audio_output_t *aout)
286 /* aout_New() -safely- calls this function without the lock, before any
287 * other thread knows of this audio output instance.
288 aout_assert_locked (aout); */
289 aout->pf_volume_set = aout_VolumeNoneSet;
290 var_Destroy (aout, "volume");
291 var_Destroy (aout, "mute");
295 * Volume setter for software volume.
297 static int aout_VolumeSoftSet (audio_output_t *aout, float volume, bool mute)
299 aout_owner_t *owner = aout_owner (aout);
301 aout_assert_locked (aout);
303 /* Cubic mapping from software volume to amplification factor.
304 * This provides a good tradeoff between low and high volume ranges.
306 * This code is only used for the VLC software mixer. If you change this
307 * formula, be sure to update the aout_VolumeHardInit()-based plugins also.
310 volume = volume * volume * volume;
314 owner->volume.multiplier = volume;
319 * Configures the volume setter for software mixing
320 * and apply the default volume.
321 * @note Audio output plugins that cannot apply the volume
322 * should call this function during activation.
324 void aout_VolumeSoftInit (audio_output_t *aout)
326 audio_volume_t volume = var_InheritInteger (aout, "volume");
327 bool mute = var_InheritBool (aout, "mute");
329 aout_assert_locked (aout);
330 aout->pf_volume_set = aout_VolumeSoftSet;
331 aout_VolumeSoftSet (aout, volume / (float)AOUT_VOLUME_DEFAULT, mute);
335 * Configures a custom volume setter. This is used by audio outputs that can
336 * control the hardware volume directly and/or emulate it internally.
337 * @param setter volume setter callback
339 void aout_VolumeHardInit (audio_output_t *aout, aout_volume_cb setter)
341 aout_assert_locked (aout);
342 aout->pf_volume_set = setter;
343 var_Create (aout, "volume", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT);
344 var_Create (aout, "mute", VLC_VAR_BOOL|VLC_VAR_DOINHERIT);
348 * Supply or update the current custom ("hardware") volume.
349 * @note This only makes sense after calling aout_VolumeHardInit().
350 * @param setter volume setter callback
351 * @param volume current custom volume
352 * @param mute current mute flag
354 * @warning The caller (i.e. the audio output plug-in) is responsible for
355 * interlocking and synchronizing call to this function and to the
356 * audio_output_t.pf_volume_set callback. This ensures that VLC gets correct
357 * volume information (possibly with a latency).
359 void aout_VolumeHardSet (audio_output_t *aout, float volume, bool mute)
361 audio_volume_t vol = lroundf (volume * (float)AOUT_VOLUME_DEFAULT);
363 /* We cannot acquire the volume lock as this gets called from the audio
364 * output plug-in (it would cause a lock inversion). */
365 var_SetInteger (aout, "volume", vol);
366 var_SetBool (aout, "mute", mute);
367 var_TriggerCallback (aout, "intf-change");
371 /*** Packet-oriented audio output support ***/
373 static inline aout_packet_t *aout_packet (audio_output_t *aout)
375 return (aout_packet_t *)(aout->sys);
378 void aout_PacketInit (audio_output_t *aout, aout_packet_t *p, unsigned samples)
380 assert (p == aout_packet (aout));
382 vlc_mutex_init (&p->lock);
383 aout_FifoInit (aout, &p->partial, aout->format.i_rate);
384 aout_FifoInit (aout, &p->fifo, aout->format.i_rate);
385 p->pause_date = VLC_TS_INVALID;
386 p->time_report = VLC_TS_INVALID;
387 p->samples = samples;
391 void aout_PacketDestroy (audio_output_t *aout)
393 aout_packet_t *p = aout_packet (aout);
395 aout_FifoDestroy (&p->partial);
396 aout_FifoDestroy (&p->fifo);
397 vlc_mutex_destroy (&p->lock);
400 static block_t *aout_OutputSlice (audio_output_t *);
402 void aout_PacketPlay (audio_output_t *aout, block_t *block)
404 aout_packet_t *p = aout_packet (aout);
407 vlc_mutex_lock (&p->lock);
408 aout_FifoPush (&p->partial, block);
409 while ((block = aout_OutputSlice (aout)) != NULL)
410 aout_FifoPush (&p->fifo, block);
412 time_report = p->time_report;
413 p->time_report = VLC_TS_INVALID;
414 vlc_mutex_unlock (&p->lock);
416 if (time_report != VLC_TS_INVALID)
417 aout_TimeReport (aout, mdate () - time_report);
420 void aout_PacketPause (audio_output_t *aout, bool pause, mtime_t date)
422 aout_packet_t *p = aout_packet (aout);
426 assert (p->pause_date == VLC_TS_INVALID);
427 p->pause_date = date;
431 assert (p->pause_date != VLC_TS_INVALID);
433 mtime_t duration = date - p->pause_date;
435 p->pause_date = VLC_TS_INVALID;
436 vlc_mutex_lock (&p->lock);
437 aout_FifoMoveDates (&p->partial, duration);
438 aout_FifoMoveDates (&p->fifo, duration);
439 vlc_mutex_unlock (&p->lock);
443 void aout_PacketFlush (audio_output_t *aout, bool drain)
445 aout_packet_t *p = aout_packet (aout);
447 vlc_mutex_lock (&p->lock);
448 aout_FifoReset (&p->partial);
449 aout_FifoReset (&p->fifo);
450 vlc_mutex_unlock (&p->lock);
452 (void) drain; /* TODO */
457 * Rearranges audio blocks in correct number of samples.
458 * @note (FIXME) This is left here for historical reasons. It belongs in the
459 * output code. Besides, this operation should be avoided if possible.
461 static block_t *aout_OutputSlice (audio_output_t *p_aout)
463 aout_packet_t *p = aout_packet (p_aout);
464 aout_fifo_t *p_fifo = &p->partial;
465 const unsigned samples = p->samples;
466 assert( samples > 0 );
468 vlc_assert_locked( &p->lock );
470 /* Retrieve the date of the next buffer. */
471 date_t exact_start_date = p->fifo.end_date;
472 mtime_t start_date = date_Get( &exact_start_date );
474 /* See if we have enough data to prepare a new buffer for the audio output. */
475 aout_buffer_t *p_buffer = p_fifo->p_first;
476 if( p_buffer == NULL )
479 /* Find the earliest start date available. */
480 if ( start_date == VLC_TS_INVALID )
482 start_date = p_buffer->i_pts;
483 date_Set( &exact_start_date, start_date );
485 /* Compute the end date for the new buffer. */
486 mtime_t end_date = date_Increment( &exact_start_date, samples );
488 /* Check that we have enough samples (TODO merge with next loop). */
489 for( unsigned available = 0; available < samples; )
491 p_buffer = p_buffer->p_next;
492 if( p_buffer == NULL )
495 available += p_buffer->i_nb_samples;
498 if( AOUT_FMT_LINEAR( &p_aout->format ) )
500 const unsigned framesize = p_aout->format.i_bytes_per_frame;
501 /* Build packet with adequate number of samples */
502 unsigned needed = samples * framesize;
504 p_buffer = block_Alloc( needed );
505 if( unlikely(p_buffer == NULL) )
506 /* XXX: should free input buffers */
508 p_buffer->i_nb_samples = samples;
510 for( uint8_t *p_out = p_buffer->p_buffer; needed > 0; )
512 aout_buffer_t *p_inbuf = p_fifo->p_first;
513 if( unlikely(p_inbuf == NULL) )
515 msg_Err( p_aout, "packetization error" );
516 vlc_memset( p_out, 0, needed );
520 const uint8_t *p_in = p_inbuf->p_buffer;
521 size_t avail = p_inbuf->i_nb_samples * framesize;
524 vlc_memcpy( p_out, p_in, needed );
525 p_fifo->p_first->p_buffer += needed;
526 p_fifo->p_first->i_buffer -= needed;
528 p_fifo->p_first->i_nb_samples -= needed;
530 mtime_t t = needed * CLOCK_FREQ / p_aout->format.i_rate;
531 p_fifo->p_first->i_pts += t;
532 p_fifo->p_first->i_length -= t;
536 vlc_memcpy( p_out, p_in, avail );
540 aout_BufferFree( aout_FifoPop( p_fifo ) );
544 p_buffer = aout_FifoPop( p_fifo );
546 p_buffer->i_pts = start_date;
547 p_buffer->i_length = end_date - start_date;
553 * Dequeues the next audio packet (a.k.a. audio fragment).
554 * The audio output plugin must first call aout_PacketPlay() to queue the
555 * decoded audio samples. Typically, audio_output_t.pf_play is set to, or calls
557 * @note This function is considered legacy. Please do not use this function in
558 * new audio output plugins.
559 * @param p_aout audio output instance
560 * @param start_date expected PTS of the audio packet
562 block_t *aout_PacketNext (audio_output_t *p_aout, mtime_t start_date)
564 aout_packet_t *p = aout_packet (p_aout);
565 aout_fifo_t *p_fifo = &p->fifo;
567 const bool b_can_sleek = !AOUT_FMT_LINEAR(&p_aout->format);
568 const mtime_t now = mdate ();
569 const mtime_t threshold =
570 (b_can_sleek ? start_date : now) - AOUT_MAX_PTS_DELAY;
572 vlc_mutex_lock( &p->lock );
573 if( p->pause_date != VLC_TS_INVALID )
574 goto out; /* paused: do not dequeue buffers */
578 p_buffer = p_fifo->p_first;
579 if (p_buffer == NULL)
580 goto out; /* nothing to play */
582 if (p_buffer->i_pts >= threshold)
585 /* Drop the audio sample if the audio output is really late.
586 * In the case of b_can_sleek, we don't use a resampler so we need to
587 * be a lot more severe. */
588 msg_Dbg (p_aout, "audio output is too slow (%"PRId64" us): "
589 " trashing %"PRId64" us", threshold - p_buffer->i_pts,
591 block_Release (aout_FifoPop (p_fifo));
594 mtime_t delta = start_date - p_buffer->i_pts;
595 /* This assumes that all buffers have the same duration. This is true
596 * since aout_PacketPlay() (aout_OutputSlice()) is used. */
597 if (0 >= delta + p_buffer->i_length)
601 msg_Dbg (p_aout, "audio output is starving (%"PRId64"), "
602 "playing silence", delta);
605 goto out; /* nothing to play _yet_ */
609 p_buffer = aout_FifoPop( p_fifo );
612 && (delta < -AOUT_MAX_PTS_ADVANCE || AOUT_MAX_PTS_DELAY < delta))
614 msg_Warn (p_aout, "audio output out of sync, "
615 "adjusting dates (%"PRId64" us)", delta);
616 aout_FifoMoveDates (&p->partial, delta);
617 aout_FifoMoveDates (p_fifo, delta);
618 p->time_report = delta;
620 vlc_mutex_unlock( &p->lock );
623 vlc_mutex_unlock( &p->lock );