diff --git a/spa/include/spa/utils/keys.h b/spa/include/spa/utils/keys.h index b20df9c4e..b9608e995 100644 --- a/spa/include/spa/utils/keys.h +++ b/spa/include/spa/utils/keys.h @@ -60,6 +60,7 @@ extern "C" { #define SPA_KEY_API_ALSA_CARD "api.alsa.card" /**< alsa card number */ #define SPA_KEY_API_ALSA_USE_UCM "api.alsa.use-ucm" /**< if UCM should be used */ #define SPA_KEY_API_ALSA_IGNORE_DB "api.alsa.ignore-dB" /**< if decibel info should be ignored */ +#define SPA_KEY_API_ALSA_OPEN_UCM "api.alsa.open.ucm" /**< if UCM should be opened card */ /** info from alsa card_info */ #define SPA_KEY_API_ALSA_CARD_ID "api.alsa.card.id" /**< id from card_info */ diff --git a/spa/plugins/alsa/acp/acp.c b/spa/plugins/alsa/acp/acp.c index a28f78c12..5fa42750f 100644 --- a/spa/plugins/alsa/acp/acp.c +++ b/spa/plugins/alsa/acp/acp.c @@ -241,8 +241,20 @@ static void init_device(pa_card *impl, pa_alsa_device *dev, pa_alsa_direction_t dev->ports = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - if (m->ucm_context.ucm) + if (m->ucm_context.ucm) { + const char *alibpref; dev->ucm_context = &m->ucm_context; + if ((snd_use_case_get(impl->ucm.ucm_mgr, "_alibpref", &alibpref) == 0)) { + char **d; + for (d = m->device_strings; *d; d++) { + if (pa_startswith(*d, alibpref)) { + dev->device.flags |= ACP_DEVICE_UCM_DEVICE; + break; + } + } + free((void*)alibpref); + } + } pa_dynarray_init(&dev->port_array, NULL); } diff --git a/spa/plugins/alsa/acp/acp.h b/spa/plugins/alsa/acp/acp.h index aee24be66..95c35ebaf 100644 --- a/spa/plugins/alsa/acp/acp.h +++ b/spa/plugins/alsa/acp/acp.h @@ -204,6 +204,7 @@ struct acp_device { #define ACP_DEVICE_ACTIVE (1<<0) #define ACP_DEVICE_HW_VOLUME (1<<1) #define ACP_DEVICE_HW_MUTE (1<<2) +#define ACP_DEVICE_UCM_DEVICE (1<<3) uint32_t flags; const char *name; diff --git a/spa/plugins/alsa/alsa-acp-device.c b/spa/plugins/alsa/alsa-acp-device.c index 809c7e0bc..5a9d80f4e 100644 --- a/spa/plugins/alsa/alsa-acp-device.c +++ b/spa/plugins/alsa/alsa-acp-device.c @@ -149,7 +149,7 @@ static int emit_node(struct impl *this, struct acp_device *dev) const struct acp_dict_item *it; uint32_t n_items, i; char device_name[128], path[180], channels[16], ch[12], routes[16]; - char card_id[16], *p; + char card_index[16], *p; char positions[SPA_AUDIO_MAX_CHANNELS * 12]; struct spa_device_object_info info; struct acp_card *card = this->card; @@ -168,10 +168,10 @@ static int emit_node(struct impl *this, struct acp_device *dev) info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS; - n_items = dev->props.n_items + 7; - items = alloca(n_items * sizeof(*items)); + items = alloca((dev->props.n_items + 8) * sizeof(*items)); + n_items = 0; - snprintf(card_id, sizeof(card), "%d", card->index); + snprintf(card_index, sizeof(card_index), "%d", card->index); devstr = dev->device_strings[0]; p = strstr(devstr, "%f"); @@ -182,25 +182,27 @@ static int emit_node(struct impl *this, struct acp_device *dev) } else { snprintf(device_name, sizeof(device_name), "%s", devstr); } - snprintf(path, sizeof(path), "alsa:pcm:%s:%s:%s", card_id, device_name, stream); - items[0] = SPA_DICT_ITEM_INIT(SPA_KEY_OBJECT_PATH, path); - items[1] = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_PATH, device_name); - items[2] = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_PCM_CARD, card_id); - items[3] = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_PCM_STREAM, stream); + snprintf(path, sizeof(path), "alsa:pcm:%s:%s:%s", card_index, device_name, stream); + items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_OBJECT_PATH, path); + items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_PATH, device_name); + if (dev->flags & ACP_DEVICE_UCM_DEVICE) + items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_OPEN_UCM, "true"); + items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_PCM_CARD, card_index); + items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_PCM_STREAM, stream); snprintf(channels, sizeof(channels), "%d", dev->format.channels); - items[4] = SPA_DICT_ITEM_INIT(SPA_KEY_AUDIO_CHANNELS, channels); + items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_AUDIO_CHANNELS, channels); p = positions; for (i = 0; i < dev->format.channels; i++) { p += snprintf(p, 12, "%s%s", i == 0 ? "" : ",", acp_channel_str(ch, sizeof(ch), dev->format.map[i])); } - items[5] = SPA_DICT_ITEM_INIT(SPA_KEY_AUDIO_POSITION, positions); + items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_AUDIO_POSITION, positions); snprintf(routes, sizeof(routes), "%d", dev->n_ports); - items[6] = SPA_DICT_ITEM_INIT("device.routes", routes); - n_items = 7; + items[n_items++] = SPA_DICT_ITEM_INIT("device.routes", routes); + acp_dict_for_each(it, &dev->props) items[n_items++] = SPA_DICT_ITEM_INIT(it->key, it->value); diff --git a/spa/plugins/alsa/alsa-pcm-sink.c b/spa/plugins/alsa/alsa-pcm-sink.c index 394971bc5..6ae0dadf4 100644 --- a/spa/plugins/alsa/alsa-pcm-sink.c +++ b/spa/plugins/alsa/alsa-pcm-sink.c @@ -811,6 +811,10 @@ impl_init(const struct spa_handle_factory *factory, const char *s = info->items[i].value; if (spa_streq(k, SPA_KEY_API_ALSA_PATH)) { snprintf(this->props.device, 63, "%s", s); + } else if (spa_streq(k, SPA_KEY_API_ALSA_PCM_CARD)) { + this->card_index = atoi(s); + } else if (spa_streq(k, SPA_KEY_API_ALSA_OPEN_UCM)) { + this->open_ucm = spa_atob(s); } else if (spa_streq(k, SPA_KEY_AUDIO_CHANNELS)) { this->default_channels = atoi(s); } else if (spa_streq(k, SPA_KEY_AUDIO_RATE)) { diff --git a/spa/plugins/alsa/alsa-pcm-source.c b/spa/plugins/alsa/alsa-pcm-source.c index 0993bd47b..5dcb95c00 100644 --- a/spa/plugins/alsa/alsa-pcm-source.c +++ b/spa/plugins/alsa/alsa-pcm-source.c @@ -829,6 +829,10 @@ impl_init(const struct spa_handle_factory *factory, const char *s = info->items[i].value; if (spa_streq(k, SPA_KEY_API_ALSA_PATH)) { snprintf(this->props.device, 63, "%s", s); + } else if (spa_streq(k, SPA_KEY_API_ALSA_PCM_CARD)) { + this->card_index = atoi(s); + } else if (spa_streq(k, SPA_KEY_API_ALSA_OPEN_UCM)) { + this->open_ucm = spa_atob(s); } else if (spa_streq(k, SPA_KEY_AUDIO_CHANNELS)) { this->default_channels = atoi(s); } else if (spa_streq(k, SPA_KEY_AUDIO_RATE)) { diff --git a/spa/plugins/alsa/alsa-pcm.c b/spa/plugins/alsa/alsa-pcm.c index 8b90cc823..0c2966d98 100644 --- a/spa/plugins/alsa/alsa-pcm.c +++ b/spa/plugins/alsa/alsa-pcm.c @@ -21,11 +21,28 @@ int spa_alsa_init(struct state *state) snd_config_update_free_global(); - if (strncmp(state->props.device, "_ucm", 4) == 0 && - strlen(state->props.device) >= 12 && - state->props.device[8] == '.') { - if ((err = snd_use_case_mgr_open(&state->ucm, &state->props.device[9])) < 0) + if (state->open_ucm) { + char card_name[64]; + + snprintf(card_name, sizeof(card_name), "hw:%i", state->card_index); + err = snd_use_case_mgr_open(&state->ucm, card_name); + if (err < 0) { + char *name; + err = snd_card_get_name(state->card_index, &name); + if (err < 0) { + spa_log_error(state->log, + "can't get card name from index %d", + state->card_index); + return err; + } + snprintf(card_name, sizeof(card_name), "%s", name); + free(name); + } + err = snd_use_case_mgr_open(&state->ucm, card_name); + if (err < 0) { + spa_log_error(state->log, "UCM not available for card %s", card_name); return err; + } } return 0; } diff --git a/spa/plugins/alsa/alsa-pcm.h b/spa/plugins/alsa/alsa-pcm.h index 4c59f8697..a7959cbef 100644 --- a/spa/plugins/alsa/alsa-pcm.h +++ b/spa/plugins/alsa/alsa-pcm.h @@ -95,6 +95,7 @@ struct state { struct spa_system *data_system; struct spa_loop *data_loop; + int card_index; snd_pcm_stream_t stream; snd_output_t *output; @@ -181,6 +182,7 @@ struct state { unsigned int use_mmap:1; unsigned int planar:1; unsigned int freewheel:1; + unsigned int open_ucm:1; int64_t sample_count;