[pulseaudio-discuss,2/2] alsa-ucm: Add the ability to set modargs from UCM config

Submitted by Arun Raghavan on May 3, 2016, 12:56 p.m.

Details

Message ID 1462280212-19225-3-git-send-email-arun@accosted.net
State New
Headers show
Series "Series without cover letter" ( rev: 1 ) in PulseAudio

Not browsing as part of any series.

Commit Message

Arun Raghavan May 3, 2016, 12:56 p.m.
From: Arun Raghavan <git@arunraghavan.net>

This adds mechanism to use a custom UCM value on verbs and modifiers to
allow providing sink/source module arguments that are
PulseAudio-speicific, such as mmap/tsched mode and ignore_dB.
---
 src/modules/alsa/alsa-mixer.c       |  9 +++++++
 src/modules/alsa/alsa-mixer.h       | 11 +++++++++
 src/modules/alsa/alsa-ucm.c         | 41 +++++++++++++++++++++++++++----
 src/modules/alsa/alsa-ucm.h         |  4 +++
 src/modules/alsa/module-alsa-card.c | 49 +++++++++++++++++++++++++++++++------
 5 files changed, 101 insertions(+), 13 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 3dbf6b1..5edb1bd 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -3440,6 +3440,15 @@  static void mapping_free(pa_alsa_mapping *m) {
     pa_assert(!m->input_pcm);
     pa_assert(!m->output_pcm);
 
+    if (m->sink_arguments) {
+        pa_xfree(m->sink_arguments);
+        pa_modargs_free(m->sink_modargs);
+    }
+    if (m->source_arguments) {
+        pa_xfree(m->source_arguments);
+        pa_modargs_free(m->source_modargs);
+    }
+
     pa_alsa_ucm_mapping_context_free(&m->ucm_context);
 
     pa_xfree(m);
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index 4ebf192..4aec5a5 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -29,6 +29,7 @@ 
 #include <pulse/volume.h>
 
 #include <pulsecore/llist.h>
+#include <pulsecore/modargs.h>
 #include <pulsecore/rtpoll.h>
 
 typedef struct pa_alsa_fdlist pa_alsa_fdlist;
@@ -282,6 +283,16 @@  struct pa_alsa_mapping {
     pa_sink *sink;
     pa_source *source;
 
+    /* Module arguments from config, overriden by config/command line module
+     * arguments */
+    char *sink_arguments;
+    char *source_arguments;
+
+    /* Parsed modargs, merged with the card module arguments. If null,
+     * signifies that card modargs should directly be used. */
+    pa_modargs *sink_modargs;
+    pa_modargs *source_modargs;
+
     /* ucm device context*/
     pa_alsa_ucm_mapping_context ucm_context;
 };
diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c
index 85b0913..458fe36 100644
--- a/src/modules/alsa/alsa-ucm.c
+++ b/src/modules/alsa/alsa-ucm.c
@@ -103,6 +103,8 @@  static struct ucm_items item[] = {
     {"TQ", PA_ALSA_PROP_UCM_QOS},
     {"JackControl", PA_ALSA_PROP_UCM_JACK_CONTROL},
     {"JackHWMute", PA_ALSA_PROP_UCM_JACK_HW_MUTE},
+    {"PulseAudioSinkModargs", PA_ALSA_PROP_UCM_SINK_MODARGS},
+    {"PulseAudioSourceModargs", PA_ALSA_PROP_UCM_SOURCE_MODARGS},
     {NULL, NULL},
 };
 
@@ -1253,6 +1255,7 @@  static int ucm_create_mapping_direction(
         pa_alsa_profile_set *ps,
         pa_alsa_profile *p,
         pa_alsa_ucm_device *device,
+        pa_alsa_ucm_verb *verb,
         const char *verb_name,
         const char *device_name,
         const char *device_str,
@@ -1260,6 +1263,7 @@  static int ucm_create_mapping_direction(
 
     pa_alsa_mapping *m;
     char *mapping_name;
+    const char *value;
     unsigned priority, rate, channels;
 
     mapping_name = pa_sprintf_malloc("Mapping %s: %s: %s", verb_name, device_str, is_sink ? "sink" : "source");
@@ -1290,6 +1294,16 @@  static int ucm_create_mapping_direction(
         if (rate)
             m->sample_spec.rate = rate;
         pa_channel_map_init_extend(&m->channel_map, channels, PA_CHANNEL_MAP_ALSA);
+
+        if (is_sink) {
+            value = pa_proplist_gets(verb->proplist, PA_ALSA_PROP_UCM_SINK_MODARGS);
+            if (value)
+                m->sink_arguments = pa_xstrdup(value);
+        } else {
+            value = pa_proplist_gets(verb->proplist, PA_ALSA_PROP_UCM_SOURCE_MODARGS);
+            if (value)
+                m->source_arguments = pa_xstrdup(value);
+        }
     }
 
     /* mapping priority is the highest one of ucm devices */
@@ -1310,6 +1324,7 @@  static int ucm_create_mapping_for_modifier(
         pa_alsa_profile_set *ps,
         pa_alsa_profile *p,
         pa_alsa_ucm_modifier *modifier,
+        pa_alsa_ucm_verb *verb,
         const char *verb_name,
         const char *mod_name,
         const char *device_str,
@@ -1317,6 +1332,7 @@  static int ucm_create_mapping_for_modifier(
 
     pa_alsa_mapping *m;
     char *mapping_name;
+    const char *value;
 
     mapping_name = pa_sprintf_malloc("Mapping %s: %s: %s", verb_name, device_str, is_sink ? "sink" : "source");
 
@@ -1342,6 +1358,20 @@  static int ucm_create_mapping_for_modifier(
         m->priority = 0;
 
         ucm_add_mapping(p, m);
+
+        if (is_sink) {
+            value = pa_proplist_gets(modifier->proplist, PA_ALSA_PROP_UCM_SINK_MODARGS);
+            if (!value)
+                value = pa_proplist_gets(verb->proplist, PA_ALSA_PROP_UCM_SINK_MODARGS);
+            if (value)
+                m->sink_arguments = pa_xstrdup(value);
+        } else {
+            value = pa_proplist_gets(modifier->proplist, PA_ALSA_PROP_UCM_SOURCE_MODARGS);
+            if (!value)
+                value = pa_proplist_gets(verb->proplist, PA_ALSA_PROP_UCM_SOURCE_MODARGS);
+            if (value)
+                m->source_arguments = pa_xstrdup(value);
+        }
     } else if (!m->ucm_context.ucm_modifiers) /* share pcm with device */
         m->ucm_context.ucm_modifiers = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
 
@@ -1355,6 +1385,7 @@  static int ucm_create_mapping(
         pa_alsa_profile_set *ps,
         pa_alsa_profile *p,
         pa_alsa_ucm_device *device,
+        pa_alsa_ucm_verb *verb,
         const char *verb_name,
         const char *device_name,
         const char *sink,
@@ -1368,9 +1399,9 @@  static int ucm_create_mapping(
     }
 
     if (sink)
-        ret = ucm_create_mapping_direction(ucm, ps, p, device, verb_name, device_name, sink, true);
+        ret = ucm_create_mapping_direction(ucm, ps, p, device, verb, verb_name, device_name, sink, true);
     if (ret == 0 && source)
-        ret = ucm_create_mapping_direction(ucm, ps, p, device, verb_name, device_name, source, false);
+        ret = ucm_create_mapping_direction(ucm, ps, p, device, verb, verb_name, device_name, source, false);
 
     return ret;
 }
@@ -1475,7 +1506,7 @@  static int ucm_create_profile(
         sink = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_SINK);
         source = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_SOURCE);
 
-        ucm_create_mapping(ucm, ps, p, dev, verb_name, name, sink, source);
+        ucm_create_mapping(ucm, ps, p, dev, verb, verb_name, name, sink, source);
 
         jack = ucm_get_jack(ucm, dev);
         device_set_jack(dev, jack);
@@ -1521,9 +1552,9 @@  static int ucm_create_profile(
         source = pa_proplist_gets(mod->proplist, PA_ALSA_PROP_UCM_SOURCE);
 
         if (sink)
-            ucm_create_mapping_for_modifier(ucm, ps, p, mod, verb_name, name, sink, true);
+            ucm_create_mapping_for_modifier(ucm, ps, p, mod, verb, verb_name, name, sink, true);
         else if (source)
-            ucm_create_mapping_for_modifier(ucm, ps, p, mod, verb_name, name, source, false);
+            ucm_create_mapping_for_modifier(ucm, ps, p, mod, verb, verb_name, name, source, false);
     }
 
     pa_alsa_profile_dump(p);
diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h
index f566574..165c68f 100644
--- a/src/modules/alsa/alsa-ucm.h
+++ b/src/modules/alsa/alsa-ucm.h
@@ -81,6 +81,10 @@  typedef void snd_use_case_mgr_t;
 /** For devices: Quality of Service */
 #define PA_ALSA_PROP_UCM_QOS                        "alsa.ucm.qos"
 
+/** For verbs/devices/modifiers: Passthrough module arguments for the corresponding Playback/CapturePCM */
+#define PA_ALSA_PROP_UCM_SINK_MODARGS                        "alsa.ucm.sink_arguments"
+#define PA_ALSA_PROP_UCM_SOURCE_MODARGS                      "alsa.ucm.source_arguments"
+
 /** For devices: The modifier (if any) that this device corresponds to */
 #define PA_ALSA_PROP_UCM_MODIFIER "alsa.ucm.modifier"
 
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index b743943..ce660df 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -249,7 +249,7 @@  static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
         PA_IDXSET_FOREACH(am, nd->profile->output_mappings, idx) {
 
             if (!am->sink)
-                am->sink = pa_alsa_sink_new(c->module, u->modargs, __FILE__, c, am);
+                am->sink = pa_alsa_sink_new(c->module, am->sink_modargs ? am->sink_modargs : u->modargs, __FILE__, c, am);
 
             if (sink_inputs && am->sink) {
                 pa_sink_move_all_finish(am->sink, sink_inputs, false);
@@ -261,7 +261,7 @@  static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
         PA_IDXSET_FOREACH(am, nd->profile->input_mappings, idx) {
 
             if (!am->source)
-                am->source = pa_alsa_source_new(c->module, u->modargs, __FILE__, c, am);
+                am->source = pa_alsa_source_new(c->module, am->source_modargs ? am->source_modargs : u->modargs, __FILE__, c, am);
 
             if (source_outputs && am->source) {
                 pa_source_move_all_finish(am->source, source_outputs, false);
@@ -279,11 +279,26 @@  finish:
     return ret;
 }
 
+static pa_modargs* prepare_modargs(const char *module, const char *config) {
+    pa_modargs *ma;
+
+    /* It's easier to re-parse the module arguments than to do a deep modargs copy */
+    ma = pa_modargs_new(module, valid_modargs);
+    if (!ma)
+        return NULL;
+
+    if (pa_modargs_append(ma, config, valid_modargs) < 0)
+        pa_log_error("Error parsing modargs from configuration");
+
+    return ma;
+}
+
 static void init_profile(struct userdata *u) {
     uint32_t idx;
     pa_alsa_mapping *am;
     struct profile_data *d;
     pa_alsa_ucm_config *ucm = &u->ucm;
+    pa_modargs *modargs;
 
     pa_assert(u);
 
@@ -297,13 +312,31 @@  static void init_profile(struct userdata *u) {
         }
     }
 
-    if (d->profile && d->profile->output_mappings)
-        PA_IDXSET_FOREACH(am, d->profile->output_mappings, idx)
-            am->sink = pa_alsa_sink_new(u->module, u->modargs, __FILE__, u->card, am);
+    modargs = u->modargs;
+
+    if (d->profile && d->profile->output_mappings) {
+        PA_IDXSET_FOREACH(am, d->profile->output_mappings, idx) {
+            if (am->sink_arguments) {
+                am->sink_modargs = prepare_modargs(u->module->argument, am->sink_arguments);
+                pa_assert(am->sink_modargs);
+                modargs = am->sink_modargs;
+            }
 
-    if (d->profile && d->profile->input_mappings)
-        PA_IDXSET_FOREACH(am, d->profile->input_mappings, idx)
-            am->source = pa_alsa_source_new(u->module, u->modargs, __FILE__, u->card, am);
+            am->sink = pa_alsa_sink_new(u->module, modargs, __FILE__, u->card, am);
+        }
+    }
+
+    if (d->profile && d->profile->input_mappings) {
+        PA_IDXSET_FOREACH(am, d->profile->input_mappings, idx) {
+            if (am->source_arguments) {
+                am->source_modargs = prepare_modargs(u->module->argument, am->source_arguments);
+                pa_assert(am->source_modargs);
+                modargs = am->source_modargs;
+            }
+
+            am->source = pa_alsa_source_new(u->module, modargs, __FILE__, u->card, am);
+        }
+    }
 }
 
 static pa_available_t calc_port_state(pa_device_port *p, struct userdata *u) {

Comments

On Tue, 2016-05-03 at 18:26 +0530, arun@accosted.net wrote:
> @@ -1253,6 +1255,7 @@ static int ucm_create_mapping_direction(
>          pa_alsa_profile_set *ps,
>          pa_alsa_profile *p,
>          pa_alsa_ucm_device *device,
> +        pa_alsa_ucm_verb *verb,
>          const char *verb_name,

The verb_name argument could be removed, since it's available through
the verb object.

> @@ -1310,6 +1324,7 @@ static int ucm_create_mapping_for_modifier(
>          pa_alsa_profile_set *ps,
>          pa_alsa_profile *p,
>          pa_alsa_ucm_modifier *modifier,
> +        pa_alsa_ucm_verb *verb,
>          const char *verb_name,

Same as above.

> @@ -1355,6 +1385,7 @@ static int ucm_create_mapping(
>          pa_alsa_profile_set *ps,
>          pa_alsa_profile *p,
>          pa_alsa_ucm_device *device,
> +        pa_alsa_ucm_verb *verb,
>          const char *verb_name,

Same as above.

> @@ -249,7 +249,7 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
>          PA_IDXSET_FOREACH(am, nd->profile->output_mappings, idx) {
>  
>              if (!am->sink)
> -                am->sink = pa_alsa_sink_new(c->module, u->modargs, __FILE__, c, am);
> +                am->sink = pa_alsa_sink_new(c->module, am->sink_modargs ? am->sink_modargs : u->modargs, __FILE__, c, am);

I think it would be nicer if the place where you prepare am-
>sink_modargs would always set the variable, so that we could always
pass am->sink_modargs here.

> +static pa_modargs* prepare_modargs(const char *module, const char *config) {
> +    pa_modargs *ma;
> +
> +    /* It's easier to re-parse the module arguments than to do a deep modargs copy */
> +    ma = pa_modargs_new(module, valid_modargs);
> +    if (!ma)
> +        return NULL;

This should never happen, so an assertion would be better here.

-- 
Tanu