874 lines
22 KiB
C
874 lines
22 KiB
C
/*
|
||
* Copyright (c) CompanyNameMagicTag 2019-2022. All rights reserved.
|
||
* Description: ai sample
|
||
* Author: audio
|
||
* Create: 2019-09-17
|
||
*/
|
||
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <unistd.h>
|
||
|
||
#include "thread_os.h"
|
||
#include "osal_list.h"
|
||
#include "soc_uapi_adp.h"
|
||
#include "soc_uapi_ai.h"
|
||
#include "soc_uapi_sea.h"
|
||
#include "sample_audio_api.h"
|
||
#include "sample_audio_utils.h"
|
||
|
||
#ifdef __cplusplus
|
||
#if __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
#endif
|
||
|
||
typedef struct {
|
||
td_bool task_enable;
|
||
athread_handle task;
|
||
td_bool sea_enable;
|
||
td_bool mute;
|
||
|
||
td_handle h_adp;
|
||
td_handle h_aenc;
|
||
td_handle h_ai;
|
||
td_handle h_sea;
|
||
td_handle h_player;
|
||
uapi_ai_port ai_port;
|
||
uapi_ai_gain volume;
|
||
uapi_acodec_id acodec_id;
|
||
uapi_audio_pcm_format pcm_format;
|
||
struct osal_list_head node;
|
||
} sample_ai_aenc_inst;
|
||
|
||
static OSAL_LIST_HEAD(g_sample_ai_aenc_list);
|
||
|
||
static sample_ai_aenc_inst *sample_ai_aenc_alloc_inst(td_void)
|
||
{
|
||
sample_ai_aenc_inst *inst = (sample_ai_aenc_inst *)malloc(sizeof(sample_ai_aenc_inst));
|
||
if (inst == TD_NULL) {
|
||
return TD_NULL;
|
||
}
|
||
|
||
(td_void)memset_s(inst, sizeof(*inst), 0, sizeof(sample_ai_aenc_inst));
|
||
|
||
osal_list_add_tail(&inst->node, &g_sample_ai_aenc_list);
|
||
return inst;
|
||
}
|
||
|
||
static td_void sample_ai_aenc_free_inst(sample_ai_aenc_inst *inst)
|
||
{
|
||
if (inst == TD_NULL) {
|
||
return;
|
||
}
|
||
|
||
osal_list_del(&inst->node);
|
||
free(inst);
|
||
}
|
||
|
||
static sample_ai_aenc_inst *sample_ai_aenc_get_inst(td_void)
|
||
{
|
||
if (osal_list_empty(&g_sample_ai_aenc_list) != TD_FALSE) {
|
||
return TD_NULL;
|
||
}
|
||
|
||
return osal_list_first_entry(&g_sample_ai_aenc_list, sample_ai_aenc_inst, node);
|
||
}
|
||
|
||
static td_void sample_ai_aenc_thread(td_void *args)
|
||
{
|
||
td_s32 ret;
|
||
uapi_stream_buf stream;
|
||
sample_ai_aenc_inst *inst = (sample_ai_aenc_inst *)args;
|
||
|
||
if (inst == TD_NULL) {
|
||
sap_err_log_info("ai_aenc_inst is null");
|
||
return;
|
||
}
|
||
|
||
while (inst->task_enable) {
|
||
ret = uapi_adp_acquire_stream(inst->h_adp, &stream);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_msleep(THREAD_SLEEP_10MS); /* */
|
||
continue;
|
||
}
|
||
|
||
while (inst->task_enable) {
|
||
ret = uapi_adp_send_stream(inst->h_player, &stream);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_msleep(THREAD_SLEEP_10MS); /* */
|
||
continue;
|
||
}
|
||
break;
|
||
}
|
||
|
||
ret = uapi_adp_release_stream(inst->h_adp, &stream);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_adp_release_stream, ret);
|
||
}
|
||
}
|
||
|
||
athread_set_exit(inst->task, TD_TRUE);
|
||
}
|
||
|
||
static td_s32 sample_ai_aenc_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_ai_init();
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_ai_init, ret);
|
||
goto out0;
|
||
}
|
||
|
||
ret = uapi_sea_init();
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_sea_init, ret);
|
||
goto out1;
|
||
}
|
||
|
||
ret = uapi_sea_load_engine(UAPI_SEA_LIB_SEE, "imedia_2mic");
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_sea_load_engine, ret);
|
||
goto out2;
|
||
}
|
||
|
||
ret = uapi_aenc_init();
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_init, ret);
|
||
goto out3;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
out3:
|
||
(td_void)uapi_sea_unload_engine(UAPI_SEA_LIB_SEE, "imedia_2mic");
|
||
out2:
|
||
(td_void)uapi_sea_deinit();
|
||
out1:
|
||
(td_void)uapi_ai_deinit();
|
||
out0:
|
||
(td_void)uapi_adp_deinit();
|
||
return ret;
|
||
}
|
||
|
||
static td_void sample_ai_aenc_sys_deinit(td_void)
|
||
{
|
||
td_s32 ret;
|
||
|
||
ret = uapi_aenc_deinit();
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_deinit, ret);
|
||
}
|
||
|
||
ret = uapi_sea_unload_engine(UAPI_SEA_LIB_SEE, "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_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_void sample_ai_aenc_close_adp(sample_ai_aenc_inst *inst)
|
||
{
|
||
if (inst->h_adp != 0) {
|
||
uapi_adp_destroy(inst->h_adp);
|
||
inst->h_adp = 0;
|
||
}
|
||
}
|
||
|
||
static td_s32 sample_ai_aenc_open_adp(sample_ai_aenc_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
uapi_adp_attr adp_attr;
|
||
|
||
inst->h_adp = 0;
|
||
|
||
ret = uapi_adp_get_def_attr(&adp_attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_adp_get_def_attr, ret);
|
||
return ret;
|
||
}
|
||
|
||
ret = uapi_adp_create(&inst->h_adp, &adp_attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_adp_create, ret);
|
||
return ret;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
static td_void sample_ai_aenc_close_aenc(sample_ai_aenc_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
|
||
if (inst->h_aenc == 0) {
|
||
return;
|
||
}
|
||
|
||
ret = uapi_aenc_detach_output(inst->h_aenc, inst->h_adp);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_detach_output, ret);
|
||
}
|
||
|
||
ret = uapi_aenc_destroy(inst->h_aenc);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_destroy, ret);
|
||
}
|
||
|
||
inst->h_aenc = 0;
|
||
}
|
||
|
||
static td_s32 sample_ai_aenc_open_aenc(sample_ai_aenc_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
uapi_aenc_attr aenc_attr;
|
||
|
||
inst->h_aenc = 0;
|
||
ret = uapi_aenc_create(&inst->h_aenc);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_create, ret);
|
||
return ret;
|
||
}
|
||
|
||
ret = uapi_aenc_get_attr(inst->h_aenc, &aenc_attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_get_attr, ret);
|
||
goto out;
|
||
}
|
||
|
||
aenc_attr.codec_id = inst->acodec_id;
|
||
aenc_attr.param.interleaved = TD_TRUE;
|
||
aenc_attr.param.channels = inst->pcm_format.channels;
|
||
aenc_attr.param.bit_depth = inst->pcm_format.bit_depth;
|
||
aenc_attr.param.sample_rate = inst->pcm_format.sample_rate;
|
||
aenc_attr.param.samples_per_frame = inst->pcm_format.sample_per_frame;
|
||
aenc_attr.param.private_data = TD_NULL;
|
||
aenc_attr.param.private_data_size = 0;
|
||
|
||
ret = uapi_aenc_set_attr(inst->h_aenc, &aenc_attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_set_attr, ret);
|
||
goto out;
|
||
}
|
||
|
||
ret = uapi_aenc_attach_output(inst->h_aenc, inst->h_adp);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_attach_output, ret);
|
||
goto out;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
|
||
out:
|
||
(td_void)uapi_aenc_destroy(inst->h_aenc);
|
||
return ret;
|
||
}
|
||
|
||
static td_void sample_ai_aenc_close_sea(sample_ai_aenc_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
|
||
if (inst->h_sea == 0) {
|
||
return;
|
||
}
|
||
|
||
ret = uapi_sea_detach_output(inst->h_sea, UAPI_SEA_OUTPUT_ASR_SRC, inst->h_aenc);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_sea_detach_output, ret);
|
||
}
|
||
|
||
ret = uapi_sea_destroy(inst->h_sea);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_sea_destroy, ret);
|
||
}
|
||
|
||
inst->h_sea = 0;
|
||
}
|
||
|
||
static td_s32 sample_ai_aenc_open_sea(sample_ai_aenc_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
uapi_sea_attr sea_attr;
|
||
uapi_sea_eng_sel sea_eng;
|
||
uapi_sea_afe_attr afe_attr = {
|
||
.type = UAPI_SEA_AFE_SEE,
|
||
.mode = UAPI_SEA_NORM_MODE,
|
||
.u.see.options = UAPI_SEA_AFE_OPT_AGC,
|
||
};
|
||
|
||
inst->h_sea = 0;
|
||
if (!inst->sea_enable) {
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
/* Create SEA instance */
|
||
(td_void)memset_s(&sea_eng, sizeof(sea_eng), 0, sizeof(sea_eng));
|
||
sea_eng.afe.type = UAPI_SEA_AFE_SEE;
|
||
sea_eng.afe.lib_id = UAPI_SEA_LIB_SEE;
|
||
ret = uapi_sea_get_default_attr(&sea_eng, &sea_attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_sea_get_default_attr, ret);
|
||
return ret;
|
||
}
|
||
|
||
sea_attr.in_pcm.bit_depth = inst->pcm_format.bit_depth;
|
||
sea_attr.in_pcm.channels = inst->pcm_format.channels;
|
||
sea_attr.in_pcm.sample_rate = inst->pcm_format.sample_rate;
|
||
sea_attr.in_pcm.sample_per_frame = inst->pcm_format.sample_per_frame;
|
||
sea_attr.ref_pcm.channels = 0;
|
||
ret = uapi_sea_create(&inst->h_sea, &sea_eng, &sea_attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_sea_create, ret);
|
||
return ret;
|
||
}
|
||
|
||
ret = uapi_sea_set_afe_attr(inst->h_sea, UAPI_SEA_AFE_SEE, &afe_attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_sea_set_afe_attr, ret);
|
||
goto out;
|
||
}
|
||
|
||
ret = uapi_sea_attach_output(inst->h_sea, UAPI_SEA_OUTPUT_ASR_SRC, inst->h_aenc);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_sea_attach_output, ret);
|
||
goto out;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
out:
|
||
(td_void)uapi_sea_destroy(inst->h_sea);
|
||
return ret;
|
||
}
|
||
|
||
static td_void sample_ai_aenc_close_ai(sample_ai_aenc_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
|
||
if (inst->h_ai == 0) {
|
||
return;
|
||
}
|
||
|
||
if (inst->h_sea != 0) {
|
||
ret = uapi_ai_detach_output(inst->h_ai, inst->h_sea);
|
||
} else {
|
||
ret = uapi_ai_detach_output(inst->h_ai, inst->h_aenc);
|
||
}
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_ai_detach_output, ret);
|
||
}
|
||
|
||
ret = uapi_ai_close(inst->h_ai);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_ai_close, ret);
|
||
}
|
||
|
||
inst->h_ai = 0;
|
||
}
|
||
|
||
static td_void sample_ai_aenc_set_port_attr(const sample_ai_aenc_inst *inst, uapi_ai_attr *ai_attr)
|
||
{
|
||
td_s32 ret;
|
||
|
||
ret = memcpy_s(&ai_attr->pcm_attr, sizeof(ai_attr->pcm_attr), &inst->pcm_format,
|
||
sizeof(inst->pcm_format));
|
||
if (ret != EOK) {
|
||
return;
|
||
}
|
||
|
||
ai_attr->ref_attr.enable = TD_FALSE;
|
||
|
||
switch (inst->ai_port) {
|
||
case UAPI_AI_PORT_PDM0:
|
||
case UAPI_AI_PORT_PDM1:
|
||
ai_attr->port_attr.pdm.i2s_attr.channels = inst->pcm_format.channels;
|
||
ai_attr->port_attr.pdm.i2s_attr.bit_depth = inst->pcm_format.bit_depth;
|
||
break;
|
||
|
||
case UAPI_AI_PORT_ADC0:
|
||
case UAPI_AI_PORT_I2S0:
|
||
case UAPI_AI_PORT_I2S1:
|
||
ai_attr->port_attr.i2s.i2s_attr.channels = inst->pcm_format.channels;
|
||
ai_attr->port_attr.i2s.i2s_attr.bit_depth = inst->pcm_format.bit_depth;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
static td_s32 sample_ai_aenc_open_ai(sample_ai_aenc_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
uapi_ai_attr ai_attr;
|
||
|
||
ret = uapi_ai_get_default_attr(inst->ai_port, &ai_attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_ai_get_default_attr, ret);
|
||
return ret;
|
||
}
|
||
|
||
sample_ai_aenc_set_port_attr(inst, &ai_attr);
|
||
|
||
ret = uapi_ai_open(&inst->h_ai, inst->ai_port, &ai_attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_ai_open, ret);
|
||
return ret;
|
||
}
|
||
|
||
ret = uapi_ai_set_volume(inst->h_ai, &inst->volume);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_ai_set_volume, ret);
|
||
goto out;
|
||
}
|
||
|
||
ret = uapi_ai_set_mute(inst->h_ai, inst->mute);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_ai_set_mute, ret);
|
||
goto out;
|
||
}
|
||
|
||
if (inst->h_sea != 0) {
|
||
ret = uapi_ai_attach_output(inst->h_ai, inst->h_sea);
|
||
} else {
|
||
ret = uapi_ai_attach_output(inst->h_ai, inst->h_aenc);
|
||
}
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_ai_attach_output, ret);
|
||
goto out;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
out:
|
||
(td_void)uapi_ai_close(inst->h_ai);
|
||
return ret;
|
||
}
|
||
|
||
static td_void sample_ai_aenc_close_player(sample_ai_aenc_inst *inst)
|
||
{
|
||
if (inst->h_player == 0) {
|
||
return;
|
||
}
|
||
|
||
sample_esplay_close();
|
||
inst->h_player = 0;
|
||
}
|
||
|
||
static td_s32 sample_ai_aenc_open_player(sample_ai_aenc_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
sample_acodec_arg arg;
|
||
|
||
inst->h_player = 0;
|
||
arg.file = TD_NULL;
|
||
arg.acodec_id = inst->acodec_id;
|
||
ret = memcpy_s(&arg.pcm_format, sizeof(arg.pcm_format), &inst->pcm_format, sizeof(inst->pcm_format));
|
||
if (ret != EOK) {
|
||
return ret;
|
||
}
|
||
|
||
/* esplay播放器是单独的流程,仅仅提供一个播放句柄h_player,不影响sample_ai_aenc流程 */
|
||
ret = sample_esplay_open(&arg, &inst->h_player, UAPI_SND_AEF_PROFILE_RINGTONE);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_esplay_open, ret);
|
||
return ret;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
static td_void sample_ai_aenc_inst_init(sample_ai_aenc_inst *inst)
|
||
{
|
||
inst->ai_port = UAPI_AI_PORT_MAX;
|
||
|
||
/* ai/aenc的默认属性 */
|
||
inst->acodec_id = UAPI_ACODEC_ID_MSBC;
|
||
inst->pcm_format.channels = UAPI_AUDIO_CHANNEL_1;
|
||
inst->pcm_format.bit_depth = UAPI_AUDIO_BIT_DEPTH_16;
|
||
inst->pcm_format.sample_rate = UAPI_AUDIO_SAMPLE_RATE_16K;
|
||
inst->pcm_format.sample_per_frame = inst->pcm_format.sample_rate / 100; /* 100 --> 10ms */
|
||
|
||
inst->volume.integer = AI_VOLUME_DEFAULT;
|
||
inst->volume.decimal = 0;
|
||
}
|
||
|
||
static td_void sample_ai_aenc_close_inst(sample_ai_aenc_inst *inst)
|
||
{
|
||
sample_ai_aenc_close_ai(inst);
|
||
sample_ai_aenc_close_sea(inst);
|
||
sample_ai_aenc_close_aenc(inst);
|
||
sample_ai_aenc_close_adp(inst);
|
||
sample_ai_aenc_sys_deinit();
|
||
}
|
||
|
||
static td_s32 sample_ai_aenc_open_inst(sample_ai_aenc_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
|
||
ret = sample_ai_aenc_sys_init();
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_ai_aenc_sys_init, ret);
|
||
return ret;
|
||
}
|
||
|
||
/*
|
||
* 数据流向 ai -->sea--> aenc --> adp
|
||
* 按照数据流向反方向打开实例
|
||
* 按照数据方向attach output
|
||
*/
|
||
ret = sample_ai_aenc_open_adp(inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_ai_aenc_open_adp, ret);
|
||
goto out0;
|
||
}
|
||
|
||
ret = sample_ai_aenc_open_aenc(inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_ai_aenc_open_aenc, ret);
|
||
goto out1;
|
||
}
|
||
|
||
ret = sample_ai_aenc_open_sea(inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_ai_aenc_open_sea, ret);
|
||
goto out2;
|
||
}
|
||
|
||
ret = sample_ai_aenc_open_ai(inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_ai_aenc_open_ai, ret);
|
||
goto out3;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
out3:
|
||
sample_ai_aenc_close_sea(inst);
|
||
out2:
|
||
sample_ai_aenc_close_aenc(inst);
|
||
out1:
|
||
sample_ai_aenc_close_adp(inst);
|
||
out0:
|
||
sample_ai_aenc_sys_deinit();
|
||
return ret;
|
||
}
|
||
|
||
static td_void sample_ai_aenc_stop_inst(sample_ai_aenc_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
|
||
if (inst->task != TD_NULL) {
|
||
inst->task_enable = TD_FALSE;
|
||
athread_exit(inst->task);
|
||
inst->task = TD_NULL;
|
||
}
|
||
|
||
ret = uapi_aenc_stop(inst->h_aenc);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_stop, ret);
|
||
}
|
||
|
||
if (inst->sea_enable) {
|
||
ret = uapi_sea_stop(inst->h_sea);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_sea_stop, ret);
|
||
}
|
||
sample_gui_aef_delete_handle(inst->h_sea);
|
||
}
|
||
|
||
ret = uapi_ai_stop(inst->h_ai);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_ai_stop, ret);
|
||
}
|
||
}
|
||
|
||
static td_s32 sample_ai_aenc_start_inst(sample_ai_aenc_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
athread_attr attr;
|
||
|
||
ret = uapi_ai_start(inst->h_ai);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_ai_start, ret);
|
||
return ret;
|
||
}
|
||
|
||
if (inst->sea_enable) {
|
||
ret = uapi_sea_start(inst->h_sea);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_sea_start, ret);
|
||
goto out0;
|
||
}
|
||
|
||
sample_gui_aef_add_handle(GUI_AEF_SEA, inst->h_sea);
|
||
}
|
||
|
||
ret = uapi_aenc_start(inst->h_aenc);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_start, ret);
|
||
goto out1;
|
||
}
|
||
|
||
inst->task_enable = TD_TRUE;
|
||
attr.priority = ATHREAD_PRIORITY_NORMAL;
|
||
attr.stack_size = 0x1000; /* 4k */
|
||
attr.name = "sample_ai_aenc";
|
||
ret = athread_create(&inst->task, sample_ai_aenc_thread, (td_void *)inst, &attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(athread_create, ret);
|
||
goto out2;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
out2:
|
||
(td_void)uapi_aenc_stop(inst->h_aenc);
|
||
out1:
|
||
if (inst->sea_enable) {
|
||
(td_void)uapi_sea_stop(inst->h_sea);
|
||
sample_gui_aef_delete_handle(inst->h_sea);
|
||
}
|
||
out0:
|
||
(td_void)uapi_ai_stop(inst->h_ai);
|
||
return ret;
|
||
}
|
||
|
||
static td_void sample_ai_aenc_usage(const td_char *name)
|
||
{
|
||
sap_printf(" usage: %s -p [port] -c [channels] -b [bit_depth] -s [sample_rate] -v [volume]\n", name);
|
||
sap_printf(" -h show this usage message and abort\n");
|
||
sap_printf(" -p specify ai port(mad0/i2s0/i2s1/adc0)\n"
|
||
" -t the type of encoder format(mp3/opus/lc3/l2hc/sbc/msbc)\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"
|
||
" -v volume of ai port(default: 0dB)\n"
|
||
" -m mute ai port(default: false)\n"
|
||
"\n");
|
||
|
||
sap_printf(" examples:\n");
|
||
sap_printf(" %s -p mad0 -c 1 -s 16000\n", name);
|
||
sap_printf(" %s -p i2s1 -c 1 -s 16000\n", name);
|
||
sap_printf(" %s -p adc0 -c 1 -s 16000 -v 30\n", name);
|
||
sap_printf(" %s -p adc0 -c 1 -s 16000 -v 30 -t mp3\n", name);
|
||
sap_printf(" %s -p adc0 -c 1 -s 16000 -v 30 -t opus\n", name);
|
||
sap_printf("\n");
|
||
}
|
||
|
||
static td_void sample_ai_aenc_parse_port(const td_char *port_name, sample_ai_aenc_inst *inst)
|
||
{
|
||
td_u32 i;
|
||
const struct {
|
||
const td_char *name;
|
||
uapi_ai_port ai_port;
|
||
} ai_port_name[] = {
|
||
{"mad0", UAPI_AI_PORT_PDM0},
|
||
{"pdm0", UAPI_AI_PORT_PDM0},
|
||
{"pdm1", UAPI_AI_PORT_PDM1},
|
||
{"adc0", UAPI_AI_PORT_ADC0},
|
||
{"adc1", UAPI_AI_PORT_ADC1},
|
||
{"lpadc0", UAPI_AI_PORT_LPADC0},
|
||
{"i2s0", UAPI_AI_PORT_I2S0},
|
||
{"i2s1", UAPI_AI_PORT_I2S1},
|
||
{"i2s2", UAPI_AI_PORT_I2S2},
|
||
{"i2s3", UAPI_AI_PORT_I2S3},
|
||
};
|
||
|
||
for (i = 0; i < sizeof(ai_port_name) / sizeof(ai_port_name[0]); i++) {
|
||
if (strcmp(ai_port_name[i].name, port_name) == 0) {
|
||
inst->ai_port = ai_port_name[i].ai_port;
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
static td_s32 sample_ai_aenc_parse_opt(td_char opt, const td_char *opt_arg, sample_ai_aenc_inst *inst)
|
||
{
|
||
if (opt == 'h') {
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
if (opt_arg == TD_NULL) {
|
||
sap_printf("invalid option -- '%c'\n", opt);
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
switch (opt) {
|
||
case 's':
|
||
inst->pcm_format.sample_rate = (td_u32)strtoul(opt_arg, TD_NULL, 0);
|
||
break;
|
||
case 'c':
|
||
inst->pcm_format.channels = (td_u32)strtoul(opt_arg, TD_NULL, 0);
|
||
break;
|
||
case 'b':
|
||
inst->pcm_format.bit_depth = (td_u32)strtoul(opt_arg, TD_NULL, 0);
|
||
break;
|
||
case 'p':
|
||
sample_ai_aenc_parse_port(opt_arg, inst);
|
||
break;
|
||
case 'v':
|
||
inst->volume.integer = (td_s32)strtol(opt_arg, TD_NULL, 0);
|
||
break;
|
||
case 't': /* direct return */
|
||
return sample_audio_get_acodec_id(opt_arg, &inst->acodec_id);
|
||
case 'm':
|
||
inst->mute = TD_TRUE;
|
||
break;
|
||
default:
|
||
sap_printf("invalid command line\n");
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
static td_s32 sample_ai_aenc_parse_cmd_line(td_s32 argc, td_char *argv[], sample_ai_aenc_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
td_char opt;
|
||
parg_state arg_parse;
|
||
|
||
if (argv == TD_NULL) {
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
parg_init(&arg_parse);
|
||
|
||
while (1) {
|
||
ret = parg_getopt(&arg_parse, argc, argv, "s:c:b:p:v:t:hm");
|
||
if (ret == -1) {
|
||
break;
|
||
}
|
||
|
||
opt = (td_char)ret;
|
||
if (sample_ai_aenc_parse_opt(opt, arg_parse.optarg, inst) != EXT_SUCCESS) {
|
||
sample_ai_aenc_usage(argv[0]);
|
||
return EXT_FAILURE;
|
||
}
|
||
}
|
||
|
||
inst->pcm_format.sample_per_frame = inst->pcm_format.sample_rate / 100; /* 100 --> 10ms */
|
||
|
||
if (inst->ai_port == UAPI_AI_PORT_MAX) {
|
||
sample_ai_aenc_usage(argv[0]);
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
static td_s32 sample_ai_aenc_entry(td_s32 argc, td_char *argv[], td_bool sea_enable)
|
||
{
|
||
td_s32 ret;
|
||
sample_ai_aenc_inst *inst = sample_ai_aenc_get_inst();
|
||
if (inst != TD_NULL) {
|
||
sap_printf("%s is already running", argv[0]);
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
inst = sample_ai_aenc_alloc_inst();
|
||
if (inst == TD_NULL) {
|
||
sap_printf("sample_ai_aenc_alloc_inst failed");
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
sample_ai_aenc_inst_init(inst);
|
||
inst->sea_enable = sea_enable;
|
||
|
||
ret = sample_ai_aenc_parse_cmd_line(argc, argv, inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
goto out0;
|
||
}
|
||
|
||
/* 按照ai/aenc的属性创建播放器,用于播放aenc输出的es流 */
|
||
ret = sample_ai_aenc_open_player(inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_ai_aenc_open_player, ret);
|
||
goto out0;
|
||
}
|
||
|
||
ret = sample_ai_aenc_open_inst(inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_ai_aenc_open_inst, ret);
|
||
goto out1;
|
||
}
|
||
|
||
ret = sample_ai_aenc_start_inst(inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_ai_aenc_start_inst, ret);
|
||
goto out2;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
out2:
|
||
sample_ai_aenc_close_inst(inst);
|
||
out1:
|
||
sample_ai_aenc_close_player(inst);
|
||
out0:
|
||
sample_ai_aenc_free_inst(inst);
|
||
return ret;
|
||
}
|
||
|
||
static td_s32 sample_ai_aenc_exit(td_void)
|
||
{
|
||
sample_ai_aenc_inst *inst = sample_ai_aenc_get_inst();
|
||
if (inst != TD_NULL) {
|
||
sample_ai_aenc_stop_inst(inst);
|
||
sample_ai_aenc_close_inst(inst);
|
||
sample_ai_aenc_close_player(inst);
|
||
sample_ai_aenc_free_inst(inst);
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
td_s32 sample_ai_aenc(td_s32 argc, td_char *argv[])
|
||
{
|
||
if (argc <= 1) {
|
||
sample_ai_aenc_usage(argv[0]);
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
if (strcmp(argv[1], "q") == 0) {
|
||
return sample_ai_aenc_exit();
|
||
} else {
|
||
return sample_ai_aenc_entry(argc, argv, TD_FALSE);
|
||
}
|
||
}
|
||
|
||
td_s32 sample_ai_sea_aenc(td_s32 argc, td_char *argv[])
|
||
{
|
||
if (argc <= 1) {
|
||
sample_ai_aenc_usage(argv[0]);
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
if (strcmp(argv[1], "q") == 0) {
|
||
return sample_ai_aenc_exit();
|
||
} else {
|
||
return sample_ai_aenc_entry(argc, argv, TD_TRUE);
|
||
}
|
||
}
|
||
|
||
#ifdef __cplusplus
|
||
#if __cplusplus
|
||
}
|
||
#endif
|
||
#endif
|