OSDN Git Service

Merge "liblog: use log/log.h when utilizing ALOG macros" am: 1fb716a12b am: b239ca4c99
[android-x86/system-media.git] / audio_route / audio_route.c
index af1abca..3796958 100644 (file)
@@ -24,7 +24,7 @@
 #include <stdio.h>
 #include <string.h>
 
-#include <cutils/log.h>
+#include <log/log.h>
 
 #include <tinyalsa/asoundlib.h>
 
@@ -33,7 +33,8 @@
 #define INITIAL_MIXER_PATH_SIZE 8
 
 union ctl_values {
-    int *integer;
+    int *enumerated;
+    long *integer;
     void *ptr;
     unsigned char *bytes;
 };
@@ -56,7 +57,7 @@ struct mixer_setting {
 struct mixer_value {
     unsigned int ctl_index;
     int index;
-    int value;
+    long value;
 };
 
 struct mixer_path {
@@ -97,12 +98,32 @@ static bool is_supported_ctl_type(enum mixer_ctl_type type)
     }
 }
 
+/* as they match in alsa */
+static size_t sizeof_ctl_type(enum mixer_ctl_type type) {
+    switch (type) {
+    case MIXER_CTL_TYPE_BOOL:
+    case MIXER_CTL_TYPE_INT:
+        return sizeof(long);
+    case MIXER_CTL_TYPE_ENUM:
+        return sizeof(int);
+    case MIXER_CTL_TYPE_BYTE:
+        return sizeof(unsigned char);
+    case MIXER_CTL_TYPE_INT64:
+    case MIXER_CTL_TYPE_IEC958:
+    case MIXER_CTL_TYPE_UNKNOWN:
+    default:
+        LOG_ALWAYS_FATAL("Unsupported mixer ctl type: %d, check type before calling", (int)type);
+        return 0;
+    }
+}
+
 static inline struct mixer_ctl *index_to_ctl(struct audio_route *ar,
                                              unsigned int ctl_index)
 {
     return ar->mixer_state[ctl_index].ctl;
 }
 
+#if 0
 static void path_print(struct audio_route *ar, struct mixer_path *path)
 {
     unsigned int i;
@@ -116,12 +137,16 @@ static void path_print(struct audio_route *ar, struct mixer_path *path)
         if (mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_BYTE) {
             for (j = 0; j < path->setting[i].num_values; j++)
                 ALOGE("    id=%d value=0x%02x", j, path->setting[i].value.bytes[j]);
+        } else if (mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_ENUM) {
+            for (j = 0; j < path->setting[i].num_values; j++)
+                ALOGE("    id=%d value=%d", j, path->setting[i].value.enumerated[j]);
         } else {
             for (j = 0; j < path->setting[i].num_values; j++)
-                ALOGE("    id=%d value=%d", j, path->setting[i].value.integer[j]);
+                ALOGE("    id=%d value=%ld", j, path->setting[i].value.integer[j]);
         }
     }
 }
+#endif
 
 static void path_free(struct audio_route *ar)
 {
@@ -137,6 +162,8 @@ static void path_free(struct audio_route *ar)
         }
     }
     free(ar->mixer_path);
