1875 lines
56 KiB
C
1875 lines
56 KiB
C
/*
|
|
Copyright (c), 2001-2022, Shenshu Tech. Co., Ltd.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/ioctl.h>
|
|
#include <fcntl.h>
|
|
#include <pthread.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <limits.h>
|
|
|
|
#include "sample_comm.h"
|
|
#include "audio_aac_adp.h"
|
|
#include "audio_dl_adp.h"
|
|
#include "ot_resample.h"
|
|
#if defined(OT_VQE_USE_STATIC_MODULE_REGISTER)
|
|
#include "ot_vqe_register.h"
|
|
#endif
|
|
|
|
static ot_payload_type g_payload_type = OT_PT_AAC;
|
|
static td_bool g_aio_resample = TD_FALSE;
|
|
static td_bool g_user_get_mode = TD_FALSE;
|
|
static td_bool g_ao_volume_ctrl = TD_FALSE;
|
|
static ot_audio_sample_rate g_in_sample_rate = OT_AUDIO_SAMPLE_RATE_BUTT;
|
|
static ot_audio_sample_rate g_out_sample_rate = OT_AUDIO_SAMPLE_RATE_BUTT;
|
|
/* 0: close, 1: record, 2: talk */
|
|
static td_u32 g_ai_vqe_type = 2;
|
|
ot_ai_record_vqe_cfg g_ai_vqe_record_attr = { 0 };
|
|
ot_ai_talk_vqe_cfg g_ai_vqe_talk_attr = { 0 };
|
|
|
|
static void *g_res_handle = TD_NULL;
|
|
static td_s16 *g_res_out_buf = TD_NULL;
|
|
|
|
static td_bool g_sample_audio_exit = TD_FALSE;
|
|
|
|
#define sample_dbg(ret) \
|
|
do { \
|
|
printf("ret = %#x, fuc:%s, line:%d\n", ret, __FUNCTION__, __LINE__); \
|
|
} while (0)
|
|
|
|
#define sample_res_check_null_ptr(ptr) \
|
|
do { \
|
|
if ((td_u8*)(ptr) == TD_NULL) { \
|
|
printf("ptr is TD_NULL,fuc:%s,line:%d\n", __FUNCTION__, __LINE__); \
|
|
return TD_FAILURE; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define OT_RES_LIB_NAME "libvqe_res.so"
|
|
|
|
/* function : PT number to string */
|
|
static char *sample_audio_pt2_str(ot_payload_type type)
|
|
{
|
|
if (type == OT_PT_G711A) {
|
|
return "g711a";
|
|
} else if (type == OT_PT_G711U) {
|
|
return "g711u";
|
|
} else if (type == OT_PT_ADPCMA) {
|
|
return "adpcm";
|
|
} else if (type == OT_PT_G726) {
|
|
return "g726";
|
|
} else if (type == OT_PT_LPCM) {
|
|
return "pcm";
|
|
} else if (type == OT_PT_AAC) {
|
|
return "aac";
|
|
} else {
|
|
return "data";
|
|
}
|
|
}
|
|
|
|
typedef struct {
|
|
td_bool start;
|
|
td_s32 ai_dev;
|
|
td_s32 ai_chn;
|
|
ot_audio_sample_rate in_sample;
|
|
ot_audio_sample_rate out_sample;
|
|
td_u32 per_frame;
|
|
FILE *fd;
|
|
pthread_t ai_pid;
|
|
} ot_sample_ai_to_ext_res;
|
|
|
|
typedef td_void *(*ot_resample_create_callback)(td_s32 in_rate, td_s32 out_rate, td_s32 chn_num);
|
|
typedef td_s32 (*ot_resample_process_callback)(td_void *instance, const td_s16 *in_buf, td_s32 in_samples,
|
|
td_s16 *out_buf);
|
|
typedef td_void (*ot_resample_destroy_callback)(td_void *instance);
|
|
typedef td_s32 (*ot_resample_get_max_output_num_callback)(td_void *instance, td_s32 in_samples);
|
|
|
|
typedef struct {
|
|
td_void *lib_handle;
|
|
ot_resample_create_callback resample_create_callback;
|
|
ot_resample_process_callback resample_process_callback;
|
|
ot_resample_destroy_callback resample_destroy_callback;
|
|
ot_resample_get_max_output_num_callback resample_get_max_output_num_callback;
|
|
} ot_sample_res_fun;
|
|
|
|
static ot_sample_ai_to_ext_res g_sample_ai_ext_res[OT_AI_DEV_MAX_NUM * OT_AI_MAX_CHN_NUM];
|
|
static ot_sample_res_fun g_sample_res_fun = {0};
|
|
|
|
static td_void sample_audio_ai_to_res_proc(ot_sample_ai_to_ext_res *ai_ctrl, ot_audio_frame *frame,
|
|
td_s16 *cache, td_u16 *cache_count, td_u16 cache_sample)
|
|
{
|
|
td_u32 proc_frame, out_sample, cur_sample, ret;
|
|
td_u32 mulit = 1;
|
|
|
|
if (ai_ctrl->in_sample % ai_ctrl->out_sample == 0) {
|
|
mulit = ai_ctrl->in_sample / ai_ctrl->out_sample;
|
|
if (ai_ctrl->per_frame % mulit == 0) {
|
|
mulit = 1;
|
|
}
|
|
}
|
|
|
|
/* send frame to encoder */
|
|
if (mulit != 1) {
|
|
if (*cache_count != 0) {
|
|
if (cache_sample < *cache_count) {
|
|
return;
|
|
}
|
|
ret = memcpy_s(cache + (*cache_count), (cache_sample - *cache_count) * sizeof(td_s16),
|
|
frame->virt_addr[0], (mulit - *cache_count) * sizeof(td_s16));
|
|
if (ret != EOK) {
|
|
printf("%s: memcpy_s failed, ret:0x%x.\n", __FUNCTION__, ret);
|
|
return;
|
|
}
|
|
out_sample = g_sample_res_fun.resample_process_callback(g_res_handle, cache, mulit, g_res_out_buf);
|
|
(td_void)fwrite(g_res_out_buf, 2, out_sample, ai_ctrl->fd); /* 2:byte */
|
|
}
|
|
|
|
proc_frame = ai_ctrl->per_frame - (mulit - *cache_count);
|
|
proc_frame = proc_frame - proc_frame % mulit;
|
|
out_sample = g_sample_res_fun.resample_process_callback(g_res_handle, (td_s16*)(frame->virt_addr[0] +
|
|
(mulit - *cache_count) * sizeof(td_s16)), proc_frame, g_res_out_buf);
|
|
(td_void)fwrite(g_res_out_buf, 2, out_sample, ai_ctrl->fd); /* 2:byte */
|
|
|
|
cur_sample = proc_frame + (mulit - *cache_count);
|
|
if ((ai_ctrl->per_frame - cur_sample) != 0) {
|
|
ret = memcpy_s(cache, cache_sample * sizeof(td_s16),
|
|
frame->virt_addr[0] + cur_sample * sizeof(td_s16), (ai_ctrl->per_frame - cur_sample) * sizeof(td_s16));
|
|
if (ret != EOK) {
|
|
printf("%s: memcpy_s failed, ret:0x%x.\n", __FUNCTION__, ret);
|
|
return;
|
|
}
|
|
}
|
|
*cache_count = ai_ctrl->per_frame - cur_sample;
|
|
} else {
|
|
out_sample = g_sample_res_fun.resample_process_callback(g_res_handle, (td_s16*)frame->virt_addr[0],
|
|
ai_ctrl->per_frame, g_res_out_buf);
|
|
(td_void)fwrite(g_res_out_buf, 2, out_sample, ai_ctrl->fd); /* 2:byte */
|
|
}
|
|
|
|
fflush(ai_ctrl->fd);
|
|
}
|
|
|
|
static td_s32 sample_audio_ai_to_res_init(ot_sample_ai_to_ext_res *ai_ctrl)
|
|
{
|
|
ot_ai_chn_param ai_chn_para;
|
|
td_s32 ret, out_max_num;
|
|
sample_res_check_null_ptr(g_sample_res_fun.resample_create_callback);
|
|
sample_res_check_null_ptr(g_sample_res_fun.resample_process_callback);
|
|
sample_res_check_null_ptr(g_sample_res_fun.resample_destroy_callback);
|
|
sample_res_check_null_ptr(g_sample_res_fun.resample_get_max_output_num_callback);
|
|
|
|
ret = ss_mpi_ai_get_chn_param(ai_ctrl->ai_dev, ai_ctrl->ai_chn, &ai_chn_para);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("%s: Get ai chn param failed\n", __FUNCTION__);
|
|
return ret;
|
|
}
|
|
|
|
ai_chn_para.usr_frame_depth = 30; /* 30:frame depth */
|
|
|
|
ret = ss_mpi_ai_set_chn_param(ai_ctrl->ai_dev, ai_ctrl->ai_chn, &ai_chn_para);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("%s: set ai chn param failed, ret=0x%x\n", __FUNCTION__, ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Create Resample. only support mono channel. */
|
|
g_res_handle = g_sample_res_fun.resample_create_callback(ai_ctrl->in_sample, ai_ctrl->out_sample, 1);
|
|
if (g_res_handle == TD_NULL) {
|
|
printf("%s: ot_resampler_create failed, ret=0x%x\n", __FUNCTION__, ret);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
out_max_num = g_sample_res_fun.resample_get_max_output_num_callback(g_res_handle, ai_ctrl->per_frame);
|
|
if (out_max_num <= 0) {
|
|
printf("get max output num failed\n");
|
|
g_sample_res_fun.resample_destroy_callback(g_res_handle);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
g_res_out_buf = malloc(out_max_num * sizeof(td_s16) + 2); /* 2:Reserved space */
|
|
if (g_res_out_buf == TD_NULL) {
|
|
printf("malloc failed\n");
|
|
g_sample_res_fun.resample_destroy_callback(g_res_handle);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 sample_comm_audio_select(td_s32 ai_fd, fd_set *read_fds)
|
|
{
|
|
td_s32 ret;
|
|
struct timeval time_out_val;
|
|
time_out_val.tv_sec = 1;
|
|
time_out_val.tv_usec = 0;
|
|
|
|
FD_ZERO(read_fds);
|
|
FD_SET(ai_fd, read_fds);
|
|
|
|
ret = select(ai_fd + 1, read_fds, TD_NULL, TD_NULL, &time_out_val);
|
|
if (ret < 0) {
|
|
return TD_FAILURE;
|
|
} else if (ret == 0) {
|
|
printf("%s: get ai frame select time out\n", __FUNCTION__);
|
|
return TD_FAILURE;
|
|
}
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
/* function : get frame from Ai, send it to Resampler */
|
|
void *sample_comm_audio_ai_ext_res_proc(void *parg)
|
|
{
|
|
td_s32 ret;
|
|
td_s32 ai_fd = -1;
|
|
ot_audio_frame frame = {0};
|
|
ot_aec_frame aec_frm = {0};
|
|
ot_sample_ai_to_ext_res *ai_ctrl = (ot_sample_ai_to_ext_res *)parg;
|
|
fd_set read_fds;
|
|
td_u16 cache_count = 0;
|
|
td_s16 cache[16]; /* 16:Max 64 / 8 * 2. */
|
|
|
|
ret = sample_audio_ai_to_res_init(ai_ctrl);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("%s: sample_audio_ai_to_res_param_set failed\n", __FUNCTION__);
|
|
return TD_NULL;
|
|
}
|
|
|
|
ai_fd = ss_mpi_ai_get_fd(ai_ctrl->ai_dev, ai_ctrl->ai_chn);
|
|
if (ai_fd < 0) {
|
|
printf("%s: get ai fd failed\n", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
|
|
while (ai_ctrl->start) {
|
|
ret = sample_comm_audio_select(ai_fd, &read_fds);
|
|
if (ret != TD_SUCCESS) {
|
|
break;
|
|
}
|
|
|
|
if (FD_ISSET(ai_fd, &read_fds)) {
|
|
/* get frame from ai chn */
|
|
(td_void)memset_s(&aec_frm, sizeof(ot_aec_frame), 0, sizeof(ot_aec_frame));
|
|
|
|
ret = ss_mpi_ai_get_frame(ai_ctrl->ai_dev, ai_ctrl->ai_chn, &frame, &aec_frm, TD_FALSE);
|
|
if (ret != TD_SUCCESS) {
|
|
continue;
|
|
}
|
|
|
|
sample_audio_ai_to_res_proc(ai_ctrl, &frame, cache, &cache_count, sizeof(cache) / sizeof(td_s16));
|
|
|
|
ret = ss_mpi_ai_release_frame(ai_ctrl->ai_dev, ai_ctrl->ai_chn, &frame, &aec_frm);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("%s: ss_mpi_ai_release_frame(%d, %d), failed with %#x!\n", \
|
|
__FUNCTION__, ai_ctrl->ai_dev, ai_ctrl->ai_chn, ret);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
ai_ctrl->start = TD_FALSE;
|
|
free(g_res_out_buf);
|
|
g_res_out_buf = TD_NULL;
|
|
g_sample_res_fun.resample_destroy_callback(g_res_handle);
|
|
|
|
return TD_NULL;
|
|
}
|
|
|
|
/* function : Create the thread to get frame from ai and send to aenc */
|
|
td_s32 sample_comm_audio_creat_trd_ai_ext_res(ot_aio_attr *aio_attr, ot_audio_dev ai_dev,
|
|
ot_ai_chn ai_chn, ot_audio_sample_rate out_sample_rate, FILE *res_fd)
|
|
{
|
|
ot_sample_ai_to_ext_res *ai_to_ext_res = TD_NULL;
|
|
|
|
if ((ai_dev >= OT_AI_DEV_MAX_NUM) || (ai_dev < 0) ||
|
|
(ai_chn >= OT_AI_MAX_CHN_NUM) || (ai_chn < 0)) {
|
|
printf("%s: ai_dev = %d, ai_chn = %d error.\n", __FUNCTION__, ai_dev, ai_chn);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
ai_to_ext_res = &g_sample_ai_ext_res[ai_dev * OT_AI_MAX_CHN_NUM + ai_chn];
|
|
ai_to_ext_res->ai_dev = ai_dev;
|
|
ai_to_ext_res->ai_chn = ai_chn;
|
|
ai_to_ext_res->in_sample = aio_attr->sample_rate;
|
|
ai_to_ext_res->out_sample = out_sample_rate;
|
|
ai_to_ext_res->per_frame = aio_attr->point_num_per_frame;
|
|
ai_to_ext_res->fd = res_fd;
|
|
ai_to_ext_res->start = TD_TRUE;
|
|
pthread_create(&ai_to_ext_res->ai_pid, 0, sample_comm_audio_ai_ext_res_proc, ai_to_ext_res);
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
/* function : Destory the thread to get frame from ai and send to extern resamler */
|
|
td_s32 sample_comm_audio_destroy_trd_ai_ext_res(ot_audio_dev ai_dev, ot_ai_chn ai_chn)
|
|
{
|
|
ot_sample_ai_to_ext_res *ai_to_ext_res = TD_NULL;
|
|
|
|
if ((ai_dev >= OT_AI_DEV_MAX_NUM) || (ai_dev < 0) ||
|
|
(ai_chn >= OT_AI_MAX_CHN_NUM) || (ai_chn < 0)) {
|
|
printf("%s: ai_dev = %d, ai_chn = %d error.\n", __FUNCTION__, ai_dev, ai_chn);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
ai_to_ext_res = &g_sample_ai_ext_res[ai_dev * OT_AI_MAX_CHN_NUM + ai_chn];
|
|
if (ai_to_ext_res->start) {
|
|
ai_to_ext_res->start = TD_FALSE;
|
|
pthread_join(ai_to_ext_res->ai_pid, 0);
|
|
}
|
|
|
|
if (ai_to_ext_res->fd != TD_NULL) {
|
|
fclose(ai_to_ext_res->fd);
|
|
ai_to_ext_res->fd = TD_NULL;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
/* function : DeInit resamle functions */
|
|
static td_void sample_audio_deinit_ext_res_fun(td_void)
|
|
{
|
|
td_s32 ret;
|
|
|
|
#if defined(OT_VQE_USE_STATIC_MODULE_REGISTER)
|
|
ret = memset_s(&g_sample_res_fun, sizeof(ot_sample_res_fun), 0, sizeof(ot_sample_res_fun));
|
|
if (ret != EOK) {
|
|
printf("%s: g_sample_res_fun init failed with %d!\n", __FUNCTION__, ret);
|
|
return;
|
|
}
|
|
#else
|
|
if (g_sample_res_fun.lib_handle != TD_NULL) {
|
|
audio_dlclose(g_sample_res_fun.lib_handle);
|
|
ret = memset_s(&g_sample_res_fun, sizeof(ot_sample_res_fun), 0, sizeof(ot_sample_res_fun));
|
|
if (ret != EOK) {
|
|
printf("%s: g_sample_res_fun init failed with %d!\n", __FUNCTION__, ret);
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* function : Init resamle functions */
|
|
static td_s32 sample_audio_init_ext_res_fun(td_void)
|
|
{
|
|
ot_sample_res_fun sample_res_fun = {0};
|
|
|
|
sample_audio_deinit_ext_res_fun();
|
|
|
|
#if defined(OT_VQE_USE_STATIC_MODULE_REGISTER)
|
|
sample_res_fun.resample_create_callback = ot_resample_create;
|
|
sample_res_fun.resample_process_callback = ot_resample_process;
|
|
sample_res_fun.resample_destroy_callback = ot_resample_destroy;
|
|
sample_res_fun.resample_get_max_output_num_callback = ot_resample_get_max_output_num;
|
|
#else
|
|
td_s32 ret;
|
|
ret = audio_dlopen(&(sample_res_fun.lib_handle), OT_RES_LIB_NAME);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("[Func]:%s [Line]:%d [Info]:%s\n", __FUNCTION__, __LINE__, "load resample lib fail!\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
ret = audio_dlsym((td_void**)&(sample_res_fun.resample_create_callback), sample_res_fun.lib_handle,
|
|
"ot_resample_create");
|
|
if (ret != TD_SUCCESS) {
|
|
printf("[Func]:%s [Line]:%d [Info]:%s\n", __FUNCTION__, __LINE__, "find symbol error!\n");
|
|
goto dysym_fail;
|
|
}
|
|
|
|
ret = audio_dlsym((td_void**)&(sample_res_fun.resample_process_callback), sample_res_fun.lib_handle,
|
|
"ot_resample_process");
|
|
if (ret != TD_SUCCESS) {
|
|
printf("[Func]:%s [Line]:%d [Info]:%s\n", __FUNCTION__, __LINE__, "find symbol error!\n");
|
|
goto dysym_fail;
|
|
}
|
|
|
|
ret = audio_dlsym((td_void**)&(sample_res_fun.resample_destroy_callback), sample_res_fun.lib_handle,
|
|
"ot_resample_destroy");
|
|
if (ret != TD_SUCCESS) {
|
|
printf("[Func]:%s [Line]:%d [Info]:%s\n", __FUNCTION__, __LINE__, "find symbol error!\n");
|
|
goto dysym_fail;
|
|
}
|
|
|
|
ret = audio_dlsym((td_void**)&(sample_res_fun.resample_get_max_output_num_callback), sample_res_fun.lib_handle,
|
|
"ot_resample_get_max_output_num");
|
|
if (ret != TD_SUCCESS) {
|
|
printf("[Func]:%s [Line]:%d [Info]:%s\n", __FUNCTION__, __LINE__, "find symbol error!\n");
|
|
goto dysym_fail;
|
|
}
|
|
#endif
|
|
|
|
(td_void)memcpy_s(&g_sample_res_fun, sizeof(g_sample_res_fun), &sample_res_fun, sizeof(sample_res_fun));
|
|
|
|
return TD_SUCCESS;
|
|
|
|
#if !defined(OT_VQE_USE_STATIC_MODULE_REGISTER)
|
|
dysym_fail:
|
|
audio_dlclose(sample_res_fun.lib_handle);
|
|
sample_res_fun.lib_handle = TD_NULL;
|
|
return TD_FAILURE;
|
|
#endif
|
|
}
|
|
|
|
static td_void sample_audio_exit_proc(td_void)
|
|
{
|
|
td_u32 dev_id, chn_id;
|
|
|
|
for (dev_id = 0; dev_id < OT_AI_DEV_MAX_NUM; dev_id++) {
|
|
for (chn_id = 0; chn_id < OT_AI_MAX_CHN_NUM; chn_id++) {
|
|
if (sample_comm_audio_destroy_trd_ai_ext_res(dev_id, chn_id) != TD_SUCCESS) {
|
|
printf("%s: sample_comm_audio_destroy_trd_ai_ext_res(%d,%d) failed!\n", __FUNCTION__,
|
|
dev_id, chn_id);
|
|
}
|
|
}
|
|
}
|
|
sample_comm_audio_destory_all_trd();
|
|
sample_comm_sys_exit();
|
|
}
|
|
|
|
static int smaple_audio_getchar(td_void)
|
|
{
|
|
int c;
|
|
|
|
if (g_sample_audio_exit == TD_TRUE) {
|
|
sample_audio_exit_proc();
|
|
printf("\033[0;31mprogram exit abnormally!\033[0;39m\n");
|
|
exit(-1);
|
|
}
|
|
|
|
c = getchar();
|
|
|
|
if (g_sample_audio_exit == TD_TRUE) {
|
|
sample_audio_exit_proc();
|
|
printf("\033[0;31mprogram exit abnormally!\033[0;39m\n");
|
|
exit(-1);
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
/* function : open aenc file */
|
|
static FILE *sample_audio_open_aenc_file(ot_aenc_chn ae_chn, ot_payload_type type)
|
|
{
|
|
FILE *fd = TD_NULL;
|
|
td_char asz_file_name[FILE_NAME_LEN] = {0};
|
|
td_s32 ret;
|
|
|
|
/* create file for save stream */
|
|
#ifdef __LITEOS__
|
|
ret = snprintf_s(asz_file_name, FILE_NAME_LEN, FILE_NAME_LEN - 1,
|
|
"/sharefs/audio_chn%d.%s", ae_chn, sample_audio_pt2_str(type));
|
|
#else
|
|
ret = snprintf_s(asz_file_name, FILE_NAME_LEN, FILE_NAME_LEN - 1,
|
|
"audio_chn%d.%s", ae_chn, sample_audio_pt2_str(type));
|
|
#endif
|
|
if (ret < 0) {
|
|
printf("[func]:%s [line]:%d [info]:%s\n", __FUNCTION__, __LINE__, "get aenc file name failed");
|
|
return TD_NULL;
|
|
}
|
|
|
|
if (asz_file_name[0] == '\0') {
|
|
printf("[func]:%s [line]:%d [info]:%s\n", __FUNCTION__, __LINE__, "aenc file name is NULL");
|
|
return TD_NULL;
|
|
}
|
|
|
|
if (strlen(asz_file_name) > (FILE_NAME_LEN - 1)) {
|
|
printf("[func]:%s [line]:%d [info]:%s\n", __FUNCTION__, __LINE__, "aenc file name extra long");
|
|
return TD_NULL;
|
|
}
|
|
|
|
fd = fopen(asz_file_name, "w+");
|
|
if (fd == NULL) {
|
|
printf("%s: open file %s failed\n", __FUNCTION__, asz_file_name);
|
|
return NULL;
|
|
}
|
|
printf("open stream file:\"%s\" for aenc ok\n", asz_file_name);
|
|
return fd;
|
|
}
|
|
|
|
/* function : Open ExtResample File */
|
|
static FILE *sample_audio_open_res_file(ot_ai_chn ai_chn)
|
|
{
|
|
FILE *fd = TD_NULL;
|
|
td_char asz_file_name[FILE_NAME_LEN] = {0};
|
|
td_s32 ret;
|
|
|
|
/* create file for save stream */
|
|
#ifdef __LITEOS__
|
|
ret = snprintf_s(asz_file_name, FILE_NAME_LEN, FILE_NAME_LEN - 1, "/sharefs/res_chn%d.pcm", ai_chn);
|
|
#else
|
|
ret = snprintf_s(asz_file_name, FILE_NAME_LEN, FILE_NAME_LEN - 1, "res_chn%d.pcm", ai_chn);
|
|
#endif
|
|
if (ret < 0) {
|
|
printf("[func]:%s [line]:%d [info]:%s\n", __FUNCTION__, __LINE__, "get res file name failed");
|
|
return TD_NULL;
|
|
}
|
|
|
|
if (asz_file_name[0] == '\0') {
|
|
printf("[func]:%s [line]:%d [info]:%s\n", __FUNCTION__, __LINE__, "res file name is NULL");
|
|
return TD_NULL;
|
|
}
|
|
|
|
if (strlen(asz_file_name) > (FILE_NAME_LEN - 1)) {
|
|
printf("[func]:%s [line]:%d [info]:%s\n", __FUNCTION__, __LINE__, "res file name extra long");
|
|
return TD_NULL;
|
|
}
|
|
|
|
fd = fopen(asz_file_name, "w+");
|
|
if (fd == TD_NULL) {
|
|
printf("%s: open file %s failed\n", __FUNCTION__, asz_file_name);
|
|
return TD_NULL;
|
|
}
|
|
printf("open stream file:\"%s\" for resample ok\n", asz_file_name);
|
|
return fd;
|
|
}
|
|
|
|
/* function : open adec file */
|
|
static FILE *sample_audio_open_adec_file(ot_adec_chn ad_chn, ot_payload_type type)
|
|
{
|
|
FILE *fd = TD_NULL;
|
|
td_char asz_file_name[FILE_NAME_LEN] = {0};
|
|
td_s32 ret;
|
|
td_char path[PATH_MAX] = {0};
|
|
|
|
/* create file for save stream */
|
|
#ifdef __LITEOS__
|
|
ret = snprintf_s(asz_file_name, FILE_NAME_LEN, FILE_NAME_LEN - 1,
|
|
"/sharefs/audio_chn%d.%s", ad_chn, sample_audio_pt2_str(type));
|
|
#else
|
|
ret = snprintf_s(asz_file_name, FILE_NAME_LEN, FILE_NAME_LEN - 1,
|
|
"audio_chn%d.%s", ad_chn, sample_audio_pt2_str(type));
|
|
#endif
|
|
if (ret < 0) {
|
|
printf("[func]:%s [line]:%d [info]:%s\n", __FUNCTION__, __LINE__, "get adec file name failed");
|
|
return TD_NULL;
|
|
}
|
|
|
|
if (asz_file_name[0] == '\0') {
|
|
printf("[func]:%s [line]:%d [info]:%s\n", __FUNCTION__, __LINE__, "adec file name is NULL");
|
|
return TD_NULL;
|
|
}
|
|
|
|
if (strlen(asz_file_name) > (FILE_NAME_LEN - 1)) {
|
|
printf("[func]:%s [line]:%d [info]:%s\n", __FUNCTION__, __LINE__, "adec file name extra long");
|
|
return TD_NULL;
|
|
}
|
|
|
|
if (realpath(asz_file_name, path) == TD_NULL) {
|
|
printf("[func]:%s [line]:%d [info]:%s\n", __FUNCTION__, __LINE__, "adec file name realpath fail");
|
|
return TD_NULL;
|
|
}
|
|
|
|
fd = fopen(path, "rb");
|
|
if (fd == NULL) {
|
|
printf("%s: open file %s failed\n", __FUNCTION__, asz_file_name);
|
|
return NULL;
|
|
}
|
|
printf("open stream file:\"%s\" for adec ok\n", asz_file_name);
|
|
return fd;
|
|
}
|
|
|
|
static td_void sample_audio_set_ai_vqe_param(sample_comm_ai_vqe_param *ai_vqe_param,
|
|
ot_audio_sample_rate out_sample_rate, td_bool resample_en, td_void *ai_vqe_attr, td_u32 ai_vqe_type)
|
|
{
|
|
ai_vqe_param->out_sample_rate = out_sample_rate;
|
|
ai_vqe_param->resample_en = resample_en;
|
|
ai_vqe_param->ai_vqe_attr = ai_vqe_attr;
|
|
ai_vqe_param->ai_vqe_type = ai_vqe_type;
|
|
}
|
|
|
|
static td_void sample_audio_adec_ao_init_param(ot_aio_attr *aio_attr, ot_audio_dev *ao_dev)
|
|
{
|
|
//aio_attr->sample_rate = OT_AUDIO_SAMPLE_RATE_16000;
|
|
aio_attr->sample_rate = OT_AUDIO_SAMPLE_RATE_48000;
|
|
aio_attr->bit_width = OT_AUDIO_BIT_WIDTH_16;
|
|
aio_attr->work_mode = OT_AIO_MODE_I2S_MASTER;
|
|
aio_attr->snd_mode = OT_AUDIO_SOUND_MODE_STEREO;
|
|
aio_attr->expand_flag = 0;
|
|
aio_attr->frame_num = 30; /* 30:frame num */
|
|
if (g_payload_type == OT_PT_AAC) {
|
|
aio_attr->point_num_per_frame = AACLC_SAMPLES_PER_FRAME;
|
|
} else {
|
|
aio_attr->point_num_per_frame = SAMPLE_AUDIO_POINT_NUM_PER_FRAME;
|
|
}
|
|
aio_attr->chn_cnt = 2;
|
|
|
|
*ao_dev = SAMPLE_AUDIO_EXTERN_AO_DEV;
|
|
aio_attr->clk_share = 1;
|
|
aio_attr->i2s_type = OT_AIO_I2STYPE_EXTERN;
|
|
|
|
g_aio_resample = TD_FALSE;
|
|
g_in_sample_rate = OT_AUDIO_SAMPLE_RATE_BUTT;
|
|
g_out_sample_rate = OT_AUDIO_SAMPLE_RATE_BUTT;
|
|
}
|
|
|
|
td_void sample_audio_adec_ao_inner(ot_audio_dev ao_dev, ot_audio_dev ao_hdmi_dev, ot_ao_chn ao_chn, ot_adec_chn ad_chn)
|
|
{
|
|
td_s32 ret;
|
|
FILE *fd = NULL;
|
|
|
|
ret = sample_comm_audio_ao_bind_adec(ao_dev, ao_chn, ad_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
return;
|
|
}
|
|
|
|
ret = sample_comm_audio_ao_bind_adec(ao_hdmi_dev, ao_chn, ad_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
return;
|
|
}
|
|
|
|
|
|
fd = sample_audio_open_adec_file(ad_chn, g_payload_type);
|
|
if (fd == TD_NULL) {
|
|
sample_dbg(TD_FAILURE);
|
|
goto adec_ao_err0;
|
|
}
|
|
|
|
ret = sample_comm_audio_creat_trd_file_adec(ad_chn, fd);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
fclose(fd);
|
|
fd = TD_NULL;
|
|
goto adec_ao_err0;
|
|
}
|
|
|
|
printf("bind adec:%d to ao(%d,%d) ok \n", ad_chn, ao_dev, ao_chn);
|
|
|
|
printf("\nplease press twice ENTER to exit this sample\n");
|
|
smaple_audio_getchar();
|
|
smaple_audio_getchar();
|
|
|
|
ret = sample_comm_audio_destory_trd_file_adec(ad_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
|
|
adec_ao_err0:
|
|
ret = sample_comm_audio_ao_unbind_adec(ao_dev, ao_chn, ad_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* function : file -> adec -> ao */
|
|
td_s32 sample_audio_adec_ao(td_void)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 ao_chn_cnt;
|
|
td_u32 adec_chn_cnt;
|
|
ot_audio_dev ao_dev;
|
|
ot_audio_dev ao_hdmi_dev;
|
|
ot_aio_attr aio_attr;
|
|
ot_aio_attr hdmi_ao_attr;
|
|
const ot_ao_chn ao_chn = 0;
|
|
const ot_adec_chn ad_chn = 0;
|
|
|
|
sample_audio_adec_ao_init_param(&aio_attr, &ao_dev);
|
|
|
|
hdmi_ao_attr.sample_rate = OT_AUDIO_SAMPLE_RATE_48000;
|
|
//hdmi_ao_attr.sample_rate = OT_AUDIO_SAMPLE_RATE_16000;
|
|
hdmi_ao_attr.bit_width = OT_AUDIO_BIT_WIDTH_16;
|
|
hdmi_ao_attr.work_mode = OT_AIO_MODE_I2S_MASTER;
|
|
hdmi_ao_attr.snd_mode = OT_AUDIO_SOUND_MODE_STEREO;
|
|
hdmi_ao_attr.expand_flag = 0;
|
|
hdmi_ao_attr.frame_num = 30; /* 30:frame num */
|
|
hdmi_ao_attr.point_num_per_frame = AACLC_SAMPLES_PER_FRAME;
|
|
hdmi_ao_attr.chn_cnt = 2; /* 2:chn cnt */
|
|
hdmi_ao_attr.clk_share = 1;
|
|
hdmi_ao_attr.i2s_type = OT_AIO_I2STYPE_INNERHDMI;
|
|
|
|
ao_hdmi_dev = SAMPLE_AUDIO_INNER_HDMI_AO_DEV;
|
|
|
|
|
|
|
|
adec_chn_cnt = aio_attr.chn_cnt >> ((td_u32)aio_attr.snd_mode);
|
|
ret = sample_comm_audio_start_adec(adec_chn_cnt, g_payload_type);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto adec_ao_err3;
|
|
}
|
|
|
|
ao_chn_cnt = aio_attr.chn_cnt;
|
|
ret = sample_comm_audio_start_ao(ao_dev, ao_chn_cnt, &aio_attr, g_in_sample_rate, g_aio_resample);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto adec_ao_err2;
|
|
}
|
|
|
|
ret = sample_comm_audio_start_ao(ao_hdmi_dev, ao_chn_cnt, &hdmi_ao_attr, g_in_sample_rate, g_aio_resample);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto adec_ao_err2;
|
|
}
|
|
|
|
|
|
|
|
ret = sample_comm_audio_cfg_acodec(&aio_attr);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto adec_ao_err1;
|
|
}
|
|
|
|
sample_audio_adec_ao_inner(ao_dev,ao_hdmi_dev, ao_chn, ad_chn);
|
|
|
|
adec_ao_err1:
|
|
ret = sample_comm_audio_stop_ao(ao_dev, ao_chn_cnt, g_aio_resample);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
|
|
adec_ao_err2:
|
|
ret = sample_comm_audio_stop_adec(ad_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
|
|
adec_ao_err3:
|
|
return ret;
|
|
}
|
|
|
|
static td_void sample_audio_ai_aenc_init_param(ot_aio_attr *aio_attr, ot_audio_dev *ai_dev, ot_audio_dev *ao_dev)
|
|
{
|
|
aio_attr->sample_rate = OT_AUDIO_SAMPLE_RATE_48000;
|
|
aio_attr->bit_width = OT_AUDIO_BIT_WIDTH_16;
|
|
aio_attr->work_mode = OT_AIO_MODE_I2S_MASTER;
|
|
aio_attr->snd_mode = OT_AUDIO_SOUND_MODE_STEREO;
|
|
aio_attr->expand_flag = 0;
|
|
aio_attr->frame_num = 30; /* 30:frame num */
|
|
if (g_payload_type == OT_PT_AAC) {
|
|
aio_attr->point_num_per_frame = AACLC_SAMPLES_PER_FRAME;
|
|
} else {
|
|
aio_attr->point_num_per_frame = SAMPLE_AUDIO_POINT_NUM_PER_FRAME;
|
|
}
|
|
aio_attr->chn_cnt = 2;
|
|
|
|
*ai_dev = SAMPLE_AUDIO_EXTERN_AI_DEV;
|
|
*ao_dev = SAMPLE_AUDIO_EXTERN_AO_DEV;
|
|
aio_attr->clk_share = 1;
|
|
aio_attr->i2s_type = OT_AIO_I2STYPE_EXTERN;
|
|
|
|
g_aio_resample = TD_FALSE;
|
|
g_in_sample_rate = OT_AUDIO_SAMPLE_RATE_BUTT;
|
|
g_out_sample_rate = OT_AUDIO_SAMPLE_RATE_BUTT;
|
|
}
|
|
|
|
static td_s32 sample_audio_aenc_bind_ai(ot_audio_dev ai_dev, td_u32 aenc_chn_cnt)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 i, j;
|
|
ot_ai_chn ai_chn;
|
|
ot_aenc_chn ae_chn;
|
|
|
|
for (i = 0; i < aenc_chn_cnt; i++) {
|
|
ae_chn = i;
|
|
ai_chn = i;
|
|
|
|
if (g_user_get_mode == TD_TRUE) {
|
|
ret = sample_comm_audio_creat_trd_ai_aenc(ai_dev, ai_chn, ae_chn);
|
|
} else {
|
|
ret = sample_comm_audio_aenc_bind_ai(ai_dev, ai_chn, ae_chn);
|
|
}
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto aenc_bind_err;
|
|
}
|
|
printf("ai(%d,%d) bind to aenc_chn:%d ok!\n", ai_dev, ai_chn, ae_chn);
|
|
}
|
|
return TD_SUCCESS;
|
|
|
|
aenc_bind_err:
|
|
for (j = 0; j < i; j++) {
|
|
ae_chn = j;
|
|
ai_chn = j;
|
|
|
|
if (g_user_get_mode == TD_TRUE) {
|
|
sample_comm_audio_destory_trd_ai(ai_dev, ai_chn);
|
|
} else {
|
|
sample_comm_audio_aenc_unbind_ai(ai_dev, ai_chn, ae_chn);
|
|
}
|
|
}
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
static td_void sample_audio_aenc_unbind_ai(ot_audio_dev ai_dev, td_u32 aenc_chn_cnt)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 i;
|
|
ot_ai_chn ai_chn;
|
|
ot_aenc_chn ae_chn;
|
|
|
|
for (i = 0; i < aenc_chn_cnt; i++) {
|
|
ae_chn = i;
|
|
ai_chn = i;
|
|
|
|
if (g_user_get_mode == TD_TRUE) {
|
|
ret = sample_comm_audio_destory_trd_ai(ai_dev, ai_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
} else {
|
|
ret = sample_comm_audio_aenc_unbind_ai(ai_dev, ai_chn, ae_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static td_s32 sample_audio_adec_bind_aenc(td_u32 adec_chn_cnt)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 i, j;
|
|
ot_aenc_chn ae_chn;
|
|
ot_adec_chn ad_chn;
|
|
FILE *fd = NULL;
|
|
|
|
for (i = 0; i < adec_chn_cnt; i++) {
|
|
ae_chn = i;
|
|
ad_chn = i;
|
|
|
|
fd = sample_audio_open_aenc_file(ad_chn, g_payload_type);
|
|
if (fd == TD_NULL) {
|
|
sample_dbg(TD_FAILURE);
|
|
for (j = 0; j < i; j++) {
|
|
sample_comm_audio_destory_trd_aenc_adec(j);
|
|
}
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
ret = sample_comm_audio_creat_trd_aenc_adec(ae_chn, ad_chn, fd);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
fclose(fd);
|
|
fd = TD_NULL;
|
|
for (j = 0; j < i; j++) {
|
|
sample_comm_audio_destory_trd_aenc_adec(j);
|
|
}
|
|
return TD_FAILURE;
|
|
}
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void sample_audio_adec_unbind_aenc(td_u32 adec_chn_cnt)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 i;
|
|
ot_adec_chn ad_chn;
|
|
|
|
for (i = 0; i < adec_chn_cnt; i++) {
|
|
ad_chn = i;
|
|
ret = sample_comm_audio_destory_trd_aenc_adec(ad_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
}
|
|
}
|
|
|
|
static td_s32 sample_audio_ao_bind_adec(td_u32 adec_chn_cnt, ot_audio_dev ao_dev)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 i, j;
|
|
ot_ao_chn ao_chn;
|
|
ot_adec_chn ad_chn;
|
|
|
|
for (i = 0; i < adec_chn_cnt; i++) {
|
|
ao_chn = i;
|
|
ad_chn = i;
|
|
ret = sample_comm_audio_ao_bind_adec(ao_dev, ao_chn, ad_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
for (j = 0; j < i; j++) {
|
|
sample_comm_audio_ao_unbind_adec(ao_dev, j, j);
|
|
}
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
printf("bind adec:%d to ao(%d,%d) ok \n", ad_chn, ao_dev, ao_chn);
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void sample_audio_ao_unbind_adec(td_u32 adec_chn_cnt, ot_audio_dev ao_dev)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 i;
|
|
ot_ao_chn ao_chn;
|
|
ot_adec_chn ad_chn;
|
|
|
|
for (i = 0; i < adec_chn_cnt; i++) {
|
|
ao_chn = i;
|
|
ad_chn = i;
|
|
ret = sample_comm_audio_ao_unbind_adec(ao_dev, ao_chn, ad_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
}
|
|
}
|
|
|
|
static td_void sample_audio_ai_aenc_inner(td_bool send_adec, ot_aio_attr *aio_attr, ot_audio_dev ao_dev)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 i;
|
|
ot_adec_chn ad_chn;
|
|
td_u32 ao_chn_cnt;
|
|
td_u32 adec_chn_cnt;
|
|
|
|
/* step 5: start adec & ao. ( if you want ) */
|
|
if (send_adec == TD_TRUE) {
|
|
adec_chn_cnt = aio_attr->chn_cnt >> ((td_u32)aio_attr->snd_mode);
|
|
ret = sample_comm_audio_start_adec(adec_chn_cnt, g_payload_type);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
return;
|
|
}
|
|
|
|
ao_chn_cnt = aio_attr->chn_cnt;
|
|
ret = sample_comm_audio_start_ao(ao_dev, ao_chn_cnt, aio_attr, g_in_sample_rate, g_aio_resample);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto ai_aenc_err2;
|
|
}
|
|
|
|
ret = sample_audio_adec_bind_aenc(adec_chn_cnt);
|
|
if (ret != TD_SUCCESS) {
|
|
goto ai_aenc_err1;
|
|
}
|
|
|
|
ret = sample_audio_ao_bind_adec(adec_chn_cnt, ao_dev);
|
|
if (ret != TD_SUCCESS) {
|
|
goto ai_aenc_err0;
|
|
}
|
|
}
|
|
|
|
printf("\nplease press twice ENTER to exit this sample\n");
|
|
smaple_audio_getchar();
|
|
smaple_audio_getchar();
|
|
|
|
/* step 6: exit the process */
|
|
if (send_adec == TD_TRUE) {
|
|
sample_audio_ao_unbind_adec(adec_chn_cnt, ao_dev);
|
|
|
|
ai_aenc_err0:
|
|
sample_audio_adec_unbind_aenc(adec_chn_cnt);
|
|
|
|
ai_aenc_err1:
|
|
ret = sample_comm_audio_stop_ao(ao_dev, ao_chn_cnt, g_aio_resample);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
|
|
ai_aenc_err2:
|
|
for (i = 0; i < adec_chn_cnt; i++) {
|
|
ad_chn = i;
|
|
ret = sample_comm_audio_stop_adec(ad_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* function : ai -> aenc -> file
|
|
* -> adec -> ao
|
|
*/
|
|
td_s32 sample_audio_ai_aenc(td_void)
|
|
{
|
|
td_s32 ret;
|
|
ot_audio_dev ai_dev;
|
|
ot_audio_dev ao_dev;
|
|
td_u32 ai_chn_cnt;
|
|
td_u32 aenc_chn_cnt;
|
|
td_bool send_adec = TD_TRUE;
|
|
ot_aio_attr aio_attr = {0};
|
|
sample_comm_ai_vqe_param ai_vqe_param = {0};
|
|
|
|
sample_audio_ai_aenc_init_param(&aio_attr, &ai_dev, &ao_dev);
|
|
|
|
/* step 1: start ai */
|
|
ai_chn_cnt = aio_attr.chn_cnt;
|
|
sample_audio_set_ai_vqe_param(&ai_vqe_param, g_out_sample_rate, g_aio_resample, TD_NULL, 0);
|
|
ret = sample_comm_audio_start_ai(ai_dev, ai_chn_cnt, &aio_attr, &ai_vqe_param, -1);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto ai_aenc_err6;
|
|
}
|
|
|
|
/* step 2: config audio codec */
|
|
ret = sample_comm_audio_cfg_acodec(&aio_attr);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto ai_aenc_err5;
|
|
}
|
|
|
|
/* step 3: start aenc */
|
|
aenc_chn_cnt = aio_attr.chn_cnt >> ((td_u32)aio_attr.snd_mode);
|
|
ret = sample_comm_audio_start_aenc(aenc_chn_cnt, &aio_attr, g_payload_type);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto ai_aenc_err5;
|
|
}
|
|
|
|
/* step 4: aenc bind ai chn */
|
|
ret = sample_audio_aenc_bind_ai(ai_dev, aenc_chn_cnt);
|
|
if (ret != TD_SUCCESS) {
|
|
goto ai_aenc_err4;
|
|
}
|
|
|
|
sample_audio_ai_aenc_inner(send_adec, &aio_attr, ao_dev);
|
|
|
|
sample_audio_aenc_unbind_ai(ai_dev, aenc_chn_cnt);
|
|
|
|
ai_aenc_err4:
|
|
ret = sample_comm_audio_stop_aenc(aenc_chn_cnt);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
|
|
ai_aenc_err5:
|
|
ret = sample_comm_audio_stop_ai(ai_dev, ai_chn_cnt, g_aio_resample, TD_FALSE);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
|
|
ai_aenc_err6:
|
|
return ret;
|
|
}
|
|
|
|
static td_void sample_audio_ai_to_ext_resample_init_param(ot_aio_attr *aio_attr, ot_audio_dev *ai_dev)
|
|
{
|
|
aio_attr->sample_rate = OT_AUDIO_SAMPLE_RATE_16000;
|
|
aio_attr->bit_width = OT_AUDIO_BIT_WIDTH_16;
|
|
aio_attr->work_mode = OT_AIO_MODE_I2S_MASTER;
|
|
aio_attr->snd_mode = OT_AUDIO_SOUND_MODE_MONO;
|
|
aio_attr->expand_flag = 0;
|
|
aio_attr->frame_num = 30; /* 30:frame num */
|
|
aio_attr->point_num_per_frame = SAMPLE_AUDIO_POINT_NUM_PER_FRAME;
|
|
aio_attr->chn_cnt = 1;
|
|
|
|
*ai_dev = SAMPLE_AUDIO_EXTERN_AI_DEV;
|
|
aio_attr->clk_share = 1;
|
|
aio_attr->i2s_type = OT_AIO_I2STYPE_EXTERN;
|
|
|
|
g_aio_resample = TD_FALSE;
|
|
g_out_sample_rate = OT_AUDIO_SAMPLE_RATE_24000;
|
|
}
|
|
|
|
static td_s32 sample_audio_start_ai_resample(td_u32 ai_chn_cnt, ot_audio_dev ai_dev, ot_aio_attr *aio_attr)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 i, j;
|
|
ot_ai_chn ai_chn;
|
|
FILE *fd = TD_NULL;
|
|
|
|
for (i = 0; i < ai_chn_cnt; i++) {
|
|
ai_chn = i;
|
|
|
|
fd = sample_audio_open_res_file(ai_chn);
|
|
if (fd == TD_NULL) {
|
|
sample_dbg(TD_FAILURE);
|
|
for (j = 0; j < i; j++) {
|
|
sample_comm_audio_destroy_trd_ai_ext_res(ai_dev, j);
|
|
}
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
ret = sample_comm_audio_creat_trd_ai_ext_res(aio_attr, ai_dev, ai_chn, g_out_sample_rate, fd);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
fclose(fd);
|
|
fd = TD_NULL;
|
|
for (j = 0; j < i; j++) {
|
|
sample_comm_audio_destroy_trd_ai_ext_res(ai_dev, j);
|
|
}
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
printf("ai(%d,%d) extern resample ok!\n", ai_dev, ai_chn);
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void sample_audio_stop_ai_resample(td_u32 ai_chn_cnt, ot_audio_dev ai_dev)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 i;
|
|
ot_ai_chn ai_chn;
|
|
|
|
for (i = 0; i < ai_chn_cnt; i++) {
|
|
ai_chn = i;
|
|
ret = sample_comm_audio_destroy_trd_ai_ext_res(ai_dev, ai_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* function : Ai -> ExtResample -> file */
|
|
td_s32 sample_audio_ai_to_ext_resample(td_void)
|
|
{
|
|
td_s32 ret;
|
|
ot_audio_dev ai_dev;
|
|
td_u32 ai_chn_cnt;
|
|
ot_aio_attr aio_attr = {0};
|
|
sample_comm_ai_vqe_param ai_vqe_param = {0};
|
|
|
|
sample_audio_ai_to_ext_resample_init_param(&aio_attr, &ai_dev);
|
|
|
|
/* step 1: start Ai, disable inner resample. */
|
|
ai_chn_cnt = aio_attr.chn_cnt;
|
|
sample_audio_set_ai_vqe_param(&ai_vqe_param, g_out_sample_rate, g_aio_resample, TD_NULL, 0);
|
|
ret = sample_comm_audio_start_ai(ai_dev, ai_chn_cnt, &aio_attr, &ai_vqe_param, -1);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto ai_res_err3;
|
|
}
|
|
|
|
/* step 2: config audio codec */
|
|
ret = sample_comm_audio_cfg_acodec(&aio_attr);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto ai_res_err2;
|
|
}
|
|
|
|
/* step 3: enable extern resample. */
|
|
ret = sample_audio_init_ext_res_fun();
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto ai_res_err2;
|
|
}
|
|
|
|
/* step 4: Create thread to resample. */
|
|
ret = sample_audio_start_ai_resample(ai_chn_cnt, ai_dev, &aio_attr);
|
|
if (ret != TD_SUCCESS) {
|
|
goto ai_res_err1;
|
|
}
|
|
|
|
printf("\nplease press twice ENTER to exit this sample\n");
|
|
smaple_audio_getchar();
|
|
smaple_audio_getchar();
|
|
|
|
/* step 5: exit the process */
|
|
sample_audio_stop_ai_resample(ai_chn_cnt, ai_dev);
|
|
|
|
ai_res_err1:
|
|
sample_audio_deinit_ext_res_fun();
|
|
|
|
ai_res_err2:
|
|
ret = sample_comm_audio_stop_ai(ai_dev, ai_chn_cnt, g_aio_resample, TD_FALSE);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
|
|
ai_res_err3:
|
|
return ret;
|
|
}
|
|
|
|
static td_void sample_audio_ai_ao_init_param(ot_aio_attr *aio_attr, ot_audio_dev *ai_dev, ot_audio_dev *ao_dev)
|
|
{
|
|
aio_attr->sample_rate = OT_AUDIO_SAMPLE_RATE_16000;
|
|
aio_attr->bit_width = OT_AUDIO_BIT_WIDTH_16;
|
|
aio_attr->work_mode = OT_AIO_MODE_I2S_MASTER;
|
|
aio_attr->snd_mode = OT_AUDIO_SOUND_MODE_STEREO;
|
|
aio_attr->expand_flag = 0;
|
|
aio_attr->frame_num = 30; /* 30:frame num */
|
|
aio_attr->point_num_per_frame = AACLC_SAMPLES_PER_FRAME;
|
|
aio_attr->chn_cnt = 2; /* 2:chn cnt */
|
|
|
|
*ai_dev = SAMPLE_AUDIO_EXTERN_AI_DEV;
|
|
*ao_dev = SAMPLE_AUDIO_EXTERN_AO_DEV;
|
|
aio_attr->clk_share = 1;
|
|
aio_attr->i2s_type = OT_AIO_I2STYPE_EXTERN;
|
|
|
|
g_aio_resample = TD_FALSE;
|
|
/* config ao resample attr if needed */
|
|
if (g_aio_resample == TD_TRUE) {
|
|
/* ai 48k -> 32k */
|
|
g_out_sample_rate = OT_AUDIO_SAMPLE_RATE_32000;
|
|
|
|
/* ao 32k -> 48k */
|
|
g_in_sample_rate = OT_AUDIO_SAMPLE_RATE_32000;
|
|
} else {
|
|
g_in_sample_rate = OT_AUDIO_SAMPLE_RATE_BUTT;
|
|
g_out_sample_rate = OT_AUDIO_SAMPLE_RATE_BUTT;
|
|
}
|
|
|
|
/* resample and anr should be user get mode */
|
|
g_user_get_mode = (g_aio_resample == TD_TRUE) ? TD_TRUE : TD_FALSE;
|
|
}
|
|
|
|
static td_s32 sample_audio_ao_bind_ai(ot_audio_dev ai_dev, ot_ai_chn ai_chn,
|
|
ot_audio_dev ao_dev, ot_ao_chn ao_chn)
|
|
{
|
|
td_s32 ret;
|
|
if (g_user_get_mode == TD_TRUE) {
|
|
ret = sample_comm_audio_creat_trd_ai_ao(ai_dev, ai_chn, ao_dev, ao_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
return TD_FAILURE;
|
|
}
|
|
} else {
|
|
ret = sample_comm_audio_ao_bind_ai(ai_dev, ai_chn, ao_dev, ao_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
return TD_FAILURE;
|
|
}
|
|
}
|
|
|
|
printf("ai(%d,%d) bind to ao(%d,%d) ok\n", ai_dev, ai_chn, ao_dev, ao_chn);
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void sample_audio_ao_unbind_ai(ot_audio_dev ai_dev, ot_ai_chn ai_chn,
|
|
ot_audio_dev ao_dev, ot_ao_chn ao_chn)
|
|
{
|
|
td_s32 ret;
|
|
if (g_user_get_mode == TD_TRUE) {
|
|
ret = sample_comm_audio_destory_trd_ai(ai_dev, ai_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
} else {
|
|
ret = sample_comm_audio_ao_unbind_ai(ai_dev, ai_chn, ao_dev, ao_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
}
|
|
}
|
|
|
|
static td_void sample_audio_ai_ao_inner(ot_audio_dev ai_dev, ot_ai_chn ai_chn,
|
|
ot_audio_dev ao_dev, ot_ao_chn ao_chn)
|
|
{
|
|
td_s32 ret;
|
|
|
|
/* bind AI to AO channel */
|
|
ret = sample_audio_ao_bind_ai(ai_dev, ai_chn, ao_dev, ao_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
if (g_ao_volume_ctrl == TD_TRUE) {
|
|
ret = sample_comm_audio_creat_trd_ao_vol_ctrl(ao_dev);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto ai_ao_err0;
|
|
}
|
|
}
|
|
|
|
printf("\nplease press twice ENTER to exit this sample\n");
|
|
smaple_audio_getchar();
|
|
smaple_audio_getchar();
|
|
|
|
if (g_ao_volume_ctrl == TD_TRUE) {
|
|
ret = sample_comm_audio_destory_trd_ao_vol_ctrl(ao_dev);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
}
|
|
|
|
ai_ao_err0:
|
|
sample_audio_ao_unbind_ai(ai_dev, ai_chn, ao_dev, ao_chn);
|
|
}
|
|
|
|
/* function : ai -> ao(with fade in/out and volume adjust) */
|
|
td_s32 sample_audio_ai_ao(td_void)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 ai_chn_cnt;
|
|
td_u32 ao_chn_cnt;
|
|
ot_audio_dev ai_dev;
|
|
ot_audio_dev ao_dev;
|
|
const ot_ai_chn ai_chn = 0;
|
|
const ot_ao_chn ao_chn = 0;
|
|
ot_aio_attr aio_attr = {0};
|
|
sample_comm_ai_vqe_param ai_vqe_param = {0};
|
|
|
|
sample_audio_ai_ao_init_param(&aio_attr, &ai_dev, &ao_dev);
|
|
|
|
/* enable AI channel */
|
|
ai_chn_cnt = aio_attr.chn_cnt;
|
|
sample_audio_set_ai_vqe_param(&ai_vqe_param, g_out_sample_rate, g_aio_resample, TD_NULL, 0);
|
|
ret = sample_comm_audio_start_ai(ai_dev, ai_chn_cnt, &aio_attr, &ai_vqe_param, -1);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto ai_ao_err3;
|
|
}
|
|
|
|
/* enable AO channel */
|
|
ao_chn_cnt = aio_attr.chn_cnt;
|
|
ret = sample_comm_audio_start_ao(ao_dev, ao_chn_cnt, &aio_attr, g_in_sample_rate, g_aio_resample);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto ai_ao_err2;
|
|
}
|
|
|
|
/* config internal audio codec */
|
|
ret = sample_comm_audio_cfg_acodec(&aio_attr);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto ai_ao_err1;
|
|
}
|
|
|
|
sample_audio_ai_ao_inner(ai_dev, ai_chn, ao_dev, ao_chn);
|
|
|
|
ai_ao_err1:
|
|
ret = sample_comm_audio_stop_ao(ao_dev, ao_chn_cnt, g_aio_resample);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
|
|
ai_ao_err2:
|
|
ret = sample_comm_audio_stop_ai(ai_dev, ai_chn_cnt, g_aio_resample, TD_FALSE);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
|
|
ai_ao_err3:
|
|
return ret;
|
|
}
|
|
|
|
static td_void sample_audio_ai_to_ao_sys_chn_init_param(ot_aio_attr *aio_attr, ot_audio_dev *ai_dev,
|
|
ot_audio_dev *ao_dev)
|
|
{
|
|
aio_attr->sample_rate = OT_AUDIO_SAMPLE_RATE_16000;
|
|
aio_attr->bit_width = OT_AUDIO_BIT_WIDTH_16;
|
|
aio_attr->work_mode = OT_AIO_MODE_I2S_MASTER;
|
|
aio_attr->snd_mode = OT_AUDIO_SOUND_MODE_MONO;
|
|
aio_attr->expand_flag = 0;
|
|
aio_attr->frame_num = 30; /* 30:frame num */
|
|
aio_attr->point_num_per_frame = AACLC_SAMPLES_PER_FRAME;
|
|
aio_attr->chn_cnt = 1;
|
|
|
|
*ai_dev = SAMPLE_AUDIO_EXTERN_AI_DEV;
|
|
*ao_dev = SAMPLE_AUDIO_EXTERN_AO_DEV;
|
|
aio_attr->clk_share = 1;
|
|
aio_attr->i2s_type = OT_AIO_I2STYPE_EXTERN;
|
|
|
|
g_aio_resample = TD_FALSE;
|
|
/* config ao resample attr if needed */
|
|
if (g_aio_resample == TD_TRUE) {
|
|
/* ai 48k -> 32k */
|
|
g_out_sample_rate = OT_AUDIO_SAMPLE_RATE_32000;
|
|
|
|
/* ao 32k -> 48k */
|
|
g_in_sample_rate = OT_AUDIO_SAMPLE_RATE_32000;
|
|
} else {
|
|
g_in_sample_rate = OT_AUDIO_SAMPLE_RATE_BUTT;
|
|
g_out_sample_rate = OT_AUDIO_SAMPLE_RATE_BUTT;
|
|
}
|
|
|
|
/* resample and anr should be user get mode */
|
|
g_user_get_mode = (g_aio_resample == TD_TRUE) ? TD_TRUE : TD_FALSE;
|
|
}
|
|
|
|
static td_void sample_audio_ai_to_ao_sys_chn_inner(ot_audio_dev ai_dev, ot_ai_chn ai_chn,
|
|
ot_audio_dev ao_dev)
|
|
{
|
|
td_s32 ret;
|
|
|
|
/* bind AI to AO channel */
|
|
ret = sample_comm_audio_creat_trd_ai_ao(ai_dev, ai_chn, ao_dev, OT_AO_SYS_CHN_ID);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
return;
|
|
}
|
|
printf("ai(%d,%d) bind to ao(%d,%d) ok\n", ai_dev, ai_chn, ao_dev, OT_AO_SYS_CHN_ID);
|
|
|
|
printf("\nplease press twice ENTER to exit this sample\n");
|
|
smaple_audio_getchar();
|
|
smaple_audio_getchar();
|
|
|
|
ret = sample_comm_audio_destory_trd_ai(ai_dev, ai_chn);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
}
|
|
|
|
/* function : ai -> ao (sys chn) */
|
|
td_s32 sample_audio_ai_to_ao_sys_chn(td_void)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 ai_chn_cnt, ao_chn_cnt;
|
|
ot_audio_dev ai_dev, ao_dev;
|
|
const ot_ai_chn ai_chn = 0;
|
|
ot_aio_attr aio_attr = {0};
|
|
sample_comm_ai_vqe_param ai_vqe_param = {0};
|
|
|
|
sample_audio_ai_to_ao_sys_chn_init_param(&aio_attr, &ai_dev, &ao_dev);
|
|
|
|
/* enable AI channel */
|
|
ai_chn_cnt = aio_attr.chn_cnt;
|
|
sample_audio_set_ai_vqe_param(&ai_vqe_param, g_out_sample_rate, g_aio_resample, TD_NULL, 0);
|
|
ret = sample_comm_audio_start_ai(ai_dev, ai_chn_cnt, &aio_attr, &ai_vqe_param, -1);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto ai_ao_sys_chn_err3;
|
|
}
|
|
|
|
/* enable AO channel */
|
|
ao_chn_cnt = aio_attr.chn_cnt;
|
|
ret = sample_comm_audio_start_ao(ao_dev, ao_chn_cnt, &aio_attr, g_in_sample_rate, g_aio_resample);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto ai_ao_sys_chn_err2;
|
|
}
|
|
|
|
/* config internal audio codec */
|
|
ret = sample_comm_audio_cfg_acodec(&aio_attr);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto ai_ao_sys_chn_err1;
|
|
}
|
|
|
|
sample_audio_ai_to_ao_sys_chn_inner(ai_dev, ai_chn, ao_dev);
|
|
|
|
ai_ao_sys_chn_err1:
|
|
ret = sample_comm_audio_stop_ao(ao_dev, ao_chn_cnt, g_aio_resample);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
|
|
ai_ao_sys_chn_err2:
|
|
ret = sample_comm_audio_stop_ai(ai_dev, ai_chn_cnt, g_aio_resample, TD_FALSE);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
|
|
ai_ao_sys_chn_err3:
|
|
return ret;
|
|
}
|
|
|
|
static td_void ai_init_record_vqe_param(ot_ai_record_vqe_cfg *ai_vqe_record_attr)
|
|
{
|
|
ai_vqe_record_attr->work_sample_rate = OT_AUDIO_SAMPLE_RATE_48000;
|
|
ai_vqe_record_attr->frame_sample = AACLC_SAMPLES_PER_FRAME;
|
|
ai_vqe_record_attr->work_state = OT_VQE_WORK_STATE_COMMON;
|
|
ai_vqe_record_attr->in_chn_num = 2; /* 2: chn num */
|
|
ai_vqe_record_attr->out_chn_num = 2; /* 2: chn num */
|
|
ai_vqe_record_attr->record_type = OT_VQE_RECORD_NORMAL;
|
|
ai_vqe_record_attr->drc_cfg.usr_mode = TD_FALSE;
|
|
ai_vqe_record_attr->rnr_cfg.usr_mode = TD_FALSE;
|
|
ai_vqe_record_attr->hdr_cfg.usr_mode = TD_FALSE;
|
|
ai_vqe_record_attr->hpf_cfg.usr_mode = TD_TRUE;
|
|
ai_vqe_record_attr->hpf_cfg.hpf_freq = OT_AUDIO_HPF_FREQ_80;
|
|
|
|
ai_vqe_record_attr->open_mask =
|
|
OT_AI_RECORDVQE_MASK_DRC | OT_AI_RECORDVQE_MASK_HPF | OT_AI_RECORDVQE_MASK_RNR;
|
|
}
|
|
|
|
static td_void ai_init_talk_vqe_param(ot_ai_talk_vqe_cfg *ai_vqe_talk_attr)
|
|
{
|
|
ai_vqe_talk_attr->work_sample_rate = OT_AUDIO_SAMPLE_RATE_16000;
|
|
ai_vqe_talk_attr->frame_sample = AACLC_SAMPLES_PER_FRAME;
|
|
ai_vqe_talk_attr->work_state = OT_VQE_WORK_STATE_COMMON;
|
|
ai_vqe_talk_attr->agc_cfg.usr_mode = TD_FALSE;
|
|
ai_vqe_talk_attr->aec_cfg.usr_mode = TD_FALSE;
|
|
ai_vqe_talk_attr->anr_cfg.usr_mode = TD_FALSE;
|
|
ai_vqe_talk_attr->hpf_cfg.usr_mode = TD_TRUE;
|
|
ai_vqe_talk_attr->hpf_cfg.hpf_freq = OT_AUDIO_HPF_FREQ_150;
|
|
|
|
ai_vqe_talk_attr->open_mask = OT_AI_TALKVQE_MASK_AGC | OT_AI_TALKVQE_MASK_ANR | OT_AI_TALKVQE_MASK_HPF;
|
|
}
|
|
|
|
static td_void sample_audio_ai_vqe_process_ao_init_param(ot_aio_attr *aio_attr, ot_audio_dev *ai_dev,
|
|
ot_audio_dev *ao_dev, td_void **ai_vqe_attr)
|
|
{
|
|
aio_attr->sample_rate = OT_AUDIO_SAMPLE_RATE_16000;
|
|
aio_attr->bit_width = OT_AUDIO_BIT_WIDTH_16;
|
|
aio_attr->work_mode = OT_AIO_MODE_I2S_MASTER;
|
|
aio_attr->snd_mode = OT_AUDIO_SOUND_MODE_MONO;
|
|
aio_attr->expand_flag = 0;
|
|
aio_attr->frame_num = 30; /* 30:frame num */
|
|
aio_attr->point_num_per_frame = AACLC_SAMPLES_PER_FRAME;
|
|
aio_attr->chn_cnt = 1;
|
|
|
|
*ai_dev = SAMPLE_AUDIO_EXTERN_AI_DEV;
|
|
*ao_dev = SAMPLE_AUDIO_EXTERN_AO_DEV;
|
|
aio_attr->clk_share = 1;
|
|
aio_attr->i2s_type = OT_AIO_I2STYPE_EXTERN;
|
|
|
|
g_aio_resample = TD_FALSE;
|
|
g_in_sample_rate = OT_AUDIO_SAMPLE_RATE_BUTT;
|
|
g_out_sample_rate = OT_AUDIO_SAMPLE_RATE_BUTT;
|
|
|
|
if (g_ai_vqe_type == 1) { /* 1:record vqe */
|
|
ai_init_record_vqe_param(&g_ai_vqe_record_attr);
|
|
*ai_vqe_attr = (td_void *)&g_ai_vqe_record_attr;
|
|
} else if (g_ai_vqe_type == 2) { /* 2:talk vqe */
|
|
ai_init_talk_vqe_param(&g_ai_vqe_talk_attr);
|
|
*ai_vqe_attr = (td_void *)&g_ai_vqe_talk_attr;
|
|
} else {
|
|
*ai_vqe_attr = TD_NULL;
|
|
}
|
|
}
|
|
|
|
static td_s32 sample_audio_ao_bind_ai_multi_chn(ot_audio_dev ai_dev, td_u32 ai_chn_cnt,
|
|
ot_audio_dev ao_dev)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 i, j;
|
|
|
|
for (i = 0; i < ai_chn_cnt; i++) {
|
|
ret = sample_comm_audio_creat_trd_ai_ao(ai_dev, i, ao_dev, i);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
for (j = 0; j < i; j++) {
|
|
sample_comm_audio_destory_trd_ai(ai_dev, j);
|
|
}
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
printf("bind ai(%d,%d) to ao(%d,%d) ok \n", ai_dev, i, ao_dev, i);
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void sample_audio_ao_unbind_ai_multi_chn(ot_audio_dev ai_dev, td_u32 ai_chn_cnt)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 i;
|
|
|
|
for (i = 0; i < ai_chn_cnt; i++) {
|
|
ret = sample_comm_audio_destory_trd_ai(ai_dev, i);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* function : ai -> ao (with VQE) */
|
|
td_s32 sample_audio_ai_vqe_process_ao(td_void)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 ai_chn_cnt;
|
|
td_u32 ao_chn_cnt;
|
|
ot_audio_dev ai_dev;
|
|
ot_audio_dev ao_dev;
|
|
ot_aio_attr aio_attr = {0};
|
|
td_void *ai_vqe_attr = NULL;
|
|
sample_comm_ai_vqe_param ai_vqe_param = {0};
|
|
|
|
sample_audio_ai_vqe_process_ao_init_param(&aio_attr, &ai_dev, &ao_dev, &ai_vqe_attr);
|
|
|
|
/* step 1: start ai */
|
|
ai_chn_cnt = aio_attr.chn_cnt;
|
|
sample_audio_set_ai_vqe_param(&ai_vqe_param, g_out_sample_rate, g_aio_resample, ai_vqe_attr, g_ai_vqe_type);
|
|
ret = sample_comm_audio_start_ai(ai_dev, ai_chn_cnt, &aio_attr, &ai_vqe_param, ao_dev);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto vqe_err2;
|
|
}
|
|
|
|
/* step 2: start ao */
|
|
ao_chn_cnt = aio_attr.chn_cnt;
|
|
ret = sample_comm_audio_start_ao(ao_dev, ao_chn_cnt, &aio_attr, g_in_sample_rate, g_aio_resample);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto vqe_err1;
|
|
}
|
|
|
|
/* step 3: config audio codec */
|
|
ret = sample_comm_audio_cfg_acodec(&aio_attr);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto vqe_err0;
|
|
}
|
|
|
|
/* step 4: ao bind ai chn */
|
|
ret = sample_audio_ao_bind_ai_multi_chn(ai_dev, ai_chn_cnt, ao_dev);
|
|
if (ret != TD_SUCCESS) {
|
|
goto vqe_err0;
|
|
}
|
|
|
|
printf("\nplease press twice ENTER to exit this sample\n");
|
|
smaple_audio_getchar();
|
|
smaple_audio_getchar();
|
|
|
|
/* step 5: exit the process */
|
|
sample_audio_ao_unbind_ai_multi_chn(ai_dev, ai_chn_cnt);
|
|
|
|
vqe_err0:
|
|
ret = sample_comm_audio_stop_ao(ao_dev, ao_chn_cnt, g_aio_resample);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
|
|
vqe_err1:
|
|
ret = sample_comm_audio_stop_ai(ai_dev, ai_chn_cnt, g_aio_resample, TD_TRUE);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
|
|
vqe_err2:
|
|
return ret;
|
|
}
|
|
|
|
static td_void sample_audio_ai_hdmi_ao_init_param(ot_aio_attr *aio_attr, ot_audio_dev *ai_dev,
|
|
ot_aio_attr *hdmi_ao_attr)
|
|
{
|
|
aio_attr->sample_rate = OT_AUDIO_SAMPLE_RATE_48000;
|
|
aio_attr->bit_width = OT_AUDIO_BIT_WIDTH_16;
|
|
aio_attr->work_mode = OT_AIO_MODE_I2S_MASTER;
|
|
aio_attr->snd_mode = OT_AUDIO_SOUND_MODE_STEREO;
|
|
aio_attr->expand_flag = 0;
|
|
aio_attr->frame_num = 30; /* 30:frame num */
|
|
aio_attr->point_num_per_frame = AACLC_SAMPLES_PER_FRAME;
|
|
aio_attr->chn_cnt = 2; /* 2:chn cnt */
|
|
|
|
*ai_dev = SAMPLE_AUDIO_EXTERN_AI_DEV;
|
|
aio_attr->clk_share = 1;
|
|
aio_attr->i2s_type = OT_AIO_I2STYPE_EXTERN;
|
|
|
|
hdmi_ao_attr->sample_rate = OT_AUDIO_SAMPLE_RATE_48000;
|
|
hdmi_ao_attr->bit_width = OT_AUDIO_BIT_WIDTH_16;
|
|
hdmi_ao_attr->work_mode = OT_AIO_MODE_I2S_MASTER;
|
|
hdmi_ao_attr->snd_mode = OT_AUDIO_SOUND_MODE_STEREO;
|
|
hdmi_ao_attr->expand_flag = 0;
|
|
hdmi_ao_attr->frame_num = 30; /* 30:frame num */
|
|
hdmi_ao_attr->point_num_per_frame = AACLC_SAMPLES_PER_FRAME;
|
|
hdmi_ao_attr->chn_cnt = 2; /* 2:chn cnt */
|
|
hdmi_ao_attr->clk_share = 1;
|
|
hdmi_ao_attr->i2s_type = OT_AIO_I2STYPE_INNERHDMI;
|
|
|
|
g_in_sample_rate = aio_attr->sample_rate;
|
|
g_aio_resample = TD_FALSE;
|
|
/* resample should be user get mode */
|
|
g_user_get_mode = (g_aio_resample == TD_TRUE) ? TD_TRUE : TD_FALSE;
|
|
}
|
|
|
|
/* function : ai -> ao(hdmi) */
|
|
td_s32 sample_audio_ai_hdmi_ao(td_void)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 ai_chn_cnt;
|
|
td_u32 ao_chn_cnt;
|
|
ot_audio_dev ai_dev;
|
|
ot_audio_dev ao_dev = SAMPLE_AUDIO_INNER_HDMI_AO_DEV;
|
|
ot_aio_attr aio_attr = {0};
|
|
ot_aio_attr hdmi_ao_attr = {0};
|
|
sample_comm_ai_vqe_param ai_vqe_param = {0};
|
|
|
|
sample_audio_ai_hdmi_ao_init_param(&aio_attr, &ai_dev, &hdmi_ao_attr);
|
|
|
|
/* enable AI channel */
|
|
ai_chn_cnt = aio_attr.chn_cnt;
|
|
sample_audio_set_ai_vqe_param(&ai_vqe_param, OT_AUDIO_SAMPLE_RATE_BUTT, TD_FALSE, TD_NULL, 0);
|
|
ret = sample_comm_audio_start_ai(ai_dev, ai_chn_cnt, &aio_attr, &ai_vqe_param, -1);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto hdmi_err2;
|
|
}
|
|
|
|
/* enable AO channel */
|
|
ao_chn_cnt = hdmi_ao_attr.chn_cnt;
|
|
ret = sample_comm_audio_start_ao(ao_dev, ao_chn_cnt, &hdmi_ao_attr, g_in_sample_rate, g_aio_resample);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto hdmi_err1;
|
|
}
|
|
|
|
/* config audio codec */
|
|
ret = sample_comm_audio_cfg_acodec(&aio_attr);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
goto hdmi_err0;
|
|
}
|
|
|
|
/* AI to AO channel */
|
|
ret = sample_audio_ao_bind_ai_multi_chn(ai_dev, ai_chn_cnt, ao_dev);
|
|
if (ret != TD_SUCCESS) {
|
|
goto hdmi_err0;
|
|
}
|
|
|
|
printf("\nplease press twice ENTER to exit this sample\n");
|
|
smaple_audio_getchar();
|
|
smaple_audio_getchar();
|
|
|
|
sample_audio_ao_unbind_ai_multi_chn(ai_dev, ai_chn_cnt);
|
|
|
|
hdmi_err0:
|
|
ret = sample_comm_audio_stop_ao(ao_dev, hdmi_ao_attr.chn_cnt, TD_FALSE);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
|
|
hdmi_err1:
|
|
ret = sample_comm_audio_stop_ai(ai_dev, ai_chn_cnt, TD_FALSE, TD_FALSE);
|
|
if (ret != TD_SUCCESS) {
|
|
sample_dbg(ret);
|
|
}
|
|
|
|
hdmi_err2:
|
|
return ret;
|
|
}
|
|
|
|
#if defined(OT_VQE_USE_STATIC_MODULE_REGISTER)
|
|
/* function : to register vqe module */
|
|
td_s32 sample_audio_register_vqe_module(td_void)
|
|
{
|
|
td_s32 ret;
|
|
ot_audio_vqe_register vqe_reg_cfg = {0};
|
|
|
|
/* RecordVQE */
|
|
vqe_reg_cfg.record_mod_cfg.handle = ot_vqe_record_get_handle();
|
|
|
|
/* Resample */
|
|
vqe_reg_cfg.resample_mod_cfg.handle = ot_vqe_resample_get_handle();
|
|
|
|
/* TalkVQE */
|
|
vqe_reg_cfg.hpf_mod_cfg.handle = ot_vqe_hpf_get_handle();
|
|
vqe_reg_cfg.aec_mod_cfg.handle = ot_vqe_aec_get_handle();
|
|
vqe_reg_cfg.agc_mod_cfg.handle = ot_vqe_agc_get_handle();
|
|
vqe_reg_cfg.anr_mod_cfg.handle = ot_vqe_anr_get_handle();
|
|
vqe_reg_cfg.eq_mod_cfg.handle = ot_vqe_eq_get_handle();
|
|
|
|
ret = ss_mpi_audio_register_vqe_mod(&vqe_reg_cfg);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("%s: register vqe module fail with ret = %d!\n", __FUNCTION__, ret);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
td_void sample_audio_usage(td_void)
|
|
{
|
|
printf("\n\n/usage:./sample_audio <index>/\n");
|
|
printf("\tindex and its function list below\n");
|
|
printf("\t0: start AI to AO loop\n");
|
|
printf("\t1: send audio frame to AENC channel from AI, save them\n");
|
|
printf("\t2: read audio stream from file, decode and send AO\n");
|
|
printf("\t3: start AI(VQE process), then send to AO\n");
|
|
printf("\t4: start AI to AO(HDMI) loop\n");
|
|
printf("\t5: start AI to AO(sys_chn) loop\n");
|
|
printf("\t6: start AI, then send to resample, save it\n");
|
|
}
|
|
|
|
/* function : to process abnormal case */
|
|
static td_void sample_audio_handle_sig(td_s32 signo)
|
|
{
|
|
if (g_sample_audio_exit == TD_TRUE) {
|
|
return;
|
|
}
|
|
|
|
if ((signo == SIGINT) || (signo == SIGTERM)) {
|
|
g_sample_audio_exit = TD_TRUE;
|
|
}
|
|
}
|
|
|
|
static td_void main_inner(td_u32 index)
|
|
{
|
|
switch (index) {
|
|
case 0: { /* 0:ai->ao */
|
|
sample_audio_ai_ao();
|
|
break;
|
|
}
|
|
case 1: { /* 1:ai->aenc->adec->ao */
|
|
sample_audio_ai_aenc();
|
|
break;
|
|
}
|
|
case 2: { /* 2:file->adec->ao */
|
|
sample_audio_adec_ao();
|
|
break;
|
|
}
|
|
case 7: { /* 2:file->adec->ao */
|
|
// sample_audio_adec_hdmi_ao();
|
|
break;
|
|
}
|
|
case 3: { /* 3:ai->ao vqe */
|
|
sample_audio_ai_vqe_process_ao();
|
|
break;
|
|
}
|
|
case 4: { /* 4:ai->ao hdmi */
|
|
sample_audio_ai_hdmi_ao();
|
|
break;
|
|
}
|
|
case 5: { /* 5:ai->ao synchn */
|
|
sample_audio_ai_to_ao_sys_chn();
|
|
break;
|
|
}
|
|
case 6: { /* 6:resample test */
|
|
sample_audio_ai_to_ext_resample();
|
|
break;
|
|
}
|
|
default: {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* function : main */
|
|
#ifdef __LITEOS__
|
|
td_s32 app_main(int argc, char *argv[])
|
|
#else
|
|
td_s32 main(int argc, char *argv[])
|
|
#endif
|
|
{
|
|
td_s32 ret;
|
|
ot_vb_cfg vb_conf;
|
|
td_u32 index;
|
|
|
|
if (argc != 2) { /* 2:argv num */
|
|
sample_audio_usage();
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (!strncmp(argv[1], "-h", 2)) { /* 2:arg num */
|
|
sample_audio_usage();
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if ((strlen(argv[1]) != 1) ||
|
|
(argv[1][0] < '0' || argv[1][0] > '6')) { /* 6:arg num */
|
|
sample_audio_usage();
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
index = atoi(argv[1]);
|
|
|
|
sample_sys_signal(&sample_audio_handle_sig);
|
|
#if defined(OT_VQE_USE_STATIC_MODULE_REGISTER)
|
|
ret = sample_audio_register_vqe_module();
|
|
if (ret != TD_SUCCESS) {
|
|
return TD_FAILURE;
|
|
}
|
|
#endif
|
|
ret = memset_s(&vb_conf, sizeof(ot_vb_cfg), 0, sizeof(ot_vb_cfg));
|
|
if (ret != EOK) {
|
|
printf("%s: vb_config init failed with %d!\n", __FUNCTION__, ret);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
ret = sample_comm_sys_init(&vb_conf);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("%s: system init failed with %d!\n", __FUNCTION__, ret);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
ss_mpi_aenc_aac_init();
|
|
ss_mpi_adec_aac_init();
|
|
|
|
main_inner(index);
|
|
|
|
ss_mpi_aenc_aac_deinit();
|
|
ss_mpi_adec_aac_deinit();
|
|
|
|
sample_comm_sys_exit();
|
|
|
|
return ret;
|
|
}
|