am 095e4663: (-s ours) Camera2: Docs - Add output_file option to metadata_parser_xml.py: DO NOT MERGE
# Via Igor Murashkin
* commit '095e4663d6062c7005a1aa49e652529c6c5db97e':
Camera2: Docs - Add output_file option to metadata_parser_xml.py: 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 94834d1..9f5ad50 100644
--- a/camera/docs/docs.html
+++ b/camera/docs/docs.html
@@ -673,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 -->
@@ -1039,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 -->
@@ -9361,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>
@@ -9393,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>
@@ -9603,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>
@@ -9635,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>
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/include/system/camera_metadata_tags.h b/camera/include/system/camera_metadata_tags.h
index 2cd5b31..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
diff --git a/camera/src/camera_metadata_tag_info.c b/camera/src/camera_metadata_tag_info.c
index c9161cf..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";
}