/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LOG_TAG "source_track"
/*#define LOG_NDEBUG 0*/
#define LOG_NDDEBUG 0
#include <errno.h>
#include <math.h>
#include <cutils/log.h>
#include "audio_hw.h"
#include "platform.h"
#include "platform_api.h"
#include "voice_extn.h"
#include <stdlib.h>
#include <cutils/str_parms.h>
#ifdef SOURCE_TRACKING_ENABLED
/* Audio Paramater Key to identify the list of start angles.
* Starting angle (in degrees) defines the boundary starting angle for each sector.
*/
#define AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES "SoundFocus.start_angles"
/* Audio Paramater Key to identify the list of enable flags corresponding to each sector.
*/
#define AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS "SoundFocus.enable_sectors"
/* Audio Paramater Key to identify the gain step value to be applied to all enabled sectors.
*/
#define AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP "SoundFocus.gain_step"
/* Audio Paramater Key to identify the list of voice activity detector outputs corresponding
* to each sector.
*/
#define AUDIO_PARAMETER_KEY_SOURCE_TRACK_VAD "SourceTrack.vad"
/* Audio Paramater Key to identify the direction (in degrees) of arrival for desired talker
* (dominant source of speech).
*/
#define AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_SPEECH "SourceTrack.doa_speech"
/* Audio Paramater Key to identify the list of directions (in degrees) of arrival for
* interferers (interfering noise sources).
*/
#define AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_NOISE "SourceTrack.doa_noise"
/* Audio Paramater Key to identify the list of sound strength indicators at each degree
* of the horizontal plane referred to by a full circle (360 degrees).
*/
#define AUDIO_PARAMETER_KEY_SOURCE_TRACK_POLAR_ACTIVITY "SourceTrack.polar_activity"
#define BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES 0x1
#define BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS 0x2
#define BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP 0x4
#define BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_VAD 0x8
#define BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_SPEECH 0x10
#define BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_NOISE 0x20
#define BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_POLAR_ACTIVITY 0x40
#define BITMASK_AUDIO_PARAMETER_KEYS_SOUND_FOCUS \
(BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES |\
BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS |\
BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP)
#define BITMASK_AUDIO_PARAMETER_KEYS_SOURCE_TRACKING \
(BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_VAD |\
BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_SPEECH |\
BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_NOISE |\
BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_POLAR_ACTIVITY)
#define MAX_SECTORS 8
#define MAX_STR_SIZE 2048
struct audio_device_to_audio_interface audio_device_to_interface_table[];
int audio_device_to_interface_table_len;
struct sound_focus_param {
uint16_t start_angle[MAX_SECTORS];
uint8_t enable[MAX_SECTORS];
uint16_t gain_step;
};
struct source_tracking_param {
uint8_t vad[MAX_SECTORS];
uint16_t doa_speech;
uint16_t doa_noise[3];
uint8_t polar_activity[360];
};
static int add_audio_intf_name_to_mixer_ctl(audio_devices_t device, char *mixer_ctl_name,
struct audio_device_to_audio_interface *table, int len)
{
int ret = 0;
int i;
if (table == NULL) {
ALOGE("%s: table is NULL", __func__);
ret = -EINVAL;
goto done;
}
if (mixer_ctl_name == NULL) {
ret = -EINVAL;
goto done;
}
for (i=0; i < len; i++) {
if (device == table[i].device) {
strlcat(mixer_ctl_name, " ", MIXER_PATH_MAX_LENGTH);
strlcat(mixer_ctl_name, table[i].interface_name, MIXER_PATH_MAX_LENGTH);
break;
}
}
if (i == len) {
ALOGE("%s: Audio Device not found in the table", __func__);
ret = -EINVAL;
}
done:
return ret;
}
static bool is_stt_supported_snd_device(snd_device_t snd_device)
{
bool ret = false;
switch (snd_device) {
case SND_DEVICE_IN_HANDSET_DMIC:
case SND_DEVICE_IN_HANDSET_DMIC_AEC:
case SND_DEVICE_IN_HANDSET_DMIC_NS:
case SND_DEVICE_IN_HANDSET_DMIC_AEC_NS:
case SND_DEVICE_IN_HANDSET_STEREO_DMIC:
case SND_DEVICE_IN_HANDSET_QMIC:
case SND_DEVICE_IN_VOICE_DMIC:
case SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE:
case SND_DEVICE_IN_HEADSET_MIC_FLUENCE:
case SND_DEVICE_IN_SPEAKER_DMIC:
case SND_DEVICE_IN_SPEAKER_DMIC_AEC:
case SND_DEVICE_IN_SPEAKER_DMIC_NS:
case SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS:
case SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE:
case SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE:
case SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE:
case SND_DEVICE_IN_SPEAKER_QMIC_AEC:
case SND_DEVICE_IN_SPEAKER_QMIC_NS:
case SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS:
case SND_DEVICE_IN_VOICE_SPEAKER_DMIC:
case SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE:
case SND_DEVICE_IN_VOICE_SPEAKER_QMIC:
ret = true;
break;
default:
break;
}
return ret;
}
audio_devices_t get_input_audio_device(audio_devices_t device)
{
audio_devices_t in_device = device;
switch (device) {
case AUDIO_DEVICE_OUT_EARPIECE:
case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
in_device = AUDIO_DEVICE_IN_BUILTIN_MIC;
break;
case AUDIO_DEVICE_OUT_SPEAKER:
in_device = AUDIO_DEVICE_IN_BACK_MIC;
break;
case AUDIO_DEVICE_OUT_WIRED_HEADSET:
in_device = AUDIO_DEVICE_IN_WIRED_HEADSET;
break;
case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
in_device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
break;
default:
break;
}
return in_device;
}
static int derive_mixer_ctl_from_usecase_intf(struct audio_device *adev,
char *mixer_ctl_name) {
struct audio_usecase *usecase = NULL;
audio_devices_t in_device;
int ret = 0;
if (mixer_ctl_name == NULL) {
ALOGE("%s: mixer_ctl_name is NULL", __func__);
ret = -EINVAL;
goto done;
}
if (voice_is_in_call(adev)) {
strlcat(mixer_ctl_name, " ", MIXER_PATH_MAX_LENGTH);
strlcat(mixer_ctl_name, "Voice Tx", MIXER_PATH_MAX_LENGTH);
usecase = get_usecase_from_list(adev,
get_usecase_id_from_usecase_type(adev, VOICE_CALL));
} else if (voice_extn_compress_voip_is_active(adev)) {
strlcat(mixer_ctl_name, " ", MIXER_PATH_MAX_LENGTH);
strlcat(mixer_ctl_name, "Voice Tx", MIXER_PATH_MAX_LENGTH);
usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
} else {
strlcat(mixer_ctl_name, " ", MIXER_PATH_MAX_LENGTH);
strlcat(mixer_ctl_name, "Audio Tx", MIXER_PATH_MAX_LENGTH);
usecase = get_usecase_from_list(adev, get_usecase_id_from_usecase_type(adev, PCM_CAPTURE));
}
if (usecase && (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
if (is_stt_supported_snd_device(usecase->in_snd_device)) {
in_device = get_input_audio_device(usecase->devices);
ret = add_audio_intf_name_to_mixer_ctl(in_device, mixer_ctl_name,
audio_device_to_interface_table, audio_device_to_interface_table_len);
} else {
ALOGE("%s: Sound Focus/Source Tracking not supported on the input sound device (%s)",
__func__, platform_get_snd_device_name(usecase->in_snd_device));
ret = -EINVAL;
}
} else {
ALOGE("%s: No use case is active which supports Sound Focus/Source Tracking",
__func__);
ret = -EINVAL;
}
done:
return ret;
}
static int parse_soundfocus_sourcetracking_keys(struct str_parms *parms)
{
char *str;
char *value = NULL;
int val, len;
int ret = 0, err;
char *kv_pairs = str_parms_to_str(parms);
ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
len = strlen(kv_pairs);
value = (char*)calloc(len, sizeof(char));
if(value == NULL) {
ret = -ENOMEM;
ALOGE("%s: failed to allocate memory", __func__);
goto done;
}
err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES,
value, len);
if (err >= 0) {
str_parms_del(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES);
ret = ret | BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES;
}
err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS,
value, len);
if (err >= 0) {
str_parms_del(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS);
ret = ret | BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS;
}
err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP,
value, len);
if (err >= 0) {
str_parms_del(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP);
ret = ret | BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP;
}
err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOURCE_TRACK_VAD,
value, len);
if (err >= 0) {
str_parms_del(parms, AUDIO_PARAMETER_KEY_SOURCE_TRACK_VAD);
ret = ret | BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_VAD;
}
err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_SPEECH,
value, len);
if (err >= 0) {
str_parms_del(parms, AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_SPEECH);
ret = ret | BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_SPEECH;
}
err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_NOISE,
value, len);
if (err >= 0) {
str_parms_del(parms, AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_NOISE);
ret = ret | BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_NOISE;
}
err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOURCE_TRACK_POLAR_ACTIVITY,
value, len);
if (err >= 0) {
str_parms_del(parms, AUDIO_PARAMETER_KEY_SOURCE_TRACK_POLAR_ACTIVITY);
ret = ret | BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_POLAR_ACTIVITY;
}
done:
free(kv_pairs);
if(value != NULL)
free(value);
ALOGV("%s: returning bitmask = %d", __func__, ret);
return ret;
}
static int get_soundfocus_sourcetracking_data(struct audio_device *adev,
const int bitmask,
struct sound_focus_param *sound_focus_data,
struct source_tracking_param *source_tracking_data)
{
struct mixer_ctl *ctl;
char sound_focus_mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = "Sound Focus";
char source_tracking_mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = "Source Tracking";
int ret = -EINVAL;
int i, count;
if (bitmask & BITMASK_AUDIO_PARAMETER_KEYS_SOUND_FOCUS) {
/* Derive the mixer control name based on the use case and the audio interface
* for the corresponding audio device
*/
ret = derive_mixer_ctl_from_usecase_intf(adev, sound_focus_mixer_ctl_name);
if (ret != 0) {
ALOGE("%s: Could not get Sound Focus Params", __func__);
goto done;
} else {
ALOGV("%s: Mixer Ctl name: %s", __func__, sound_focus_mixer_ctl_name);
}
ctl = mixer_get_ctl_by_name(adev->mixer, sound_focus_mixer_ctl_name);
if (!ctl) {
ALOGE("%s: Could not get ctl for mixer cmd - %s",
__func__, sound_focus_mixer_ctl_name);
ret = -EINVAL;
goto done;
} else {
ALOGV("%s: Getting Sound Focus Params", __func__);
mixer_ctl_update(ctl);
count = mixer_ctl_get_num_values(ctl);
if (count != sizeof(struct sound_focus_param)) {
ALOGE("%s: mixer_ctl_get_num_values() invalid sound focus data size", __func__);
ret = -EINVAL;
goto done;
}
ret = mixer_ctl_get_array(ctl, (void *)sound_focus_data, count);
if (ret != 0) {
ALOGE("%s: mixer_ctl_get_array() failed to get Sound Focus Params", __func__);
ret = -EINVAL;
goto done;
}
}
}
if (bitmask & BITMASK_AUDIO_PARAMETER_KEYS_SOURCE_TRACKING) {
/* Derive the mixer control name based on the use case and the audio interface
* for the corresponding audio device
*/
ret = derive_mixer_ctl_from_usecase_intf(adev, source_tracking_mixer_ctl_name);
if (ret != 0) {
ALOGE("%s: Could not get Source Tracking Params", __func__);
goto done;
} else {
ALOGV("%s: Mixer Ctl name: %s", __func__, source_tracking_mixer_ctl_name);
}
ctl = mixer_get_ctl_by_name(adev->mixer, source_tracking_mixer_ctl_name);
if (!ctl) {
ALOGE("%s: Could not get ctl for mixer cmd - %s",
__func__, source_tracking_mixer_ctl_name);
ret = -EINVAL;
goto done;
} else {
ALOGV("%s: Getting Source Tracking Params", __func__);
mixer_ctl_update(ctl);
count = mixer_ctl_get_num_values(ctl);
if (count != sizeof(struct source_tracking_param)) {
ALOGE("%s: mixer_ctl_get_num_values() invalid source tracking data size", __func__);
ret = -EINVAL;
goto done;
}
ret = mixer_ctl_get_array(ctl, (void *)source_tracking_data, count);
if (ret != 0) {
ALOGE("%s: mixer_ctl_get_array() failed to get Source Tracking Params", __func__);
ret = -EINVAL;
goto done;
}
}
}
done:
return ret;
}
static void send_soundfocus_sourcetracking_params(struct str_parms *reply,
const int bitmask,
const struct sound_focus_param sound_focus_data,
const struct source_tracking_param source_tracking_data)
{
int i = 0, len = 0;
char value[MAX_STR_SIZE] = "";
if (bitmask & BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES) {
for (i = 0; i < MAX_SECTORS; i++) {
if ((i >=4) && (sound_focus_data.start_angle[i] == 0xFFFF))
continue;
if (i)
snprintf(value + strlen(value), MAX_STR_SIZE, ",");
snprintf(value + strlen(value), MAX_STR_SIZE, "%d", sound_focus_data.start_angle[i]);
}
str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES, value);
}
strlcpy(value, "", sizeof(""));
if (bitmask & BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS) {
for (i = 0; i < MAX_SECTORS; i++) {
if ((i >=4) && (sound_focus_data.enable[i] == 0xFF))
continue;
if (i)
snprintf(value + strlen(value), MAX_STR_SIZE, ",");
snprintf(value + strlen(value), MAX_STR_SIZE, "%d", sound_focus_data.enable[i]);
}
str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS, value);
}
if (bitmask & BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP)
str_parms_add_int(reply, AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP, sound_focus_data.gain_step);
strlcpy(value, "", sizeof(""));
if (bitmask & BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_VAD) {
for (i = 0; i < MAX_SECTORS; i++) {
if ((i >=4) && (source_tracking_data.vad[i] == 0xFF))
continue;
if (i)
snprintf(value + strlen(value), MAX_STR_SIZE, ",");
snprintf(value + strlen(value), MAX_STR_SIZE, "%d", source_tracking_data.vad[i]);
}
str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SOURCE_TRACK_VAD, value);
}
if (bitmask & BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_SPEECH)
str_parms_add_int(reply, AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_SPEECH, source_tracking_data.doa_speech);
strlcpy(value, "", sizeof(""));
if (bitmask & BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_NOISE) {
snprintf(value, MAX_STR_SIZE,
"%d,%d,%d", source_tracking_data.doa_noise[0], source_tracking_data.doa_noise[1], source_tracking_data.doa_noise[2]);
str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_NOISE, value);
}
strlcpy(value, "", sizeof(""));
if (bitmask & BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_POLAR_ACTIVITY) {
for (i = 0; i < 360; i++) {
if (i)
snprintf(value + strlen(value), MAX_STR_SIZE, ",");
snprintf(value + strlen(value), MAX_STR_SIZE, "%d", source_tracking_data.polar_activity[i]);
}
str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SOURCE_TRACK_POLAR_ACTIVITY, value);
}
}
void audio_extn_source_track_get_parameters(struct audio_device *adev,
struct str_parms *query,
struct str_parms *reply)
{
int bitmask = 0, ret = 0;
struct sound_focus_param sound_focus_data;
struct source_tracking_param source_tracking_data;
memset(&sound_focus_data, 0xFF, sizeof(struct sound_focus_param));
memset(&source_tracking_data, 0xFF, sizeof(struct source_tracking_param));
// Parse the input parameters string for Source Tracking keys
bitmask = parse_soundfocus_sourcetracking_keys(query);
if (bitmask) {
// Get the parameter values from the backend
ret = get_soundfocus_sourcetracking_data(adev, bitmask, &sound_focus_data, &source_tracking_data);
if (ret == 0) {
// Construct the return string with key, value pairs
send_soundfocus_sourcetracking_params(reply, bitmask, sound_focus_data, source_tracking_data);
}
}
}
void audio_extn_source_track_set_parameters(struct audio_device *adev,
struct str_parms *parms)
{
int len, ret, count;;
struct mixer_ctl *ctl;
char sound_focus_mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = "Sound Focus";
char *value = NULL;
char *kv_pairs = str_parms_to_str(parms);
len = strlen(kv_pairs);
value = (char*)calloc(len, sizeof(char));
if(value == NULL) {
ret = -ENOMEM;
ALOGE("%s: failed to allocate memory", __func__);
goto done;
}
// Parse the input parameter string for Source Tracking key, value pairs
ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES,
value, len);
if (ret >= 0) {
char *saveptr, *tok;
int i = 0, val;
struct sound_focus_param sound_focus_param;
memset(&sound_focus_param, 0xFF, sizeof(struct sound_focus_param));
str_parms_del(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES);
tok = strtok_r(value, ",", &saveptr);
while ((i < MAX_SECTORS) && (tok != NULL)) {
if (sscanf(tok, "%d", &val) == 1) {
sound_focus_param.start_angle[i++] = (uint16_t)val;
}
tok = strtok_r(NULL, ",", &saveptr);
}
ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS,
value, len);
if (ret >= 0) {
str_parms_del(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS);
tok = strtok_r(value, ",", &saveptr);
i = 0;
while ((i < MAX_SECTORS) && (tok != NULL)) {
if (sscanf(tok, "%d", &val) == 1) {
sound_focus_param.enable[i++] = (uint8_t)val;
}
tok = strtok_r(NULL, ",", &saveptr);
}
} else {
ALOGE("%s: SoundFocus.enable_sectors key not found", __func__);
goto done;
}
ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP, &val);
if (ret >= 0) {
str_parms_del(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP);
sound_focus_param.gain_step = (uint16_t)val;
} else {
ALOGE("%s: SoundFocus.gain_step key not found", __func__);
goto done;
}
/* Derive the mixer control name based on the use case and the audio h/w
* interface name for the corresponding audio device
*/
ret = derive_mixer_ctl_from_usecase_intf(adev, sound_focus_mixer_ctl_name);
if (ret != 0) {
ALOGE("%s: Could not set Sound Focus Params", __func__);
goto done;
} else {
ALOGV("%s: Mixer Ctl name: %s", __func__, sound_focus_mixer_ctl_name);
}
ctl = mixer_get_ctl_by_name(adev->mixer, sound_focus_mixer_ctl_name);
if (!ctl) {
ALOGE("%s: Could not get ctl for mixer cmd - %s",
__func__, sound_focus_mixer_ctl_name);
goto done;
} else {
ALOGV("%s: Setting Sound Focus Params", __func__);
for (i = 0; i < MAX_SECTORS;i++) {
ALOGV("%s: start_angles[%d] = %d", __func__, i, sound_focus_param.start_angle[i]);
}
for (i = 0; i < MAX_SECTORS;i++) {
ALOGV("%s: enable_sectors[%d] = %d", __func__, i, sound_focus_param.enable[i]);
}
ALOGV("%s: gain_step = %d", __func__, sound_focus_param.gain_step);
mixer_ctl_update(ctl);
count = mixer_ctl_get_num_values(ctl);
if (count != sizeof(struct sound_focus_param)) {
ALOGE("%s: mixer_ctl_get_num_values() invalid data size", __func__);
goto done;
}
// Set the parameters on the mixer control derived above
ret = mixer_ctl_set_array(ctl, (void *)&sound_focus_param, count);
if (ret != 0) {
ALOGE("%s: mixer_ctl_set_array() failed to set Sound Focus Params", __func__);
goto done;
}
}
}
done:
free(kv_pairs);
if(value != NULL)
free(value);
return;
}
#endif /* SOURCE_TRACKING_ENABLED end */