You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
318 lines
8.0 KiB
318 lines
8.0 KiB
/*
|
|
* Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2020. All rights reserved.
|
|
* Description: ai sample
|
|
* Author: audio
|
|
* Create: 2019-09-17
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <pthread.h>
|
|
|
|
#include "uapi_system.h"
|
|
#include "uapi_ai.h"
|
|
#include "uapi_sound.h"
|
|
#include "securec.h"
|
|
#include "adp_common_ext.h"
|
|
|
|
typedef struct {
|
|
td_char *sample;
|
|
td_char *size_limit;
|
|
td_char *out_stream;
|
|
td_char *port;
|
|
td_char *mode;
|
|
} input_arg;
|
|
|
|
typedef struct {
|
|
uapi_ai_port ai_port;
|
|
|
|
FILE *out_stream;
|
|
td_u32 size_limit;
|
|
|
|
td_bool stop;
|
|
pthread_t thread;
|
|
|
|
td_handle ai;
|
|
} sample_ai_ctx;
|
|
|
|
#define AI_THREAD_SLEEP_TIME (10 * 1000) /* 10ms */
|
|
#define INPUT_CMD_LENGTH 32
|
|
|
|
static td_u32 audio_frame_pcm_data_size(const uapi_audio_frame *frame)
|
|
{
|
|
if (frame->bit_depth == UAPI_AUDIO_BIT_DEPTH_16) {
|
|
return frame->pcm_samples * frame->channels * sizeof(td_s16);
|
|
} else {
|
|
return frame->pcm_samples * frame->channels * sizeof(td_s32);
|
|
}
|
|
}
|
|
|
|
static td_void *sample_ai_thread(td_void *args)
|
|
{
|
|
td_s32 ret;
|
|
uapi_audio_frame ai_frame;
|
|
td_u32 frame_size;
|
|
td_u32 total_counter = 0;
|
|
sample_ai_ctx *ctx = (sample_ai_ctx *)args;
|
|
|
|
while (ctx->stop == TD_FALSE) {
|
|
ret = uapi_ai_acquire_frame(ctx->ai, &ai_frame, 0);
|
|
if (ret != TD_SUCCESS) {
|
|
usleep(AI_THREAD_SLEEP_TIME);
|
|
continue;
|
|
}
|
|
|
|
frame_size = audio_frame_pcm_data_size(&ai_frame);
|
|
total_counter += frame_size;
|
|
|
|
if (total_counter <= ctx->size_limit) {
|
|
fwrite(ai_frame.pcm_buffer, 1, frame_size, ctx->out_stream);
|
|
}
|
|
|
|
ret = uapi_ai_release_frame(ctx->ai, &ai_frame);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("[%s] uapi_ai_release_frame failed 0x%x\n", __FUNCTION__, ret);
|
|
}
|
|
}
|
|
|
|
return TD_NULL;
|
|
}
|
|
|
|
static td_void sample_ctx_deinit(sample_ai_ctx *ctx)
|
|
{
|
|
if (ctx->out_stream != TD_NULL) {
|
|
(td_void)fclose(ctx->out_stream);
|
|
ctx->out_stream = TD_NULL;
|
|
}
|
|
}
|
|
|
|
static td_s32 sample_ctx_init(const input_arg *arg, sample_ai_ctx *ctx)
|
|
{
|
|
ctx->size_limit = (td_u32)strtol(arg->size_limit, TD_NULL, 0);
|
|
if ((ctx->size_limit <= 0) || (ctx->size_limit > 500)) { /* 500 max file size */
|
|
printf("file save length limit %u is not set or larger than 500MB\n",
|
|
ctx->size_limit);
|
|
return TD_FAILURE;
|
|
} else {
|
|
printf("file save length limit %u(MB)\n", ctx->size_limit);
|
|
}
|
|
|
|
ctx->size_limit = (ctx->size_limit << 20); /* 20: Mb to bytes */
|
|
|
|
ctx->out_stream = fopen(arg->out_stream, "wb");
|
|
if (ctx->out_stream == TD_NULL) {
|
|
printf("open file %s error!\n", arg->out_stream);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
ctx->ai = TD_INVALID_HANDLE;
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void sample_ai_deinit(sample_ai_ctx *ctx)
|
|
{
|
|
td_s32 ret;
|
|
|
|
ret = uapi_ai_set_enable(ctx->ai, TD_FALSE);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_ai_set_enable failed\n");
|
|
return;
|
|
}
|
|
|
|
ret = uapi_ai_destroy(ctx->ai);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_ai_destroy failed\n");
|
|
return;
|
|
}
|
|
|
|
ctx->ai = TD_INVALID_HANDLE;
|
|
|
|
ret = uapi_ai_deinit();
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_ai_deinit failed\n");
|
|
return;
|
|
}
|
|
|
|
ret = uapi_sys_deinit();
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_sys_deinit failed\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
static td_bool is_i2s_port(input_arg *arg)
|
|
{
|
|
if (strncmp(arg->port, "i2s0", strlen("i2s0")) == 0 || strncmp(arg->port, "i2s1", strlen("i2s1")) == 0 ||
|
|
strncmp(arg->port, "i2s2", strlen("i2s2")) == 0 || strncmp(arg->port, "i2s3", strlen("i2s3")) == 0 ||
|
|
strncmp(arg->port, "i2s4", strlen("i2s4")) == 0) {
|
|
return TD_TRUE;
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
static td_bool is_adc_port(input_arg *arg)
|
|
{
|
|
if (strncmp(arg->port, "adc0", strlen("adc0")) == 0) {
|
|
return TD_TRUE;
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
static td_s32 sample_ai_init(input_arg *arg, sample_ai_ctx *ctx)
|
|
{
|
|
td_s32 ret;
|
|
uapi_ai_attr ai_attr;
|
|
|
|
ret = uapi_sys_init();
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_sys_init failed(0x%x)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = uapi_ai_init();
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_ai_init failed(0x%x)\n", ret);
|
|
goto sys_deinit;
|
|
}
|
|
|
|
if (is_i2s_port(arg) == TD_TRUE) {
|
|
ctx->ai_port = (uapi_ai_port)strtol(arg->port + 3, TD_NULL, 0); /* 3: i2s strlen */
|
|
} else {
|
|
ctx->ai_port = UAPI_AI_PORT_ADC0;
|
|
}
|
|
ret = uapi_ai_get_default_attr(ctx->ai_port, &ai_attr);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_ai_get_default_attr failed\n");
|
|
goto ai_deinit;
|
|
}
|
|
|
|
if (is_i2s_port(arg) == TD_TRUE && strncmp(arg->mode, "pcm", strlen("pcm")) == 0) {
|
|
ai_attr.sample_rate = UAPI_AUDIO_SAMPLE_RATE_16K;
|
|
ai_attr.attr.i2s_attr.attr.i2s_mode = UAPI_AUDIO_I2S_PCM_MODE;
|
|
ai_attr.attr.i2s_attr.attr.channels = 1;
|
|
ai_attr.attr.i2s_attr.attr.bit_depth = UAPI_AUDIO_BIT_DEPTH_16;
|
|
ai_attr.attr.i2s_attr.attr.bclk_sel = UAPI_AUDIO_I2S_BCLK_8_DIV;
|
|
ai_attr.attr.i2s_attr.attr.master = 1;
|
|
ai_attr.attr.i2s_attr.attr.pcm_delay_cycle = 1;
|
|
}
|
|
|
|
ret = uapi_ai_create(ctx->ai_port, &ai_attr, &ctx->ai);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_ai_create failed\n");
|
|
goto ai_deinit;
|
|
}
|
|
|
|
ret = uapi_ai_set_enable(ctx->ai, TD_TRUE);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_ai_set_enable failed\n");
|
|
goto ai_destroy;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
ai_destroy:
|
|
(td_void)uapi_ai_destroy(ctx->ai);
|
|
ai_deinit:
|
|
(td_void)uapi_ai_deinit();
|
|
sys_deinit:
|
|
(td_void)uapi_sys_deinit();
|
|
return ret;
|
|
}
|
|
|
|
static td_void sample_ai_stop(sample_ai_ctx *ctx)
|
|
{
|
|
ctx->stop = TD_TRUE;
|
|
pthread_join(ctx->thread, TD_NULL);
|
|
}
|
|
|
|
static td_void sample_ai_start(sample_ai_ctx *ctx)
|
|
{
|
|
ctx->stop = TD_FALSE;
|
|
pthread_create(&ctx->thread, TD_NULL, sample_ai_thread, ctx);
|
|
}
|
|
|
|
static td_void usage(const input_arg *arg)
|
|
{
|
|
printf(" usage: %s size(MB) file(*.pcm) port i2s_mode\n", arg->sample);
|
|
printf(" examples: \n");
|
|
printf(" %s 100 /mnt/ai.pcm i2s3 pcm\n", arg->sample);
|
|
printf("port: i2s0/i2s1/i2s2/i2s3/adc0\n");
|
|
printf("i2s_mode: std/pcm/tdm\n");
|
|
}
|
|
|
|
static td_s32 sample_arg_check(input_arg *arg)
|
|
{
|
|
if (is_i2s_port(arg) != TD_TRUE && is_adc_port(arg) != TD_TRUE) {
|
|
printf("olny i2s and adc0 port\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (is_i2s_port(arg) == TD_TRUE && strncmp(arg->mode, "std", strlen("std")) != 0 &&
|
|
strncmp(arg->mode, "pcm", strlen("pcm")) != 0 && strncmp(arg->mode, "tdm", strlen("std")) != 0) {
|
|
printf("err i2s mode\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
td_s32 main(td_s32 argc, td_char *argv[])
|
|
{
|
|
td_s32 ret;
|
|
sample_ai_ctx ctx;
|
|
|
|
input_arg *arg = (input_arg *)argv;
|
|
td_char input_cmd[INPUT_CMD_LENGTH];
|
|
|
|
if (argc != sizeof(input_arg) / sizeof(td_char *)) {
|
|
usage(arg);
|
|
return -1;
|
|
}
|
|
|
|
ret = memset_s(&ctx, sizeof(ctx), 0, sizeof(sample_ai_ctx));
|
|
if (ret != EOK) {
|
|
printf("call memset_s failed(0x%x)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = sample_arg_check(arg);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("invalid input param failed(0x%x)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = sample_ctx_init(arg, &ctx);
|
|
if (ret != EOK) {
|
|
printf("call sample_ctx_init failed(0x%x)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = sample_ai_init(arg, &ctx);
|
|
if (ret != EOK) {
|
|
printf("call sample_ai_init failed(0x%x)\n", ret);
|
|
goto out;
|
|
}
|
|
|
|
sample_ai_start(&ctx);
|
|
|
|
while (1) {
|
|
printf("please input the q to quit!\n");
|
|
(td_void)fgets((char *)(input_cmd), (sizeof(input_cmd) - 1), stdin);
|
|
|
|
if (input_cmd[0] == 'q') {
|
|
printf("prepare to quit!\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
sample_ai_stop(&ctx);
|
|
sample_ai_deinit(&ctx);
|
|
|
|
out:
|
|
sample_ctx_deinit(&ctx);
|
|
return ret;
|
|
}
|