diff options
author | Wim Taymans <wtaymans@redhat.com> | 2019-04-25 12:53:23 +0200 |
---|---|---|
committer | Wim Taymans <wtaymans@redhat.com> | 2019-04-25 12:53:23 +0200 |
commit | d8f39a7c020197e6eaacbfd3fec61aa942bee4a9 (patch) | |
tree | 55b1ac0c58eef658409339950e3860a2565e1c63 | |
parent | f8513029a17c0217b1200f9a9c2cf45dfcc6eb38 (diff) |
alsa: improve clock slaving for source
-rw-r--r-- | spa/plugins/alsa/alsa-source.c | 6 | ||||
-rw-r--r-- | spa/plugins/alsa/alsa-utils.c | 39 | ||||
-rw-r--r-- | spa/plugins/alsa/alsa-utils.h | 2 |
3 files changed, 26 insertions, 21 deletions
diff --git a/spa/plugins/alsa/alsa-source.c b/spa/plugins/alsa/alsa-source.c index ea292041..8b0d2d7c 100644 --- a/spa/plugins/alsa/alsa-source.c +++ b/spa/plugins/alsa/alsa-source.c @@ -648,16 +648,16 @@ static int impl_node_process(struct spa_node *node) io->buffer_id = SPA_ID_INVALID; } - if (spa_list_is_empty(&this->ready)) + if (spa_list_is_empty(&this->ready) && this->slaved) spa_alsa_read(this, 0); - if (spa_list_is_empty(&this->ready)) + if (spa_list_is_empty(&this->ready) || !this->slaved) return SPA_STATUS_OK; b = spa_list_first(&this->ready, struct buffer, link); spa_list_remove(&b->link); - spa_log_trace_fp(this->log, NAME " %p: dequeue buffer %d", node, b->id); + spa_log_trace_fp(this->log, NAME " %p: dequeue buffer %d", this, b->id); io->buffer_id = b->id; io->status = SPA_STATUS_HAVE_BUFFER; diff --git a/spa/plugins/alsa/alsa-utils.c b/spa/plugins/alsa/alsa-utils.c index c99480a0..ad21419f 100644 --- a/spa/plugins/alsa/alsa-utils.c +++ b/spa/plugins/alsa/alsa-utils.c @@ -591,7 +591,7 @@ static int get_status(struct state *state, snd_pcm_sframes_t *delay) static int update_time(struct state *state, uint64_t nsec, snd_pcm_sframes_t delay, bool slave) { - double err, corr, elapsed; + double err, corr; if (state->bw == 0.0) { set_loop(state, BW_MAX); @@ -599,7 +599,10 @@ static int update_time(struct state *state, uint64_t nsec, snd_pcm_sframes_t del state->base_time = nsec; } - err = delay - state->threshold; + if (state->stream == SND_PCM_STREAM_PLAYBACK) + err = delay - state->threshold; + else + err = state->threshold - delay; state->z1 += state->w0 * (state->w1 * err - state->z1); state->z2 += state->w0 * (state->z1 - state->z2); @@ -607,15 +610,15 @@ static int update_time(struct state *state, uint64_t nsec, snd_pcm_sframes_t del corr = 1.0 - (state->z2 + state->z3); - elapsed = (state->next_time - state->base_time) * 1e-9; - if (elapsed > BW_PERIOD) { + if ((state->next_time - state->base_time) > BW_PERIOD) { state->base_time = state->next_time; if (state->bw == BW_MAX) set_loop(state, BW_MED); else if (state->bw == BW_MED) set_loop(state, BW_MIN); - spa_log_debug(state->log, "slave:%d rate:%f bw:%f", slave, corr, state->bw); + spa_log_debug(state->log, "slave:%d rate:%f bw:%f err:%f (%f %f %f)", + slave, corr, state->bw, err, state->z1, state->z2, state->z3); } if (slave && state->notify) { @@ -665,6 +668,12 @@ int spa_alsa_write(struct state *state, snd_pcm_uframes_t silence) if ((res = get_status(state, &delay)) < 0) return res; + if (delay > state->threshold * 2) { + spa_log_warn(state->log, "slave: resync %f %f %f", + state->z1, state->z2, state->z3); + init_loop(state); + state->alsa_sync = true; + } if (state->alsa_sync) { if (delay > state->threshold) snd_pcm_rewind(state->hndl, delay - state->threshold); @@ -678,12 +687,6 @@ int spa_alsa_write(struct state *state, snd_pcm_uframes_t silence) nsec = SPA_TIMESPEC_TO_NSEC(&state->now); if ((res = update_time(state, nsec, delay, true)) < 0) return res; - - if (delay > state->threshold * 2) { - spa_log_warn(state->log, "slave: skip period"); - snd_pcm_rewind(state->hndl, state->threshold); - delay -= state->threshold; - } } total_written = 0; @@ -857,14 +860,16 @@ int spa_alsa_read(struct state *state, snd_pcm_uframes_t silence) if ((res = get_status(state, &delay)) < 0) return res; - if ((res = update_time(state, nsec, delay, true)) < 0) - return res; - if (delay > state->threshold * 2) { - spa_log_trace_fp(state->log, "slave: skip period"); - snd_pcm_forward(state->hndl, state->threshold); - delay -= state->threshold; + spa_log_warn(state->log, "slave: resync %f %f %f", + state->z1, state->z2, state->z3); + snd_pcm_forward(state->hndl, delay - state->threshold); + delay = state->threshold; + init_loop(state); } + + if ((res = update_time(state, nsec, delay, true)) < 0) + return res; } again: diff --git a/spa/plugins/alsa/alsa-utils.h b/spa/plugins/alsa/alsa-utils.h index fe622c95..1749dc8d 100644 --- a/spa/plugins/alsa/alsa-utils.h +++ b/spa/plugins/alsa/alsa-utils.h @@ -68,7 +68,7 @@ struct buffer { #define BW_MAX 0.256 #define BW_MED 0.064 #define BW_MIN 0.016 -#define BW_PERIOD 3.0 +#define BW_PERIOD (3 * SPA_NSEC_PER_SEC) struct state { struct spa_handle handle; |