summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Taymans <wtaymans@redhat.com>2019-04-25 12:53:23 +0200
committerWim Taymans <wtaymans@redhat.com>2019-04-25 12:53:23 +0200
commitd8f39a7c020197e6eaacbfd3fec61aa942bee4a9 (patch)
tree55b1ac0c58eef658409339950e3860a2565e1c63
parentf8513029a17c0217b1200f9a9c2cf45dfcc6eb38 (diff)
alsa: improve clock slaving for source
-rw-r--r--spa/plugins/alsa/alsa-source.c6
-rw-r--r--spa/plugins/alsa/alsa-utils.c39
-rw-r--r--spa/plugins/alsa/alsa-utils.h2
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;