mcu_hi3321_watch/application/audio/sample_lpwk/sample_lpwk.c
2025-05-26 20:15:20 +08:00

1316 lines
38 KiB
C

/*
* Copyright (c) CompanyNameMagicTag 2019-2020. All rights reserved.
* Description: sea sample
* Author: audio
* Create: 2019-09-17
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "thread_os.h"
#include "chip_type.h"
#include "audio_type.h"
#include "securec.h"
#include "soc_uapi_adp.h"
#include "soc_uapi_vad.h"
#include "soc_uapi_ai.h"
#include "soc_uapi_sea.h"
#include "sample_audio_api.h"
#include "sample_audio_utils.h"
#if (SAP_CHIP_TYPE == brandy)
#include "pm_clocks.h"
#endif /* SAP_CHIP_TYPE */
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
#define LPWK_PHRASE_COUNT 21
#define LPWK_TASK_NAME_LENGTH 32
#define LPWK_STREAM_MAX_DUR 600 /* 10 minute */
#define LPWK_VAD_RESET_INTERVAL 5
#define LPWK_AI_DEF_PORT UAPI_AI_PORT_PDM0
#define LPWK_VAD_TASK_NAME "lpwk_vad"
#define LPWK_AI_TASK_NAME "lpwk_ai"
#define LPWK_SEA_TASK_NAME "lpwk_sea"
typedef enum {
LPWK_SVC_VAD = 0,
LPWK_SVC_AI,
LPWK_SVC_SEA,
LPWK_SVC_MAX
} lpwk_svc_type;
typedef enum {
LPWK_LEVEL_MIN = 0,
LPWK_LEVEL_1 = LPWK_LEVEL_MIN,
LPWK_LEVEL_2,
LPWK_LEVEL_3,
LPWK_LEVEL_MAX
} lpwk_level_type;
typedef enum {
LPWK_VAD_MIN = 0,
LPWK_VAD_AVAD = LPWK_VAD_MIN,
LPWK_VAD_MAD,
LPWK_VAD_MAX
} lpwk_vad_type;
typedef enum {
LPWK_KWS_MIN = 0,
LPWK_KWS_3A_GRU = LPWK_KWS_MIN,
LPWK_KWS_3A_ANPU,
LPWK_KWS_GRU,
LPWK_KWS_ANPU,
LPWK_KWS_MAX
} lpwk_kws_type;
typedef struct {
lpwk_level_type level;
lpwk_vad_type vad_type;
lpwk_kws_type kws_type;
uapi_ai_port ai_port;
uapi_sea_lib_id afe_id;
uapi_sea_lib_id aai_id;
uapi_audio_pcm_format pcm_attr;
td_bool export_data;
} lpwk_cmd_opt;
typedef struct {
lpwk_cmd_opt *cmd_opt;
uapi_audio_pcm_format out_pcm;
lpwk_svc_type type;
athread_handle h_task;
td_bool task_enable;
td_char task_name[LPWK_TASK_NAME_LENGTH];
FILE *h_file;
td_u32 file_size;
td_u32 file_limit_size;
td_u32 (*save_frame)(FILE *h_file, const uapi_audio_frame *frame);
td_handle h_adp;
td_handle h_mod;
td_s32 (*close)(td_handle mod);
td_s32 (*start)(td_handle mod);
td_s32 (*stop)(td_handle mod);
td_s32 (*reset)(td_handle mod);
td_s32 (*attach)(td_handle mod, td_handle output);
td_s32 (*detach)(td_handle mod, td_handle output);
} lpwk_svc_inst;
typedef struct {
td_u32 phs_count;
td_u32 phs_match_cnt[LPWK_PHRASE_COUNT];
uapi_sea_item phrase[LPWK_PHRASE_COUNT];
} lpwk_phs_sets;
static td_bool g_lpwk_inst_inited = TD_FALSE;
static lpwk_cmd_opt g_lpwk_cmd_opt;
static lpwk_phs_sets g_lpwk_phs_sets;
static lpwk_svc_inst g_lpwk_inst[LPWK_SVC_MAX];
typedef td_s32 (*lpwk_fsm_next)(lpwk_svc_inst *vad_inst, lpwk_svc_inst *ai_inst, lpwk_svc_inst *sea_inst);
typedef td_s32 (*lpwk_event_proc)(td_handle mod, td_s32 event, const td_void *param, td_void *context);
static td_void lpwk_save_frame(lpwk_svc_inst *inst, const uapi_audio_frame *frame);
static td_void vad_reset_proc(td_void *args);
static td_s32 vad_event_proc(td_handle vad, td_s32 event, const td_void *param, td_void *context);
static td_s32 ai_event_proc(td_handle ai, td_s32 event, const td_void *param, td_void *context);
static td_void lpwk_start_task(lpwk_svc_inst *inst);
static td_void lpwk_stop_task(lpwk_svc_inst *inst);
static td_s32 lpwk_open_inst(lpwk_svc_inst *inst, lpwk_event_proc eproc, td_void *context);
static td_void lpwk_close_inst(lpwk_svc_inst *inst);
static td_s32 lpwk_open_kws_inst(lpwk_svc_inst *ai_inst, lpwk_svc_inst *sea_inst);
static td_s32 lpwk_close_kws_inst(lpwk_svc_inst *ai_inst, lpwk_svc_inst *sea_inst);
static td_s32 fsm_l3_start(lpwk_svc_inst *vad_inst, const lpwk_svc_inst *ai_inst, const lpwk_svc_inst *sea_inst)
{
td_s32 ret;
ret = lpwk_open_inst(vad_inst, vad_event_proc, (td_void *)vad_inst);
if (ret != EXT_SUCCESS) {
return ret;
}
if (vad_inst->reset != TD_NULL) {
vad_inst->reset(vad_inst->h_mod);
}
sap_unused(ai_inst);
sap_unused(sea_inst);
return EXT_SUCCESS;
}
static td_s32 fsm_l2_start(lpwk_svc_inst *vad_inst, lpwk_svc_inst *ai_inst, lpwk_svc_inst *sea_inst)
{
td_s32 ret;
lpwk_cmd_opt *cmd_opt = vad_inst->cmd_opt;
if (cmd_opt->vad_type == LPWK_VAD_AVAD) {
ret = lpwk_open_inst(vad_inst, vad_event_proc, (td_void *)vad_inst);
if (ret != EXT_SUCCESS) {
return ret;
}
if (vad_inst->reset != TD_NULL) {
vad_inst->reset(vad_inst->h_mod);
}
} else {
ret = lpwk_open_kws_inst(ai_inst, sea_inst);
if (ret != EXT_SUCCESS) {
return ret;
}
}
return EXT_SUCCESS;
}
static td_s32 fsm_l1_start(lpwk_svc_inst *vad_inst, lpwk_svc_inst *ai_inst, const lpwk_svc_inst *sea_inst)
{
td_s32 ret;
lpwk_cmd_opt *cmd_opt = vad_inst->cmd_opt;
if (cmd_opt->vad_type == LPWK_VAD_AVAD) {
ret = lpwk_open_inst(vad_inst, vad_event_proc, (td_void *)vad_inst);
if (ret != EXT_SUCCESS) {
return ret;
}
lpwk_start_task(vad_inst);
} else {
ret = lpwk_open_inst(ai_inst, ai_event_proc, (td_void *)ai_inst);
if (ret != EXT_SUCCESS) {
return ret;
}
lpwk_start_task(ai_inst);
}
audio_unused(sea_inst);
return EXT_SUCCESS;
}
static td_s32 lpwk_fsm_start(lpwk_level_type level, lpwk_svc_inst *vad_inst, lpwk_svc_inst *ai_inst,
lpwk_svc_inst *sea_inst)
{
switch (level) {
case LPWK_LEVEL_1:
return fsm_l1_start(vad_inst, ai_inst, sea_inst);
case LPWK_LEVEL_2:
return fsm_l2_start(vad_inst, ai_inst, sea_inst);
case LPWK_LEVEL_3:
return fsm_l3_start(vad_inst, ai_inst, sea_inst);
default:
break;
}
return EXT_SUCCESS;
}
static td_s32 fsm_l3_avad_valid_next(lpwk_svc_inst *vad_inst, lpwk_svc_inst *ai_inst, lpwk_svc_inst *sea_inst)
{
td_s32 ret;
lpwk_close_inst(vad_inst);
vad_inst->cmd_opt->vad_type = LPWK_VAD_MAD;
ret = lpwk_fsm_start(LPWK_LEVEL_2, vad_inst, ai_inst, sea_inst);
if (ret != EXT_SUCCESS) {
return ret;
}
return EXT_SUCCESS;
}
static td_s32 fsm_l3_mad_valid_next(const lpwk_svc_inst *vad_inst, lpwk_svc_inst *ai_inst, lpwk_svc_inst *sea_inst)
{
if (ai_inst->start != TD_NULL) {
ai_inst->start(ai_inst->h_mod);
}
if (sea_inst->start != TD_NULL) {
sea_inst->start(sea_inst->h_mod);
}
audio_unused(vad_inst);
return EXT_SUCCESS;
}
static td_s32 fsm_l3_sea_match_next(lpwk_svc_inst *vad_inst, lpwk_svc_inst *ai_inst, lpwk_svc_inst *sea_inst)
{
td_s32 ret;
if (sea_inst->stop != TD_NULL) {
sea_inst->stop(sea_inst->h_mod);
}
if (ai_inst->stop != TD_NULL) {
ai_inst->stop(ai_inst->h_mod);
}
ret = lpwk_close_kws_inst(ai_inst, sea_inst);
if (ret != EXT_SUCCESS) {
return ret;
}
ret = fsm_l3_start(vad_inst, ai_inst, sea_inst);
if (ret != EXT_SUCCESS) {
return ret;
}
return EXT_SUCCESS;
}
static td_s32 fsm_l2_avad_valid_next(lpwk_svc_inst *vad_inst, lpwk_svc_inst *ai_inst, lpwk_svc_inst *sea_inst)
{
td_s32 ret;
lpwk_close_inst(vad_inst);
ret = lpwk_open_kws_inst(ai_inst, sea_inst);
if (ret != EXT_SUCCESS) {
return ret;
}
if (ai_inst->start != TD_NULL) {
ai_inst->start(ai_inst->h_mod);
}
if (sea_inst->start != TD_NULL) {
sea_inst->start(sea_inst->h_mod);
}
return EXT_SUCCESS;
}
static td_s32 fsm_l2_mad_valid_next(const lpwk_svc_inst *vad_inst, lpwk_svc_inst *ai_inst, lpwk_svc_inst *sea_inst)
{
if (ai_inst->start != TD_NULL) {
ai_inst->start(ai_inst->h_mod);
}
if (sea_inst->start != TD_NULL) {
sea_inst->start(sea_inst->h_mod);
}
sap_unused(vad_inst);
return EXT_SUCCESS;
}
static td_s32 fsm_l2_sea_match_next(lpwk_svc_inst *vad_inst, lpwk_svc_inst *ai_inst, lpwk_svc_inst *sea_inst)
{
td_s32 ret;
if (sea_inst->cmd_opt->vad_type == LPWK_VAD_AVAD) {
ret = lpwk_close_kws_inst(ai_inst, sea_inst);
if (ret != EXT_SUCCESS) {
return ret;
}
ret = lpwk_open_inst(vad_inst, vad_event_proc, (td_void *)vad_inst);
if (ret != EXT_SUCCESS) {
return ret;
}
if (vad_inst->reset != TD_NULL) {
vad_inst->reset(vad_inst->h_mod);
}
} else {
if (ai_inst->reset != TD_NULL) {
ai_inst->reset(ai_inst->h_mod);
}
}
return EXT_SUCCESS;
}
static td_s32 fsm_l1_fsm_next(const lpwk_svc_inst *vad_inst, const lpwk_svc_inst *ai_inst,
const lpwk_svc_inst *sea_inst)
{
sap_unused(vad_inst);
sap_unused(ai_inst);
sap_unused(sea_inst);
return EXT_SUCCESS;
}
static td_s32 lpwk_fsm_next_vad(lpwk_level_type level, lpwk_svc_inst *vad_inst, lpwk_svc_inst *ai_inst,
lpwk_svc_inst *sea_inst)
{
switch (level) {
case LPWK_LEVEL_1:
return fsm_l1_fsm_next(vad_inst, ai_inst, sea_inst);
case LPWK_LEVEL_2:
return fsm_l2_avad_valid_next(vad_inst, ai_inst, sea_inst);
case LPWK_LEVEL_3:
return fsm_l3_avad_valid_next(vad_inst, ai_inst, sea_inst);
default:
break;
}
return EXT_SUCCESS;
}
static td_s32 lpwk_fsm_next_ai(lpwk_level_type level, lpwk_svc_inst *vad_inst, lpwk_svc_inst *ai_inst,
lpwk_svc_inst *sea_inst)
{
switch (level) {
case LPWK_LEVEL_1:
return fsm_l1_fsm_next(vad_inst, ai_inst, sea_inst);
case LPWK_LEVEL_2:
return fsm_l2_mad_valid_next(vad_inst, ai_inst, sea_inst);
case LPWK_LEVEL_3:
return fsm_l3_mad_valid_next(vad_inst, ai_inst, sea_inst);
default:
break;
}
return EXT_SUCCESS;
}
static td_s32 lpwk_fsm_next_sea(lpwk_level_type level, lpwk_svc_inst *vad_inst, lpwk_svc_inst *ai_inst,
lpwk_svc_inst *sea_inst)
{
switch (level) {
case LPWK_LEVEL_1:
return fsm_l1_fsm_next(vad_inst, ai_inst, sea_inst);
case LPWK_LEVEL_2:
return fsm_l2_sea_match_next(vad_inst, ai_inst, sea_inst);
case LPWK_LEVEL_3:
return fsm_l3_sea_match_next(vad_inst, ai_inst, sea_inst);
default:
break;
}
return EXT_SUCCESS;
}
static td_s32 lpwk_fsm_next_fun(lpwk_svc_type type, lpwk_level_type level, lpwk_svc_inst *vad_inst,
lpwk_svc_inst *ai_inst, lpwk_svc_inst *sea_inst)
{
switch (type) {
case LPWK_SVC_VAD:
return lpwk_fsm_next_vad(level, vad_inst, ai_inst, sea_inst);
case LPWK_SVC_AI:
return lpwk_fsm_next_ai(level, vad_inst, ai_inst, sea_inst);
case LPWK_SVC_SEA:
return lpwk_fsm_next_sea(level, vad_inst, ai_inst, sea_inst);
default:
break;
}
return EXT_SUCCESS;
}
static td_s32 vad_event_proc(td_handle vad, td_s32 event, const td_void *param, td_void *context)
{
uapi_vad_event_type vad_event = (uapi_vad_event_type)event;
lpwk_svc_inst *vad_inst = (lpwk_svc_inst *)context;
lpwk_svc_inst *ai_inst = &g_lpwk_inst[LPWK_SVC_AI];
lpwk_svc_inst *sea_inst = &g_lpwk_inst[LPWK_SVC_SEA];
if (vad_event == UAPI_VAD_EVENT_VAD_VALID) {
sap_err_log_h32(vad_event);
lpwk_fsm_next_fun(vad_inst->type, vad_inst->cmd_opt->level, vad_inst, ai_inst, sea_inst);
}
audio_unused(vad);
audio_unused(param);
return EXT_SUCCESS;
}
static td_s32 ai_event_proc(td_handle ai, td_s32 event, const td_void *param, td_void *context)
{
uapi_ai_event_type ai_event = (uapi_ai_event_type)event;
lpwk_svc_inst *ai_inst = (lpwk_svc_inst *)context;
lpwk_svc_inst *vad_inst = &g_lpwk_inst[LPWK_SVC_VAD];
lpwk_svc_inst *sea_inst = &g_lpwk_inst[LPWK_SVC_SEA];
if (ai_event == UAPI_AI_EVENT_VAD_VALID) {
#if (SAP_CHIP_TYPE == brandy)
uapi_set_hifi_mode(HIFI_LPM_CLK_HIGH_LEVEL);
#endif /* SAP_CHIP_TYPE */
sap_err_log_h32(ai_event);
lpwk_fsm_next_fun(ai_inst->type, ai_inst->cmd_opt->level, vad_inst, ai_inst, sea_inst);
} else if (ai_event == UAPI_AI_EVENT_VAD_TIMEOUT) {
sap_err_log_h32(ai_event);
lpwk_fsm_next_fun(sea_inst->type, ai_inst->cmd_opt->level, vad_inst, ai_inst, sea_inst);
} else {
}
audio_unused(ai);
audio_unused(param);
return EXT_SUCCESS;
}
static td_s32 sea_event_proc(td_handle sea, td_s32 event, const td_void *param, td_void *context)
{
td_u32 i;
uapi_sea_event_type sea_event = (uapi_sea_event_type)event;
uapi_sea_kws_event_param *event_param = (uapi_sea_kws_event_param *)param;
lpwk_phs_sets *phs_sets = &g_lpwk_phs_sets;
lpwk_svc_inst *sea_inst = (lpwk_svc_inst *)context;
lpwk_svc_inst *vad_inst = &g_lpwk_inst[LPWK_SVC_VAD];
lpwk_svc_inst *ai_inst = &g_lpwk_inst[LPWK_SVC_AI];
sap_err_log_h32(sea_event);
if (sea_event == UAPI_SEA_EVENT_KWS_MATCH) {
if (event_param->phrase_id == 0) {
return EXT_SUCCESS;
}
phs_sets->phs_match_cnt[event_param->phrase_id]++;
sap_printf("\n--------------------------------------------------");
sap_printf("cmdid %u\n", event_param->phrase_id);
for (i = 0; i < phs_sets->phs_count; i++) {
if (event_param->phrase_id == phs_sets->phrase[i].id) {
sap_printf("cmd: <%s>, cnt: %u\n", phs_sets->phrase[i].name,
phs_sets->phs_match_cnt[phs_sets->phrase[i].id]);
} else {
sap_printf("cmd: [%s], cnt: %u\n", phs_sets->phrase[i].name,
phs_sets->phs_match_cnt[phs_sets->phrase[i].id]);
}
}
sap_printf("\n--------------------------------------------------");
lpwk_fsm_next_fun(sea_inst->type, sea_inst->cmd_opt->level, vad_inst, ai_inst, sea_inst);
} else if (sea_event == UAPI_SEA_EVENT_VAD_END) {
#if (SAP_CHIP_TYPE == brandy)
uapi_set_hifi_mode(HIFI_LPM_CLK_LEVEL1);
#endif /* SAP_CHIP_TYPE */
if (ai_inst->stop != TD_NULL) {
ai_inst->stop(ai_inst->h_mod);
}
if (sea_inst->stop != TD_NULL) {
sea_inst->stop(sea_inst->h_mod);
}
lpwk_fsm_next_fun(sea_inst->type, sea_inst->cmd_opt->level, vad_inst, ai_inst, sea_inst);
}
audio_unused(sea);
return EXT_SUCCESS;
}
static td_void adp_data_proc(td_void *args)
{
td_s32 ret;
uapi_audio_frame frame;
lpwk_svc_inst *inst = (lpwk_svc_inst *)args;
while (inst->task_enable) {
ret = uapi_adp_acquire_frame(inst->h_adp, &frame);
if (ret != EXT_SUCCESS) {
sap_msleep(THREAD_SLEEP_10MS); /* */
continue;
}
lpwk_save_frame(inst, &frame);
(td_void)uapi_adp_release_frame(inst->h_adp, &frame);
}
athread_set_exit(inst->h_task, TD_TRUE);
}
static td_void vad_reset_proc(td_void *args)
{
td_s32 ret = EXT_SUCCESS;
lpwk_svc_inst *inst = (lpwk_svc_inst *)args;
while (inst->task_enable) {
sleep(LPWK_VAD_RESET_INTERVAL);
if (inst->cmd_opt->level == LPWK_LEVEL_1) {
if (inst->reset != TD_NULL) {
ret = inst->reset(inst->h_mod);
}
}
if (ret != EXT_SUCCESS) {
sap_err_log_fun(inst->reset, ret);
}
}
athread_set_exit(inst->h_task, TD_TRUE);
}
static td_u32 adp_save_frame(FILE *h_file, const uapi_audio_frame *frame)
{
td_u32 ret;
if (h_file == TD_NULL) {
return 0;
}
ret = fwrite((td_void *)frame->bits_buffer, 1, frame->bits_bytes, h_file);
return ret;
}
static td_s32 sea_attach_output(td_handle sea, td_handle output)
{
return uapi_sea_attach_output(sea, UAPI_SEA_OUTPUT_ASR_SRC, output);
}
static td_s32 sea_detach_output(td_handle sea, td_handle output)
{
return uapi_sea_detach_output(sea, UAPI_SEA_OUTPUT_ASR_SRC, output);
}
static td_void opt_set_ai_attr(lpwk_cmd_opt *cmd_opt, uapi_ai_attr *ai_attr)
{
(td_void)memset_s(ai_attr, sizeof(*ai_attr), 0, sizeof(*ai_attr));
uapi_ai_get_default_attr(cmd_opt->ai_port, ai_attr);
(td_void)memcpy_s(&ai_attr->pcm_attr, sizeof(ai_attr->pcm_attr),
&cmd_opt->pcm_attr, sizeof(cmd_opt->pcm_attr));
ai_attr->ref_attr.enable = TD_FALSE;
if ((cmd_opt->level == LPWK_LEVEL_3) || (cmd_opt->vad_type == LPWK_VAD_MAD)) {
ai_attr->vad_attr.enable = TD_TRUE;
} else {
ai_attr->vad_attr.enable = TD_FALSE;
}
switch (cmd_opt->ai_port) {
case UAPI_AI_PORT_PDM0:
case UAPI_AI_PORT_PDM1:
ai_attr->port_attr.pdm.rx_type = UAPI_AI_RX_MAD;
ai_attr->port_attr.pdm.i2s_attr.channels = ai_attr->pcm_attr.channels;
ai_attr->port_attr.pdm.i2s_attr.bit_depth = ai_attr->pcm_attr.bit_depth;
break;
case UAPI_AI_PORT_ADC0:
case UAPI_AI_PORT_LPADC0:
ai_attr->port_attr.adc.rx_type = UAPI_AI_RX_MAD;
break;
case UAPI_AI_PORT_I2S0:
case UAPI_AI_PORT_I2S1:
ai_attr->port_attr.i2s.i2s_attr.channels = ai_attr->pcm_attr.channels;
ai_attr->port_attr.i2s.i2s_attr.bit_depth = ai_attr->pcm_attr.bit_depth;
break;
default:
break;
}
}
static td_void opt_set_sea_attr(lpwk_cmd_opt *cmd_opt, uapi_sea_eng_sel *eng_sel, uapi_sea_attr *sea_attr)
{
(td_void)memset_s(eng_sel, sizeof(*eng_sel), 0, sizeof(*eng_sel));
if (cmd_opt->afe_id != UAPI_SEA_LIB_NULL) {
eng_sel->afe.type = UAPI_SEA_AFE_SEE;
eng_sel->afe.lib_id = cmd_opt->afe_id;
}
if (cmd_opt->aai_id != UAPI_SEA_LIB_NULL) {
eng_sel->aai[0].type = UAPI_SEA_AAI_KWS;
eng_sel->aai[0].lib_id = cmd_opt->aai_id;
}
uapi_sea_get_default_attr(eng_sel, sea_attr);
(td_void)memcpy_s(&sea_attr->in_pcm, sizeof(sea_attr->in_pcm),
&cmd_opt->pcm_attr, sizeof(cmd_opt->pcm_attr));
sea_attr->ref_pcm.channels = 0;
}
static td_void opt_load_sea_engine(uapi_sea_lib_id afe_id, uapi_sea_lib_id aai_id)
{
td_s32 ret;
if (afe_id != UAPI_SEA_LIB_NULL) {
ret = uapi_sea_load_engine(afe_id, "imedia_2mic");
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_sea_load_engine, ret);
}
}
if (aai_id != UAPI_SEA_LIB_NULL) {
ret = uapi_sea_load_engine(aai_id, "imedia_keyword");
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_sea_load_engine, ret);
}
}
}
static uapi_ai_port opt_get_ai_port(const td_char *port_name)
{
td_u32 i;
const struct {
const td_char *name;
uapi_ai_port ai_port;
} ai_port_name[] = {
{"pdm0", UAPI_AI_PORT_PDM0},
{"pdm1", UAPI_AI_PORT_PDM1},
{"i2s0", UAPI_AI_PORT_I2S0},
{"adc0", UAPI_AI_PORT_ADC0},
{"lpadc0", UAPI_AI_PORT_LPADC0},
};
for (i = 0; i < sizeof(ai_port_name) / sizeof(ai_port_name[0]); i++) {
if (strcmp(ai_port_name[i].name, port_name) == 0) {
return ai_port_name[i].ai_port;
}
}
return LPWK_AI_DEF_PORT;
}
static td_void opt_get_sea_lib_id(lpwk_kws_type type, uapi_sea_lib_id *afe_id, uapi_sea_lib_id *aai_id)
{
switch (type) {
case LPWK_KWS_3A_GRU:
*afe_id = UAPI_SEA_LIB_SEE;
*aai_id = UAPI_SEA_LIB_KWS;
break;
case LPWK_KWS_3A_ANPU:
*afe_id = UAPI_SEA_LIB_SEE;
*aai_id = UAPI_SEA_LIB_ASR;
break;
case LPWK_KWS_GRU:
*afe_id = UAPI_SEA_LIB_NULL;
*aai_id = UAPI_SEA_LIB_KWS;
break;
case LPWK_KWS_ANPU:
*afe_id = UAPI_SEA_LIB_NULL;
*aai_id = UAPI_SEA_LIB_ASR;
break;
default:
*afe_id = UAPI_SEA_LIB_SEE;
*aai_id = UAPI_SEA_LIB_KWS;
break;
}
}
static td_s32 lpwk_sys_init(td_void)
{
td_s32 ret;
ret = uapi_adp_init();
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_adp_init, ret);
return ret;
}
ret = uapi_vad_init();
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_vad_init, ret);
return ret;
}
ret = uapi_ai_init();
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_ai_init, ret);
return ret;
}
ret = uapi_sea_init();
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_sea_init, ret);
return ret;
}
return EXT_SUCCESS;
}
static td_void lpwk_sys_deinit(uapi_sea_lib_id afe_id, uapi_sea_lib_id aai_id)
{
td_s32 ret;
if (aai_id != UAPI_SEA_LIB_NULL) {
ret = uapi_sea_unload_engine(aai_id, "imedia_keyword");
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_sea_unload_engine, ret);
}
}
if (aai_id != UAPI_SEA_LIB_NULL) {
ret = uapi_sea_unload_engine(afe_id, "imedia_2mic");
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_sea_unload_engine, ret);
}
}
ret = uapi_sea_deinit();
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_sea_deinit, ret);
}
ret = uapi_vad_deinit();
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_vad_deinit, ret);
}
ret = uapi_ai_deinit();
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_ai_deinit, ret);
}
ret = uapi_adp_deinit();
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_adp_deinit, ret);
}
}
static td_s32 lpwk_open_file(lpwk_svc_inst *inst, td_char *dir)
{
td_s32 ret;
td_char *dir_path = TD_NULL;
td_char file_path[FILE_PATH_LEN];
uapi_audio_pcm_format *pcm_attr = &inst->out_pcm;
if (dir == TD_NULL) {
dir_path = FILE_STREAM_PATH;
} else {
dir_path = dir;
}
ret = snprintf_s(file_path, FILE_PATH_LEN - 1, FILE_PATH_LEN - 1,
"%s/%s_%uk_%ubit_%uch.pcm", dir_path, inst->task_name,
pcm_attr->sample_rate / HZ_NUM_PER_KHZ,
pcm_attr->bit_depth, pcm_attr->channels);
if (ret < 0) {
sap_err_log_fun(snprintf_s, ret);
return EXT_FAILURE;
}
inst->h_file = fopen(file_path, "a+");
if (inst->h_file == TD_NULL) {
sap_printf("open %s failed", file_path);
return EXT_FAILURE;
}
inst->save_frame = adp_save_frame;
inst->file_limit_size = (pcm_attr->channels * pcm_attr->bit_depth / BITS_NUM_PER_BYTE) *
(pcm_attr->sample_rate * LPWK_STREAM_MAX_DUR);
return EXT_SUCCESS;
}
static td_void lpwk_save_frame(lpwk_svc_inst *inst, const uapi_audio_frame *frame)
{
inst->file_size += frame->bits_bytes;
if (inst->file_size >= inst->file_limit_size) {
return;
}
if (inst->save_frame(inst->h_file, frame) == 0) {
inst->file_size = inst->file_limit_size;
}
}
static td_void lpwk_opt_init(lpwk_cmd_opt *lpwk_opt)
{
(td_void)memset_s(lpwk_opt, sizeof(*lpwk_opt), 0, sizeof(*lpwk_opt));
lpwk_opt->level = LPWK_LEVEL_3;
lpwk_opt->vad_type = LPWK_VAD_MAD;
lpwk_opt->kws_type = LPWK_KWS_3A_GRU;
lpwk_opt->ai_port = LPWK_AI_DEF_PORT;
lpwk_opt->pcm_attr.channels = UAPI_AUDIO_CHANNEL_1;
lpwk_opt->pcm_attr.bit_depth = UAPI_AUDIO_BIT_DEPTH_16;
lpwk_opt->pcm_attr.sample_rate = UAPI_AUDIO_SAMPLE_RATE_16K;
lpwk_opt->pcm_attr.sample_per_frame = lpwk_opt->pcm_attr.sample_rate / 100; /* 100 --> 10ms */
lpwk_opt->export_data = TD_FALSE;
}
static td_void lpwk_inst_init(lpwk_svc_inst *inst, const lpwk_cmd_opt *lpwk_opt, const td_char *task_name)
{
td_s32 ret;
(td_void)memset_s(inst, sizeof(*inst), 0, sizeof(*inst));
inst->cmd_opt = (lpwk_cmd_opt *)lpwk_opt;
inst->out_pcm.channels = UAPI_AUDIO_CHANNEL_1;
inst->out_pcm.bit_depth = UAPI_AUDIO_BIT_DEPTH_16;
inst->out_pcm.sample_rate = UAPI_AUDIO_SAMPLE_RATE_16K;
inst->out_pcm.sample_per_frame = inst->out_pcm.sample_rate / 100; /* 100 --> 10ms */
if (task_name == TD_NULL) {
return;
}
ret = strncpy_s(inst->task_name, sizeof(inst->task_name), task_name, strlen(task_name));
if (ret != EOK) {
sap_err_log_fun(strncpy_s, ret);
}
}
static td_s32 lpwk_open_vad(lpwk_svc_inst *inst, lpwk_event_proc eproc, td_void *context)
{
td_s32 ret;
uapi_vad_attr vad_attr;
uapi_vad_get_default_attr(&vad_attr);
ret = uapi_vad_open(&inst->h_mod, &vad_attr);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_vad_open, ret);
return ret;
}
(td_void)uapi_vad_register_event_proc(inst->h_mod, (uapi_vad_event_proc)eproc, context);
(td_void)memset_s(&inst->out_pcm, sizeof(inst->out_pcm), 0, sizeof(inst->out_pcm));
inst->close = uapi_vad_close;
inst->start = TD_NULL;
inst->stop = TD_NULL;
inst->reset = uapi_vad_reset;
inst->attach = TD_NULL;
inst->detach = TD_NULL;
return EXT_SUCCESS;
}
static td_s32 lpwk_open_ai(lpwk_svc_inst *inst, lpwk_event_proc eproc, td_void *context)
{
td_s32 ret;
uapi_ai_attr ai_attr;
opt_set_ai_attr(inst->cmd_opt, &ai_attr);
ret = uapi_ai_open(&inst->h_mod, inst->cmd_opt->ai_port, &ai_attr);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_ai_open, ret);
return ret;
}
(td_void)uapi_ai_register_event_proc(inst->h_mod, (uapi_ai_event_proc)eproc, context);
(td_void)memcpy_s(&inst->out_pcm, sizeof(inst->out_pcm), &ai_attr.pcm_attr, sizeof(ai_attr.pcm_attr));
inst->close = uapi_ai_close;
inst->start = uapi_ai_start;
inst->stop = uapi_ai_stop;
inst->reset = uapi_ai_reset_vad;
inst->attach = uapi_ai_attach_output;
inst->detach = uapi_ai_detach_output;
return EXT_SUCCESS;
}
static td_s32 lpwk_open_sea(lpwk_svc_inst *inst, lpwk_event_proc eproc, td_void *context)
{
td_s32 ret;
uapi_sea_attr sea_attr;
uapi_sea_eng_sel sea_eng;
uapi_sea_item_sets item_sets;
lpwk_phs_sets *phs_sets = &g_lpwk_phs_sets;
opt_load_sea_engine(inst->cmd_opt->afe_id, inst->cmd_opt->aai_id);
opt_set_sea_attr(inst->cmd_opt, &sea_eng, &sea_attr);
ret = uapi_sea_create(&inst->h_mod, &sea_eng, &sea_attr);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_sea_create, ret);
return ret;
}
(td_void)uapi_sea_register_event_proc(inst->h_mod, (uapi_sea_event_proc)eproc, context);
(td_void)memcpy_s(&inst->out_pcm, sizeof(inst->out_pcm),
&sea_attr.out_pcm[UAPI_SEA_OUTPUT_ASR_SRC],
sizeof(sea_attr.out_pcm[UAPI_SEA_OUTPUT_ASR_SRC]));
item_sets.size = LPWK_PHRASE_COUNT;
item_sets.array = phs_sets->phrase;
ret = uapi_sea_get_phrase_sets(inst->h_mod, &item_sets);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_sea_get_phrase_sets, ret);
}
phs_sets->phs_count = item_sets.count;
inst->close = uapi_sea_destroy;
inst->start = uapi_sea_start;
inst->stop = uapi_sea_stop;
inst->reset = TD_NULL;
inst->attach = sea_attach_output;
inst->detach = sea_detach_output;
return EXT_SUCCESS;
}
static td_s32 lpwk_open_inst(lpwk_svc_inst *inst, lpwk_event_proc eproc, td_void *context)
{
td_s32 ret;
uapi_adp_attr adp_attr;
if (strcmp(inst->task_name, LPWK_VAD_TASK_NAME) == 0) {
inst->type = LPWK_SVC_VAD;
ret = lpwk_open_vad(inst, eproc, context);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(lpwk_open_vad, ret);
return ret;
}
} else if (strcmp(inst->task_name, LPWK_AI_TASK_NAME) == 0) {
inst->type = LPWK_SVC_AI;
ret = lpwk_open_ai(inst, eproc, context);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(lpwk_open_ai, ret);
return ret;
}
} else if (strcmp(inst->task_name, LPWK_SEA_TASK_NAME) == 0) {
inst->type = LPWK_SVC_SEA;
ret = lpwk_open_sea(inst, eproc, context);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(lpwk_open_sea, ret);
return ret;
}
} else {
sap_err_log_ret(EXT_FAILURE);
return EXT_FAILURE;
}
if (inst->cmd_opt->export_data == TD_TRUE) {
(td_void)memset_s(&adp_attr, sizeof(adp_attr), 0, sizeof(adp_attr));
ret = uapi_adp_create(&inst->h_adp, &adp_attr);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_adp_create, ret);
if (inst->close != TD_NULL) {
inst->close(inst->h_mod);
inst->h_mod = 0;
}
return ret;
}
}
return EXT_SUCCESS;
}
static td_void lpwk_close_inst(lpwk_svc_inst *inst)
{
if (inst->task_enable) {
return;
}
if (inst->h_mod != 0) {
if (inst->close != TD_NULL) {
inst->close(inst->h_mod);
}
inst->h_mod = 0;
}
if (inst->h_adp != 0) {
uapi_adp_destroy(inst->h_adp);
inst->h_adp = 0;
}
}
static td_void lpwk_start_task(lpwk_svc_inst *inst)
{
td_s32 ret;
athread_attr task_attr;
(td_void)memset_s(&task_attr, sizeof(task_attr), 0, sizeof(task_attr));
task_attr.priority = ATHREAD_PRIORITY_NORMAL;
task_attr.stack_size = 0x1000; /* 4k */
task_attr.name = inst->task_name;
if (inst->cmd_opt->level == LPWK_LEVEL_1) { /* Level1 no data export */
inst->task_enable = TD_TRUE;
ret = athread_create(&inst->h_task, vad_reset_proc, (td_void *)inst, &task_attr);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(athread_create, ret);
}
} else { /* L2&L3 support data export */
if (inst->cmd_opt->export_data == TD_TRUE) {
ret = lpwk_open_file(inst, TD_NULL);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(lpwk_open_file, ret);
return;
}
if (inst->attach == TD_NULL) {
return;
}
ret = inst->attach(inst->h_mod, inst->h_adp);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(inst->attach, ret);
return;
}
inst->task_enable = TD_TRUE;
ret = athread_create(&inst->h_task, adp_data_proc, (td_void *)inst, &task_attr);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(athread_create, ret);
}
}
}
}
static td_void lpwk_stop_task(lpwk_svc_inst *inst)
{
td_s32 ret;
if (inst->stop != TD_NULL) {
ret = inst->stop(inst->h_mod);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(inst->stop, ret);
}
}
/* Destory Task to stop ADP instance reading pcm data */
inst->task_enable = TD_FALSE;
if (inst->h_task != TD_NULL) {
athread_exit(inst->h_task);
inst->h_task = TD_NULL;
}
/* Destory Task to stop ADP instance reading pcm data */
if (inst->cmd_opt->export_data == TD_TRUE) {
if (inst->detach != TD_NULL) {
ret = inst->detach(inst->h_mod, inst->h_adp);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(inst->detach, ret);
}
}
if (inst->h_file != TD_NULL) {
fclose(inst->h_file);
inst->h_file = TD_NULL;
}
}
}
static td_s32 lpwk_open_kws_inst(lpwk_svc_inst *ai_inst, lpwk_svc_inst *sea_inst)
{
td_s32 ret;
/* IPC wakeup DSP from Deep Standby */
ret = lpwk_open_inst(ai_inst, ai_event_proc, (td_void *)ai_inst);
if (ret != EXT_SUCCESS) {
return ret;
}
ret = lpwk_open_inst(sea_inst, sea_event_proc, (td_void *)sea_inst);
if (ret != EXT_SUCCESS) {
lpwk_close_inst(ai_inst);
return ret;
}
if (ai_inst->attach != TD_NULL) {
ret = ai_inst->attach(ai_inst->h_mod, sea_inst->h_mod);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(ai_inst->attach, ret);
}
}
lpwk_start_task(sea_inst);
lpwk_start_task(ai_inst);
return EXT_SUCCESS;
}
static td_s32 lpwk_close_kws_inst(lpwk_svc_inst *ai_inst, lpwk_svc_inst *sea_inst)
{
td_s32 ret;
lpwk_stop_task(sea_inst);
lpwk_stop_task(ai_inst);
if (ai_inst->stop != TD_NULL) {
ai_inst->stop(ai_inst->h_mod);
}
if (sea_inst->stop != TD_NULL) {
sea_inst->stop(sea_inst->h_mod);
}
if (ai_inst->detach != TD_NULL) {
ret = ai_inst->detach(ai_inst->h_mod, sea_inst->h_mod);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(ai_inst->attach, ret);
}
}
lpwk_close_inst(sea_inst);
lpwk_close_inst(ai_inst);
/* DSP auto enter Deep Standby */
return EXT_SUCCESS;
}
static td_void sample_lpwk_usage(const td_char *name)
{
sap_printf(" usage: %s -l [level] -p [port] -v [vad_type] -w [kws_type]\n", name);
sap_printf(" -h show this usage message and abort\n");
sap_printf(" -l level of lowper wakeup(range: 1~3, default: 3)\n"
" -v specify vad type for level 1&2(0:avad, 1:mad, default:0)\n"
" -w specify kws type for level 2&3(0:3a+gru, 1:3a+anpu, 2:gru, 3:anpu, defualt:0)\n"
" -p specify ai port(mad0, adc0, lpadc0, i2s0, i2s1)\n"
" -c channels of ai port(default:1)\n"
" -b bit depth of ai port(default:16)\n"
" -s samplerate of ai port(default:16000)\n"
" -d export data(0:diable, 1:enable, default:0)\n"
"\n");
sap_printf(" examples:\n");
sap_printf(" %s -l 3 -p pdm0\n", name);
sap_printf(" %s -l 2 -p pdm0 -v 0 -w 0\n", name);
sap_printf(" %s -l 2 -p pdm0 -v 1 -w 0\n", name);
sap_printf(" %s -l 1 -p pdm0 -v 0\n", name);
sap_printf(" %s -l 1 -p pdm0 -v 1\n", name);
sap_printf(" %s -l 3 -p adc0\n", name);
sap_printf(" %s -l 2 -p adc0 -v 0 -w 0\n", name);
sap_printf(" %s -l 2 -p adc0 -v 1 -w 0\n", name);
sap_printf(" %s -l 1 -p adc0 -v 0\n", name);
sap_printf(" %s -l 1 -p adc0 -v 1\n", name);
sap_printf("\n");
}
static td_s32 lpwk_parse_opt(td_s32 opt, const td_char *opt_arg, lpwk_cmd_opt *cmd_opt)
{
if (opt == 'h') {
return EXT_FAILURE;
}
if (opt_arg == TD_NULL) {
sap_printf("invalid option -- '%c'\n", (td_char)opt);
return EXT_FAILURE;
}
switch (opt) {
case 'l':
cmd_opt->level = (lpwk_level_type)(strtol(opt_arg, TD_NULL, 0) - 1);
break;
case 'v':
cmd_opt->vad_type = (lpwk_vad_type)strtol(opt_arg, TD_NULL, 0);
break;
case 'w':
cmd_opt->kws_type = (lpwk_kws_type)strtol(opt_arg, TD_NULL, 0);
break;
case 'p':
cmd_opt->ai_port = opt_get_ai_port(opt_arg);
break;
case 'c':
cmd_opt->pcm_attr.channels = (td_u32)strtol(opt_arg, TD_NULL, 0);
break;
case 'b':
cmd_opt->pcm_attr.bit_depth = (td_u32)strtol(opt_arg, TD_NULL, 0);
break;
case 's':
cmd_opt->pcm_attr.sample_rate = (td_u32)strtol(opt_arg, TD_NULL, 0);
break;
case 'd':
cmd_opt->export_data = (strtol(opt_arg, TD_NULL, 0) == 0 ? TD_FALSE : TD_TRUE);
break;
default:
sap_printf("invalid command line\n");
return EXT_FAILURE;
}
return EXT_SUCCESS;
}
static td_s32 lpwk_parse_cmd_line(td_s32 argc, td_char *argv[], lpwk_cmd_opt *cmd_opt)
{
td_s32 opt;
if (argv == TD_NULL) {
return EXT_FAILURE;
}
#if (SAP_CHIP_TYPE != socmn1)
optind = 0;
opterr = 0;
while (TD_TRUE) {
opt = getopt(argc, argv, "l:v:w:p:c:b:s:d:h");
if (opt == -1) {
break;
}
if (lpwk_parse_opt(opt, optarg, cmd_opt) != EXT_SUCCESS) {
sample_lpwk_usage(argv[0]);
return EXT_FAILURE;
}
}
#endif
if ((cmd_opt->level >= LPWK_LEVEL_MAX || cmd_opt->level < LPWK_LEVEL_MIN) ||
(cmd_opt->vad_type >= LPWK_VAD_MAX || cmd_opt->vad_type < LPWK_VAD_MIN) ||
(cmd_opt->kws_type >= LPWK_KWS_MAX || cmd_opt->kws_type < LPWK_KWS_MIN)) {
sample_lpwk_usage(argv[0]);
return EXT_FAILURE;
}
opt_get_sea_lib_id(cmd_opt->kws_type, &cmd_opt->afe_id, &cmd_opt->aai_id);
cmd_opt->pcm_attr.sample_per_frame = cmd_opt->pcm_attr.sample_rate / 100; /* 100 --> 10ms */
return EXT_SUCCESS;
}
static td_s32 sample_lpwk_entry(td_s32 argc, td_char *argv[])
{
td_s32 ret;
lpwk_cmd_opt *cmd_opt = &g_lpwk_cmd_opt;
lpwk_phs_sets *phs_sets = &g_lpwk_phs_sets;
lpwk_svc_inst *vad_inst = &g_lpwk_inst[LPWK_SVC_VAD];
lpwk_svc_inst *ai_inst = &g_lpwk_inst[LPWK_SVC_AI];
lpwk_svc_inst *sea_inst = &g_lpwk_inst[LPWK_SVC_SEA];
#if (SAP_CHIP_TYPE == brandy)
uapi_set_hifi_mode(HIFI_LPM_CLK_LEVEL1);
#endif /* SAP_CHIP_TYPE */
(td_void)memset_s(phs_sets, sizeof(*phs_sets), 0, sizeof(*phs_sets));
lpwk_opt_init(cmd_opt);
lpwk_inst_init(vad_inst, cmd_opt, LPWK_VAD_TASK_NAME);
lpwk_inst_init(ai_inst, cmd_opt, LPWK_AI_TASK_NAME);
lpwk_inst_init(sea_inst, cmd_opt, LPWK_SEA_TASK_NAME);
g_lpwk_inst_inited = TD_TRUE;
ret = lpwk_parse_cmd_line(argc, argv, cmd_opt);
if (ret != EXT_SUCCESS) {
return ret;
}
ret = lpwk_sys_init();
if (ret != EXT_SUCCESS) {
return ret;
}
ret = lpwk_fsm_start(cmd_opt->level, vad_inst, ai_inst, sea_inst);
if (ret != EXT_SUCCESS) {
lpwk_sys_deinit(cmd_opt->afe_id, cmd_opt->aai_id);
return ret;
}
return EXT_SUCCESS;
}
static td_s32 sample_lpwk_exit(td_void)
{
td_s32 ret;
lpwk_cmd_opt *cmd_opt = &g_lpwk_cmd_opt;
lpwk_svc_inst *vad_inst = &g_lpwk_inst[LPWK_SVC_VAD];
lpwk_svc_inst *ai_inst = &g_lpwk_inst[LPWK_SVC_AI];
lpwk_svc_inst *sea_inst = &g_lpwk_inst[LPWK_SVC_SEA];
if (g_lpwk_inst_inited == TD_FALSE) {
return EXT_SUCCESS;
}
lpwk_stop_task(sea_inst);
lpwk_stop_task(ai_inst);
lpwk_stop_task(vad_inst);
/* Detach SEA instance from AI instance */
if ((ai_inst->detach != TD_NULL) && (ai_inst->h_mod != 0) && (sea_inst->h_mod != 0)) {
ret = ai_inst->detach(ai_inst->h_mod, sea_inst->h_mod);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(ai_inst->detach, ret);
}
}
lpwk_close_inst(sea_inst);
lpwk_close_inst(ai_inst);
lpwk_close_inst(vad_inst);
lpwk_sys_deinit(cmd_opt->afe_id, cmd_opt->aai_id);
g_lpwk_inst_inited = TD_FALSE;
return EXT_SUCCESS;
}
td_s32 sample_lpwk(td_s32 argc, td_char *argv[])
{
if (argc <= 1) {
sample_lpwk_usage(argv[0]);
return EXT_SUCCESS;
}
if (strcmp(argv[1], "q") == 0) {
return sample_lpwk_exit();
} else {
return sample_lpwk_entry(argc, argv);
}
return EXT_SUCCESS;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif