]> git.alsa-project.org Git - alsa-utils.git/commitdiff
topology: pre-process-object: Add support for pre-processing Objects
authorRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Mon, 26 Apr 2021 16:34:48 +0000 (09:34 -0700)
committerJaroslav Kysela <perex@perex.cz>
Tue, 25 May 2021 16:26:51 +0000 (18:26 +0200)
Add support for pre-processing object instances in the input
config. An object's attributes can be set in multiple places
such as, within the object instance, default values in the class
defnition, inherited from a parent object or explicitly set
in a parent object. Before converting the object config into
the relevant section in the existing syntax, all the attribute
values must be consolidated into one place so that it is easy
to verify if all mandatory attributes are set.
Also, the name of the object will be constructed from the
attributes defined in the attributes.constructor[] config
in the class definition and the unique attribute's value
must be set from the value passed in the object instance.

This patch create a temporary config for each object instance
and populates its unique attribute value. The rest of the steps
will be added in the following patches.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
topology/Makefile.am
topology/pre-process-object.c [new file with mode: 0644]
topology/pre-processor.c
topology/pre-processor.h

index f97851a7ac3cc8d37d701b9fbcc3a337e7787d40..8efbf4f358de6c59ba847993a2a52ca272683670 100644 (file)
@@ -8,7 +8,7 @@ endif
 %.1: %.rst
        rst2man $< > $@
 
-alsatplg_SOURCES = topology.c pre-processor.c pre-process-class.c
+alsatplg_SOURCES = topology.c pre-processor.c pre-process-class.c pre-process-object.c
 
 noinst_HEADERS = topology.h pre-processor.h
 
