am f15f1ec0: (-s ours) Update camera metadata tests to new enums: DO NOT MERGE

# Via Igor Murashkin
* commit 'f15f1ec0f4204d172b38ae57548df1a2a31d423c':
  Update camera metadata tests to new enums: DO NOT MERGE
diff --git a/audio_effects/include/audio_effects/effect_bassboost.h b/audio_effects/include/audio_effects/effect_bassboost.h
index cf9375e..3735904 100644
--- a/audio_effects/include/audio_effects/effect_bassboost.h
+++ b/audio_effects/include/audio_effects/effect_bassboost.h
@@ -24,7 +24,8 @@
 #endif
 
 #ifndef OPENSL_ES_H_
-static const effect_uuid_t SL_IID_BASSBOOST_ = { 0x0634f220, 0xddd4, 0x11db, 0xa0fc, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+static const effect_uuid_t SL_IID_BASSBOOST_ = { 0x0634f220, 0xddd4, 0x11db, 0xa0fc,
+        { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
 const effect_uuid_t * const SL_IID_BASSBOOST = &SL_IID_BASSBOOST_;
 #endif //OPENSL_ES_H_
 
diff --git a/audio_effects/include/audio_effects/effect_environmentalreverb.h b/audio_effects/include/audio_effects/effect_environmentalreverb.h
index 77f3697..3acbd5c 100644
--- a/audio_effects/include/audio_effects/effect_environmentalreverb.h
+++ b/audio_effects/include/audio_effects/effect_environmentalreverb.h
@@ -24,7 +24,8 @@
 #endif
 
 #ifndef OPENSL_ES_H_
-static const effect_uuid_t SL_IID_ENVIRONMENTALREVERB_ = { 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, { 0x4e, 0x23, 0x4d, 0x6, 0x83, 0x9e } };
+static const effect_uuid_t SL_IID_ENVIRONMENTALREVERB_ = { 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac,
+        { 0x4e, 0x23, 0x4d, 0x6, 0x83, 0x9e } };
 const effect_uuid_t * const SL_IID_ENVIRONMENTALREVERB = &SL_IID_ENVIRONMENTALREVERB_;
 #endif //OPENSL_ES_H_
 
diff --git a/audio_effects/include/audio_effects/effect_equalizer.h b/audio_effects/include/audio_effects/effect_equalizer.h
index e0c3bbd..17ee74f 100644
--- a/audio_effects/include/audio_effects/effect_equalizer.h
+++ b/audio_effects/include/audio_effects/effect_equalizer.h
@@ -20,7 +20,8 @@
 #include <hardware/audio_effect.h>
 
 #ifndef OPENSL_ES_H_
-static const effect_uuid_t SL_IID_EQUALIZER_ = { 0x0bed4300, 0xddd6, 0x11db, 0x8f34, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+static const effect_uuid_t SL_IID_EQUALIZER_ = { 0x0bed4300, 0xddd6, 0x11db, 0x8f34,
+        { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
 const effect_uuid_t * const SL_IID_EQUALIZER = &SL_IID_EQUALIZER_;
 #endif //OPENSL_ES_H_
 
@@ -31,12 +32,14 @@
 /* enumerated parameters for Equalizer effect */
 typedef enum
 {
-    EQ_PARAM_NUM_BANDS,             // Gets the number of frequency bands that the equalizer supports.
+    EQ_PARAM_NUM_BANDS,             // Gets the number of frequency bands that the equalizer
+                                    // supports.
     EQ_PARAM_LEVEL_RANGE,           // Returns the minimum and maximum band levels supported.
     EQ_PARAM_BAND_LEVEL,            // Gets/Sets the gain set for the given equalizer band.
     EQ_PARAM_CENTER_FREQ,           // Gets the center frequency of the given band.
     EQ_PARAM_BAND_FREQ_RANGE,       // Gets the frequency range of the given frequency band.
-    EQ_PARAM_GET_BAND,              // Gets the band that has the most effect on the given frequency.
+    EQ_PARAM_GET_BAND,              // Gets the band that has the most effect on the given
+                                    // frequency.
     EQ_PARAM_CUR_PRESET,            // Gets/Sets the current preset.
     EQ_PARAM_GET_NUM_OF_PRESETS,    // Gets the total number of presets the equalizer supports.
     EQ_PARAM_GET_PRESET_NAME,       // Gets the preset name based on the index.
diff --git a/audio_effects/include/audio_effects/effect_presetreverb.h b/audio_effects/include/audio_effects/effect_presetreverb.h
index e8d6052..ba1beae 100644
--- a/audio_effects/include/audio_effects/effect_presetreverb.h
+++ b/audio_effects/include/audio_effects/effect_presetreverb.h
@@ -24,7 +24,8 @@
 #endif
 
 #ifndef OPENSL_ES_H_
-static const effect_uuid_t SL_IID_PRESETREVERB_ = { 0x47382d60, 0xddd8, 0x11db, 0xbf3a, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+static const effect_uuid_t SL_IID_PRESETREVERB_ = { 0x47382d60, 0xddd8, 0x11db, 0xbf3a,
+        { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
 const effect_uuid_t * const SL_IID_PRESETREVERB = &SL_IID_PRESETREVERB_;
 #endif //OPENSL_ES_H_
 
diff --git a/audio_effects/include/audio_effects/effect_virtualizer.h b/audio_effects/include/audio_effects/effect_virtualizer.h
index a6f6fa2..fdb68a9 100644
--- a/audio_effects/include/audio_effects/effect_virtualizer.h
+++ b/audio_effects/include/audio_effects/effect_virtualizer.h
@@ -24,7 +24,8 @@
 #endif
 
 #ifndef OPENSL_ES_H_
-static const effect_uuid_t SL_IID_VIRTUALIZER_ = { 0x37cc2c00, 0xdddd, 0x11db, 0x8577, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+static const effect_uuid_t SL_IID_VIRTUALIZER_ = { 0x37cc2c00, 0xdddd, 0x11db, 0x8577,
+        { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
 const effect_uuid_t * const SL_IID_VIRTUALIZER = &SL_IID_VIRTUALIZER_;
 #endif //OPENSL_ES_H_
 
diff --git a/audio_route/Android.mk b/audio_route/Android.mk
new file mode 100644
index 0000000..7470dc6
--- /dev/null
+++ b/audio_route/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES += \
+	external/tinyalsa/include \
+	external/expat/lib
+LOCAL_SRC_FILES:= audio_route.c
+LOCAL_MODULE := libaudioroute
+LOCAL_SHARED_LIBRARIES:= liblog libcutils libutils libexpat libtinyalsa
+LOCAL_MODULE_TAGS := optional
+LOCAL_PRELINK_MODULE := false
+include $(BUILD_SHARED_LIBRARY)
diff --git a/audio_route/MODULE_LICENSE_BSD b/audio_route/MODULE_LICENSE_BSD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio_route/MODULE_LICENSE_BSD
diff --git a/audio_route/NOTICE b/audio_route/NOTICE
new file mode 100644
index 0000000..91b6565
--- /dev/null
+++ b/audio_route/NOTICE
@@ -0,0 +1,25 @@
+Copyright 2013, The Android Open Source Project
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of The Android Open Source Project nor the names of
+      its contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
diff --git a/audio_route/audio_route.c b/audio_route/audio_route.c
new file mode 100644
index 0000000..ae6c7f7
--- /dev/null
+++ b/audio_route/audio_route.c
@@ -0,0 +1,707 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ * Inspired by TinyHW, written by Mark Brown at Wolfson Micro
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_route"
+/*#define LOG_NDEBUG 0*/
+
+#include <errno.h>
+#include <expat.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <cutils/log.h>
+
+#include <tinyalsa/asoundlib.h>
+
+#define BUF_SIZE 1024
+#define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
+#define INITIAL_MIXER_PATH_SIZE 8
+
+struct mixer_state {
+    struct mixer_ctl *ctl;
+    unsigned int num_values;
+    int *old_value;
+    int *new_value;
+    int *reset_value;
+    /* If linked is true, only the first element in each array is valid */
+    bool old_linked;
+    bool new_linked;
+    bool reset_linked;
+};
+
+struct mixer_setting {
+    struct mixer_ctl *ctl;
+    unsigned int num_values;
+    int *value;
+    /* If linked is true, only the first element in each array is valid */
+    bool linked;
+};
+
+struct mixer_value {
+    struct mixer_ctl *ctl;
+    int index;
+    int value;
+};
+
+struct mixer_path {
+    char *name;
+    unsigned int size;
+    unsigned int length;
+    struct mixer_setting *setting;
+};
+
+struct audio_route {
+    struct mixer *mixer;
+    unsigned int num_mixer_ctls;
+    struct mixer_state *mixer_state;
+
+    unsigned int mixer_path_size;
+    unsigned int num_mixer_paths;
+    struct mixer_path *mixer_path;
+};
+
+struct config_parse_state {
+    struct audio_route *ar;
+    struct mixer_path *path;
+    int level;
+};
+
+/* path functions */
+
+static void path_print(struct mixer_path *path)
+{
+    unsigned int i;
+    unsigned int j;
+
+    ALOGE("Path: %s, length: %d", path->name, path->length);
+    for (i = 0; i < path->length; i++) {
+        ALOGE("  id=%d: ctl=%s linked=%c", i,
+              mixer_ctl_get_name(path->setting[i].ctl),
+              path->setting[i].linked ? 'y' : 'n');
+        for (j = 0; j < path->setting[i].num_values; j++)
+            ALOGE("    id=%d value=%d", j, path->setting[i].value[j]);
+    }
+}
+
+static void path_free(struct audio_route *ar)
+{
+    unsigned int i;
+
+    for (i = 0; i < ar->num_mixer_paths; i++) {
+        if (ar->mixer_path[i].name)
+            free(ar->mixer_path[i].name);
+        if (ar->mixer_path[i].setting) {
+            if (ar->mixer_path[i].setting->value)
+                free(ar->mixer_path[i].setting->value);
+            free(ar->mixer_path[i].setting);
+        }
+    }
+    free(ar->mixer_path);
+}
+
+static struct mixer_path *path_get_by_name(struct audio_route *ar,
+                                           const char *name)
+{
+    unsigned int i;
+
+    for (i = 0; i < ar->num_mixer_paths; i++)
+        if (strcmp(ar->mixer_path[i].name, name) == 0)
+            return &ar->mixer_path[i];
+
+    return NULL;
+}
+
+static struct mixer_path *path_create(struct audio_route *ar, const char *name)
+{
+    struct mixer_path *new_mixer_path = NULL;
+
+    if (path_get_by_name(ar, name)) {
+        ALOGE("Path name '%s' already exists", name);
+        return NULL;
+    }
+
+    /* check if we need to allocate more space for mixer paths */
+    if (ar->mixer_path_size <= ar->num_mixer_paths) {
+        if (ar->mixer_path_size == 0)
+            ar->mixer_path_size = INITIAL_MIXER_PATH_SIZE;
+        else
+            ar->mixer_path_size *= 2;
+
+        new_mixer_path = realloc(ar->mixer_path, ar->mixer_path_size *
+                                 sizeof(struct mixer_path));
+        if (new_mixer_path == NULL) {
+            ALOGE("Unable to allocate more paths");
+            return NULL;
+        } else {
+            ar->mixer_path = new_mixer_path;
+        }
+    }
+
+    /* initialise the new mixer path */
+    ar->mixer_path[ar->num_mixer_paths].name = strdup(name);
+    ar->mixer_path[ar->num_mixer_paths].size = 0;
+    ar->mixer_path[ar->num_mixer_paths].length = 0;
+    ar->mixer_path[ar->num_mixer_paths].setting = NULL;
+
+    /* return the mixer path just added, then increment number of them */
+    return &ar->mixer_path[ar->num_mixer_paths++];
+}
+
+static int find_ctl_in_path(struct mixer_path *path, struct mixer_ctl *ctl)
+{
+    unsigned int i;
+
+    for (i = 0; i < path->length; i++)
+        if (path->setting[i].ctl == ctl)
+            return i;
+
+    return -1;
+}
+
+static int alloc_path_setting(struct mixer_path *path)
+{
+    struct mixer_setting *new_path_setting;
+    int path_index;
+
+    /* check if we need to allocate more space for path settings */
+    if (path->size <= path->length) {
+        if (path->size == 0)
+            path->size = INITIAL_MIXER_PATH_SIZE;
+        else
+            path->size *= 2;
+
+        new_path_setting = realloc(path->setting,
+                                   path->size * sizeof(struct mixer_setting));
+        if (new_path_setting == NULL) {
+            ALOGE("Unable to allocate more path settings");
+            return -1;
+        } else {
+            path->setting = new_path_setting;
+        }
+    }
+
+    path_index = path->length;
+    path->length++;
+
+    return path_index;
+}
+
+static int path_add_setting(struct mixer_path *path,
+                            struct mixer_setting *setting)
+{
+    unsigned int i;
+    int path_index;
+
+    if (find_ctl_in_path(path, setting->ctl) != -1) {
+        ALOGE("Control '%s' already exists in path '%s'",
+              mixer_ctl_get_name(setting->ctl), path->name);
+        return -1;
+    }
+
+    path_index = alloc_path_setting(path);
+    if (path_index < 0)
+        return -1;
+
+    path->setting[path_index].ctl = setting->ctl;
+    path->setting[path_index].num_values = setting->num_values;
+    path->setting[path_index].value = malloc(setting->num_values * sizeof(int));
+    path->setting[path_index].linked = setting->linked;
+    if (setting->linked) {
+        path->setting[path_index].value[0] = setting->value[0];
+    } else {
+        for (i = 0; i < setting->num_values; i++)
+            path->setting[path_index].value[i] = setting->value[i];
+    }
+
+    return 0;
+}
+
+static int path_add_value(struct mixer_path *path,
+                          struct mixer_value *mixer_value)
+{
+    unsigned int i;
+    int path_index;
+    unsigned int num_values;
+
+    /* Check that mixer value index is within range */
+    num_values = mixer_ctl_get_num_values(mixer_value->ctl);
+    if (mixer_value->index >= (int)num_values) {
+        ALOGE("mixer index %d is out of range for '%s'", mixer_value->index,
+              mixer_ctl_get_name(mixer_value->ctl));
+        return -1;
+    }
+
+    path_index = find_ctl_in_path(path, mixer_value->ctl);
+    if (path_index < 0) {
+        /* New path */
+
+        path_index = alloc_path_setting(path);
+        if (path_index < 0)
+            return -1;
+
+        /* initialise the new path setting */
+        path->setting[path_index].ctl = mixer_value->ctl;
+        path->setting[path_index].num_values = num_values;
+        path->setting[path_index].value = malloc(num_values * sizeof(int));
+        path->setting[path_index].linked = true;
+        path->setting[path_index].value[0] = mixer_value->value;
+    }
+
+    if (mixer_value->index == -1) {
+        /* Linked, so only set the first value */
+        path->setting[path_index].linked = true;
+        path->setting[path_index].value[0] = mixer_value->value;
+    } else {
+        if (path->setting[path_index].linked && (num_values > 1)) {
+            /* Unlinking the values, so duplicate them across */
+            for (i = 1; i < num_values; i++) {
+                path->setting[path_index].value[i] =
+                        path->setting[path_index].value[0];
+            }
+            path->setting[path_index].linked = false;
+        }
+        path->setting[path_index].value[mixer_value->index] = mixer_value->value;
+    }
+
+    return 0;
+}
+
+static int path_add_path(struct mixer_path *path, struct mixer_path *sub_path)
+{
+    unsigned int i;
+
+    for (i = 0; i < sub_path->length; i++)
+        if (path_add_setting(path, &sub_path->setting[i]) < 0)
+            return -1;
+
+    return 0;
+}
+
+static int path_apply(struct audio_route *ar, struct mixer_path *path)
+{
+    unsigned int i;
+    unsigned int j;
+    unsigned int ctl_index;
+
+    for (i = 0; i < path->length; i++) {
+        struct mixer_ctl *ctl = path->setting[i].ctl;
+
+        /* locate the mixer ctl in the list */
+        for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++)
+            if (ar->mixer_state[ctl_index].ctl == ctl)
+                break;
+
+        /* apply the new value(s) */
+        for (j = 0; j < ar->mixer_state[ctl_index].num_values; j++) {
+            ar->mixer_state[ctl_index].new_value[j] = path->setting[i].value[j];
+            if (path->setting[i].linked)
+                break;
+        }
+        ar->mixer_state[ctl_index].new_linked = path->setting[i].linked;
+    }
+
+    return 0;
+}
+
+/* mixer helper function */
+static int mixer_enum_string_to_value(struct mixer_ctl *ctl, const char *string)
+{
+    unsigned int i;
+
+    /* Search the enum strings for a particular one */
+    for (i = 0; i < mixer_ctl_get_num_enums(ctl); i++) {
+        if (strcmp(mixer_ctl_get_enum_string(ctl, i), string) == 0)
+            break;
+    }
+
+    return i;
+}
+
+static void start_tag(void *data, const XML_Char *tag_name,
+                      const XML_Char **attr)
+{
+    const XML_Char *attr_name = NULL;
+    const XML_Char *attr_id = NULL;
+    const XML_Char *attr_value = NULL;
+    struct config_parse_state *state = data;
+    struct audio_route *ar = state->ar;
+    unsigned int i;
+    unsigned int ctl_index;
+    struct mixer_ctl *ctl;
+    int value;
+    unsigned int id;
+    struct mixer_value mixer_value;
+
+    /* Get name, id and value attributes (these may be empty) */
+    for (i = 0; attr[i]; i += 2) {
+        if (strcmp(attr[i], "name") == 0)
+            attr_name = attr[i + 1];
+        if (strcmp(attr[i], "id") == 0)
+            attr_id = attr[i + 1];
+        else if (strcmp(attr[i], "value") == 0)
+            attr_value = attr[i + 1];
+    }
+
+    /* Look at tags */
+    if (strcmp(tag_name, "path") == 0) {
+        if (attr_name == NULL) {
+            ALOGE("Unnamed path!");
+        } else {
+            if (state->level == 1) {
+                /* top level path: create and stash the path */
+                state->path = path_create(ar, (char *)attr_name);
+            } else {
+                /* nested path */
+                struct mixer_path *sub_path = path_get_by_name(ar, attr_name);
+                path_add_path(state->path, sub_path);
+            }
+        }
+    }
+
+    else if (strcmp(tag_name, "ctl") == 0) {
+        /* Obtain the mixer ctl and value */
+        ctl = mixer_get_ctl_by_name(ar->mixer, attr_name);
+        switch (mixer_ctl_get_type(ctl)) {
+        case MIXER_CTL_TYPE_BOOL:
+        case MIXER_CTL_TYPE_INT:
+            value = atoi((char *)attr_value);
+            break;
+        case MIXER_CTL_TYPE_ENUM:
+            value = mixer_enum_string_to_value(ctl, (char *)attr_value);
+            break;
+        default:
+            value = 0;
+            break;
+        }
+
+        if (state->level == 1) {
+            /* top level ctl (initial setting) */
+
+            /* locate the mixer ctl in the list */
+            for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) {
+                if (ar->mixer_state[ctl_index].ctl == ctl)
+                    break;
+            }
+
+            /* apply the new value */
+            if (attr_id) {
+                /* set only one value */
+                id = atoi((char *)attr_id);
+                if (id < ar->mixer_state[ctl_index].num_values) {
+                    if (ar->mixer_state[ctl_index].new_linked) {
+                        /*
+                         * We're unlinking the values, so copy old_value[0] into
+                         * all the new_value elements.
+                         */
+                        for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++) {
+                            ar->mixer_state[ctl_index].new_value[i] =
+                                    ar->mixer_state[ctl_index].old_value[0];
+                        }
+                        ar->mixer_state[ctl_index].new_linked = false;
+                    }
+                    ar->mixer_state[ctl_index].new_value[id] = value;
+                } else {
+                    ALOGE("value id out of range for mixer ctl '%s'",
+                          mixer_ctl_get_name(ctl));
+                }
+            } else {
+                ar->mixer_state[ctl_index].new_value[0] = value;
+                ar->mixer_state[ctl_index].new_linked = true;
+            }
+        } else {
+            /* nested ctl (within a path) */
+            mixer_value.ctl = ctl;
+            mixer_value.value = value;
+            if (attr_id)
+                mixer_value.index = atoi((char *)attr_id);
+            else
+                mixer_value.index = -1;
+            path_add_value(state->path, &mixer_value);
+        }
+    }
+
+    state->level++;
+}
+
+static void end_tag(void *data, const XML_Char *tag_name)
+{
+    struct config_parse_state *state = data;
+
+    state->level--;
+}
+
+static int alloc_mixer_state(struct audio_route *ar)
+{
+    unsigned int i;
+    unsigned int j;
+    unsigned int num_values;
+    struct mixer_ctl *ctl;
+    bool linked;
+
+    ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer);
+    ar->mixer_state = malloc(ar->num_mixer_ctls * sizeof(struct mixer_state));
+    if (!ar->mixer_state)
+        return -1;
+
+    for (i = 0; i < ar->num_mixer_ctls; i++) {
+        ctl = mixer_get_ctl(ar->mixer, i);
+        num_values = mixer_ctl_get_num_values(ctl);
+
+        ar->mixer_state[i].old_value = malloc(num_values * sizeof(int));
+        ar->mixer_state[i].new_value = malloc(num_values * sizeof(int));
+        ar->mixer_state[i].reset_value = malloc(num_values * sizeof(int));
+
+        /*
+         * Get all mixer values for controls with multiple values. If all
+         * values are the same, set the linked flag.
+         */
+        linked = true;
+        for (j = 0; j < num_values; j++) {
+            ar->mixer_state[i].old_value[j] = mixer_ctl_get_value(ctl, j);
+            ar->mixer_state[i].new_value[j] = ar->mixer_state[i].old_value[j];
+
+            /*
+             * If the next value is different from the last, set linked to
+             * false.
+             */
+            if ((j > 0) && (ar->mixer_state[i].old_value[j - 1] !=
+                            ar->mixer_state[i].old_value[j])) {
+                linked = false;
+            }
+        }
+        ar->mixer_state[i].ctl = ctl;
+        ar->mixer_state[i].old_linked = linked;
+        ar->mixer_state[i].new_linked = linked;
+        ar->mixer_state[i].num_values = num_values;
+    }
+
+    return 0;
+}
+
+static void free_mixer_state(struct audio_route *ar)
+{
+    unsigned int i;
+
+    for (i = 0; i < ar->num_mixer_ctls; i++) {
+        free(ar->mixer_state[i].old_value);
+        free(ar->mixer_state[i].new_value);
+        free(ar->mixer_state[i].reset_value);
+    }
+
+    free(ar->mixer_state);
+    ar->mixer_state = NULL;
+}
+
+/* Update the mixer with any changed values */
+int audio_route_update_mixer(struct audio_route *ar)
+{
+    unsigned int i;
+    unsigned int j;
+
+    for (i = 0; i < ar->num_mixer_ctls; i++) {
+        unsigned int num_values = ar->mixer_state[i].num_values;
+
+        /* if the value has changed, update the mixer */
+        if (ar->mixer_state[i].new_linked) {
+            if (ar->mixer_state[i].old_value[0] != ar->mixer_state[i].new_value[0]) {
+                /* linked ctl, so set all ctl values the same */
+                for (j = 0; j < num_values; j++)
+                    mixer_ctl_set_value(ar->mixer_state[i].ctl, j,
+                                        ar->mixer_state[i].new_value[0]);
+                ar->mixer_state[i].old_value[0] = ar->mixer_state[i].new_value[0];
+            }
+        } else {
+            for (j = 0; j < num_values; j++) {
+                /*
+                 * unlinked ctl, so set each value if necessary.
+                 * Note that if the new value is unlinked but the old is
+                 * linked, only value 0 is valid, so we always have to
+                 * update the mixer for the other values.
+                 */
+                if (ar->mixer_state[i].old_linked ||
+                    (ar->mixer_state[i].old_value[j] !=
+                            ar->mixer_state[i].new_value[j])) {
+                    mixer_ctl_set_value(ar->mixer_state[i].ctl, j,
+                                        ar->mixer_state[i].new_value[j]);
+                    ar->mixer_state[i].old_value[j] = ar->mixer_state[i].new_value[j];
+                }
+            }
+        }
+        ar->mixer_state[i].old_linked = ar->mixer_state[i].new_linked;
+    }
+
+    return 0;
+}
+
+/* saves the current state of the mixer, for resetting all controls */
+static void save_mixer_state(struct audio_route *ar)
+{
+    unsigned int i;
+    unsigned int j;
+
+    for (i = 0; i < ar->num_mixer_ctls; i++) {
+        for (j = 0; j < ar->mixer_state[i].num_values; j++) {
+            ar->mixer_state[i].reset_value[j] = ar->mixer_state[i].new_value[j];
+
+            /* if the values are linked, only need to save value 0 */
+            if (ar->mixer_state[i].new_linked)
+                break;
+        }
+        ar->mixer_state[i].reset_linked = ar->mixer_state[i].new_linked;
+    }
+}
+
+/* Reset the audio routes back to the initial state */
+void audio_route_reset(struct audio_route *ar)
+{
+    unsigned int i;
+    unsigned int j;
+
+    /* load all of the saved values */
+    for (i = 0; i < ar->num_mixer_ctls; i++) {
+        for (j = 0; j < ar->mixer_state[i].num_values; j++) {
+            ar->mixer_state[i].new_value[j] = ar->mixer_state[i].reset_value[j];
+
+            /* if the values are linked, only need to save value 0 */
+            if (ar->mixer_state[i].reset_linked)
+                break;
+        }
+        ar->mixer_state[i].new_linked = ar->mixer_state[i].reset_linked;
+    }
+}
+
+/* Apply an audio route path by name */
+int audio_route_apply_path(struct audio_route *ar, const char *name)
+{
+    struct mixer_path *path;
+
+    if (!ar) {
+        ALOGE("invalid audio_route");
+        return -1;
+    }
+
+    path = path_get_by_name(ar, name);
+    if (!path) {
+        ALOGE("unable to find path '%s'", name);
+        return -1;
+    }
+
+    path_apply(ar, path);
+
+    return 0;
+}
+
+struct audio_route *audio_route_init(unsigned int card, const char *xml_path)
+{
+    struct config_parse_state state;
+    XML_Parser parser;
+    FILE *file;
+    int bytes_read;
+    void *buf;
+    int i;
+    struct audio_route *ar;
+
+    ar = calloc(1, sizeof(struct audio_route));
+    if (!ar)
+        goto err_calloc;
+
+    ar->mixer = mixer_open(card);
+    if (!ar->mixer) {
+        ALOGE("Unable to open the mixer, aborting.");
+        goto err_mixer_open;
+    }
+
+    ar->mixer_path = NULL;
+    ar->mixer_path_size = 0;
+    ar->num_mixer_paths = 0;
+
+    /* allocate space for and read current mixer settings */
+    if (alloc_mixer_state(ar) < 0)
+        goto err_mixer_state;
+
+    /* use the default XML path if none is provided */
+    if (xml_path == NULL)
+        xml_path = MIXER_XML_PATH;
+
+    file = fopen(xml_path, "r");
+
+    if (!file) {
+        ALOGE("Failed to open %s", xml_path);
+        goto err_fopen;
+    }
+
+    parser = XML_ParserCreate(NULL);
+    if (!parser) {
+        ALOGE("Failed to create XML parser");
+        goto err_parser_create;
+    }
+
+    memset(&state, 0, sizeof(state));
+    state.ar = ar;
+    XML_SetUserData(parser, &state);
+    XML_SetElementHandler(parser, start_tag, end_tag);
+
+    for (;;) {
+        buf = XML_GetBuffer(parser, BUF_SIZE);
+        if (buf == NULL)
+            goto err_parse;
+
+        bytes_read = fread(buf, 1, BUF_SIZE, file);
+        if (bytes_read < 0)
+            goto err_parse;
+
+        if (XML_ParseBuffer(parser, bytes_read,
+                            bytes_read == 0) == XML_STATUS_ERROR) {
+            ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH);
+            goto err_parse;
+        }
+
+        if (bytes_read == 0)
+            break;
+    }
+
+    /* apply the initial mixer values, and save them so we can reset the
+       mixer to the original values */
+    audio_route_update_mixer(ar);
+    save_mixer_state(ar);
+
+    XML_ParserFree(parser);
+    fclose(file);
+    return ar;
+
+err_parse:
+    XML_ParserFree(parser);
+err_parser_create:
+    fclose(file);
+err_fopen:
+    free_mixer_state(ar);
+err_mixer_state:
+    mixer_close(ar->mixer);
+err_mixer_open:
+    free(ar);
+    ar = NULL;
+err_calloc:
+    return NULL;
+}
+
+void audio_route_free(struct audio_route *ar)
+{
+    free_mixer_state(ar);
+    mixer_close(ar->mixer);
+    free(ar);
+}
diff --git a/audio_route/include/audio_route/audio_route.h b/audio_route/include/audio_route/audio_route.h
new file mode 100644
index 0000000..0fea474
--- /dev/null
+++ b/audio_route/include/audio_route/audio_route.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUDIO_ROUTE_H
+#define AUDIO_ROUTE_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Initialize and free the audio routes */
+struct audio_route *audio_route_init(unsigned int card, const char *xml_path);
+void audio_route_free(struct audio_route *ar);
+
+/* Apply an audio route path by name */
+int audio_route_apply_path(struct audio_route *ar, const char *name);
+
+/* Reset the audio routes back to the initial state */
+void audio_route_reset(struct audio_route *ar);
+
+/* Update the mixer with any changed values */
+int audio_route_update_mixer(struct audio_route *ar);
+
+#if defined(__cplusplus)
+}  /* extern "C" */
+#endif
+
+#endif
diff --git a/audio_utils/Android.mk b/audio_utils/Android.mk
index e3f3e5e..1ddaced 100644
--- a/audio_utils/Android.mk
+++ b/audio_utils/Android.mk
@@ -21,3 +21,42 @@
 	libspeexresampler
 
 include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libaudioutils
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := \
+	primitives.c
+LOCAL_C_INCLUDES += \
+	$(call include-path-for, audio-utils)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libsndfile
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+	tinysndfile.c
+
+LOCAL_C_INCLUDES += \
+	$(call include-path-for, audio-utils)
+
+#LOCAL_SHARED_LIBRARIES := libaudioutils
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libsndfile
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+	tinysndfile.c
+
+LOCAL_C_INCLUDES += \
+	$(call include-path-for, audio-utils)
+
+#LOCAL_SHARED_LIBRARIES := libaudioutils
+
+include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/audio_utils/echo_reference.c b/audio_utils/echo_reference.c
index c05a60f..90f9a9f 100644
--- a/audio_utils/echo_reference.c
+++ b/audio_utils/echo_reference.c
@@ -83,9 +83,11 @@
         return -ENODATA;
     }
 
-    buffer->frame_count = (buffer->frame_count > er->wr_frames_in) ? er->wr_frames_in : buffer->frame_count;
+    buffer->frame_count = (buffer->frame_count > er->wr_frames_in) ?
+            er->wr_frames_in : buffer->frame_count;
     // this is er->rd_channel_count here as we resample after stereo to mono conversion if any
-    buffer->i16 = (int16_t *)er->wr_src_buf + (er->wr_curr_frame_size - er->wr_frames_in) * er->rd_channel_count;
+    buffer->i16 = (int16_t *)er->wr_src_buf + (er->wr_curr_frame_size - er->wr_frames_in) *
+            er->rd_channel_count;
 
     return 0;
 }
@@ -234,8 +236,8 @@
                     goto exit;
                 }
             }
-            // er->wr_src_buf and er->wr_frames_in are used by getNexBuffer() called by the resampler
-            // to get new frames
+            // er->wr_src_buf and er->wr_frames_in are used by getNexBuffer() called by the
+            // resampler to get new frames
             if (er->rd_channel_count != er->wr_channel_count) {
                 er->wr_src_buf = er->wr_buf;
             } else {
@@ -373,7 +375,8 @@
 
             int64_t  deltaNs = delayNs - expectedDelayNs;
 
-            ALOGV("echo_reference_read(): EchoPathDelayDeviation between reference and DMA [%lld]", deltaNs);
+            ALOGV("echo_reference_read(): EchoPathDelayDeviation between reference and DMA [%lld]",
+                    deltaNs);
             if (abs(deltaNs) >= MIN_DELAY_DELTA_NS) {
                 // smooth the variation and update the reference buffer only
                 // if a deviation in the same direction is observed for more than MIN_DELTA_NUM
@@ -493,7 +496,8 @@
     }
     if ((rdChannelCount != 1 && rdChannelCount != 2) ||
             wrChannelCount != 2) {
-        ALOGW("create_echo_reference bad channel count rd %d, wr %d", rdChannelCount, wrChannelCount);
+        ALOGW("create_echo_reference bad channel count rd %d, wr %d", rdChannelCount,
+                wrChannelCount);
         return -EINVAL;
     }
 
diff --git a/audio_utils/fixedfft.cpp b/audio_utils/fixedfft.cpp
index 2c92e74..eba84e7 100644
--- a/audio_utils/fixedfft.cpp
+++ b/audio_utils/fixedfft.cpp
@@ -35,7 +35,9 @@
 #define LOG_FFT_SIZE 10
 #define MAX_FFT_SIZE (1 << LOG_FFT_SIZE)
 
-static const int32_t twiddle[MAX_FFT_SIZE / 4] = {
+// Actually int32_t, but declare as uint32_t to avoid warnings due to overflow.
+// Be sure to cast all accesses before use, for example "(int32_t) twiddle[...]".
+static const uint32_t twiddle[MAX_FFT_SIZE / 4] = {
     0x00008000, 0xff378001, 0xfe6e8002, 0xfda58006, 0xfcdc800a, 0xfc13800f,
     0xfb4a8016, 0xfa81801e, 0xf9b88027, 0xf8ef8032, 0xf827803e, 0xf75e804b,
     0xf6958059, 0xf5cd8068, 0xf5058079, 0xf43c808b, 0xf374809e, 0xf2ac80b2,
@@ -132,7 +134,7 @@
         for (r = 1; r < p; ++r) {
             int32_t w = MAX_FFT_SIZE / 4 - (r << scale);
             i = w >> 31;
-            w = twiddle[(w ^ i) - i] ^ (i << 16);
+            w = ((int32_t) twiddle[(w ^ i) - i]) ^ (i << 16);
             for (i = r; i < n; i += p << 1) {
                 int32_t x = half(v[i]);
                 int32_t y = mult(w, v[i + p]);
@@ -157,7 +159,7 @@
         int32_t z = half(v[n - i]);
         int32_t y = z - (x ^ 0xFFFF);
         x = half(x + (z ^ 0xFFFF));
-        y = mult(y, twiddle[i << scale]);
+        y = mult(y, ((int32_t) twiddle[i << scale]));
         v[i] = x - y;
         v[n - i] = (x + y) ^ 0xFFFF;
     }
diff --git a/audio_utils/include/audio_utils/primitives.h b/audio_utils/include/audio_utils/primitives.h
index 00b5cd9..b34e309 100644
--- a/audio_utils/include/audio_utils/primitives.h
+++ b/audio_utils/include/audio_utils/primitives.h
@@ -18,6 +18,7 @@
 #define ANDROID_AUDIO_PRIMITIVES_H
 
 #include <stdint.h>
+#include <stdlib.h>
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
@@ -44,6 +45,17 @@
  */
 void memcpy_to_i16_from_u8(int16_t *dst, const uint8_t *src, size_t count);
 
+/* Shrink and copy samples from signed 16-bit to unsigned 8-bit offset by 0x80.
+ * Parameters:
+ *  dst     Destination buffer
+ *  src     Source buffer
+ *  count   Number of samples to copy
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address.  Partially overlapping buffers are not supported.
+ * The conversion is done by truncation, without dithering, so it loses resolution.
+ */
+void memcpy_to_u8_from_i16(uint8_t *dst, const int16_t *src, size_t count);
+
 /* Downmix pairs of interleaved stereo input 16-bit samples to mono output 16-bit samples.
  * Parameters:
  *  dst     Destination buffer
diff --git a/audio_utils/include/audio_utils/sndfile.h b/audio_utils/include/audio_utils/sndfile.h
new file mode 100644
index 0000000..c652654
--- /dev/null
+++ b/audio_utils/include/audio_utils/sndfile.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AUDIO_UTIL_SNDFILE_H
+#define __AUDIO_UTIL_SNDFILE_H
+
+// This is a C library for reading and writing PCM .wav files.  It is
+// influenced by other libraries such as libsndfile and audiofile, except is
+// much smaller and has an Apache 2.0 license.
+// The API should be familiar to clients of similar libraries, but there is
+// no guarantee that it will stay exactly source-code compatible with other libraries.
+
+#include <stdio.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+// visible to clients
+typedef int sf_count_t;
+
+typedef struct {
+    sf_count_t frames;
+    int samplerate;
+    int channels;
+    int format;
+} SF_INFO;
+
+// opaque to clients
+typedef struct SNDFILE_ SNDFILE;
+
+// Access modes
+#define SFM_READ    1
+#define SFM_WRITE   2
+
+// Format
+#define SF_FORMAT_TYPEMASK  1
+#define SF_FORMAT_WAV       1
+#define SF_FORMAT_SUBMASK   6
+#define SF_FORMAT_PCM_16    2
+#define SF_FORMAT_PCM_U8    4
+
+// Open stream
+SNDFILE *sf_open(const char *path, int mode, SF_INFO *info);
+
+// Close stream
+void sf_close(SNDFILE *handle);
+
+// Read interleaved frames and return actual number of frames read
+sf_count_t sf_readf_short(SNDFILE *handle, short *ptr, sf_count_t desired);
+
+// Write interleaved frames and return actual number of frames written
+sf_count_t sf_writef_short(SNDFILE *handle, const short *ptr, sf_count_t desired);
+
+__END_DECLS
+
+#endif /* __AUDIO_UTIL_SNDFILE_H */
diff --git a/audio_utils/primitives.c b/audio_utils/primitives.c
index bec87e0..af9ab40 100644
--- a/audio_utils/primitives.c
+++ b/audio_utils/primitives.c
@@ -39,6 +39,13 @@
     }
 }
 
+void memcpy_to_u8_from_i16(uint8_t *dst, const int16_t *src, size_t count)
+{
+    while (count--) {
+        *dst++ = (*src++ >> 8) + 0x80;
+    }
+}
+
 void downmix_to_mono_i16_from_stereo_i16(int16_t *dst, const int16_t *src, size_t count)
 {
     while (count--) {
diff --git a/audio_utils/tinysndfile.c b/audio_utils/tinysndfile.c
new file mode 100644
index 0000000..efdb3ce
--- /dev/null
+++ b/audio_utils/tinysndfile.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <audio_utils/sndfile.h>
+#include <audio_utils/primitives.h>
+#include <stdio.h>
+#include <string.h>
+
+struct SNDFILE_ {
+    int mode;
+    uint8_t *temp;  // realloc buffer used for shrinking 16 bits to 8 bits and byte-swapping
+    FILE *stream;
+    size_t bytesPerFrame;
+    size_t remaining;   // frames unread for SFM_READ, frames written for SFM_WRITE
+    SF_INFO info;
+};
+
+static unsigned little2u(unsigned char *ptr)
+{
+    return (ptr[1] << 8) + ptr[0];
+}
+
+static unsigned little4u(unsigned char *ptr)
+{
+    return (ptr[3] << 24) + (ptr[2] << 16) + (ptr[1] << 8) + ptr[0];
+}
+
+static int isLittleEndian(void)
+{
+    static const short one = 1;
+    return *((const char *) &one) == 1;
+}
+
+static void swab(short *ptr, size_t numToSwap)
+{
+    while (numToSwap > 0) {
+        *ptr = little2u((unsigned char *) ptr);
+        --numToSwap;
+        ++ptr;
+    }
+}
+
+static SNDFILE *sf_open_read(const char *path, SF_INFO *info)
+{
+    FILE *stream = fopen(path, "rb");
+    if (stream == NULL)
+        return NULL;
+    // don't attempt to parse all valid forms, just the most common one
+    unsigned char wav[44];
+    size_t actual;
+    actual = fread(wav, sizeof(char), sizeof(wav), stream);
+    if (actual != sizeof(wav))
+        return NULL;
+    for (;;) {
+        if (memcmp(wav, "RIFF", 4))
+            break;
+        unsigned riffSize = little4u(&wav[4]);
+        if (riffSize < 36)
+            break;
+        if (memcmp(&wav[8], "WAVEfmt ", 8))
+            break;
+        unsigned fmtsize = little4u(&wav[16]);
+        if (fmtsize != 16)
+            break;
+        unsigned format = little2u(&wav[20]);
+        if (format != 1)    // PCM
+            break;
+        unsigned channels = little2u(&wav[22]);
+        if (channels != 1 && channels != 2)
+            break;
+        unsigned samplerate = little4u(&wav[24]);
+        if (samplerate == 0)
+            break;
+        // ignore byte rate
+        // ignore block alignment
+        unsigned bitsPerSample = little2u(&wav[34]);
+        if (bitsPerSample != 8 && bitsPerSample != 16)
+            break;
+        unsigned bytesPerFrame = (bitsPerSample >> 3) * channels;
+        if (memcmp(&wav[36], "data", 4))
+            break;
+        unsigned dataSize = little4u(&wav[40]);
+        SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE));
+        handle->mode = SFM_READ;
+        handle->temp = NULL;
+        handle->stream = stream;
+        handle->bytesPerFrame = bytesPerFrame;
+        handle->remaining = dataSize / bytesPerFrame;
+        handle->info.frames = handle->remaining;
+        handle->info.samplerate = samplerate;
+        handle->info.channels = channels;
+        handle->info.format = SF_FORMAT_WAV;
+        if (bitsPerSample == 8)
+            handle->info.format |= SF_FORMAT_PCM_U8;
+        else
+            handle->info.format |= SF_FORMAT_PCM_16;
+        *info = handle->info;
+        return handle;
+    }
+    return NULL;
+}
+
+static void write4u(unsigned char *ptr, unsigned u)
+{
+    ptr[0] = u;
+    ptr[1] = u >> 8;
+    ptr[2] = u >> 16;
+    ptr[3] = u >> 24;
+}
+
+static SNDFILE *sf_open_write(const char *path, SF_INFO *info)
+{
+    if (!(
+            (info->samplerate > 0) &&
+            (info->channels == 1 || info->channels == 2) &&
+            ((info->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV) &&
+            ((info->format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_16 ||
+             (info->format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_U8)
+          )) {
+        return NULL;
+    }
+    FILE *stream = fopen(path, "w+b");
+    unsigned char wav[44];
+    memset(wav, 0, sizeof(wav));
+    memcpy(wav, "RIFF", 4);
+    wav[4] = 36;    // riffSize
+    memcpy(&wav[8], "WAVEfmt ", 8);
+    wav[16] = 16;   // fmtsize
+    wav[20] = 1;    // format = PCM
+    wav[22] = info->channels;
+    write4u(&wav[24], info->samplerate);
+    unsigned bitsPerSample = (info->format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_16 ? 16 : 8;
+    unsigned blockAlignment = (bitsPerSample >> 3) * info->channels;
+    unsigned byteRate = info->samplerate * blockAlignment;
+    write4u(&wav[28], byteRate);
+    wav[32] = blockAlignment;
+    wav[34] = bitsPerSample;
+    memcpy(&wav[36], "data", 4);
+    // dataSize is initially zero
+    (void) fwrite(wav, sizeof(wav), 1, stream);
+    SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE));
+    handle->mode = SFM_WRITE;
+    handle->temp = NULL;
+    handle->stream = stream;
+    handle->bytesPerFrame = blockAlignment;
+    handle->remaining = 0;
+    handle->info = *info;
+    return handle;
+}
+
+SNDFILE *sf_open(const char *path, int mode, SF_INFO *info)
+{
+    if (path == NULL || info == NULL)
+        return NULL;
+    switch (mode) {
+    case SFM_READ:
+        return sf_open_read(path, info);
+    case SFM_WRITE:
+        return sf_open_write(path, info);
+    default:
+        return NULL;
+    }
+}
+
+void sf_close(SNDFILE *handle)
+{
+    if (handle == NULL)
+        return;
+    free(handle->temp);
+    if (handle->mode == SFM_WRITE) {
+        (void) fflush(handle->stream);
+        rewind(handle->stream);
+        unsigned char wav[44];
+        (void) fread(wav, sizeof(wav), 1, handle->stream);
+        unsigned dataSize = handle->remaining * handle->bytesPerFrame;
+        write4u(&wav[4], dataSize + 36);    // riffSize
+        write4u(&wav[40], dataSize);        // dataSize
+        rewind(handle->stream);
+        (void) fwrite(wav, sizeof(wav), 1, handle->stream);
+    }
+    (void) fclose(handle->stream);
+    free(handle);
+}
+
+sf_count_t sf_readf_short(SNDFILE *handle, short *ptr, sf_count_t desiredFrames)
+{
+    if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
+            desiredFrames <= 0) {
+        return 0;
+    }
+    if (handle->remaining < (size_t) desiredFrames)
+        desiredFrames = handle->remaining;
+    size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
+    // does not check for numeric overflow
+    size_t actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
+    size_t actualFrames = actualBytes / handle->bytesPerFrame;
+    handle->remaining -= actualFrames;
+    switch (handle->info.format & SF_FORMAT_SUBMASK) {
+    case SF_FORMAT_PCM_U8:
+        memcpy_to_i16_from_u8(ptr, (unsigned char *) ptr, actualFrames * handle->info.channels);
+        break;
+    case SF_FORMAT_PCM_16:
+        if (!isLittleEndian())
+            swab(ptr, actualFrames * handle->info.channels);
+        break;
+    }
+    return actualFrames;
+}
+
+sf_count_t sf_writef_short(SNDFILE *handle, const short *ptr, sf_count_t desiredFrames)
+{
+    if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0)
+        return 0;
+    size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
+    size_t actualBytes = 0;
+    switch (handle->info.format & SF_FORMAT_SUBMASK) {
+    case SF_FORMAT_PCM_U8:
+        handle->temp = realloc(handle->temp, desiredBytes);
+        memcpy_to_u8_from_i16(handle->temp, ptr, desiredBytes);
+        actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
+        break;
+    case SF_FORMAT_PCM_16:
+        // does not check for numeric overflow
+        if (isLittleEndian()) {
+            actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream);
+        } else {
+            handle->temp = realloc(handle->temp, desiredBytes);
+            memcpy(handle->temp, ptr, desiredBytes);
+            swab((short *) handle->temp, desiredFrames * handle->info.channels);
+            actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
+        }
+        break;
+    }
+    size_t actualFrames = actualBytes / handle->bytesPerFrame;
+    handle->remaining += actualFrames;
+    return actualFrames;
+}
diff --git a/camera/docs/docs.html b/camera/docs/docs.html
index 845c9d4..9f5ad50 100644
--- a/camera/docs/docs.html
+++ b/camera/docs/docs.html
@@ -657,6 +657,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -672,16 +673,16 @@
 
                 <ul class="entry_type_enum">
                   <li>
+                    <span class="entry_type_enum_name">OFF</span>
+                    <span class="entry_type_enum_notes">Autoexposure lock is disabled; the AE algorithm
+            is free to update its parameters.<wbr></span>
+                  </li>
+                  <li>
                     <span class="entry_type_enum_name">ON</span>
                     <span class="entry_type_enum_notes">Autoexposure lock is enabled; the AE algorithm
             must not update the exposure and sensitivity parameters
             while the lock is active</span>
                   </li>
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes">Autoexposure lock is disabled; the AE algorithm
-            is free to update its parameters.<wbr></span>
-                  </li>
                 </ul>
 
             </td> <!-- entry_type -->
@@ -705,6 +706,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -773,6 +775,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -822,6 +825,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -861,6 +865,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -968,6 +973,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -1017,6 +1023,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -1032,17 +1039,17 @@
 
                 <ul class="entry_type_enum">
                   <li>
-                    <span class="entry_type_enum_name">ON</span>
-                    <span class="entry_type_enum_notes">Auto-whitebalance lock is enabled; the AWB
-            algorithm must not update the exposure and sensitivity
-            parameters while the lock is active</span>
-                  </li>
-                  <li>
                     <span class="entry_type_enum_name">OFF</span>
                     <span class="entry_type_enum_notes">Auto-whitebalance lock is disabled; the AWB
             algorithm is free to update its parameters if in AUTO
             mode.<wbr></span>
                   </li>
+                  <li>
+                    <span class="entry_type_enum_name">ON</span>
+                    <span class="entry_type_enum_notes">Auto-whitebalance lock is enabled; the AWB
+            algorithm must not update the exposure and sensitivity
+            parameters while the lock is active</span>
+                  </li>
                 </ul>
 
             </td> <!-- entry_type -->
@@ -1066,6 +1073,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -1129,6 +1137,8 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+                  <li><a href="#tag_AWB">AWB</a></li>
               </ul>
             </td>
 
@@ -1178,6 +1188,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -1249,6 +1260,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -1319,6 +1331,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -1377,6 +1390,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -1487,6 +1501,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -1530,6 +1545,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -1705,6 +1721,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -1738,6 +1755,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -1777,6 +1795,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -1815,6 +1834,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -1854,6 +1874,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -1892,6 +1913,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -1924,6 +1946,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -1957,6 +1980,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -2014,6 +2038,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -2124,6 +2149,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -2297,6 +2325,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -2344,6 +2375,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -2507,6 +2541,10 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+                  <li><a href="#tag_AWB">AWB</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -2554,6 +2592,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -2663,6 +2704,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -2739,6 +2783,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -2992,6 +3037,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -3028,6 +3074,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -3078,6 +3125,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -3143,6 +3191,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -3179,6 +3228,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -3216,6 +3266,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_ADV">ADV</a></li>
               </ul>
             </td>
 
@@ -3250,6 +3301,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_ADV">ADV</a></li>
               </ul>
             </td>
 
@@ -3313,6 +3365,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -3347,6 +3402,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -3395,6 +3453,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -3559,6 +3620,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_ADV">ADV</a></li>
               </ul>
             </td>
 
@@ -3641,6 +3703,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -3708,6 +3771,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_ADV">ADV</a></li>
               </ul>
             </td>
 
@@ -3788,6 +3852,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -3859,6 +3924,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -3892,6 +3958,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -3925,6 +3992,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -3959,6 +4027,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -3993,6 +4062,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -4026,6 +4096,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -4063,6 +4134,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -4130,6 +4202,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -4229,6 +4302,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -4260,6 +4336,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -4291,6 +4370,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -4323,6 +4405,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -4355,6 +4440,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -4425,6 +4513,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -4460,6 +4551,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -4527,6 +4621,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -4563,6 +4658,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -4597,6 +4693,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -4633,6 +4730,8 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -4676,6 +4775,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -4745,6 +4845,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -4786,6 +4887,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -4827,6 +4929,8 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -4864,6 +4968,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -4908,6 +5013,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_DNG">DNG</a></li>
               </ul>
             </td>
 
@@ -4946,6 +5052,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -4982,6 +5089,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -5018,6 +5126,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -5060,6 +5169,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_DNG">DNG</a></li>
               </ul>
             </td>
 
@@ -5098,6 +5208,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -5184,6 +5295,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_ADV">ADV</a></li>
               </ul>
             </td>
 
@@ -5221,6 +5333,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -5284,6 +5397,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -5320,6 +5434,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -5354,6 +5469,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -5389,6 +5505,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -5426,6 +5543,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -5469,6 +5587,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -5505,6 +5624,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -5587,6 +5707,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -5695,6 +5816,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -5940,6 +6064,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -6181,6 +6306,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -6311,6 +6437,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -6475,6 +6604,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -6560,6 +6690,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -6602,6 +6733,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -6640,6 +6772,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -6711,6 +6844,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -6752,6 +6886,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -6793,6 +6928,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -6864,6 +7000,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -6937,6 +7074,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -7004,6 +7144,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -7041,6 +7182,8 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -7077,6 +7220,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -7147,6 +7291,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_DNG">DNG</a></li>
               </ul>
             </td>
 
@@ -7185,6 +7330,8 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -7238,6 +7385,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_DNG">DNG</a></li>
               </ul>
             </td>
 
@@ -7277,6 +7425,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -7314,6 +7463,8 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -7352,6 +7503,8 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -7391,6 +7544,8 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_DNG">DNG</a></li>
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -7426,6 +7581,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_DNG">DNG</a></li>
               </ul>
             </td>
 
@@ -7461,6 +7617,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -7501,6 +7658,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_DNG">DNG</a></li>
               </ul>
             </td>
 
@@ -7538,6 +7696,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_DNG">DNG</a></li>
               </ul>
             </td>
 
@@ -7575,6 +7734,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_DNG">DNG</a></li>
               </ul>
             </td>
 
@@ -7616,6 +7776,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_DNG">DNG</a></li>
               </ul>
             </td>
 
@@ -7654,6 +7815,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_DNG">DNG</a></li>
               </ul>
             </td>
 
@@ -7691,6 +7853,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_DNG">DNG</a></li>
               </ul>
             </td>
 
@@ -7728,6 +7891,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_DNG">DNG</a></li>
               </ul>
             </td>
 
@@ -7764,6 +7928,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -7809,6 +7974,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -7847,6 +8013,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -7964,6 +8131,8 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_DNG">DNG</a></li>
+                  <li><a href="#tag_EXIF">EXIF</a></li>
               </ul>
             </td>
 
@@ -8057,6 +8226,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -8092,6 +8264,10 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
+                  <li><a href="#tag_BC">BC</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -8126,6 +8302,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -8161,6 +8340,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -8274,6 +8454,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_ADV">ADV</a></li>
               </ul>
             </td>
 
@@ -8430,6 +8611,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -8470,6 +8652,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -8510,6 +8693,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -8814,6 +8998,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -8850,6 +9037,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -8888,6 +9076,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -8926,6 +9115,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -8964,6 +9154,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_BC">BC</a></li>
               </ul>
             </td>
 
@@ -9005,6 +9196,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -9044,6 +9236,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -9082,6 +9277,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
               </ul>
             </td>
 
@@ -9121,6 +9317,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_V1">V1</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -9162,7 +9361,7 @@
           <tr class="entry" id="controls_android.tonemap.curveBlue">
             <td class="entry_name">android.<wbr>tonemap.<wbr>curve<wbr>Blue</td>
             <td class="entry_type">
-                <span class="entry_type_name">byte</span>
+                <span class="entry_type_name">float</span>
 
 
 
@@ -9194,7 +9393,7 @@
           <tr class="entry" id="controls_android.tonemap.curveGreen">
             <td class="entry_name">android.<wbr>tonemap.<wbr>curve<wbr>Green</td>
             <td class="entry_type">
-                <span class="entry_type_name">byte</span>
+                <span class="entry_type_name">float</span>
 
 
 
@@ -9262,6 +9461,7 @@
 
             <td class="entry_tags">
               <ul class="entry_tags">
+                  <li><a href="#tag_DNG">DNG</a></li>
               </ul>
             </td>
 
@@ -9403,7 +9603,7 @@
           <tr class="entry" id="dynamic_android.tonemap.curveBlue">
             <td class="entry_name">android.<wbr>tonemap.<wbr>curve<wbr>Blue</td>
             <td class="entry_type">
-                <span class="entry_type_name">byte</span>
+                <span class="entry_type_name">float</span>
 
 
 
@@ -9435,7 +9635,7 @@
           <tr class="entry" id="dynamic_android.tonemap.curveGreen">
             <td class="entry_name">android.<wbr>tonemap.<wbr>curve<wbr>Green</td>
             <td class="entry_type">
-                <span class="entry_type_name">byte</span>
+                <span class="entry_type_name">float</span>
 
 
 
@@ -9502,6 +9702,9 @@
             </td>
 
             <td class="entry_tags">
+              <ul class="entry_tags">
+                  <li><a href="#tag_DNG">DNG</a></li>
+              </ul>
             </td>
 
           </tr> <!-- end of entry -->
@@ -9725,4 +9928,3 @@
 
 </body>
 </html>
-
diff --git a/camera/docs/html.mako b/camera/docs/html.mako
index 4866472..0baf181 100644
--- a/camera/docs/html.mako
+++ b/camera/docs/html.mako
@@ -137,7 +137,7 @@
       <tr class="description"><td>${section.description}</td></tr>
     % endif
 
-    % for kind in section.kinds: # dynamic,static,controls
+    % for kind in section.merged_kinds: # dynamic,static,controls
       <tr><td colspan="7" class="kind">${kind.name}</td></tr>
 
       <thead>
@@ -256,7 +256,7 @@
             </td>
 
             <td class="entry_tags">
-            % if list(prop.tags):
+            % if next(prop.tags, None):
               <ul class="entry_tags">
               % for tag in prop.tags:
                   <li><a href="#tag_${tag.id}">${tag.id}</a></li>
diff --git a/camera/docs/metadata-generate b/camera/docs/metadata-generate
index a9e53d8..7869763 100755
--- a/camera/docs/metadata-generate
+++ b/camera/docs/metadata-generate
@@ -25,12 +25,26 @@
 
 thisdir=$(dirname $(readlink -f $0))
 
+function relpath() {
+    python -c "import os.path; print os.path.relpath('$1', '$PWD')"
+}
+
 function gen_file() {
     local in=$thisdir/$1
     local out=$thisdir/$2
 
-    python $thisdir/metadata_parser_xml.py $thisdir/metadata_properties.xml $in > $out
-    return $?
+    python $thisdir/metadata_parser_xml.py $thisdir/metadata_properties.xml $in $out
+
+    local succ=$?
+
+    if [[ $succ -eq 0 ]]
+    then
+        echo "OK: Generated $(relpath "$out")"
+    else
+        echo "FAIL: Errors while generating $(relpath "$out")" >& 2
+    fi
+
+    return $succ
 }
 
 $thisdir/metadata-check-dependencies || exit 1
diff --git a/camera/docs/metadata-parser-sanity-check b/camera/docs/metadata-parser-sanity-check
index a7ff41e..520a5f2 100755
--- a/camera/docs/metadata-parser-sanity-check
+++ b/camera/docs/metadata-parser-sanity-check
@@ -29,7 +29,7 @@
 tmp_tidy1=$(mktemp)
 tmp_tidy2=$(mktemp)
 
-python $thisdir/metadata_parser_xml.py $thisdir/metadata_properties.xml $thisdir/metadata_template.mako > $tmp_out || exit 1
+python $thisdir/metadata_parser_xml.py $thisdir/metadata_properties.xml $thisdir/metadata_template.mako $tmp_out || exit 1
 tidy -indent -xml -quiet $thisdir/metadata_properties.xml > $tmp_tidy1
 tidy -indent -xml -quiet $tmp_out > $tmp_tidy2
 
diff --git a/camera/docs/metadata_model.py b/camera/docs/metadata_model.py
index e2a2f0e..fa85a58 100644
--- a/camera/docs/metadata_model.py
+++ b/camera/docs/metadata_model.py
@@ -34,6 +34,7 @@
 """
 
 import sys
+import itertools
 from collections import OrderedDict
 
 class Node(object):
@@ -429,42 +430,35 @@
 
   # 'controls', 'static' 'dynamic'. etc
   def _construct_kinds(self, section):
-
-    kinds_dict = self._dictionary_by_name(section.kinds)
-    for name, kind in kinds_dict.iteritems():
+    for kind in section.kinds:
       kind._leafs = []
       section.validate_tree()
 
-    for p in section._leafs:
-      kind = kinds_dict.get(p.kind, Kind(p.kind, section))
-      kinds_dict[p.kind] = kind
-      section.validate_tree()
+    group_entry_by_kind = itertools.groupby(section._leafs, lambda x: x.kind)
+    leaf_it = ((k, g) for k, g in group_entry_by_kind)
 
-      if p not in kind._leafs:
-        kind._leafs.append(p)
+    # allow multiple kinds with the same name. merge if adjacent
+    # e.g. dynamic,dynamic,static,static,dynamic -> dynamic,static,dynamic
+    # this helps maintain ABI compatibility when adding an entry in a new kind
+    for idx, (kind_name, entry_it) in enumerate(leaf_it):
+      if idx >= len(section._kinds):
+        kind = Kind(kind_name, section)
+        section._kinds.append(kind)
+        section.validate_tree()
 
-    if len(kinds_dict) > 3:
-      sec = section
-      if sec is not None:
-        sec_name = sec.name
-      else:
-        sec_name = "Unknown"
+      kind = section._kinds[idx]
 
-      print >> sys.stderr, ("ERROR: Kind '%s' has too many children(%d) " +    \
-                            "in section '%s'") %(name, len(kc), sec_name)
+      for p in entry_it:
+        if p not in kind._leafs:
+          kind._leafs.append(p)
 
-
-    for name, kind in kinds_dict.iteritems():
-
+    for kind in section._kinds:
       kind.validate_tree()
       self._construct_inner_namespaces(kind)
       kind.validate_tree()
       self._construct_entries(kind)
       kind.validate_tree()
 
-      if kind not in section.kinds:
-        section._kinds.append(kind)
-
       if not section.validate_tree():
         print >> sys.stderr, ("ERROR: Failed to validate tree in " +           \
                              "construct_kinds, with kind = '%s'") %(kind)
@@ -604,6 +598,8 @@
     parent: An edge to the parent, which is always an OuterNamespace instance.
     description: A string description of the section, or None.
     kinds: A sequence of Kind children.
+    merged_kinds: A sequence of virtual Kind children,
+                  with each Kind's children merged by the kind.name
   """
   def __init__(self, name, parent, description=None, kinds=[]):
     self._name = name
@@ -635,6 +631,27 @@
   def _get_children(self):
     return (i for i in self.kinds)
 
+  @property
+  def merged_kinds(self):
+
+    def aggregate_by_name(acc, el):
+      existing = [i for i in acc if i.name == el.name]
+      if existing:
+        k = existing[0]
+      else:
+        k = Kind(el.name, el.parent)
+        acc.append(k)
+
+      k._namespaces.extend(el._namespaces)
+      k._entries.extend(el._entries)
+
+      return acc
+
+    new_kinds_lst = reduce(aggregate_by_name, self.kinds, [])
+
+    for k in new_kinds_lst:
+      yield k
+
 class Kind(Node):
   """
   A node corresponding to one of: <static>,<dynamic>,<controls> under a
@@ -1137,22 +1154,22 @@
     props_distinct = ['description', 'units', 'range', 'notes', 'tags', 'kind']
 
     for p in props_distinct:
+      p = '_' + p
       if entry.is_clone():
-        setattr(self, '_' + p, getattr(entry, p) or getattr(entry.entry, p))
+        setattr(self, p, getattr(entry, p) or getattr(entry.entry, p))
       else:
-        setattr(self, '_' + p, getattr(entry, p))
+        setattr(self, p, getattr(entry, p))
 
-    props_common = ['parent', 'name', 'name_short', 'container',
+    props_common = ['parent', 'name', 'container',
                     'container_sizes', 'enum',
                     'tuple_values',
                     'type',
                     'type_notes',
-                    'enum'
                    ]
 
     for p in props_common:
+      p = '_' + p
       if entry.is_clone():
-        setattr(self, '_' + p, getattr(entry.entry, p))
+        setattr(self, p, getattr(entry.entry, p))
       else:
-        setattr(self, '_' + p, getattr(entry, p))
-
+        setattr(self, p, getattr(entry, p))
diff --git a/camera/docs/metadata_parser_xml.py b/camera/docs/metadata_parser_xml.py
index d42a8b4..7b55273 100755
--- a/camera/docs/metadata_parser_xml.py
+++ b/camera/docs/metadata_parser_xml.py
@@ -21,8 +21,8 @@
 over a Mako template.
 
 Usage:
-  metadata_parser_xml.py <filename.xml> <template.mako>
-  - outputs the resulting template to stdout
+  metadata_parser_xml.py <filename.xml> <template.mako> [<output_file>]
+  - outputs the resulting template to output_file (stdout if none specified)
 
 Module:
   The parser is also available as a module import (MetadataParserXml) to use
@@ -253,14 +253,16 @@
 #####################
 
 if __name__ == "__main__":
-  if len(sys.argv) <= 1:
-    print >> sys.stderr, "Usage: %s <filename.xml> <template.mako>"            \
-                        % (sys.argv[0])
+  if len(sys.argv) <= 2:
+    print >> sys.stderr,                                                       \
+           "Usage: %s <filename.xml> <template.mako> [<output_file>]"          \
+           % (sys.argv[0])
     sys.exit(0)
 
   file_name = sys.argv[1]
   template_name = sys.argv[2]
+  output_name = sys.argv[3] if len(sys.argv) > 3 else None
   parser = MetadataParserXml(file_name)
-  parser.render(template_name)
+  parser.render(template_name, output_name)
 
   sys.exit(0)
diff --git a/camera/docs/metadata_properties.xml b/camera/docs/metadata_properties.xml
index 99f5844..d0a1d33 100644
--- a/camera/docs/metadata_properties.xml
+++ b/camera/docs/metadata_properties.xml
@@ -105,13 +105,13 @@
         </entry>
         <entry name="aeLock" type="byte" enum="true">
           <enum>
+            <value>OFF
+            <notes>Autoexposure lock is disabled; the AE algorithm
+            is free to update its parameters.</notes></value>
             <value>ON
             <notes>Autoexposure lock is enabled; the AE algorithm
             must not update the exposure and sensitivity parameters
             while the lock is active</notes></value>
-            <value>OFF
-            <notes>Autoexposure lock is disabled; the AE algorithm
-            is free to update its parameters.</notes></value>
           </enum>
           <description>Whether AE is currently locked to its latest
           calculated values</description>
@@ -279,14 +279,14 @@
         </entry>
         <entry name="awbLock" type="byte" enum="true">
           <enum>
-            <value>ON
-            <notes>Auto-whitebalance lock is enabled; the AWB
-            algorithm must not update the exposure and sensitivity
-            parameters while the lock is active</notes></value>
             <value>OFF
             <notes>Auto-whitebalance lock is disabled; the AWB
             algorithm is free to update its parameters if in AUTO
             mode.</notes></value>
+            <value>ON
+            <notes>Auto-whitebalance lock is enabled; the AWB
+            algorithm must not update the exposure and sensitivity
+            parameters while the lock is active</notes></value>
           </enum>
           <description>Whether AWB is currently locked to its
           latest calculated values</description>
@@ -2092,13 +2092,13 @@
     </section>
     <section name="tonemap">
       <controls>
-        <entry name="curveBlue" type="byte">
+        <entry name="curveBlue" type="float">
           <description>Table mapping blue input values to output
           values</description>
           <units>same as android.tonemap.curveRed</units>
           <range>same as android.tonemap.curveRed</range>
         </entry>
-        <entry name="curveGreen" type="byte">
+        <entry name="curveGreen" type="float">
           <description>Table mapping green input values to output
           values</description>
           <units>same as android.tonemap.curveRed</units>
diff --git a/camera/docs/metadata_properties.xsd b/camera/docs/metadata_properties.xsd
index 48a2c26..259aebf 100644
--- a/camera/docs/metadata_properties.xsd
+++ b/camera/docs/metadata_properties.xsd
@@ -37,11 +37,13 @@
     </complexType>
 
     <complexType name="SectionType">
-        <all>
-            <element name="controls" type="tns:SectionKindType" maxOccurs="1" minOccurs="0"></element>
-            <element name="static" type="tns:SectionKindType" maxOccurs="1" minOccurs="0"></element>
-            <element name="dynamic" type="tns:SectionKindType" maxOccurs="1" minOccurs="0"></element>
-        </all>
+        <sequence>
+            <choice maxOccurs="unbounded">
+                <element name="controls" type="tns:SectionKindType" maxOccurs="unbounded" minOccurs="0"></element>
+                <element name="static" type="tns:SectionKindType" maxOccurs="unbounded" minOccurs="0"></element>
+                <element name="dynamic" type="tns:SectionKindType" maxOccurs="unbounded" minOccurs="0"></element>
+            </choice>
+        </sequence>
         <attribute name="name" type="string" use="required"></attribute>
     </complexType>
 
diff --git a/camera/include/system/camera_metadata_tags.h b/camera/include/system/camera_metadata_tags.h
index c5fbec2..8d20ae8 100644
--- a/camera/include/system/camera_metadata_tags.h
+++ b/camera/include/system/camera_metadata_tags.h
@@ -323,8 +323,8 @@
 
 // ANDROID_CONTROL_AE_LOCK
 typedef enum camera_metadata_enum_android_control_ae_lock {
-    ANDROID_CONTROL_AE_LOCK_ON,
     ANDROID_CONTROL_AE_LOCK_OFF,
+    ANDROID_CONTROL_AE_LOCK_ON,
 } camera_metadata_enum_android_control_ae_lock_t;
 
 // ANDROID_CONTROL_AE_MODE
@@ -348,8 +348,8 @@
 
 // ANDROID_CONTROL_AWB_LOCK
 typedef enum camera_metadata_enum_android_control_awb_lock {
-    ANDROID_CONTROL_AWB_LOCK_ON,
     ANDROID_CONTROL_AWB_LOCK_OFF,
+    ANDROID_CONTROL_AWB_LOCK_ON,
 } camera_metadata_enum_android_control_awb_lock_t;
 
 // ANDROID_CONTROL_AWB_MODE
@@ -627,4 +627,3 @@
                                  uint32_t value,
                                  char *dst,
                                  size_t size);
-
diff --git a/camera/src/camera_metadata_tag_info.c b/camera/src/camera_metadata_tag_info.c
index 5eee140..e8d340a 100644
--- a/camera/src/camera_metadata_tag_info.c
+++ b/camera/src/camera_metadata_tag_info.c
@@ -489,9 +489,9 @@
 static tag_info_t android_tonemap[ANDROID_TONEMAP_END -
         ANDROID_TONEMAP_START] = {
     [ ANDROID_TONEMAP_CURVE_BLUE - ANDROID_TONEMAP_START ] =
-    { "curveBlue",                     TYPE_BYTE   },
+    { "curveBlue",                     TYPE_FLOAT  },
     [ ANDROID_TONEMAP_CURVE_GREEN - ANDROID_TONEMAP_START ] =
-    { "curveGreen",                    TYPE_BYTE   },
+    { "curveGreen",                    TYPE_FLOAT  },
     [ ANDROID_TONEMAP_CURVE_RED - ANDROID_TONEMAP_START ] =
     { "curveRed",                      TYPE_FLOAT  },
     [ ANDROID_TONEMAP_MODE - ANDROID_TONEMAP_START ] =
@@ -585,14 +585,14 @@
         }
         case ANDROID_CONTROL_AE_LOCK: {
             switch (value) {
-                case ANDROID_CONTROL_AE_LOCK_ON:
-                    msg = "ON";
-                    ret = 0;
-                    break;
                 case ANDROID_CONTROL_AE_LOCK_OFF:
                     msg = "OFF";
                     ret = 0;
                     break;
+                case ANDROID_CONTROL_AE_LOCK_ON:
+                    msg = "ON";
+                    ret = 0;
+                    break;
                 default:
                     msg = "error: enum value out of range";
             }
@@ -667,14 +667,14 @@
         }
         case ANDROID_CONTROL_AWB_LOCK: {
             switch (value) {
-                case ANDROID_CONTROL_AWB_LOCK_ON:
-                    msg = "ON";
-                    ret = 0;
-                    break;
                 case ANDROID_CONTROL_AWB_LOCK_OFF:
                     msg = "OFF";
                     ret = 0;
                     break;
+                case ANDROID_CONTROL_AWB_LOCK_ON:
+                    msg = "ON";
+                    ret = 0;
+                    break;
                 default:
                     msg = "error: enum value out of range";
             }
@@ -1776,4 +1776,3 @@
 
 
 #define CAMERA_METADATA_ENUM_STRING_MAX_SIZE 23
-