alsa: support fixed latency range in alsa modules

This adds a boolean module parameter to disable automatic dynamic
latency readjustments on underruns, but leaves automatic dynamic
watermark readjustments untouched.
This commit is contained in:
Lars R. Damerow 2011-11-03 21:14:45 +01:00 committed by Lennart Poettering
parent 6124bf8951
commit 7a387fed36
5 changed files with 47 additions and 10 deletions

View file

@ -134,7 +134,7 @@ struct userdata {
char *device_name; /* name of the PCM device */
char *control_device; /* name of the control device */
pa_bool_t use_mmap:1, use_tsched:1, deferred_volume:1;
pa_bool_t use_mmap:1, use_tsched:1, deferred_volume:1, fixed_latency_range:1;
pa_bool_t first, after_rewind;
@ -331,7 +331,12 @@ static void increase_watermark(struct userdata *u) {
return;
}
/* Hmm, we cannot increase the watermark any further, hence let's raise the latency */
/* Hmm, we cannot increase the watermark any further, hence let's
raise the latency, unless doing so was disabled in
configuration */
if (u->fixed_latency_range)
return;
old_min_latency = u->sink->thread_info.min_latency;
new_min_latency = PA_MIN(old_min_latency * 2, old_min_latency + TSCHED_WATERMARK_INC_STEP_USEC);
new_min_latency = PA_MIN(new_min_latency, u->sink->thread_info.max_latency);
@ -1969,7 +1974,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
uint32_t nfrags, frag_size, buffer_size, tsched_size, tsched_watermark, rewind_safeguard;
snd_pcm_uframes_t period_frames, buffer_frames, tsched_frames;
size_t frame_size;
pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE, namereg_fail = FALSE, deferred_volume = FALSE, set_formats = FALSE;
pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE, namereg_fail = FALSE, deferred_volume = FALSE, set_formats = FALSE, fixed_latency_range = FALSE;
pa_sink_new_data data;
pa_alsa_profile_set *profile_set = NULL;
@ -2039,6 +2044,11 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
goto fail;
}
if (pa_modargs_get_value_boolean(ma, "fixed_latency_range", &fixed_latency_range) < 0) {
pa_log("Failed to parse fixed_latency_range argument.");
goto fail;
}
use_tsched = pa_alsa_may_tsched(use_tsched);
u = pa_xnew0(struct userdata, 1);
@ -2047,6 +2057,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
u->use_mmap = use_mmap;
u->use_tsched = use_tsched;
u->deferred_volume = deferred_volume;
u->fixed_latency_range = fixed_latency_range;
u->first = TRUE;
u->rewind_safeguard = rewind_safeguard;
u->rtpoll = pa_rtpoll_new();
@ -2143,9 +2154,13 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
if (u->use_mmap)
pa_log_info("Successfully enabled mmap() mode.");
if (u->use_tsched)
if (u->use_tsched) {
pa_log_info("Successfully enabled timer-based scheduling mode.");
if (u->fixed_latency_range)
pa_log_info("Disabling latency range changes on underrun");
}
if (is_iec958(u) || is_hdmi(u))
set_formats = TRUE;

View file

