/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2019. All rights reserved. * Description: mix engine sample * Author: audio * Create: 2019-09-17 */ #include #include #include #include #include "uapi_sound.h" #include "uapi_system.h" #include "securec.h" #include "adp_common_ext.h" #define FRAME_TIME 5 /* 5ms */ #define THREAD_SLEEP_TIME (FRAME_TIME * 1000) /* 1000 s to ms */ #define INPUT_CMD_LENGTH 32 typedef struct { td_char *sample; td_char *in_stream; td_char *sample_rate; td_char *channels; } sample_dma_input_arg; typedef struct { uapi_snd snd; td_char *file_name; FILE *in_stream; td_u32 sample_rate; td_u32 channels; td_u32 pcm_samples; td_u32 frame_size; td_bool stop; pthread_t thread; } sample_dma_ctx; static td_s32 sample_dma_snd_init(sample_dma_ctx *dma_ctx) { td_s32 ret; uapi_snd_attr snd_attr; ret = uapi_snd_init(); if (ret != TD_SUCCESS) { printf("call uapi_snd_init failed(0x%x)\n", ret); return ret; } ret = uapi_snd_get_default_open_attr(dma_ctx->snd, &snd_attr); if (ret != TD_SUCCESS) { printf("call uapi_snd_get_default_open_attr failed(0x%x)\n", ret); return ret; } ret = uapi_snd_open(dma_ctx->snd, &snd_attr); if (ret != TD_SUCCESS) { printf("call uapi_snd_open failed(0x%x)\n", ret); (td_void)uapi_snd_deinit(); return ret; } return TD_SUCCESS; } static td_void sample_dma_snd_deinit(sample_dma_ctx *dma_ctx) { td_s32 ret; ret = uapi_snd_close(dma_ctx->snd); if (ret != TD_SUCCESS) { printf("call uapi_snd_close failed(0x%x).\n", ret); return; } ret = uapi_snd_deinit(); if (ret != TD_SUCCESS) { printf("call uapi_snd_deinit failed(0x%x)\n", ret); return; } } static td_void sample_dma_audio_frame_init(const sample_dma_ctx *dma_ctx, uapi_audio_frame *frame) { td_s32 ret; ret = memset_s(frame, sizeof(*frame), 0, sizeof(uapi_audio_frame)); if (ret != EOK) { printf("call memset_s failed(0x%x).\n", ret); return; } frame->pts = TD_INVALID_PTS; frame->bit_depth = UAPI_AUDIO_BIT_DEPTH_16; frame->interleaved = TD_TRUE; frame->channels = dma_ctx->channels; frame->sample_rate = dma_ctx->sample_rate; frame->pcm_samples = dma_ctx->pcm_samples; } static td_void *sample_dma_play_thread(td_void *arg) { td_s32 ret; td_void *pcm_buf = TD_NULL; sample_dma_ctx *dma_ctx = (sample_dma_ctx *)arg; uapi_audio_frame ao_frame; td_bool send_pending = TD_FALSE; td_u32 read_len; if (dma_ctx->frame_size > (UAPI_AUDIO_SAMPLE_RATE_192K * UAPI_AUDIO_CHANNEL_16 * sizeof(td_s32))) { return TD_NULL; } pcm_buf = (td_void *)malloc(dma_ctx->frame_size); if (pcm_buf == TD_NULL) { printf("malloc pcm buffer failed!\n"); return TD_NULL; } sample_dma_audio_frame_init(dma_ctx, &ao_frame); ao_frame.pcm_buffer = (td_s32 *)(pcm_buf); while (dma_ctx->stop != TD_TRUE) { if (send_pending == TD_FALSE) { read_len = (td_u32)fread(pcm_buf, 1, dma_ctx->frame_size, dma_ctx->in_stream); if (read_len != dma_ctx->frame_size) { printf("rewind file: %s\n", dma_ctx->file_name); rewind(dma_ctx->in_stream); continue; } } ret = uapi_snd_send_dma_frame(dma_ctx->snd, &ao_frame, 30); /* keep delay to 30ms */ if (ret == TD_SUCCESS) { send_pending = TD_FALSE; continue; } else if (ret == TD_FAILURE) { printf("uapi_snd_send_dma_frame failed(0x%x)!\n", ret); break; } else { usleep(THREAD_SLEEP_TIME); send_pending = TD_TRUE; continue; } } free(pcm_buf); return TD_NULL; } static td_void sample_dma_stop(sample_dma_ctx *dma_ctx) { td_s32 ret; dma_ctx->stop = TD_TRUE; pthread_join(dma_ctx->thread, TD_NULL); ret = uapi_snd_set_dma_mode_enable(dma_ctx->snd, TD_FALSE); if (ret != TD_SUCCESS) { printf("call uapi_snd_set_dma_mode_enable failed(0x%x)\n", ret); return; } } static td_s32 sample_dma_start(sample_dma_ctx *dma_ctx) { td_s32 ret; ret = uapi_snd_set_dma_mode_enable(dma_ctx->snd, TD_TRUE); if (ret != TD_SUCCESS) { printf("call uapi_snd_set_dma_mode_enable failed(0x%x)\n", ret); return ret; } dma_ctx->stop = TD_FALSE; pthread_create(&dma_ctx->thread, TD_NULL, sample_dma_play_thread, dma_ctx); return TD_SUCCESS; } static const struct { td_s32 (*init)(sample_dma_ctx *dma_ctx); td_void (*deinit)(sample_dma_ctx *dma_ctx); } g_sample_dma_module[] = { {sample_dma_snd_init, sample_dma_snd_deinit}, {sample_dma_start, sample_dma_stop}, }; static td_void sample_dma_deinit(sample_dma_ctx *dma_ctx) { td_s32 ret; td_s32 module; const td_s32 num = sizeof(g_sample_dma_module) / sizeof(g_sample_dma_module[0]); for (module = num - 1; module >= 0; module--) { g_sample_dma_module[module].deinit(dma_ctx); } ret = uapi_sys_deinit(); if (ret != TD_SUCCESS) { printf("call uapi_sys_deinit failed(0x%x)\n", ret); return; } } static td_s32 sample_dma_init(sample_dma_ctx *dma_ctx) { td_s32 ret; td_s32 module; const td_s32 num = sizeof(g_sample_dma_module) / sizeof(g_sample_dma_module[0]); ret = uapi_sys_init(); if (ret != TD_SUCCESS) { printf("call uapi_sys_init failed(0x%x)\n", ret); return ret; } for (module = 0; module < num; module++) { ret = g_sample_dma_module[module].init(dma_ctx); if (ret != TD_SUCCESS) { printf("call init failed(0x%x)\n", ret); goto out; } } return TD_SUCCESS; out: module--; for (; module >= 0; module--) { g_sample_dma_module[module].deinit(dma_ctx); } return ret; } static td_void sample_dma_ctx_deinit(sample_dma_ctx *dma_ctx) { if (dma_ctx->in_stream == TD_NULL) { return; } (td_void)fclose(dma_ctx->in_stream); dma_ctx->in_stream = TD_NULL; dma_ctx->file_name = TD_NULL; } static td_void sample_dma_usage(const sample_dma_input_arg *arg) { printf("sample_dma_usage: %s " "file0 sample_rate channels\n", arg->sample); printf("examples:\n"); printf("%s file0 48000 2\n", arg->sample); } static td_s32 sample_dma_ctx_init(td_s32 argc, td_char *argv[], sample_dma_ctx *dma_ctx) { sample_dma_input_arg *arg = (sample_dma_input_arg *)argv; if (argc != sizeof(sample_dma_input_arg) / sizeof(td_char *)) { sample_dma_usage(arg); return TD_FAILURE; } dma_ctx->file_name = arg->in_stream; dma_ctx->in_stream = fopen(arg->in_stream, "rb"); if (dma_ctx->in_stream == TD_NULL) { printf("open file %s failed\n", arg->in_stream); return TD_FAILURE; } dma_ctx->sample_rate = (td_u32)strtol(arg->sample_rate, NULL, 10); /* 10 is Dec */ dma_ctx->channels = (td_u32)strtol(arg->channels, NULL, 10); /* 10 is Dec */ if ((dma_ctx->sample_rate > UAPI_AUDIO_SAMPLE_RATE_192K) || (dma_ctx->channels > UAPI_AUDIO_CHANNEL_16)) { printf("invalid samplerate(%d) or channel(%d).\n", dma_ctx->sample_rate, dma_ctx->channels); goto out; } dma_ctx->pcm_samples = dma_ctx->sample_rate * FRAME_TIME / 1000; /* 1000 s to ms */ dma_ctx->frame_size = dma_ctx->pcm_samples * dma_ctx->channels * sizeof(td_s16); return TD_SUCCESS; out: sample_dma_ctx_deinit(dma_ctx); return TD_FAILURE; } td_s32 main(int argc, char *argv[]) { td_s32 ret; sample_dma_ctx dma_ctx; td_char input_cmd[INPUT_CMD_LENGTH]; ret = memset_s(&dma_ctx, sizeof(dma_ctx), 0, sizeof(sample_dma_ctx)); if (ret != EOK) { printf("call memset_s failed(0x%x)\n", ret); return ret; } dma_ctx.snd = UAPI_SND_0; ret = sample_dma_ctx_init(argc, argv, &dma_ctx); if (ret != TD_SUCCESS) { printf("call sample_dma_ctx_init failed(0x%x)\n", ret); return ret; } ret = sample_dma_init(&dma_ctx); if (ret != TD_SUCCESS) { printf("call sample_dma_init failed(0x%x)\n", ret); goto out; } while (1) { printf("please input the q to quit!\n"); (td_void)fgets((char *)(input_cmd), (INPUT_CMD_LENGTH - 1), stdin); if (input_cmd[0] == 'q') { printf("prepare to quit!\n"); break; } } sample_dma_deinit(&dma_ctx); out: sample_dma_ctx_deinit(&dma_ctx); return ret; }