mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
alsa: handle driver bugs better
Use the NEAREST flag when setting a format. This only works for raw formats and will update the format with the nearest accepted rate or channels. We can then query the real configured format and use that for the converter. This makes things work when a driver tells us it can do 44100Hz but then refuses and changes the rate to 48000. See #2197, #2457, #2455, rhbz#2096193
This commit is contained in:
parent
ecc0eecf0f
commit
0f62d3442c
4 changed files with 35 additions and 12 deletions
|
|
@ -616,7 +616,7 @@ static int port_set_format(void *object,
|
|||
const struct spa_pod *format)
|
||||
{
|
||||
struct state *this = object;
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
if (format == NULL) {
|
||||
if (!this->have_format)
|
||||
|
|
@ -673,7 +673,7 @@ static int port_set_format(void *object,
|
|||
}
|
||||
emit_port_info(this, false);
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -566,7 +566,7 @@ static int port_set_format(void *object,
|
|||
uint32_t flags, const struct spa_pod *format)
|
||||
{
|
||||
struct state *this = object;
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
if (format == NULL) {
|
||||
if (!this->have_format)
|
||||
|
|
@ -610,7 +610,7 @@ static int port_set_format(void *object,
|
|||
}
|
||||
emit_port_info(this, false);
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -1409,7 +1409,10 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_
|
|||
state->props.device, rchannels, val);
|
||||
if (!SPA_FLAG_IS_SET(flags, SPA_NODE_PARAM_FLAG_NEAREST))
|
||||
return -EINVAL;
|
||||
if (fmt->media_subtype != SPA_MEDIA_SUBTYPE_raw)
|
||||
return -EINVAL;
|
||||
rchannels = val;
|
||||
fmt->info.raw.channels = rchannels;
|
||||
match = false;
|
||||
}
|
||||
|
||||
|
|
@ -1429,7 +1432,10 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_
|
|||
state->props.device, rrate, val);
|
||||
if (!SPA_FLAG_IS_SET(flags, SPA_NODE_PARAM_FLAG_NEAREST))
|
||||
return -EINVAL;
|
||||
if (fmt->media_subtype != SPA_MEDIA_SUBTYPE_raw)
|
||||
return -EINVAL;
|
||||
rrate = val;
|
||||
fmt->info.raw.rate = rrate;
|
||||
match = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -442,6 +442,29 @@ static int configure_format(struct impl *this, uint32_t flags, const struct spa_
|
|||
if (format && spa_log_level_enabled(this->log, SPA_LOG_LEVEL_DEBUG))
|
||||
spa_debug_format(0, NULL, format);
|
||||
|
||||
if ((res = spa_node_port_set_param(this->follower,
|
||||
this->direction, 0,
|
||||
SPA_PARAM_Format, flags,
|
||||
format)) < 0)
|
||||
return res;
|
||||
if (res > 0) {
|
||||
uint8_t buffer[4096];
|
||||
struct spa_pod_builder b = { 0 };
|
||||
uint32_t state = 0;
|
||||
struct spa_pod *fmt;
|
||||
|
||||
/* format was changed to nearest compatible format */
|
||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
if ((res = spa_node_port_enum_params_sync(this->follower,
|
||||
this->direction, 0,
|
||||
SPA_PARAM_Format, &state,
|
||||
NULL, &fmt, &b)) != 1)
|
||||
return -EIO;
|
||||
|
||||
format = fmt;
|
||||
}
|
||||
|
||||
if (this->target != this->follower && this->convert) {
|
||||
if ((res = spa_node_port_set_param(this->convert,
|
||||
SPA_DIRECTION_REVERSE(this->direction), 0,
|
||||
|
|
@ -450,12 +473,6 @@ static int configure_format(struct impl *this, uint32_t flags, const struct spa_
|
|||
return res;
|
||||
}
|
||||
|
||||
if ((res = spa_node_port_set_param(this->follower,
|
||||
this->direction, 0,
|
||||
SPA_PARAM_Format, flags,
|
||||
format)) < 0)
|
||||
return res;
|
||||
|
||||
this->have_format = format != NULL;
|
||||
if (format == NULL) {
|
||||
this->n_buffers = 0;
|
||||
|
|
@ -513,7 +530,7 @@ static int reconfigure_mode(struct impl *this, bool passthrough,
|
|||
/* set new target */
|
||||
this->target = passthrough ? this->follower : this->convert;
|
||||
|
||||
if ((res = configure_format(this, 0, format)) < 0)
|
||||
if ((res = configure_format(this, SPA_NODE_PARAM_FLAG_NEAREST, format)) < 0)
|
||||
return res;
|
||||
|
||||
if (this->passthrough != passthrough) {
|
||||
|
|
@ -775,7 +792,7 @@ static int negotiate_format(struct impl *this)
|
|||
|
||||
spa_pod_fixate(format);
|
||||
|
||||
res = configure_format(this, 0, format);
|
||||
res = configure_format(this, SPA_NODE_PARAM_FLAG_NEAREST, format);
|
||||
|
||||
done:
|
||||
spa_node_send_command(this->follower,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue