Skip to content

Commit

Permalink
aplay: do not reset delay report after xrun
Browse files Browse the repository at this point in the history
  • Loading branch information
borine committed Feb 15, 2025
1 parent e1dd657 commit e5e7bae
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 27 deletions.
31 changes: 12 additions & 19 deletions utils/aplay/aplay.c
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ static void *io_worker_routine(struct io_worker *w) {
ffb_shift(&read_buffer, discard_samples);
#if ENABLE_APLAY_RESAMPLER
if (use_resampler)
resampler_reset(resampler, 0);
resampler_reset(resampler);
#endif
}

Expand Down Expand Up @@ -760,6 +760,12 @@ static void *io_worker_routine(struct io_worker *w) {
/* Reset moving delay window buffer. */
delay_report_reset(&dr);

#if ENABLE_APLAY_RESAMPLER
/* Start the resampler stabilization timer */
if (use_resampler)
resampler_reset(resampler);
#endif

if (verbose >= 2) {
info("Used configuration for %s:\n"
" ALSA PCM buffer time: %u us (%zu bytes)\n"
Expand Down Expand Up @@ -807,16 +813,11 @@ static void *io_worker_routine(struct io_worker *w) {
if (!w->ba_pcm.running)
goto device_inactive;

if (w->alsa_pcm.underrun) {
/* Reset moving delay window buffer. */
delay_report_reset(&dr);
}

#if ENABLE_APLAY_RESAMPLER
size_t resample_delay_frames;
if (use_resampler) {
if (w->alsa_pcm.underrun)
resampler_reset(resampler, 0);
resampler_reset(resampler);

resample_delay_frames = ffb_len_out(write_buffer) / w->ba_pcm.channels;
resample_delay_frames /= resampler_current_rate_ratio(resampler);
Expand All @@ -834,18 +835,10 @@ static void *io_worker_routine(struct io_worker *w) {
}

#if ENABLE_APLAY_RESAMPLER
/* Allow time for the delay average to settle before adjusting the
* resampling ratio */
if (use_resampler && dr.values_i > 2 * ARRAYSIZE(dr.values)) {
if (!resampler_ready(resampler)) {
if (alsa_pcm_is_running(&w->alsa_pcm))
resampler_reset(resampler, dr.avg_value);
}
else {
bool rate_changed = resampler_update_rate_ratio(resampler, dr.avg_value);
if (verbose >= 5 && rate_changed)
debug("new rate ratio %.8f", resampler_current_rate_ratio(resampler));
}
if (use_resampler) {
bool rate_changed = resampler_update_rate_ratio(resampler, dr.avg_value);
if (verbose >= 5 && rate_changed)
debug("new rate ratio %.8f", resampler_current_rate_ratio(resampler));
}
#endif

Expand Down
36 changes: 29 additions & 7 deletions utils/aplay/resampler.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@

#include "shared/log.h"
#include "shared/ffb.h"
#include "shared/rt.h"

#include "resampler.h"

/* How many milliseconds to allow the delay to change before adjusting the
* resampling rate. */
# define RESAMPLER_TOLERANCE_MS 2

/* How many milliseconds to wait for the delay value to stabilize after a
* reset. */
#define RESAMPLER_STABILIZE_MS 2000

struct aplay_resampler {
SRC_STATE *src_state;
SRC_DATA src_data;
Expand All @@ -40,6 +45,12 @@ struct aplay_resampler {
snd_pcm_uframes_t target_delay;
snd_pcm_uframes_t delay_tolerance;
snd_pcm_sframes_t delay_diff;
struct timespec reset_ts;
};

static const struct timespec ts_stabilize = {
.tv_sec = RESAMPLER_STABILIZE_MS / 1000,
.tv_nsec = (RESAMPLER_STABILIZE_MS % 1000) * 1000000,
};

/**
Expand Down Expand Up @@ -193,10 +204,20 @@ bool resampler_update_rate_ratio(
struct aplay_resampler *resampler,
snd_pcm_uframes_t delay) {

if (resampler->target_delay == 0)
return false;
/* Check if we need to re-enable adaptive resampling after a reset */
if (resampler->target_delay == 0) {
struct timespec ts_now;
struct timespec ts_wait;
timespecadd(&resampler->reset_ts, &ts_stabilize, &ts_wait);
gettimestamp(&ts_now);
if (difftimespec(&ts_now, &ts_wait, &ts_wait) < 0) {
resampler->target_delay = delay;
return true;
}
else
return false;
}

double old_ratio = resampler->src_data.src_ratio;
bool rate_changed = true;
snd_pcm_sframes_t delay_diff = delay - resampler->target_delay;
if (labs(delay_diff) > resampler->delay_tolerance) {
Expand All @@ -205,7 +226,7 @@ bool resampler_update_rate_ratio(
else if (delay_diff < 0 && delay_diff <= resampler->delay_diff)
resampler->src_data.src_ratio += resampler->rate_delta;
else
rate_changed = false
rate_changed = false;
}
else if (labs(resampler->delay_diff) > resampler->delay_tolerance) {
if (resampler->delay_diff > 0)
Expand All @@ -221,11 +242,12 @@ bool resampler_update_rate_ratio(
}

/**
* Reset the resampling ratio and the target delay after any discontinuity in
* Reset the resampling ratio to its nominal rate after any discontinuity in
* the stream. */
void resampler_reset(struct aplay_resampler *resampler, snd_pcm_uframes_t target) {
void resampler_reset(struct aplay_resampler *resampler) {
resampler->src_data.src_ratio = resampler->nominal_rate_ratio;
resampler->target_delay = target;
resampler->target_delay = 0;
gettimestamp(&resampler->reset_ts);
}

double resampler_current_rate_ratio(struct aplay_resampler *resampler) {
Expand Down
2 changes: 1 addition & 1 deletion utils/aplay/resampler.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ bool resampler_update_rate_ratio(
struct aplay_resampler *resampler,
snd_pcm_uframes_t delay);

void resampler_reset(struct aplay_resampler *resampler, snd_pcm_uframes_t target);
void resampler_reset(struct aplay_resampler *resampler);
double resampler_current_rate_ratio(struct aplay_resampler *resampler);
bool resampler_ready(struct aplay_resampler *resampler);

Expand Down

0 comments on commit e5e7bae

Please sign in to comment.