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

/*
* 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;
}