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:
Christopher N. Hesse 2017-02-25 01:37:56 +01:00
parent 68f8fb65aa
commit 0fdef0cbd6
6 changed files with 291 additions and 0 deletions

View File

@ -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
View 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
View 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();

View 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 */

View File

@ -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

View File

@ -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;