]> git.alsa-project.org Git - alsa-utils.git/commitdiff
Make alsactl restore a bit more robust
authorTakashi Iwai <tiwai@suse.de>
Wed, 24 Oct 2007 11:08:28 +0000 (13:08 +0200)
committerTakashi Iwai <tiwai@suse.de>
Wed, 24 Oct 2007 11:08:28 +0000 (13:08 +0200)
Make "alsactl restore" a bit more robust.  Now it tries to parse the
compound items in the case that the number of channels was changed.
The former mono-value is expanded to all channels.

alsactl/state.c

index 9644ea30ff2587c196aa395262b181e9a0666ea8..887589f3ee3b53a5d5f20aa8d0471c92df426df1 100644 (file)
@@ -651,6 +651,7 @@ static int config_bool(snd_config_t *n)
        const char *str;
        long val;
        long long lval;
+
        switch (snd_config_get_type(n)) {
        case SND_CONFIG_TYPE_INTEGER:
                snd_config_get_integer(n, &val);
@@ -665,6 +666,11 @@ static int config_bool(snd_config_t *n)
        case SND_CONFIG_TYPE_STRING:
                snd_config_get_string(n, &str);
                break;
+       case SND_CONFIG_TYPE_COMPOUND:
+               if (!force_restore)
+                       return -1;
+               n = snd_config_iterator_entry(snd_config_iterator_first(n));
+               return config_bool(n);
        default:
                return -1;
        }
