mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
alsa-pcm: add support for api.alsa.dll-bandwidth-max
In USB Audio Class 2 (UAC2) setups, pitch control is handled by feedback endpoints. The host adjusts its data rate accordingly. When pitch control is active (pitch_elem), applying the default delay-locked loop (DLL) bandwidth can lead to instability and oscillations around the target rate. This patch adds a new parameter, api.alsa.dll-bandwidth-max, to configure the maximum DLL bandwidth. It introduces a new field in the ALSA state to store this value. By default, it uses SPA_DLL_BW_MAX, but when pitch control is in use, setting it to a lower value (e.g. 0.02) helps ensure better stability, based on empirical testing.
This commit is contained in:
parent
deb7dddbef
commit
8aa836d588
3 changed files with 13 additions and 2 deletions
|
|
@ -778,6 +778,12 @@ Setting this to 0 makes htimestamp never get disabled.
|
||||||
Disable timer-based scheduling, and use IRQ for scheduling instead.
|
Disable timer-based scheduling, and use IRQ for scheduling instead.
|
||||||
The "Pro Audio" profile will usually enable this setting, if it is expected it works on the hardware.
|
The "Pro Audio" profile will usually enable this setting, if it is expected it works on the hardware.
|
||||||
|
|
||||||
|
@PAR@ node-prop api.alsa.dll-bandwidth-max # double
|
||||||
|
Sets the maximum bandwidth of the DLL (delay-locked loop) filter used to smooth out rate adjustments.
|
||||||
|
The default value may be too responsive in some scenarios.
|
||||||
|
For example, with UAC2 pitch control, the host reacts more slowly compared to local resampling,
|
||||||
|
so using a lower bandwidth helps avoid oscillations or instability.
|
||||||
|
|
||||||
@PAR@ node-prop api.alsa.auto-link = false # boolean
|
@PAR@ node-prop api.alsa.auto-link = false # boolean
|
||||||
Link follower PCM devices to the driver PCM device when using IRQ-based scheduling.
|
Link follower PCM devices to the driver PCM device when using IRQ-based scheduling.
|
||||||
The "Pro Audio" profile will usually enable this setting, if it is expected it works on the hardware.
|
The "Pro Audio" profile will usually enable this setting, if it is expected it works on the hardware.
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
static struct spa_list cards = SPA_LIST_INIT(&cards);
|
static struct spa_list cards = SPA_LIST_INIT(&cards);
|
||||||
static struct spa_list states = SPA_LIST_INIT(&states);
|
static struct spa_list states = SPA_LIST_INIT(&states);
|
||||||
|
#define SPA_ALSA_DLL_BW_MIN 0.001
|
||||||
|
|
||||||
static struct card *find_card(uint32_t index)
|
static struct card *find_card(uint32_t index)
|
||||||
{
|
{
|
||||||
|
|
@ -198,6 +199,9 @@ static int alsa_set_param(struct state *state, const char *k, const char *s)
|
||||||
state->disable_batch = spa_atob(s);
|
state->disable_batch = spa_atob(s);
|
||||||
} else if (spa_streq(k, "api.alsa.disable-tsched")) {
|
} else if (spa_streq(k, "api.alsa.disable-tsched")) {
|
||||||
state->disable_tsched = spa_atob(s);
|
state->disable_tsched = spa_atob(s);
|
||||||
|
} else if (spa_streq(k, "api.alsa.dll-bandwidth-max")) {
|
||||||
|
state->dll_bw_max = SPA_CLAMPD(spa_strtod(s, NULL),
|
||||||
|
SPA_ALSA_DLL_BW_MIN, SPA_DLL_BW_MAX);
|
||||||
} else if (spa_streq(k, "api.alsa.use-chmap")) {
|
} else if (spa_streq(k, "api.alsa.use-chmap")) {
|
||||||
state->props.use_chmap = spa_atob(s);
|
state->props.use_chmap = spa_atob(s);
|
||||||
} else if (spa_streq(k, "api.alsa.multi-rate")) {
|
} else if (spa_streq(k, "api.alsa.multi-rate")) {
|
||||||
|
|
@ -2799,7 +2803,7 @@ static int update_time(struct state *state, uint64_t current_time, snd_pcm_sfram
|
||||||
int32_t diff;
|
int32_t diff;
|
||||||
|
|
||||||
if (SPA_UNLIKELY(state->dll.bw == 0.0)) {
|
if (SPA_UNLIKELY(state->dll.bw == 0.0)) {
|
||||||
spa_dll_set_bw(&state->dll, SPA_DLL_BW_MAX, state->threshold, state->rate);
|
spa_dll_set_bw(&state->dll, state->dll_bw_max, state->threshold, state->rate);
|
||||||
state->next_time = current_time;
|
state->next_time = current_time;
|
||||||
state->base_time = current_time;
|
state->base_time = current_time;
|
||||||
}
|
}
|
||||||
|
|
@ -2862,7 +2866,7 @@ static int update_time(struct state *state, uint64_t current_time, snd_pcm_sfram
|
||||||
err, state->max_error, state->max_resync, state->err_avg, state->err_var, bw);
|
err, state->max_error, state->max_resync, state->err_avg, state->err_var, bw);
|
||||||
|
|
||||||
spa_dll_set_bw(&state->dll,
|
spa_dll_set_bw(&state->dll,
|
||||||
SPA_CLAMPD(bw, 0.001, SPA_DLL_BW_MAX),
|
SPA_CLAMPD(bw, SPA_ALSA_DLL_BW_MIN, state->dll_bw_max),
|
||||||
state->threshold, state->rate);
|
state->threshold, state->rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -244,6 +244,7 @@ struct state {
|
||||||
uint64_t underrun;
|
uint64_t underrun;
|
||||||
|
|
||||||
struct spa_dll dll;
|
struct spa_dll dll;
|
||||||
|
double dll_bw_max;
|
||||||
double max_error;
|
double max_error;
|
||||||
double max_resync;
|
double max_resync;
|
||||||
double err_avg, err_var, err_wdw;
|
double err_avg, err_var, err_wdw;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue