blob: 355389765292c3784c7940239191576212f239d3 [file] [log] [blame]
/* st_hw_extn_intf.c
*
* This library contains the API that are add ons to
* sound trigger interface.
*
* Copyright (c) 2016-2017, 2019 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 "sound_trigger_hw_ext_intf"
/* #define LOG_NDEBUG 0 */
#define LOG_NDDEBUG 0
/* #define VERY_VERBOSE_LOGGING */
#ifdef VERY_VERBOSE_LOGGING
#define ALOGVV ALOGV
#else
#define ALOGVV(a...) do { } while(0)
#endif
#include <errno.h>
#include <fcntl.h>
#include <cutils/log.h>
#include <cutils/str_parms.h>
#include <hardware/sound_trigger.h>
#include <unistd.h>
#include "st_common_defs.h"
#include "sound_trigger_platform.h"
#include "sound_trigger_hw.h"
#include "st_session.h"
#include "st_hw_common.h"
#include "sound_trigger_prop_intf.h"
static size_t get_frame_size(struct pcm_config config)
{
size_t chan_samp_sz;
int format = config.format;
chan_samp_sz = pcm_format_to_bits(format) >> 3;
return config.channels * chan_samp_sz;
}
/* Add set of functions exposed via fptrs here */
static int sthw_extn_set_parameters(const struct sound_trigger_hw_device *dev,
sound_model_handle_t sound_model_handle,
const char *kvpairs)
{
struct sound_trigger_device *stdev = (struct sound_trigger_device *)dev;
st_session_t *st_session = NULL;
struct str_parms *parms;
char value[32];
int ret = 0, err, pause, bad_mic_channel_index;
bool backend_cfg_change = false;
audio_devices_t ec_ref_dev;
ALOGD("%s:[%d] Enter kv pairs %s", __func__, sound_model_handle, kvpairs);
if (!stdev) {
ALOGE("%s: Invalid sound trigger device passed", __func__);
return -EINVAL;
}
pthread_mutex_lock(&stdev->lock);
parms = str_parms_create_str(kvpairs);
if (!parms) {
ALOGD("%s: str_parms returned query NULL", __func__);
goto exit;
}
/* process global set parameters if sound model handle is sent as 0 */
if (sound_model_handle == 0) {
err = str_parms_get_int(parms, QSTHW_PARAMETER_BAD_MIC_CHANNEL_INDEX, &bad_mic_channel_index);
if (err >= 0) {
str_parms_del(parms, QSTHW_PARAMETER_BAD_MIC_CHANNEL_INDEX);
ALOGV("%s: bad mic channel index 0x%x", __func__, bad_mic_channel_index);
ret = platform_stdev_update_bad_mic_channel_index(stdev->platform,
bad_mic_channel_index,
&backend_cfg_change);
if (ret)
goto exit;
/*
* re route to new device if backend cfg change due to bad mic index update
* Set session as NULL to stop and start all the currently running sessions
*/
if (backend_cfg_change) {
stop_other_sessions(stdev, NULL);
start_other_sessions(stdev, NULL);
}
}
err = str_parms_get_int(parms, QSTHW_PARAMETER_EC_REF_DEVICE, (int *)&ec_ref_dev);
if (err >= 0) {
str_parms_del(parms, QSTHW_PARAMETER_EC_REF_DEVICE);
ALOGV("%s: ec ref device 0x%x", __func__, ec_ref_dev);
stdev->ec_ref_dev = ec_ref_dev;
}
goto exit;
}
/* process session specific set parameters */
st_session = get_sound_trigger_session(stdev, sound_model_handle);
if (!st_session) {
ALOGE("%s: ERROR. Could not find session for sound model %d", __func__, sound_model_handle);
ret = -EINVAL;
goto exit;
}
err = str_parms_get_str(parms, QSTHW_PARAMETER_CUSTOM_CHANNEL_MIXING, value, sizeof(value));
if (err >= 0) {
str_parms_del(parms, QSTHW_PARAMETER_CUSTOM_CHANNEL_MIXING);
ALOGV("%s: [%d] set custom channel mixing coeff", __func__, sound_model_handle);
ret = st_session_send_custom_chmix_coeff(st_session, value);
}
err = str_parms_get_int(parms, QSTHW_PARAMETER_SESSION_PAUSE, &pause);
if (err >= 0) {
str_parms_del(parms, QSTHW_PARAMETER_SESSION_PAUSE);
if (pause) {
ALOGV("%s: [%d] pause session", __func__, sound_model_handle);
st_session_pause(st_session);
} else {
ALOGV("%s: [%d] resume session", __func__, sound_model_handle);
st_session_resume(st_session);
}
}
exit:
if (parms)
str_parms_destroy(parms);
pthread_mutex_unlock(&stdev->lock);
return ret;
}
static size_t sthw_extn_get_buffer_size(const struct sound_trigger_hw_device *dev,
sound_model_handle_t sound_model_handle)
{
struct sound_trigger_device *stdev = (struct sound_trigger_device *)dev;
st_session_t *st_session = NULL;
size_t buf_size = 0;
struct pcm_config config;
if (!stdev) {
ALOGE("%s: Invalid sound trigger device passed", __func__);
return -EINVAL;
}
st_session = get_sound_trigger_session(stdev, sound_model_handle);
if (!st_session) {
ALOGE("%s: ERROR. Could not find session for sound model %d", __func__, sound_model_handle);
return -EINVAL;
}
if (st_session_get_config(st_session, &config)) {
ALOGE("%s: Could not get config for session %d", __func__, sound_model_handle);
return -EINVAL;
}
buf_size = config.period_size * get_frame_size(config);
return buf_size;
}
static int sthw_extn_read_buffer(const struct sound_trigger_hw_device *dev,
sound_model_handle_t sound_model_handle,
unsigned char *buf,
size_t bytes)
{
struct sound_trigger_device *stdev = (struct sound_trigger_device *)dev;
st_session_t *st_session = NULL;
struct pcm_config config;
int ret = 0;
size_t bytes_read = 0;
if (!stdev || !buf || !bytes) {
ALOGE("%s: Invalid params", __func__);
ret = -EINVAL;
goto exit;
}
pthread_mutex_lock(&stdev->lock);
st_session = get_sound_trigger_session(stdev, sound_model_handle);
if (!st_session) {
ALOGE("%s: ERROR. Could not find session for sound model %d", __func__, sound_model_handle);
ret = -EINVAL;
pthread_mutex_unlock(&stdev->lock);
goto exit;
}
st_session_get_config(st_session, &config);
pthread_mutex_unlock(&stdev->lock);
ret = st_session_read_pcm(st_session, buf,
bytes, &bytes_read);
if (ret != 0) {
memset(buf, 0, bytes);
ALOGE("%s: read failed status %d - sleep for buffer duration", __func__, ret);
usleep((bytes * 1000000) /
(get_frame_size(config) * config.rate));
}
exit:
return ret;
}
static int sthw_extn_stop_buffering(const struct sound_trigger_hw_device *dev,
sound_model_handle_t sound_model_handle)
{
struct sound_trigger_device *stdev = (struct sound_trigger_device *)dev;
st_session_t *st_session = NULL;
int ret = 0;
if (!stdev) {
ALOGE("%s: Invalid sound trigger device passed", __func__);
return -EINVAL;
}
pthread_mutex_lock(&stdev->lock);
st_session = get_sound_trigger_session(stdev, sound_model_handle);
if (!st_session) {
ALOGE("%s: ERROR. Could not find session for sound model %d", __func__, sound_model_handle);
ret = -EINVAL;
goto exit;
}
st_session_stop_lab(st_session);
exit:
pthread_mutex_unlock(&stdev->lock);
return ret;
}
static int sthw_extn_get_param_data(const struct sound_trigger_hw_device *dev,
sound_model_handle_t sound_model_handle,
const char *param,
void *payload,
size_t payload_size,
size_t *param_data_size)
{
struct sound_trigger_device *stdev = (struct sound_trigger_device *)dev;
st_session_t *st_session = NULL;
int status = 0;
if (!stdev) {
ALOGE("%s: Invalid sound trigger device passed", __func__);
goto exit;
}
pthread_mutex_lock(&stdev->lock);
st_session = get_sound_trigger_session(stdev, sound_model_handle);
if (!st_session) {
ALOGE("%s: ERROR. Could not find session for sound model %d", __func__, sound_model_handle);
status = -EINVAL;
goto exit;
}
status = st_session_get_param_data(st_session, param, payload, payload_size,
param_data_size);
if (status)
ALOGE("%s: ERROR. fetching get param data %d", __func__, status);
exit:
pthread_mutex_unlock(&stdev->lock);
ALOGV("%s: exit: return - %d", __func__, status);
return status;
}
void sthw_extn_get_fptrs(sthw_extn_fptrs_t *fptrs)
{
if (!fptrs) {
ALOGE("%s: ERROR Invalid argument", __func__);
return;
}
fptrs->set_parameters = sthw_extn_set_parameters;
fptrs->get_buffer_size = sthw_extn_get_buffer_size;
fptrs->read_buffer = sthw_extn_read_buffer;
fptrs->stop_buffering = sthw_extn_stop_buffering;
fptrs->get_param_data = sthw_extn_get_param_data;
}