diff --git a/topology/pre-process-object.c b/topology/pre-process-object.c
new file mode 100644 (file)
index 0000000..efcf48f
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+  Copyright(c) 2021 Intel Corporation
+  All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  The full GNU General Public License is included in this distribution
+  in the file called LICENSE.GPL.
+*/
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <alsa/input.h>
+#include <alsa/output.h>
+#include <alsa/conf.h>
+#include <alsa/error.h>
+#include "gettext.h"
+#include "topology.h"
+#include "pre-processor.h"
+
+/* set the attribute value by type */
+static int tplg_set_attribute_value(snd_config_t *attr, const char *value)
+{
+       int err;
+       snd_config_type_t type = snd_config_get_type(attr);
+
+       switch (type) {
+       case SND_CONFIG_TYPE_INTEGER:
+       {
+               long v;
+
+               v = strtol(value, NULL, 10);
+               err = snd_config_set_integer(attr, v);
+               assert(err >= 0);
+               break;
+       }
+       case SND_CONFIG_TYPE_INTEGER64:
+       {
+               long long v;
+
+               v = strtoll(value, NULL, 10);
+               err = snd_config_set_integer64(attr, v);
+               assert(err >= 0);
+               break;
+       }
+       case SND_CONFIG_TYPE_STRING:
+       {
+               err = snd_config_set_string(attr, value);
+               assert(err >= 0);
+               break;
+       }
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Find the unique attribute in the class definition and set its value and type.
+ * Only string or integer types are allowed for unique values.
+ */
+static int tplg_object_set_unique_attribute(struct tplg_pre_processor *tplg_pp,
+                                           snd_config_t *obj, snd_config_t *class_cfg,
+                                           const char *id)
+{
+       snd_config_t *unique_attr, *new;
+       const char *unique_name, *class_id;
+       int ret;
+
+       if (snd_config_get_id(class_cfg, &class_id) < 0)
+               return 0;
+
+       /* find config for class unique attribute */
+       unique_name = tplg_class_get_unique_attribute_name(tplg_pp, class_cfg);
+       if (!unique_name)
+               return -ENOENT;
+
+       /* find the unique attribute definition in the class */
+       unique_attr = tplg_class_find_attribute_by_name(tplg_pp, class_cfg, unique_name);
+       if (!unique_attr)
+               return -ENOENT;
+
+       /* override value if unique attribute is set in the object instance */
+       ret = snd_config_search(obj, unique_name, &new);
+       if (ret < 0) {
+               ret = snd_config_make(&new, unique_name,
+                                     tplg_class_get_attribute_type(tplg_pp, unique_attr));
+               if (ret < 0) {
+                       SNDERR("error creating new attribute cfg for object %s\n", id);
+                       return ret;
+               }
+               ret = snd_config_add(obj, new);
+               if (ret < 0) {
+                       SNDERR("error adding new attribute cfg for object %s\n", id);
+                       return ret;
+               }
+       }
+
+       ret = tplg_set_attribute_value(new, id);
+       if (ret < 0) {
+               SNDERR("error setting unique attribute cfg for object %s\n", id);
+               return ret;
+       }
+
+       return ret;
+}
+
+/*
+ * Helper function to get object instance config which is 2 nodes down from class_type config.
+ * ex: Get the pointer to the config node with ID "0" from the input config Widget.pga.0 {}
+ */
+snd_config_t *tplg_object_get_instance_config(struct tplg_pre_processor *tplg_pp,
+                                       snd_config_t *class_type)
+{
+       snd_config_iterator_t first;
+       snd_config_t *cfg;
+
+       first = snd_config_iterator_first(class_type);
+       cfg = snd_config_iterator_entry(first);
+       first = snd_config_iterator_first(cfg);
+       return snd_config_iterator_entry(first);
+}
+
+/* build object config */
+static int tplg_build_object(struct tplg_pre_processor *tplg_pp, snd_config_t *new_obj,
+                             snd_config_t *parent)
+{
+       snd_config_t *obj_local, *class_cfg;
+       const char *id, *class_id;
+       int ret;
+
+       obj_local = tplg_object_get_instance_config(tplg_pp, new_obj);
+       if (!obj_local)
+               return -EINVAL;
+
+       class_cfg = tplg_class_lookup(tplg_pp, new_obj);
+       if (!class_cfg)
+               return -EINVAL;
+
+       if (snd_config_get_id(obj_local, &id) < 0)
+               return 0;
+
+       if (snd_config_get_id(class_cfg, &class_id) < 0)
+               return 0;
+
+       /* set unique attribute value */
+       ret = tplg_object_set_unique_attribute(tplg_pp, obj_local, class_cfg, id);
+       if (ret < 0)
+               SNDERR("error setting unique attribute value for '%s.%s'\n", class_id, id);
+
+       return ret;
+}
+
+/* create top-level topology objects */
+int tplg_pre_process_objects(struct tplg_pre_processor *tplg_pp, snd_config_t *cfg,
+                            snd_config_t *parent)
+{
+       snd_config_iterator_t i, next, i2, next2;
+       snd_config_t *n, *n2, *_obj_type, *_obj_class, *_obj;
+       const char *id, *class_type, *class_name;
+       int ret;
+
+       if (snd_config_get_id(cfg, &class_type) < 0)
+               return 0;
+
+       /* create all objects of the same type and class */
+       snd_config_for_each(i, next, cfg) {
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_id(n, &class_name) < 0)
+                       continue;
+               snd_config_for_each(i2, next2, n) {
+                       n2 = snd_config_iterator_entry(i2);
+                       if (snd_config_get_id(n2, &id) < 0) {
+                               SNDERR("Invalid id for object\n");
+                               return -EINVAL;
+                       }
+
+                       /* create a temp config for object with class type as the root node */
+                       ret = snd_config_make(&_obj_type, class_type, SND_CONFIG_TYPE_COMPOUND);
+                       if (ret < 0)
+                               return ret;
+
+                       ret = snd_config_make(&_obj_class, class_name, SND_CONFIG_TYPE_COMPOUND);
+                       if (ret < 0)
+                               goto err;
+
+                       ret = snd_config_add(_obj_type, _obj_class);
+                       if (ret < 0) {
+                               snd_config_delete(_obj_class);
+                               goto err;
+                       }
+
+                       ret = snd_config_copy(&_obj, n2);
+                       if (ret < 0)
+                               goto err;
+
+                       ret = snd_config_add(_obj_class, _obj);
+                       if (ret < 0) {
+                               snd_config_delete(_obj);
+                               goto err;
+                       }
+
+                       /* Build the object now */
+                       ret = tplg_build_object(tplg_pp, _obj_type, parent);
+                       if (ret < 0)
+                               SNDERR("Error building object %s.%s.%s\n",
+                                      class_type, class_name, id);
+err:
+                       snd_config_delete(_obj_type);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
index 3d50d8ce2fca698f90a200b16950a636176312a4..0458c3ccec0b96b545548730182c99747ae57099 100644 (file)
@@ -125,6 +125,7 @@ static int pre_process_config(struct tplg_pre_processor *tplg_pp, snd_config_t *
        snd_config_iterator_t i, next, i2, next2;
        snd_config_t *n, *n2;
        const char *id;
+       int err;
 
        if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
                fprintf(stderr, "compound type expected at top level");
@@ -156,7 +157,10 @@ static int pre_process_config(struct tplg_pre_processor *tplg_pp, snd_config_t *
                                return -EINVAL;
                        }
 
-                       /* TODO: Add support for parsing objects */
+                       /* pre-process Object instance. Top-level object have no parent */
+                       err = tplg_pre_process_objects(tplg_pp, n2, NULL);
+                       if (err < 0)
+                               return err;
                }
        }
 
index ce72e096b5926638dd899698c434cc11912b3fd9..5cb1727d15e328f8e723f630e36698e35608b974 100644 (file)
 void tplg_pp_debug(char *fmt, ...);
 void tplg_pp_config_debug(struct tplg_pre_processor *tplg_pp, snd_config_t *cfg);
 
+/* object helpers */
+int tplg_pre_process_objects(struct tplg_pre_processor *tplg_pp, snd_config_t *cfg,
+                            snd_config_t *parent);
+snd_config_t *tplg_object_get_instance_config(struct tplg_pre_processor *tplg_pp,
+                                       snd_config_t *class_type);
+
 /* class helpers */
 snd_config_t *tplg_class_lookup(struct tplg_pre_processor *tplg_pp, snd_config_t *cfg);
 snd_config_t *tplg_class_find_attribute_by_name(struct tplg_pre_processor *tplg_pp,