[pulseaudio-discuss] [PATCH 3/3] alsa-ucm: Support Playback/CaptureVolume
David Henningsson
david.henningsson at canonical.com
Mon Sep 30 05:06:48 PDT 2013
On 09/20/2013 01:57 PM, Arun Raghavan wrote:
> This allows us to support the PlaybackVolume and CaptureVolume commands
> in UCM, specifying a mixer control to use for hardware volume control.
>
> This only works with ports corresponding to single devices at the
> moment, and doesn't support stacking controls for combination ports.
>
> On the UCM side, this also requires that when disabling the device for
> the port, the volume should be reset to some default.
Overall, this seems to be a very well written patch, good work! Just two
comments further down.
> When enabling/disabling combination devices, things are a bit iffy since
> we have no way to reset the volume before switching to a combination
> device. It would be nice to have a combination-transition-sequence
> command in UCM to handle this and other similar cases.
> ---
> src/modules/alsa/alsa-sink.c | 69 +++++++++++++++-----
> src/modules/alsa/alsa-source.c | 34 ++++++----
> src/modules/alsa/alsa-ucm.c | 126 ++++++++++++++++++++++++++++++++++--
> src/modules/alsa/alsa-ucm.h | 19 +++++-
> src/modules/alsa/module-alsa-card.c | 4 +-
> 5 files changed, 215 insertions(+), 37 deletions(-)
>
> diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
> index d3d5b19..3b64448 100644
> --- a/src/modules/alsa/alsa-sink.c
> +++ b/src/modules/alsa/alsa-sink.c
> @@ -1422,7 +1422,7 @@ static void sink_set_mute_cb(pa_sink *s) {
> static void mixer_volume_init(struct userdata *u) {
> pa_assert(u);
>
> - if (!u->mixer_path->has_volume) {
> + if (!u->mixer_path || !u->mixer_path->has_volume) {
> pa_sink_set_write_volume_callback(u->sink, NULL);
> pa_sink_set_get_volume_callback(u->sink, NULL);
> pa_sink_set_set_volume_callback(u->sink, NULL);
> @@ -1457,7 +1457,7 @@ static void mixer_volume_init(struct userdata *u) {
> pa_log_info("Using hardware volume control. Hardware dB scale %s.", u->mixer_path->has_dB ? "supported" : "not supported");
> }
>
> - if (!u->mixer_path->has_mute) {
> + if (!u->mixer_path || !u->mixer_path->has_mute) {
> pa_sink_set_get_mute_callback(u->sink, NULL);
> pa_sink_set_set_mute_callback(u->sink, NULL);
> pa_log_info("Driver does not support hardware mute control, falling back to software mute control.");
> @@ -1470,10 +1470,31 @@ static void mixer_volume_init(struct userdata *u) {
>
> static int sink_set_port_ucm_cb(pa_sink *s, pa_device_port *p) {
> struct userdata *u = s->userdata;
> + pa_alsa_ucm_port_data *data;
> +
> + data = PA_DEVICE_PORT_DATA(p);
>
> pa_assert(u);
> pa_assert(p);
> pa_assert(u->ucm_context);
> + pa_assert(u->mixer_handle);
> +
> + u->mixer_path = data->path;
> + mixer_volume_init(u);
> +
> + if (data->path) {
> + pa_alsa_path_select(u->mixer_path, NULL, u->mixer_handle, s->muted);
> +
> + if (s->set_mute)
> + s->set_mute(s);
> + if (s->flags & PA_SINK_DEFERRED_VOLUME) {
> + if (s->write_volume)
> + s->write_volume(s);
> + } else {
> + if (s->set_volume)
> + s->set_volume(s);
> + }
> + }
>
> return pa_alsa_ucm_set_port(u->ucm_context, p, true);
> }
> @@ -1896,7 +1917,7 @@ static void set_sink_name(pa_sink_new_data *data, pa_modargs *ma, const char *de
> static void find_mixer(struct userdata *u, pa_alsa_mapping *mapping, const char *element, bool ignore_dB) {
> snd_hctl_t *hctl;
>
> - if (!mapping && !element)
> + if (!u->ucm_context && (!mapping && !element))
> return;
>
> if (!(u->mixer_handle = pa_alsa_open_mixer_for_pcm(u->pcm_handle, &u->control_device, &hctl))) {
> @@ -1904,6 +1925,11 @@ static void find_mixer(struct userdata *u, pa_alsa_mapping *mapping, const char
> return;
> }
>
> + if (u->ucm_context) {
> + /* We just want to open the device */
> + return;
> + }
> +
> if (element) {
>
> if (!(u->mixer_path = pa_alsa_path_synthesize(element, PA_ALSA_DIRECTION_OUTPUT)))
> @@ -1941,16 +1967,31 @@ static int setup_mixer(struct userdata *u, bool ignore_dB) {
> return 0;
>
> if (u->sink->active_port) {
> - pa_alsa_port_data *data;
> + if (!u->ucm_context) {
> + pa_alsa_port_data *data;
>
> - /* We have a list of supported paths, so let's activate the
> - * one that has been chosen as active */
> + /* We have a list of supported paths, so let's activate the
> + * one that has been chosen as active */
>
> - data = PA_DEVICE_PORT_DATA(u->sink->active_port);
> - u->mixer_path = data->path;
> + data = PA_DEVICE_PORT_DATA(u->sink->active_port);
> + u->mixer_path = data->path;
>
> - pa_alsa_path_select(data->path, data->setting, u->mixer_handle, u->sink->muted);
> + pa_alsa_path_select(data->path, data->setting, u->mixer_handle, u->sink->muted);
> + } else {
> + pa_alsa_ucm_port_data *data;
> +
> + /* First activate the port on the UCM side */
> + if (pa_alsa_ucm_set_port(u->ucm_context, u->sink->active_port, true) < 0)
> + return -1;
>
> + data = PA_DEVICE_PORT_DATA(u->sink->active_port);
> +
> + /* Now activate volume controls, if any */
> + if (data->path) {
> + u->mixer_path = data->path;
> + pa_alsa_path_select(data->path, NULL, u->mixer_handle, u->sink->muted);
> + }
> + }
> } else {
>
> if (!u->mixer_path && u->mixer_path_set)
> @@ -2244,8 +2285,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
> /* ALSA might tweak the sample spec, so recalculate the frame size */
> frame_size = pa_frame_size(&ss);
>
> - if (!u->ucm_context)
> - find_mixer(u, mapping, pa_modargs_get_value(ma, "control", NULL), ignore_dB);
> + find_mixer(u, mapping, pa_modargs_get_value(ma, "control", NULL), ignore_dB);
>
> pa_sink_new_data_init(&data);
> data.driver = driver;
> @@ -2295,7 +2335,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
> }
>
> if (u->ucm_context)
> - pa_alsa_ucm_add_ports(&data.ports, data.proplist, u->ucm_context, true, card);
> + pa_alsa_ucm_add_ports(&data.ports, data.proplist, u->ucm_context, true, card, u->pcm_handle, ignore_dB);
> else if (u->mixer_path_set)
> pa_alsa_add_ports(&data, u->mixer_path_set, card);
>
> @@ -2366,10 +2406,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
> if (update_sw_params(u) < 0)
> goto fail;
>
> - if (u->ucm_context) {
> - if (u->sink->active_port && pa_alsa_ucm_set_port(u->ucm_context, u->sink->active_port, true) < 0)
> - goto fail;
> - } else if (setup_mixer(u, ignore_dB) < 0)
> + if (setup_mixer(u, ignore_dB) < 0)
> goto fail;
>
> pa_alsa_dump(PA_LOG_DEBUG, u->pcm_handle);
> diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
> index 8416ba8..9b80b9e 100644
> --- a/src/modules/alsa/alsa-source.c
> +++ b/src/modules/alsa/alsa-source.c
> @@ -1652,16 +1652,31 @@ static int setup_mixer(struct userdata *u, bool ignore_dB) {
> return 0;
>
> if (u->source->active_port) {
> - pa_alsa_port_data *data;
> + if (!u->ucm_context) {
> + pa_alsa_port_data *data;
>
> - /* We have a list of supported paths, so let's activate the
> - * one that has been chosen as active */
> + /* We have a list of supported paths, so let's activate the
> + * one that has been chosen as active */
>
> - data = PA_DEVICE_PORT_DATA(u->source->active_port);
> - u->mixer_path = data->path;
> + data = PA_DEVICE_PORT_DATA(u->source->active_port);
> + u->mixer_path = data->path;
>
> - pa_alsa_path_select(data->path, data->setting, u->mixer_handle, u->source->muted);
> + pa_alsa_path_select(data->path, data->setting, u->mixer_handle, u->source->muted);
> + } else {
> + pa_alsa_ucm_port_data *data;
> +
> + /* First activate the port on the UCM side */
> + if (pa_alsa_ucm_set_port(u->ucm_context, u->source->active_port, true) < 0)
> + return -1;
> +
> + data = PA_DEVICE_PORT_DATA(u->source->active_port);
>
> + /* Now activate volume controls, if any */
> + if (data->path) {
> + u->mixer_path = data->path;
> + pa_alsa_path_select(data->path, NULL, u->mixer_handle, u->source->muted);
> + }
> + }
> } else {
>
> if (!u->mixer_path && u->mixer_path_set)
> @@ -1994,7 +2009,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
> }
>
> if (u->ucm_context)
> - pa_alsa_ucm_add_ports(&data.ports, data.proplist, u->ucm_context, false, card);
> + pa_alsa_ucm_add_ports(&data.ports, data.proplist, u->ucm_context, false, card, u->pcm_handle, ignore_dB);
> else if (u->mixer_path_set)
> pa_alsa_add_ports(&data, u->mixer_path_set, card);
>
> @@ -2057,10 +2072,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
> if (update_sw_params(u) < 0)
> goto fail;
>
> - if (u->ucm_context) {
> - if (u->source->active_port && pa_alsa_ucm_set_port(u->ucm_context, u->source->active_port, false) < 0)
> - goto fail;
> - } else if (setup_mixer(u, ignore_dB) < 0)
> + if (setup_mixer(u, ignore_dB) < 0)
> goto fail;
>
> pa_alsa_dump(PA_LOG_DEBUG, u->pcm_handle);
> diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c
> index 47ff926..822f760 100644
> --- a/src/modules/alsa/alsa-ucm.c
> +++ b/src/modules/alsa/alsa-ucm.c
> @@ -278,6 +278,17 @@ static int ucm_get_device_property(
> else
> pa_log_debug("UCM playback priority %s for device %s error", value, device_name);
> }
> +
> + /* Volume control element */
> + if (!device->playback_volume)
> + device->playback_volume = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, pa_xfree,
> + pa_xfree);
> +
> + value = pa_proplist_gets(device->proplist, PA_ALSA_PROP_UCM_PLAYBACK_VOLUME);
> + if (value) {
> + pa_hashmap_put(device->playback_volume, pa_xstrdup(pa_proplist_gets(verb->proplist, PA_ALSA_PROP_UCM_NAME)),
> + pa_xstrdup(value));
> + }
> }
>
> if (device->capture_channels) { /* source device */
> @@ -299,6 +310,17 @@ static int ucm_get_device_property(
> else
> pa_log_debug("UCM capture priority %s for device %s error", value, device_name);
> }
> +
> + /* Volume control element */
> + if (!device->capture_volume)
> + device->capture_volume = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, pa_xfree,
> + pa_xfree);
> +
> + value = pa_proplist_gets(device->proplist, PA_ALSA_PROP_UCM_CAPTURE_VOLUME);
> + if (value) {
> + pa_hashmap_put(device->capture_volume, pa_xstrdup(pa_proplist_gets(verb->proplist, PA_ALSA_PROP_UCM_NAME)),
> + pa_xstrdup(value));
> + }
> }
>
> if (PA_UCM_PLAYBACK_PRIORITY_UNSET(device) || PA_UCM_CAPTURE_PRIORITY_UNSET(device)) {
> @@ -671,6 +693,57 @@ static int pa_alsa_ucm_device_cmp(const void *a, const void *b) {
> return strcmp(pa_proplist_gets(d1->proplist, PA_ALSA_PROP_UCM_NAME), pa_proplist_gets(d2->proplist, PA_ALSA_PROP_UCM_NAME));
> }
>
> +static void ucm_port_data_free(pa_device_port *port) {
> + pa_alsa_ucm_port_data *data = PA_DEVICE_PORT_DATA(port);
> +
> + if (data->paths) {
> + pa_hashmap_free(data->paths);
> + }
> +
> + data->path = NULL;
Any reason why you set data->path to null but not data->paths?
> +}
> +
> +static void probe_volumes(pa_hashmap *hash, snd_pcm_t *pcm_handle, bool ignore_dB) {
> + pa_device_port *port;
> + pa_alsa_path *path;
> + pa_alsa_ucm_port_data *data;
> + snd_mixer_t *mixer_handle;
> + snd_hctl_t *hctl;
> + const char *profile;
> + void *state, *state2;
> +
> + if (!(mixer_handle = pa_alsa_open_mixer_for_pcm(pcm_handle, NULL, &hctl))) {
> + pa_log_error("Failed to find a working mixer device.");
> + goto fail;
> + }
You probably want to not do "pa_alsa_open_mixer_for_pcm" here, but
instead try to use whatever the ucm file specifies in "cset" - in most
cases there wouldn't be a difference, but who knows...
(This might also apply to more places)
> +
> + PA_HASHMAP_FOREACH(port, hash, state) {
> + data = PA_DEVICE_PORT_DATA(port);
> +
> + PA_HASHMAP_FOREACH_KV(profile, path, data->paths, state2) {
> + if (pa_alsa_path_probe(path, mixer_handle, hctl, ignore_dB) < 0) {
> + pa_log_warn("Could not probe path: %s, using s/w volume", data->path->name);
> + pa_hashmap_remove(data->paths, profile);
> + pa_alsa_path_free(path);
> + } else
> + pa_log_debug("Set up h/w volume using '%s' for %s:%s", path->name, profile, port->name);
> + }
> + }
> +
> + return;
> +
> +fail:
> + /* We could not probe the paths we created. Free them and rever to software volumes. */
> + PA_HASHMAP_FOREACH(port, hash, state) {
> + data = PA_DEVICE_PORT_DATA(port);
> +
> + if (data->path) {
> + pa_alsa_path_free(data->path);
> + data->path = NULL;
> + }
> + }
> +}
> +
> static void ucm_add_port_combination(
> pa_hashmap *hash,
> pa_alsa_ucm_mapping_context *context,
> @@ -688,7 +761,10 @@ static void ucm_add_port_combination(
> char *name, *desc;
> const char *dev_name;
> const char *direction;
> + const char *profile, *volume;
> pa_alsa_ucm_device *sorted[num], *dev;
> + pa_alsa_ucm_port_data *data;
> + void *state;
>
> for (i = 0; i < num; i++)
> sorted[i] = pdevices[i];
> @@ -743,15 +819,35 @@ static void ucm_add_port_combination(
> pa_device_port_new_data_set_description(&port_data, desc);
> pa_device_port_new_data_set_direction(&port_data, is_sink ? PA_DIRECTION_OUTPUT : PA_DIRECTION_INPUT);
>
> - port = pa_device_port_new(core, &port_data, 0);
> + port = pa_device_port_new(core, &port_data, sizeof(pa_alsa_ucm_port_data));
> pa_device_port_new_data_done(&port_data);
> - pa_assert(port);
> +
> + data = PA_DEVICE_PORT_DATA(port);
> + data->paths = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, pa_xfree,
> + (pa_free_cb_t) pa_alsa_path_free);
> + port->impl_free = ucm_port_data_free;
>
> pa_hashmap_put(ports, port->name, port);
> pa_log_debug("Add port %s: %s", port->name, port->description);
> port->profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
> }
>
> + if (num == 1) {
> + /* To keep things simple and not worry about stacking controls, we only support hardware volumes on non-combination
> + * ports. */
> + data = PA_DEVICE_PORT_DATA(port);
> +
> + PA_HASHMAP_FOREACH_KV(profile, volume, is_sink ? dev->playback_volume : dev->capture_volume, state) {
> + pa_alsa_path *path = pa_alsa_path_synthesize(volume,
> + is_sink ? PA_ALSA_DIRECTION_OUTPUT : PA_ALSA_DIRECTION_INPUT);
> +
> + if (!path)
> + pa_log_warn("Failed to set up volume control: %s", volume);
> + else
> + pa_hashmap_put(data->paths, pa_xstrdup(profile), path);
> + }
> + }
> +
> port->priority = priority;
>
> pa_xfree(name);
> @@ -931,7 +1027,9 @@ void pa_alsa_ucm_add_ports(
> pa_proplist *proplist,
> pa_alsa_ucm_mapping_context *context,
> bool is_sink,
> - pa_card *card) {
> + pa_card *card,
> + snd_pcm_t *pcm_handle,
> + bool ignore_dB) {
>
> uint32_t idx;
> char *merged_roles;
> @@ -946,6 +1044,9 @@ void pa_alsa_ucm_add_ports(
> /* add ports first */
> pa_alsa_ucm_add_ports_combination(*p, context, is_sink, card->ports, NULL, card->core);
>
> + /* now set up volume paths if any */
> + probe_volumes(*p, pcm_handle, ignore_dB);
> +
> /* then set property PA_PROP_DEVICE_INTENDED_ROLES */
> merged_roles = pa_xstrdup(pa_proplist_gets(proplist, PA_PROP_DEVICE_INTENDED_ROLES));
> PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) {
> @@ -970,10 +1071,13 @@ void pa_alsa_ucm_add_ports(
> }
>
> /* Change UCM verb and device to match selected card profile */
> -int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, const char *new_profile, const char *old_profile) {
> +int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, const char *new_profile, const char *old_profile) {
> int ret = 0;
> const char *profile;
> pa_alsa_ucm_verb *verb;
> + pa_device_port *port;
> + pa_alsa_ucm_port_data *data;
> + void *state;
>
> if (new_profile == old_profile)
> return ret;
> @@ -1002,6 +1106,12 @@ int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, const char *new_profile, co
> }
> }
>
> + /* select volume controls on ports */
> + PA_HASHMAP_FOREACH(port, card->ports, state) {
> + data = PA_DEVICE_PORT_DATA(port);
> + data->path = pa_hashmap_get(data->paths, new_profile);
> + }
> +
> return ret;
> }
>
> @@ -1551,6 +1661,8 @@ static void free_verb(pa_alsa_ucm_verb *verb) {
>
> PA_LLIST_FOREACH_SAFE(di, dn, verb->devices) {
> PA_LLIST_REMOVE(pa_alsa_ucm_device, verb->devices, di);
> + pa_hashmap_free(di->playback_volume);
> + pa_hashmap_free(di->capture_volume);
> pa_proplist_free(di->proplist);
> if (di->conflicting_devices)
> pa_idxset_free(di->conflicting_devices, NULL);
> @@ -1684,7 +1796,7 @@ pa_alsa_profile_set* pa_alsa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_cha
> return NULL;
> }
>
> -int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, const char *new_profile, const char *old_profile) {
> +int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, const char *new_profile, const char *old_profile) {
> return -1;
> }
>
> @@ -1697,7 +1809,9 @@ void pa_alsa_ucm_add_ports(
> pa_proplist *proplist,
> pa_alsa_ucm_mapping_context *context,
> bool is_sink,
> - pa_card *card) {
> + pa_card *card,
> + snd_pcm_t *pcm_handle,
> + bool ignore_dB) {
> }
>
> void pa_alsa_ucm_add_ports_combination(
> diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h
> index 2fae6c4..36a491f 100644
> --- a/src/modules/alsa/alsa-ucm.h
> +++ b/src/modules/alsa/alsa-ucm.h
> @@ -91,10 +91,11 @@ typedef struct pa_alsa_ucm_modifier pa_alsa_ucm_modifier;
> typedef struct pa_alsa_ucm_device pa_alsa_ucm_device;
> typedef struct pa_alsa_ucm_config pa_alsa_ucm_config;
> typedef struct pa_alsa_ucm_mapping_context pa_alsa_ucm_mapping_context;
> +typedef struct pa_alsa_ucm_port_data pa_alsa_ucm_port_data;
>
> int pa_alsa_ucm_query_profiles(pa_alsa_ucm_config *ucm, int card_index);
> pa_alsa_profile_set* pa_alsa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map);
> -int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, const char *new_profile, const char *old_profile);
> +int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, const char *new_profile, const char *old_profile);
>
> int pa_alsa_ucm_get_verb(snd_use_case_mgr_t *uc_mgr, const char *verb_name, const char *verb_desc, pa_alsa_ucm_verb **p_verb);
>
> @@ -103,7 +104,9 @@ void pa_alsa_ucm_add_ports(
> pa_proplist *proplist,
> pa_alsa_ucm_mapping_context *context,
> bool is_sink,
> - pa_card *card);
> + pa_card *card,
> + snd_pcm_t *pcm_handle,
> + bool ignore_dB);
> void pa_alsa_ucm_add_ports_combination(
> pa_hashmap *hash,
> pa_alsa_ucm_mapping_context *context,
> @@ -135,6 +138,11 @@ struct pa_alsa_ucm_device {
> unsigned playback_channels;
> unsigned capture_channels;
>
> + /* These may be different per verb, so we store this as a hashmap of verb -> volume_control. We might eventually want to
> + * make this a hashmap of verb -> per-verb-device-properties-struct. */
> + pa_hashmap *playback_volume;
> + pa_hashmap *capture_volume;
> +
> pa_alsa_mapping *playback_mapping;
> pa_alsa_mapping *capture_mapping;
>
> @@ -194,4 +202,11 @@ struct pa_alsa_ucm_mapping_context {
> pa_idxset *ucm_modifiers;
> };
>
> +struct pa_alsa_ucm_port_data {
> + /* profile -> pa_alsa_path for volume control */
> + pa_hashmap *paths;
> + /* Current path, set when activating profile */
> + pa_alsa_path *path;
> +};
> +
> #endif
> diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
> index 96e88e5..970344a 100644
> --- a/src/modules/alsa/module-alsa-card.c
> +++ b/src/modules/alsa/module-alsa-card.c
> @@ -244,7 +244,7 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
>
> /* if UCM is available for this card then update the verb */
> if (u->use_ucm) {
> - if (pa_alsa_ucm_set_profile(&u->ucm, nd->profile ? nd->profile->name : NULL,
> + if (pa_alsa_ucm_set_profile(&u->ucm, c, nd->profile ? nd->profile->name : NULL,
> od->profile ? od->profile->name : NULL) < 0)
> return -1;
> }
> @@ -294,7 +294,7 @@ static void init_profile(struct userdata *u) {
>
> if (d->profile && u->use_ucm) {
> /* Set initial verb */
> - if (pa_alsa_ucm_set_profile(ucm, d->profile->name, NULL) < 0) {
> + if (pa_alsa_ucm_set_profile(ucm, u->card, d->profile->name, NULL) < 0) {
> pa_log("Failed to set ucm profile %s", d->profile->name);
> return;
> }
>
--
David Henningsson, Canonical Ltd.
https://launchpad.net/~diwic
More information about the pulseaudio-discuss
mailing list