+    ar->mixer_path = NULL;
+    ar->mixer_path_size = 0;
 }
 
 static struct mixer_path *path_get_by_name(struct audio_route *ar,
@@ -231,7 +258,6 @@ static int path_add_setting(struct audio_route *ar, struct mixer_path *path,
                             struct mixer_setting *setting)
 {
     int path_index;
-    unsigned int value_sz = sizeof(int);
 
     if (find_ctl_index_in_path(path, setting->ctl_index) != -1) {
         struct mixer_ctl *ctl = index_to_ctl(ar, setting->ctl_index);
@@ -241,6 +267,11 @@ static int path_add_setting(struct audio_route *ar, struct mixer_path *path,
         return -1;
     }
 
+    if (!is_supported_ctl_type(setting->type)) {
+        ALOGE("unsupported type %d", (int)setting->type);
+        return -1;
+    }
+
     path_index = alloc_path_setting(path);
     if (path_index < 0)
         return -1;
@@ -249,10 +280,9 @@ static int path_add_setting(struct audio_route *ar, struct mixer_path *path,
     path->setting[path_index].type = setting->type;
     path->setting[path_index].num_values = setting->num_values;
 
-    if (setting->type == MIXER_CTL_TYPE_BYTE)
-        value_sz = sizeof(unsigned char);
+    size_t value_sz = sizeof_ctl_type(setting->type);
 
-    path->setting[path_index].value.ptr = malloc(setting->num_values * value_sz);
+    path->setting[path_index].value.ptr = calloc(setting->num_values, value_sz);
     /* copy all values */
     memcpy(path->setting[path_index].value.ptr, setting->value.ptr,
            setting->num_values * value_sz);
@@ -266,7 +296,6 @@ static int path_add_value(struct audio_route *ar, struct mixer_path *path,
     unsigned int i;
     int path_index;
     unsigned int num_values;
-    unsigned int value_sz = sizeof(int);
     struct mixer_ctl *ctl;
 
     /* Check that mixer value index is within range */
@@ -282,6 +311,11 @@ static int path_add_value(struct audio_route *ar, struct mixer_path *path,
     if (path_index < 0) {
         /* New path */
 
+        enum mixer_ctl_type type = mixer_ctl_get_type(ctl);
+        if (!is_supported_ctl_type(type)) {
+            ALOGE("unsupported type %d", (int)type);
+            return -1;
+        }
         path_index = alloc_path_setting(path);
         if (path_index < 0)
             return -1;
@@ -289,14 +323,14 @@ static int path_add_value(struct audio_route *ar, struct mixer_path *path,
         /* initialise the new path setting */
         path->setting[path_index].ctl_index = mixer_value->ctl_index;
         path->setting[path_index].num_values = num_values;
-        path->setting[path_index].type = mixer_ctl_get_type(ctl);
+        path->setting[path_index].type = type;
 
-        if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE)
-            value_sz = sizeof(unsigned char);
-
-        path->setting[path_index].value.ptr = malloc(num_values * value_sz);
+        size_t value_sz = sizeof_ctl_type(type);
+        path->setting[path_index].value.ptr = calloc(num_values, value_sz);
         if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE)
             path->setting[path_index].value.bytes[0] = mixer_value->value;
+        else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM)
+            path->setting[path_index].value.enumerated[0] = mixer_value->value;
         else
             path->setting[path_index].value.integer[0] = mixer_value->value;
     }
@@ -306,6 +340,9 @@ static int path_add_value(struct audio_route *ar, struct mixer_path *path,
         if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE) {
             for (i = 0; i < num_values; i++)
                 path->setting[path_index].value.bytes[i] = mixer_value->value;
+        } else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM) {
+            for (i = 0; i < num_values; i++)
+                path->setting[path_index].value.enumerated[i] = mixer_value->value;
         } else {
             for (i = 0; i < num_values; i++)
                 path->setting[path_index].value.integer[i] = mixer_value->value;
@@ -314,6 +351,8 @@ static int path_add_value(struct audio_route *ar, struct mixer_path *path,
         /* set only one value */
         if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE)
             path->setting[path_index].value.bytes[mixer_value->index] = mixer_value->value;
+        else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM)
+            path->setting[path_index].value.enumerated[mixer_value->index] = mixer_value->value;
         else
             path->setting[path_index].value.integer[mixer_value->index] = mixer_value->value;
     }
@@ -336,7 +375,6 @@ static int path_add_path(struct audio_route *ar, struct mixer_path *path,
 static int path_apply(struct audio_route *ar, struct mixer_path *path)
 {
     unsigned int i;
-    unsigned int value_sz;
     unsigned int ctl_index;
     struct mixer_ctl *ctl;
     enum mixer_ctl_type type;
@@ -347,12 +385,7 @@ static int path_apply(struct audio_route *ar, struct mixer_path *path)
         type = mixer_ctl_get_type(ctl);
         if (!is_supported_ctl_type(type))
             continue;
-
-        if (type == MIXER_CTL_TYPE_BYTE)
-            value_sz = sizeof(unsigned char);
-        else
-            value_sz = sizeof(int);
-
+        size_t value_sz = sizeof_ctl_type(type);
         memcpy(ar->mixer_state[ctl_index].new_value.ptr, path->setting[i].value.ptr,
                    path->setting[i].num_values * value_sz);
     }
@@ -363,8 +396,6 @@ static int path_apply(struct audio_route *ar, struct mixer_path *path)
 static int path_reset(struct audio_route *ar, struct mixer_path *path)
 {
     unsigned int i;
-    unsigned int j;
-    unsigned int value_sz;
     unsigned int ctl_index;
     struct mixer_ctl *ctl;
     enum mixer_ctl_type type;
@@ -375,12 +406,7 @@ static int path_reset(struct audio_route *ar, struct mixer_path *path)
         type = mixer_ctl_get_type(ctl);
         if (!is_supported_ctl_type(type))
             continue;
-
-        if (type == MIXER_CTL_TYPE_BYTE)
-            value_sz = sizeof(unsigned char);
-        else
-            value_sz = sizeof(int);
-
+        size_t value_sz = sizeof_ctl_type(type);
         /* reset the value(s) */
         memcpy(ar->mixer_state[ctl_index].new_value.ptr,
                ar->mixer_state[ctl_index].reset_value.ptr,
@@ -394,13 +420,24 @@ static int path_reset(struct audio_route *ar, struct mixer_path *path)
 static int mixer_enum_string_to_value(struct mixer_ctl *ctl, const char *string)
 {
     unsigned int i;
+    unsigned int num_values = mixer_ctl_get_num_enums(ctl);
+
+    if (string == NULL) {
+        ALOGE("NULL enum value string passed to mixer_enum_string_to_value() for ctl %s",
+              mixer_ctl_get_name(ctl));
+        return 0;
+    }
 
     /* Search the enum strings for a particular one */
-    for (i = 0; i < mixer_ctl_get_num_enums(ctl); i++) {
+    for (i = 0; i < num_values; i++) {
         if (strcmp(mixer_ctl_get_enum_string(ctl, i), string) == 0)
             break;
     }
-
+    if (i == num_values) {
+        ALOGE("unknown enum value string %s for ctl %s",
+              string, mixer_ctl_get_name(ctl));
+        return 0;
+    }
     return i;
 }
 
@@ -415,7 +452,7 @@ static void start_tag(void *data, const XML_Char *tag_name,
     unsigned int i;
     unsigned int ctl_index;
     struct mixer_ctl *ctl;
-    int value;
+    long value;
     unsigned int id;
     struct mixer_value mixer_value;
     enum mixer_ctl_type type;
@@ -457,7 +494,7 @@ static void start_tag(void *data, const XML_Char *tag_name,
         switch (mixer_ctl_get_type(ctl)) {
         case MIXER_CTL_TYPE_BOOL:
         case MIXER_CTL_TYPE_INT:
-            value = (int) strtol((char *)attr_value, NULL, 0);
+            value = strtol((char *)attr_value, NULL, 0);
             break;
         case MIXER_CTL_TYPE_BYTE:
             value = (unsigned char) strtol((char *)attr_value, NULL, 16);
@@ -488,6 +525,8 @@ static void start_tag(void *data, const XML_Char *tag_name,
                     if (id < ar->mixer_state[ctl_index].num_values)
                         if (type == MIXER_CTL_TYPE_BYTE)
                             ar->mixer_state[ctl_index].new_value.bytes[id] = value;
+                        else if (type == MIXER_CTL_TYPE_ENUM)
+                            ar->mixer_state[ctl_index].new_value.enumerated[id] = value;
                         else
                             ar->mixer_state[ctl_index].new_value.integer[id] = value;
                     else
@@ -498,6 +537,8 @@ static void start_tag(void *data, const XML_Char *tag_name,
                     for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++)
                         if (type == MIXER_CTL_TYPE_BYTE)
                             ar->mixer_state[ctl_index].new_value.bytes[i] = value;
+                        else if (type == MIXER_CTL_TYPE_ENUM)
+                            ar->mixer_state[ctl_index].new_value.enumerated[i] = value;
                         else
                             ar->mixer_state[ctl_index].new_value.integer[i] = value;
                 }
@@ -529,14 +570,12 @@ static void end_tag(void *data, const XML_Char *tag_name)
 static int alloc_mixer_state(struct audio_route *ar)
 {
     unsigned int i;
-    unsigned int j;
     unsigned int num_values;
-    unsigned int value_sz;
     struct mixer_ctl *ctl;
     enum mixer_ctl_type type;
 
     ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer);
-    ar->mixer_state = malloc(ar->num_mixer_ctls * sizeof(struct mixer_state));
+    ar->mixer_state = calloc(ar->num_mixer_ctls, sizeof(struct mixer_state));
     if (!ar->mixer_state)
         return -1;
 
@@ -553,17 +592,13 @@ static int alloc_mixer_state(struct audio_route *ar)
         if (!is_supported_ctl_type(type))
             continue;
 
-        if (type == MIXER_CTL_TYPE_BYTE)
-            value_sz = sizeof(unsigned char);
-        else
-            value_sz = sizeof(int);
-
-        ar->mixer_state[i].old_value.ptr = malloc(num_values * value_sz);
-        ar->mixer_state[i].new_value.ptr = malloc(num_values * value_sz);
-        ar->mixer_state[i].reset_value.ptr = malloc(num_values * value_sz);
+        size_t value_sz = sizeof_ctl_type(type);
+        ar->mixer_state[i].old_value.ptr = calloc(num_values, value_sz);
+        ar->mixer_state[i].new_value.ptr = calloc(num_values, value_sz);
+        ar->mixer_state[i].reset_value.ptr = calloc(num_values, value_sz);
 
         if (type == MIXER_CTL_TYPE_ENUM)
-            ar->mixer_state[i].old_value.integer[0] = mixer_ctl_get_value(ctl, 0);
+            ar->mixer_state[i].old_value.enumerated[0] = mixer_ctl_get_value(ctl, 0);
         else
             mixer_ctl_get_array(ctl, ar->mixer_state[i].old_value.ptr, num_values);
 
@@ -620,6 +655,14 @@ int audio_route_update_mixer(struct audio_route *ar)
                     break;
                 }
             }
+         } else if (type == MIXER_CTL_TYPE_ENUM) {
+             for (j = 0; j < num_values; j++) {
+                 if (ar->mixer_state[i].old_value.enumerated[j]
+                         != ar->mixer_state[i].new_value.enumerated[j]) {
+                     changed = true;
+                     break;
+                 }
+             }
          } else {
             for (j = 0; j < num_values; j++) {
                 if (ar->mixer_state[i].old_value.integer[j] != ar->mixer_state[i].new_value.integer[j]) {
@@ -629,16 +672,12 @@ int audio_route_update_mixer(struct audio_route *ar)
             }
         }
         if (changed) {
-            unsigned int value_sz = sizeof(int);
-
-            if (type == MIXER_CTL_TYPE_BYTE)
-                value_sz = sizeof(unsigned char);
-
             if (type == MIXER_CTL_TYPE_ENUM)
-                mixer_ctl_set_value(ctl, 0, ar->mixer_state[i].new_value.integer[0]);
+                mixer_ctl_set_value(ctl, 0, ar->mixer_state[i].new_value.enumerated[0]);
             else
                 mixer_ctl_set_array(ctl, ar->mixer_state[i].new_value.ptr, num_values);
 
+            size_t value_sz = sizeof_ctl_type(type);
             memcpy(ar->mixer_state[i].old_value.ptr, ar->mixer_state[i].new_value.ptr,
                    num_values * value_sz);
         }
@@ -651,7 +690,6 @@ int audio_route_update_mixer(struct audio_route *ar)
 static void save_mixer_state(struct audio_route *ar)
 {
     unsigned int i;
-    unsigned int value_sz;
     enum mixer_ctl_type type;
 
     for (i = 0; i < ar->num_mixer_ctls; i++) {
@@ -659,11 +697,7 @@ static void save_mixer_state(struct audio_route *ar)
         if (!is_supported_ctl_type(type))
             continue;
 
-        if (type == MIXER_CTL_TYPE_BYTE)
-            value_sz = sizeof(unsigned char);
-        else
-            value_sz = sizeof(int);
-
+        size_t value_sz = sizeof_ctl_type(type);
         memcpy(ar->mixer_state[i].reset_value.ptr, ar->mixer_state[i].new_value.ptr,
                ar->mixer_state[i].num_values * value_sz);
     }
@@ -673,7 +707,6 @@ static void save_mixer_state(struct audio_route *ar)
 void audio_route_reset(struct audio_route *ar)
 {
     unsigned int i;
-    unsigned int value_sz;
     enum mixer_ctl_type type;
 
     /* load all of the saved values */
@@ -682,11 +715,7 @@ void audio_route_reset(struct audio_route *ar)
         if (!is_supported_ctl_type(type))
             continue;
 
-        if (type == MIXER_CTL_TYPE_BYTE)
-            value_sz = sizeof(unsigned char);
-        else
-            value_sz = sizeof(int);
-
+        size_t value_sz = sizeof_ctl_type(type);
         memcpy(ar->mixer_state[i].new_value.ptr, ar->mixer_state[i].reset_value.ptr,
             ar->mixer_state[i].num_values * value_sz);
     }
@@ -771,21 +800,25 @@ static int audio_route_update_path(struct audio_route *ar, const char *name, boo
             continue;
         }
 
+       size_t value_sz = sizeof_ctl_type(type);
         /* if any value has changed, update the mixer */
         for (j = 0; j < ms->num_values; j++) {
             if (type == MIXER_CTL_TYPE_BYTE) {
                 if (ms->old_value.bytes[j] != ms->new_value.bytes[j]) {
                     mixer_ctl_set_array(ms->ctl, ms->new_value.bytes, ms->num_values);
-                    memcpy(ms->old_value.bytes, ms->new_value.bytes, ms->num_values);
+                    memcpy(ms->old_value.bytes, ms->new_value.bytes, ms->num_values * value_sz);
                     break;
                 }
-            }
-            else if (ms->old_value.integer[j] != ms->new_value.integer[j]) {
-                if (type == MIXER_CTL_TYPE_ENUM)
-                    mixer_ctl_set_value(ms->ctl, 0, ms->new_value.integer[0]);
-                else
-                    mixer_ctl_set_array(ms->ctl, ms->new_value.integer, ms->num_values);
-                    memcpy(ms->old_value.integer, ms->new_value.integer, ms->num_values * sizeof(int));
+            } else if (type == MIXER_CTL_TYPE_ENUM) {
+                if (ms->old_value.enumerated[j] != ms->new_value.enumerated[j]) {
+                    mixer_ctl_set_value(ms->ctl, 0, ms->new_value.enumerated[0]);
+                    memcpy(ms->old_value.enumerated, ms->new_value.enumerated,
+                            ms->num_values * value_sz);
+                    break;
+                }
+            } else if (ms->old_value.integer[j] != ms->new_value.integer[j]) {
+                mixer_ctl_set_array(ms->ctl, ms->new_value.integer, ms->num_values);
+                memcpy(ms->old_value.integer, ms->new_value.integer, ms->num_values * value_sz);
                 break;
             }
         }
@@ -818,7 +851,6 @@ struct audio_route *audio_route_init(unsigned int card, const char *xml_path)
     FILE *file;
     int bytes_read;
     void *buf;
-    int i;
     struct audio_route *ar;
 
     ar = calloc(1, sizeof(struct audio_route));
@@ -890,6 +922,7 @@ struct audio_route *audio_route_init(unsigned int card, const char *xml_path)
     return ar;
 
 err_parse:
+    path_free(ar);
     XML_ParserFree(parser);
 err_parser_create:
     fclose(file);
@@ -908,5 +941,6 @@ void audio_route_free(struct audio_route *ar)
 {
     free_mixer_state(ar);
     mixer_close(ar->mixer);
+    path_free(ar);
     free(ar);
 }