alsa: improve resync

Use the max error to do a resync. Don't reset the dll, there is no
reason for that.
Don't use _rewind, but instead limit the amount of samples we read and
write
Should keep more stable sync in most cases.
This commit is contained in:
Wim Taymans 2022-02-15 16:29:43 +01:00
parent 87f4726164
commit 761199be70

View file

@ -1775,7 +1775,13 @@ static int update_time(struct state *state, uint64_t current_time, snd_pcm_sfram
state, follower, state->last_threshold, state->threshold, diff, err); state, follower, state->last_threshold, state->threshold, diff, err);
state->last_threshold = state->threshold; state->last_threshold = state->threshold;
} }
err = SPA_CLAMP(err, -state->max_error, state->max_error); if (err > state->max_error) {
err = state->max_error;
state->alsa_sync = true;
} else if (err < -state->max_error) {
err = -state->max_error;
state->alsa_sync = true;
}
if (!follower || state->matching) if (!follower || state->matching)
corr = spa_dll_update(&state->dll, err); corr = spa_dll_update(&state->dll, err);
@ -1789,10 +1795,10 @@ static int update_time(struct state *state, uint64_t current_time, snd_pcm_sfram
state->base_time = state->next_time; state->base_time = state->next_time;
spa_log_debug(state->log, "%s: follower:%d match:%d rate:%f " spa_log_debug(state->log, "%s: follower:%d match:%d rate:%f "
"bw:%f thr:%u del:%ld target:%ld err:%f", "bw:%f thr:%u del:%ld target:%ld err:%f max:%f",
state->props.device, follower, state->matching, state->props.device, follower, state->matching,
corr, state->dll.bw, state->threshold, delay, target, corr, state->dll.bw, state->threshold, delay, target,
err); err, state->max_error);
} }
if (state->rate_match) { if (state->rate_match) {
@ -1862,12 +1868,14 @@ int spa_alsa_write(struct state *state)
{ {
snd_pcm_t *hndl = state->hndl; snd_pcm_t *hndl = state->hndl;
const snd_pcm_channel_area_t *my_areas; const snd_pcm_channel_area_t *my_areas;
snd_pcm_uframes_t written, frames, offset, off, to_write, total_written; snd_pcm_uframes_t written, frames, offset, off, to_write, total_written, max_write;
snd_pcm_sframes_t commitres; snd_pcm_sframes_t commitres;
int res = 0; int res = 0;
check_position_config(state); check_position_config(state);
max_write = state->buffer_frames;
if (state->following && state->alsa_started) { if (state->following && state->alsa_started) {
uint64_t current_time; uint64_t current_time;
snd_pcm_uframes_t delay, target; snd_pcm_uframes_t delay, target;
@ -1877,22 +1885,16 @@ int spa_alsa_write(struct state *state)
if (SPA_UNLIKELY((res = get_status(state, current_time, &delay, &target)) < 0)) if (SPA_UNLIKELY((res = get_status(state, current_time, &delay, &target)) < 0))
return res; return res;
if (SPA_UNLIKELY(!state->alsa_recovering && (delay < target / 2 || delay > 2 * target))) {
spa_dll_init(&state->dll);
state->alsa_sync = true;
}
if (SPA_UNLIKELY(state->alsa_sync)) { if (SPA_UNLIKELY(state->alsa_sync)) {
spa_log_warn(state->log, "%s: follower delay:%ld target:%ld thr:%u, resync", spa_log_warn(state->log, "%s: follower delay:%ld target:%ld thr:%u, resync",
state->props.device, delay, target, state->threshold); state->props.device, delay, target, state->threshold);
target += state->threshold / 2;
if (delay > target) if (delay > target)
snd_pcm_rewind(state->hndl, delay - target); max_write = delay - target;
else else if (delay < target)
spa_alsa_silence(state, target - delay); spa_alsa_silence(state, target - delay);
delay = target; delay = target;
state->alsa_sync = false; state->alsa_sync = false;
} }
if (SPA_UNLIKELY((res = update_time(state, current_time, delay, target, true)) < 0)) if (SPA_UNLIKELY((res = update_time(state, current_time, delay, target, true)) < 0))
return res; return res;
} }
@ -1900,8 +1902,8 @@ int spa_alsa_write(struct state *state)
total_written = 0; total_written = 0;
again: again:
frames = state->buffer_frames; frames = max_write;
if (state->use_mmap) { if (state->use_mmap && frames > 0) {
if (SPA_UNLIKELY((res = snd_pcm_mmap_begin(hndl, &my_areas, &offset, &frames)) < 0)) { if (SPA_UNLIKELY((res = snd_pcm_mmap_begin(hndl, &my_areas, &offset, &frames)) < 0)) {
spa_log_error(state->log, "%s: snd_pcm_mmap_begin error: %s", spa_log_error(state->log, "%s: snd_pcm_mmap_begin error: %s",
state->props.device, snd_strerror(res)); state->props.device, snd_strerror(res));
@ -2099,7 +2101,7 @@ push_frames(struct state *state,
int spa_alsa_read(struct state *state) int spa_alsa_read(struct state *state)
{ {
snd_pcm_t *hndl = state->hndl; snd_pcm_t *hndl = state->hndl;
snd_pcm_uframes_t total_read = 0, to_read; snd_pcm_uframes_t total_read = 0, to_read, max_read;
const snd_pcm_channel_area_t *my_areas; const snd_pcm_channel_area_t *my_areas;
snd_pcm_uframes_t read, frames, offset; snd_pcm_uframes_t read, frames, offset;
snd_pcm_sframes_t commitres; snd_pcm_sframes_t commitres;
@ -2123,6 +2125,8 @@ int spa_alsa_read(struct state *state)
} }
} }
max_read = state->buffer_frames;
if (state->following && state->alsa_started) { if (state->following && state->alsa_started) {
uint64_t current_time; uint64_t current_time;
snd_pcm_uframes_t delay, target; snd_pcm_uframes_t delay, target;
@ -2133,16 +2137,11 @@ int spa_alsa_read(struct state *state)
if ((res = get_status(state, current_time, &delay, &target)) < 0) if ((res = get_status(state, current_time, &delay, &target)) < 0)
return res; return res;
if (!state->alsa_recovering && delay > target * 2) {
spa_dll_init(&state->dll);
state->alsa_sync = true;
}
if (state->alsa_sync) { if (state->alsa_sync) {
spa_log_warn(state->log, "%s: follower delay:%lu target:%lu thr:%u, resync", spa_log_warn(state->log, "%s: follower delay:%lu target:%lu thr:%u, resync",
state->props.device, delay, target, threshold); state->props.device, delay, target, threshold);
target += threshold / 2;
if (delay < target) if (delay < target)
snd_pcm_rewind(state->hndl, target - delay); max_read = target - delay;
else if (delay > target) else if (delay > target)
snd_pcm_forward(state->hndl, delay - target); snd_pcm_forward(state->hndl, delay - target);
delay = target; delay = target;
@ -2151,11 +2150,12 @@ int spa_alsa_read(struct state *state)
if ((res = update_time(state, current_time, delay, target, true)) < 0) if ((res = update_time(state, current_time, delay, target, true)) < 0)
return res; return res;
if (delay < state->read_size) if (delay < state->read_size)
state->read_size = 0; max_read = 0;
} }
frames = state->read_size; frames = SPA_MIN(max_read, state->read_size);
if (state->use_mmap) { if (state->use_mmap) {
to_read = state->buffer_frames; to_read = state->buffer_frames;