[pulseaudio-discuss] [PATCH 3/4] alsa-sink: Add hack to compensate USB startup behavior
Georg Chini
georg at chini.tk
Sun Jun 5 19:48:57 UTC 2016
USB sinks exhibit a strange behavior at startup. See comment in the code for
more explanation. This hack compensates the issue.
---
src/modules/alsa/alsa-sink.c | 47 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 46 insertions(+), 1 deletion(-)
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index d497200..de51710 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -150,6 +150,9 @@ struct userdata {
double time_factor;
bool first_delayed;
+ bool usb_hack;
+
+ double hack_threshold;
pa_idxset *formats;
@@ -850,6 +853,10 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, bool polled, bo
}
static void init_time_estimate(struct userdata *u) {
+ const char *id;
+ snd_pcm_info_t* pcm_info;
+
+ snd_pcm_info_alloca(&pcm_info);
/* Reset variables for rate estimation */
u->drift_filter = 1.0;
@@ -857,6 +864,21 @@ static void init_time_estimate(struct userdata *u) {
u->time_factor = 1.0;
u->start_pos = 0;
u->first_delayed = false;
+ u->usb_hack = false;
+ u->time_offset = 0;
+
+ /* Check if this is an USB device, see alsa-util.c
+ * USB devices unfortunately need some special handling */
+ if (snd_pcm_info(u->pcm_handle, pcm_info) == 0 &&
+ (id = snd_pcm_info_get_id(pcm_info))) {
+ if (pa_streq(id, "USB Audio")) {
+ /* USB device, set hack parameter */
+ u->usb_hack = true;
+ u->hack_threshold = 2000;
+ if (!u->use_tsched)
+ u->hack_threshold = 1000;
+ }
+ }
/* Start time */
u->start_time = pa_rtclock_now();
@@ -869,6 +891,7 @@ static void update_time_estimate(struct userdata *u) {
double byte_count, iteration_time;
int err;
double time_delta_system, time_delta_card, drift, filter_constant, filter_constant_1;
+ double temp;
pa_usec_t time_stamp;
snd_pcm_status_t *status;
@@ -935,6 +958,28 @@ static void update_time_estimate(struct userdata *u) {
* be on a sample boundary */
time_delta_card = byte_count / u->frame_size / u->sink->sample_spec.rate * PA_USEC_PER_SEC;
+ /* This is a horrible hack which is necessary because USB devices seem to fix up
+ * the reported delay by some millisecondsconds shortly after startup. This is
+ * an artifact, the real latency does not change on the reported jump. If the
+ * change is not caught or if the hack is triggered inadvertently, it will lead to
+ * prolonged convergence time and decreased stability of the reported latency.
+ * Since the fix up will occur within the first seconds, it is disabled later to
+ * avoid false triggers. When run as batch device, the threshold for the hack must
+ * be lower than for timer based scheduling. */
+ if (u->usb_hack && time_delta_system < 5 * PA_USEC_PER_SEC) {
+ if (abs(time_delta_system - time_delta_card / u->time_factor) > u->hack_threshold) {
+ /* Recalculate initial conditions */
+ temp = time_stamp - time_delta_card - u->start_time;
+ u->start_time += temp;
+ u->first_start_time += temp;
+ u->time_offset = -temp;
+
+ pa_log_debug("USB Hack, start time corrected by %0.2f usec", temp);
+ u->usb_hack = false;
+ return;
+ }
+ }
+
/* Parameter for lowpass filter with 2s and 15s time constant */
filter_constant = iteration_time / (iteration_time + 318310.0);
filter_constant_1 = iteration_time / (iteration_time + 2387324.0);
@@ -960,7 +1005,7 @@ static pa_usec_t sink_get_latency(struct userdata *u, bool raw) {
pa_assert(u);
/* Convert system time difference to soundcard time difference */
- now2 = (pa_rtclock_now() - u->start_time) * u->time_factor;
+ now2 = (pa_rtclock_now() - u->start_time - u->time_offset) * u->time_factor;
/* Don't use pa_bytes_to_usec(), u->start_pos needs not be on a sample boundary */
delay = (int64_t)(((double)u->write_count - u->start_pos) / u->frame_size / u->sink->sample_spec.rate * PA_USEC_PER_SEC) - now2;
--
2.8.1
More information about the pulseaudio-discuss
mailing list