Commit 35e81fbf authored by Wim Taymans's avatar Wim Taymans
Browse files

alsa: rework UCM open

Use _alibpref to check if a device needs a UCM local config. Mark
the device as such and use this to set the OPEN_UCM property on
the device.
Open the UCM for a card when the device has the property set. Use the
same logic for loading the UCM as the acp code.

See #1251
parent 58d0e446
Pipeline #330905 passed with stages
in 2 minutes and 38 seconds
......@@ -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 */
......
......@@ -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);
}
......
......@@ -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;
......
......@@ -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);
......
......@@ -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)) {
......
......@@ -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)) {
......
......@@ -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;
}
......
......@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment