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.

334 lines
8.5 KiB

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