diff --git a/spa/plugins/alsa/alsa-seq.c b/spa/plugins/alsa/alsa-seq.c index 62dd6be0d..a771e506a 100644 --- a/spa/plugins/alsa/alsa-seq.c +++ b/spa/plugins/alsa/alsa-seq.c @@ -703,9 +703,7 @@ static int update_time(struct seq_state *state, uint64_t nsec, bool follower) const snd_seq_real_time_t* queue_time; uint64_t queue_real; double err, corr; - uint64_t queue_elapsed; - - corr = 1.0 - (state->dll.z2 + state->dll.z3); + uint64_t q1, q2; /* take queue time */ snd_seq_queue_status_alloca(&status); @@ -713,33 +711,43 @@ static int update_time(struct seq_state *state, uint64_t nsec, bool follower) queue_time = snd_seq_queue_status_get_real_time(status); queue_real = SPA_TIMESPEC_TO_NSEC(queue_time); - if (state->queue_time == 0) - queue_elapsed = 0; - else - queue_elapsed = (queue_real - state->queue_time) / corr; - - state->queue_time = queue_real; - - queue_elapsed = NSEC_TO_CLOCK(&state->rate, queue_elapsed); - - err = ((int64_t)state->threshold - (int64_t) queue_elapsed); - err = SPA_CLAMP(err, -64, 64); - if (state->dll.bw == 0.0) { spa_dll_set_bw(&state->dll, SPA_DLL_BW_MAX, state->threshold, state->rate.denom); state->next_time = nsec; state->base_time = nsec; + state->queue_next = queue_real; } + + /* track our estimated elapsed time against the real elapsed queue time */ + q1 = NSEC_TO_CLOCK(&state->rate, state->queue_next); + q2 = NSEC_TO_CLOCK(&state->rate, queue_real); + err = ((int64_t)q1 - (int64_t) q2); + + if (fabs(err) > state->threshold) + spa_dll_init(&state->dll); + + err = SPA_CLAMP(err, -64, 64); corr = spa_dll_update(&state->dll, err); + /* this is our current estimated queue time and rate */ + state->queue_time = state->queue_next; + state->queue_corr = corr; + + /* make a new estimated queue time with the current quantum, if we are following, + * use the rate correction, else we will use the rate correction only for the new + * timeout. */ + if (state->following) + state->queue_next += state->threshold * corr * 1e9 / state->rate.denom; + else + state->queue_next += state->threshold * 1e9 / state->rate.denom; + if ((state->next_time - state->base_time) > BW_PERIOD) { state->base_time = state->next_time; spa_log_debug(state->log, "%p: follower:%d rate:%f bw:%f err:%f (%f %f %f)", state, follower, corr, state->dll.bw, err, state->dll.z1, state->dll.z2, state->dll.z3); } - state->next_time += state->threshold / corr * 1e9 / state->rate.denom; if (!follower && state->clock) { diff --git a/spa/plugins/alsa/alsa-seq.h b/spa/plugins/alsa/alsa-seq.h index 697d696df..de43948f4 100644 --- a/spa/plugins/alsa/alsa-seq.h +++ b/spa/plugins/alsa/alsa-seq.h @@ -142,6 +142,8 @@ struct seq_state { uint64_t next_time; uint64_t base_time; uint64_t queue_time; + uint64_t queue_next; + double queue_corr; unsigned int opened:1; unsigned int started:1;