author | lei.qian <lei.qian> | 2013-04-25 08:57:59 (GMT) |
---|---|---|
committer | Lawrence Mok <lawrence.mok@amlogic.com> | 2013-04-25 18:41:38 (GMT) |
commit | 2f395805113cb149069b17de0c7cdc92a31aa176 (patch) | |
tree | 28c5076be8d487dd0c9d935cb28786d50423be38 | |
parent | c77f925577f3644cf7dfed2d9af72a2a36beaa83 (diff) | |
download | audio-2f395805113cb149069b17de0c7cdc92a31aa176.zip audio-2f395805113cb149069b17de0c7cdc92a31aa176.tar.gz audio-2f395805113cb149069b17de0c7cdc92a31aa176.tar.bz2 |
pd #69289: modified for USB audio.
-rwxr-xr-x | Android.mk | 35 | ||||
-rwxr-xr-x | audio_hw.c | 234 | ||||
-rwxr-xr-x[-rw-r--r--] | audio_policy.c | 0 | ||||
-rwxr-xr-x | audio_route.c | 494 | ||||
-rwxr-xr-x | audio_route.h | 33 | ||||
-rw-r--r-- | m3codec_mixer_ctl.h | 43 | ||||
-rwxr-xr-x | rt3261_mixer_ctrl.h | 897 | ||||
-rwxr-xr-x | rt5631_mixer_ctrl.h | 203 | ||||
-rwxr-xr-x | rt5631_mixer_paths.xml | 34 | ||||
-rwxr-xr-x | usb_audio_hw.c | 1119 | ||||
-rwxr-xr-x | wm8960_mixer_ctrl.h | 237 | ||||
-rwxr-xr-x | wm8960_mixer_paths.xml | 45 |
12 files changed, 1777 insertions, 1597 deletions
@@ -26,12 +26,17 @@ ifeq ($(strip $(BOARD_ALSA_AUDIO)),tiny) LOCAL_MODULE := audio.primary.amlogic LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw - LOCAL_SRC_FILES := audio_hw.c + LOCAL_SRC_FILES := \ + audio_hw.c \ + audio_route.c LOCAL_C_INCLUDES += \ external/tinyalsa/include \ system/media/audio_utils/include \ - system/media/audio_effects/include - LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa libaudioutils libdl + system/media/audio_effects/include \ + external/expat/lib + LOCAL_SHARED_LIBRARIES := \ + liblog libcutils libtinyalsa \ + libaudioutils libdl libexpat LOCAL_MODULE_TAGS := optional #CONFIG_AML_CODEC @@ -39,16 +44,24 @@ ifeq ($(strip $(BOARD_ALSA_AUDIO)),tiny) LOCAL_CFLAGS += -DAML_AUDIO_RT5631 endif - ifeq ($(BOARD_AUDIO_CODEC),wm8960) - LOCAL_CFLAGS += -DAML_AUDIO_WM8960 + include $(BUILD_SHARED_LIBRARY) +#build for USB audio + ifeq ($(strip $(BOARD_USE_USB_AUDIO)),true) + include $(CLEAR_VARS) + + LOCAL_MODULE := audio.usb.amlogic + LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw + LOCAL_SRC_FILES := \ + usb_audio_hw.c + LOCAL_C_INCLUDES += \ + external/tinyalsa/include \ + system/media/audio_utils/include + LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa libaudioutils + LOCAL_MODULE_TAGS := optional + + include $(BUILD_SHARED_LIBRARY) endif - ifeq ($(BOARD_AUDIO_CODEC),rt3261) - LOCAL_CFLAGS += -DAML_AUDIO_RT3261 - endif - - include $(BUILD_SHARED_LIBRARY) - # The stub audio policy HAL module that can be used as a skeleton for # new implementations. #include $(CLEAR_VARS) @@ -43,48 +43,7 @@ #include <audio_utils/echo_reference.h> #include <hardware/audio_effect.h> #include <audio_effects/effect_aec.h> - -#include <cutils/properties.h> - -#if defined(AML_AUDIO_RT5631) -#include "rt5631_mixer_ctrl.h" -#elif defined(AML_AUDIO_M3CODEC) -#include "m3codec_mixer_ctl.h" -#elif defined(AML_AUDIO_WM8960) -#include "wm8960_mixer_ctrl.h" -#elif defined(AML_AUDIO_RT3261) -#include "rt3261_mixer_ctrl.h" -#else -struct route_setting -{ - char *ctl_name; - int intval; - char *strval; -}; -struct route_setting mic_input[] = -{ - { - .ctl_name = NULL, - }, -}; -struct route_setting line_input[] = -{ - { - .ctl_name = NULL, - }, -}; -static struct route_setting output_headphone[] = -{ - { - .ctl_name = NULL, - }, -};static struct route_setting output_speaker[] = -{ - { - .ctl_name = NULL, - }, -}; -#endif +#include "audio_route.h" /* ALSA cards for AML */ #define CARD_AMLOGIC_BOARD 0 @@ -93,8 +52,7 @@ static struct route_setting output_headphone[] = /* ALSA ports for AML */ #define PORT_MM 0 /* number of frames per period */ -#define DEFAULT_PERIOD_SIZE 1024 -static unsigned PERIOD_SIZE = DEFAULT_PERIOD_SIZE; +#define PERIOD_SIZE 1024 /* number of periods for low power playback */ #define PLAYBACK_PERIOD_COUNT 4 /* number of periods for capture */ @@ -118,7 +76,7 @@ static unsigned PERIOD_SIZE = DEFAULT_PERIOD_SIZE; struct pcm_config pcm_config_out = { .channels = 2, .rate = MM_FULL_POWER_SAMPLING_RATE, - .period_size = DEFAULT_PERIOD_SIZE, + .period_size = PERIOD_SIZE, .period_count = PLAYBACK_PERIOD_COUNT, .format = PCM_FORMAT_S16_LE, }; @@ -126,21 +84,15 @@ struct pcm_config pcm_config_out = { struct pcm_config pcm_config_in = { .channels = 2, .rate = MM_FULL_POWER_SAMPLING_RATE, - .period_size = DEFAULT_PERIOD_SIZE, + .period_size = PERIOD_SIZE, .period_count = PLAYBACK_PERIOD_COUNT, .format = PCM_FORMAT_S16_LE, }; -struct mixer_ctls{ - struct mixer_ctl *master_playback_volume; - struct mixer_ctl *capture_volume; -}; struct aml_audio_device { struct audio_hw_device hw_device; pthread_mutex_t lock; /* see note below on mutex acquisition order */ - struct mixer *mixer; - struct mixer_ctls mixer_ctls; int mode; audio_devices_t in_device; audio_devices_t out_device; @@ -152,6 +104,7 @@ struct aml_audio_device { struct aml_stream_out *active_output; bool mic_mute; + struct audio_route *ar; struct echo_reference_itfe *echo_reference; bool bluetooth_nrec; bool low_power; @@ -215,56 +168,6 @@ static int adev_set_voice_volume(struct audio_hw_device *dev, float volume); static int do_input_standby(struct aml_stream_in *in); static int do_output_standby(struct aml_stream_out *out); -static int getprop_bool(const char * path) -{ - char buf[20]; - int ret = -1; - - ret = property_get(path, buf, NULL); - if (ret > 0) { - if(strcasecmp(buf,"true")==0 || strcmp(buf,"1")==0) - return 1; - } - return 0; -} - -/* The enable flag when 0 makes the assumption that enums are disabled by - * "Off" and integers/booleans by 0 */ -static int set_route_by_array(struct mixer *mixer, struct route_setting *route, - int enable) -{ - struct mixer_ctl *ctl; - unsigned int i, j; - - /* Go through the route array and set each value */ - i = 0; - while (route[i].ctl_name) { - ctl = mixer_get_ctl_by_name(mixer, route[i].ctl_name); - if (!ctl) - return -EINVAL; - - //LOGFUNC("set_route_by_array().... index[%d] enable[%d] : ctl_name=%s, strval=%s, intval=%d", - // i, enable, route[i].ctl_name, route[i].strval,route[i].intval); - if (route[i].strval) { - if (enable) - mixer_ctl_set_enum_by_string(ctl, route[i].strval); - else - mixer_ctl_set_enum_by_string(ctl, "Off"); - } else { - /* This ensures multiple (i.e. stereo) values are set jointly */ - for (j = 0; j < mixer_ctl_get_num_values(ctl); j++) { - if (enable) - mixer_ctl_set_value(ctl, j, route[i].intval); - else - mixer_ctl_set_value(ctl, j, 0); - } - } - i++; - } - - return 0; -} - static void select_output_device(struct aml_audio_device *adev) { LOGFUNC("%s(mode=%d, out_device=%#x)", __FUNCTION__, adev->mode, adev->out_device); @@ -277,28 +180,30 @@ static void select_output_device(struct aml_audio_device *adev) headphone_on = adev->out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; speaker_on = adev->out_device & AUDIO_DEVICE_OUT_SPEAKER; LOGFUNC("~~~~ %s : hs=%d , hp=%d, sp=%d", __func__, headset_on, headphone_on, speaker_on); - if(headset_on|headphone_on) - set_route_by_array(adev->mixer, output_headphone, headset_on | headphone_on); - else - { - set_route_by_array(adev->mixer, output_speaker, speaker_on); - LOGFUNC("speaker_on\n"); - } + reset_mixer_state(adev->ar); + if (speaker_on) + audio_route_apply_path(adev->ar, "speaker"); + if (headphone_on || headset_on) + audio_route_apply_path(adev->ar, "headphone"); + update_mixer_state(adev->ar); } static void select_input_device(struct aml_audio_device *adev) { - int mic_in = adev->in_device & (AUDIO_DEVICE_IN_BUILTIN_MIC | AUDIO_DEVICE_IN_BACK_MIC); + int mic_in = adev->in_device & AUDIO_DEVICE_IN_BUILTIN_MIC; int headset_mic = adev->in_device & AUDIO_DEVICE_IN_WIRED_HEADSET; - LOGFUNC("~~~~ %s : in_device(%#x), mic_in(%#x)", __func__, adev->in_device, mic_in); - - if (mic_in) - set_route_by_array(adev->mixer, mic_input, mic_in); - else if(headset_mic) - set_route_by_array(adev->mixer, headset_input, headset_mic); - else - LOGFUNC("ERROR, no active input device available!\n"); - + LOGFUNC("~~~~ %s : in_device(%#x), mic_in(%#x), headset_mic(%#x)", __func__, adev->in_device, mic_in, headset_mic); + + reset_mixer_state(adev->ar); + if (mic_in) + { + audio_route_apply_path(adev->ar, "main_mic"); + } + if (headset_mic) + { + audio_route_apply_path(adev->ar, "headset-mic"); + } + update_mixer_state(adev->ar); return; } @@ -449,14 +354,6 @@ static int start_output_stream(struct aml_stream_out *out) card = CARD_AMLOGIC_BOARD; port = PORT_MM; LOGFUNC("------------open on board audio-------"); - if(getprop_bool("media.libplayer.wfd")){ - PERIOD_SIZE = DEFAULT_PERIOD_SIZE/2; - out->config.period_size = PERIOD_SIZE; - } - else{ - PERIOD_SIZE = DEFAULT_PERIOD_SIZE; - out->config.period_size = PERIOD_SIZE; - } out->config.rate = MM_FULL_POWER_SAMPLING_RATE; /* default to low power: will be corrected in out_write if necessary before first write to * tinyalsa. @@ -682,21 +579,7 @@ static audio_channel_mask_t out_get_channels(const struct audio_stream *stream) // return AUDIO_CHANNEL_OUT_STEREO; //return AUDIO_CHANNEL_OUT_STEREO; } -/* -static uint32_t out_get_channels(const struct audio_stream *stream) -{ - //LOGFUNC("%s(%p)", __FUNCTION__, stream); - struct aml_stream_out *out = (struct aml_stream_out *)stream; - if (out->config.channels == 1) { - return AUDIO_CHANNEL_OUT_MONO; - } else { - return AUDIO_CHANNEL_OUT_STEREO; - } - - return AUDIO_CHANNEL_OUT_STEREO; -} -*/ static audio_format_t out_get_format(const struct audio_stream *stream) { // LOGFUNC("%s(%p)", __FUNCTION__, stream); @@ -729,8 +612,8 @@ static int do_output_standby(struct aml_stream_out *out) be done when the call is ended */ if (adev->mode != AUDIO_MODE_IN_CALL) { /* FIXME: only works if only one output can be active at a time */ - set_route_by_array(adev->mixer, output_headphone, 0); - set_route_by_array(adev->mixer, output_speaker, 0); + + reset_mixer_state(adev->ar); } /* stop writing to echo reference */ @@ -1117,16 +1000,6 @@ static int start_input_stream(struct aml_stream_in *in) ALOGV("%s(in->requested_rate=%d, in->config.rate=%d)", __FUNCTION__, in->requested_rate, in->config.rate); - if(getprop_bool("media.libplayer.wfd")){ - PERIOD_SIZE = DEFAULT_PERIOD_SIZE/2; - in->config.period_size = PERIOD_SIZE; - } - else - { - PERIOD_SIZE = DEFAULT_PERIOD_SIZE; - in->config.period_size = PERIOD_SIZE; - } - if (in->need_echo_reference && in->echo_reference == NULL) { in->echo_reference = get_echo_reference(adev, AUDIO_FORMAT_PCM_16_BIT, @@ -1249,19 +1122,7 @@ static audio_channel_mask_t in_get_channels(const struct audio_stream *stream) } //return AUDIO_CHANNEL_IN_MONO; } -/* -static uint32_t in_get_channels(const struct audio_stream *stream) -{ - struct aml_stream_in *in = (struct aml_stream_in *)stream; - //LOGFUNC("%s(%p)", __FUNCTION__, stream); - if (in->config.channels == 1) { - return AUDIO_CHANNEL_IN_MONO; - } else { - return AUDIO_CHANNEL_IN_STEREO; - } -} -*/ static audio_format_t in_get_format(const struct audio_stream *stream) { //LOGFUNC("%s(%p)", __FUNCTION__, stream); @@ -1529,7 +1390,6 @@ static int get_next_buffer(struct resampler_buffer_provider *buffer_provider, { struct aml_stream_in *in; - //LOGFUNC("%s(%p, %p)", __FUNCTION__, buffer_provider, buffer); if (buffer_provider == NULL || buffer == NULL) return -EINVAL; @@ -2353,9 +2213,7 @@ static int adev_close(hw_device_t *device) LOGFUNC("%s(%p)", __FUNCTION__, device); /* RIL */ //ril_close(&adev->ril); - - mixer_close(adev->mixer); - + audio_route_free(adev->ar); free(device); return 0; } @@ -2423,49 +2281,13 @@ 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->mixer = mixer_open(0); - if (!adev->mixer) { - free(adev); - ALOGE("Unable to open the mixer, aborting."); - return -EINVAL; - } - -#if 0 -{ - struct mixer *mixer = adev->mixer; - struct mixer_ctl *ctl; - unsigned int i, j; - char name[128]; - - ALOGE("ctl_name... adev_open"); - - for(i = 0 ; i < mixer_get_num_ctls(mixer) ; i++) { - ctl = mixer_get_ctl(mixer, i); - if (ctl != NULL) { - j = mixer_ctl_get_name(ctl, name, 128); - ALOGE("ctl_name[%02d]: %s, type : %s", i, name, mixer_ctl_get_type_string(ctl)); - if(mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_ENUM) - { - for(j=0; j<mixer_ctl_get_num_enums(ctl); j++) - { - mixer_ctl_get_enum_string(ctl, j, name, 128); - ALOGE("\t ENUM(%d) : %s", j, name); - } - } - - } - else - ALOGE("ctl_name[%02d]: can not get control pointer", i); - } -} -#endif + adev->ar = audio_route_init(); /* Set the default route before the PCM stream is opened */ adev->mode = AUDIO_MODE_NORMAL; adev->out_device = AUDIO_DEVICE_OUT_SPEAKER; adev->in_device = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN; - //adev->devices = AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_IN_BUILTIN_MIC; select_output_device(adev); *device = &adev->hw_device.common; diff --git a/audio_policy.c b/audio_policy.c index 0f623b0..0f623b0 100644..100755 --- a/audio_policy.c +++ b/audio_policy.c diff --git a/audio_route.c b/audio_route.c new file mode 100755 index 0000000..a4ec8f5 --- a/dev/null +++ b/audio_route.c @@ -0,0 +1,494 @@ +/* + * 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 0 + +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_route.h b/audio_route.h new file mode 100755 index 0000000..31355dd --- a/dev/null +++ b/audio_route.h @@ -0,0 +1,33 @@ +/* + * 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 diff --git a/m3codec_mixer_ctl.h b/m3codec_mixer_ctl.h deleted file mode 100644 index c4f3e33..0000000 --- a/m3codec_mixer_ctl.h +++ b/dev/null @@ -1,43 +0,0 @@ -/* - * m3codec_mixer_ctl.h -- AML_M3 Mixer control for Android ICS - * - * Copyright 2012 Amlogic Corp. - * - */ - -#ifndef _M3CODEC_MIXER_CTL_H_ -#define _M3CODEC_MIXER_CTL_H_ - -//Todo: add route controls -struct route_setting -{ - char *ctl_name; - int intval; - char *strval; -}; -struct route_setting mic_input[] = -{ - { - .ctl_name = NULL, - }, -}; -struct route_setting line_input[] = -{ - { - .ctl_name = NULL, - }, -}; -static struct route_setting output_headphone[] = -{ - { - .ctl_name = NULL, - }, -};static struct route_setting output_speaker[] = -{ - { - .ctl_name = NULL, - }, -}; - -#endif //_M3CODEC_MIXER_CTL_H_ - diff --git a/rt3261_mixer_ctrl.h b/rt3261_mixer_ctrl.h deleted file mode 100755 index 1c77857..0000000 --- a/rt3261_mixer_ctrl.h +++ b/dev/null @@ -1,897 +0,0 @@ -/* - * rt3261_mixer_ctrl.h -- RT3261 Mixer control for Android ICS - * - * Copyright 2012 Amlogic Corp. - * - */ - -#ifndef _RT3261_MIXER_CTRL_H_ -#define _RT3261_MIXER_CTRL_H_ - -struct route_setting -{ - char *ctl_name; - int intval; - char *strval; -}; - -struct route_setting output_speaker[] = { - { - .ctl_name = "Mono DAC MIXL DAC L2 Switch", - .intval = 0, - }, - { - .ctl_name = "Mono DAC MIXR DAC R2 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXL BST1 Switch", - .intval = 1, - }, - { - .ctl_name = "RECMIXR BST1 Switch", - .intval = 1, - }, - { - .ctl_name = "RECMIXL BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "RECMIXR BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "Stereo ADC L1 Mux", - .strval = "ADC", - }, - { - .ctl_name = "Stereo ADC R1 Mux", - .strval = "ADC", - }, - { - .ctl_name = "Stereo ADC MIXL ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "Stereo ADC MIXR ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "Stereo DAC MIXL DAC L1 Switch", - .intval = 1, - }, - { - .ctl_name = "Stereo DAC MIXR DAC R1 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXL DAC L1 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXR DAC R1 Switch", - .intval = 1, - }, - { - .ctl_name = "SPK MIXL OUT MIXL Switch", - .intval = 1, - }, - { - .ctl_name = "SPK MIXR OUT MIXR Switch", - .intval = 1, - }, - { - .ctl_name = "SPOL MIX SPKVOL L Switch", - .intval = 1, - }, - { - .ctl_name = "SPOR MIX SPKVOL R Switch", - .intval = 1, - }, - { - .ctl_name = "I2S2 mode Switch", - .strval = "Disable", - }, - { - .ctl_name = NULL, - }, -}; - -struct route_setting speaker_ringtone[] = { - { - .ctl_name = "RECMIXL BST1 Switch", - .intval = 1, - }, - { - .ctl_name = "RECMIXR BST1 Switch", - .intval = 1, - }, - { - .ctl_name = "RECMIXL BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "RECMIXR BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "Mono ADC L1 Mux", - .strval = "ADCL", - }, - { - .ctl_name = "Mono ADC R1 Mux", - .strval = "ADCR", - }, - { - .ctl_name = "Mono ADC MIXL ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "Mono ADC MIXR ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "IF2 ADC L Mux", - .strval = "Mono ADC MIXL", - }, - { - .ctl_name = "IF2 ADC R Mux", - .strval = "Mono ADC MIXR", - }, - { - .ctl_name = "Stereo DAC MIXL DAC L1 Switch", - .intval = 1, - }, - { - .ctl_name = "Stereo DAC MIXR DAC R1 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXL DAC L1 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXR DAC R1 Switch", - .intval = 1, - }, - { - .ctl_name = "SPK MIXL OUT MIXL Switch", - .intval = 1, - }, - { - .ctl_name = "SPK MIXR OUT MIXR Switch", - .intval = 1, - }, - { - .ctl_name = "SPOL MIX SPKVOL L Switch", - .intval = 1, - }, - { - .ctl_name = "SPOR MIX SPKVOL R Switch", - .intval = 1, - }, - { - .ctl_name = "I2S2 mode Switch", - .strval = "Disable", - }, - { - .ctl_name = NULL, - }, -}; - -struct route_setting speaker_incall[] = { - { - .ctl_name = "I2S2 mode Switch", - .strval = "3G", - }, - { - .ctl_name = "Stereo DAC MIXL DAC L1 Switch", - .intval = 0, - }, - { - .ctl_name = "Stereo DAC MIXR DAC R1 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXL BST1 Switch", - .intval = 1, - }, - { - .ctl_name = "RECMIXR BST1 Switch", - .intval = 1, - }, - { - .ctl_name = "RECMIXL BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "RECMIXR BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "Mono ADC L1 Mux", - .strval = "ADCL", - }, - { - .ctl_name = "Mono ADC R1 Mux", - .strval = "ADCR", - }, - { - .ctl_name = "Mono ADC MIXL ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "Mono ADC MIXR ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "IF2 ADC L Mux", - .strval = "Mono ADC MIXL", - }, - { - .ctl_name = "IF2 ADC R Mux", - .strval = "Mono ADC MIXR", - }, - { - .ctl_name = "DAC L2 Mux", - .strval = "IF2", - }, - { - .ctl_name = "DAC R2 Mux", - .strval = "IF2", - }, - { - .ctl_name = "Mono DAC MIXL DAC L2 Switch", - .intval = 1, - }, - { - .ctl_name = "Mono DAC MIXR DAC R2 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXL DAC L2 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXR DAC R2 Switch", - .intval = 1, - }, - { - .ctl_name = "SPK MIXL OUT MIXL Switch", - .intval = 1, - }, - { - .ctl_name = "SPK MIXR OUT MIXR Switch", - .intval = 1, - }, - { - .ctl_name = "SPOL MIX SPKVOL L Switch", - .intval = 1, - }, - { - .ctl_name = "SPOR MIX SPKVOL R Switch", - .intval = 1, - }, - { - .ctl_name = NULL, - }, -}; - -struct route_setting output_headphone[] = { - { - .ctl_name = "Mono DAC MIXL DAC L2 Switch", - .intval = 0, - }, - { - .ctl_name = "Mono DAC MIXR DAC R2 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXL BST1 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXR BST1 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXL BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "RECMIXR BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "Stereo ADC L1 Mux", - .strval = "ADC", - }, - { - .ctl_name = "Stereo ADC R1 Mux", - .strval = "ADC", - }, - { - .ctl_name = "Stereo ADC MIXL ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "Stereo ADC MIXR ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "Stereo DAC MIXL DAC L1 Switch", - .intval = 1, - }, - { - .ctl_name = "Stereo DAC MIXR DAC R1 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXL DAC L1 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXR DAC R1 Switch", - .intval = 1, - }, - { - .ctl_name = "SPK MIXL DAC L1 Switch", - .intval = 0, - }, - { - .ctl_name = "SPK MIXR DAC R1 Switch", - .intval = 0, - }, - { - .ctl_name = "SPK MIXL OUT MIXL Switch", - .intval = 0, - }, - { - .ctl_name = "SPK MIXR OUT MIXR Switch", - .intval = 0, - }, - { - .ctl_name = "SPOL MIX SPKVOL L Switch", - .intval = 0, - }, - { - .ctl_name = "SPOR MIX SPKVOL R Switch", - .intval = 0, - }, - { - .ctl_name = "HPOL MIX HPVOL Switch", - .intval = 1, - }, - { - .ctl_name = "HPOR MIX HPVOL Switch", - .intval = 1, - }, - { - .ctl_name = "I2S2 mode Switch", - .strval = "Disable", - }, - { - .ctl_name = NULL, - }, -}; - -struct route_setting headphone_ringtone[] = { - { - .ctl_name = "RECMIXL BST1 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXR BST1 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXL BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "RECMIXR BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "Mono ADC L1 Mux", - .strval = "ADCL", - }, - { - .ctl_name = "Mono ADC R1 Mux", - .strval = "ADCR", - }, - { - .ctl_name = "Mono ADC MIXL ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "Mono ADC MIXR ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "IF2 ADC L Mux", - .strval = "Mono ADC MIXL", - }, - { - .ctl_name = "IF2 ADC R Mux", - .strval = "Mono ADC MIXR", - }, - { - .ctl_name = "Stereo DAC MIXL DAC L1 Switch", - .intval = 1, - }, - { - .ctl_name = "Stereo DAC MIXR DAC R1 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXL DAC L1 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXR DAC R1 Switch", - .intval = 1, - }, - { - .ctl_name = "SPK MIXL OUT MIXL Switch", - .intval = 1, - }, - { - .ctl_name = "SPK MIXR OUT MIXR Switch", - .intval = 1, - }, - { - .ctl_name = "SPOL MIX SPKVOL L Switch", - .intval = 1, - }, - { - .ctl_name = "SPOR MIX SPKVOL R Switch", - .intval = 1, - }, - { - .ctl_name = "HPOL MIX HPVOL Switch", - .intval = 1, - }, - { - .ctl_name = "HPOR MIX HPVOL Switch", - .intval = 1, - }, - { - .ctl_name = "I2S2 mode Switch", - .strval = "Disable", - }, - { - .ctl_name = NULL, - }, -}; - -struct route_setting headphone_incall[] = { - { - .ctl_name = "I2S2 mode Switch", - .strval = "3G", - }, - { - .ctl_name = "Stereo DAC MIXL DAC L1 Switch", - .intval = 0, - }, - { - .ctl_name = "Stereo DAC MIXR DAC R1 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXL BST1 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXR BST1 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXL BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "RECMIXR BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "Mono ADC L1 Mux", - .strval = "ADCL", - }, - { - .ctl_name = "Mono ADC R1 Mux", - .strval = "ADCR", - }, - { - .ctl_name = "Mono ADC MIXL ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "Mono ADC MIXR ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "IF2 ADC L Mux", - .strval = "Mono ADC MIXL", - }, - { - .ctl_name = "IF2 ADC R Mux", - .strval = "Mono ADC MIXR", - }, - { - .ctl_name = "DAC L2 Mux", - .strval = "IF2", - }, - { - .ctl_name = "DAC R2 Mux", - .strval = "IF2", - }, - { - .ctl_name = "Mono DAC MIXL DAC L2 Switch", - .intval = 1, - }, - { - .ctl_name = "Mono DAC MIXR DAC R2 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXL DAC L2 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXR DAC R2 Switch", - .intval = 1, - }, - { - .ctl_name = "SPK MIXL OUT MIXL Switch", - .intval = 0, - }, - { - .ctl_name = "SPK MIXR OUT MIXR Switch", - .intval = 0, - }, - { - .ctl_name = "SPOL MIX SPKVOL L Switch", - .intval = 0, - }, - { - .ctl_name = "SPOR MIX SPKVOL R Switch", - .intval = 0, - }, - { - .ctl_name = "HPOL MIX HPVOL Switch", - .intval = 1, - }, - { - .ctl_name = "HPOR MIX HPVOL Switch", - .intval = 1, - }, - { - .ctl_name = NULL, - }, -}; - -struct route_setting headset[] = { - { - .ctl_name = "Mono DAC MIXL DAC L2 Switch", - .intval = 0, - }, - { - .ctl_name = "Mono DAC MIXR DAC R2 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXL BST1 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXR BST1 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXL BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "RECMIXR BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "Stereo ADC L1 Mux", - .strval = "ADC", - }, - { - .ctl_name = "Stereo ADC R1 Mux", - .strval = "ADC", - }, - { - .ctl_name = "Stereo ADC MIXL ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "Stereo ADC MIXR ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "Stereo DAC MIXL DAC L1 Switch", - .intval = 1, - }, - { - .ctl_name = "Stereo DAC MIXR DAC R1 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXL DAC L1 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXR DAC R1 Switch", - .intval = 1, - }, - { - .ctl_name = "SPK MIXL DAC L1 Switch", - .intval = 0, - }, - { - .ctl_name = "SPK MIXR DAC R1 Switch", - .intval = 0, - }, - { - .ctl_name = "SPK MIXL OUT MIXL Switch", - .intval = 0, - }, - { - .ctl_name = "SPK MIXR OUT MIXR Switch", - .intval = 0, - }, - { - .ctl_name = "SPOL MIX SPKVOL L Switch", - .intval = 0, - }, - { - .ctl_name = "SPOR MIX SPKVOL R Switch", - .intval = 0, - }, - { - .ctl_name = "HPOL MIX HPVOL Switch", - .intval = 1, - }, - { - .ctl_name = "HPOR MIX HPVOL Switch", - .intval = 1, - }, - { - .ctl_name = "I2S2 mode Switch", - .strval = "Disable", - }, - { - .ctl_name = NULL, - }, -}; - -struct route_setting headset_ringtone[] = { - { - .ctl_name = "RECMIXL BST1 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXR BST1 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXL BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "RECMIXR BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "Mono ADC L1 Mux", - .strval = "ADCL", - }, - { - .ctl_name = "Mono ADC R1 Mux", - .strval = "ADCR", - }, - { - .ctl_name = "Mono ADC MIXL ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "Mono ADC MIXR ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "IF2 ADC L Mux", - .strval = "Mono ADC MIXL", - }, - { - .ctl_name = "IF2 ADC R Mux", - .strval = "Mono ADC MIXR", - }, - { - .ctl_name = "Stereo DAC MIXL DAC L1 Switch", - .intval = 1, - }, - { - .ctl_name = "Stereo DAC MIXR DAC R1 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXL DAC L1 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXR DAC R1 Switch", - .intval = 1, - }, - { - .ctl_name = "SPK MIXL OUT MIXL Switch", - .intval = 1, - }, - { - .ctl_name = "SPK MIXR OUT MIXR Switch", - .intval = 1, - }, - { - .ctl_name = "SPOL MIX SPKVOL L Switch", - .intval = 1, - }, - { - .ctl_name = "SPOR MIX SPKVOL R Switch", - .intval = 1, - }, - { - .ctl_name = "HPOL MIX HPVOL Switch", - .intval = 1, - }, - { - .ctl_name = "HPOR MIX HPVOL Switch", - .intval = 1, - }, - { - .ctl_name = "I2S2 mode Switch", - .strval = "Disable", - }, - { - .ctl_name = NULL, - }, -}; - -struct route_setting headset_incall[] = { - { - .ctl_name = "I2S2 mode Switch", - .strval = "3G", - }, - { - .ctl_name = "Stereo DAC MIXL DAC L1 Switch", - .intval = 0, - }, - { - .ctl_name = "Stereo DAC MIXR DAC R1 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXL BST1 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXR BST1 Switch", - .intval = 0, - }, - { - .ctl_name = "RECMIXL BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "RECMIXR BST2 Switch", - .intval = 1, - }, - { - .ctl_name = "Mono ADC L1 Mux", - .strval = "ADCL", - }, - { - .ctl_name = "Mono ADC R1 Mux", - .strval = "ADCR", - }, - { - .ctl_name = "Mono ADC MIXL ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "Mono ADC MIXR ADC1 Switch", - .intval = 1, - }, - { - .ctl_name = "IF2 ADC L Mux", - .strval = "Mono ADC MIXL", - }, - { - .ctl_name = "IF2 ADC R Mux", - .strval = "Mono ADC MIXR", - }, - { - .ctl_name = "DAC L2 Mux", - .strval = "IF2", - }, - { - .ctl_name = "DAC R2 Mux", - .strval = "IF2", - }, - { - .ctl_name = "Mono DAC MIXL DAC L2 Switch", - .intval = 1, - }, - { - .ctl_name = "Mono DAC MIXR DAC R2 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXL DAC L2 Switch", - .intval = 1, - }, - { - .ctl_name = "OUT MIXR DAC R2 Switch", - .intval = 1, - }, - { - .ctl_name = "SPK MIXL OUT MIXL Switch", - .intval = 0, - }, - { - .ctl_name = "SPK MIXR OUT MIXR Switch", - .intval = 0, - }, - { - .ctl_name = "SPOL MIX SPKVOL L Switch", - .intval = 0, - }, - { - .ctl_name = "SPOR MIX SPKVOL R Switch", - .intval = 0, - }, - { - .ctl_name = "HPOL MIX HPVOL Switch", - .intval = 1, - }, - { - .ctl_name = "HPOR MIX HPVOL Switch", - .intval = 1, - }, - { - .ctl_name = NULL, - }, -}; - -struct route_setting mic_input[] = { - { - .ctl_name = "RECMIXL Mixer MIC1_BST1 Capture Switch", - .intval = 1, - }, - { - .ctl_name = "MIC1 Boost", - .intval = 3, - }, - { - .ctl_name = NULL, - }, -}; - -struct route_setting headset_mic[] = { - { - .ctl_name = "RECMIXL Mixer MIC2_BST1 Capture Switch", - .intval = 1, - }, - { - .ctl_name = "MIC2 Boost", - .intval = 3, - }, - { - .ctl_name = NULL, - }, -}; - -#endif //_RT3261_MIXER_CTRL_H_ - diff --git a/rt5631_mixer_ctrl.h b/rt5631_mixer_ctrl.h deleted file mode 100755 index 175f685..0000000 --- a/rt5631_mixer_ctrl.h +++ b/dev/null @@ -1,203 +0,0 @@ -/* - * rt5631_mixer_ctrl.h -- RT5631 Mixer control for Android ICS - * - * Copyright 2012 Amlogic Corp. - * - */ - -#ifndef _RT5631_MIXER_CTRL_H_ -#define _RT5631_MIXER_CTRL_H_ - -struct route_setting -{ - char *ctl_name; - int intval; - char *strval; -}; - -/* Mixer control names */ -/* INT type */ -#define MIXER_HP_PLAYBACK_VOLUME "HP Playback Volume" -#define MIXER_SPK_PLAYBACK_VOLUME "Speaker Playback Volume" -#define MIXER_MIC1_BOOST "MIC1 Boost" - -/* ENUM type */ -#define MIXER_JACK_FUNC_ENUM "Jack Function" -#define MIXER_SPEAKER_FUNC_ENUM "Speaker Function" -#define MIXER_R_HPVOL_MUX_ENUM "Right HPVOL Mux" -#define MIXER_L_HPVOL_MUX_ENUM "Left HPVOL Mux" -#define MIXER_R_SPKVOL_MUX_ENUM "Right SPKVOL Mux" -#define MIXER_L_SPKVOL_MUX_ENUM "Left SPKVOL Mux" -#define MIXER_SPKR_MUX_ENUM "SPOR Mux" -#define MIXER_SPKL_MUX_ENUM "SPOL Mux" -#define MIXER_HPL_MUX_ENUM "HPL Mux" -#define MIXER_HPR_MUX_ENUM "HPR Mux" - -/* BOOL type */ -#define MIXER_HP_PLAYBACK_SWITCH "HP Playback Switch" -#define MIXER_SPK_PLAYBACK_SWITCH "Speaker Playback Switch" -#define MIXER_RECMIXL_MIC1_CAPTURE_SWITCH "RECMIXL Mixer MIC1_BST1 Capture Switch" -#define MIXER_OUT_DACR_PLAYBACK_SWITCH "OUTMIXR Mixer DACR Playback Switch" -#define MIXER_OUT_DACL_PLAYBACK_SWITCH "OUTMIXL Mixer DACL Playback Switch" -#define MIXER_SPKMIX_DACR_PLAYBACK_SWITCH "SPKMIXR Mixer DACR Playback Switch" -#define MIXER_SPKMIX_DACL_PLAYBACK_SWITCH "SPKMIXL Mixer DACL Playback Switch" -#define MIXER_SPKRMIX_SPKVOLR_PLAYBACK_SWITCH "SPORMIX Mixer SPKVOLR Playback Switch" -#define MIXER_SPKLMIX_SPKVOLL_PLAYBACK_SWITCH "SPOLMIX Mixer SPKVOLL Playback Switch" -#define MIXER_SPKRMIX_SPKVOLL_PLAYBACK_SWITCH "SPORMIX Mixer SPKVOLL Playback Switch" -#define MIXER_SPKLMIX_SPKVOLR_PLAYBACK_SWITCH "SPOLMIX Mixer SPKVOLR Playback Switch" - -/* Mixer control value */ -#define MIXER_JACK_SPEAKER "Speaker" -#define MIXER_JACK_HEADPHONE "HeadPhone" -#define MIXER_SPEAKER_ON "On" -#define MIXER_SPEAKER_OFF "Off" -#define MIXER_L_HPVOL_OUTMIX "OUTMIXL" -#define MIXER_R_HPVOL_OUTMIX "OUTMIXR" -#define MIXER_L_SPKVOL_OUTMIX "SPKMIXL" -#define MIXER_R_SPKVOL_OUTMIX "SPKMIXR" -#define MIXER_SPK_MUX_SPOL "SPOLMIX" -#define MIXER_SPK_MUX_SPOR "SPORMIX" - -struct route_setting mic_input[] = { - { - .ctl_name = MIXER_RECMIXL_MIC1_CAPTURE_SWITCH, - .intval = 1 - }, - { - .ctl_name = MIXER_MIC1_BOOST, - .intval = 4 - }, - { - .ctl_name = NULL, - }, -}; - -struct route_setting headset_input[] = { - { - .ctl_name = NULL, - }, -}; - -struct route_setting output_speaker[] = { - { - .ctl_name = MIXER_SPKMIX_DACR_PLAYBACK_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_SPKMIX_DACL_PLAYBACK_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_R_SPKVOL_MUX_ENUM, - .strval = MIXER_R_SPKVOL_OUTMIX, - }, - { - .ctl_name = MIXER_L_SPKVOL_MUX_ENUM, - .strval = MIXER_L_SPKVOL_OUTMIX, - }, - { - .ctl_name = MIXER_SPKLMIX_SPKVOLL_PLAYBACK_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_SPKRMIX_SPKVOLR_PLAYBACK_SWITCH, - .intval = 1, - }, -/* { - .ctl_name = MIXER_SPKRMIX_SPKVOLL_PLAYBACK_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_SPKLMIX_SPKVOLR_PLAYBACK_SWITCH, - .intval = 1, - },*/ - { - .ctl_name = MIXER_SPKR_MUX_ENUM, - .strval = MIXER_SPK_MUX_SPOR, - }, - { - .ctl_name = MIXER_SPKL_MUX_ENUM, - .strval = MIXER_SPK_MUX_SPOL, - }, -/* { - .ctl_name = MIXER_SPK_PLAYBACK_SWITCH, - .intval = 1, - },*/ - { - .ctl_name = MIXER_SPK_PLAYBACK_VOLUME, - .intval = 33, - }, - { - .ctl_name = NULL, - }, -}; - -struct route_setting output_headphone[] = { - { - .ctl_name = MIXER_HPL_MUX_ENUM, - .intval = 1, - }, - { - .ctl_name = MIXER_HPR_MUX_ENUM, - .intval = 1, - }, -/* { - .ctl_name = MIXER_HP_PLAYBACK_SWITCH, - .intval = 1, - },*/ - { - .ctl_name = MIXER_HP_PLAYBACK_VOLUME, - .intval = 31, - }, - { - .ctl_name = NULL, - }, - { - .ctl_name = NULL, - }, -}; - -struct route_setting output_headset[] = { - { - .ctl_name = MIXER_R_HPVOL_MUX_ENUM, - .strval = MIXER_R_HPVOL_OUTMIX, - }, - { - .ctl_name = MIXER_L_HPVOL_MUX_ENUM, - .strval = MIXER_L_HPVOL_OUTMIX, - }, - { - .ctl_name = MIXER_OUT_DACR_PLAYBACK_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_OUT_DACL_PLAYBACK_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_HP_PLAYBACK_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_HP_PLAYBACK_VOLUME, - .intval = 31, - }, - { - .ctl_name = MIXER_JACK_FUNC_ENUM, - .strval = MIXER_JACK_HEADPHONE, - }, - { - .ctl_name = MIXER_SPEAKER_FUNC_ENUM, - .strval = MIXER_SPEAKER_OFF, - }, - { - .ctl_name = NULL, - }, - { - .ctl_name = NULL, - }, -}; - - -#endif //_RT5631_MIXER_CTRL_H_ - diff --git a/rt5631_mixer_paths.xml b/rt5631_mixer_paths.xml new file mode 100755 index 0000000..8d677c7 --- a/dev/null +++ b/rt5631_mixer_paths.xml @@ -0,0 +1,34 @@ +<mixer> + <ctl name="Speaker Playback Volume" value="33" /> + <ctl name="HP Playback Volume" value="31" /> + <ctl name="MIC1 Boost" value="4" /> + <ctl name="MIC2 Boost" value="0" /> + + <path name="speaker"> + <ctl name="SPKMIXR Mixer DACR Playback Switch" value="1" /> + <ctl name="SPKMIXL Mixer DACL Playback Switch" value="1" /> + <ctl name="Right SPKVOL Mux" value="SPKMIXR" /> + <ctl name="Left SPKVOL Mux" value="SPKMIXL" /> + <ctl name="SPOLMIX Mixer SPKVOLL Playback Switch" value="1" /> + <ctl name="SPORMIX Mixer SPKVOLR Playback Switch" value="1" /> + <ctl name="SPOR Mux" value="SPORMIX" /> + <ctl name="SPOL Mux" value="SPOLMIX" /> + <ctl name="HP Playback Volume" value="0" /> + </path> + + <path name="headphone"> + <ctl name="HPL Mux" value="1" /> + <ctl name="HPR Mux" value="1" /> + <ctl name="Speaker Playback Volume" value="0" /> + </path> + + <path name="main_mic"> + <ctl name="RECMIXL Mixer MIC1_BST1 Capture Switch" value="1" /> + <ctl name="MIC1 Boost" value="4" /> + </path> + + <path name="headset-mic"> + <ctl name="RECMIXR Mixer MIC2_BST1 Capture Switch" value="1" /> + <ctl name="MIC2 Boost" value="3" /> + </path> +</mixer> diff --git a/usb_audio_hw.c b/usb_audio_hw.c new file mode 100755 index 0000000..58ddbbe --- a/dev/null +++ b/usb_audio_hw.c @@ -0,0 +1,1119 @@ +/* + * 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. + */ + +#define LOG_TAG "usb_audio_hw" +//#define LOG_NDEBUG 0 + +#include <errno.h> +#include <pthread.h> +#include <stdint.h> +#include <sys/time.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <cutils/log.h> +#include <cutils/str_parms.h> +#include <cutils/properties.h> + +#include <hardware/hardware.h> +#include <system/audio.h> +#include <hardware/audio.h> + +#include <tinyalsa/asoundlib.h> +#include <audio_utils/resampler.h> + +#define DEFAULT_OUT_SAMPLING_RATE 44100 +#define RESAMPLER_BUFFER_SIZE 4096 +#define BUFFSIZE 100000 +struct pcm_config pcm_out_config = { + .channels = 2, + .rate = DEFAULT_OUT_SAMPLING_RATE, + .period_size = 1024, + .period_count = 4, + .format = PCM_FORMAT_S16_LE, +}; + +struct pcm_config pcm_in_config = { + .channels = 1, + .rate = DEFAULT_OUT_SAMPLING_RATE, + .period_size = 1024, + .period_count = 4, + .format = PCM_FORMAT_S16_LE, +}; + +struct audio_device { + struct audio_hw_device hw_device; + + pthread_mutex_t lock; /* see note below on mutex acquisition order */ + int card; + int device; + struct stream_in *active_input; + struct stream_out *active_output; + bool mic_mute; + bool standby; +}; + +struct stream_out { + struct audio_stream_out stream; + + pthread_mutex_t lock; /* see note below on mutex acquisition order */ + struct pcm_config out_config; + struct pcm *out_pcm; + struct resampler_itfe *resampler; + char *buffer; + bool standby; + + struct audio_device *dev; +}; + +struct stream_in { + struct audio_stream_in stream; + + pthread_mutex_t lock; /* see note below on mutex acquisition order */ + struct pcm_config in_config; + struct pcm *in_pcm; + struct resampler_itfe *resampler; + struct resampler_buffer_provider buf_provider; + int16_t *buffer; + size_t frames_in; + unsigned int requested_rate; + int standby; + int read_status; + + struct audio_device *dev; +}; + +int getnumOfRates(char *ratesStr){ + int i, size = 0; + char *nextSRString, *temp_ptr; + nextSRString = strtok_r(ratesStr, " ,", &temp_ptr); + if (nextSRString == NULL) { + ALOGE("ERROR: getnumOfRates: could not find rates string"); + return 0; + } + for (i = 1; nextSRString != NULL; i++) { + size ++; + nextSRString = strtok_r(NULL, " ,.-", &temp_ptr); + } + return size; +} + +static int get_usb_cap(char *type, uint *channels, uint *sampleRate, int card) +{ + ALOGV("getCap for %s",type); + long unsigned fileSize; + FILE *fp; + char path[32]; + char *buffer; + int err = 1; + int size = 0; + int needRsmp = 1; + int fd, i, lchannelsPlayback; + char *read_buf, *str_start, *channel_start, *ratesStr, *ratesStrForVal, + *ratesStrStart, *chString, *nextSRStr, *test, *nextSRString, *temp_ptr; + struct stat st; + memset(&st, 0x0, sizeof(struct stat)); + err = sprintf(path,"/proc/asound/card%d/stream0", card); + ALOGD("path = %s",path); + + fd = open(path, O_RDONLY); + if (fd <0) { + ALOGE("ERROR: failed to open config file %s error: %d\n", path, errno); + close(fd); + return -EINVAL; + } + + if (fstat(fd, &st) < 0) { + ALOGE("ERROR: failed to stat %s error %d\n", path, errno); + close(fd); + return -EINVAL; + } + + read_buf = (char *)malloc(BUFFSIZE); + memset(read_buf, 0x0, BUFFSIZE); + err = read(fd, read_buf, BUFFSIZE); + str_start = strstr(read_buf, type); + if (str_start == NULL) { + ALOGE("ERROR:%s section not found in usb config file", type); + close(fd); + free(read_buf); + return -EINVAL; + } + + channel_start = strstr(str_start, "Channels:"); + if (channel_start == NULL) { + ALOGE("ERROR: Could not find Channels information"); + close(fd); + free(read_buf); + return -EINVAL; + } + channel_start = strstr(channel_start, " "); + if (channel_start == NULL) { + ALOGE("ERROR: Channel section not found in usb config file"); + close(fd); + free(read_buf); + return -EINVAL; + } + + lchannelsPlayback = atoi(channel_start); + if (lchannelsPlayback == 1) { + *channels = 1; + } else { + *channels = 2; + } + ratesStrStart = strstr(str_start, "Rates:"); + if (ratesStrStart == NULL) { + ALOGE("ERROR: Cant find rates information"); + close(fd); + free(read_buf); + return -EINVAL; + } + + ratesStrStart = strstr(ratesStrStart, " "); + if (ratesStrStart == NULL) { + ALOGE("ERROR: Channel section not found in usb config file"); + close(fd); + free(read_buf); + return -EINVAL; + } + + //copy to ratesStr, current line. + char *target = strchr(ratesStrStart, '\n'); + if (target == NULL) { + ALOGE("ERROR: end of line not found"); + close(fd); + free(read_buf); + return -EINVAL; + } + size = target - ratesStrStart; + ratesStr = (char *)malloc(size + 1) ; + ratesStrForVal = (char *)malloc(size + 1) ; + memcpy(ratesStr, ratesStrStart, size); + memcpy(ratesStrForVal, ratesStrStart, size); + ratesStr[size] = '\0'; + ratesStrForVal[size] = '\0'; + + size = getnumOfRates(ratesStr); + if (!size) { + ALOGE("ERROR: Could not get rate size, returning"); + close(fd); + free(ratesStrForVal); + free(ratesStr); + free(read_buf); + return -EINVAL; + } + + //populate playback rates array + uint ratesSupported[size]; + nextSRString = strtok_r(ratesStrForVal, " ,", &temp_ptr); + if (nextSRString == NULL) { + ALOGE("ERROR: Could not get first rate val"); + close(fd); + free(ratesStrForVal); + free(ratesStr); + free(read_buf); + return -EINVAL; + } + + ratesSupported[0] = atoi(nextSRString); + ALOGV("ratesSupported[0] for %s:: %d", type, ratesSupported[0]); + for (i = 1; i<size; i++) { + nextSRString = strtok_r(NULL, " ,.-", &temp_ptr); + ratesSupported[i] = atoi(nextSRString); + ALOGV("ratesSupported[%d] for %s:: %d", i, type, ratesSupported[i]); + } + + for (i = 0; i<size; i++) { + if((*sampleRate == ratesSupported[i]) && (ratesSupported[i] <= 48000)) { + needRsmp = 0; + ALOGV("**sampleRate supports**"); + } + } + if(needRsmp){ + *sampleRate == ratesSupported[size-1]; + ALOGE("sampleRate do not support!! Using Need resampler!!"); + } + ALOGD("sampleRate: %d", *sampleRate); + + close(fd); + free(ratesStrForVal); + free(ratesStr); + free(read_buf); + ratesStrForVal = NULL; + ratesStr = NULL; + read_buf = NULL; + return 0; +} +/** + * NOTE: when multiple mutexes have to be acquired, always respect the + * following order: hw device > out stream + */ + +/* Helper functions */ + +/* must be called with hw device and output stream mutexes locked */ +static int start_output_stream(struct stream_out *out) +{ALOGD("%s", __func__); + struct audio_device *adev = out->dev; + int i, err; + if ((adev->card < 0) || (adev->device < 0)) { + return -EINVAL; + } + if(adev->device & AUDIO_DEVICE_OUT_USB_DEVICE){ + err = get_usb_cap("Playback:", &out->out_config.channels, &out->out_config.rate, adev->card); + if (err) { + ALOGE("ERROR: Could not get playback capabilities from usb device"); + return -EINVAL; + } + } + if (out->out_config.rate != pcm_out_config.rate){ + err = create_resampler(DEFAULT_OUT_SAMPLING_RATE, + out->out_config.rate, + 2, + RESAMPLER_QUALITY_DEFAULT, + NULL, + &out->resampler); + if (err != 0) + return -ENOMEM; + out->buffer = malloc(RESAMPLER_BUFFER_SIZE); /* todo: allow for reallocing */ + if (!out->buffer) + return -ENOMEM; + } + + out->out_pcm = pcm_open(adev->card, adev->device, PCM_OUT, &out->out_config); + + if (!pcm_is_ready(out->out_pcm)) { + ALOGE("pcm_open() failed: %s", pcm_get_error(out->out_pcm)); + pcm_close(out->out_pcm); + adev->active_output = NULL; + return -ENOMEM; + } + return 0; +} + +/* API functions */ +static uint32_t out_get_sample_rate(const struct audio_stream *stream) +{ + return pcm_out_config.rate; +} + +static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) +{ + return 0; +} + +static size_t out_get_buffer_size(const struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + /* take resampling into account and return the closest majoring + * multiple of 16 frames, as audioflinger expects audio buffers to + *be a multiple of 16 frames + */ + size_t size = (pcm_out_config.period_size * DEFAULT_OUT_SAMPLING_RATE) / out->out_config.rate; + size = ((size + 15) / 16) * 16; + return size * audio_stream_frame_size((struct audio_stream *)stream); +} + +static uint32_t out_get_channels(const struct audio_stream *stream) +{ + return AUDIO_CHANNEL_OUT_STEREO; +} + +static audio_format_t out_get_format(const struct audio_stream *stream) +{ + return AUDIO_FORMAT_PCM_16_BIT; +} + +static int out_set_format(struct audio_stream *stream, audio_format_t format) +{ + return 0; +} + +static int do_output_standby(struct stream_out *out) +{ + struct audio_device *adev = out->dev; + + if (!out->standby) { + pcm_close(out->out_pcm); + out->out_pcm = NULL; + + adev->active_output = 0; + out->standby = 1; + } + return 0; +} + + +static int out_standby(struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + int status; + + pthread_mutex_lock(&out->dev->lock); + pthread_mutex_lock(&out->lock); + ALOGD("******%s******", __func__); + status = do_output_standby(out); + pthread_mutex_unlock(&out->lock); + pthread_mutex_unlock(&out->dev->lock); + return status; +} + +static int out_dump(const struct audio_stream *stream, int fd) +{ + return 0; +} + +static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) +{ + struct stream_out *out = (struct stream_out *)stream; + struct audio_device *adev = out->dev; + struct str_parms *parms; + char value[32]; + + int ret; + int routing = 0; + ALOGD("******%s*****%s*", __func__, kvpairs); + + parms = str_parms_create_str(kvpairs); + pthread_mutex_lock(&adev->lock); + + ret = str_parms_get_str(parms, "card", value, sizeof(value)); + if (ret >= 0) + + adev->card = atoi(value); + + ret = str_parms_get_str(parms, "device", value, sizeof(value)); + if (ret >= 0) + + adev->device = atoi(value); + pthread_mutex_unlock(&adev->lock); + str_parms_destroy(parms); + + return 0; +} + +static char * out_get_parameters(const struct audio_stream *stream, const char *keys) +{ + return strdup(""); +} + +static uint32_t out_get_latency(const struct audio_stream_out *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + return (pcm_out_config.period_size * pcm_out_config.period_count * 1000) / + out->out_config.rate; +} + +static int out_set_volume(struct audio_stream_out *stream, float left, + float right) +{ + return -ENOSYS; +} + + +static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes) +{ + int ret; + struct stream_out *out = (struct stream_out *)stream; + struct audio_device *adev = out->dev; + size_t frame_size = audio_stream_frame_size(&out->stream.common); + size_t in_frames = bytes / frame_size; + size_t out_frames = RESAMPLER_BUFFER_SIZE / frame_size; + bool force_input_standby = false; + struct stream_in *in; + int kernel_frames; + void *buf; + + pthread_mutex_lock(&out->dev->lock); + pthread_mutex_lock(&out->lock); + if (out->standby) { + ret = start_output_stream(out); + if (ret != 0) { + pthread_mutex_unlock(&adev->lock); + goto err; + } + out->standby = false; + } + /* only use resampler if required */ + if (out->out_config.rate != DEFAULT_OUT_SAMPLING_RATE) { + out->resampler->resample_from_input(out->resampler, + (int16_t *)buffer, + &in_frames, + (int16_t *)out->buffer, + &out_frames); + buf = out->buffer; + } else { + out_frames = in_frames; + buf = (void *)buffer; + } + + pcm_write(out->out_pcm, (void *)buf, out_frames * frame_size); + + pthread_mutex_unlock(&out->lock); + pthread_mutex_unlock(&out->dev->lock); + + return bytes; + +err: + pthread_mutex_unlock(&out->lock); + + if (ret != 0) { + + usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) / + out_get_sample_rate(&stream->common)); + } + + return bytes; +} + +static int out_get_render_position(const struct audio_stream_out *stream, + uint32_t *dsp_frames) +{ + return -EINVAL; +} + +static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + return 0; +} + +static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + return 0; +} + +static int out_get_next_write_timestamp(const struct audio_stream_out *stream, + int64_t *timestamp) +{ + return -EINVAL; +} + +/** audio_stream_in implementation **/ +static uint32_t in_get_sample_rate(const struct audio_stream *stream) +{ + struct stream_in *in = (struct stream_in *)stream; + return in->requested_rate; +} + +static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) +{ + return 0; +} + +static size_t get_input_buffer_size(uint32_t sample_rate, int format, int channel_count) +{ + size_t size; + size_t device_rate; + + /* take resampling into account and return the closest majoring + multiple of 16 frames, as audioflinger expects audio buffers to + be a multiple of 16 frames */ + size = (pcm_in_config.period_size * sample_rate) / pcm_in_config.rate; + size = ((size + 15) / 16) * 16; + + return size * channel_count * sizeof(short); +} + +static size_t in_get_buffer_size(const struct audio_stream *stream) +{ + struct stream_in *in = (struct stream_in *)stream; + + return get_input_buffer_size(in->in_config.rate, + AUDIO_FORMAT_PCM_16_BIT, + in->in_config.channels); +} + +static uint32_t in_get_channels(const struct audio_stream *stream) +{ + struct stream_in *in = (struct stream_in *)stream; + + if (in->in_config.channels == 1) { + return AUDIO_CHANNEL_IN_MONO; + } else { + return AUDIO_CHANNEL_IN_STEREO; + } +} + +static audio_format_t in_get_format(const struct audio_stream *stream) +{ + return AUDIO_FORMAT_PCM_16_BIT; +} + +static int in_set_format(struct audio_stream *stream, audio_format_t format) +{ + return 0; +} + +/* must be called with hw device and input stream mutexes locked */ +static int do_input_standby(struct stream_in *in) +{ + struct audio_device *adev = in->dev; + ALOGD("******%s******", __func__); + + if (!in->standby) { + pcm_close(in->in_pcm); + in->in_pcm = NULL; + adev->active_input = 0; + in->standby = 1; + } + return 0; +} + +static int in_standby(struct audio_stream *stream) +{ + struct stream_in *in = (struct stream_in *)stream; + int status; + ALOGD("******%s******", __func__);// + + pthread_mutex_lock(&in->dev->lock); + pthread_mutex_lock(&in->lock); + status = do_input_standby(in); + pthread_mutex_unlock(&in->lock); + pthread_mutex_unlock(&in->dev->lock); + return status; +} + +static int in_dump(const struct audio_stream *stream, int fd) +{ + return 0; +} + +static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) +{ + return 0; +} + +static char * in_get_parameters(const struct audio_stream *stream, + const char *keys) +{ + return strdup(""); +} + +static int in_set_gain(struct audio_stream_in *stream, float gain) +{ + return 0; +} + +#define USB_AUDIO_PCM "/proc/asound/usb_audio_info" + +static int get_usb_card(struct stream_in *in){ + int card = -1, err = 0; + int fd; + unsigned fileSize; + char *read_buf; + struct stat st; + struct audio_device *adev = in->dev; + fd = open(USB_AUDIO_PCM, O_RDONLY); + if (fd <0) { + ALOGE("ERROR: failed to open config file %s error: %d\n", USB_AUDIO_PCM, errno); + close(fd); + return -EINVAL; + } + + if (fstat(fd, &st) < 0) { + ALOGE("ERROR: failed to stat %s error %d\n", USB_AUDIO_PCM, errno); + close(fd); + return -EINVAL; + } + + fileSize = st.st_size; + read_buf = (char *)malloc(16); + err = read(fd, read_buf, 16); + card = atoi(read_buf); + + adev->card = card; + adev->device = 0; + close(fd); + return err; +} + +static int get_next_buffer(struct resampler_buffer_provider *buffer_provider, + struct resampler_buffer* buffer) +{ + struct stream_in *in; + + if (buffer_provider == NULL || buffer == NULL) + return -EINVAL; + + in = (struct stream_in *)((char *)buffer_provider - + offsetof(struct stream_in, buf_provider)); + + if (in->in_pcm == NULL) { + buffer->raw = NULL; + buffer->frame_count = 0; + in->read_status = -ENODEV; + return -ENODEV; + } + + if (in->frames_in == 0) { + in->read_status = pcm_read(in->in_pcm, + (void*)in->buffer, + in->in_config.period_size * + audio_stream_frame_size(&in->stream.common)); + if (in->read_status != 0) { + ALOGE("get_next_buffer() pcm_read error %d", in->read_status); + buffer->raw = NULL; + buffer->frame_count = 0; + return in->read_status; + } + in->frames_in = in->in_config.period_size; + } + + buffer->frame_count = (buffer->frame_count > in->frames_in) ? + in->frames_in : buffer->frame_count; + buffer->i16 = in->buffer + (in->in_config.period_size - in->frames_in) * + in->in_config.channels; + + return in->read_status; + +} + +static void release_buffer(struct resampler_buffer_provider *buffer_provider, + struct resampler_buffer* buffer) +{ + struct stream_in *in; + + if (buffer_provider == NULL || buffer == NULL) + return; + + in = (struct stream_in *)((char *)buffer_provider - + offsetof(struct stream_in, buf_provider)); + + in->frames_in -= buffer->frame_count; +} + +static int start_input_stream(struct stream_in *in) +{ + int err; + struct audio_device *adev = in->dev; + adev->active_input = in; + //get_usb_card(in); + + if ((adev->card < 0) || (adev->device < 0)) { + ALOGE("ERROR: Could not get usb card info"); + return -EINVAL; + } +#if 0 + err = get_usb_cap((char *)"Capture:", &in->in_config.channels, &in->in_config.rate, adev->card); + if (err) { + ALOGE("ERROR: Could not get capture capabilities from usb device"); + return -EINVAL; + } + if (in->requested_rate != in->in_config.rate) { + in->buf_provider.get_next_buffer = get_next_buffer; + in->buf_provider.release_buffer = release_buffer; + ALOGD("Create resampler for input stream"); + err = create_resampler(in->in_config.rate, + in->requested_rate, + in->in_config.channels, + RESAMPLER_QUALITY_DEFAULT, + &in->buf_provider, + &in->resampler); + if (err != 0) { + err = -EINVAL; + goto err; + } + } +#endif + //ALOGD("pcm_open in: card(%d), port(%d)", adev->card, adev->device); + in->in_pcm = pcm_open(adev->card, adev->device, PCM_IN, &in->in_config); + if (!pcm_is_ready(in->in_pcm)) { + ALOGE("cannot open pcm_in driver: %s", pcm_get_error(in->in_pcm)); + pcm_close(in->in_pcm); + adev->active_input = NULL; + return -ENOMEM; + } + ALOGD("pcm_open in: card(%d), port(%d)", adev->card, adev->device); + return 0; + +err: + if (in->resampler) + release_resampler(in->resampler); + return err; +} + +/* read_frames() reads frames from kernel driver, down samples to capture rate + * if necessary and output the number of frames requested to the buffer specified */ +static ssize_t read_frames(struct stream_in *in, void *buffer, ssize_t frames) +{ + ssize_t frames_wr = 0; + + while (frames_wr < frames) { + size_t frames_rd = frames - frames_wr; + if (in->resampler != NULL) { + in->resampler->resample_from_provider(in->resampler, + (int16_t *)((char *)buffer + + frames_wr * audio_stream_frame_size(&in->stream.common)), + &frames_rd); + } else { + struct resampler_buffer buf = { + { raw : NULL, }, + frame_count : frames_rd, + }; + get_next_buffer(&in->buf_provider, &buf); + if (buf.raw != NULL) { + memcpy((char *)buffer + + frames_wr * audio_stream_frame_size(&in->stream.common), + buf.raw, + buf.frame_count * audio_stream_frame_size(&in->stream.common)); + frames_rd = buf.frame_count; + } + release_buffer(&in->buf_provider, &buf); + } + /* in->read_status is updated by getNextBuffer() also called by + * in->resampler->resample_from_provider() */ + if (in->read_status != 0) + return in->read_status; + + frames_wr += frames_rd; + } + return frames_wr; +} + +static ssize_t in_read(struct audio_stream_in *stream, void* buffer, + size_t bytes) +{ + int ret = 0; + struct stream_in *in = (struct stream_in *)stream; + struct audio_device *adev = in->dev; + size_t frames_rq = bytes / audio_stream_frame_size(&stream->common); + + /* acquiring hw device mutex systematically is useful if a low priority thread is waiting + * on the input stream mutex - e.g. executing select_mode() while holding the hw device + * mutex + */ + pthread_mutex_lock(&adev->lock); + pthread_mutex_lock(&in->lock); + if (in->standby) { + ret = start_input_stream(in); + if (ret == 0) + in->standby = 0; + } + pthread_mutex_unlock(&adev->lock); + + if (ret < 0) + goto exit; + + if (in->resampler != NULL) + ret = read_frames(in, buffer, frames_rq); + else + ret = pcm_read(in->in_pcm, buffer, bytes); + if (ret > 0) + ret = 0; + + if (ret == 0 && adev->mic_mute){ + memset(buffer, 0, bytes); + } + +exit: + if (ret < 0) + usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) / + in_get_sample_rate(&stream->common)); + + pthread_mutex_unlock(&in->lock); + return bytes; +} + +static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) +{ + return 0; +} + +static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + return 0; +} + +static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + return 0; +} + +static int adev_open_output_stream(struct audio_hw_device *dev, + audio_io_handle_t handle, + audio_devices_t devices, + audio_output_flags_t flags, + struct audio_config *out_config, + struct audio_stream_out **stream_out) +{ + struct audio_device *adev = (struct audio_device *)dev; + struct stream_out *out; + int ret; + + out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); + if (!out) + return -ENOMEM; + + out->stream.common.get_sample_rate = out_get_sample_rate; + out->stream.common.set_sample_rate = out_set_sample_rate; + out->stream.common.get_buffer_size = out_get_buffer_size; + out->stream.common.get_channels = out_get_channels; + out->stream.common.get_format = out_get_format; + out->stream.common.set_format = out_set_format; + out->stream.common.standby = out_standby; + out->stream.common.dump = out_dump; + out->stream.common.set_parameters = out_set_parameters; + out->stream.common.get_parameters = out_get_parameters; + out->stream.common.add_audio_effect = out_add_audio_effect; + out->stream.common.remove_audio_effect = out_remove_audio_effect; + out->stream.get_latency = out_get_latency; + out->stream.set_volume = out_set_volume; + out->stream.write = out_write; + out->stream.get_render_position = out_get_render_position; + out->stream.get_next_write_timestamp = out_get_next_write_timestamp; + memcpy(&out->out_config, &pcm_out_config, sizeof(pcm_out_config)); + + out->dev = adev; + + out_config->format = out_get_format(&out->stream.common); + out_config->channel_mask = out_get_channels(&out->stream.common); + out_config->sample_rate = out_get_sample_rate(&out->stream.common); + + out->standby = true; + + adev->card = -1; + adev->device = -1; + + *stream_out = &out->stream; + return 0; + +err_open: + free(out); + *stream_out = NULL; + return ret; +} + +static void adev_close_output_stream(struct audio_hw_device *dev, + struct audio_stream_out *stream) +{ + struct stream_out *out = (struct stream_out *)stream; +ALOGD("******%s******", __func__);// + + out_standby(&stream->common); + free(stream); +} + +static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) +{ + return 0; +} + +static char * adev_get_parameters(const struct audio_hw_device *dev, + const char *keys) +{ + return strdup(""); +} + +static int adev_init_check(const struct audio_hw_device *dev) +{ + return 0; +} + +static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) +{ + return -ENOSYS; +} + +static int adev_set_master_volume(struct audio_hw_device *dev, float volume) +{ + return -ENOSYS; +} + +static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) +{ + return 0; +} + +static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) +{ + return -ENOSYS; +} + +static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) +{ + return -ENOSYS; +} + +static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, + const struct audio_config *config) +{ + return 0; +} + +static int adev_open_input_stream(struct audio_hw_device *dev, + audio_io_handle_t handle, + audio_devices_t devices, + struct audio_config *config, + struct audio_stream_in **stream_in) +{ + struct audio_device *adev = (struct audio_device *)dev; + struct stream_in *in; + int ret; + + in = (struct stream_in *)calloc(1, sizeof(struct stream_in)); + if (!in){ + ALOGE("%s nomem error!!!! ", __func__); + return -ENOMEM; + } + in->stream.common.get_sample_rate = in_get_sample_rate; + in->stream.common.set_sample_rate = in_set_sample_rate; + in->stream.common.get_buffer_size = in_get_buffer_size; + in->stream.common.get_channels = in_get_channels; + in->stream.common.get_format = in_get_format; + in->stream.common.set_format = in_set_format; + in->stream.common.standby = in_standby; + in->stream.common.dump = in_dump; + in->stream.common.set_parameters = in_set_parameters; + in->stream.common.get_parameters = in_get_parameters; + in->stream.common.add_audio_effect = in_add_audio_effect; + in->stream.common.remove_audio_effect = in_remove_audio_effect; + in->stream.read = in_read; + in->stream.get_input_frames_lost = in_get_input_frames_lost; + + in->requested_rate = config->sample_rate; + memcpy(&in->in_config, &pcm_in_config, sizeof(pcm_in_config)); + in->dev = adev; + in->in_config.rate = in->requested_rate; + ret = get_usb_card(in); + if (ret < 0){ + ALOGE("ERROR: Could not get usb card number"); + goto err_open; + } + ret = get_usb_cap("Capture:", &in->in_config.channels, &in->in_config.rate, adev->card); + if (ret) { + ALOGE("ERROR: Could not get capture capabilities from usb device"); + goto err_open; + } + if (in->requested_rate != in->in_config.rate) { + in->buffer = malloc(in->in_config.period_size * + audio_stream_frame_size(&in->stream.common)); + if (!in->buffer) { + ret = -ENOMEM; + goto err_open; + } + in->buf_provider.get_next_buffer = get_next_buffer; + in->buf_provider.release_buffer = release_buffer; + ALOGD("Create resampler for input stream"); + ret = create_resampler(in->in_config.rate, + in->requested_rate, + in->in_config.channels, + RESAMPLER_QUALITY_DEFAULT, + &in->buf_provider, + &in->resampler); + if (ret != 0) { + ret = -EINVAL; + goto err_open; + } + } + + config->format = in_get_format(&in->stream.common); + config->channel_mask = in_get_channels(&in->stream.common); + config->sample_rate = in_get_sample_rate(&in->stream.common); + + in->standby = true; + *stream_in = &in->stream; + return 0; + +err_open: + free(in); + *stream_in = NULL; + return ret; +} + +static void adev_close_input_stream(struct audio_hw_device *dev, + struct audio_stream_in *stream) +{ + struct stream_in *in = (struct stream_in *)stream; +ALOGD("******%s******", __func__);// + + in_standby(&stream->common); + free(stream); +} + +static int adev_dump(const audio_hw_device_t *device, int fd) +{ + return 0; +} + +static int adev_close(hw_device_t *device) +{ + struct audio_device *adev = (struct audio_device *)device; + + free(device); + return 0; +} + +static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev) +{ + return AUDIO_DEVICE_OUT_ALL_USB|AUDIO_DEVICE_IN_USB_DEVICE; +} + +static int adev_open(const hw_module_t* module, const char* name, + hw_device_t** device) +{ + struct audio_device *adev; + int ret; + + if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) + return -EINVAL; + + adev = calloc(1, sizeof(struct audio_device)); + if (!adev) + return -ENOMEM; + + adev->hw_device.common.tag = HARDWARE_DEVICE_TAG; + adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0; + adev->hw_device.common.module = (struct hw_module_t *) module; + adev->hw_device.common.close = adev_close; + + adev->hw_device.get_supported_devices = adev_get_supported_devices; + adev->hw_device.init_check = adev_init_check; + adev->hw_device.set_voice_volume = adev_set_voice_volume; + adev->hw_device.set_master_volume = adev_set_master_volume; + adev->hw_device.set_mode = adev_set_mode; + adev->hw_device.set_mic_mute = adev_set_mic_mute; + adev->hw_device.get_mic_mute = adev_get_mic_mute; + adev->hw_device.set_parameters = adev_set_parameters; + adev->hw_device.get_parameters = adev_get_parameters; + adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size; + adev->hw_device.open_output_stream = adev_open_output_stream; + adev->hw_device.close_output_stream = adev_close_output_stream; + adev->hw_device.open_input_stream = adev_open_input_stream; + adev->hw_device.close_input_stream = adev_close_input_stream; + adev->hw_device.dump = adev_dump; + + *device = &adev->hw_device.common; + + return 0; +} + +static struct hw_module_methods_t hal_module_methods = { + .open = adev_open, +}; + +struct audio_module HAL_MODULE_INFO_SYM = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .module_api_version = AUDIO_MODULE_API_VERSION_0_1, + .hal_api_version = HARDWARE_HAL_API_VERSION, + .id = AUDIO_HARDWARE_MODULE_ID, + .name = "USB audio HW HAL", + .author = "The Android Open Source Project", + .methods = &hal_module_methods, + }, +}; diff --git a/wm8960_mixer_ctrl.h b/wm8960_mixer_ctrl.h deleted file mode 100755 index 829af63..0000000 --- a/wm8960_mixer_ctrl.h +++ b/dev/null @@ -1,237 +0,0 @@ -/* - * wm8960_mixer_ctrl.h -- Wm8960 Mixer control for Android ICS - * - * Copyright 2012 Amlogic Corp. - * - */ - -#ifndef _WM8960_MIXER_CTRL_H_ -#define _WM8960_MIXER_CTRL_H_ - -struct route_setting -{ - char *ctl_name; - int intval; - char *strval; -}; - - - -#define MIXER_LEFT_BOOST_MIXER_LINPUT1_SWITCH "Left Boost Mixer LINPUT1 Switch" -#define MIXER_LEFT_INPUT_MIXER_BOOST_SWITCH "Left Input Mixer Boost Switch" -#define MIXER_LEFT_BOOST_MIXER_LINPUT3_SWITCH "Left Boost Mixer LINPUT3 Switch" -#define MIXER_LEFT_BOOST_MIXER_LINPUT2_SWITCH "Left Boost Mixer LINPUT2 Switch" -#define MIXER_CAPTURE_SWITCH "Capture Switch" -#define MIXER_CAPTURE_VOLUME "Capture Volume" -#define MIXER_ADC_HIGH_PASS_FILTER_SWITCH "ADC High Pass Filter Switch" -#define MIXER_CAPTURE_VOLUME_ZC_SWITCH "Capture Volume ZC Switch" -#define MIXER_ADC_OUTPUT_SELECT "ADC Output Select" -#define MIXER_ADC_PCM_CAPTURE_VOLUME "ADC PCM Capture Volume" -#define MIXER_LEFT_OUTPUT_MIXER_PCM_PLAYBACK_SWITCH "Left Output Mixer PCM Playback Switch" -#define MIXER_RIGHT_OUTPUT_MIXER_PCM_PLAYBACK_SWITCH "Right Output Mixer PCM Playback Switch" -#define MIXER_HEADPHONE_PLAYBACK_VOLUME "Headphone Playback Volume" -#define MIXER_SPEAKER_PLAYBACK_VOLUME "Speaker Playback Volume" -#define MIXER_SPEAK_DC_VOLUME "Speaker DC Volume" -#define MIXER_SPEAKER_AC_VOLUME "Speaker AC Volume" -#define MIXER_DAC_MONO_MIX "DAC Mono Mix" -#define MIXER_MONO_OUTPUT_MIXER_LEFT_SWITCH "Mono Output Mixer Left Switch" -#define MIXER_MONO_OUTPUT_MIXER_RIGHT_SWITCH "Mono Output Mixer Right Switch" - - -struct route_setting mic_input[] = { - { - .ctl_name = MIXER_LEFT_BOOST_MIXER_LINPUT1_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_LEFT_INPUT_MIXER_BOOST_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_LEFT_BOOST_MIXER_LINPUT3_SWITCH, - .intval = 0, - }, - { - .ctl_name = MIXER_LEFT_BOOST_MIXER_LINPUT2_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_CAPTURE_SWITCH, - .intval = 0, - }, - { - .ctl_name = MIXER_CAPTURE_VOLUME, - .intval = 40, - }, - { - .ctl_name = MIXER_ADC_HIGH_PASS_FILTER_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_CAPTURE_VOLUME_ZC_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_ADC_OUTPUT_SELECT, - .intval = 1, - }, - { - .ctl_name = MIXER_ADC_PCM_CAPTURE_VOLUME, - .intval = 2, - }, - { - .ctl_name = NULL, - }, -}; - -struct route_setting headset_input[] = { - { - .ctl_name = "Right Boost Mixer RINPUT1 Switch", - .intval = 1 - }, - { - .ctl_name = "Right Input Mixer Boost Switch", - .intval = 1 - }, - { - .ctl_name = "Right Boost Mixer RINPUT3 Switch", - .intval = 0 - }, - { - .ctl_name = "Right Boost Mixer RINPUT2 Switch", - .intval = 1 - }, - { - .ctl_name = "Capture Switch", - .intval = 0 - }, - { - .ctl_name = "Capture Volume", - .intval = 30 - }, - { - .ctl_name = "ADC Output Select", - .intval = 2 - }, - { - .ctl_name = "ADC PCM Capture Volume", - .intval = 2 - }, - { - .ctl_name = NULL, - }, -}; - -struct route_setting line_input[] = { - { - .ctl_name = NULL, - }, -}; - -struct route_setting output_speaker[] = { - { - .ctl_name = MIXER_LEFT_OUTPUT_MIXER_PCM_PLAYBACK_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_RIGHT_OUTPUT_MIXER_PCM_PLAYBACK_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_SPEAKER_PLAYBACK_VOLUME, - .intval = 123, - }, - { - .ctl_name = MIXER_SPEAK_DC_VOLUME, - .intval = 2, - }, - { - .ctl_name = MIXER_SPEAKER_AC_VOLUME, - .intval = 3, - }, - { - .ctl_name = MIXER_DAC_MONO_MIX, - .intval = 1, - }, - { - .ctl_name = MIXER_HEADPHONE_PLAYBACK_VOLUME, - .intval = 0, - }, - { - .ctl_name = NULL, - }, -}; - -struct route_setting output_headphone[] = { - { - .ctl_name = MIXER_LEFT_OUTPUT_MIXER_PCM_PLAYBACK_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_RIGHT_OUTPUT_MIXER_PCM_PLAYBACK_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_SPEAKER_PLAYBACK_VOLUME, - .intval = 0, - }, - { - .ctl_name = MIXER_SPEAK_DC_VOLUME, - .intval = 0, - }, - { - .ctl_name = MIXER_SPEAKER_AC_VOLUME, - .intval = 0, - }, - { - .ctl_name = MIXER_DAC_MONO_MIX, - .intval = 0, - }, - { - .ctl_name = MIXER_HEADPHONE_PLAYBACK_VOLUME, - .intval = 118, - }, - { - .ctl_name = NULL, - }, - -}; - -struct route_setting output_headset[] = { - { - .ctl_name = MIXER_LEFT_OUTPUT_MIXER_PCM_PLAYBACK_SWITCH, - .intval = 1, - }, - { - .ctl_name = MIXER_RIGHT_OUTPUT_MIXER_PCM_PLAYBACK_SWITCH, - .intval = 1, - }, - - { - .ctl_name = MIXER_SPEAKER_PLAYBACK_VOLUME, - .intval = 0, - }, - { - .ctl_name = MIXER_DAC_MONO_MIX, - .intval = 0, - }, - { - .ctl_name = MIXER_MONO_OUTPUT_MIXER_LEFT_SWITCH, - .intval = 0, - }, - { - .ctl_name = MIXER_MONO_OUTPUT_MIXER_RIGHT_SWITCH, - .intval = 0, - }, - { - .ctl_name = MIXER_HEADPHONE_PLAYBACK_VOLUME, - .intval = 115, - }, - { - .ctl_name = NULL, - }, -}; - - -#endif //_WM8960_MIXER_CTRL_H_ - diff --git a/wm8960_mixer_paths.xml b/wm8960_mixer_paths.xml new file mode 100755 index 0000000..f929211 --- a/dev/null +++ b/wm8960_mixer_paths.xml @@ -0,0 +1,45 @@ +<mixer> + <path name="speaker"> + <ctl name="Left Output Mixer PCM Playback Switch" value="1" /> + <ctl name="Right Output Mixer PCM Playback Switch" value="1" /> + <ctl name="Speaker Playback Volume" value="123" /> + <ctl name="Speaker DC Volume" value="3" /> + <ctl name="Speaker AC Volume" value="3" /> + <ctl name="DAC Mono Mix" value="1" /> + <ctl name="Headphone Playback Volume" value="0" /> + </path> + + <path name="headphone"> + <ctl name="Left Output Mixer PCM Playback Switch" value="1" /> + <ctl name="Right Output Mixer PCM Playback Switch" value="1" /> + <ctl name="Speaker Playback Volume" value="0" /> + <ctl name="Speaker DC Volume" value="0" /> + <ctl name="Speaker AC Volume" value="0" /> + <ctl name="DAC Mono Mix" value="0" /> + <ctl name="Headphone Playback Volume" value="115" /> + </path> + + <path name="main_mic"> + <ctl name="Left Boost Mixer LINPUT1 Switch" value="1" /> + <ctl name="Left Input Mixer Boost Switch" value="1" /> + <ctl name="Left Boost Mixer LINPUT3 Switch" value="0" /> + <ctl name="Left Boost Mixer LINPUT2 Switch" value="1" /> + <ctl name="Capture Switch" value="0" /> + <ctl name="Capture Volume" value="40" /> + <ctl name="ADC High Pass Filter Switch" value="1" /> + <ctl name="Capture Volume ZC Switch" value="1" /> + <ctl name="ADC Output Select" value="1" /> + <ctl name="ADC PCM Capture Volume" value="1" /> + </path> + + <path name="headset-mic"> + <ctl name="Right Boost Mixer RINPUT1 Switch" value="1" /> + <ctl name="Right Input Mixer Boost Switch" value="1" /> + <ctl name="Right Boost Mixer RINPUT3 Switch" value="0" /> + <ctl name="Right Boost Mixer RINPUT2 Switch" value="1" /> + <ctl name="Capture Switch" value="0" /> + <ctl name="Capture Volume" value="30" /> + <ctl name="ADC Output Select" value="2" /> + <ctl name="ADC PCM Capture Volume" value="2" /> + </path> +</mixer> |