@ -121,7 +121,7 @@ struct userdata {
char *device_name; /* name of the PCM device */
char *control_device; /* name of the control device */
pa_bool_t use_mmap:1, use_tsched:1, deferred_volume:1;
pa_bool_t use_mmap:1, use_tsched:1, deferred_volume:1, fixed_latency_range:1;
pa_bool_t first;
@ -306,7 +306,12 @@ static void increase_watermark(struct userdata *u) {
return;
}
/* Hmm, we cannot increase the watermark any further, hence let's raise the latency */
/* Hmm, we cannot increase the watermark any further, hence let's
raise the latency unless doing so was disabled in
configuration */
if (u->fixed_latency_range)
return;
old_min_latency = u->source->thread_info.min_latency;
new_min_latency = PA_MIN(old_min_latency * 2, old_min_latency + TSCHED_WATERMARK_INC_STEP_USEC);
new_min_latency = PA_MIN(new_min_latency, u->source->thread_info.max_latency);
@ -1710,7 +1715,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
uint32_t nfrags, frag_size, buffer_size, tsched_size, tsched_watermark;
snd_pcm_uframes_t period_frames, buffer_frames, tsched_frames;
size_t frame_size;
pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE, namereg_fail = FALSE, deferred_volume = FALSE;
pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE, namereg_fail = FALSE, deferred_volume = FALSE, fixed_latency_range = FALSE;
pa_source_new_data data;
pa_alsa_profile_set *profile_set = NULL;
@ -1774,6 +1779,11 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
goto fail;
}
if (pa_modargs_get_value_boolean(ma, "fixed_latency_range", &fixed_latency_range) < 0) {
pa_log("Failed to parse fixed_latency_range argument.");
goto fail;
}
use_tsched = pa_alsa_may_tsched(use_tsched);
u = pa_xnew0(struct userdata, 1);
@ -1782,6 +1792,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
u->use_mmap = use_mmap;
u->use_tsched = use_tsched;
u->deferred_volume = deferred_volume;
u->fixed_latency_range = fixed_latency_range;
u->first = TRUE;
u->rtpoll = pa_rtpoll_new();
pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
@ -1877,8 +1888,11 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
if (u->use_mmap)
pa_log_info("Successfully enabled mmap() mode.");
if (u->use_tsched)
if (u->use_tsched) {
pa_log_info("Successfully enabled timer-based scheduling mode.");
if (u->fixed_latency_range)
pa_log_info("Disabling latency range changes on overrun");
}
u->rates = pa_alsa_get_supported_rates(u->pcm_handle);
if (!u->rates) {

View file

@ -59,7 +59,8 @@ PA_MODULE_USAGE(
"rewind_safeguard=<number of bytes that cannot be rewound> "
"deferred_volume=<Synchronize software and hardware volume changes to avoid momentary jumps?> "
"deferred_volume_safety_margin=<usec adjustment depending on volume direction> "
"deferred_volume_extra_delay=<usec adjustment to HW volume changes>");
"deferred_volume_extra_delay=<usec adjustment to HW volume changes> "
"fixed_latency_range=<disable latency range changes on underrun?>");
static const char* const valid_modargs[] = {
"name",
@ -85,6 +86,7 @@ static const char* const valid_modargs[] = {
"deferred_volume",
"deferred_volume_safety_margin",
"deferred_volume_extra_delay",
"fixed_latency_range",
NULL
};

View file

@ -67,7 +67,8 @@ PA_MODULE_USAGE(
"control=<name of mixer control>"
"deferred_volume=<Synchronize software and hardware volume changes to avoid momentary jumps?> "
"deferred_volume_safety_margin=<usec adjustment depending on volume direction> "
"deferred_volume_extra_delay=<usec adjustment to HW volume changes>");
"deferred_volume_extra_delay=<usec adjustment to HW volume changes> "
"fixed_latency_range=<disable latency range changes on overrun?>");
static const char* const valid_modargs[] = {
"name",
@ -92,6 +93,7 @@ static const char* const valid_modargs[] = {
"deferred_volume",
"deferred_volume_safety_margin",
"deferred_volume_extra_delay",
"fixed_latency_range",
NULL
};

View file

@ -1008,6 +1008,10 @@ static void fix_playback_buffer_attr(playback_stream *s) {
tlength_usec -= s->configured_sink_latency;
}
pa_log_debug("Requested latency=%0.2f ms, Received latency=%0.2f ms",
(double) sink_usec / PA_USEC_PER_MSEC,
(double) s->configured_sink_latency / PA_USEC_PER_MSEC);
/* FIXME: This is actually larger than necessary, since not all of
* the sink latency is actually rewritable. */
if (tlength_usec < s->configured_sink_latency + 2*minreq_usec)