diff options
| author | safarend <s.a.f.a.r.end@live.com.au> | 2015-06-28 14:44:15 +1200 |
|---|---|---|
| committer | safarend <s.a.f.a.r.end@live.com.au> | 2015-06-28 14:44:15 +1200 |
| commit | c096c387fae84171f8804e5186ba0677e339410b (patch) | |
| tree | 472e0e70434fc9737e1f8e6d32dba7d6ba3fdef6 | |
| parent | 7701ed5341cc52e856f0176672c6cf707bec838e (diff) | |
| parent | 8dbcb4d7e161ffc50aadad0ea009ed7489370dc3 (diff) | |
Merge branch 'cm-12.0' of https://github.com/safarend/android_device_samsung_ha3g into HEAD
| -rw-r--r-- | BoardConfig.mk | 20 | ||||
| -rw-r--r-- | audio/Android.mk | 61 | ||||
| -rw-r--r-- | audio/audio_hw.c | 1748 | ||||
| -rw-r--r-- | audio/eS325VoiceProcessing.cpp | 1574 | ||||
| -rw-r--r-- | audio/eS325VoiceProcessing.h | 77 | ||||
| -rw-r--r-- | audio/mixer_paths.xml | 409 | ||||
| -rw-r--r-- | audio/ril_interface.c | 203 | ||||
| -rw-r--r-- | audio/ril_interface.h | 93 | ||||
| -rw-r--r-- | audio/routing.h | 249 | ||||
| -rw-r--r-- | camera/CameraWrapper.cpp | 66 | ||||
| -rw-r--r-- | device.mk | 18 | ||||
| -rw-r--r-- | include/hardware/gps.h | 11 | ||||
| -rw-r--r-- | include/telephony/ril.h | 3 | ||||
| -rw-r--r-- | overlay/frameworks/base/core/res/res/values/config.xml | 28 | ||||
| -rw-r--r-- | overlay/packages/apps/Phone/res/values/config.xml | 22 | ||||
| -rw-r--r-- | proprietary-files.txt | 2 |
16 files changed, 4509 insertions, 75 deletions
diff --git a/BoardConfig.mk b/BoardConfig.mk index 47e4baf..bf7e0a0 100644 --- a/BoardConfig.mk +++ b/BoardConfig.mk @@ -65,11 +65,11 @@ RED_LED_PATH := "/sys/devices/virtual/sec/led/led_r" GREEN_LED_PATH := "/sys/devices/virtual/led/led_g" BLUE_LED_PATH := "/sys/devices/virtual/led/led_b" BACKLIGHT_PATH := "/sys/class/backlight/panel/brightness" -CHARGING_ENABLED_PATH := "/sys/class/power_supply/battery/batt_lp_charging" # Kernel TARGET_KERNEL_SOURCE := kernel/samsung/ha3g TARGET_KERNEL_CONFIG := cm_ha3g_defconfig +# TARGET_KERNEL_CONFIG := SueMax_01_defconfig #TARGET_KERNEL_SELINUX_CONFIG := selinux_defconfig #BOARD_KERNEL_CMDLINE := console=null vmalloc=512M androidboot.console=null user_debug=31 BOARD_KERNEL_BASE := 0x10000000 @@ -77,8 +77,7 @@ BOARD_KERNEL_PAGESIZE := 2048 #BOARD_MKBOOTIMG_ARGS := --ramdisk_offset 0x02900000 --tags_offset 0x02700000 # Battery -BOARD_CHARGER_ENABLE_SUSPEND := true -CHARGING_ENABLED_PATH := "/sys/class/power_supply/battery/batt_lp_charging" +\ BOARD_BATTERY_DEVICE_NAME := battery # FIMG2D @@ -86,11 +85,11 @@ BOARD_USES_SKIA_FIMGAPI := true BOARD_USES_NEON_BLITANTIH := true # GSC -BOARD_USES_ONLY_GSC0_GSC1 := true +# BOARD_USES_ONLY_GSC0_GSC1 := true # HDMI -BOARD_USES_GSC_VIDEO := true -BOARD_USES_CEC := true +# BOARD_USES_GSC_VIDEO := true +# BOARD_USES_CEC := true # Graphics USE_OPENGL_RENDERER := true @@ -100,7 +99,7 @@ BOARD_EGL_CFG := $(LOCAL_PATH)/configs/egl.cfg NUM_FRAMEBUFFER_SURFACE_BUFFERS := 5 # 0 is by default # VSYNC_EVENT_PHASE_OFFSET_NS := 0 -OVERRIDE_RS_DRIVER := libRSDriverArm.so +#OVERRIDE_RS_DRIVER := libRSDriverArm.so # HWCServices BOARD_USES_HWC_SERVICES := true @@ -113,14 +112,15 @@ TARGET_SPECIFIC_HEADER_PATH := $(LOCAL_PATH)/include TARGET_NR_SVC_SUPP_GIDS := 20 # SurfaceFlinger -# BOARD_USES_SYNC_MODE_FOR_MEDIA := true +BOARD_USES_SYNC_MODE_FOR_MEDIA := true # NFC BOARD_HAVE_NFC := true BOARD_NFC_HAL_SUFFIX := universal5420 # Media -#COMMON_GLOBAL_CFLAGS += -DUSE_NATIVE_SEC_NV12TILED # use format from fw/native +COMMON_GLOBAL_CFLAGS += -DUSE_NATIVE_SEC_NV12TILED # use format from fw/native +COMMON_GLOBAL_CFLAGS += -DWIDEVINE_PLUGIN_PRE_NOTIFY_ERROR # OpenMAX Video BOARD_USE_STOREMETADATA := true @@ -138,7 +138,7 @@ BOARD_USE_ENCODER_RGBINPUT_SUPPORT := true BOARD_USE_DUALDPB_MODE := true # Samsung Gralloc -TARGET_SAMSUNG_GRALLOC_EXTERNAL_USECASES := true +# TARGET_SAMSUNG_GRALLOC_EXTERNAL_USECASES := true # Partitions BOARD_BOOTIMAGE_PARTITION_SIZE := 11534336 diff --git a/audio/Android.mk b/audio/Android.mk new file mode 100644 index 0000000..abd5908 --- /dev/null +++ b/audio/Android.mk @@ -0,0 +1,61 @@ +# Copyright (C) 2013 The CyanogenMod 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. + +LOCAL_PATH := $(call my-dir) + +# Audio HAL +include $(CLEAR_VARS) + +LOCAL_MODULE := audio.primary.$(TARGET_BOOTLOADER_BOARD_NAME) +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := audio_hw.c ril_interface.c + +LOCAL_C_INCLUDES += \ + external/tinyalsa/include \ + $(call include-path-for, audio-effects) \ + $(call include-path-for, audio-utils) \ + $(call include-path-for, audio-route) + +LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa libaudioutils libdl \ + libaudience_voicefx libaudioroute + +include $(BUILD_SHARED_LIBRARY) + + +# Audience voice preprocessing library +include $(CLEAR_VARS) + +LOCAL_MODULE := libaudience_voicefx +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := eS325VoiceProcessing.cpp + +LOCAL_C_INCLUDES += \ + $(call include-path-for, audio-effects) + +LOCAL_SHARED_LIBRARIES := liblog libutils + +include $(BUILD_SHARED_LIBRARY) + + +# Mixer configurations +include $(CLEAR_VARS) +LOCAL_MODULE := mixer_paths.xml +LOCAL_MODULE_TAGS := optional eng +LOCAL_MODULE_CLASS := ETC +LOCAL_SRC_FILES := mixer_paths.xml +LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) +include $(BUILD_PREBUILT) diff --git a/audio/audio_hw.c b/audio/audio_hw.c new file mode 100644 index 0000000..d180931 --- /dev/null +++ b/audio/audio_hw.c @@ -0,0 +1,1748 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2012 Wolfson Microelectronics plc + * Copyright (C) 2013 The CyanogenMod Project + * Daniel Hillenbrand <codeworkx@cyanogenmod.com> + * Guillaume "XpLoDWilD" Lesniak <xplodgui@gmail.com> + * + * 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 <pthread.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/time.h> +#include <dlfcn.h> + +#include <cutils/log.h> +#include <cutils/properties.h> +#include <cutils/str_parms.h> + +#include <hardware/audio.h> +#include <hardware/hardware.h> + +#include <system/audio.h> + +#include <tinyalsa/asoundlib.h> + +#include <audio_utils/resampler.h> +#include <audio_utils/echo_reference.h> +#include <audio_route/audio_route.h> + +#include "routing.h" + +#include "eS325VoiceProcessing.h" + +#include "ril_interface.h" + +#define PCM_CARD 0 +#define PCM_TOTAL 1 + +#define PCM_DEVICE 0 +#define PCM_DEVICE_VOICE 1 +#define PCM_DEVICE_SCO 2 +#define PCM_DEVICE_IN 3 + +#define MIXER_CARD 0 + +#define CAPTURE_START_RAMP_MS 8 + +#define MAX_SUPPORTED_CHANNEL_MASKS 1 + +#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a[0]))) + +struct pcm_config pcm_config_fast = { + .channels = 2, + .rate = 48000, + .period_size = 240, + .period_count = 2, + .format = PCM_FORMAT_S16_LE, +}; + +struct pcm_config pcm_config_deep = { + .channels = 2, + .rate = 48000, + .period_size = 3840, + .period_count = 2, + .format = PCM_FORMAT_S16_LE, +}; + +struct pcm_config pcm_config_in = { + .channels = 2, + .rate = 48000, + .period_size = 240, + .period_count = 2, + .format = PCM_FORMAT_S16_LE, +}; + +struct pcm_config pcm_config_sco = { + .channels = 1, + .rate = 8000, + .period_size = 128, + .period_count = 2, + .format = PCM_FORMAT_S16_LE, +}; + +struct pcm_config pcm_config_sco_wide = { + .channels = 1, + .rate = 16000, + .period_size = 128, + .period_count = 2, + .format = PCM_FORMAT_S16_LE, +}; + +struct pcm_config pcm_config_voice = { + .channels = 2, + .rate = 8000, + .period_size = 960, + .period_count = 2, + .format = PCM_FORMAT_S16_LE, +}; + +struct pcm_config pcm_config_voice_wide = { + .channels = 2, + .rate = 16000, + .period_size = 960, + .period_count = 2, + .format = PCM_FORMAT_S16_LE, +}; + +enum output_type { + OUTPUT_DEEP_BUF, + OUTPUT_LOW_LATENCY, + OUTPUT_TOTAL +}; + +struct audio_device { + struct audio_hw_device hw_device; + + pthread_mutex_t lock; /* see note below on mutex acquisition order */ + audio_devices_t out_device; + audio_devices_t in_device; + bool mic_mute; + struct audio_route *ar; + audio_source_t input_source; + int cur_route_id; /* current route ID: combination of input source + * and output device IDs */ + audio_mode_t mode; + + /* ES325 */ + int es325_preset; + int es325_new_mode; + int es325_mode; + + audio_channel_mask_t in_channel_mask; + + /* Call audio */ + struct pcm *pcm_voice_rx; + struct pcm *pcm_voice_tx; + + /* SCO audio */ + struct pcm *pcm_sco_rx; + struct pcm *pcm_sco_tx; + + float voice_volume; + bool in_call; + bool tty_mode; + bool bluetooth_nrec; + bool wb_amr; + + /* RIL */ + struct ril_handle ril; + + struct stream_out *outputs[OUTPUT_TOTAL]; +}; + +struct stream_out { + struct audio_stream_out stream; + + pthread_mutex_t lock; /* see note below on mutex acquisition order */ + struct pcm *pcm[PCM_TOTAL]; + struct pcm_config config; + unsigned int pcm_device; + bool standby; + audio_devices_t device; + + struct resampler_itfe *resampler; + struct echo_reference_itfe *echo_reference; + int16_t *buffer; + size_t buffer_frames; + + audio_channel_mask_t channel_mask; + /* Array of supported channel mask configurations. +1 so that the last entry is always 0 */ + audio_channel_mask_t supported_channel_masks[MAX_SUPPORTED_CHANNEL_MASKS + 1]; + + 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 *pcm; + bool standby; + + unsigned int requested_rate; + struct resampler_itfe *resampler; + struct resampler_buffer_provider buf_provider; + int16_t *buffer; + size_t frames_in; + int read_status; + + audio_source_t input_source; + audio_io_handle_t io_handle; + audio_devices_t device; + + uint16_t ramp_vol; + uint16_t ramp_step; + uint16_t ramp_frames; + + audio_channel_mask_t channel_mask; + + struct audio_device *dev; +}; + +#define STRING_TO_ENUM(string) { #string, string } + +struct string_to_enum { + const char *name; + uint32_t value; +}; + +const struct string_to_enum out_channels_name_to_enum_table[] = { + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1), +}; + +/* Routing functions */ + +static int get_output_device_id(audio_devices_t device) +{ + if (device == AUDIO_DEVICE_NONE) + return OUT_DEVICE_NONE; + + if (popcount(device) == 2) { + if ((device == (AUDIO_DEVICE_OUT_SPEAKER | + AUDIO_DEVICE_OUT_WIRED_HEADSET)) || + (device == (AUDIO_DEVICE_OUT_SPEAKER | + AUDIO_DEVICE_OUT_WIRED_HEADPHONE))) + return OUT_DEVICE_SPEAKER_AND_HEADSET; + else if (device == (AUDIO_DEVICE_OUT_SPEAKER | + AUDIO_DEVICE_OUT_EARPIECE)) + return OUT_DEVICE_SPEAKER_AND_EARPIECE; + else + return OUT_DEVICE_NONE; + } + + if (popcount(device) != 1) + return OUT_DEVICE_NONE; + + switch (device) { + case AUDIO_DEVICE_OUT_SPEAKER: + return OUT_DEVICE_SPEAKER; + case AUDIO_DEVICE_OUT_EARPIECE: + return OUT_DEVICE_EARPIECE; + case AUDIO_DEVICE_OUT_WIRED_HEADSET: + return OUT_DEVICE_HEADSET; + case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: + return OUT_DEVICE_HEADPHONES; + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO: + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET: + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT: + return OUT_DEVICE_BT_SCO; + default: + return OUT_DEVICE_NONE; + } +} + +static int get_input_source_id(audio_source_t source) +{ + switch (source) { + case AUDIO_SOURCE_DEFAULT: + return IN_SOURCE_NONE; + case AUDIO_SOURCE_MIC: + return IN_SOURCE_MIC; + case AUDIO_SOURCE_CAMCORDER: + return IN_SOURCE_CAMCORDER; + case AUDIO_SOURCE_VOICE_RECOGNITION: + return IN_SOURCE_VOICE_RECOGNITION; + case AUDIO_SOURCE_VOICE_COMMUNICATION: + return IN_SOURCE_VOICE_COMMUNICATION; + case AUDIO_SOURCE_VOICE_CALL: + return IN_SOURCE_VOICE_CALL; + default: + return IN_SOURCE_NONE; + } +} + +static void adev_set_call_audio_path(struct audio_device *adev); + +/* + * NOTE: when multiple mutexes have to be acquired, always take the + * audio_device mutex first, followed by the stream_in and/or + * stream_out mutexes. + */ + +static void select_devices(struct audio_device *adev) +{ + int output_device_id = get_output_device_id(adev->out_device); + int input_source_id = get_input_source_id(adev->input_source); + const char *output_route = NULL; + const char *input_route = NULL; + int new_route_id; + int new_es325_preset = -1; + + audio_route_reset(adev->ar); + + new_route_id = (1 << (input_source_id + OUT_DEVICE_CNT)) + (1 << output_device_id); + if ((new_route_id == adev->cur_route_id) && (adev->es325_mode == adev->es325_new_mode)) + return; + adev->cur_route_id = new_route_id; + adev->es325_mode = adev->es325_new_mode; + + if (input_source_id != IN_SOURCE_NONE) { + if (output_device_id != OUT_DEVICE_NONE) { + input_route = + route_configs[input_source_id][output_device_id]->input_route; + output_route = + route_configs[input_source_id][output_device_id]->output_route; + new_es325_preset = + route_configs[input_source_id][output_device_id]->es325_preset[adev->es325_mode]; + } else { + switch(adev->in_device) { + case AUDIO_DEVICE_IN_WIRED_HEADSET & ~AUDIO_DEVICE_BIT_IN: + output_device_id = OUT_DEVICE_HEADSET; + break; + case AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET & ~AUDIO_DEVICE_BIT_IN: + output_device_id = OUT_DEVICE_BT_SCO; + break; + default: + output_device_id = OUT_DEVICE_SPEAKER; + break; + } + input_route = + route_configs[input_source_id][output_device_id]->input_route; + new_es325_preset = + route_configs[input_source_id][output_device_id]->es325_preset[adev->es325_mode]; + } + } else { + if (output_device_id != OUT_DEVICE_NONE) { + output_route = + route_configs[IN_SOURCE_MIC][output_device_id]->output_route; + } + } + ALOGV("select_devices() devices %#x input src %d output route %s input route %s", + adev->out_device, adev->input_source, + output_route ? output_route : "none", + input_route ? input_route : "none"); + + if (output_route) + audio_route_apply_path(adev->ar, output_route); + if (input_route) + audio_route_apply_path(adev->ar, input_route); + + if ((new_es325_preset != ES325_PRESET_CURRENT) && + (new_es325_preset != adev->es325_preset)) { + ALOGV(" select_devices() changing es325 preset from %d to %d", + adev->es325_preset, new_es325_preset); + + if (eS325_UsePreset(new_es325_preset) == 0) { + adev->es325_preset = new_es325_preset; + } + + } + + audio_route_update_mixer(adev->ar); + + adev_set_call_audio_path(adev); +} + +/* BT SCO functions */ + +/* must be called with hw device mutex locked, OK to hold other mutexes */ +static void start_bt_sco(struct audio_device *adev) +{ + struct pcm_config *sco_config; + + if (adev->pcm_sco_rx || adev->pcm_sco_tx) { + ALOGW("%s: SCO PCMs already open!\n", __func__); + return; + } + + ALOGV("%s: Opening SCO PCMs", __func__); + + if (adev->wb_amr) + sco_config = &pcm_config_sco_wide; + else + sco_config = &pcm_config_sco; + + adev->pcm_sco_rx = pcm_open(PCM_CARD, PCM_DEVICE_SCO, PCM_OUT, + sco_config); + if (adev->pcm_sco_rx && !pcm_is_ready(adev->pcm_sco_rx)) { + ALOGE("%s: cannot open PCM SCO RX stream: %s", + __func__, pcm_get_error(adev->pcm_sco_rx)); + goto err_sco_rx; + } + + adev->pcm_sco_tx = pcm_open(PCM_CARD, PCM_DEVICE_SCO, PCM_IN, + sco_config); + if (adev->pcm_sco_tx && !pcm_is_ready(adev->pcm_sco_tx)) { + ALOGE("%s: cannot open PCM SCO TX stream: %s", + __func__, pcm_get_error(adev->pcm_sco_tx)); + goto err_sco_tx; + } + + pcm_start(adev->pcm_sco_rx); + pcm_start(adev->pcm_sco_tx); + + return; + +err_sco_tx: + pcm_close(adev->pcm_sco_tx); +err_sco_rx: + pcm_close(adev->pcm_sco_rx); +} + +/* must be called with hw device mutex locked, OK to hold other mutexes */ +static void end_bt_sco(struct audio_device *adev) +{ + ALOGV("%s: Closing SCO PCMs", __func__); + + if (adev->pcm_sco_rx) { + pcm_stop(adev->pcm_sco_rx); + pcm_close(adev->pcm_sco_rx); + adev->pcm_sco_rx = NULL; + } + + if (adev->pcm_sco_tx) { + pcm_stop(adev->pcm_sco_tx); + pcm_close(adev->pcm_sco_tx); + adev->pcm_sco_tx = NULL; + } +} + +/* Samsung RIL functions */ + +/* must be called with hw device mutex locked, OK to hold other mutexes */ +static int start_voice_call(struct audio_device *adev) +{ + struct pcm_config *voice_config; + + if (adev->pcm_voice_rx || adev->pcm_voice_tx) { + ALOGW("%s: Voice PCMs already open!\n", __func__); + return 0; + } + + ALOGV("%s: Opening voice PCMs", __func__); + + if (adev->wb_amr) + voice_config = &pcm_config_voice_wide; + else + voice_config = &pcm_config_voice; + + /* Open modem PCM channels */ + adev->pcm_voice_rx = pcm_open(PCM_CARD, PCM_DEVICE_VOICE, PCM_OUT, + voice_config); + if (adev->pcm_voice_rx && !pcm_is_ready(adev->pcm_voice_rx)) { + ALOGE("%s: cannot open PCM voice RX stream: %s", + __func__, pcm_get_error(adev->pcm_voice_rx)); + goto err_voice_rx; + } + + adev->pcm_voice_tx = pcm_open(PCM_CARD, PCM_DEVICE_VOICE, PCM_IN, + voice_config); + if (adev->pcm_voice_tx && !pcm_is_ready(adev->pcm_voice_tx)) { + ALOGE("%s: cannot open PCM voice TX stream: %s", + __func__, pcm_get_error(adev->pcm_voice_tx)); + goto err_voice_tx; + } + + pcm_start(adev->pcm_voice_rx); + pcm_start(adev->pcm_voice_tx); + + return 0; + +err_voice_tx: + pcm_close(adev->pcm_voice_tx); + adev->pcm_voice_tx = NULL; +err_voice_rx: + pcm_close(adev->pcm_voice_rx); + adev->pcm_voice_rx = NULL; + + return -ENOMEM; +} + +/* must be called with hw device mutex locked, OK to hold other mutexes */ +static void end_voice_call(struct audio_device *adev) +{ + ALOGV("%s: Closing voice PCMs", __func__); + + if (adev->pcm_voice_rx) { + pcm_stop(adev->pcm_voice_rx); + pcm_close(adev->pcm_voice_rx); + adev->pcm_voice_rx = NULL; + } + + if (adev->pcm_voice_tx) { + pcm_stop(adev->pcm_voice_tx); + pcm_close(adev->pcm_voice_tx); + adev->pcm_voice_tx = NULL; + } +} + +static void adev_set_wb_amr_callback(void *data, int enable) +{ + struct audio_device *adev = (struct audio_device *)data; + + ALOGV("%s: setting to: %d", __func__, enable); + + pthread_mutex_lock(&adev->lock); + if (adev->wb_amr != enable) { + adev->wb_amr = enable; + + /* reopen the modem PCMs at the new rate */ + if (adev->in_call) { +#if 0 + /* TODO: set rate properly */ + end_voice_call(adev); + select_devices(adev); + start_voice_call(adev); +#endif + } + } + pthread_mutex_unlock(&adev->lock); +} + +static void adev_set_call_audio_path(struct audio_device *adev) +{ + enum ril_audio_path device_type; + + switch(adev->out_device) { + case AUDIO_DEVICE_OUT_SPEAKER: + device_type = SOUND_AUDIO_PATH_SPEAKER; + break; + case AUDIO_DEVICE_OUT_EARPIECE: + device_type = SOUND_AUDIO_PATH_HANDSET; + break; + case AUDIO_DEVICE_OUT_WIRED_HEADSET: + device_type = SOUND_AUDIO_PATH_HEADSET; + break; + case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: + device_type = SOUND_AUDIO_PATH_HEADPHONE; + break; + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO: + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET: + case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT: + if (adev->bluetooth_nrec) { + device_type = SOUND_AUDIO_PATH_BLUETOOTH; + } else { + device_type = SOUND_AUDIO_PATH_BLUETOOTH_NO_NR; + } + break; + default: + /* if output device isn't supported, use handset by default */ + device_type = SOUND_AUDIO_PATH_HANDSET; + break; + } + + ALOGV("%s: ril_set_call_audio_path(%d)", __func__, device_type); + ril_set_call_audio_path(&adev->ril, device_type); +} + +/* Helper functions */ + +static int start_output_stream(struct stream_out *out) +{ + struct audio_device *adev = out->dev; + + ALOGV("%s: starting stream", __func__); + + out->pcm[PCM_CARD] = pcm_open(PCM_CARD, out->pcm_device, + PCM_OUT, &out->config); + if (out->pcm[PCM_CARD] && !pcm_is_ready(out->pcm[PCM_CARD])) { + ALOGE("pcm_open(PCM_CARD) failed: %s", + pcm_get_error(out->pcm[PCM_CARD])); + pcm_close(out->pcm[PCM_CARD]); + return -ENOMEM; + } + + /* in call routing must go through set_parameters */ + if (!adev->in_call) { + adev->out_device |= out->device; + select_devices(adev); + } + + if (out->device & AUDIO_DEVICE_OUT_ALL_SCO) + start_bt_sco(adev); + + ALOGV("%s: stream out device: %d, actual: %d", + __func__, out->device, adev->out_device); + + return 0; +} + +/* must be called with hw device and input stream mutexes locked */ +static int start_input_stream(struct stream_in *in) +{ + struct audio_device *adev = in->dev; + + in->pcm = pcm_open(PCM_CARD, PCM_DEVICE_IN, PCM_IN, &pcm_config_in); + + if (in->pcm && !pcm_is_ready(in->pcm)) { + ALOGE("pcm_open() failed: %s", pcm_get_error(in->pcm)); + pcm_close(in->pcm); + return -ENOMEM; + } + + /* if no supported sample rate is available, use the resampler */ + if (in->resampler) + in->resampler->reset(in->resampler); + + in->frames_in = 0; + /* in call routing must go through set_parameters */ + if (!adev->in_call) { + adev->input_source = in->input_source; + adev->in_device = in->device; + adev->in_channel_mask = in->channel_mask; + + eS325_SetActiveIoHandle(in->io_handle); + select_devices(adev); + } + + if (in->device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) + start_bt_sco(adev); + + /* initialize volume ramp */ + in->ramp_frames = (CAPTURE_START_RAMP_MS * in->requested_rate) / 1000; + in->ramp_step = (uint16_t)(USHRT_MAX / in->ramp_frames); + in->ramp_vol = 0; + + return 0; +} + +static size_t get_input_buffer_size(unsigned int sample_rate, + audio_format_t format, + unsigned int channel_count) +{ + size_t size; + + /* + * 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_config_in.period_size * sample_rate) / pcm_config_in.rate; + size = ((size + 15) / 16) * 16; + + return size * channel_count * audio_bytes_per_sample(format); +} + +static int get_next_buffer(struct resampler_buffer_provider *buffer_provider, + struct resampler_buffer* buffer) +{ + struct stream_in *in; + size_t i; + + if (buffer_provider == NULL || buffer == NULL) + return -EINVAL; + + in = (struct stream_in *)((char *)buffer_provider - + offsetof(struct stream_in, buf_provider)); + + if (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->pcm, + (void*)in->buffer, + pcm_frames_to_bytes(in->pcm, pcm_config_in.period_size)); + 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 = pcm_config_in.period_size; + + /* Do stereo to mono conversion in place by discarding right channel */ + if (in->channel_mask == AUDIO_CHANNEL_IN_MONO) + for (i = 1; i < in->frames_in; i++) + in->buffer[i] = in->buffer[i * 2]; + } + + buffer->frame_count = (buffer->frame_count > in->frames_in) ? + in->frames_in : buffer->frame_count; + buffer->i16 = in->buffer + + (pcm_config_in.period_size - in->frames_in) * popcount(in->channel_mask); + + 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; +} + +/* 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; + size_t frame_size = audio_stream_frame_size(&in->stream.common); + + 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 * frame_size), + &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 * frame_size, + buf.raw, + buf.frame_count * frame_size); + 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; +} + +/* API functions */ + +static uint32_t out_get_sample_rate(const struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + return out->config.rate; +} + +static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) +{ + return -ENOSYS; +} + +static size_t out_get_buffer_size(const struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + return out->config.period_size * + audio_stream_frame_size((struct audio_stream *)stream); +} + +static audio_channel_mask_t out_get_channels(const struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + return out->channel_mask; +} + +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 -ENOSYS; +} + +/* Return the set of output devices associated with active streams + * other than out. Assumes out is non-NULL and out->dev is locked. + */ +static audio_devices_t output_devices(struct stream_out *out) +{ + struct audio_device *dev = out->dev; + enum output_type type; + audio_devices_t devices = AUDIO_DEVICE_NONE; + + for (type = 0; type < OUTPUT_TOTAL; ++type) { + struct stream_out *other = dev->outputs[type]; + if (other && (other != out) && !other->standby) { + /* safe to access other stream without a mutex, + * because we hold the dev lock, + * which prevents the other stream from being closed + */ + devices |= other->device; + } + } + + return devices; +} + +static int do_out_standby(struct stream_out *out) +{ + struct audio_device *adev = out->dev; + int i; + + ALOGV("%s: output standby: %d", __func__, out->standby); + + if (!out->standby) { + for (i = 0; i < PCM_TOTAL; i++) { + if (out->pcm[i]) { + pcm_close(out->pcm[i]); + out->pcm[i] = NULL; + } + } + out->standby = true; + +#if 0 + if (out == adev->outputs[OUTPUT_HDMI]) { + /* force standby on low latency output stream so that it can reuse HDMI driver if + * necessary when restarted */ + force_non_hdmi_out_standby(adev); + } +#endif + + if (out->device & AUDIO_DEVICE_OUT_ALL_SCO) + end_bt_sco(adev); + + /* re-calculate the set of active devices from other streams */ + adev->out_device = output_devices(out); + + /* Skip resetting the mixer if no output device is active */ + if (adev->out_device) + select_devices(adev); + } + return 0; +} + +static int out_standby(struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + int ret; + + pthread_mutex_lock(&out->dev->lock); + pthread_mutex_lock(&out->lock); + + ret = do_out_standby(out); + + pthread_mutex_unlock(&out->lock); + pthread_mutex_unlock(&out->dev->lock); + return ret; +} + +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; + unsigned int val; + + ALOGV("%s: key value pairs: %s", __func__, kvpairs); + + parms = str_parms_create_str(kvpairs); + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, + value, sizeof(value)); + if (ret >= 0) { + val = atoi(value); + pthread_mutex_lock(&adev->lock); + pthread_mutex_lock(&out->lock); + if (((adev->out_device) != val) && (val != 0)) { + /* force output standby to stop SCO pcm stream if needed */ + if ((val & AUDIO_DEVICE_OUT_ALL_SCO) ^ + (out->device & AUDIO_DEVICE_OUT_ALL_SCO)) { + do_out_standby(out); + } + + out->device = val; + adev->out_device = val; + select_devices(adev); + + /* start SCO stream if needed */ + if (val & AUDIO_DEVICE_OUT_ALL_SCO) + start_bt_sco(adev); + } + pthread_mutex_unlock(&out->lock); + pthread_mutex_unlock(&adev->lock); + } + + str_parms_destroy(parms); + return ret; +} + +static char * out_get_parameters(const struct audio_stream *stream, const char *keys) +{ + struct stream_out *out = (struct stream_out *)stream; + struct str_parms *query = str_parms_create_str(keys); + char *str; + char value[256]; + struct str_parms *reply = str_parms_create(); + size_t i, j; + int ret; + bool first = true; + + ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value)); + if (ret >= 0) { + value[0] = '\0'; + i = 0; + /* the last entry in supported_channel_masks[] is always 0 */ + while (out->supported_channel_masks[i] != 0) { + for (j = 0; j < ARRAY_SIZE(out_channels_name_to_enum_table); j++) { + if (out_channels_name_to_enum_table[j].value == out->supported_channel_masks[i]) { + if (!first) { + strcat(value, "|"); + } + strcat(value, out_channels_name_to_enum_table[j].name); + first = false; + break; + } + } + i++; + } + str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value); + str = strdup(str_parms_to_str(reply)); + } else { + str = strdup(keys); + } + str_parms_destroy(query); + str_parms_destroy(reply); + return str; +} + +static uint32_t out_get_latency(const struct audio_stream_out *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + return (out->config.period_size * out->config.period_count * 1000) / + 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; + int i; + + /* + * acquiring hw device mutex systematically is useful if a low + * priority thread is waiting on the output stream mutex - e.g. + * executing out_set_parameters() while holding the hw device + * mutex + */ + pthread_mutex_lock(&adev->lock); + pthread_mutex_lock(&out->lock); + if (out->standby) { + ret = start_output_stream(out); + if (ret != 0) { + pthread_mutex_unlock(&adev->lock); + goto exit; + } + out->standby = false; + } + pthread_mutex_unlock(&adev->lock); + + /* Write to all active PCMs */ + for (i = 0; i < PCM_TOTAL; i++) + if (out->pcm[i]) + pcm_write(out->pcm[i], (void *)buffer, bytes); + + +exit: + 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 audio_channel_mask_t in_get_channels(const struct audio_stream *stream) +{ + struct stream_in *in = (struct stream_in *)stream; + + return in->channel_mask; +} + +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->requested_rate, + AUDIO_FORMAT_PCM_16_BIT, + popcount(in_get_channels(stream))); +} + +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 -ENOSYS; +} + +static int do_in_standby(struct stream_in *in) +{ + struct audio_device *adev = in->dev; + + if (!in->standby) { + pcm_close(in->pcm); + in->pcm = NULL; + + if (in->device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) + end_bt_sco(adev); + + in->dev->input_source = AUDIO_SOURCE_DEFAULT; + in->dev->in_device = AUDIO_DEVICE_NONE; + in->dev->in_channel_mask = 0; + select_devices(adev); + in->standby = true; + } + + eS325_SetActiveIoHandle(ES325_IO_HANDLE_NONE); + return 0; +} + +static int in_standby(struct audio_stream *stream) +{ + struct stream_in *in = (struct stream_in *)stream; + int ret; + + pthread_mutex_lock(&in->dev->lock); + pthread_mutex_lock(&in->lock); + + ret = do_in_standby(in); + + pthread_mutex_unlock(&in->lock); + pthread_mutex_unlock(&in->dev->lock); + + return ret; +} + +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) +{ + struct stream_in *in = (struct stream_in *)stream; + struct audio_device *adev = in->dev; + struct str_parms *parms; + char value[32]; + int ret; + unsigned int val; + bool apply_now = false; + + parms = str_parms_create_str(kvpairs); + + pthread_mutex_lock(&adev->lock); + pthread_mutex_lock(&in->lock); + ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, + value, sizeof(value)); + if (ret >= 0) { + val = atoi(value); + /* no audio source uses val == 0 */ + if ((in->input_source != val) && (val != 0)) { + in->input_source = val; + apply_now = !in->standby; + } + } + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, + value, sizeof(value)); + if (ret >= 0) { + /* strip AUDIO_DEVICE_BIT_IN to allow bitwise comparisons */ + val = atoi(value) & ~AUDIO_DEVICE_BIT_IN; + /* no audio device uses val == 0 */ + if ((in->device != val) && (val != 0)) { + /* force output standby to start or stop SCO pcm stream if needed */ + if ((val & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) ^ + (in->device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) { + do_in_standby(in); + } + in->device = val; + apply_now = !in->standby; + } + } + + if (apply_now) { + adev->input_source = in->input_source; + adev->in_device = in->device; + select_devices(adev); + } + + pthread_mutex_unlock(&in->lock); + pthread_mutex_unlock(&adev->lock); + + str_parms_destroy(parms); + return ret; +} + +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; +} + +static void in_apply_ramp(struct stream_in *in, int16_t *buffer, size_t frames) +{ + size_t i; + uint16_t vol = in->ramp_vol; + uint16_t step = in->ramp_step; + + frames = (frames < in->ramp_frames) ? frames : in->ramp_frames; + + if (in->channel_mask == AUDIO_CHANNEL_IN_MONO) { + for (i = 0; i < frames; i++) { + buffer[i] = (int16_t)((buffer[i] * vol) >> 16); + vol += step; + } + } else { + for (i = 0; i < frames; i++) { + buffer[2*i] = (int16_t)((buffer[2*i] * vol) >> 16); + buffer[2*i + 1] = (int16_t)((buffer[2*i + 1] * vol) >> 16); + vol += step; + } + } + + in->ramp_vol = vol; + in->ramp_frames -= frames; +} + +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 in_set_parameters() 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->num_preprocessors != 0) + ret = process_frames(in, buffer, frames_rq); + else */ + ret = read_frames(in, buffer, frames_rq); + + if (ret > 0) + ret = 0; + + if (in->ramp_frames > 0) + in_apply_ramp(in, buffer, frames_rq); + + /* + * Instead of writing zeroes here, we could trust the hardware + * to always provide zeroes when muted. + */ + 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) +{ + struct stream_in *in = (struct stream_in *)stream; + effect_descriptor_t descr; + if ((*effect)->get_descriptor(effect, &descr) == 0) { + + pthread_mutex_lock(&in->dev->lock); + pthread_mutex_lock(&in->lock); + + eS325_AddEffect(&descr, in->io_handle); + + pthread_mutex_unlock(&in->lock); + pthread_mutex_unlock(&in->dev->lock); + } + + return 0; +} + +static int in_remove_audio_effect(const struct audio_stream *stream, + effect_handle_t effect) +{ + struct stream_in *in = (struct stream_in *)stream; + effect_descriptor_t descr; + if ((*effect)->get_descriptor(effect, &descr) == 0) { + + pthread_mutex_lock(&in->dev->lock); + pthread_mutex_lock(&in->lock); + + eS325_RemoveEffect(&descr, in->io_handle); + + pthread_mutex_unlock(&in->lock); + pthread_mutex_unlock(&in->dev->lock); + } + + 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 *config, + struct audio_stream_out **stream_out) +{ + struct audio_device *adev = (struct audio_device *)dev; + struct stream_out *out; + int ret; + enum output_type type; + + out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); + if (!out) + return -ENOMEM; + + out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO; + out->channel_mask = AUDIO_CHANNEL_OUT_STEREO; + if (devices == AUDIO_DEVICE_NONE) + devices = AUDIO_DEVICE_OUT_SPEAKER; + out->device = devices; + + if (flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) { + out->config = pcm_config_deep; + out->pcm_device = PCM_DEVICE; + type = OUTPUT_DEEP_BUF; + } else { + out->config = pcm_config_fast; + out->pcm_device = PCM_DEVICE; + type = OUTPUT_LOW_LATENCY; + } + + 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; + + out->dev = adev; + + config->format = out_get_format(&out->stream.common); + config->channel_mask = out_get_channels(&out->stream.common); + config->sample_rate = out_get_sample_rate(&out->stream.common); + + out->standby = true; + + pthread_mutex_lock(&adev->lock); + if (adev->outputs[type]) { + pthread_mutex_unlock(&adev->lock); + ret = -EBUSY; + goto err_open; + } + adev->outputs[type] = out; + pthread_mutex_unlock(&adev->lock); + + *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 audio_device *adev; + enum output_type type; + + out_standby(&stream->common); + adev = (struct audio_device *)dev; + pthread_mutex_lock(&adev->lock); + for (type = 0; type < OUTPUT_TOTAL; type++) { + if (adev->outputs[type] == (struct stream_out *) stream) { + adev->outputs[type] = NULL; + break; + } + } + pthread_mutex_unlock(&adev->lock); + free(stream); +} + +static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) +{ + struct audio_device *adev = (struct audio_device *)dev; + struct str_parms *parms; + char *str; + char value[32]; + int ret; + + parms = str_parms_create_str(kvpairs); +#if 0 + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value)); + if (ret >= 0) { + int tty_mode; + + if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_OFF) == 0) + tty_mode = TTY_MODE_OFF; + else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_VCO) == 0) + tty_mode = TTY_MODE_VCO; + else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_HCO) == 0) + tty_mode = TTY_MODE_HCO; + else if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_FULL) == 0) + tty_mode = TTY_MODE_FULL; + else + return -EINVAL; + + pthread_mutex_lock(&adev->lock); + if (tty_mode != adev->tty_mode) { + adev->tty_mode = tty_mode; + if (adev->mode == AUDIO_MODE_IN_CALL) + select_output_device(adev); + } + pthread_mutex_unlock(&adev->lock); + } +#endif + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value)); + if (ret >= 0) { + if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0) + adev->bluetooth_nrec = true; + else + adev->bluetooth_nrec = false; + } + + ret = str_parms_get_str(parms, "noise_suppression", value, sizeof(value)); + if (ret >= 0) { + if (strcmp(value, "on") == 0) { + ALOGV("%s: enabling two mic control", __func__); + ril_set_two_mic_control(&adev->ril, AUDIENCE, TWO_MIC_SOLUTION_ON); + } else { + ALOGV("%s: disabling two mic control", __func__); + ril_set_two_mic_control(&adev->ril, AUDIENCE, TWO_MIC_SOLUTION_OFF); + } + } + + str_parms_destroy(parms); + return ret; +} + +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) +{ + struct audio_device *adev = (struct audio_device *)dev; + + adev->voice_volume = volume; + + if (adev->mode == AUDIO_MODE_IN_CALL) + ril_set_call_volume(&adev->ril, SOUND_TYPE_VOICE, volume); + + return 0; +} + +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) +{ + struct audio_device *adev = (struct audio_device *)dev; + + if (adev->mode == mode) + return 0; + + pthread_mutex_lock(&adev->lock); + adev->mode = mode; + + if (adev->mode == AUDIO_MODE_IN_CALL) { + ALOGV("%s: Entering IN_CALL mode", __func__); + if (!adev->in_call) { + if (adev->out_device == AUDIO_DEVICE_NONE || + adev->out_device == AUDIO_DEVICE_OUT_SPEAKER) { + adev->out_device = AUDIO_DEVICE_OUT_EARPIECE; + } + adev->input_source = AUDIO_SOURCE_VOICE_CALL; + select_devices(adev); + start_voice_call(adev); + ril_set_call_clock_sync(&adev->ril, SOUND_CLOCK_START); + adev_set_voice_volume(&adev->hw_device, adev->voice_volume); + adev->in_call = true; + } + } else { + ALOGV("%s: Leaving IN_CALL mode", __func__); + if (adev->in_call) { + adev->in_call = false; + end_voice_call(adev); + ril_set_call_clock_sync(&adev->ril, SOUND_CLOCK_STOP); + if (adev->out_device & AUDIO_DEVICE_OUT_ALL_SCO) + end_bt_sco(adev); + adev->input_source = AUDIO_SOURCE_DEFAULT; + select_devices(adev); + } + } + pthread_mutex_unlock(&adev->lock); + + return 0; +} + +static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) +{ + struct audio_device *adev = (struct audio_device *)dev; + enum ril_mute_state ril_state = state ? TX_MUTE : TX_UNMUTE; + + ALOGV("%s: set mic mute: %d\n", __func__, state); + + adev->mic_mute = state; + + if (adev->in_call) + ril_set_mute(&adev->ril, ril_state); + + return 0; +} + +static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) +{ + struct audio_device *adev = (struct audio_device *)dev; + + *state = adev->mic_mute; + + return 0; +} + +static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, + const struct audio_config *config) +{ + return get_input_buffer_size(config->sample_rate, config->format, + popcount(config->channel_mask)); +} + +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; + + *stream_in = NULL; + + /* Respond with a request for stereo if a different format is given. */ + if (config->channel_mask != AUDIO_CHANNEL_IN_STEREO) { + config->channel_mask = AUDIO_CHANNEL_IN_STEREO; + return -EINVAL; + } + + in = (struct stream_in *)calloc(1, sizeof(struct stream_in)); + if (!in) + 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.set_gain = in_set_gain; + in->stream.read = in_read; + in->stream.get_input_frames_lost = in_get_input_frames_lost; + + in->dev = adev; + in->standby = true; + in->requested_rate = config->sample_rate; + in->input_source = AUDIO_SOURCE_DEFAULT; + /* strip AUDIO_DEVICE_BIT_IN to allow bitwise comparisons */ + in->device = devices & ~AUDIO_DEVICE_BIT_IN; + in->io_handle = handle; + in->channel_mask = config->channel_mask; + + in->buffer = malloc(pcm_config_in.period_size * pcm_config_in.channels + * audio_stream_frame_size(&in->stream.common)); + if (!in->buffer) { + ret = -ENOMEM; + goto err_malloc; + } + + if (in->requested_rate != pcm_config_in.rate) { + in->buf_provider.get_next_buffer = get_next_buffer; + in->buf_provider.release_buffer = release_buffer; + + ret = create_resampler(pcm_config_in.rate, + in->requested_rate, + popcount(in->channel_mask), + RESAMPLER_QUALITY_DEFAULT, + &in->buf_provider, + &in->resampler); + if (ret != 0) { + ret = -EINVAL; + goto err_resampler; + } + + ALOGV("%s: Created resampler converting %d -> %d\n", + __func__, pcm_config_in.rate, in->requested_rate); + } + + ALOGV("%s: Requesting input stream with rate: %d, channels: 0x%x\n", + __func__, config->sample_rate, config->channel_mask); + + *stream_in = &in->stream; + return 0; + +err_resampler: + free(in->buffer); +err_malloc: + free(in); + 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; + + in_standby(&stream->common); + if (in->resampler) { + release_resampler(in->resampler); + in->resampler = NULL; + } + free(in->buffer); + 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; + + audio_route_free(adev->ar); + + eS325_Release(); + + /* RIL */ + ril_close(&adev->ril); + + free(device); + return 0; +} + +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.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; + adev->hw_device.set_master_mute = NULL; + adev->hw_device.get_master_mute = NULL; + + adev->ar = audio_route_init(MIXER_CARD, NULL); + adev->input_source = AUDIO_SOURCE_DEFAULT; + /* adev->cur_route_id initial value is 0 and such that first device + * selection is always applied by select_devices() */ + + adev->es325_preset = ES325_PRESET_INIT; + adev->es325_new_mode = ES325_MODE_LEVEL; + adev->es325_mode = ES325_MODE_LEVEL; + + adev->mode = AUDIO_MODE_NORMAL; + adev->voice_volume = 1.0f; + + /* RIL */ + ril_open(&adev->ril); + /* register callback for wideband AMR setting */ + ril_register_set_wb_amr_callback(adev_set_wb_amr_callback, (void *)adev); + + *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 = "JA audio HW HAL", + .author = "The CyanogenMod Project", + .methods = &hal_module_methods, + }, +}; diff --git a/audio/eS325VoiceProcessing.cpp b/audio/eS325VoiceProcessing.cpp new file mode 100644 index 0000000..6e93820 --- /dev/null +++ b/audio/eS325VoiceProcessing.cpp @@ -0,0 +1,1574 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <errno.h> +#include <fcntl.h> + +#define LOG_TAG "eS325VoiceProcessing" +//#define LOG_NDEBUG 0 +#include <cutils/log.h> + +#include "eS325VoiceProcessing.h" +#include <audio_effects/effect_aec.h> +#include <audio_effects/effect_ns.h> +#include <audio_effects/effect_agc.h> + +extern "C" { + +//------------------------------------------------------------------------------ +// local definitions +//------------------------------------------------------------------------------ + +// number of sessions this effect bundle can be used for +#define ADNC_PFX_NUM_SESSION 8 + +// types of pre processing modules +enum adnc_pfx_id +{ + PFX_ID_AEC = 0, // Acoustic Echo Cancellation + PFX_ID_NS, // Noise Suppression + PFX_ID_AGC, // Automatic Gain Control + PFX_ID_CNT +}; + +// Session state +enum adnc_pfx_session_state { + PFX_SESSION_STATE_INIT, // initialized + PFX_SESSION_STATE_CONFIG // configuration received +}; + +// Effect/Preprocessor state +enum adnc_pfx_effect_state { + PFX_EFFECT_STATE_INIT, // initialized + PFX_EFFECT_STATE_CREATED, // effect created + PFX_EFFECT_STATE_CONFIG, // configuration received/disabled + PFX_EFFECT_STATE_ACTIVE // active/enabled +}; + +typedef struct adnc_pfx_session_s adnc_pfx_session_t; +typedef struct adnc_pfx_effect_s adnc_pfx_effect_t; +typedef struct adnc_pfx_ops_s adnc_pfx_ops_t; + +// Effect operation table. Functions for all pre processors are declared in sPreProcOps[] table. +// Function pointer can be null if no action required. +struct adnc_pfx_ops_s { + int (* create)(adnc_pfx_effect_t *fx); + int (* init)(adnc_pfx_effect_t *fx); + int (* reset)(adnc_pfx_effect_t *fx); + void (* enable)(adnc_pfx_effect_t *fx); + void (* disable)(adnc_pfx_effect_t *fx); + int (* set_parameter)(adnc_pfx_effect_t *fx, void *param, void *value); + int (* get_parameter)(adnc_pfx_effect_t *fx, void *param, size_t *size, void *value); + int (* set_device)(adnc_pfx_effect_t *fx, uint32_t device); +}; + +// Effect context +struct adnc_pfx_effect_s { + const struct effect_interface_s *itfe; + uint32_t procId; // type of pre processor (enum adnc_pfx_id) + uint32_t state; // current state (enum adnc_pfx_effect_state) + adnc_pfx_session_t *session; // session the effect is on + const adnc_pfx_ops_t *ops; // effect ops table +}; + +// Session context +struct adnc_pfx_session_s { + uint32_t state; // current state (enum adnc_pfx_session_state) + audio_source_t audioSource; + // FIXME not used, delete? + //int audioSessionId; // audio session ID + int ioHandle; // handle of input stream this session is on + uint32_t createdMsk; // bit field containing IDs of created pre processors + uint32_t activeMsk; // bit field containing IDs of pre processors currently active + struct adnc_pfx_effect_s effects[PFX_ID_CNT]; // effects in this session + + // effect settings + // none controllable from public API here +}; + +//----------------------------------------- +// forward declarations +//----------------------------------------- +int Adnc_SetNoiseSuppressionInt_l(bool); +int Adnc_SetAutomaticGainControlInt_l(bool); +int Adnc_SetEchoCancellationInt_l(bool); +int Adnc_ReevaluateUsageInt_l(audio_io_handle_t); +int Adnc_SleepInt_l(); + +//------------------------------------------------------------------------------ +// eS325 control +//------------------------------------------------------------------------------ +/* TODO: figure out how to use VEQ mode */ +#define ES325_SYSFS_PATH "/sys/class/2mic/es325/" +#define ES325_VOICE_PROCESSING_PATH ES325_SYSFS_PATH "voice_processing" +#define ES325_VEQ_PATH ES325_SYSFS_PATH "veq" +#define ES325_PRESET_PATH ES325_SYSFS_PATH "preset" +#define ES325_TX_NS_LEVEL_PATH ES325_SYSFS_PATH "tx_ns_level" +#define ES325_TX_AGC_ENABLE_PATH ES325_SYSFS_PATH "tx_agc_enable" +#define ES325_AEC_ENABLE_PATH ES325_SYSFS_PATH "aec_enable" +#define ES325_SLEEP_PATH ES325_SYSFS_PATH "sleep" + +enum eS325_controls { + ES325_CTRL_VOICE_PROCESSING = 0, + ES325_CTRL_VEQ, + ES325_CTRL_PRESET, + ES325_CTRL_TX_NS_LEVEL, + ES325_CTRL_TX_AGC_ENABLE, + ES325_CTRL_AEC_ENABLE, + ES325_CTRL_SLEEP, + ES325_NUM_CTRL +}; + +struct eS325_ctrl_s { + int fd[ES325_NUM_CTRL]; + int current_preset; + int requested_preset; + int ioHandle; +}; +typedef struct eS325_ctrl_s eS325_ctrl_t; + +static eS325_ctrl_t eS325_ctrl = { + { -1/*vp*/, -1/*preset*/, -1/*ns*/, -1/*agc*/, -1/*aec*/, -1/*sleep*/}, + ES325_PRESET_OFF /*current_preset*/, + ES325_PRESET_INIT /*requested_preset, an invalid preset, different from current_preset*/, + ES325_IO_HANDLE_NONE +}; + +//------------------------------------------------------------------------------ +// Effect descriptors +//------------------------------------------------------------------------------ + +// UUIDs for effect types have been generated from http://www.itu.int/ITU-T/asn1/uuid.html +// as the pre processing effects are not defined by OpenSL ES + +// Acoustic Echo Cancellation +static const effect_descriptor_t aec_descriptor = { + FX_IID_AEC_, // type + { 0xfd90ff00, 0x0b55, 0x11e2, 0x892e, { 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }, // uuid + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND), + 0, //FIXME indicate CPU load + 0, //FIXME indicate memory usage + "Acoustic Echo Canceler", + "Audience" +}; + +// Noise suppression +static const effect_descriptor_t ns_descriptor = { + FX_IID_NS_, // type + { 0x08fa98b0, 0x0b56, 0x11e2, 0x892e, { 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }, // uuid + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND), + 0, //FIXME indicate CPU load + 0, //FIXME indicate memory usage + "Noise Suppression", + "Audience" +}; + +// Automatic Gain Control +static const effect_descriptor_t agc_descriptor = { + FX_IID_AGC_, // type + { 0xe9e87eb0, 0x0b55, 0x11e2, 0x892e, { 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }, // uuid + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND), + 0, //FIXME indicate CPU load + 0, //FIXME indicate memory usage + "Automatic Gain Control", + "Audience" +}; + +static const effect_descriptor_t *adnc_pfx_descriptors[PFX_ID_CNT] = { + &aec_descriptor, + &ns_descriptor, + &agc_descriptor +}; + + +//------------------------------------------------------------------------------ +// Helper functions +//------------------------------------------------------------------------------ +static const effect_uuid_t * const sAdncUuidTable[PFX_ID_CNT] = { + FX_IID_AEC, + FX_IID_NS, + FX_IID_AGC +}; + +const effect_uuid_t * Adnc_ProcIdToUuid(int procId) +{ + if (procId >= PFX_ID_CNT) { + return EFFECT_UUID_NULL; + } + return sAdncUuidTable[procId]; +} + +uint32_t Adnc_UuidToProcId(const effect_uuid_t * uuid) +{ + size_t i; + for (i = 0; i < PFX_ID_CNT; i++) { + if (memcmp(uuid, sAdncUuidTable[i], sizeof(*uuid)) == 0) { + break; + } + } + return i; +} + + +//------------------------------------------------------------------------------ +// Acoustic Echo Canceler (AEC) +//------------------------------------------------------------------------------ +int aec_init (adnc_pfx_effect_t *effect) +{ + ALOGV("aec_init [noop]"); + return 0; +} + +int aec_create(adnc_pfx_effect_t *effect) +{ + ALOGV("aec_create [noop]"); + return aec_init (effect); +} + +int aec_reset(adnc_pfx_effect_t *effect) +{ + ALOGV("aec_reset [noop]"); + return 0; +} + +int aec_get_parameter(adnc_pfx_effect_t *effect, + void *pParam, + size_t *pValueSize, + void *pValue) +{ + int status = 0; + uint32_t param = *(uint32_t *)pParam; + + if (*pValueSize < sizeof(uint32_t)) { + return -EINVAL; + } + /* NOT SUPPORTED + switch (param) { + case AEC_PARAM_ECHO_DELAY: + case AEC_PARAM_PROPERTIES: + break; + default: + ALOGW("aec_get_parameter() unknown param %08x value %08x", param, *(uint32_t *)pValue); + status = -EINVAL; + break; + } + return status; + */ + return -EINVAL; +} + +int aec_set_parameter (adnc_pfx_effect_t *effect, void *pParam, void *pValue) +{ + int status = 0; + uint32_t param = *(uint32_t *)pParam; + uint32_t value = *(uint32_t *)pValue; + + /* NOT SUPPORTED + switch (param) { + case AEC_PARAM_ECHO_DELAY: + case AEC_PARAM_PROPERTIES: + ALOGV("aec_setParameter() echo delay %d us, status %d", value, status); + break; + default: + ALOGW("aec_setParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue); + status = -EINVAL; + break; + } + */ + return status; +} + +void aec_enable(adnc_pfx_effect_t *effect) +{ + ALOGV("aec_enable [noop]"); +} + +void aec_disable(adnc_pfx_effect_t *effect) +{ + ALOGV("aec_disable [noop]"); +} + +int aec_set_device(adnc_pfx_effect_t *effect, uint32_t device) +{ + ALOGV("aec_set_device(device=%08x) [noop]", device); + + /* + switch(device) { + case AUDIO_DEVICE_OUT_EARPIECE: + break; + case AUDIO_DEVICE_OUT_SPEAKER: + break; + case AUDIO_DEVICE_OUT_WIRED_HEADSET: + case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: + default: + break; + } + */ + + return 0; +} + +static const adnc_pfx_ops_t aec_ops = { + aec_create, + aec_init, + aec_reset, + aec_enable, + aec_disable, + aec_set_parameter, + aec_get_parameter, + aec_set_device, +}; + + +//------------------------------------------------------------------------------ +// Noise Suppression (NS) +//------------------------------------------------------------------------------ +int ns_init (adnc_pfx_effect_t *effect) +{ + ALOGV("ns_init [noop]"); + + return 0; +} + +int ns_create(adnc_pfx_effect_t *effect) +{ + ALOGV("ns_create %p", effect); + + return ns_init (effect); +} + +int ns_get_parameter(adnc_pfx_effect_t *effect, + void *pParam, + size_t *pValueSize, + void *pValue) +{ + int status = 0; + return status; +} + +int ns_set_parameter(adnc_pfx_effect_t *effect, void *pParam, void *pValue) +{ + int status = 0; + return status; +} + +void ns_enable(adnc_pfx_effect_t *effect) +{ + ALOGV("ns_enable [noop]"); +} + +void ns_disable(adnc_pfx_effect_t *effect) +{ + ALOGV("ns_disable [noop]"); +} + +static const adnc_pfx_ops_t ns_ops = { + ns_create, + ns_init, + NULL, + ns_enable, + ns_disable, + ns_set_parameter, + ns_get_parameter, + NULL, +}; + + +//------------------------------------------------------------------------------ +// Automatic Gain Control (AGC) +//------------------------------------------------------------------------------ +int agc_init (adnc_pfx_effect_t *effect) +{ + ALOGV("agc_init [noop]"); + + return 0; +} + +int agc_create(adnc_pfx_effect_t *effect) +{ + ALOGV("agc_create %p", effect); + + return agc_init (effect); +} + +int agc_get_parameter(adnc_pfx_effect_t *effect, + void *pParam, + size_t *pValueSize, + void *pValue) +{ + int status = 0; + return status; +} + +int agc_set_parameter(adnc_pfx_effect_t *effect, void *pParam, void *pValue) +{ + int status = 0; + return status; +} + +void agc_enable(adnc_pfx_effect_t *effect) +{ + ALOGV("agc_enable [noop]"); +} + +void agc_disable(adnc_pfx_effect_t *effect) +{ + ALOGV("agc_disable [noop]"); +} + +static const adnc_pfx_ops_t agc_ops = { + agc_create, + agc_init, + NULL, + agc_enable, + agc_disable, + agc_set_parameter, + agc_get_parameter, + NULL, +}; + +//------------------------------------------------------------------------------ +// +//------------------------------------------------------------------------------ +static const adnc_pfx_ops_t *sPreProcOps[PFX_ID_CNT] = { + &aec_ops, + &ns_ops, + &agc_ops +}; + +//------------------------------------------------------------------------------ +// Pre-processing effect functions +//------------------------------------------------------------------------------ +extern const struct effect_interface_s sEffectInterface; + +#define BAD_STATE_ABORT(from, to) \ + LOG_ALWAYS_FATAL("Bad state transition from %d to %d", from, to); + +void AdncSession_SetProcEnabled(adnc_pfx_session_t *session, uint32_t procId, bool enabled); + +int AdncPreProFx_SetState(adnc_pfx_effect_t *effect, uint32_t state) +{ + int status = 0; + ALOGV("AdncPreProFx_SetState procId %d, new %d old %d", effect->procId, state, effect->state); + switch(state) { + case PFX_EFFECT_STATE_INIT: + switch(effect->state) { + case PFX_EFFECT_STATE_ACTIVE: + effect->ops->disable(effect); + AdncSession_SetProcEnabled(effect->session, effect->procId, false); + case PFX_EFFECT_STATE_CONFIG: + case PFX_EFFECT_STATE_CREATED: + case PFX_EFFECT_STATE_INIT: + break; + default: + BAD_STATE_ABORT(effect->state, state); + } + break; + case PFX_EFFECT_STATE_CREATED: + switch(effect->state) { + case PFX_EFFECT_STATE_INIT: + status = effect->ops->create(effect); + break; + case PFX_EFFECT_STATE_CREATED: + case PFX_EFFECT_STATE_ACTIVE: + case PFX_EFFECT_STATE_CONFIG: + ALOGE("Effect_SetState invalid transition"); + status = -ENOSYS; + break; + default: + BAD_STATE_ABORT(effect->state, state); + } + break; + case PFX_EFFECT_STATE_CONFIG: + switch(effect->state) { + case PFX_EFFECT_STATE_INIT: + ALOGE("Effect_SetState invalid transition"); + status = -ENOSYS; + break; + case PFX_EFFECT_STATE_ACTIVE: + effect->ops->disable(effect); + AdncSession_SetProcEnabled(effect->session, effect->procId, false); + break; + case PFX_EFFECT_STATE_CREATED: + case PFX_EFFECT_STATE_CONFIG: + break; + default: + BAD_STATE_ABORT(effect->state, state); + } + break; + case PFX_EFFECT_STATE_ACTIVE: + switch(effect->state) { + case PFX_EFFECT_STATE_INIT: + case PFX_EFFECT_STATE_CREATED: + ALOGE("Effect_SetState invalid transition"); + status = -ENOSYS; + break; + case PFX_EFFECT_STATE_ACTIVE: + // enabling an already enabled effect is just ignored + break; + case PFX_EFFECT_STATE_CONFIG: + effect->ops->enable(effect); + AdncSession_SetProcEnabled(effect->session, effect->procId, true); + break; + default: + BAD_STATE_ABORT(effect->state, state); + } + break; + default: + BAD_STATE_ABORT(effect->state, state); + } + if (status == 0) { + effect->state = state; + } + return status; +} + +int AdncPreProFx_Init(adnc_pfx_effect_t *effect, uint32_t procId) +{ + ALOGV(" AdncPreProFx_Init(procId=%d)", procId); + effect->itfe = &sEffectInterface; + effect->ops = sPreProcOps[procId]; + effect->procId = procId; + effect->state = PFX_EFFECT_STATE_INIT; + return 0; +} + +int AdncPreProFx_Create(adnc_pfx_effect_t *effect, + adnc_pfx_session_t *session, + effect_handle_t *interface) +{ + ALOGV(" AdncPreProFx_Create(effect=%p)", effect); + effect->session = session; + *interface = (effect_handle_t)&effect->itfe; + return AdncPreProFx_SetState(effect, PFX_EFFECT_STATE_CREATED); +} + +int AdncPreProFx_Release(adnc_pfx_effect_t *effect) +{ + return AdncPreProFx_SetState(effect, PFX_EFFECT_STATE_INIT); +} + + +//------------------------------------------------------------------------------ +// Session functions +//------------------------------------------------------------------------------ +/* + * Initialize a session context. + * Must be called with a lock on sAdncBundleLock. + */ +int AdncSession_Init_l(adnc_pfx_session_t *session) +{ + ALOGV("AdncSession_Init()"); + size_t i; + int status = 0; + + session->state = PFX_SESSION_STATE_INIT; + session->audioSource = AUDIO_SOURCE_DEFAULT; + //session->audioSessionId = ES325_SESSION_ID_NONE; // FIXME not used delete? + session->ioHandle = ES325_IO_HANDLE_NONE; + session->createdMsk = 0; + session->activeMsk = 0; + // initialize each effect for this session context + for (i = 0; i < PFX_ID_CNT && status == 0; i++) { + status = AdncPreProFx_Init(&session->effects[i], i); + } + return status; +} + +/* + * Must be called with a lock on sAdncBundleLock. + */ +int AdncSession_CreateEffect_l(adnc_pfx_session_t *session, + int32_t procId, + effect_handle_t *interface) +{ + int status = -ENOMEM; + ALOGV("AdncSession_CreateEffect handle=%d procId %d, old createdMsk %08x", + session->ioHandle, procId, session->createdMsk); + + status = AdncPreProFx_Create(&session->effects[procId], session, interface); + if (status >= 0) { + ALOGV(" AdncSession_CreateEffect OK"); + session->createdMsk |= (1 << procId); + } + return status; +} + +int AdncSession_SetConfig(adnc_pfx_session_t *session, effect_config_t *config) +{ + ALOGV("AdncSession_SetConfig [noop]"); + return 0; +} + +void AdncSession_GetConfig(adnc_pfx_session_t *session, effect_config_t *config) +{ + ALOGV("AdncSession_GetConfig [noop]"); +} + +int AdncSession_SetReverseConfig(adnc_pfx_session_t *session, effect_config_t *config) +{ + ALOGV("AdncSession_SetReverseConfig [noop]"); + return 0; +} + +void AdncSession_GetReverseConfig(adnc_pfx_session_t *session, effect_config_t *config) +{ + ALOGV("AdncSession_GetReverseConfig [noop]"); +} + +void AdncSession_SetProcEnabled(adnc_pfx_session_t *session, uint32_t procId, bool enabled) +{ + ALOGV("AdncSession_SetProcEnabled [noop] proc %d, enabled %d", procId, enabled); + //no need to reevaluate session settings, if recording is currently ongoing, we'll reevaluate + // through eS325_AddEffect() +} + +int AdncSession_SetSource(adnc_pfx_session_t *session, audio_source_t source) +{ + session->audioSource = source; + return 0; +} + +//------------------------------------------------------------------------------ +// Bundle functions +//------------------------------------------------------------------------------ +#define ADNC_BUNDLE_NO_INIT 1 +static int sAdncBundleInitStatus = ADNC_BUNDLE_NO_INIT; +static adnc_pfx_session_t sAdncSessions[ADNC_PFX_NUM_SESSION]; +static pthread_mutex_t sAdncBundleLock; + +/* Returns a session context for the given IO handle + * Returns an existing session context if the IO handle matches, initializes a new one otherwise. + * Returns NULL if no more session contexts are available + * Must be called with a lock on sAdncBundleLock + */ +adnc_pfx_session_t *AdncBundle_GetSession_l(int32_t procId, int32_t sessionId, int32_t ioId) +{ + size_t i; + for (i = 0; i < ADNC_PFX_NUM_SESSION; i++) { + if (sAdncSessions[i].ioHandle == ioId) { + return &sAdncSessions[i]; + } + } + for (i = 0; i < ADNC_PFX_NUM_SESSION; i++) { + if (sAdncSessions[i].ioHandle == ES325_IO_HANDLE_NONE) { + //sAdncSessions[i].audioSessionId = sessionId; // FIXME not used delete? + sAdncSessions[i].ioHandle = ioId; + return &sAdncSessions[i]; + } + } + ALOGV("AdncBundle_GetSession_l"); + return NULL; +} + +/* + * Must be called with a lock on sAdncBundleLock. + */ +int AdncBundle_Init_l() { + size_t i; + int status = 0; + + if (sAdncBundleInitStatus <= 0) { + return sAdncBundleInitStatus; + } + // initialize all the session contexts that this bundle supports + for (i = 0; i < ADNC_PFX_NUM_SESSION && status == 0; i++) { + status = AdncSession_Init_l(&sAdncSessions[i]); + } + sAdncBundleInitStatus = status; + return sAdncBundleInitStatus; +} + +/* + * Must be called with a lock on sAdncBundleLock. + */ +int AdncBundle_Release_l() { + ALOGV("AdncBundle_Release_l()"); + + Adnc_SleepInt_l(); + + for (int i = 0 ; i < ES325_NUM_CTRL ; i++) { + if (eS325_ctrl.fd[i] >= 0) { + close(eS325_ctrl.fd[i]); + } + eS325_ctrl.fd[i] = -1; + } + return 0; +} + +const effect_descriptor_t *AdncBundle_GetDescriptor(const effect_uuid_t *uuid) +{ + size_t i; + for (i = 0; i < PFX_ID_CNT; i++) { + if (memcmp(&adnc_pfx_descriptors[i]->uuid, uuid, sizeof(effect_uuid_t)) == 0) { + return adnc_pfx_descriptors[i]; + } + } + return NULL; +} + +/* + * Debug only: display session contexts + */ +void AdncBundle_logv_dumpSessions() { + ALOGV("Sessions:"); + for (int i=0 ; i<ADNC_PFX_NUM_SESSION ; i++) { + ALOGV(" session %d handle=%d cre=%2x act=%2x", + i, sAdncSessions[i].ioHandle, sAdncSessions[i].createdMsk, sAdncSessions[i].activeMsk); + } +} + +//------------------------------------------------------------------------------ +// Effect Control Interface Implementation +//------------------------------------------------------------------------------ +int AdncVoiceProcessingFx_Command(effect_handle_t self, + uint32_t cmdCode, + uint32_t cmdSize, + void *pCmdData, + uint32_t *replySize, + void *pReplyData) +{ + adnc_pfx_effect_t * effect = (adnc_pfx_effect_t *) self; + int retsize; + int status; + + if (effect == NULL){ + return -EINVAL; + } + + ALOGV("AdncVoiceProcessingFx_Command: command %d cmdSize %d",cmdCode, cmdSize); + + switch (cmdCode){ + case EFFECT_CMD_INIT: + if (pReplyData == NULL || *replySize != sizeof(int)){ + return -EINVAL; + } + if (effect->ops->init) { + effect->ops->init(effect); + } + *(int *)pReplyData = 0; + break; + + case EFFECT_CMD_SET_CONFIG: { + if (pCmdData == NULL|| + cmdSize != sizeof(effect_config_t)|| + pReplyData == NULL|| + *replySize != sizeof(int)){ + ALOGV("AdncVoiceProcessingFx_Command cmdCode Case: " + "EFFECT_CMD_SET_CONFIG: ERROR"); + return -EINVAL; + } + + *(int *)pReplyData = AdncSession_SetConfig(effect->session, (effect_config_t *)pCmdData); + + if (*(int *)pReplyData != 0) { + break; + } + if (effect->state != PFX_EFFECT_STATE_ACTIVE) { + *(int *)pReplyData = AdncPreProFx_SetState(effect, PFX_EFFECT_STATE_CONFIG); + } + } break; + + case EFFECT_CMD_GET_CONFIG: + if (pReplyData == NULL || + *replySize != sizeof(effect_config_t)) { + ALOGV("\tLVM_ERROR : AdncVoiceProcessingFx_Command cmdCode Case: " + "EFFECT_CMD_GET_CONFIG: ERROR"); + return -EINVAL; + } + + AdncSession_GetConfig(effect->session, (effect_config_t *)pReplyData); + break; + + case EFFECT_CMD_SET_CONFIG_REVERSE: + if (pCmdData == NULL || + cmdSize != sizeof(effect_config_t) || + pReplyData == NULL || + *replySize != sizeof(int)) { + ALOGV("AdncVoiceProcessingFx_Command cmdCode Case: " + "EFFECT_CMD_SET_CONFIG_REVERSE: ERROR"); + return -EINVAL; + } + *(int *)pReplyData = AdncSession_SetReverseConfig(effect->session, + (effect_config_t *)pCmdData); + if (*(int *)pReplyData != 0) { + break; + } + break; + + case EFFECT_CMD_GET_CONFIG_REVERSE: + if (pReplyData == NULL || + *replySize != sizeof(effect_config_t)){ + ALOGV("AdncVoiceProcessingFx_Command cmdCode Case: " + "EFFECT_CMD_GET_CONFIG_REVERSE: ERROR"); + return -EINVAL; + } + AdncSession_GetReverseConfig(effect->session, (effect_config_t *)pCmdData); + break; + + case EFFECT_CMD_RESET: + if (effect->ops->reset) { + effect->ops->reset(effect); + } + break; + + case EFFECT_CMD_GET_PARAM:{ + if (pCmdData == NULL || + cmdSize < (int)sizeof(effect_param_t) || + pReplyData == NULL || + *replySize < (int)sizeof(effect_param_t)){ + ALOGV("AdncVoiceProcessingFx_Command cmdCode Case: " + "EFFECT_CMD_GET_PARAM: ERROR"); + return -EINVAL; + } + effect_param_t *p = (effect_param_t *)pCmdData; + + memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize); + + p = (effect_param_t *)pReplyData; + + int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); + + if (effect->ops->get_parameter) { + p->status = effect->ops->get_parameter(effect, p->data, + (size_t *)&p->vsize, + p->data + voffset); + *replySize = sizeof(effect_param_t) + voffset + p->vsize; + } + } break; + + case EFFECT_CMD_SET_PARAM:{ + if (pCmdData == NULL|| + cmdSize < (int)sizeof(effect_param_t) || + pReplyData == NULL || + *replySize != sizeof(int32_t)){ + ALOGV("AdncVoiceProcessingFx_Command cmdCode Case: " + "EFFECT_CMD_SET_PARAM: ERROR"); + return -EINVAL; + } + effect_param_t *p = (effect_param_t *) pCmdData; + + if (p->psize != sizeof(int32_t)){ + ALOGV("AdncVoiceProcessingFx_Command cmdCode Case: " + "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)"); + return -EINVAL; + } + if (effect->ops->set_parameter) { + *(int *)pReplyData = effect->ops->set_parameter(effect, + (void *)p->data, + p->data + p->psize); + } + } break; + + case EFFECT_CMD_ENABLE: + if (pReplyData == NULL || *replySize != sizeof(int)){ + ALOGV("AdncVoiceProcessingFx_Command cmdCode Case: EFFECT_CMD_ENABLE: ERROR"); + return -EINVAL; + } + *(int *)pReplyData = AdncPreProFx_SetState(effect, PFX_EFFECT_STATE_ACTIVE); + break; + + case EFFECT_CMD_DISABLE: + if (pReplyData == NULL || *replySize != sizeof(int)){ + ALOGV("AdncVoiceProcessingFx_Command cmdCode Case: EFFECT_CMD_DISABLE: ERROR"); + return -EINVAL; + } + *(int *)pReplyData = AdncPreProFx_SetState(effect, PFX_EFFECT_STATE_CONFIG); + break; + + case EFFECT_CMD_SET_DEVICE: + case EFFECT_CMD_SET_INPUT_DEVICE: + if (pCmdData == NULL || + cmdSize != sizeof(uint32_t)) { + ALOGV("AdncVoiceProcessingFx_Command cmdCode Case: EFFECT_CMD_SET_DEVICE: ERROR"); + return -EINVAL; + } + + if (effect->ops->set_device) { + effect->ops->set_device(effect, *(uint32_t *)pCmdData); + } + break; + + case EFFECT_CMD_SET_VOLUME: + case EFFECT_CMD_SET_AUDIO_MODE: + case EFFECT_CMD_SET_FEATURE_CONFIG: + break; + + case EFFECT_CMD_SET_AUDIO_SOURCE: + if (pCmdData == NULL || + cmdSize != sizeof(uint32_t)) { + ALOGV("AdncVoiceProcessingFx_Command cmdCode Case: EFFECT_CMD_SET_AUDIO_SOURCE: ERROR"); + return -EINVAL; + } + return AdncSession_SetSource(effect->session, (audio_source_t) *(uint32_t *)pCmdData); + break; + + default: + return -EINVAL; + } + return 0; +} + + +int AdncVoiceProcessingFx_GetDescriptor(effect_handle_t self, + effect_descriptor_t *pDescriptor) +{ + adnc_pfx_effect_t * effect = (adnc_pfx_effect_t *) self; + + if (effect == NULL || pDescriptor == NULL) { + return -EINVAL; + } + + memcpy(pDescriptor, adnc_pfx_descriptors[effect->procId], sizeof(effect_descriptor_t)); + + return 0; +} + + +// effect_handle_t interface implementation for effect +const struct effect_interface_s sEffectInterface = { + NULL, /* Process */ + AdncVoiceProcessingFx_Command, + AdncVoiceProcessingFx_GetDescriptor, + NULL +}; +//------------------------------------------------------------------------------ +// Effect Library Interface Implementation +//------------------------------------------------------------------------------ + +int adnc_create(const effect_uuid_t *uuid, + int32_t sessionId, + int32_t ioId, + effect_handle_t *pInterface) +{ + ALOGV("adnc_create: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId); + + int status = 0; + const effect_descriptor_t *desc; + adnc_pfx_session_t *session; + uint32_t procId; + + pthread_mutex_lock(&sAdncBundleLock); + + if (AdncBundle_Init_l() != 0) { + status = sAdncBundleInitStatus; + goto exit; + } + + desc = AdncBundle_GetDescriptor(uuid); + if (desc == NULL) { + ALOGW(" adnc_create: fx not found uuid: %08x", uuid->timeLow); + status = -EINVAL; + goto exit; + } + procId = Adnc_UuidToProcId(&desc->type); + + session = AdncBundle_GetSession_l(procId, sessionId, ioId); + if (session == NULL) { + ALOGW(" adnc_create: no more session available"); + status = -EINVAL; + goto exit; + } + + status = AdncSession_CreateEffect_l(session, procId, pInterface); + + if (status < 0 && session->createdMsk == 0) { + session->ioHandle = ES325_IO_HANDLE_NONE; + } + +exit: + pthread_mutex_unlock(&sAdncBundleLock); + return status; +} + +int adnc_release(effect_handle_t interface) +{ + int i, status = 0; + ALOGV("adnc_release %p", interface); + + // the effect handle comes from the effect framework, ok to cast + const adnc_pfx_effect_t * fx = (adnc_pfx_effect_t *) interface; + + const uint32_t removalMsk = ~(1 << fx->procId); + + pthread_mutex_lock(&sAdncBundleLock); + + if (AdncBundle_Init_l() != 0) { + status = sAdncBundleInitStatus; + goto exit; + } + + if (fx->session->ioHandle == 0) { + status = -EINVAL; + goto exit; + } + + // effect is released, flag it as inactive and not created + fx->session->createdMsk &= removalMsk; + fx->session->activeMsk &= removalMsk; + + // configuration has changed, reevaluate + status = Adnc_ReevaluateUsageInt_l(fx->session->ioHandle); + // not checking the return status here: if there was an error, + // we still need to free the session and wouldn't exit here + + // free session if it has no more effects + if (fx->session->createdMsk == 0) { + ALOGV(" resetting session on handle %d after effect release", fx->session->ioHandle); + const int statusInit = AdncSession_Init_l(fx->session); + if (status == 0) { + status = statusInit; + } + } + +exit: + pthread_mutex_unlock(&sAdncBundleLock); + return status; +} + +int adnc_get_descriptor(const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor) { + if (pDescriptor == NULL || uuid == NULL){ + ALOGV("adnc_get_descriptor() invalid params"); + return -EINVAL; + } + + const effect_descriptor_t *desc = AdncBundle_GetDescriptor(uuid); + if (desc == NULL) { + ALOGV("adnc_get_descriptor() not found"); + return -EINVAL; + } + + ALOGV("adnc_get_descriptor() got fx %s", desc->name); + + memcpy(pDescriptor, desc, sizeof(effect_descriptor_t)); + return 0; +} + +audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { + tag : AUDIO_EFFECT_LIBRARY_TAG, + version : EFFECT_LIBRARY_API_VERSION, + name : "Audience Voice Preprocessing Library", + implementor : "The Android Open Source Project", + create_effect : adnc_create, + release_effect : adnc_release, + get_descriptor : adnc_get_descriptor +}; + +//------------------------------------------------------- +// eS325 control interface +//------------------------------------------------------- +int Adnc_SetAutomaticGainControlInt_l(bool agc_on) +{ + ALOGV("Adnc_SetAutomaticGainControlInt_l(%d)", agc_on); + + if (eS325_ctrl.fd[ES325_CTRL_TX_AGC_ENABLE] < 0) { + ALOGV(" opening eS325 path for agc"); + eS325_ctrl.fd[ES325_CTRL_TX_AGC_ENABLE] = open(ES325_TX_AGC_ENABLE_PATH, O_RDWR); + if (eS325_ctrl.fd[ES325_CTRL_TX_AGC_ENABLE] < 0) { + ALOGE(" Cannot open eS325 path for agc: %s", strerror(errno)); + return -ENODEV; + } + } + + if (agc_on) { + write(eS325_ctrl.fd[ES325_CTRL_TX_AGC_ENABLE], ES325_AGC_ON, strlen(ES325_AGC_ON)); + } else { + write(eS325_ctrl.fd[ES325_CTRL_TX_AGC_ENABLE], ES325_AGC_OFF, strlen(ES325_AGC_OFF)); + } + return 0; +} + +int Adnc_SetEchoCancellationInt_l(bool aec_on) +{ + ALOGV("Adnc_SetEchoCancellationInt_l(%d)", aec_on); + + if (eS325_ctrl.fd[ES325_CTRL_AEC_ENABLE] < 0) { + ALOGV(" opening eS325 path for aec"); + eS325_ctrl.fd[ES325_CTRL_AEC_ENABLE] = open(ES325_AEC_ENABLE_PATH, O_RDWR); + if (eS325_ctrl.fd[ES325_CTRL_AEC_ENABLE] < 0) { + ALOGE(" Cannot open eS325 path for aec: %s", strerror(errno)); + return -ENODEV; + } + } + + if (aec_on) { + write(eS325_ctrl.fd[ES325_CTRL_AEC_ENABLE], ES325_AEC_ON, strlen(ES325_AEC_ON)); + } else { + write(eS325_ctrl.fd[ES325_CTRL_AEC_ENABLE], ES325_AEC_OFF, strlen(ES325_AEC_OFF)); + } + return 0; +} + +int Adnc_SetNoiseSuppressionInt_l(bool ns_on) +{ + ALOGV("Adnc_SetNoiseSuppressionInt(%d)", ns_on); + + if (eS325_ctrl.fd[ES325_CTRL_TX_NS_LEVEL] < 0) { + ALOGV(" opening eS325 path for ns"); + eS325_ctrl.fd[ES325_CTRL_TX_NS_LEVEL] = open(ES325_TX_NS_LEVEL_PATH, O_RDWR); + if (eS325_ctrl.fd[ES325_CTRL_TX_NS_LEVEL] < 0) { + ALOGE(" Cannot open eS325 path for ns: %s", strerror(errno)); + return -ENODEV; + } + } + + if (ns_on) { + if (eS325_ctrl.requested_preset == ES325_PRESET_ASRA_HANDHELD) { + ALOGV(" setting ns to %s", ES325_NS_VOICE_REC_HANDHELD_ON); + write(eS325_ctrl.fd[ES325_CTRL_TX_NS_LEVEL], + ES325_NS_VOICE_REC_HANDHELD_ON, strlen(ES325_NS_VOICE_REC_HANDHELD_ON)); + } else if ((eS325_ctrl.requested_preset == ES325_PRESET_ASRA_DESKTOP) + || (eS325_ctrl.requested_preset == ES325_PRESET_ASRA_HEADSET)) { + ALOGV(" setting ns to %s", ES325_NS_VOICE_REC_SINGLE_MIC_ON); + write(eS325_ctrl.fd[ES325_CTRL_TX_NS_LEVEL], + ES325_NS_VOICE_REC_SINGLE_MIC_ON, strlen(ES325_NS_VOICE_REC_SINGLE_MIC_ON)); + } else { + ALOGV(" setting ns to %s", ES325_NS_DEFAULT_ON); + write(eS325_ctrl.fd[ES325_CTRL_TX_NS_LEVEL], + ES325_NS_DEFAULT_ON, strlen(ES325_NS_DEFAULT_ON)); + } + } else { + ALOGV(" setting ns to %s", ES325_NS_OFF); + write(eS325_ctrl.fd[ES325_CTRL_TX_NS_LEVEL], ES325_NS_OFF, strlen(ES325_NS_OFF)); + } + return 0; +} + +int Adnc_SetVoiceProcessingInt_l(bool vp_on) +{ + if (eS325_ctrl.fd[ES325_CTRL_VOICE_PROCESSING] < 0) { + ALOGV(" opening eS325 path for VP"); + eS325_ctrl.fd[ES325_CTRL_VOICE_PROCESSING] = open(ES325_VOICE_PROCESSING_PATH, O_RDWR); + if (eS325_ctrl.fd[ES325_CTRL_VOICE_PROCESSING] < 0) { + ALOGE(" cannot open eS325 path for VP: %s", strerror(errno)); + return -ENODEV; + } + } + if (vp_on) { + write(eS325_ctrl.fd[ES325_CTRL_VOICE_PROCESSING], ES325_ON, strlen(ES325_ON)); + } else { + write(eS325_ctrl.fd[ES325_CTRL_VOICE_PROCESSING], ES325_OFF, strlen(ES325_OFF)); + } + return 0; +} + +int Adnc_SetVeqInt_l(bool veq_on) +{ + if (eS325_ctrl.fd[ES325_CTRL_VEQ] < 0) { + ALOGV(" opening eS325 path for VEQ"); + eS325_ctrl.fd[ES325_CTRL_VEQ] = open(ES325_VEQ_PATH, O_RDWR); + if (eS325_ctrl.fd[ES325_CTRL_VEQ] < 0) { + ALOGE(" cannot open eS325 path for VEQ: %s", strerror(errno)); + return -ENODEV; + } + } + if (veq_on) { + write(eS325_ctrl.fd[ES325_CTRL_VEQ], ES325_ON, strlen(ES325_ON)); + } else { + write(eS325_ctrl.fd[ES325_CTRL_VEQ], ES325_OFF, strlen(ES325_OFF)); + } + return 0; +} + +/* + * Put the eS325 to sleep + * Post condition when no error: eS325_ctrl.current_preset == ES325_PRESET_OFF + */ +int Adnc_SleepInt_l() +{ + if (eS325_ctrl.current_preset == ES325_PRESET_OFF) { + return 0; + } + + ALOGV(" Adnc_SleepInt()_l setting VP off + sleep 1"); + + Adnc_SetVoiceProcessingInt_l(false /*vp_on*/); + + ALOGV(" Adnc_SetSleepInt_l"); + if (eS325_ctrl.fd[ES325_CTRL_SLEEP] < 0) { + ALOGV(" opening eS325 path for sleep"); + eS325_ctrl.fd[ES325_CTRL_SLEEP] = open(ES325_SLEEP_PATH, O_RDWR); + if (eS325_ctrl.fd[ES325_CTRL_SLEEP] < 0) { + ALOGE(" cannot open eS325 path for sleep: %s", strerror(errno)); + return -ENODEV; + } + } + + write(eS325_ctrl.fd[ES325_CTRL_SLEEP], ES325_ON, strlen(ES325_ON)); + + eS325_ctrl.current_preset = ES325_PRESET_OFF; + + return 0; +} + +/* + * Apply the eS325_ctrl.requested_preset preset after turning VP on + * Post condition when no error: eS325_ctrl.current_preset == eS325_ctrl.requested_preset + */ +int Adnc_ApplyPresetInt_l() +{ + ALOGV("Adnc_ApplyPresetInt() current_preset=%d, requested_preset=%d", + eS325_ctrl.current_preset, eS325_ctrl.requested_preset); + + if (eS325_ctrl.requested_preset == eS325_ctrl.current_preset) { + ALOGV(" nothing to do, preset %d is current", eS325_ctrl.requested_preset); + return 0; + } + + // preset off implies going to sleep + if (eS325_ctrl.requested_preset == ES325_PRESET_OFF) { + return Adnc_SleepInt_l(); + } + + // voice processing must be on before setting the preset + if ((eS325_ctrl.current_preset == ES325_PRESET_OFF) + || (eS325_ctrl.current_preset == ES325_PRESET_INIT)) { + const int status = Adnc_SetVoiceProcessingInt_l(true /*vp_on*/); + if (status != 0) { + return status; + } + } + + if (eS325_ctrl.fd[ES325_CTRL_PRESET] < 0) { + ALOGV(" opening eS325 path for PRESET"); + eS325_ctrl.fd[ES325_CTRL_PRESET] = open(ES325_PRESET_PATH, O_RDWR); + } + if (eS325_ctrl.fd[ES325_CTRL_PRESET] < 0) { + ALOGE(" Cannot open eS325 path for PRESET: %s", strerror(errno)); + return -ENODEV; + } + + char str[8]; + sprintf(str, "%d", eS325_ctrl.requested_preset); + write(eS325_ctrl.fd[ES325_CTRL_PRESET], str, strlen(str)); + + eS325_ctrl.current_preset = eS325_ctrl.requested_preset; + + return 0; +} + + +/* + * Apply the settings of given the session context + */ +int Adnc_ApplySettingsFromSessionContextInt_l(adnc_pfx_session_t * session) +{ + ALOGV("Adnc_ApplySettingsFromSessionContextInt_l cre=%2x ac=%2x handle=%d", + session->createdMsk, session->activeMsk, session->ioHandle); + int status = 0; + + if (session->ioHandle != eS325_ctrl.ioHandle) { + return status; + } + + // NS: special case of noise suppression, always reset according to effect state + // as default desirable value might differ from the preset + const bool ns_on = ((session->activeMsk & (1 << PFX_ID_NS)) != 0); + status = Adnc_SetNoiseSuppressionInt_l(ns_on /*ns_on*/); + + // AEC + if ((session->createdMsk & (1 << PFX_ID_AEC)) /* the effect has been created */ + && (session->activeMsk & (1 << PFX_ID_AEC))) /* the effect is active */ + { + Adnc_SetEchoCancellationInt_l(true /*aec_on*/); + } + + // AGC + if ((session->createdMsk & (1 << PFX_ID_AGC)) /* the effect has been created */ + && (session->activeMsk & (1 << PFX_ID_AGC))) /* the effect is active */ + { + Adnc_SetAutomaticGainControlInt_l(true /*agc_on*/); + } + + return status; +} + +/* + * Return a value between 0 and ADNC_PFX_NUM_SESSION-1 if a session context has the given handle, + * -1 if the handle isn't in handled by one of the sessions. + * Must be called with a lock on sAdncBundleLock + */ +int Adnc_SessionNumberForHandle_l(audio_io_handle_t handle) +{ + for (int i = 0 ; i < ADNC_PFX_NUM_SESSION ; i++) { + if (sAdncSessions[i].ioHandle == handle) { + return i; + } + } + return -1; +} + + +/* + * Apply the settings of the session matching the given IO handle. + * Must be called with a lock on sAdncBundleLock + */ +int Adnc_ApplySettingsForHandleInt_l(audio_io_handle_t handle) +{ + ALOGV(" Adnc_ApplySettingsForHandleInt_l(handle=%d)", handle); + // indicates whether this effect bundle currently has a session context for this IO handle + bool hasSession = false; + int status = 0; + int i; + + if (sAdncBundleInitStatus != 0) { + // This assumes that the default config of the eS325 after setting a preset + // is the correct configuration. + ALOGV(" no effect settings to apply for IO handle %d, no effect bundle", handle); + return status; + } + + const int sessionId = Adnc_SessionNumberForHandle_l(handle); + if (sessionId >= 0) { + ALOGV(" applying settings from session num %d", sessionId); + status = Adnc_ApplySettingsFromSessionContextInt_l( &sAdncSessions[sessionId] ); + } + else { + ALOGV(" no session found for handle %d", handle); + } + + return status; +} + +/* + * Reevaluate the usage of the eS325 based on the given IO handle. + * Must be called with a lock on sAdncBundleLock + */ +int Adnc_ReevaluateUsageInt_l(audio_io_handle_t handle) +{ + ALOGV(" Adnc_ReevaluateUsageInt_l(handle=%d) current_preset=%d requested_preset=%d", + handle, eS325_ctrl.current_preset, eS325_ctrl.requested_preset); + int status = 0; + if ((eS325_ctrl.requested_preset == ES325_PRESET_OFF) || (handle == ES325_IO_HANDLE_NONE)) { + status = Adnc_SleepInt_l(); + } else { + const int sessionId = Adnc_SessionNumberForHandle_l(handle); + if (sessionId >= 0) { + // recording active, use the preset only if there is an effect, + // reset preset to off otherwise + if (sAdncSessions[sessionId].activeMsk != 0) { + status = Adnc_ApplyPresetInt_l(); + if (status == 0) { + //apply the settings of the session associated with the handle (if any) + status = Adnc_ApplySettingsForHandleInt_l(handle); + } + } else { + status = Adnc_SleepInt_l(); + } + } + } + return status; +} + + +//------------------------------------------------------- +// eS325 public control interface from HAL +//------------------------------------------------------- +int eS325_UsePreset(int preset) +{ + ALOGV("eS325_UsePreset(%d) current=%d handle=%d", + preset, eS325_ctrl.current_preset, eS325_ctrl.ioHandle); + + int status = 0; + + pthread_mutex_lock(&sAdncBundleLock); + + //if (preset != -1) { AdncBundle_logv_dumpSessions(); } + + // allow preset transition from any preset to any other during recording, + // except from one ASRA preset to another + if (eS325_ctrl.ioHandle != ES325_IO_HANDLE_NONE) { + switch(eS325_ctrl.current_preset) { + case ES325_PRESET_ASRA_HANDHELD: + case ES325_PRESET_ASRA_DESKTOP: + case ES325_PRESET_ASRA_HEADSET: + switch(preset) { + case ES325_PRESET_ASRA_HANDHELD: + case ES325_PRESET_ASRA_DESKTOP: + case ES325_PRESET_ASRA_HEADSET: + ALOGV(" not switching from ASRA preset %d to %d during voice recognition", + eS325_ctrl.current_preset, preset); + status = -EINVAL; + goto exit; + default: + // transitioning from ASRA to non-ASRA: valid + break; + } + break; + default: + // transitioning from non-ASRA: valid + break; + } + } + + eS325_ctrl.requested_preset = preset; + + status = AdncBundle_Init_l(); + if (status != 0) { + ALOGE(" error applying preset, bundle failed to initialize"); + goto exit; + } + + status = Adnc_ReevaluateUsageInt_l(eS325_ctrl.ioHandle); + +exit: + pthread_mutex_unlock(&sAdncBundleLock); + return status; +} + + +int eS325_SetVeq(bool enable) +{ + ALOGV("eS325_EnableVeq(%d)", enable); + + int status; + + pthread_mutex_lock(&sAdncBundleLock); + + status = AdncBundle_Init_l(); + if (status != 0) { + ALOGE(" error enabling VEQ, bundle failed to initialize"); + goto exit; + } + + status = Adnc_SetVeqInt_l(enable); + +exit: + pthread_mutex_unlock(&sAdncBundleLock); + return status; +} + + +int eS325_SetActiveIoHandle(audio_io_handle_t handle) +{ + ALOGV("eS325_SetActiveIoHandle(%d)", handle); + + pthread_mutex_lock(&sAdncBundleLock); + + int status = AdncBundle_Init_l(); + if (status != 0) { + ALOGE(" error setting active handle, bundle failed to initialize"); + pthread_mutex_unlock(&sAdncBundleLock); + return status; + } + + status = Adnc_ReevaluateUsageInt_l(handle); + + if (status == 0) { + eS325_ctrl.ioHandle = handle; + } else { + ALOGE(" failed to update for new handle %d (current preset = %d)", + handle, eS325_ctrl.current_preset); + } + + pthread_mutex_unlock(&sAdncBundleLock); + + return status; +} + + +int eS325_AddEffect(effect_descriptor_t * descr, audio_io_handle_t handle) +{ + ALOGV("eS325_AddEffect(handle=%d)", handle); + + pthread_mutex_lock(&sAdncBundleLock); + + int status = AdncBundle_Init_l(); + if (status != 0) { + ALOGE(" error setting adding effect, bundle failed to initialize"); + pthread_mutex_unlock(&sAdncBundleLock); + return status; + } + + if (descr == NULL){ + ALOGV(" eS325_AddEffect() ERROR effect descriptor is NULL"); + pthread_mutex_unlock(&sAdncBundleLock); + return -EINVAL; + } + + uint32_t procId = Adnc_UuidToProcId(&descr->type); + + adnc_pfx_session_t * session = AdncBundle_GetSession_l( + procId, ES325_SESSION_ID_NONE, handle/*ioId*/); + + if (session != NULL) { + // mark the effect as active + session->activeMsk |= (1 << procId); + + // update settings if necessary + Adnc_ReevaluateUsageInt_l(session->ioHandle); + } + + pthread_mutex_unlock(&sAdncBundleLock); + + return status; +} + + +int eS325_RemoveEffect(effect_descriptor_t * descr, audio_io_handle_t handle) +{ + ALOGV("eS325_RemoveEffect()"); + + pthread_mutex_lock(&sAdncBundleLock); + + int status = AdncBundle_Init_l(); + if (status != 0) { + ALOGE(" error setting removing effect, bundle failed to initialize"); + pthread_mutex_unlock(&sAdncBundleLock); + return status; + } + + if (descr == NULL){ + ALOGV(" eS325_AddEffect() ERROR effect descriptor is NULL"); + pthread_mutex_unlock(&sAdncBundleLock); + return -EINVAL; + } + + uint32_t procId = Adnc_UuidToProcId(&descr->type); + + adnc_pfx_session_t * session = AdncBundle_GetSession_l( + procId, ES325_SESSION_ID_NONE, handle/*ioId*/); + + if (session != NULL) { + // mark the effect as inactive + session->activeMsk &= ~(1 << procId); + + // update settings if necessary + Adnc_ReevaluateUsageInt_l(session->ioHandle); + } + + pthread_mutex_unlock(&sAdncBundleLock); + + return status; +} + + +int eS325_Release() { + ALOGV("eS325_Release()"); + + pthread_mutex_lock(&sAdncBundleLock); + + AdncBundle_Release_l(); + + pthread_mutex_unlock(&sAdncBundleLock); + + return 0; +} + +} // extern "C" diff --git a/audio/eS325VoiceProcessing.h b/audio/eS325VoiceProcessing.h new file mode 100644 index 0000000..331b276 --- /dev/null +++ b/audio/eS325VoiceProcessing.h @@ -0,0 +1,77 @@ +/* + * 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 _ES325_VOICE_PROCESSING_ +#define _ES325_VOICE_PROCESSING_ + +#include <system/audio.h> +#include <hardware/audio_effect.h> + +#define ES325_IO_HANDLE_NONE -1 +#define ES325_SESSION_ID_NONE -1977 + +#define ES325_ON "1" +#define ES325_OFF "0" + +#define ES325_NS_DEFAULT_ON "4" +#define ES325_NS_VOICE_REC_HANDHELD_ON "6" +#define ES325_NS_VOICE_REC_SINGLE_MIC_ON "0" +#define ES325_NS_OFF "0" +#define ES325_AGC_ON "1" +#define ES325_AGC_OFF "0" +#define ES325_AEC_ON "1" +#define ES325_AEC_OFF "0" + +enum { + ES325_PRESET_INIT = -3, + ES325_PRESET_CURRENT = -2, + ES325_PRESET_OFF = -1, + ES325_PRESET_VOIP_HANDHELD = 0, + ES325_PRESET_ASRA_HANDHELD = 1, + ES325_PRESET_VOIP_DESKTOP = 2, + ES325_PRESET_ASRA_DESKTOP = 3, + ES325_PRESET_VOIP_HEADSET = 4, + ES325_PRESET_ASRA_HEADSET = 5, + ES325_PRESET_VOIP_HEADPHONES = 6, + ES325_PRESET_VOIP_HP_DESKTOP = 7, + ES325_PRESET_CAMCORDER = 8, +}; + +#ifdef __cplusplus +extern "C" { +#endif + + int eS325_UsePreset(int preset); + + int eS325_SetVeq(bool enable); + + /* + * Sets the IO handle for the current input stream, or ADNC_IO_HANDLE_NONE when stream is + * stopped. + */ + int eS325_SetActiveIoHandle(audio_io_handle_t handle); + + int eS325_AddEffect(effect_descriptor_t * descr, audio_io_handle_t handle); + + int eS325_RemoveEffect(effect_descriptor_t * descr, audio_io_handle_t handle); + + int eS325_Release(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/audio/mixer_paths.xml b/audio/mixer_paths.xml new file mode 100644 index 0000000..7727be9 --- /dev/null +++ b/audio/mixer_paths.xml @@ -0,0 +1,409 @@ +<mixer> +<!-- +INOUT_MAP { + <ctl name="Earpiece", "Builtin Mic", "Back Mic" /> + <ctl name="Speaker", "Back Mic", "Third Mic" /> + <ctl name="Headset Out", "Headset In" /> + <ctl name="Headphone", "Builtin Mic" /> + <ctl name="SCO Headset Out", "SCO Headset In" /> + <ctl name="SCO", "SCO Headset In" /> + <ctl name="SCO Carkit", "SCO Headset In" /> +} + +INPUT_CHANNEL_MAP { + <ctl name="Builtin Mic", "Left" /> + <ctl name="Back Mic", "Right" /> + <ctl name="Headset In", "Left" /> + <ctl name="Third Mic", "Left" /> + <ctl name="SCO Headset In" value="None" /> +} +--> + + <!-- Initial mixer settings --> + + <!-- Noise gate control --> + <ctl name="Noise Gate Switch" value="0" />, + <ctl name="HPOUT1L NG HPOUT1L Switch" value="0" /> + <ctl name="HPOUT1R NG HPOUT1R Switch" value="0" /> + <ctl name="HPOUT2L NG HPOUT2L Switch" value="0" /> + <ctl name="HPOUT2R NG HPOUT2R Switch" value="0" /> + <ctl name="EPOUT NG EPOUT Switch" value="0" /> + <ctl name="SPKOUTL NG SPKOUTL Switch" value="0" /> + <ctl name="SPKOUTR NG SPKOUTR Switch" value="0" /> + <ctl name="SPKDAT1L NG SPKDAT1L Switch" value="0" /> + <ctl name="SPKDAT1R NG SPKDAT1R Switch" value="0" /> + <ctl name="Noise Gate Threshold Volume" value="0" /> + + <!-- Analog output AMP --> + <!-- AP Side is mixed to Input 1 of each out mixer --> + <!-- RCV(Mono) --> + <ctl name="EPOUT Input 1" value="AIF1RX1" /> + <ctl name="EPOUT Input 2" value="AIF1RX2" /> + <ctl name="EPOUT Digital Switch" value="1" /> + + <!-- SPK(Mono) --> + <ctl name="SPKOUTL Input 1" value="AIF1RX1" /> + <ctl name="SPKOUTL Input 2" value="AIF1RX2" /> + <ctl name="Speaker Digital Switch" value="1" /> + + <!-- HP(stereo) --> + <ctl name="HPOUT1L Input 1" value="AIF1RX1" /> + <ctl name="HPOUT1R Input 1" value="AIF1RX2" /> + <ctl name="HPOUT1 Digital Switch" value="1" /> + + <!-- VPS(stereo) --> + <ctl name="HPOUT2L Input 1" value="AIF1RX1" /> + <ctl name="HPOUT2R Input 1" value="AIF1RX2" /> + <ctl name="OUT2 Digital Switch" value="1" /> + + <!-- BT <-AP(use input 1) --> + <!-- ASRC2(RX domain) --> + <ctl name="ASRC2L Input" value="AIF2RX1" /> + <ctl name="ASRC2R Input" value="AIF2RX2" /> + + <!-- Currently use i2c dual mono(both L/R) --> + <!-- CP->RCV --> + <ctl name="EPOUT Input 3" value="None" /> + + <!-- CP->SPK --> + <ctl name="SPKOUTL Input 3" value="None" /> + + <!-- CP->HP --> + <ctl name="HPOUT1L Input 2" value="None" /> + <ctl name="HPOUT1R Input 2" value="None" /> + + <!-- CP->BT --> + <ctl name="AIF3TX1 Input 2" value="AIF2RX1" /> + <ctl name="AIF3TX2 Input 2" value="AIF2RX2" /> + + <!-- Route all mics via LHPF1 --> + <!-- need to move modifier field --> + <ctl name="LHPF1 Mode" value="High-pass" /> + <ctl name="LHPF2 Mode" value="High-pass" /> + + <!-- BT mic->CP --> + <ctl name="AIF2TX1 Input 2" value="AIF3RX1" /> + <ctl name="AIF2TX2 Input 2" value="AIF3RX2" /> + + <!-- Stereo recording from mics --> + <!-- need to move channeltype --> + + <!-- Gain for main and headset mics --> + <ctl name="IN1L Volume" value="30" /> + <ctl name="IN1R Volume" value="30" /> + + <!-- Gain for sub and 3rd mic --> + <ctl name="IN2L Volume" value="30" /> + <ctl name="IN2R Volume" value="30" /> + + <!-- Mics to AIF2TX --> + <ctl name="ASRC1L Input" value="LHPF1" /> + <ctl name="ASRC1R Input" value="LHPF2" /> + <ctl name="AIF2TX1 Input 1" value="ASRC1L" /> + <ctl name="AIF2TX2 Input 1" value="ASRC1R" /> + + <!-- BT<-CP(use input 2) --> + <ctl name="AIF1TX1 Input 2" value="ASRC2L" /> + <ctl name="AIF1TX2 Input 2" value="ASRC2R" /> + + <!-- LHPF1 & 2 filter --> + <ctl name="LHPF1 COEFF FILTER" value="130Hz" /> + <ctl name="LHPF2 COEFF FILTER" value="130Hz" /> + + <!-- common digital volume --> + <!-- don't change this common volume --> + <ctl name="AIF1TX1 Input 1 Volume" value="32" /> + <ctl name="AIF1TX1 Input 2 Volume" value="32" /> + <ctl name="AIF1TX1 Input 3 Volume" value="32" /> + <ctl name="AIF1TX1 Input 4 Volume" value="32" /> + <ctl name="AIF1TX2 Input 1 Volume" value="32" /> + <ctl name="AIF1TX2 Input 2 Volume" value="32" /> + <ctl name="AIF1TX2 Input 3 Volume" value="32" /> + <ctl name="AIF1TX2 Input 4 Volume" value="32" /> + <ctl name="AIF1TX3 Input 1 Volume" value="32" /> + <ctl name="AIF1TX3 Input 2 Volume" value="32" /> + <ctl name="AIF1TX3 Input 3 Volume" value="32" /> + <ctl name="AIF1TX3 Input 4 Volume" value="32" /> + <ctl name="AIF1TX4 Input 1 Volume" value="32" /> + <ctl name="AIF1TX4 Input 2 Volume" value="32" /> + <ctl name="AIF1TX4 Input 3 Volume" value="32" /> + <ctl name="AIF1TX4 Input 4 Volume" value="32" /> + <ctl name="AIF1TX5 Input 1 Volume" value="32" /> + <ctl name="AIF1TX5 Input 2 Volume" value="32" /> + <ctl name="AIF1TX5 Input 3 Volume" value="32" /> + <ctl name="AIF1TX5 Input 4 Volume" value="32" /> + <ctl name="AIF1TX6 Input 1 Volume" value="32" /> + <ctl name="AIF1TX6 Input 2 Volume" value="32" /> + <ctl name="AIF1TX6 Input 3 Volume" value="32" /> + <ctl name="AIF1TX6 Input 4 Volume" value="32" /> + <ctl name="AIF1TX7 Input 1 Volume" value="32" /> + <ctl name="AIF1TX7 Input 2 Volume" value="32" /> + <ctl name="AIF1TX7 Input 3 Volume" value="32" /> + <ctl name="AIF1TX7 Input 4 Volume" value="32" /> + <ctl name="AIF1TX8 Input 1 Volume" value="32" /> + <ctl name="AIF1TX8 Input 2 Volume" value="32" /> + <ctl name="AIF1TX8 Input 3 Volume" value="32" /> + <ctl name="AIF1TX8 Input 4 Volume" value="32" /> + <ctl name="AIF2TX1 Input 1 Volume" value="32" /> + <ctl name="AIF2TX1 Input 2 Volume" value="32" /> + <ctl name="AIF2TX1 Input 3 Volume" value="32" /> + <ctl name="AIF2TX1 Input 4 Volume" value="32" /> + <ctl name="AIF2TX2 Input 1 Volume" value="32" /> + <ctl name="AIF2TX2 Input 2 Volume" value="32" /> + <ctl name="AIF2TX2 Input 3 Volume" value="32" /> + <ctl name="AIF2TX2 Input 4 Volume" value="32" /> + <ctl name="AIF3TX1 Input 1 Volume" value="32" /> + <ctl name="AIF3TX1 Input 2 Volume" value="32" /> + <ctl name="AIF3TX1 Input 3 Volume" value="32" /> + <ctl name="AIF3TX1 Input 4 Volume" value="32" /> + <ctl name="AIF3TX2 Input 1 Volume" value="32" /> + <ctl name="AIF3TX2 Input 2 Volume" value="32" /> + <ctl name="AIF3TX2 Input 3 Volume" value="32" /> + <ctl name="AIF3TX2 Input 4 Volume" value="32" /> + + <ctl name="Input Ramp Up" value="8ms/6dB" /> + + <ctl name="RCV Switch" value="0" /> + <ctl name="SPK Switch" value="0" /> + <ctl name="HP Switch" value="0" /> + <ctl name="VPS Switch" value="0" /> + <ctl name="HDMI Switch" value="0" /> + <ctl name="Main Mic Switch" value="0" /> + <ctl name="Sub Mic Switch" value="0" /> + <ctl name="3rd Mic Switch" value="0" /> + <ctl name="Headset Mic Switch" value="0" /> + + <ctl name="AIF2 Mode" value="Master" /> + + <!-- Channels --> + + <path name="channel-left"> + <ctl name="AIF1TX1 Input 1" value="LHPF1" /> + <ctl name="AIF1TX2 Input 1" value="LHPF1" /> + <ctl name="ASRC1L Input" value="LHPF1" /> + <ctl name="ASRC1R Input" value="LHPF1" /> + </path> + + <path name="channel-right"> + <ctl name="AIF1TX1 Input 1" value="LHPF2" /> + <ctl name="AIF1TX2 Input 1" value="LHPF2" /> + <ctl name="ASRC1L Input" value="LHPF2" /> + <ctl name="ASRC1R Input" value="LHPF2" /> + </path> + + <path name="channel-stereo"> + <ctl name="AIF1TX1 Input 1" value="LHPF1" /> + <ctl name="AIF1TX2 Input 1" value="LHPF2" /> + <ctl name="ASRC1L Input" value="LHPF1" /> + <ctl name="ASRC1R Input" value="LHPF2" /> + </path> + + <path name="channel-none"> + <ctl name="AIF3TX1 Input 1" value="ASRC1L" /> + <ctl name="AIF3TX2 Input 1" value="ASRC1R" /> + <ctl name="ASRC1L Input" value="AIF1RX1" /> + <ctl name="ASRC1R Input" value="AIF1RX2" /> + </path> + + <!-- Paths that roughly correspond to devices --> + + <path name="speaker"> + <ctl name="SPK Switch" value="1" /> + </path> + + <path name="earpiece"> + <ctl name="RCV Switch" value="1" /> + </path> + + <path name="headphones"> + <ctl name="HP Switch" value="1" /> + </path> + + <path name="sco-out"> + <ctl name="AIF3TX1 Input 2" value="AIF2RX1" /> + <ctl name="AIF3TX2 Input 2" value="AIF2RX2" /> + </path> + + <path name="dock"> + <ctl name="VPS Switch" value="1" /> + </path> + + <path name="aux-digital"> + <ctl name="HDMI Switch" value="1" /> + </path> + + <path name="aif2-stereo-mic"> + <ctl name="AIF2TX1 Input 1" value="ASRC1L" /> + <ctl name="AIF2TX2 Input 1" value="ASRC1R" /> + </path> + + <path name="builtin-mic"> + <ctl name="Main Mic Switch" value="1" /> + <ctl name="LHPF1 Input 1" value="IN1L" /> + <ctl name="IN1L Volume" value="18" /> + <ctl name="IN1L Digital Volume" value="150" /> + </path> + + <path name="back-mic"> + <ctl name="Sub Mic Switch" value="1" /> + <ctl name="LHPF2 Input 1" value="IN2L" /> + <ctl name="IN2L Volume" value="17" /> + <ctl name="IN2L Digital Volume" value="150" /> + </path> + + <path name="third-mic"> + <ctl name="3rd Mic Switch" value="1" /> + <ctl name="LHPF1 Input 1" value="IN2R" /> + <ctl name="IN2R Volume" value="20" /> + <ctl name="IN2R Digital Volume" value="150" /> + </path> + + <path name="headset-in"> + <ctl name="Headset Mic Switch" value="1" /> + <ctl name="HPOUT1L Input 3" value="None" /> + <ctl name="HPOUT1R Input 3" value="None" /> + <ctl name="LHPF1 Input 1" value="IN1R" /> + <ctl name="IN1R Volume" value="30" /> + <ctl name="IN1R Digital Volume" value="150" /> + </path> + + <path name="sco-in"> + <ctl name="AIF2TX1 Input 2" value="AIF3RX1" /> + <ctl name="AIF2TX2 Input 2" value="AIF3RX2" /> + <ctl name="ASRC2L Input" value="AIF3RX1" /> + <ctl name="ASRC2R Input" value="AIF3RX2" /> + <ctl name="AIF2TX1 Input 1" value="None" /> + <ctl name="AIF2TX2 Input 1" value="None" /> + </path> + + <!-- Paths used by HAL --> + + <!-- Playback paths --> + <path name="voice-speaker"> + <path name="speaker" /> + <ctl name="AIF2 Mode" value="Slave" /> + <ctl name="SPKOUTL Input 3" value="ASRC2L" /> + </path> + + <path name="voice-earpiece"> + <path name="earpiece" /> + <ctl name="AIF2 Mode" value="Slave" /> + <ctl name="EPOUT Input 3" value="ASRC2L" /> + </path> + + <path name="voice-headphones"> + <path name="headphones" /> + <ctl name="AIF2 Mode" value="Slave" /> + <ctl name="HPOUT1L Input 2" value="ASRC2L" /> + <ctl name="HPOUT1R Input 2" value="ASRC2R" /> + </path> + + <path name="media-speaker"> + <path name="speaker" /> + </path> + + <path name="media-earpiece"> + <path name="earpiece" /> + </path> + + <path name="media-headphones"> + <path name="headphones" /> + </path> + + <path name="voice-rec-speaker"> + <path name="speaker" /> + </path> + + <path name="voice-rec-headphones"> + <path name="headphones" /> + </path> + + <path name="communication-speaker"> + <path name="speaker" /> + </path> + + <path name="communication-earpiece"> + <path name="earpiece" /> + </path> + + <path name="communication-headphones"> + <path name="headphones" /> + </path> + + <path name="speaker-and-headphones"> + <path name="speaker" /> + <path name="headphones" /> + </path> + + <path name="bt-sco-headset"> + <path name="sco-out" /> + <ctl name="AIF2 Mode" value="Slave" /> + </path> + + <!-- Capture paths --> + + <path name="voice-main-mic"> + <path name="channel-stereo" /> + <path name="aif2-stereo-mic" /> + <path name="builtin-mic" /> + <path name="back-mic" /> + </path> + + <path name="voice-headset-mic"> + <path name="channel-left" /> + <path name="aif2-stereo-mic" /> + <path name="headset-in" /> + </path> + + <path name="media-main-mic"> + <path name="channel-left" /> + <path name="aif2-stereo-mic" /> + <path name="builtin-mic" /> + </path> + + <path name="media-second-mic"> + <path name="channel-right" /> + <path name="aif2-stereo-mic" /> + <path name="back-mic" /> + </path> + + <path name="media-headset-mic"> + <path name="channel-left" /> + <path name="aif2-stereo-mic" /> + <path name="headset-in" /> + </path> + + <path name="voice-rec-main-mic"> + <path name="channel-left" /> + <path name="aif2-stereo-mic" /> + <path name="builtin-mic" /> + </path> + + <path name="communication-main-mic"> + <path name="channel-left" /> + <path name="aif2-stereo-mic" /> + <path name="builtin-mic" /> + </path> + + <path name="bt-sco-mic"> + <path name="channel-none" /> + <path name="sco-in" /> + </path> + + <path name="voice-rec-headset-mic"> + <path name="channel-left" /> + <path name="aif2-stereo-mic" /> + <path name="headset-in" /> + </path> + + <path name="communication-headset-mic"> + <path name="channel-left" /> + <path name="aif2-stereo-mic" /> + <path name="headset-in" /> + </path> + + <path name="none"> + <!-- Empty path --> + </path> + +</mixer> diff --git a/audio/ril_interface.c b/audio/ril_interface.c new file mode 100644 index 0000000..4f0110a --- /dev/null +++ b/audio/ril_interface.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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 "audio_hw_primary" +/*#define LOG_NDEBUG 0*/ + +#include <dlfcn.h> +#include <stdlib.h> + +#include <utils/Log.h> +#include <cutils/properties.h> + +#include "ril_interface.h" + +#define VOLUME_STEPS_DEFAULT "5" +#define VOLUME_STEPS_PROPERTY "ro.config.vc_call_vol_steps" + +/* Function pointers */ +void *(*_ril_open_client)(void); +int (*_ril_close_client)(void *); +int (*_ril_connect)(void *); +int (*_ril_is_connected)(void *); +int (*_ril_disconnect)(void *); +int (*_ril_set_call_volume)(void *, enum ril_sound_type, int); +int (*_ril_set_call_audio_path)(void *, enum ril_audio_path); +int (*_ril_set_call_clock_sync)(void *, enum ril_clock_state); +int (*_ril_set_mute)(void *, int); +int (*_ril_set_two_mic_control)(void *, enum ril_two_mic_device, enum ril_two_mic_state); +int (*_ril_register_unsolicited_handler)(void *, int, void *); +int (*_ril_get_wb_amr)(void *, void *); + +/* Audio WB AMR callback */ +void (*_audio_set_wb_amr_callback)(void *, int); +void *callback_data = NULL; + +void ril_register_set_wb_amr_callback(void *function, void *data) +{ + _audio_set_wb_amr_callback = function; + callback_data = data; +} + +/* This is the callback function that the RIL uses to +set the wideband AMR state */ +static int ril_set_wb_amr_callback(void *ril_client, + const void *data, + size_t datalen) +{ + int enable = ((int *)data)[0]; + + if (!callback_data || !_audio_set_wb_amr_callback) + return -1; + + _audio_set_wb_amr_callback(callback_data, enable); + + return 0; +} + +static int ril_connect_if_required(struct ril_handle *ril) +{ + if (_ril_is_connected(ril->client)) + return 0; + + if (_ril_connect(ril->client) != RIL_CLIENT_ERR_SUCCESS) { + ALOGE("ril_connect() failed"); + return -1; + } + + /* get wb amr status to set pcm samplerate depending on + wb amr status when ril is connected. */ + if(_ril_get_wb_amr) + _ril_get_wb_amr(ril->client, ril_set_wb_amr_callback); + + return 0; +} + +int ril_open(struct ril_handle *ril) +{ + char property[PROPERTY_VALUE_MAX]; + + if (!ril) + return -1; + + ril->handle = dlopen(RIL_CLIENT_LIBPATH, RTLD_NOW); + + if (!ril->handle) { + ALOGE("Cannot open '%s'", RIL_CLIENT_LIBPATH); + return -1; + } + + _ril_open_client = dlsym(ril->handle, "OpenClient_RILD"); + _ril_close_client = dlsym(ril->handle, "CloseClient_RILD"); + _ril_connect = dlsym(ril->handle, "Connect_RILD"); + _ril_is_connected = dlsym(ril->handle, "isConnected_RILD"); + _ril_disconnect = dlsym(ril->handle, "Disconnect_RILD"); + _ril_set_call_volume = dlsym(ril->handle, "SetCallVolume"); + _ril_set_call_audio_path = dlsym(ril->handle, "SetCallAudioPath"); + _ril_set_call_clock_sync = dlsym(ril->handle, "SetCallClockSync"); + _ril_set_mute = dlsym(ril->handle, "SetMute"); + _ril_set_two_mic_control = dlsym(ril->handle, "SetTwoMicControl"); + _ril_register_unsolicited_handler = dlsym(ril->handle, + "RegisterUnsolicitedHandler"); + /* since this function is not supported in all RILs, don't require it */ + _ril_get_wb_amr = dlsym(ril->handle, "GetWB_AMR"); + + if (!_ril_open_client || !_ril_close_client || !_ril_connect || + !_ril_is_connected || !_ril_disconnect || !_ril_set_call_volume || + !_ril_set_call_audio_path || !_ril_set_two_mic_control || !_ril_set_call_clock_sync || + !_ril_register_unsolicited_handler) { + ALOGE("Cannot get symbols from '%s'", RIL_CLIENT_LIBPATH); + dlclose(ril->handle); + return -1; + } + + ril->client = _ril_open_client(); + if (!ril->client) { + ALOGE("ril_open_client() failed"); + dlclose(ril->handle); + return -1; + } + + /* register the wideband AMR callback */ + _ril_register_unsolicited_handler(ril->client, RIL_UNSOL_WB_AMR_STATE, + ril_set_wb_amr_callback); + + property_get(VOLUME_STEPS_PROPERTY, property, VOLUME_STEPS_DEFAULT); + ril->volume_steps_max = atoi(property); + /* this catches the case where VOLUME_STEPS_PROPERTY does not contain + an integer */ + if (ril->volume_steps_max == 0) + ril->volume_steps_max = atoi(VOLUME_STEPS_DEFAULT); + + return 0; +} + +int ril_close(struct ril_handle *ril) +{ + if (!ril || !ril->handle || !ril->client) + return -1; + + if ((_ril_disconnect(ril->client) != RIL_CLIENT_ERR_SUCCESS) || + (_ril_close_client(ril->client) != RIL_CLIENT_ERR_SUCCESS)) { + ALOGE("ril_disconnect() or ril_close_client() failed"); + return -1; + } + + dlclose(ril->handle); + return 0; +} + +int ril_set_call_volume(struct ril_handle *ril, enum ril_sound_type sound_type, + float volume) +{ + if (ril_connect_if_required(ril)) + return 0; + + return _ril_set_call_volume(ril->client, sound_type, + (int)(volume * ril->volume_steps_max)); +} + +int ril_set_call_audio_path(struct ril_handle *ril, enum ril_audio_path path) +{ + if (ril_connect_if_required(ril)) + return 0; + + return _ril_set_call_audio_path(ril->client, path); +} + +int ril_set_call_clock_sync(struct ril_handle *ril, enum ril_clock_state state) +{ + if (ril_connect_if_required(ril)) + return 0; + + return _ril_set_call_clock_sync(ril->client, state); +} + +int ril_set_mute(struct ril_handle *ril, enum ril_mute_state state) +{ + if (ril_connect_if_required(ril)) + return 0; + + return _ril_set_mute(ril->client, state); +} + +int ril_set_two_mic_control(struct ril_handle *ril, enum ril_two_mic_device device, enum ril_two_mic_state state) +{ + if (ril_connect_if_required(ril)) + return 0; + + return _ril_set_two_mic_control(ril->client, device, state); +} diff --git a/audio/ril_interface.h b/audio/ril_interface.h new file mode 100644 index 0000000..697d04e --- /dev/null +++ b/audio/ril_interface.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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 RIL_INTERFACE_H +#define RIL_INTERFACE_H + +#define RIL_CLIENT_LIBPATH "libsecril-client.so" + +#define RIL_CLIENT_ERR_SUCCESS 0 +#define RIL_CLIENT_ERR_AGAIN 1 +#define RIL_CLIENT_ERR_INIT 2 // Client is not initialized +#define RIL_CLIENT_ERR_INVAL 3 // Invalid value +#define RIL_CLIENT_ERR_CONNECT 4 // Connection error +#define RIL_CLIENT_ERR_IO 5 // IO error +#define RIL_CLIENT_ERR_RESOURCE 6 // Resource not available +#define RIL_CLIENT_ERR_UNKNOWN 7 + +#define RIL_OEM_UNSOL_RESPONSE_BASE 11000 // RIL response base index +#define RIL_UNSOL_WB_AMR_STATE \ + (RIL_OEM_UNSOL_RESPONSE_BASE + 17) // RIL AMR state index + +struct ril_handle +{ + void *handle; + void *client; + int volume_steps_max; +}; + +enum ril_sound_type { + SOUND_TYPE_VOICE, + SOUND_TYPE_SPEAKER, + SOUND_TYPE_HEADSET, + SOUND_TYPE_BTVOICE +}; + +enum ril_audio_path { + SOUND_AUDIO_PATH_HANDSET, + SOUND_AUDIO_PATH_HEADSET, + SOUND_AUDIO_PATH_SPEAKER, + SOUND_AUDIO_PATH_BLUETOOTH, + SOUND_AUDIO_PATH_BLUETOOTH_NO_NR, + SOUND_AUDIO_PATH_HEADPHONE +}; + +enum ril_clock_state { + SOUND_CLOCK_STOP, + SOUND_CLOCK_START +}; + +enum ril_mute_state { + TX_UNMUTE, + TX_MUTE, + RX_UNMUTE, + RX_MUTE, + RXTX_UNMUTE, + RXTX_MUTE +}; + +enum ril_two_mic_device { + AUDIENCE, + FORTEMEDIA +}; + +enum ril_two_mic_state { + TWO_MIC_SOLUTION_OFF, + TWO_MIC_SOLUTION_ON +}; + +/* Function prototypes */ +int ril_open(struct ril_handle *ril); +int ril_close(struct ril_handle *ril); +int ril_set_call_volume(struct ril_handle *ril, enum ril_sound_type sound_type, + float volume); +int ril_set_call_audio_path(struct ril_handle *ril, enum ril_audio_path path); +int ril_set_call_clock_sync(struct ril_handle *ril, enum ril_clock_state state); +int ril_set_mute(struct ril_handle *ril, enum ril_mute_state state); +void ril_register_set_wb_amr_callback(void *function, void *data); +int ril_set_two_mic_control(struct ril_handle *ril, enum ril_two_mic_device device, enum ril_two_mic_state state); + +#endif diff --git a/audio/routing.h b/audio/routing.h new file mode 100644 index 0000000..46d027c --- /dev/null +++ b/audio/routing.h @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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 _ROUTING_H_ +#define _ROUTING_H_ + +#include "eS325VoiceProcessing.h" + +enum { + OUT_DEVICE_SPEAKER, + OUT_DEVICE_EARPIECE, + OUT_DEVICE_HEADSET, + OUT_DEVICE_HEADPHONES, + OUT_DEVICE_BT_SCO, + OUT_DEVICE_SPEAKER_AND_HEADSET, + OUT_DEVICE_SPEAKER_AND_EARPIECE, + OUT_DEVICE_TAB_SIZE, /* number of rows in route_configs[][] */ + OUT_DEVICE_NONE, + OUT_DEVICE_CNT +}; + +enum { + IN_SOURCE_MIC, + IN_SOURCE_CAMCORDER, + IN_SOURCE_VOICE_RECOGNITION, + IN_SOURCE_VOICE_COMMUNICATION, + IN_SOURCE_VOICE_CALL, + IN_SOURCE_TAB_SIZE, /* number of lines in route_configs[][] */ + IN_SOURCE_NONE, + IN_SOURCE_CNT +}; + +enum { + ES325_MODE_DEFAULT, + ES325_MODE_LEVEL, + ES325_NUM_MODES, +}; + +struct route_config { + const char * const output_route; + const char * const input_route; + int es325_preset[ES325_NUM_MODES]; // es325 preset for this route. + // -1 means es325 bypass +}; + +/* TODO: Figure out whether voice routes need to set ES325 presets */ +const struct route_config voice_speaker = { + "voice-speaker", + "voice-main-mic", + { ES325_PRESET_OFF, + ES325_PRESET_OFF } +}; + +const struct route_config voice_earpiece = { + "voice-earpiece", + "voice-main-mic", + { ES325_PRESET_OFF, + ES325_PRESET_OFF } +}; + +const struct route_config voice_headphones = { + "voice-headphones", + "voice-main-mic", + { ES325_PRESET_OFF, + ES325_PRESET_OFF } +}; + +const struct route_config voice_headset = { + "voice-headphones", + "voice-headset-mic", + { ES325_PRESET_OFF, + ES325_PRESET_OFF } +}; + +const struct route_config media_speaker = { + "media-speaker", + "media-main-mic", + { ES325_PRESET_OFF, + ES325_PRESET_OFF } +}; + +const struct route_config media_earpiece = { + "media-earpiece", + "media-main-mic", + { ES325_PRESET_OFF, + ES325_PRESET_OFF } +}; + +const struct route_config media_headphones = { + "media-headphones", + "media-main-mic", + { ES325_PRESET_OFF, + ES325_PRESET_OFF } +}; + +const struct route_config media_headset = { + "media-headphones", + "media-headset-mic", + { ES325_PRESET_OFF, + ES325_PRESET_OFF } +}; + +const struct route_config camcorder_speaker = { + "media-speaker", + "media-second-mic", + { ES325_PRESET_CAMCORDER, + ES325_PRESET_CAMCORDER } +}; + +const struct route_config camcorder_headphones = { + "media-headphones", + "media-second-mic", + { ES325_PRESET_CAMCORDER, + ES325_PRESET_CAMCORDER } +}; + +const struct route_config voice_rec_speaker = { + "voice-rec-speaker", + "voice-rec-main-mic", + { ES325_PRESET_ASRA_HANDHELD, + ES325_PRESET_ASRA_DESKTOP } +}; + +const struct route_config voice_rec_headphones = { + "voice-rec-headphones", + "voice-rec-main-mic", + { ES325_PRESET_ASRA_HANDHELD, + ES325_PRESET_ASRA_DESKTOP } +}; + +const struct route_config voice_rec_headset = { + "voice-rec-headphones", + "voice-rec-headset-mic", + { ES325_PRESET_ASRA_HEADSET, + ES325_PRESET_ASRA_HEADSET } +}; + +const struct route_config communication_speaker = { + "communication-speaker", + "communication-main-mic", + { ES325_PRESET_VOIP_HANDHELD, + ES325_PRESET_VOIP_DESKTOP } +}; + +const struct route_config communication_earpiece = { + "communication-earpiece", + "communication-main-mic", + { ES325_PRESET_OFF, + ES325_PRESET_OFF } +}; + +const struct route_config communication_headphones = { + "communication-headphones", + "communication-main-mic", + { ES325_PRESET_VOIP_HEADPHONES, + ES325_PRESET_VOIP_HP_DESKTOP} +}; + +const struct route_config communication_headset = { + "communication-headphones", + "communication-headset-mic", + { ES325_PRESET_VOIP_HEADSET, + ES325_PRESET_VOIP_HEADSET } +}; + +const struct route_config speaker_and_headphones = { + "speaker-and-headphones", + "main-mic", + { ES325_PRESET_CURRENT, + ES325_PRESET_CURRENT } +}; + +const struct route_config bluetooth_sco = { + "bt-sco-headset", + "bt-sco-mic", + { ES325_PRESET_OFF, + ES325_PRESET_OFF } +}; + +const struct route_config none = { + "none", + "none", + { ES325_PRESET_OFF, + ES325_PRESET_OFF } +}; + +const struct route_config * const route_configs[IN_SOURCE_TAB_SIZE] + [OUT_DEVICE_TAB_SIZE] = { + { /* IN_SOURCE_MIC */ + &media_speaker, /* OUT_DEVICE_SPEAKER */ + &media_earpiece, /* OUT_DEVICE_EARPIECE */ + &media_headset, /* OUT_DEVICE_HEADSET */ + &media_headphones, /* OUT_DEVICE_HEADPHONES */ + &bluetooth_sco, /* OUT_DEVICE_BT_SCO */ + &speaker_and_headphones, /* OUT_DEVICE_SPEAKER_AND_HEADSET */ + &media_speaker /* OUT_DEVICE_SPEAKER_AND_EARPIECE */ + }, + { /* IN_SOURCE_CAMCORDER */ + &camcorder_speaker, /* OUT_DEVICE_SPEAKER */ + &none, /* OUT_DEVICE_EARPIECE */ + &camcorder_headphones, /* OUT_DEVICE_HEADSET */ + &camcorder_headphones, /* OUT_DEVICE_HEADPHONES */ + &bluetooth_sco, /* OUT_DEVICE_BT_SCO */ + &speaker_and_headphones, /* OUT_DEVICE_SPEAKER_AND_HEADSET */ + &camcorder_speaker /* OUT_DEVICE_SPEAKER_AND_EARPIECE */ + }, + { /* IN_SOURCE_VOICE_RECOGNITION */ + &voice_rec_speaker, /* OUT_DEVICE_SPEAKER */ + &none, /* OUT_DEVICE_EARPIECE */ + &voice_rec_headset, /* OUT_DEVICE_HEADSET */ + &voice_rec_headphones, /* OUT_DEVICE_HEADPHONES */ + &bluetooth_sco, /* OUT_DEVICE_BT_SCO */ + &speaker_and_headphones, /* OUT_DEVICE_SPEAKER_AND_HEADSET */ + &voice_rec_speaker /* OUT_DEVICE_SPEAKER_AND_EARPIECE */ + }, + { /* IN_SOURCE_VOICE_COMMUNICATION */ + &communication_speaker, /* OUT_DEVICE_SPEAKER */ + &communication_earpiece, /* OUT_DEVICE_EARPIECE */ + &communication_headset, /* OUT_DEVICE_HEADSET */ + &communication_headphones, /* OUT_DEVICE_HEADPHONES */ + &bluetooth_sco, /* OUT_DEVICE_BT_SCO */ + &speaker_and_headphones, /* OUT_DEVICE_SPEAKER_AND_HEADSET */ + &communication_earpiece /* OUT_DEVICE_SPEAKER_AND_EARPIECE */ + }, + { /* IN_SOURCE_VOICE_CALL */ + &voice_speaker, /* OUT_DEVICE_SPEAKER */ + &voice_earpiece, /* OUT_DEVICE_EARPIECE */ + &voice_headset, /* OUT_DEVICE_HEADSET */ + &voice_headphones, /* OUT_DEVICE_HEADPHONES */ + &bluetooth_sco, /* OUT_DEVICE_BT_SCO */ + &voice_headphones, /* OUT_DEVICE_SPEAKER_AND_HEADSET */ + &voice_earpiece /* OUT_DEVICE_SPEAKER_AND_EARPIECE */ + }, +}; + +#endif diff --git a/camera/CameraWrapper.cpp b/camera/CameraWrapper.cpp index f593fcf..fe0c418 100644 --- a/camera/CameraWrapper.cpp +++ b/camera/CameraWrapper.cpp @@ -25,8 +25,8 @@ #define LOG_TAG "CameraWrapper" #include <cutils/log.h> -#include <sys/types.h> -#include <sys/stat.h> +//#include <sys/types.h> +//#include <sys/stat.h> #include <utils/threads.h> #include <utils/String8.h> @@ -35,7 +35,7 @@ #include <camera/Camera.h> #include <camera/CameraParameters.h> -#define CAMID_PATH "/data/CameraID.txt" +//#define CAMID_PATH "/data/CameraID.txt" static android::Mutex gCameraWrapperLock; static camera_module_t *gVendorModule = 0; @@ -83,36 +83,36 @@ typedef struct wrapper_camera_device { }) #define CAMERA_ID(device) (((wrapper_camera_device_t *)(device))->id) -static void fix_camera_id_permissions() -{ - FILE* camidfile; - int amode; - int ret = -1; - camidfile = fopen(CAMID_PATH, "w"); - if (camidfile == 0) { - fprintf(stderr, "open(%s) failed\n", CAMID_PATH); - ALOGE("Can't open %s\n", CAMID_PATH); - } else { - ALOGD("Setting permissions of %s\n", CAMID_PATH); - - /* write permissions for the file owner */ - amode = S_IWUSR; - ret = chmod(CAMID_PATH, amode); - - /* owner: media; group: system */ - char* chown_cmd = (char*) malloc(strlen("chown media ") + strlen(CAMID_PATH) + 1); - char* chgrp_cmd = (char*) malloc(strlen("chgrp system ") + strlen(CAMID_PATH) + 1); - sprintf(chown_cmd, "chown media %s", CAMID_PATH); - sprintf(chgrp_cmd, "chgrp system %s", CAMID_PATH); - system(chown_cmd); - system(chgrp_cmd); - - if (ret != 0) { - fprintf(stderr, "chmod() on file %s failed\n", CAMID_PATH); - ALOGE("Can't set permissions on %s\n", CAMID_PATH); - } - } -} +//static void fix_camera_id_permissions() +//{ +// FILE* camidfile; +// int amode; +// int ret = -1; +// camidfile = fopen(CAMID_PATH, "w"); +// if (camidfile == 0) { +// fprintf(stderr, "open(%s) failed\n", CAMID_PATH); +// ALOGE("Can't open %s\n", CAMID_PATH); +// } else { +// ALOGD("Setting permissions of %s\n", CAMID_PATH); + +// /* write permissions for the file owner */ +// amode = S_IWUSR; +// ret = chmod(CAMID_PATH, amode); + +// /* owner: media; group: system */ +// char* chown_cmd = (char*) malloc(strlen("chown media ") + strlen(CAMID_PATH) + 1); +// char* chgrp_cmd = (char*) malloc(strlen("chgrp system ") + strlen(CAMID_PATH) + 1); +// sprintf(chown_cmd, "chown media %s", CAMID_PATH); +// sprintf(chgrp_cmd, "chgrp system %s", CAMID_PATH); +// system(chown_cmd); +// system(chgrp_cmd); + +// if (ret != 0) { +// fprintf(stderr, "chmod() on file %s failed\n", CAMID_PATH); +// ALOGE("Can't set permissions on %s\n", CAMID_PATH); +// } +// } +//} static int check_vendor_module() { @@ -207,6 +207,7 @@ PRODUCT_PACKAGES += \ PRODUCT_PACKAGES += \ libMcClient \ libMcRegistry \ + libPaApi \ libgdmcprov \ mcDriverDaemon @@ -218,10 +219,14 @@ PRODUCT_PACKAGES += \ # OMX PRODUCT_PACKAGES += \ - libcsc \ libExynosOMX_Core \ - libOMX.Exynos.MP3.Decoder \ - libstagefrighthw \ + libOMX.Exynos.MPEG4.Decoder \ + libOMX.Exynos.AVC.Decoder \ + libOMX.Exynos.MPEG4.Encoder \ + libOMX.Exynos.AVC.Encoder \ + libOMX.Exynos.VP8.Decoder \ + libOMX.Exynos.VP8.Encoder \ + libstagefrighthw # Permissions PRODUCT_COPY_FILES += \ @@ -280,9 +285,12 @@ PRODUCT_PACKAGES += \ init.recovery.universal5420.rc # Sensors -# PRODUCT_PACKAGES += \ -# sensors.universal5420 +PRODUCT_PACKAGES += \ + sensors.universal5420 +# Torch +PRODUCT_PACKAGES += \ + Torch # Wifi PRODUCT_COPY_FILES += \ $(LOCAL_PATH)/configs/wpa_supplicant.conf:system/etc/wifi/wpa_supplicant.conf \ diff --git a/include/hardware/gps.h b/include/hardware/gps.h index 672ca7d..6d4a4e3 100644 --- a/include/hardware/gps.h +++ b/include/hardware/gps.h @@ -453,20 +453,14 @@ typedef struct { /** set to sizeof(GpsSvInfo) */ size_t size; /** Pseudo-random number for the SV. */ - int prn; - /** Signal to noise ratio. */ float snr; - /** Elevation of SV in degrees. */ float elevation; - /** Azimuth of SV in degrees. */ float azimuth; - int used; - } GpsSvInfo; /** Represents SV status. */ @@ -495,7 +489,6 @@ typedef struct { * were used for computing the most recent position fix. */ uint32_t used_in_fix_mask; - } GpsSvStatus; @@ -506,9 +499,6 @@ typedef struct { uint16_t mcc; uint16_t mnc; uint16_t lac; -#ifdef AGPS_USE_PSC - uint16_t psc; -#endif uint32_t cid; } AGpsRefLocationCellID; @@ -1818,4 +1808,3 @@ typedef struct { __END_DECLS #endif /* ANDROID_INCLUDE_HARDWARE_GPS_H */ - diff --git a/include/telephony/ril.h b/include/telephony/ril.h index 14cb6c6..ea550af 100644 --- a/include/telephony/ril.h +++ b/include/telephony/ril.h @@ -1,4 +1,6 @@ /* + * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * Not a Contribution * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -4418,7 +4420,6 @@ typedef struct { #define RIL_REQUEST_GET_PREFERRED_NETWORK_LIST 10051 #define RIL_REQUEST_HANGUP_VT 10052 - /***********************************************************************/ diff --git a/overlay/frameworks/base/core/res/res/values/config.xml b/overlay/frameworks/base/core/res/res/values/config.xml index b92d711..a07ab45 100644 --- a/overlay/frameworks/base/core/res/res/values/config.xml +++ b/overlay/frameworks/base/core/res/res/values/config.xml @@ -34,43 +34,43 @@ does not require auto-restore. --> <!-- the 6th element indicates boot-time dependency-met value. --> <string-array name="networkAttributes"> - <item>"wifi,1,1,1,-1,true"</item> + <item>"wifi,1,1,1,-1,true"</item> <item>"mobile,0,0,0,-1,true"</item> - <item>"mobile_mms,2,0,2,240000,true"</item> + <item>"mobile_mms,2,0,2,60000,true"</item> <item>"mobile_supl,3,0,2,60000,true"</item> - <item>"mobile_dun,4,0,2,-1,true"</item> + <item>"mobile_dun,4,0,2,60000,true"</item> <item>"mobile_hipri,5,0,3,60000,true"</item> <item>"mobile_fota,10,0,2,60000,true"</item> - <item>"mobile_ims,11,0,2,-1,true"</item> + <item>"mobile_ims,11,0,2,60000,true"</item> <item>"mobile_cbs,12,0,2,60000,true"</item> <item>"wifi_p2p,13,1,0,-1,true"</item> - <item>"bluetooth,7,7,0,-1,true"</item> - <item>"mobile_ent1,28,0,2,-1,true"</item> - <item>"mobile_ent2,29,0,2,-1,true"</item> - <item>"mobile_bip,23,0,2,60000,true"</item> + <item>"mobile_ia,14,0,2,-1,true"</item> + <item>"mobile_emergency,15,0,2,-1,true"</item> + <item>"bluetooth,7,7,2,-1,true"</item> </string-array> <!-- An Array of "[ConnectivityManager connectionType], [# simultaneous connection types]" --> <string-array translatable="false" name="radioAttributes"> - <item>"1,1"</item> - <item>"0,1"</item> + <item>"1,1"</item> + <item>"0,1"</item> + <item>"7,1"</item> </string-array> <!-- List of regexpressions describing the interface (if any) that represent tetherable USB interfaces. If the device doesn't want to support tething over USB this should be empty. An example would be "usb.*" --> <string-array translatable="false" name="config_tether_usb_regexs"> - <item>rndis\\d</item> - <item>usb\\d</item> - <item>ncm\\d</item> + <item>"rndis\\d"</item> + <item>"usb\\d"</item> </string-array> <!-- List of regexpressions describing the interface (if any) that represent tetherable Wifi interfaces. If the device doesn't want to support tethering over Wifi this should be empty. An example would be "softap.*" --> <string-array translatable="false" name="config_tether_wifi_regexs"> - <item>wlan0</item> + <item>"wlan0"</item> + <item>"softap.*"</item> </string-array> <!-- List of regexpressions describing the interface (if any) that represent tetherable diff --git a/overlay/packages/apps/Phone/res/values/config.xml b/overlay/packages/apps/Phone/res/values/config.xml new file mode 100644 index 0000000..62bbaef --- /dev/null +++ b/overlay/packages/apps/Phone/res/values/config.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 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. +--> + +<!-- Phone app resources that may need to be customized + for different hardware or product builds. --> +<resources> + <!-- Determines if device implements a noise suppression device for in call audio--> + <bool name="has_in_call_noise_suppression">true</bool> + + <!-- Audio parameter for setting noise suppression--> + <string name="in_call_noise_suppression_audioparameter">noise_suppression=true=false</string> +</resources> diff --git a/proprietary-files.txt b/proprietary-files.txt index 0c38efb..65be332 100644 --- a/proprietary-files.txt +++ b/proprietary-files.txt @@ -192,4 +192,4 @@ etc/wifi/nvram_net.txt_wisol # Input (not exist anymore) # usr/idc/sec_e-pen.idc -# usr/idc/sec_touchscreen.idc
\ No newline at end of file +# usr/idc/sec_touchscreen.idc |