@@ -682,6 +688,7 @@ static int config_enumerated(snd_config_t *n, snd_ctl_t *handle,
        long val;
        long long lval;
        unsigned int idx, items;
+
        switch (snd_config_get_type(n)) {
        case SND_CONFIG_TYPE_INTEGER:
                snd_config_get_integer(n, &val);
@@ -692,6 +699,11 @@ static int config_enumerated(snd_config_t *n, snd_ctl_t *handle,
        case SND_CONFIG_TYPE_STRING:
                snd_config_get_string(n, &str);
                break;
+       case SND_CONFIG_TYPE_COMPOUND:
+               if (!force_restore)
+                       return -1;
+               n = snd_config_iterator_entry(snd_config_iterator_first(n));
+               return config_enumerated(n, handle, info);
        default:
                return -1;
        }
@@ -710,6 +722,30 @@ static int config_enumerated(snd_config_t *n, snd_ctl_t *handle,
        return -1;
 }
 
+static int config_integer(snd_config_t *n, long *val)
+{
+       int err = snd_config_get_integer(n, val);
+       if (err < 0 && force_restore) {
+               if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND)
+                       return err;
+               n = snd_config_iterator_entry(snd_config_iterator_first(n));
+               return config_integer(n, val);
+       }
+       return err;
+}
+
+static int config_integer64(snd_config_t *n, long long *val)
+{
+       int err = snd_config_get_integer64(n, val);
+       if (err < 0 && force_restore) {
+               if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND)
+                       return err;
+               n = snd_config_iterator_entry(snd_config_iterator_first(n));
+               return config_integer64(n, val);
+       }
+       return err;
+}
+
 static int is_user_control(snd_config_t *conf)
 {
        snd_config_iterator_t i, next;
@@ -831,6 +867,82 @@ static int add_user_control(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_co
        return snd_ctl_elem_info(handle, info);
 }
 
+static int restore_config_value(snd_ctl_t *handle, snd_ctl_elem_info_t *info,
+                               snd_ctl_elem_iface_t type,
+                               snd_config_t *value,
+                               snd_ctl_elem_value_t *ctl, int idx)
+{
+       long val;
+       long long lval;
+       int err;
+
+       switch (type) {
+       case SND_CTL_ELEM_TYPE_BOOLEAN:
+               val = config_bool(value);
+               if (val >= 0) {
+                       snd_ctl_elem_value_set_boolean(ctl, idx, val);
+                       return 1;
+               }
+               break;
+       case SND_CTL_ELEM_TYPE_INTEGER:
+               err = config_integer(value, &val);
+               if (err == 0) {
+                       snd_ctl_elem_value_set_integer(ctl, idx, val);
+                       return 1;
+               }
+               break;
+       case SND_CTL_ELEM_TYPE_INTEGER64:
+               err = config_integer64(value, &lval);
+               if (err == 0) {
+                       snd_ctl_elem_value_set_integer64(ctl, idx, lval);
+                       return 1;
+               }
+               break;
+       case SND_CTL_ELEM_TYPE_ENUMERATED:
+               val = config_enumerated(value, handle, info);
+               if (val >= 0) {
+                       snd_ctl_elem_value_set_enumerated(ctl, idx, val);
+                       return 1;
+               }
+               break;
+       case SND_CTL_ELEM_TYPE_BYTES:
+       case SND_CTL_ELEM_TYPE_IEC958:
+               break;
+       default:
+               error("Unknow control type: %d", type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int restore_config_value2(snd_ctl_t *handle, snd_ctl_elem_info_t *info,
+                                snd_ctl_elem_iface_t type,
+                                snd_config_t *value,
+                                snd_ctl_elem_value_t *ctl, int idx,
+                                unsigned int numid)
+{
+       int err = restore_config_value(handle, info, type, value, ctl, idx);
+       long val;
+
+       if (err != 0)
+               return err;
+       switch (type) {
+       case SND_CTL_ELEM_TYPE_BYTES:
+       case SND_CTL_ELEM_TYPE_IEC958:
+               err = snd_config_get_integer(value, &val);
+               if (err < 0 || val < 0 || val > 255) {
+                       error("bad control.%d.value.%d content", numid, idx);
+                       return force_restore ? 0 : -EINVAL;
+               }
+               snd_ctl_elem_value_set_byte(ctl, idx, val);
+               return 1;
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
 static int set_control(snd_ctl_t *handle, snd_config_t *control)
 {
        snd_ctl_elem_value_t *ctl;
@@ -852,8 +964,6 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control)
        long index = -1;
        snd_config_t *value = NULL;
        snd_config_t *comment = NULL;
-       long val;
-       long long lval;
        unsigned int idx;
        int err;
        char *set;
@@ -1008,42 +1118,11 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control)
        snd_ctl_elem_value_set_numid(ctl, numid1);
 
        if (count == 1) {
-               switch (type) {
-               case SND_CTL_ELEM_TYPE_BOOLEAN:
-                       val = config_bool(value);
-                       if (val >= 0) {
-                               snd_ctl_elem_value_set_boolean(ctl, 0, val);
-                               goto _ok;
-                       }
-                       break;
-               case SND_CTL_ELEM_TYPE_INTEGER:
-                       err = snd_config_get_integer(value, &val);
-                       if (err == 0) {
-                               snd_ctl_elem_value_set_integer(ctl, 0, val);
-                               goto _ok;
-                       }
-                       break;
-               case SND_CTL_ELEM_TYPE_INTEGER64:
-                       err = snd_config_get_integer64(value, &lval);
-                       if (err == 0) {
-                               snd_ctl_elem_value_set_integer64(ctl, 0, lval);
-                               goto _ok;
-                       }
-                       break;
-               case SND_CTL_ELEM_TYPE_ENUMERATED:
-                       val = config_enumerated(value, handle, info);
-                       if (val >= 0) {
-                               snd_ctl_elem_value_set_enumerated(ctl, 0, val);
-                               goto _ok;
-                       }
-                       break;
-               case SND_CTL_ELEM_TYPE_BYTES:
-               case SND_CTL_ELEM_TYPE_IEC958:
-                       break;
-               default:
-                       error("Unknow control type: %d", type);
-                       return -EINVAL;
-               }
+               err = restore_config_value(handle, info, type, value, ctl, 0);
+               if (err < 0)
+                       return err;
+               if (err > 0)
+                       goto _ok;
        }
        switch (type) {
        case SND_CTL_ELEM_TYPE_BYTES:
@@ -1080,8 +1159,17 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control)
                break;
        }
        if (snd_config_get_type(value) != SND_CONFIG_TYPE_COMPOUND) {
-               error("bad control.%d.value type", numid);
-               return -EINVAL;
+               if (!force_restore) {
+                       error("bad control.%d.value type", numid);
+                       return -EINVAL;
+               }
+               for (idx = 0; idx < count; ++idx) {
+                       err = restore_config_value2(handle, info, type, value,
+                                                   ctl, idx, numid);
+                       if (err < 0)
+                               return err;
+               }
+               goto _ok;
        }
 
        set = (char*) alloca(count);
@@ -1095,59 +1183,22 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control)
                if (idx < 0 || idx >= count || 
                    set[idx]) {
                        error("bad control.%d.value index", numid);
-                       return -EINVAL;
-               }
-               switch (type) {
-               case SND_CTL_ELEM_TYPE_BOOLEAN:
-                       val = config_bool(n);
-                       if (val < 0) {
-                               error("bad control.%d.value.%d content", numid, idx);
-                               return -EINVAL;
-                       }
-                       snd_ctl_elem_value_set_boolean(ctl, idx, val);
-                       break;
-               case SND_CTL_ELEM_TYPE_INTEGER:
-                       err = snd_config_get_integer(n, &val);
-                       if (err < 0) {
-                               error("bad control.%d.value.%d content", numid, idx);
-                               return -EINVAL;
-                       }
-                       snd_ctl_elem_value_set_integer(ctl, idx, val);
-                       break;
-               case SND_CTL_ELEM_TYPE_INTEGER64:
-                       err = snd_config_get_integer64(n, &lval);
-                       if (err < 0) {
-                               error("bad control.%d.value.%d content", numid, idx);
+                       if (!force_restore)
                                return -EINVAL;
-                       }
-                       snd_ctl_elem_value_set_integer64(ctl, idx, lval);
-                       break;
-               case SND_CTL_ELEM_TYPE_ENUMERATED:
-                       val = config_enumerated(n, handle, info);
-                       if (val < 0) {
-                               error("bad control.%d.value.%d content", numid, idx);
-                               return -EINVAL;
-                       }
-                       snd_ctl_elem_value_set_enumerated(ctl, idx, val);
-                       break;
-               case SND_CTL_ELEM_TYPE_BYTES:
-               case SND_CTL_ELEM_TYPE_IEC958:
-                       err = snd_config_get_integer(n, &val);
-                       if (err < 0 || val < 0 || val > 255) {
-                               error("bad control.%d.value.%d content", numid, idx);
-                               return -EINVAL;
-                       }
-                       snd_ctl_elem_value_set_byte(ctl, idx, val);
-                       break;
-               default:
-                       break;
+                       continue;
                }
-               set[idx] = 1;
+               err = restore_config_value2(handle, info, type, value,
+                                           ctl, idx, numid);
+               if (err < 0)
+                       return err;
+               if (err > 0)
+                       set[idx] = 1;
        }
        for (idx = 0; idx < count; ++idx) {
                if (!set[idx]) {
                        error("control.%d.value.%d is not specified", numid, idx);
-                       return -EINVAL;
+                       if (!force_restore)
+                               return -EINVAL;
                }
        }