blob: a8e8a46af3ca01862cb30aa61d35784a9b3a4937 [file] [log] [blame]
/*
* Copyright (c) 2015-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.
*
* Changes from Qualcomm Innovation Center are provided under the following license:
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
/* Test app to capture STT data using ctls from kernel */
#include <tinyalsa/asoundlib.h>
#include <errno.h>
#include <math.h>
#include "stt_meta_extract.h"
#include <log/log.h>
#include <cutils/str_parms.h>
#include <cutils/properties.h>
#undef LOG_TAG
#define LOG_TAG "stt_meta"
#undef LOG_NDEBUG
/*#define LOG_NDDEBUG 0*/
/*#define LOG_NDEBUG 0*/
#define nullptr NULL
static int get_sourcetrack_metadata(void *payload, unsigned int meta_size,
struct mixer_ctl *ctl) {
int ret = 0;
unsigned int count;
if (!ctl || !payload) {
ALOGE("%s: Invalid params, ctl / source track payload is NULL", __func__);
return -EINVAL;
}
ALOGD("%s from mixer", __func__);
mixer_ctl_update(ctl);
count = mixer_ctl_get_num_values(ctl);
if (count != meta_size) {
ALOGE("%s: mixer_ctl_get_num_values() invalid source tracking data size %d",
__func__, count);
ret = -EINVAL;
goto done;
}
ret = mixer_ctl_get_array(ctl, payload, count);
if (ret != 0) {
ALOGE("%s: mixer_ctl_get_array() failed to get Source Tracking Params", __func__);
ret = -EINVAL;
goto done;
}
done:
ALOGD("%s exit with %d", __func__, ret);
return ret;
}
static int get_soundfocus_metadata(struct sound_focus_meta *sound_focus_meta,
struct mixer_ctl *ctl) {
int ret = 0, count;
struct timespec ts;
if (!ctl) {
ALOGE("%s: not a valid ctrl", __func__);
return -EINVAL;
} else {
ALOGD("%s: from mixer", __func__);
mixer_ctl_update(ctl);
count = mixer_ctl_get_num_values(ctl);
if (count != (sizeof(struct sound_focus_meta) - sizeof(ts))) {
ALOGE("%s: mixer_ctl_get_num_values() invalid sound focus data size %d",
__func__, count);
ret = -EINVAL;
goto done;
}
ret = mixer_ctl_get_array(ctl, (void *)sound_focus_meta, count);
if (ret != 0) {
ALOGE("%s: mixer_ctl_get_array() failed to get Sound Focus Params", __func__);
ret = -EINVAL;
goto done;
}
clock_gettime(CLOCK_MONOTONIC, &ts);
sound_focus_meta->ts = ts;
}
done:
ALOGD("%s exit with %d", __func__, ret);
return ret;
}
static int set_soundfocus_metadata(struct sound_focus_meta *sound_focus_meta,
struct mixer_ctl *ctl) {
int ret = 0, count;
struct timespec ts;
if (!ctl) {
ALOGE("%s: not a valid ctrl", __func__);
return -EINVAL;
} else {
ALOGD("%s: Setting Sound Focus Params func", __func__);
mixer_ctl_update(ctl);
count = mixer_ctl_get_num_values(ctl);
if (count != (sizeof(struct sound_focus_meta) - sizeof(ts))) {
ALOGE("%s: mixer_ctl_get_num_values() invalid sound focus data size %d",
__func__, count);
ret = -EINVAL;
goto done;
}
ret = mixer_ctl_set_array(ctl, (void *)sound_focus_meta, count);
if (ret != 0) {
ALOGE("%s: mixer_ctl_set_array() failed to set Sound Focus Params", __func__);
ret = -EINVAL;
goto done;
}
}
done:
ALOGD("%s exit with %d", __func__, ret);
return ret;
}
static void updatestt_data(char* str, struct sound_focus_meta *sound_focus_meta) {
int str_len = strlen(str);
int j = 0, i;
int *arr=(int*)malloc(str_len*sizeof(int));
for (i = 0; str[i] != '\0'; i++) {
if (str[i] == ',')
j++;
else
arr[j] = arr[j] * DECI + (str[i] - ASCI_NUM);
}
j=0;
for (i = 0; i < NUM_SECTORS; i++) {
sound_focus_meta->start_angle[i] = arr[j++];
}
for (i = 0; i < NUM_SECTORS; i++) {
sound_focus_meta->enable[i] = arr[j++];
}
sound_focus_meta->gain_step = arr[j];
}
static void usage() {
printf(" \n Command \n");
printf(" \n stt_meta_extract <options>\n");
printf(" \n Options\n");
printf(" -t --source_track_data - get source tracking params data with recording\n");
printf(" -f --sound_focus_data - get sound focus params data with recording\n");
printf(" -s --sound focus set - set sound focus params data with recording\n\n");
printf(" -g --meta-time-gap - time between successive get data in msec\n\n");
printf(" -n --get-data-iterations - get iterations cnt, (-ve) for cont get data\n\n");
printf(" -h --help - Show this help\n\n");
printf(" \n Examples \n");
printf(" stt_meta_extract -> Get source track meta data while record in progress\n\n");
printf(" stt_meta_extract -t 1 -> Get source track meta data while record in progress\n\n");
printf(" stt_meta_extract -f 1 -> Get sound focus meta data while record in progress\n\n");
printf(" stt_meta_extract -s 45,110,235,310,1,0,0,1,50 -> Set sound focus param data\n");
printf(" secort_startangles[4],secotr_enable[4],gain \n\n");
printf(" stt_meta_extract -g 200 -n 5 -> Get stt meta data 5 times for every 200msec\n\n");
printf(" stt_meta_extract -b TX_CDC_DMA_TX_3 -> Get stt meta with be TX_CDC_DMA_TX_3 \n\n");
}
static int derive_mixer_ctl_stt(struct mixer **stt_mixer, struct mixer_ctl **ctl_st, struct mixer_ctl **ctl_sf,
struct mixer_ctl **ctl_st_fnn, char* be_intf, enum fluence_version fversion) {
char sound_focus_mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = "Sound Focus Audio Tx ";
char source_tracking_mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = "Source Tracking Audio Tx ";
char st_fnn_mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = "FNN STM Audio Tx ";
struct mixer *mixer = NULL;
int ret = 0, retry_num = 0;
struct mixer_ctl *ctl = NULL;
if (!stt_mixer) {
ALOGE("%s: invalid mixer", __func__);
return -EINVAL;
}
if (!ctl_st) {
ALOGE("%s: invalid Source tracking mixer ctl", __func__);
return -EINVAL;
}
if (!ctl_sf) {
ALOGE("%s: invalid Sound focus mixer ctl", __func__);
return -EINVAL;
}
if (!ctl_st_fnn) {
ALOGE("%s: invalid Sound tracking mixer ctl for fnn", __func__);
return -EINVAL;
}
strlcat(sound_focus_mixer_ctl_name, be_intf, MIXER_PATH_MAX_LENGTH);
strlcat(source_tracking_mixer_ctl_name, be_intf, MIXER_PATH_MAX_LENGTH);
strlcat(st_fnn_mixer_ctl_name, be_intf, MIXER_PATH_MAX_LENGTH);
mixer = mixer_open(SOUND_CARD);
while (!mixer && retry_num < MIXER_OPEN_MAX_NUM_RETRY) {
usleep(RETRY_US);
mixer = mixer_open(SOUND_CARD);
retry_num++;
}
if (!mixer) {
ALOGE("%s: ERROR. Unable to open the mixer, aborting", __func__);
ret = -EINVAL;
goto clean;
} else {
*stt_mixer = mixer;
}
switch (fversion) {
case FV_11:
{
ctl = mixer_get_ctl_by_name(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 clean;
} else {
*ctl_st = ctl;
}
ctl = mixer_get_ctl_by_name(mixer, sound_focus_mixer_ctl_name);
if (!ctl) {
ALOGE("%s: Could not get ctl for mixer cmd - %s",
__func__, source_tracking_mixer_ctl_name);
ret = -EINVAL;
goto clean;
} else {
*ctl_sf = ctl;
}
break;
}
case FV_13:
{
ctl = mixer_get_ctl_by_name(mixer, st_fnn_mixer_ctl_name);
if (!ctl) {
ALOGE("%s: Could not get ctl for mixer cmd - %s",
__func__, st_fnn_mixer_ctl_name);
ret = -EINVAL;
goto clean;
} else {
*ctl_st_fnn = ctl;
}
break;
}
default:
ALOGE("%s: invalid fluence type", __func__);
break;
}
return ret;
clean:
if (mixer)
mixer_close(mixer);
return ret;
}
int main(int argc, char* argv[]) {
int get_data_iter = 1, get_data_time_gap = RETRY_US, idx, count, sect, ret = 0;
bool is_source_track_get = true, is_sound_focus_get = false, is_sound_focus_set = false;
char *be_intf = "TX_CDC_DMA_TX_3";
FILE * log_file = NULL;
const char *log_filename = NULL;
char fluence_property[PROPERTY_VALUE_MAX];
enum fluence_version fv;
struct timespec ts;
struct sound_focus_meta sound_focus_metadataset;
struct source_track_meta source_track_metadata;
struct sound_focus_meta sound_focus_metadata;
struct source_track_meta_fnn source_track_metadata_fnn;
/* Open mixer for snd card 0 */
struct mixer *stt_mixer = NULL;
struct mixer_ctl *ctl_st = NULL, *ctl_sf = NULL, *ctl_st_fnn = NULL;
struct option long_options[] = {
{"meta-time-gap", required_argument, 0, 'g'}, // time-gap between two meta data
{"get-data-iterations", required_argument, 0, 'n'}, // number of meta data events
{"source_track_data", required_argument, 0, 't'}, // Extract Source track meta data
{"sound_focus_data", required_argument, 0, 'f'}, // Extract Sound focus meta data
{"sound focus set", required_argument, 0, 's'}, // Set Sound focus meta data
{"audio be interface", required_argument, 0, 'b'}, // update audio back end interface
{"log file_name", required_argument, 0, 'l'}, // update log file name
{"help", no_argument, 0, 'h'}
};
int opt = 0;
int option_index = 0;
char *str;
log_file = stdout;
memset(&sound_focus_metadataset, 0x0, sizeof(struct sound_focus_meta));
memset(&source_track_metadata_fnn, 0xFF, sizeof(struct source_track_meta_fnn));
memset(&source_track_metadata, 0xFF, sizeof(struct source_track_meta));
memset(&sound_focus_metadata, 0x0, sizeof(struct sound_focus_meta));
while ((opt = getopt_long(argc,
argv,
"-g:n:t:f:s:b:l:h:",
long_options,
&option_index)) != -1) {
printf("for argument %c, value is %s\n", opt, optarg);
switch (opt) {
case 'g':
get_data_time_gap = NSEC_MSEC_CONVERT * atoi(optarg);
break;
case 'n':
get_data_iter = atoi(optarg); /* -ve value for cont get data, +ve for iterations */
break;
case 't':
is_source_track_get = atoi(optarg);
break;
case 'f':
is_sound_focus_get = atoi(optarg);
break;
case 's':
str = optarg;
updatestt_data(str, &sound_focus_metadataset);
is_sound_focus_set = true;
break;
case 'b':
be_intf = optarg;
break;
case 'l':
log_filename = optarg;
if (strcasecmp(log_filename, "stdout") &&
strcasecmp(log_filename, "1") &&
(log_file = fopen(log_filename,"wb")) == NULL) {
fprintf(log_file, "Cannot open log file %s\n", log_filename);
fprintf(stderr, "Cannot open log file %s\n", log_filename);
/* continue to log to std out. */
log_file = stdout;
}
break;
case 'h':
usage();
return 0;
break;
default:
usage();
return 0;
}
}
printf("STT GET META \n");
property_get("ro.vendor.audio.sdk.fluencetype", fluence_property, NULL);
if (property_get_bool("ro.vendor.audio.sdk.fluence.nn.enabled",false)) {
if((!strncmp("fluencenn", fluence_property, sizeof("fluencenn"))) ||
(!strncmp("fluence", fluence_property, sizeof("fluence"))))
fv = FV_13;
else
fv = FV_11;
}
else {
fv = FV_11;
}
ret = derive_mixer_ctl_stt(&stt_mixer, &ctl_st, &ctl_sf, &ctl_st_fnn, be_intf, fv);
if (ret != 0) {
printf("failed to derive mixer controls %d", ret);
goto done;
}
fprintf(log_file, "get_source_track meta data with gap of %d us \n", get_data_time_gap);
if (is_sound_focus_set) {
if (fv != FV_11) {
printf("sound_focus set is not supported for fluence version %d ", fv);
ret = -1;
goto done;
}
ret = set_soundfocus_metadata(&sound_focus_metadataset, ctl_sf);
if (ret != 0) {
printf("failed to set soundfocus metadata %d", ret);
goto done;
}
ret = get_soundfocus_metadata(&sound_focus_metadata, ctl_sf);
if (ret != 0) {
printf("failed to get soundfocus metadata %d", ret);
goto done;
}
}
while (get_data_iter != 0) {
switch (fv) {
case FV_13:
{
if (is_source_track_get) {
ret = get_sourcetrack_metadata((void *)&source_track_metadata_fnn,
sizeof(struct source_track_meta_fnn), ctl_st_fnn);
if (ret != 0) {
printf("failed to get source track meta data %d", ret);
goto done;
}
}
/* Print meta data */
fprintf(log_file, "time stamp session_time_lsw %u session_time_msw %u \n",
source_track_metadata_fnn.session_time_lsw,source_track_metadata_fnn.session_time_msw);
for (idx = 0; idx < TOTAL_SPEAKERS; idx++)
printf("speakers[%d]=%d ",idx, source_track_metadata_fnn.speakers[idx]);
fprintf(log_file, "\nreserved=%d\n",source_track_metadata_fnn.reserved);
for (idx = 0; idx < TOTAL_DEGREES; idx++)
printf("polarActivity[%d]=%d ",idx, source_track_metadata_fnn.polarActivity[idx]);
break;
}
case FV_11:
{
if (is_sound_focus_get) {
ret = get_soundfocus_metadata(&sound_focus_metadata, ctl_sf);
if (ret != 0) {
printf("failed to get soundfocus metadata %d", ret);
goto done;
}
}
if (is_source_track_get) {
ret = get_sourcetrack_metadata((void *)&source_track_metadata, sizeof(struct source_track_meta) - sizeof(struct timespec), ctl_st);
if (ret != 0) {
printf("failed to get source track meta data %d", ret);
goto done;
}
clock_gettime(CLOCK_MONOTONIC, &ts);
source_track_metadata.ts = ts;
}
/* Print meta data */
fprintf(log_file, "time stamp sec %ld msec %ld \n", (source_track_metadata.ts).tv_sec,
(source_track_metadata.ts).tv_nsec / NSEC_MSEC_CONVERT);
for (idx = 0; idx < NUM_SECTORS; idx++){
printf("vad[%d]=%d ",idx, source_track_metadata.vad[idx]);
if (idx < (NUM_SECTORS-1))
printf("doa_noise[%d]=%d \n",
idx, source_track_metadata.doa_noise[idx]);
}
fprintf(log_file, "doa_speech=%d\n",source_track_metadata.doa_speech);
if (is_sound_focus_get || is_sound_focus_set) {
fprintf(log_file, "polar_activity:");
for (sect = 0; sect < NUM_SECTORS; sect++ ){
fprintf(log_file, "Sector No-%d:",sect + 1);
idx = sound_focus_metadata.start_angle[sect];
fprintf(log_file, "idx %d:",idx);
count = sound_focus_metadata.start_angle[(sect + 1)%NUM_SECTORS] -
sound_focus_metadata.start_angle[sect];
fprintf(log_file, "count %d:",count);
if (count < 0)
count = count + TOTAL_DEGREES;
do {
fprintf(log_file, "%d ",
source_track_metadata.polar_activity[idx%TOTAL_DEGREES]);
count--;
idx++;
} while (count);
}
}
break;
}
default:
printf("fluence version is not supported");
break;
}
usleep(get_data_time_gap);
if (get_data_iter > 0)
get_data_iter--;
}
done:
mixer_close(stt_mixer);
stt_mixer = NULL;
if ((log_file != stdout) && (log_file != nullptr))
fclose(log_file);
fprintf(log_file, "\nADL: BYE BYE\n");
return ret;
}