/* * Copyright (c) CompanyNameMagicTag 2019-2020. All rights reserved. * Description: ai sample * Author: audio * Create: 2019-09-17 */ #include #include #include #include #include "thread_os.h" #include "chip_type.h" #include "audio_type.h" #include "osal_list.h" #include "soc_uapi_adp.h" #include "soc_uapi_ai.h" #include "sample_audio_api.h" #include "sample_audio_utils.h" #include "sample_phone.h" #ifdef __cplusplus #if __cplusplus extern "C" { #endif #endif #define MIC0_TYPE "mic0" #define MIC1_TYPE "mic1" typedef enum { CHANNEL_L = 0x1, CHANNEL_R = 0x2, } channel_type; typedef struct { td_char *sample; td_char *size; td_char *file; } sample_ai_arg; typedef struct sample_ai_inst { athread_handle task; td_bool task_enable; td_bool mute; FILE *h_file; td_u32 file_size; td_u32 file_limit_size; td_handle h_adp; td_handle h_ai; td_handle h_player; td_u32 channel_type; uapi_ai_port ai_port; uapi_audio_pcm_format pcm_format; uapi_ai_gain volume; /* ao */ uapi_snd snd_id; uapi_snd_out_port ao_port; td_u32 (*save_frame)(struct sample_ai_inst *inst, const uapi_audio_frame *frame); data_info write_data; td_bool run_bt_loopback; td_void (*sample_ai_process)(struct sample_ai_inst *inst, const uapi_audio_frame *frame); struct osal_list_head node; } sample_ai_inst; static OSAL_LIST_HEAD(g_sample_ai_list); static inline td_bool ai_check_volume_adjust_support(uapi_ai_port ai_port) { if ((ai_port >= UAPI_AI_PORT_ADC0 && ai_port <= UAPI_AI_PORT_ADC3) || (ai_port >= UAPI_AI_PORT_LPADC0 && ai_port <= UAPI_AI_PORT_LPADC1) || (ai_port >= UAPI_AI_PORT_PDM0 && ai_port <= UAPI_AI_PORT_PDM3)) { return TD_TRUE; } return TD_FALSE; } static sample_ai_inst *sample_ai_alloc_inst(td_void) { sample_ai_inst *inst = (sample_ai_inst *)malloc(sizeof(sample_ai_inst)); if (inst == TD_NULL) { return TD_NULL; } (td_void)memset_s(inst, sizeof(*inst), 0, sizeof(sample_ai_inst)); osal_list_add_tail(&inst->node, &g_sample_ai_list); return inst; } static td_void sample_ai_free_inst(sample_ai_inst *inst) { if (inst == TD_NULL) { return; } osal_list_del(&inst->node); free(inst); } static sample_ai_inst *sample_ai_get_inst(td_void) { if (osal_list_empty(&g_sample_ai_list) != TD_FALSE) { return TD_NULL; } return osal_list_first_entry(&g_sample_ai_list, sample_ai_inst, node); } static td_bool run_bt_loopback = TD_FALSE; static td_s32 ai_event_proc(td_handle ai, uapi_ai_event_type event, const td_void *param, td_void *context) { sample_ai_inst *test_inst = (sample_ai_inst *)context; sap_err_log_h32(event); if (event == UAPI_AI_EVENT_VAD_VALID) { } else { } sap_unused(ai); sap_unused(param); sap_unused(test_inst); return EXT_SUCCESS; } static uapi_ai_port sample_ai_get_test_port(td_void) { #if (SAP_CHIP_TYPE == brandy) return UAPI_AI_PORT_ADC0; #elif (SAP_CHIP_TYPE == socmn1) return UAPI_AI_PORT_LPADC0; #else return UAPI_AI_PORT_I2S0; #endif /* SAP_CHIP_TYPE */ } static td_u32 save_frame_to_buf(sample_ai_inst *inst, const uapi_audio_frame *frame) { circ_buf *cb = &inst->write_data.cb; if (circ_buf_query_free(cb) <= frame->bits_bytes) { sap_printf("Warning: PCM data enough"); return 0; } return circ_buf_write(cb, (const td_u8 *)frame->bits_buffer, frame->bits_bytes); } static td_u32 save_frame_to_file(sample_ai_inst *inst, const uapi_audio_frame *frame) { td_u32 ret; if (inst->h_file == TD_NULL) { return 0; } ret = fwrite((td_void *)frame->bits_buffer, 1, frame->bits_bytes, inst->h_file); return ret; } static td_void sample_ai_save_frame(sample_ai_inst *inst, const uapi_audio_frame *frame) { inst->file_size += frame->bits_bytes; if (inst->file_size >= inst->file_limit_size) { return; } if (inst->save_frame(inst, frame) == 0) { inst->file_size = inst->file_limit_size; } } static td_void sample_ai_ao_parse_mic(const td_char *mic_name, sample_ai_inst *inst) { if (strcmp(MIC0_TYPE, mic_name) == 0) { inst->channel_type |= CHANNEL_L; } else if (strcmp(MIC1_TYPE, mic_name) == 0) { inst->channel_type |= CHANNEL_R; } } #if (SAP_CHIP_TYPE == socmn1) static td_void smaple_ai_ao_channel_sel(td_void *pcm, td_u32 samples, td_u32 channel_type) { td_u32 i; td_s16 *in = TD_NULL; if (pcm == NULL) { return; } in = (td_s16 *)pcm; for (i = 0; i < samples; i++) { if (channel_type == CHANNEL_L) { *in = 0; } else if (channel_type == CHANNEL_R) { *(in + 1) = 0; } in += 2; /* 2 is num */ } } #endif static td_void sample_ai_ao_process(sample_ai_inst *inst, const uapi_audio_frame *frame) { td_s32 ret; #if (SAP_CHIP_TYPE == socmn1) if (inst->channel_type == CHANNEL_L || inst->channel_type == CHANNEL_R) { smaple_ai_ao_channel_sel((td_void *)frame->bits_buffer, frame->pcm_samples, inst->channel_type); } #endif while (inst->task_enable) { ret = uapi_adp_send_frame(inst->h_player, frame); if (ret != EXT_SUCCESS) { sap_msleep(THREAD_SLEEP_10MS); /* */ continue; } break; } } static td_void sample_ai_thread(td_void *args) { td_s32 ret; uapi_audio_frame frame; sample_ai_inst *inst = (sample_ai_inst *)args; if (inst == TD_NULL) { sap_err_log_info("ai_inst is null"); return; } while (inst->task_enable) { ret = uapi_adp_acquire_frame(inst->h_adp, &frame); if (ret != EXT_SUCCESS) { sap_msleep(THREAD_SLEEP_10MS); continue; } if (inst->sample_ai_process != NULL) { inst->sample_ai_process(inst, &frame); } ret = uapi_adp_release_frame(inst->h_adp, &frame); if (ret != EXT_SUCCESS) { sap_err_log_fun(uapi_adp_release_frame, ret); } } athread_set_exit(inst->task, TD_TRUE); } static td_s32 sample_ai_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 out; } return EXT_SUCCESS; out: (td_void)uapi_adp_deinit(); return ret; } static td_void sample_ai_sys_deinit(td_void) { td_s32 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_close_adp(sample_ai_inst *inst) { if (inst->h_adp != 0) { uapi_adp_destroy(inst->h_adp); inst->h_adp = 0; } } static td_s32 sample_ai_open_adp(sample_ai_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_close_ai(sample_ai_inst *inst) { td_s32 ret; if (inst->h_ai == 0) { return; } /* Detach ADP instance from AI instance */ ret = uapi_ai_detach_output(inst->h_ai, inst->h_adp); 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_set_port_attr(const sample_ai_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: ai_attr->port_attr.pdm.rx_type = UAPI_AI_RX_DEFAULT; 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_LPADC0: case UAPI_AI_PORT_LPADC1: ai_attr->port_attr.adc.rx_type = UAPI_AI_RX_DEFAULT; break; case UAPI_AI_PORT_I2S0: case UAPI_AI_PORT_I2S1: case UAPI_AI_PORT_I2S2: get_i2s_attr(&ai_attr->port_attr.i2s.i2s_attr, (const uapi_audio_pcm_format *)&inst->pcm_format, TD_FALSE); break; default: break; } } static td_s32 sample_ai_open_ai(sample_ai_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_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; } /* Register AI event process callback */ ret = uapi_ai_register_event_proc(inst->h_ai, ai_event_proc, (td_void *)inst); if (ret != EXT_SUCCESS) { sap_err_log_fun(uapi_ai_register_event_proc, ret); goto out; } if (ai_check_volume_adjust_support(inst->ai_port) == TD_TRUE) { 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; } } /* Attach ADP instance to AI instance */ ret = uapi_ai_attach_output(inst->h_ai, inst->h_adp); 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_close_file(sample_ai_inst *inst) { if (inst->h_file != TD_NULL) { fclose(inst->h_file); inst->h_file = TD_NULL; } } static td_s32 sample_ai_open_file(sample_ai_inst *inst, const td_char *file) { if (file == TD_NULL || strcmp("null", file) == 0) { inst->h_file = TD_NULL; data_info_init(&inst->write_data, FPGA_SAVE_DATA_ADDR, FPGA_SAVE_DATA_SIZE); inst->save_frame = save_frame_to_buf; } else { td_s32 ret; td_char file_path[FILE_PATH_LEN]; ret = snprintf_s(file_path, FILE_PATH_LEN - 1, FILE_PATH_LEN - 1, "%s_%uk_%ubit_%uch.pcm", file, inst->pcm_format.sample_rate / 1000, /* 1000 Hz to kHz */ inst->pcm_format.bit_depth, inst->pcm_format.channels); if (ret < 0) { sap_err_log_fun(snprintf_s, ret); return EXT_FAILURE; } inst->h_file = fopen(file_path, "wb"); if (inst->h_file == TD_NULL) { sap_printf("open %s failed", file_path); return EXT_FAILURE; } inst->save_frame = save_frame_to_file; } return EXT_SUCCESS; } static td_void sample_ai_inst_deinit(sample_ai_inst *inst) { sample_ai_close_file(inst); } static td_s32 sample_ai_inst_init(const sample_ai_arg *arg, sample_ai_inst *inst) { td_s32 ret; td_u32 size; inst->ai_port = sample_ai_get_test_port(); size = (td_u32)strtoul(arg->size, TD_NULL, 0); if (size == 0 || size > 100) { /* 100 max file size */ sap_err_log_ret(size); return EXT_FAILURE; } inst->file_limit_size = (size << 20); /* 20: bytes to MB */ 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; ret = sample_ai_open_file(inst, arg->file); if (ret != EXT_SUCCESS) { sap_err_log_fun(sample_ai_open_file, ret); return ret; } return EXT_SUCCESS; } static td_void sample_ai_close_inst(sample_ai_inst *inst) { sample_ai_close_ai(inst); sample_ai_close_adp(inst); sample_ai_sys_deinit(); } static td_s32 sample_ai_open_inst(sample_ai_inst *inst) { td_s32 ret; ret = sample_ai_sys_init(); if (ret != EXT_SUCCESS) { sap_err_log_fun(sample_ai_sys_init, ret); return ret; } /* * 数据流向 ai --> adp * 按照数据流向反方向打开实例 * 按照数据方向attach output */ ret = sample_ai_open_adp(inst); if (ret != EXT_SUCCESS) { sap_err_log_fun(sample_ai_open_adp, ret); goto out0; } ret = sample_ai_open_ai(inst); if (ret != EXT_SUCCESS) { sap_err_log_fun(sample_ai_open_ai, ret); goto out1; } return EXT_SUCCESS; out1: sample_ai_close_adp(inst); out0: sample_ai_sys_deinit(); return ret; } static td_void sample_ai_stop_inst(sample_ai_inst *inst) { td_s32 ret; if (inst->task != TD_NULL) { /* Destory Task to stop ADP instance reading pcm data */ inst->task_enable = TD_FALSE; athread_exit(inst->task); inst->task = TD_NULL; } /* Stop AI instance output pcm data */ ret = uapi_ai_stop(inst->h_ai); if (ret != EXT_SUCCESS) { sap_err_log_fun(uapi_ai_stop, ret); } } static td_s32 sample_ai_start_inst(sample_ai_inst *inst) { td_s32 ret; athread_attr attr; /* Start AI instance to write data into ADP instance */ ret = uapi_ai_start(inst->h_ai); if (ret != EXT_SUCCESS) { sap_err_log_fun(uapi_ai_start, ret); return ret; } inst->sample_ai_process = sample_ai_save_frame; inst->task_enable = TD_TRUE; attr.priority = ATHREAD_PRIORITY_NORMAL; attr.stack_size = 0x1000; /* 4k */ attr.name = "sample_ai"; ret = athread_create(&inst->task, sample_ai_thread, (td_void *)inst, &attr); if (ret != EXT_SUCCESS) { sap_err_log_fun(athread_create, ret); goto out; } return EXT_SUCCESS; out: (td_void)uapi_ai_stop(inst->h_ai); return ret; } static td_void sample_ai_usage(const td_char *name) { sap_printf(" usage: %s size(MB) file(*.pcm)\n", name); sap_printf(" examples:\n"); sap_printf(" %s 100 /mnt/ai.pcm\n", name); sap_printf(" %s 100 null\n", name); } static td_s32 sample_ai_entry(td_s32 argc, td_char *argv[]) { td_s32 ret; sample_ai_arg *arg = (sample_ai_arg *)argv; sample_ai_inst *inst = sample_ai_get_inst(); if (inst != TD_NULL) { sap_printf("%s is already running\n", argv[0]); return EXT_FAILURE; } inst = sample_ai_alloc_inst(); if (inst == TD_NULL) { sap_printf("sample_ai_alloc_inst failed\n"); return EXT_FAILURE; } ret = sample_ai_inst_init(arg, inst); if (ret != EXT_SUCCESS) { sap_err_log_fun(sample_ai_inst_init, ret); goto out0; } ret = sample_ai_open_inst(inst); if (ret != EXT_SUCCESS) { sap_err_log_fun(sample_ai_open_inst, ret); goto out1; } ret = sample_ai_start_inst(inst); if (ret != EXT_SUCCESS) { sap_err_log_fun(sample_ai_start_inst, ret); goto out2; } sap_printf("sample_rate: %u, channels: %u, bit_depth: %u", inst->pcm_format.sample_rate, inst->pcm_format.channels, inst->pcm_format.bit_depth); return EXT_SUCCESS; out2: sample_ai_close_inst(inst); out1: sample_ai_inst_deinit(inst); out0: sample_ai_free_inst(inst); audio_unused(argc); return ret; } static td_s32 sample_ai_exit(td_void) { sample_ai_inst *inst = sample_ai_get_inst(); if (inst != NULL) { sample_ai_stop_inst(inst); sample_ai_close_inst(inst); sample_ai_inst_deinit(inst); sample_ai_free_inst(inst); } return EXT_SUCCESS; } td_s32 sample_ai(td_s32 argc, td_char *argv[]) { if (argc <= 1) { sample_ai_usage(argv[0]); return EXT_SUCCESS; } if (strcmp(argv[1], "q") == 0) { return sample_ai_exit(); } else { return sample_ai_entry(argc, argv); } } static td_void sample_ai_ao_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/lpadc0)\n" " -c channels of ai port(default: 2)\n" " -b bit_depth of ai port(default: 16)\n" " -s samplerate of ai port(default: 48000)\n" " -v volume of ai port(default: 0)\n" " -m mute ai port(default: false)\n" " -l specify a long parameter(bt_loopback/mic0/mic1)\n" "\n"); sap_printf(" examples:\n"); sap_printf(" %s -p mad0 -c 1 -s 16000\n", name); sap_printf(" %s -p mad0 -c 2 -s 48000\n", name); sap_printf(" %s -p i2s1\n", name); sap_printf(" %s -p i2s1 -c 1\n", name); sap_printf(" %s -p adc0 -c 2 -s 48000 -v 30\n", name); sap_printf("\n"); } static td_void sample_ai_ao_parse_port(const td_char *port_name, sample_ai_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}, {"i2s0", UAPI_AI_PORT_I2S0}, {"i2s1", UAPI_AI_PORT_I2S1}, {"i2s2", UAPI_AI_PORT_I2S2}, {"i2s3", UAPI_AI_PORT_I2S3}, {"adc0", UAPI_AI_PORT_ADC0}, {"adc1", UAPI_AI_PORT_ADC1}, {"lpadc0", UAPI_AI_PORT_LPADC0}, {"lpadc1", UAPI_AI_PORT_LPADC1}, }; 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; } } inst->ai_port = sample_ai_get_test_port(); } static td_void sample_ai_ao_parse_snd_port(const td_char *port_name, sample_ai_inst *inst) { td_u32 i; const struct { const td_char *name; uapi_snd_out_port ao_port; } ao_port_name[] = { {"dac0", UAPI_SND_OUT_PORT_DAC0}, {"i2s0", UAPI_SND_OUT_PORT_I2S0}, {"i2s1", UAPI_SND_OUT_PORT_I2S1}, {"i2s2", UAPI_SND_OUT_PORT_I2S2}, }; for (i = 0; i < sizeof(ao_port_name) / sizeof(ao_port_name[0]); i++) { if (strcmp(ao_port_name[i].name, port_name) == 0) { inst->ao_port = ao_port_name[i].ao_port; return; } } inst->ao_port = SND_OUT_PORT_DEFAULT; } static td_void sample_ai_ao_parse_snd_id(const td_char *snd_name, sample_ai_inst *inst) { td_u32 i; const struct { const td_char *name; uapi_snd snd_id; } ao_snd_name[] = { {"snd0", UAPI_SND_0}, {"snd1", UAPI_SND_1}, {"snd2", UAPI_SND_2}, }; for (i = 0; i < sizeof(ao_snd_name) / sizeof(ao_snd_name[0]); i++) { if (strcmp(ao_snd_name[i].name, snd_name) == 0) { inst->snd_id = ao_snd_name[i].snd_id; return; } } inst->snd_id = UAPI_SND_0; } static td_void sample_ai_ao_parse_long_opt(td_char opt, const td_char *opt_arg, sample_ai_inst *inst) { if (opt_arg == TD_NULL) { sap_printf("invalid option -- '%c'\n", opt); return; } if (strcmp(opt_arg, "bt_loopback") == 0) { inst->run_bt_loopback = TD_TRUE; return; } sample_ai_ao_parse_mic(opt_arg, inst); } static td_s32 sample_ai_ao_parse_opt(td_char opt, const td_char *opt_arg, sample_ai_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_ao_parse_port(opt_arg, inst); break; case 'o': sample_ai_ao_parse_snd_port(opt_arg, inst); break; case 'd': sample_ai_ao_parse_snd_id(opt_arg, inst); break; case 'v': inst->volume.integer = (td_s32)strtol(opt_arg, TD_NULL, 0); break; case 'm': inst->mute = TD_TRUE; break; case 'l': sample_ai_ao_parse_long_opt(opt, opt_arg, inst); break; default: sap_printf("invalid command line\n"); return EXT_FAILURE; } return EXT_SUCCESS; } static td_s32 sample_ai_ao_parse_cmd_line(td_s32 argc, td_char *argv[], sample_ai_inst *inst) { td_s32 ret; td_char opt; parg_state ps; if (argv == TD_NULL) { return EXT_FAILURE; } parg_init(&ps); while (1) { ret = parg_getopt(&ps, argc, argv, "s:c:b:p:v:o:d:hml:"); if (ret == -1) { break; } opt = (td_char)ret; if (sample_ai_ao_parse_opt(opt, ps.optarg, inst) != EXT_SUCCESS) { sample_ai_ao_usage(argv[0]); return EXT_FAILURE; } } inst->pcm_format.sample_per_frame = inst->pcm_format.sample_rate / 100; /* 100 --> 10ms */ return EXT_SUCCESS; } static td_s32 sample_ai_ao_start_inst(sample_ai_inst *inst) { td_s32 ret; athread_attr attr; /* Start AI instance to write data into ADP instance */ ret = uapi_ai_start(inst->h_ai); if (ret != EXT_SUCCESS) { sap_err_log_fun(uapi_ai_start, ret); return ret; } /* Create task for ADP instance to read pcm data */ inst->task_enable = TD_TRUE; inst->sample_ai_process = sample_ai_ao_process; if (inst->run_bt_loopback != TD_TRUE) { attr.priority = ATHREAD_PRIORITY_NORMAL; attr.stack_size = 0x1000; /* 4k */ attr.name = "sample_ai_ao"; ret = athread_create(&inst->task, sample_ai_thread, (td_void *)inst, &attr); if (ret != EXT_SUCCESS) { sap_err_log_fun(athread_create, ret); goto out; } } else { adp_handle_share_set(inst->h_adp, inst->h_player, 0); sap_printf("[audio] ul handle = x%x, dl handle = x%x\n", inst->h_adp, inst->h_player); } return EXT_SUCCESS; out: (td_void)uapi_ai_stop(inst->h_ai); return ret; } static td_void sample_ai_ao_inst_init(sample_ai_inst *inst) { inst->ai_port = sample_ai_get_test_port(); inst->snd_id = UAPI_SND_0; inst->ao_port = SND_OUT_PORT_DEFAULT; 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->run_bt_loopback = TD_FALSE; #if (SAP_CHIP_TYPE == socmn1) inst->channel_type = 0x0; #endif } static td_s32 sample_ai_player_open(sample_ai_inst *inst) { td_s32 ret; td_handle h_snd; sample_acodec_arg in_arg; const uapi_snd_attr snd_attr = { .port_num = 1, .port_attr[0].out_port = inst->ao_port, .channels = SND_OUT_CHANNEL_DEF, .bit_depth = SND_OUT_BIT_DEPTH_DEF, .sample_rate = SND_OUT_SAMPLE_RATE_DEF, }; sample_escast_arg escast_arg = { .player = &inst->h_player, .in_arg = &in_arg, .snd = &h_snd, .snd_attr = &snd_attr, .aef_profile = UAPI_SND_AEF_PROFILE_NONE, }; /* set track input pcm format matching ai output pcm format */ ret = memcpy_s(&in_arg.pcm_format, sizeof(in_arg.pcm_format), &inst->pcm_format, sizeof(inst->pcm_format)); if (ret != EOK) { sap_err_log_fun(memcpy_s, ret); return ret; } return sample_ao_player_open(&escast_arg, inst->snd_id); } static td_s32 sample_ai_ao_entry(td_s32 argc, td_char *argv[]) { td_s32 ret; sample_ai_inst *inst = TD_NULL; inst = sample_ai_alloc_inst(); if (inst == TD_NULL) { sap_err_log_info("sample_ai_ao_alloc_inst failed"); return EXT_FAILURE; } sample_ai_ao_inst_init(inst); ret = sample_ai_ao_parse_cmd_line(argc, argv, inst); if (ret != EXT_SUCCESS) { goto out0; } ret = sample_ai_player_open(inst); if (ret != EXT_SUCCESS) { sap_err_log_fun(sample_ao_player_open, ret); goto out0; } ret = sample_ai_open_inst(inst); if (ret != EXT_SUCCESS) { sap_err_log_fun(sample_ai_open_inst, ret); goto out1; } ret = sample_ai_ao_start_inst(inst); if (ret != EXT_SUCCESS) { sap_err_log_fun(sample_ai_start_inst, ret); goto out2; } sap_alert_log_u32(inst->pcm_format.sample_rate); sap_alert_log_u32(inst->pcm_format.channels); sap_alert_log_u32(inst->pcm_format.bit_depth); return EXT_SUCCESS; out2: sample_ai_close_inst(inst); out1: sample_ao_player_close(); out0: sample_ai_free_inst(inst); return ret; } static td_s32 sample_ai_ao_exit(td_void) { sample_ai_inst *inst = sample_ai_get_inst(); if (inst != NULL) { sample_ai_stop_inst(inst); sample_ai_close_inst(inst); sample_ao_player_close(); sample_ai_free_inst(inst); } return EXT_SUCCESS; } td_s32 sample_ai_ao(td_s32 argc, td_char *argv[]) { if (argc <= 1) { sample_ai_ao_usage(argv[0]); return EXT_FAILURE; } if (strcmp(argv[1], "q") == 0) { return sample_ai_ao_exit(); } else { return sample_ai_ao_entry(argc, argv); } } #ifdef __cplusplus #if __cplusplus } #endif #endif