From a6019e6dd73e686c69db5967fc3e852a8fe43ecb Mon Sep 17 00:00:00 2001
Message-ID: <a6019e6dd73e686c69db5967fc3e852a8fe43ecb.1737052666.git.sam@gentoo.org>
In-Reply-To: <1993383ddf67e296334c7916d6afc699ee6300c7.1737052666.git.sam@gentoo.org>
References: <1993383ddf67e296334c7916d6afc699ee6300c7.1737052666.git.sam@gentoo.org>
From: Arun Raghavan <arun@asymptotic.io>
Date: Fri, 29 Nov 2024 10:42:58 -0500
Subject: [PATCH 2/8] 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
---
 spa/plugins/alsa/alsa-pcm.c | 31 +++++++++++++++++--------------
 1 file changed, 17 insertions(+), 14 deletions(-)

diff --git a/spa/plugins/alsa/alsa-pcm.c b/spa/plugins/alsa/alsa-pcm.c
index 9244b66aa..b8728bfe1 100644
--- a/spa/plugins/alsa/alsa-pcm.c
+++ b/spa/plugins/alsa/alsa-pcm.c
@@ -40,6 +40,9 @@ static struct card *ensure_card(uint32_t index, bool ucm)
 	const char *alibpref = NULL;
 	int err;
 
+	if (index == SPA_ID_INVALID)
+		return NULL;
+
 	if ((c = find_card(index)) != NULL)
 		return c;
 
@@ -78,6 +81,9 @@ error:
 
 static void release_card(struct card *c)
 {
+	if (!c)
+		return;
+
 	spa_assert(c->ref > 0);
 
 	if (--c->ref > 0)
@@ -657,7 +663,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)
 {
 	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 : "");
 }
 
@@ -938,13 +944,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 */
 		sscanf(state->props.device, "%*[^:]:%u", &state->card_index);
 		if (state->card_index == SPA_ID_INVALID) {
-			spa_log_error(state->log, "Could not determine card index, maybe set %s",
-					SPA_KEY_API_ALSA_PCM_CARD);
-			return -EINVAL;
+			spa_log_info(state->log, "Could not determine card index. %s and/or clock.name "
+					"may need to be configured manually", SPA_KEY_API_ALSA_PCM_CARD);
 		}
 	}
 
-	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),
 				"api.alsa.%s-%u",
 				state->stream == SND_PCM_STREAM_PLAYBACK ? "p" : "c",
@@ -957,10 +962,7 @@ int spa_alsa_init(struct state *state, const struct spa_dict *info)
 	}
 
 	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);
 	if (state->log_file == NULL) {
 		spa_log_error(state->log, "can't create log file");
@@ -1203,7 +1205,7 @@ int spa_alsa_close(struct state *state)
 	else
 		state->n_fds = 0;
 
-	if (state->have_format)
+	if (state->have_format && state->card)
 		state->card->format_ref--;
 
 	state->have_format = false;
@@ -1423,7 +1425,7 @@ static int add_rate(struct state *state, uint32_t scale, uint32_t interleave, bo
 	if (max < min)
 		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;
 	else
 		rate = state->default_rate;
@@ -1439,8 +1441,8 @@ static int add_rate(struct state *state, uint32_t scale, uint32_t interleave, bo
 
 	rate = SPA_CLAMP(rate, min, max);
 
-	spa_log_debug(state->log, "rate:%u multi:%d card:%d def:%d",
-			rate, state->multi_rate, state->card->rate, state->default_rate);
+	spa_log_debug(state->log, "rate:%u multi:%d card:%u def:%d",
+			rate, state->multi_rate, state->card ? state->card->rate : 0, state->default_rate);
 
 	spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_rate, 0);
 
@@ -2172,6 +2174,7 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_
 	}
 
 	if (!state->multi_rate &&
+	    state->card &&
 	    state->card->format_ref > 0 &&
 	    state->card->rate != rrate) {
 		spa_log_error(state->log, "%p: card already opened at rate:%i",
@@ -2217,7 +2220,7 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_
 	state->driver_rate.denom = 0;
 
 	state->have_format = true;
-	if (state->card->format_ref++ == 0)
+	if (state->card && state->card->format_ref++ == 0)
 		state->card->rate = rrate;
 
 	dir = 0;
-- 
2.48.0

