summaryrefslogtreecommitdiff
authorlei.qian <lei.qian>2013-04-25 08:57:59 (GMT)
committer Lawrence Mok <lawrence.mok@amlogic.com>2013-04-25 18:41:38 (GMT)
commit2f395805113cb149069b17de0c7cdc92a31aa176 (patch)
tree28c5076be8d487dd0c9d935cb28786d50423be38
parentc77f925577f3644cf7dfed2d9af72a2a36beaa83 (diff)
downloadaudio-2f395805113cb149069b17de0c7cdc92a31aa176.zip
audio-2f395805113cb149069b17de0c7cdc92a31aa176.tar.gz
audio-2f395805113cb149069b17de0c7cdc92a31aa176.tar.bz2
pd #69289: modified for USB audio.
Diffstat
-rwxr-xr-xAndroid.mk35
-rwxr-xr-xaudio_hw.c234
-rwxr-xr-x[-rw-r--r--]audio_policy.c0
-rwxr-xr-xaudio_route.c494
-rwxr-xr-xaudio_route.h33
-rw-r--r--m3codec_mixer_ctl.h43
-rwxr-xr-xrt3261_mixer_ctrl.h897
-rwxr-xr-xrt5631_mixer_ctrl.h203
-rwxr-xr-xrt5631_mixer_paths.xml34
-rwxr-xr-xusb_audio_hw.c1119
-rwxr-xr-xwm8960_mixer_ctrl.h237
-rwxr-xr-xwm8960_mixer_paths.xml45
12 files changed, 1777 insertions, 1597 deletions
diff --git a/Android.mk b/Android.mk
index 77e474b..3172b87 100755
--- a/Android.mk
+++ b/Android.mk
@@ -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)
diff --git a/audio_hw.c b/audio_hw.c
index c3a3fda..410cf66 100755
--- a/audio_hw.c
+++ b/audio_hw.c
@@ -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>