/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2020. All rights reserved. * Description: ai sample * Author: audio * Create: 2019-09-17 */ #include #include #include #include #include #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; }