Commit dbd8e30b authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

aout: use event callbacks for time and volume/mute

This would allow creating audio output objects in different context.
parent 0c097799
...@@ -151,6 +151,12 @@ struct audio_output ...@@ -151,6 +151,12 @@ struct audio_output
void (* pf_flush)( audio_output_t *, bool ); /**< Flush/drain callback void (* pf_flush)( audio_output_t *, bool ); /**< Flush/drain callback
(optional, may be NULL) */ (optional, may be NULL) */
aout_volume_cb pf_volume_set; /**< Volume setter (or NULL) */ aout_volume_cb pf_volume_set; /**< Volume setter (or NULL) */
struct {
void (*time_report)(audio_output_t *, mtime_t);
void (*volume_report)(audio_output_t *, float);
void (*mute_report)(audio_output_t *, bool);
} event;
}; };
/** /**
...@@ -219,9 +225,17 @@ VLC_API const char * aout_FormatPrintChannels( const audio_sample_format_t * ) V ...@@ -219,9 +225,17 @@ VLC_API const char * aout_FormatPrintChannels( const audio_sample_format_t * ) V
VLC_API void aout_VolumeSoftInit( audio_output_t * ); VLC_API void aout_VolumeSoftInit( audio_output_t * );
VLC_API void aout_VolumeHardInit( audio_output_t *, aout_volume_cb, bool ); VLC_API void aout_VolumeHardInit( audio_output_t *, aout_volume_cb, bool );
VLC_API void aout_VolumeHardSet( audio_output_t *, float, bool );
VLC_API void aout_TimeReport(audio_output_t *, mtime_t); static inline void aout_VolumeHardSet(audio_output_t *aout, float v, bool m)
{
aout->event.volume_report(aout, v);
aout->event.mute_report(aout, m);
}
static inline void aout_TimeReport(audio_output_t *aout, mtime_t date)
{
aout->event.time_report(aout, date);
}
VLC_API int aout_ChannelsRestart( vlc_object_t *, const char *, vlc_value_t, vlc_value_t, void * ); VLC_API int aout_ChannelsRestart( vlc_object_t *, const char *, vlc_value_t, vlc_value_t, void * );
......
...@@ -381,49 +381,6 @@ bool aout_DecIsEmpty (audio_output_t *aout) ...@@ -381,49 +381,6 @@ bool aout_DecIsEmpty (audio_output_t *aout)
return empty; return empty;
} }
/**
* Notifies the audio input of the drift from the requested audio
* playback timestamp (@ref block_t.i_pts) to the anticipated playback time
* as reported by the audio output hardware.
* Depending on the drift amplitude, the input core may ignore the drift
* trigger upsampling or downsampling, or even discard samples.
* Future VLC versions may instead adjust the input decoding speed.
*
* The audio output plugin is responsible for estimating the ideal current
* playback time defined as follows:
* ideal time = buffer timestamp - (output latency + pending buffer duration)
*
* Practically, this is the PTS (block_t.i_pts) of the current buffer minus
* the latency reported by the output programming interface.
* Computing the estimated drift directly would probably be more intuitive.
* However the use of an absolute time value does not introduce extra
* measurement errors due to the CPU scheduling jitter and clock resolution.
* Furthermore, the ideal while it is an abstract value, is easy for most
* audio output plugins to compute.
* The following definition is equivalent but depends on the clock time:
* ideal time = real time + drift
* @note If aout_LatencyReport() is never called, the core will assume that
* there is no drift.
*
* @param ideal estimated ideal time as defined above.
*/
void aout_TimeReport (audio_output_t *aout, mtime_t ideal)
{
mtime_t delta = mdate() - ideal /* = -drift */;
aout_assert_locked (aout);
if (delta < -AOUT_MAX_PTS_ADVANCE || +AOUT_MAX_PTS_DELAY < delta)
{
aout_owner_t *owner = aout_owner (aout);
msg_Warn (aout, "not synchronized (%"PRId64" us), resampling",
delta);
if (date_Get (&owner->sync.date) != VLC_TS_INVALID)
date_Move (&owner->sync.date, delta);
}
}
static int ReplayGainCallback (vlc_object_t *obj, char const *var, static int ReplayGainCallback (vlc_object_t *obj, char const *var,
vlc_value_t oldval, vlc_value_t val, void *data) vlc_value_t oldval, vlc_value_t val, void *data)
{ {
......
...@@ -21,9 +21,6 @@ ...@@ -21,9 +21,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/ *****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include "config.h" # include "config.h"
#endif #endif
...@@ -39,6 +36,73 @@ ...@@ -39,6 +36,73 @@
#include "libvlc.h" #include "libvlc.h"
#include "aout_internal.h" #include "aout_internal.h"
/**
* Notifies the audio input of the drift from the requested audio
* playback timestamp (@ref block_t.i_pts) to the anticipated playback time
* as reported by the audio output hardware.
* Depending on the drift amplitude, the input core may ignore the drift
* trigger upsampling or downsampling, or even discard samples.
* Future VLC versions may instead adjust the input decoding speed.
*
* The audio output plugin is responsible for estimating the ideal current
* playback time defined as follows:
* ideal time = buffer timestamp - (output latency + pending buffer duration)
*
* Practically, this is the PTS (block_t.i_pts) of the current buffer minus
* the latency reported by the output programming interface.
* Computing the estimated drift directly would probably be more intuitive.
* However the use of an absolute time value does not introduce extra
* measurement errors due to the CPU scheduling jitter and clock resolution.
* Furthermore, the ideal while it is an abstract value, is easy for most
* audio output plugins to compute.
* The following definition is equivalent but depends on the clock time:
* ideal time = real time + drift
* @note If aout_LatencyReport() is never called, the core will assume that
* there is no drift.
*
* @param ideal estimated ideal time as defined above.
*/
static void aout_OutputTimeReport (audio_output_t *aout, mtime_t ideal)
{
mtime_t delta = mdate() - ideal /* = -drift */;
aout_assert_locked (aout);
if (delta < -AOUT_MAX_PTS_ADVANCE || +AOUT_MAX_PTS_DELAY < delta)
{
aout_owner_t *owner = aout_owner (aout);
msg_Warn (aout, "not synchronized (%"PRId64" us), resampling",
delta);
if (date_Get (&owner->sync.date) != VLC_TS_INVALID)
date_Move (&owner->sync.date, delta);
}
}
/**
* Supply or update the current custom ("hardware") volume.
* @note This only makes sense after calling aout_VolumeHardInit().
* @param volume current custom volume
*
* @warning The caller (i.e. the audio output plug-in) is responsible for
* interlocking and synchronizing call to this function and to the
* audio_output_t.pf_volume_set callback. This ensures that VLC gets correct
* volume information (possibly with a latency).
*/
static void aout_OutputVolumeReport (audio_output_t *aout, float volume)
{
audio_volume_t vol = lroundf (volume * (float)AOUT_VOLUME_DEFAULT);
/* We cannot acquire the volume lock as this gets called from the audio
* output plug-in (it would cause a lock inversion). */
var_SetInteger (aout, "volume", vol);
}
static void aout_OutputMuteReport (audio_output_t *aout, bool mute)
{
var_SetBool (aout, "mute", mute);
}
/***************************************************************************** /*****************************************************************************
* aout_OutputNew : allocate a new output and rework the filter pipeline * aout_OutputNew : allocate a new output and rework the filter pipeline
***************************************************************************** *****************************************************************************
...@@ -51,9 +115,12 @@ int aout_OutputNew( audio_output_t *p_aout, ...@@ -51,9 +115,12 @@ int aout_OutputNew( audio_output_t *p_aout,
aout_assert_locked( p_aout ); aout_assert_locked( p_aout );
p_aout->format = *p_format; p_aout->format = *p_format;
aout_FormatPrepare( &p_aout->format ); aout_FormatPrepare( &p_aout->format );
p_aout->event.time_report = aout_OutputTimeReport;
p_aout->event.volume_report = aout_OutputVolumeReport;
p_aout->event.mute_report = aout_OutputMuteReport;
/* Find the best output plug-in. */ /* Find the best output plug-in. */
owner->module = module_need (p_aout, "audio output", "$aout", false); owner->module = module_need (p_aout, "audio output", "$aout", false);
if (owner->module == NULL) if (owner->module == NULL)
...@@ -325,25 +392,3 @@ void aout_VolumeHardInit (audio_output_t *aout, aout_volume_cb setter, ...@@ -325,25 +392,3 @@ void aout_VolumeHardInit (audio_output_t *aout, aout_volume_cb setter,
setter (aout, vol, var_GetBool (aout, "mute")); setter (aout, vol, var_GetBool (aout, "mute"));
} }
} }
/**
* Supply or update the current custom ("hardware") volume.
* @note This only makes sense after calling aout_VolumeHardInit().
* @param setter volume setter callback
* @param volume current custom volume
* @param mute current mute flag
*
* @warning The caller (i.e. the audio output plug-in) is responsible for
* interlocking and synchronizing call to this function and to the
* audio_output_t.pf_volume_set callback. This ensures that VLC gets correct
* volume information (possibly with a latency).
*/
void aout_VolumeHardSet (audio_output_t *aout, float volume, bool mute)
{
audio_volume_t vol = lroundf (volume * (float)AOUT_VOLUME_DEFAULT);
/* We cannot acquire the volume lock as this gets called from the audio
* output plug-in (it would cause a lock inversion). */
var_SetInteger (aout, "volume", vol);
var_SetBool (aout, "mute", mute);
}
...@@ -20,10 +20,8 @@ aout_VolumeUp ...@@ -20,10 +20,8 @@ aout_VolumeUp
aout_ToggleMute aout_ToggleMute
aout_IsMuted aout_IsMuted
aout_SetMute aout_SetMute
aout_TimeReport
aout_VolumeSoftInit aout_VolumeSoftInit
aout_VolumeHardInit aout_VolumeHardInit
aout_VolumeHardSet
block_Alloc block_Alloc
block_FifoCount block_FifoCount
block_FifoEmpty block_FifoEmpty
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment