mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
alsa: improve capture slave resync
When we underrun, send out a buffer of 0 samples and catch up next time. Detect discont in the master and resync.
This commit is contained in:
parent
b43844e7c6
commit
5ac383e7f7
3 changed files with 46 additions and 32 deletions
|
|
@ -542,6 +542,8 @@ static int alsa_recover(struct state *state, int err)
|
|||
|
||||
spa_log_error(state->log, "%p: xrun of %"PRIu64" usec %"PRIu64" %f",
|
||||
state, xrun, missing, state->safety);
|
||||
|
||||
state->sample_count += missing ? missing : state->threshold;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -623,8 +625,9 @@ static int update_time(struct state *state, uint64_t nsec, snd_pcm_sframes_t del
|
|||
else if (state->bw == BW_MED)
|
||||
set_loop(state, BW_MIN);
|
||||
|
||||
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);
|
||||
spa_log_debug(state->log, "slave:%d rate:%f bw:%f thr:%d err:%f (%f %f %f)",
|
||||
slave, corr, state->bw, state->threshold,
|
||||
err, state->z1, state->z2, state->z3);
|
||||
}
|
||||
|
||||
if (slave && state->notify) {
|
||||
|
|
@ -675,7 +678,7 @@ int spa_alsa_write(struct state *state, snd_pcm_uframes_t silence)
|
|||
return res;
|
||||
|
||||
if (delay > state->threshold * 2) {
|
||||
spa_log_warn(state->log, "slave: resync %f %f %f",
|
||||
spa_log_warn(state->log, "slave delay:%ld resync %f %f %f", delay,
|
||||
state->z1, state->z2, state->z3);
|
||||
init_loop(state);
|
||||
state->alsa_sync = true;
|
||||
|
|
@ -819,18 +822,22 @@ push_frames(struct state *state,
|
|||
|
||||
d = b->buf->datas;
|
||||
|
||||
src = SPA_MEMBER(my_areas[0].addr, offset * state->frame_size, uint8_t);
|
||||
|
||||
avail = d[0].maxsize / state->frame_size;
|
||||
total_frames = SPA_MIN(avail, state->threshold);
|
||||
n_bytes = total_frames * state->frame_size;
|
||||
|
||||
l0 = SPA_MIN(n_bytes, frames * state->frame_size);
|
||||
l1 = n_bytes - l0;
|
||||
if (my_areas) {
|
||||
l0 = SPA_MIN(n_bytes, frames * state->frame_size);
|
||||
l1 = n_bytes - l0;
|
||||
|
||||
spa_memcpy(d[0].data, src, l0);
|
||||
if (l1 > 0)
|
||||
spa_memcpy(d[0].data, my_areas[0].addr, l1);
|
||||
src = SPA_MEMBER(my_areas[0].addr, offset * state->frame_size, uint8_t);
|
||||
spa_memcpy(d[0].data, src, l0);
|
||||
if (l1 > 0)
|
||||
spa_memcpy(d[0].data, my_areas[0].addr, l1);
|
||||
} else {
|
||||
memset(d[0].data, 0, n_bytes);
|
||||
}
|
||||
|
||||
d[0].chunk->offset = 0;
|
||||
d[0].chunk->size = n_bytes;
|
||||
|
|
@ -851,29 +858,44 @@ int spa_alsa_read(struct state *state, snd_pcm_uframes_t silence)
|
|||
snd_pcm_uframes_t read, frames, offset;
|
||||
int res;
|
||||
|
||||
if (state->position && state->threshold != state->position->size)
|
||||
state->threshold = state->position->size;
|
||||
if (state->position) {
|
||||
uint64_t position;
|
||||
|
||||
if (state->threshold != state->position->size) {
|
||||
state->threshold = state->position->size;
|
||||
}
|
||||
position = state->position->clock.position;
|
||||
if (state->last_position && state->last_position + state->last_threshold != position) {
|
||||
state->alsa_sync = true;
|
||||
spa_log_warn(state->log, "discont, resync %"PRIu64" %"PRIu64" %d",
|
||||
state->last_position, position, state->last_threshold);
|
||||
}
|
||||
state->last_position = position;
|
||||
}
|
||||
|
||||
if (state->slaved && state->alsa_started) {
|
||||
uint64_t nsec;
|
||||
snd_pcm_sframes_t delay;
|
||||
uint32_t threshold = state->threshold;
|
||||
|
||||
if ((res = get_status(state, &delay)) < 0)
|
||||
return res;
|
||||
|
||||
if (delay < state->threshold || delay > state->threshold * 2) {
|
||||
spa_log_warn(state->log, "slave: resync %f %f %f",
|
||||
if (delay < threshold) {
|
||||
spa_log_warn(state->log, "slave delay:%ld resync %f %f %f", delay,
|
||||
state->z1, state->z2, state->z3);
|
||||
init_loop(state);
|
||||
state->alsa_sync = true;
|
||||
push_frames(state, NULL, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
if (state->alsa_sync) {
|
||||
if (delay < state->threshold)
|
||||
snd_pcm_rewind(state->hndl, state->threshold - delay);
|
||||
else if (delay > state->threshold)
|
||||
snd_pcm_forward(state->hndl, delay - state->threshold);
|
||||
spa_log_warn(state->log, "slave resync %ld %d", delay, threshold);
|
||||
if (delay < threshold)
|
||||
snd_pcm_rewind(state->hndl, threshold - delay);
|
||||
else if (delay > threshold)
|
||||
snd_pcm_forward(state->hndl, delay - threshold);
|
||||
|
||||
delay = state->threshold;
|
||||
delay = threshold;
|
||||
state->alsa_sync = false;
|
||||
}
|
||||
|
||||
|
|
@ -882,34 +904,26 @@ int spa_alsa_read(struct state *state, snd_pcm_uframes_t silence)
|
|||
return res;
|
||||
}
|
||||
|
||||
again:
|
||||
to_read = state->buffer_frames;
|
||||
if ((res = snd_pcm_mmap_begin(hndl, &my_areas, &offset, &to_read)) < 0) {
|
||||
spa_log_error(state->log, "snd_pcm_mmap_begin error: %s", snd_strerror(res));
|
||||
return res;
|
||||
}
|
||||
frames = SPA_MIN(to_read, state->threshold);
|
||||
spa_log_trace_fp(state->log, "begin %ld %ld %d", offset, frames, state->threshold);
|
||||
|
||||
spa_log_trace_fp(state->log, "begin %ld %ld %ld %d", offset, frames, to_read, state->threshold);
|
||||
|
||||
read = push_frames(state, my_areas, offset, frames);
|
||||
|
||||
spa_log_trace_fp(state->log, "commit %ld %ld %"PRIi64, offset, read, state->sample_count);
|
||||
total_read += read;
|
||||
|
||||
if ((res = snd_pcm_mmap_commit(hndl, offset, read)) < 0) {
|
||||
if ((res = snd_pcm_mmap_commit(hndl, offset, frames)) < 0) {
|
||||
spa_log_error(state->log, "snd_pcm_mmap_commit error: %s", snd_strerror(res));
|
||||
if (res != -EPIPE && res != -ESTRPIPE)
|
||||
return res;
|
||||
}
|
||||
|
||||
if (to_read > read)
|
||||
to_read -= read;
|
||||
else
|
||||
to_read = 0;
|
||||
|
||||
if (read > 0 && to_read >= state->threshold && !spa_list_is_empty(&state->free))
|
||||
goto again;
|
||||
|
||||
state->sample_count += total_read;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ struct buffer {
|
|||
struct spa_list link;
|
||||
};
|
||||
|
||||
#define BW_MAX 0.256
|
||||
#define BW_MAX 0.128
|
||||
#define BW_MED 0.064
|
||||
#define BW_MIN 0.016
|
||||
#define BW_PERIOD (3 * SPA_NSEC_PER_SEC)
|
||||
|
|
@ -125,6 +125,7 @@ struct state {
|
|||
int timerfd;
|
||||
uint32_t threshold;
|
||||
uint32_t last_threshold;
|
||||
uint64_t last_position;
|
||||
unsigned int alsa_started:1;
|
||||
unsigned int alsa_sync:1;
|
||||
unsigned int slaved:1;
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ struct impl {
|
|||
|
||||
struct pw_work_queue *work;
|
||||
|
||||
uint32_t next_position;
|
||||
int last_error;
|
||||
|
||||
unsigned int pause_on_idle:1;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue