mirror of
https://github.com/team-infusion-developers/android_hardware_samsung.git
synced 2024-11-06 21:55:41 +00:00
audio: Add support for Audience EarSmart ICs
Some devices (often T-Mobile variants) have extra hardware for incall audio processing. Audio must be routed to the ES IC properly so it can be passed to ALSA, otherwise the RX/TX streams are lost. Change-Id: Ib29c747d5728a09726e14bab00f26ad273400aba
This commit is contained in:
parent
68f8fb65aa
commit
0fdef0cbd6
6 changed files with 291 additions and 0 deletions
|
@ -21,6 +21,7 @@ include $(CLEAR_VARS)
|
|||
LOCAL_ARM_MODE := arm
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
audience.c \
|
||||
audio_hw.c \
|
||||
compress_offload.c \
|
||||
ril_interface.c \
|
||||
|
|
192
audio/audience.c
Normal file
192
audio/audience.c
Normal file
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Copyright (C) 2017 Christopher N. Hesse <raymanfx@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_audience"
|
||||
#define LOG_NDEBUG 0
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <cutils/log.h>
|
||||
#include <audience-routes.h>
|
||||
|
||||
#include "audience.h"
|
||||
|
||||
/*
|
||||
* Writes an Integer to a file.
|
||||
*
|
||||
* @param path The absolute path string.
|
||||
* @param value The Integer value to be written.
|
||||
* @return 0 on success, -1 or errno on error.
|
||||
*/
|
||||
static int write_int(char const *path, const int value)
|
||||
{
|
||||
int fd;
|
||||
static int already_warned;
|
||||
|
||||
already_warned = 0;
|
||||
|
||||
ALOGV("write_int: path %s, value %d", path, value);
|
||||
fd = open(path, O_RDWR);
|
||||
|
||||
if (fd >= 0) {
|
||||
char buffer[20];
|
||||
int bytes = sprintf(buffer, "%d\n", value);
|
||||
int amt = write(fd, buffer, bytes);
|
||||
close(fd);
|
||||
return amt == -1 ? -errno : 0;
|
||||
} else {
|
||||
if (already_warned == 0) {
|
||||
ALOGE("write_int failed to open %s\n", path);
|
||||
already_warned = 1;
|
||||
}
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes the route value to sysfs.
|
||||
*
|
||||
* @param value The long Integer value to be written.
|
||||
* @return 0 on success, -1 or errno on error.
|
||||
*/
|
||||
static int es_route_value_set(int value)
|
||||
{
|
||||
return write_int(SYSFS_PATH_PRESET, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes the veq control to sysfs.
|
||||
*
|
||||
* @param value The Integer value to be written.
|
||||
* @return 0 on success, -1 or errno on error.
|
||||
*/
|
||||
static int es_veq_control_set(int value)
|
||||
{
|
||||
return write_int(SYSFS_PATH_VEQ, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes the extra volume to sysfs.
|
||||
*
|
||||
* @param value The Integer value to be written.
|
||||
* @return 0 on success, -1 or errno on error.
|
||||
*/
|
||||
static int es_extra_volume_set(int value)
|
||||
{
|
||||
return write_int(SYSFS_PATH_EXTRAVOLUME, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convertes an out_device from the session to an earSmart compatible route.
|
||||
*
|
||||
* @param out_device The output device to be converted.
|
||||
* @return Audience earSmart route, coded as long Integer.
|
||||
*/
|
||||
static long es_device_to_route(struct voice_session *session)
|
||||
{
|
||||
long ret;
|
||||
long nb_route;
|
||||
long wb_route;
|
||||
|
||||
switch(session->out_device) {
|
||||
case AUDIO_DEVICE_OUT_EARPIECE:
|
||||
nb_route = Call_CT_NB;
|
||||
wb_route = Call_CT_WB;
|
||||
break;
|
||||
case AUDIO_DEVICE_OUT_SPEAKER:
|
||||
nb_route = Call_FT_NB;
|
||||
wb_route = Call_FT_WB;
|
||||
break;
|
||||
case AUDIO_DEVICE_OUT_WIRED_HEADSET:
|
||||
case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
|
||||
nb_route = Call_HS_NB;
|
||||
wb_route = Call_HS_WB;
|
||||
break;
|
||||
case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
|
||||
case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
|
||||
case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
|
||||
nb_route = Call_BT_NB;
|
||||
wb_route = Call_BT_WB;
|
||||
break;
|
||||
default:
|
||||
/* if output device isn't supported, use earpiece by default */
|
||||
nb_route = Call_CT_NB;
|
||||
wb_route = Call_CT_WB;
|
||||
break;
|
||||
}
|
||||
|
||||
/* TODO: Handle wb_amr=2 */
|
||||
if (session->wb_amr_type >= 1) {
|
||||
ret = wb_route;
|
||||
} else {
|
||||
ret = nb_route;
|
||||
}
|
||||
|
||||
ALOGV("%s: converting out_device=%d to %s route: %ld", __func__, session->out_device,
|
||||
ret == wb_route ? "Wide Band" : "Narrow Band", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configures and enables the Audience earSmart IC.
|
||||
*
|
||||
* @param session Reference to the active voice call session.
|
||||
* @return @return 0 on success, -1 or errno on error.
|
||||
*/
|
||||
int es_start_voice_session(struct voice_session *session)
|
||||
{
|
||||
int ret;
|
||||
long es_route = es_device_to_route(session);
|
||||
|
||||
/* TODO: Calculate these */
|
||||
int extra_volume = 0;
|
||||
int veq_control = 4;
|
||||
|
||||
/*
|
||||
* The control flow for audience earSmart chip is as follows:
|
||||
*
|
||||
* route_value >> power_control(internal) >> extra_volume >> veq_control
|
||||
*/
|
||||
ret = es_route_value_set(es_route);
|
||||
if (ret != 0) {
|
||||
ALOGE("%s: es_route_value_set(%ld) failed with code: %d", __func__, es_route, ret);
|
||||
goto exit;
|
||||
}
|
||||
ret = es_extra_volume_set(extra_volume);
|
||||
if (ret != 0) {
|
||||
ALOGE("%s: es_extra_volume_set(%d) failed with code: %d", __func__, extra_volume, ret);
|
||||
goto exit;
|
||||
}
|
||||
ret = es_veq_control_set(veq_control);
|
||||
if (ret != 0) {
|
||||
ALOGE("%s: es_veq_control_set(%d) failed with code: %d", __func__, veq_control, ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disables the Audience earSmart IC.
|
||||
*/
|
||||
void es_stop_voice_session()
|
||||
{
|
||||
/* This will cancel any pending workers, stop the stream and send the IC to sleep */
|
||||
es_route_value_set(AUDIENCE_SLEEP);
|
||||
}
|
29
audio/audience.h
Normal file
29
audio/audience.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) 2017 Christopher N. Hesse <raymanfx@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.
|
||||
*/
|
||||
|
||||
#include "audio_hw.h"
|
||||
#include "voice.h"
|
||||
|
||||
enum es_power_state {
|
||||
ES_POWER_FW_LOAD,
|
||||
ES_POWER_SLEEP,
|
||||
ES_POWER_SLEEP_PENDING,
|
||||
ES_POWER_AWAKE,
|
||||
ES_MAX = ES_POWER_AWAKE
|
||||
};
|
||||
|
||||
int es_start_voice_session(struct voice_session *session);
|
||||
void es_stop_voice_session();
|
48
audio/include/audience-routes.h
Normal file
48
audio/include/audience-routes.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (C) 2017 Christopher N. Hesse <raymanfx@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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTICE
|
||||
*
|
||||
* This must be kept in sync with the kernel API, for exmaple
|
||||
* "es705-routes.h" for the Galaxy Note 5 (N920T) with its ES804 IC.
|
||||
*/
|
||||
|
||||
#define SYSFS_PATH_POWERCTRL "/sys/class/earsmart/control/power_control_set"
|
||||
#define SYSFS_PATH_PRESET "/sys/class/earsmart/control/route_value"
|
||||
#define SYSFS_PATH_VEQ "/sys/class/earsmart/control/veq_control_set"
|
||||
#define SYSFS_PATH_EXTRAVOLUME "/sys/class/earsmart/control/extra_volume"
|
||||
#define Call_HS_NB 0 /* Call, Headset, Narrow Band */
|
||||
#define Call_FT_NB 1 /* Call, Far Talk, Narrow Band */
|
||||
#define Call_CT_NB 2 /* Call, Close Talk, Narrow Band */
|
||||
#define Call_FT_NB_NR_OFF 3 /* Call, Far Talk, NB, NR off */
|
||||
#define Call_CT_NB_NR_OFF 4 /* Call, Close Talk, NB, NR off */
|
||||
#define Call_BT_NB 10 /* Call, BT, NB */
|
||||
#define Call_TTY_VCO 11 /* Call, TTY HCO NB */
|
||||
#define Call_TTY_HCO 12 /* Call, TTY VCO NB */
|
||||
#define Call_TTY_FULL 13 /* Call, TTY FULL NB */
|
||||
#define Call_FT_EVS 14 /* Call, Far Talk, EVS */
|
||||
#define Call_CT_EVS 15 /* Call, Close Talk, EVS */
|
||||
#define LOOPBACK_CT 17 /* Loopback, Close Talk */
|
||||
#define LOOPBACK_FT 18 /* Loopback, Far Talk */
|
||||
#define LOOPBACK_HS 19 /* Loopback, Headset */
|
||||
#define Call_BT_WB 20 /* Call, BT, WB */
|
||||
#define Call_HS_WB 21 /* Call, Headset, Wide Band */
|
||||
#define Call_FT_WB 22 /* Call, Far Talk, Wide Band */
|
||||
#define Call_CT_WB 23 /* Call, Close Talk, Wide Band */
|
||||
#define Call_FT_WB_NR_OFF 24 /* Call, Far Talk, WB, NR off */
|
||||
#define Call_CT_WB_NR_OFF 25 /* Call, Close Talk, WB, NR off */
|
||||
#define AUDIENCE_SLEEP 40 /* Route none, Audience Sleep State */
|
|
@ -83,4 +83,12 @@
|
|||
*/
|
||||
/* #define DSP_POWEROFF_DELAY 0 */
|
||||
|
||||
/*
|
||||
* Some device variants (often T-Mobile) have a separate voice processing IC
|
||||
* (Audience EarSmart xxx).
|
||||
* This hooks into the voice call session and enables, configures and disables
|
||||
* this extra firmware so RX/TX streams can be routed by the driver.
|
||||
*/
|
||||
/* #define AUDIENCE_EARSMART_IC */
|
||||
|
||||
#endif // SAMSUNG_AUDIO_H
|
||||
|
|
|
@ -34,6 +34,10 @@
|
|||
#include "audio_hw.h"
|
||||
#include "voice.h"
|
||||
|
||||
#ifdef AUDIENCE_EARSMART_IC
|
||||
#include "audience.h"
|
||||
#endif
|
||||
|
||||
static struct pcm_config pcm_config_voicecall = {
|
||||
.channels = 2,
|
||||
.rate = 8000,
|
||||
|
@ -249,6 +253,11 @@ int start_voice_session(struct voice_session *session)
|
|||
start_voice_session_bt_sco(session);
|
||||
}
|
||||
|
||||
#ifdef AUDIENCE_EARSMART_IC
|
||||
ALOGV("%s: Enabling Audience IC", __func__);
|
||||
es_start_voice_session(session);
|
||||
#endif
|
||||
|
||||
if (session->two_mic_control) {
|
||||
ALOGV("%s: enabling two mic control", __func__);
|
||||
ril_set_two_mic_control(&session->ril, AUDIENCE, TWO_MIC_SOLUTION_ON);
|
||||
|
@ -290,6 +299,10 @@ void stop_voice_session(struct voice_session *session)
|
|||
stop_voice_session_bt_sco(session);
|
||||
}
|
||||
|
||||
#ifdef AUDIENCE_EARSMART_IC
|
||||
ALOGV("%s: Disabling Audience IC", __func__);
|
||||
es_stop_voice_session();
|
||||
#endif
|
||||
|
||||
session->out_device = AUDIO_DEVICE_NONE;
|
||||
|
||||
|
|
Loading…
Reference in a new issue