diff options
| author | Simon Wilson <simonwilson@google.com> | 2013-01-28 17:00:41 -0800 |
|---|---|---|
| committer | Simon Wilson <simonwilson@google.com> | 2013-01-28 17:00:41 -0800 |
| commit | 89a34bc3ab83c9cc7c48b9eb4f1b73ee768c9543 (patch) | |
| tree | 0cb5dfdb27f0033c21a731d2086683fad3057e55 /audio | |
| parent | 83ec0acee1eab6254c452a3a584cb12df6dae829 (diff) | |
audio: factor out audio_route into a separate library
audio_route is mature enough now to belong in its
own library and will help remove duplication across
audio HALs.
Change-Id: If3a2a0b4a6d9bbed93d206e61d22a155066a23d4
Diffstat (limited to 'audio')
| -rw-r--r-- | audio/Android.mk | 9 | ||||
| -rw-r--r-- | audio/audio_hw.c | 11 | ||||
| -rw-r--r-- | audio/audio_route.c | 494 | ||||
| -rw-r--r-- | audio/audio_route.h | 33 |
4 files changed, 10 insertions, 537 deletions
diff --git a/audio/Android.mk b/audio/Android.mk index d903622..9b39c0a 100644 --- a/audio/Android.mk +++ b/audio/Android.mk @@ -19,13 +19,12 @@ include $(CLEAR_VARS) LOCAL_MODULE := audio.primary.grouper LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw LOCAL_SRC_FILES := \ - audio_hw.c \ - audio_route.c + audio_hw.c LOCAL_C_INCLUDES += \ external/tinyalsa/include \ - external/expat/lib \ - $(call include-path-for, audio-utils) -LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa libaudioutils libexpat + $(call include-path-for, audio-utils) \ + $(call include-path-for, audio-route) +LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa libaudioutils libaudioroute LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) diff --git a/audio/audio_hw.c b/audio/audio_hw.c index 5a9cbf6..1ddea03 100644 --- a/audio/audio_hw.c +++ b/audio/audio_hw.c @@ -35,13 +35,14 @@ #include <tinyalsa/asoundlib.h> #include <audio_utils/resampler.h> - -#include "audio_route.h" +#include <audio_route/audio_route.h> #define PCM_CARD 1 #define PCM_DEVICE 0 #define PCM_DEVICE_SCO 2 +#define MIXER_CARD 1 + #define OUT_PERIOD_SIZE 512 #define OUT_SHORT_PERIOD_COUNT 2 #define OUT_LONG_PERIOD_COUNT 8 @@ -186,7 +187,7 @@ static void select_devices(struct audio_device *adev) docked = adev->out_device & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; main_mic_on = adev->in_device & AUDIO_DEVICE_IN_BUILTIN_MIC; - reset_mixer_state(adev->ar); + audio_route_reset(adev->ar); if (speaker_on) audio_route_apply_path(adev->ar, "speaker"); @@ -201,7 +202,7 @@ static void select_devices(struct audio_device *adev) audio_route_apply_path(adev->ar, "main-mic-top"); } - update_mixer_state(adev->ar); + audio_route_update_mixer(adev->ar); ALOGV("hp=%c speaker=%c dock=%c main-mic=%c", headphone_on ? 'y' : 'n', speaker_on ? 'y' : 'n', docked ? 'y' : 'n', main_mic_on ? 'y' : 'n'); @@ -1247,7 +1248,7 @@ static int adev_open(const hw_module_t* module, const char* name, adev->hw_device.close_input_stream = adev_close_input_stream; adev->hw_device.dump = adev_dump; - adev->ar = audio_route_init(); + adev->ar = audio_route_init(MIXER_CARD, NULL); adev->orientation = ORIENTATION_UNDEFINED; adev->out_device = AUDIO_DEVICE_OUT_SPEAKER; adev->in_device = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN; diff --git a/audio/audio_route.c b/audio/audio_route.c deleted file mode 100644 index 7a13de4..0000000 --- a/audio/audio_route.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * Copyright (C) 2012 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_hw_primary" -/*#define LOG_NDEBUG 0*/ - -#include <errno.h> -#include <expat.h> -#include <stdbool.h> -#include <stdio.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 - -#define MIXER_CARD 1 - -struct mixer_state { - struct mixer_ctl *ctl; - int old_value; - int new_value; - int reset_value; -}; - -struct mixer_setting { - struct mixer_ctl *ctl; - 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_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) - 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 bool path_setting_exists(struct mixer_path *path, - struct mixer_setting *setting) -{ - unsigned int i; - - for (i = 0; i < path->length; i++) - if (path->setting[i].ctl == setting->ctl) - return true; - - return false; -} - -static int path_add_setting(struct mixer_path *path, - struct mixer_setting *setting) -{ - struct mixer_setting *new_path_setting; - - if (path_setting_exists(path, setting)) { - ALOGE("Duplicate path setting '%s'", - mixer_ctl_get_name(setting->ctl)); - return -1; - } - - /* 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; - } - } - - /* initialise the new path setting */ - path->setting[path->length].ctl = setting->ctl; - path->setting[path->length].value = setting->value; - path->length++; - - 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 void path_print(struct mixer_path *path) -{ - unsigned int i; - - ALOGV("Path: %s, length: %d", path->name, path->length); - for (i = 0; i < path->length; i++) - ALOGV(" %d: %s -> %d", i, mixer_ctl_get_name(path->setting[i].ctl), - path->setting[i].value); -} - -static int path_apply(struct audio_route *ar, struct mixer_path *path) -{ - unsigned int i; - unsigned int j; - - for (i = 0; i < path->length; i++) { - struct mixer_ctl *ctl = path->setting[i].ctl; - - /* locate the mixer ctl in the list */ - for (j = 0; j < ar->num_mixer_ctls; j++) { - if (ar->mixer_state[j].ctl == ctl) - break; - } - - /* apply the new value */ - ar->mixer_state[j].new_value = path->setting[i].value; - } - - 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_value = NULL; - struct config_parse_state *state = data; - struct audio_route *ar = state->ar; - unsigned int i; - struct mixer_ctl *ctl; - int value; - struct mixer_setting mixer_setting; - - /* Get name, type 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]; - 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 (i = 0; i < ar->num_mixer_ctls; i++) { - if (ar->mixer_state[i].ctl == ctl) - break; - } - - /* apply the new value */ - ar->mixer_state[i].new_value = value; - } else { - /* nested ctl (within a path) */ - mixer_setting.ctl = ctl; - mixer_setting.value = value; - path_add_setting(state->path, &mixer_setting); - } - } - - 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; - - 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++) { - ar->mixer_state[i].ctl = mixer_get_ctl(ar->mixer, i); - /* only get value 0, assume multiple ctl values are the same */ - ar->mixer_state[i].old_value = mixer_ctl_get_value(ar->mixer_state[i].ctl, 0); - ar->mixer_state[i].new_value = ar->mixer_state[i].old_value; - } - - return 0; -} - -static void free_mixer_state(struct audio_route *ar) -{ - free(ar->mixer_state); - ar->mixer_state = NULL; -} - -void update_mixer_state(struct audio_route *ar) -{ - unsigned int i; - unsigned int j; - - for (i = 0; i < ar->num_mixer_ctls; i++) { - /* if the value has changed, update the mixer */ - if (ar->mixer_state[i].old_value != ar->mixer_state[i].new_value) { - /* set all ctl values the same */ - for (j = 0; j < mixer_ctl_get_num_values(ar->mixer_state[i].ctl); j++) - mixer_ctl_set_value(ar->mixer_state[i].ctl, j, - ar->mixer_state[i].new_value); - ar->mixer_state[i].old_value = ar->mixer_state[i].new_value; - } - } -} - -/* saves the current state of the mixer, for resetting all controls */ -static void save_mixer_state(struct audio_route *ar) -{ - unsigned int i; - - for (i = 0; i < ar->num_mixer_ctls; i++) { - /* only get value 0, assume multiple ctl values are the same */ - ar->mixer_state[i].reset_value = mixer_ctl_get_value(ar->mixer_state[i].ctl, 0); - } -} - -/* this resets all mixer settings to the saved values */ -void reset_mixer_state(struct audio_route *ar) -{ - unsigned int i; - - /* load all of the saved values */ - for (i = 0; i < ar->num_mixer_ctls; i++) - ar->mixer_state[i].new_value = ar->mixer_state[i].reset_value; -} - -void audio_route_apply_path(struct audio_route *ar, const char *name) -{ - struct mixer_path *path; - - if (!ar) { - ALOGE("invalid audio_route"); - return; - } - - path = path_get_by_name(ar, name); - if (!path) { - ALOGE("unable to find path '%s'", name); - return; - } - - path_apply(ar, path); -} - -struct audio_route *audio_route_init(void) -{ - struct config_parse_state state; - XML_Parser parser; - FILE *file; - int bytes_read; - void *buf; - int i; - struct mixer_path *path; - struct audio_route *ar; - - ar = calloc(1, sizeof(struct audio_route)); - if (!ar) - goto err_calloc; - - ar->mixer = mixer_open(MIXER_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; - - file = fopen(MIXER_XML_PATH, "r"); - if (!file) { - ALOGE("Failed to open %s", MIXER_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 */ - update_mixer_state(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/audio_route.h b/audio/audio_route.h deleted file mode 100644 index 31355dd..0000000 --- a/audio/audio_route.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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_ROUTE_H -#define AUDIO_ROUTE_H - -/* Initialises and frees the audio routes */ -struct audio_route *audio_route_init(void); -void audio_route_free(struct audio_route *ar); - -/* Applies an audio route path by name */ -void audio_route_apply_path(struct audio_route *ar, const char *name); - -/* Resets the mixer back to its initial state */ -void reset_mixer_state(struct audio_route *ar); - -/* Updates the mixer with any changed values */ -void update_mixer_state(struct audio_route *ar); - -#endif |
