spa: alsa: Don't assume all PCMs have a card

dmix/dsnoop devices, for example, don't have an associated card, so all
the card-related checks don't make sense. Let's explicitly deal with
this case.

Fixes: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/4432
This commit is contained in:
Arun Raghavan 2024-11-29 10:42:58 -05:00
parent 4c09451e77
commit 7bc84305e6

View file

@ -40,6 +40,9 @@ static struct card *ensure_card(uint32_t index, bool ucm)
const char *alibpref = NULL; const char *alibpref = NULL;
int err; int err;
if (index == SPA_ID_INVALID)
return NULL;
if ((c = find_card(index)) != NULL) if ((c = find_card(index)) != NULL)
return c; return c;
@ -78,6 +81,9 @@ error:
static void release_card(struct card *c) static void release_card(struct card *c)
{ {
if (!c)
return;
spa_assert(c->ref > 0); spa_assert(c->ref > 0);
if (--c->ref > 0) if (--c->ref > 0)
@ -717,7 +723,7 @@ static void silence_error_handler(const char *file, int line,
static void fill_device_name(struct state *state, const char *params, char device_name[], size_t len) static void fill_device_name(struct state *state, const char *params, char device_name[], size_t len)
{ {
spa_scnprintf(device_name, len, "%s%s%s", spa_scnprintf(device_name, len, "%s%s%s",
state->card->ucm_prefix ? state->card->ucm_prefix : "", state->card && state->card->ucm_prefix ? state->card->ucm_prefix : "",
state->props.device, params ? params : ""); state->props.device, params ? params : "");
} }
@ -997,13 +1003,12 @@ int spa_alsa_init(struct state *state, const struct spa_dict *info)
/* If we don't have a card index, see if we have a *:<idx> string */ /* If we don't have a card index, see if we have a *:<idx> string */
sscanf(state->props.device, "%*[^:]:%u", &state->card_index); sscanf(state->props.device, "%*[^:]:%u", &state->card_index);
if (state->card_index == SPA_ID_INVALID) { if (state->card_index == SPA_ID_INVALID) {
spa_log_error(state->log, "Could not determine card index, maybe set %s", spa_log_info(state->log, "Could not determine card index. %s and/or clock.name "
SPA_KEY_API_ALSA_PCM_CARD); "may need to be configured manually", SPA_KEY_API_ALSA_PCM_CARD);
return -EINVAL;
} }
} }
if (state->clock_name[0] == '\0') if (state->clock_name[0] == '\0' && state->card_index != SPA_ID_INVALID)
snprintf(state->clock_name, sizeof(state->clock_name), snprintf(state->clock_name, sizeof(state->clock_name),
"api.alsa.%s-%u", "api.alsa.%s-%u",
state->stream == SND_PCM_STREAM_PLAYBACK ? "p" : "c", state->stream == SND_PCM_STREAM_PLAYBACK ? "p" : "c",
@ -1016,10 +1021,7 @@ int spa_alsa_init(struct state *state, const struct spa_dict *info)
} }
state->card = ensure_card(state->card_index, state->open_ucm); state->card = ensure_card(state->card_index, state->open_ucm);
if (state->card == NULL) {
spa_log_error(state->log, "can't create card %u", state->card_index);
return -errno;
}
state->log_file = fopencookie(state, "w", io_funcs); state->log_file = fopencookie(state, "w", io_funcs);
if (state->log_file == NULL) { if (state->log_file == NULL) {
spa_log_error(state->log, "can't create log file"); spa_log_error(state->log, "can't create log file");
@ -1262,7 +1264,7 @@ int spa_alsa_close(struct state *state)
else else
state->n_fds = 0; state->n_fds = 0;
if (state->have_format) if (state->have_format && state->card)
state->card->format_ref--; state->card->format_ref--;
state->have_format = false; state->have_format = false;
@ -1482,7 +1484,7 @@ static int add_rate(struct state *state, uint32_t scale, uint32_t interleave, bo
if (max < min) if (max < min)
return 0; return 0;
if (!state->multi_rate && state->card->format_ref > 0) if (!state->multi_rate && state->card && state->card->format_ref > 0)
rate = state->card->rate; rate = state->card->rate;
else else
rate = state->default_rate; rate = state->default_rate;
@ -1498,8 +1500,8 @@ static int add_rate(struct state *state, uint32_t scale, uint32_t interleave, bo
rate = SPA_CLAMP(rate, min, max); rate = SPA_CLAMP(rate, min, max);
spa_log_debug(state->log, "rate:%u multi:%d card:%d def:%d", spa_log_debug(state->log, "rate:%u multi:%d card:%u def:%d",
rate, state->multi_rate, state->card->rate, state->default_rate); rate, state->multi_rate, state->card ? state->card->rate : 0, state->default_rate);
spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_rate, 0); spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_rate, 0);
@ -2231,6 +2233,7 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_
} }
if (!state->multi_rate && if (!state->multi_rate &&
state->card &&
state->card->format_ref > 0 && state->card->format_ref > 0 &&
state->card->rate != rrate) { state->card->rate != rrate) {
spa_log_error(state->log, "%p: card already opened at rate:%i", spa_log_error(state->log, "%p: card already opened at rate:%i",
@ -2276,7 +2279,7 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_
state->driver_rate.denom = 0; state->driver_rate.denom = 0;
state->have_format = true; state->have_format = true;
if (state->card->format_ref++ == 0) if (state->card && state->card->format_ref++ == 0)
state->card->rate = rrate; state->card->rate = rrate;
dir = 0; dir = 0;