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.
776 lines
24 KiB
776 lines
24 KiB
/*
|
|
* Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2019. All rights reserved.
|
|
* Description: mixer plugin sample
|
|
* Author: audio
|
|
* Create: 2019-09-17
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <pthread.h>
|
|
#include <sys/mman.h>
|
|
|
|
#include "uapi_sound.h"
|
|
#include "uapi_system.h"
|
|
#include "securec.h"
|
|
#include "uapi_amp.h"
|
|
|
|
#define DEBUG_FILE 0
|
|
#define DEBUG_PRINT 0
|
|
#define DEBUG_TIME 0
|
|
#define INPUT_CMD_LENGTH 32
|
|
#define MIXER_FRAME_TIME 10 /* 10ms */
|
|
#define PLAY_THREAD_SLEEP_TIME (MIXER_FRAME_TIME * 1000) /* 1000 s to ms */
|
|
#define DELAY_1_MS 1000
|
|
#define DELAY_2_MS 2000
|
|
#define DELAY_5_MS 5000
|
|
#define FRONTOUT_DEFAULT_MAX_CHANNEL 6
|
|
|
|
typedef struct {
|
|
td_char *sample;
|
|
td_char *playback_file;
|
|
td_char *plugin_file;
|
|
} input_arg;
|
|
|
|
typedef struct {
|
|
td_u8 *virt_addr;
|
|
td_u32 size; /* buffer size */ /* CNcomment: buffer长度 */
|
|
td_u32 valid_size;
|
|
td_u32 offset;
|
|
td_s32 fd;
|
|
} audio_buffer;
|
|
|
|
typedef struct {
|
|
uapi_snd snd;
|
|
td_handle track;
|
|
|
|
td_char *playback_file_name;
|
|
FILE *playback_stream;
|
|
|
|
td_char *plugin_file_name;
|
|
FILE *plugin_stream;
|
|
FILE *dbg_read;
|
|
|
|
td_u32 volume;
|
|
td_u32 sample_rate;
|
|
td_u32 channels;
|
|
td_u32 pcm_samples;
|
|
td_u32 frame_size;
|
|
|
|
td_bool playback_enable;
|
|
td_bool playback_stop;
|
|
pthread_t playback_thread;
|
|
|
|
td_u32 frontout_max_ch;
|
|
td_u32 frontout_frame_size;
|
|
td_u32 frontout_pcm_samples;
|
|
td_u32 backin_frame_size;
|
|
|
|
td_bool plugin_stop;
|
|
pthread_t mixer_frontout_thread;
|
|
pthread_t mixer_backin_thread;
|
|
} sample_ctx;
|
|
|
|
typedef struct {
|
|
const td_char *cmd;
|
|
td_s32 (*action)(sample_ctx *mixerplugin_ctx);
|
|
} eng_cmd_map;
|
|
|
|
static td_s32 snd_init(sample_ctx *mixerplugin_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(mixerplugin_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(mixerplugin_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;
|
|
}
|
|
ret = uapi_snd_set_geq_enable(mixerplugin_ctx->snd, TD_TRUE);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_snd_set_geq_enable failed(0x%x)\n", ret);
|
|
}
|
|
ret = uapi_amp_open();
|
|
if (ret != TD_SUCCESS) {
|
|
printf("uapi_amp_open failed(0x%x)\n", ret);
|
|
}
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void snd_deinit(sample_ctx *mixerplugin_ctx)
|
|
{
|
|
td_s32 ret;
|
|
|
|
ret = uapi_snd_close(mixerplugin_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;
|
|
}
|
|
|
|
ret = uapi_amp_close();
|
|
if (ret != TD_SUCCESS) {
|
|
printf("uapi_amp_close failed(0x%x)\n", ret);
|
|
}
|
|
}
|
|
|
|
static td_void audio_frame_init(const sample_ctx *mixerplugin_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 = mixerplugin_ctx->channels;
|
|
frame->sample_rate = mixerplugin_ctx->sample_rate;
|
|
frame->pcm_samples = mixerplugin_ctx->pcm_samples;
|
|
}
|
|
|
|
static td_void audio_munmap(td_u8 *buf, td_u32 size)
|
|
{
|
|
td_s32 ret;
|
|
if (buf == TD_NULL) {
|
|
return;
|
|
}
|
|
ret = munmap((td_void *)buf, size);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_err_print_call_fun_err(munmap, ret);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static td_void *audio_mmap(td_s32 fd, td_u32 size, td_u64 phys_addr)
|
|
{
|
|
td_void *buf = TD_NULL;
|
|
if (fd < 0) {
|
|
return TD_NULL;
|
|
}
|
|
buf = (td_void *)mmap64((td_void *)0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (td_slong)phys_addr);
|
|
if (buf == MAP_FAILED) {
|
|
soc_log_err("mmap failed, fd = %d, size = %d\n", fd, size);
|
|
return TD_NULL;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
static td_void audio_munmap_ion(td_u8 *buf, td_u32 size)
|
|
{
|
|
audio_munmap(buf, size);
|
|
}
|
|
|
|
static td_s32 buf_mmap(audio_buffer *map_buf)
|
|
{
|
|
map_buf->virt_addr = audio_mmap(map_buf->fd, map_buf->size, 0);
|
|
if (map_buf->virt_addr == TD_NULL) {
|
|
printf("mmap %d %u\n", map_buf->fd, map_buf->size);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void buf_munmap(audio_buffer *map_buf)
|
|
{
|
|
audio_munmap_ion(map_buf->virt_addr, map_buf->size);
|
|
map_buf->fd = -1;
|
|
map_buf->virt_addr = TD_NULL;
|
|
}
|
|
|
|
static td_void dbg_print_data(audio_buffer *acquire_buf, td_u8 *read_buf)
|
|
{
|
|
#if DEBUG_PRINT
|
|
int i;
|
|
for (i = 0; i < acquire_buf->size; i++) {
|
|
printf("%x ", *(read_buf + i));
|
|
}
|
|
printf("\n");
|
|
#endif
|
|
TD_UNUSED(acquire_buf);
|
|
TD_UNUSED(read_buf);
|
|
}
|
|
|
|
static td_void dbg_write_data_to_file(sample_ctx *mixerplugin_ctx, audio_buffer *acquire_buf, td_u8 *read_buf)
|
|
{
|
|
TD_UNUSED(mixerplugin_ctx);
|
|
TD_UNUSED(acquire_buf);
|
|
TD_UNUSED(read_buf);
|
|
#if DEBUG_FILE
|
|
(td_void)fwrite(read_buf, 1, acquire_buf->valid_size, mixerplugin_ctx->dbg_read);
|
|
#endif
|
|
}
|
|
|
|
static td_s32 acquire_data(sample_ctx *mixerplugin_ctx, uapi_audio_mixer_plugin_frame *in_frame, td_u32 require_size,
|
|
audio_buffer *acquire_buf, td_u8 *read_buf)
|
|
{
|
|
td_s32 ret;
|
|
uapi_snd snd = mixerplugin_ctx->snd;
|
|
ret = uapi_snd_acquire_mixer_plugin_frontout_stream(snd, require_size, in_frame, 12); /* 12ms cover 512 samples */
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_snd_acquire_mixer_plugin_frontout_stream failed %x\n", ret);
|
|
}
|
|
if (in_frame->frame_addr.frame_size == 0) {
|
|
usleep(DELAY_1_MS);
|
|
return -1;
|
|
}
|
|
#if DEBUG_PRINT
|
|
printf("out fd %d %llu %d c %d\n", (td_u32)in_frame->frame_addr.start_addr.mem_handle,
|
|
in_frame->frame_addr.start_addr.addr_offset, in_frame->frame_addr.frame_size, in_frame->frame_info.channels);
|
|
#endif
|
|
acquire_buf->fd = (td_s32)in_frame->frame_addr.start_addr.mem_handle;
|
|
acquire_buf->size = (td_u32)in_frame->frame_addr.start_addr.addr_offset + in_frame->frame_addr.frame_size;
|
|
acquire_buf->valid_size = in_frame->frame_addr.frame_size;
|
|
acquire_buf->offset = (td_u32)in_frame->frame_addr.start_addr.addr_offset;
|
|
ret = buf_mmap(acquire_buf);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call buf_mmap failed %x\n", ret);
|
|
}
|
|
|
|
if (acquire_buf->valid_size > mixerplugin_ctx->frontout_frame_size) {
|
|
printf("size is error %u\n", acquire_buf->valid_size);
|
|
}
|
|
ret = memcpy_s(read_buf, mixerplugin_ctx->frontout_frame_size, acquire_buf->virt_addr + acquire_buf->offset,
|
|
acquire_buf->valid_size);
|
|
if (ret != EOK) {
|
|
printf("call memcpy_s failed %x\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = uapi_snd_release_mixer_plugin_frontout_stream(snd, in_frame);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_snd_release_mixer_plugin_frontout_stream failed %x\n", ret);
|
|
}
|
|
|
|
buf_munmap(acquire_buf);
|
|
return 0;
|
|
}
|
|
|
|
static td_s32 send_data(const sample_ctx *mixerplugin_ctx, uapi_audio_mixer_plugin_frame *out_frame,
|
|
td_u32 require_size, audio_buffer *send_buf, td_u8 *read_buf)
|
|
{
|
|
td_s32 ret;
|
|
uapi_snd snd = mixerplugin_ctx->snd;
|
|
|
|
ret = uapi_snd_get_mixer_plugin_backin_buffer(snd, require_size, out_frame, 20); /* 20ms is sample */
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_snd_get_mixer_plugin_backin_buffer failed %x\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
send_buf->fd = (td_s32)out_frame->frame_addr.start_addr.mem_handle;
|
|
send_buf->size = (td_u32)out_frame->frame_addr.start_addr.addr_offset + out_frame->frame_addr.frame_size;
|
|
send_buf->valid_size = out_frame->frame_addr.frame_size;
|
|
send_buf->offset = (td_u32)out_frame->frame_addr.start_addr.addr_offset;
|
|
#if DEBUG_PRINT
|
|
printf("in fd %d %llu %d\n", (td_u32)out_frame->frame_addr.start_addr.mem_handle,
|
|
out_frame->frame_addr.start_addr.addr_offset, out_frame->frame_addr.frame_size);
|
|
#endif
|
|
ret = buf_mmap(send_buf);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call buf_mmap failed %x\n", ret);
|
|
}
|
|
|
|
ret = memcpy_s(send_buf->virt_addr + send_buf->offset, out_frame->frame_addr.frame_size, read_buf,
|
|
send_buf->valid_size);
|
|
if (ret != EOK) {
|
|
printf("call memcpy_s failed %x\n", ret);
|
|
return ret;
|
|
}
|
|
ret = uapi_snd_put_mixer_plugin_backin_buffer(snd, out_frame);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_snd_put_mixer_plugin_backin_buffer failed %x\n", ret);
|
|
}
|
|
buf_munmap(send_buf);
|
|
return ret;
|
|
}
|
|
|
|
static td_s32 read_backin_data_from_file(sample_ctx *mixerplugin_ctx, td_u8 *write_buf)
|
|
{
|
|
td_u32 read_len;
|
|
|
|
read_len = (td_u32)fread(write_buf, 1, mixerplugin_ctx->frame_size, mixerplugin_ctx->plugin_stream);
|
|
if (read_len != mixerplugin_ctx->frame_size) {
|
|
printf("rewind plugin file: %s\n", mixerplugin_ctx->plugin_file_name);
|
|
rewind(mixerplugin_ctx->plugin_stream);
|
|
}
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void *frontout_thread(td_void *args)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 require_samples;
|
|
td_u32 require_size;
|
|
td_u8 *read_buf = TD_NULL;
|
|
sample_ctx *mixerplugin_ctx = (sample_ctx *)args;
|
|
uapi_audio_mixer_plugin_frame in_frame;
|
|
audio_buffer acquire_buf;
|
|
|
|
read_buf = (td_u8 *)malloc(mixerplugin_ctx->frontout_frame_size);
|
|
if (read_buf == TD_NULL) {
|
|
printf("malloc read buffer failed!\n");
|
|
return TD_NULL;
|
|
}
|
|
|
|
memset_s(&in_frame, sizeof(in_frame), 0, sizeof(uapi_audio_mixer_plugin_frame));
|
|
|
|
require_samples = mixerplugin_ctx->frontout_pcm_samples;
|
|
require_size = mixerplugin_ctx->frontout_frame_size;
|
|
printf("require size %u\n", require_size);
|
|
while (mixerplugin_ctx->plugin_stop != TD_TRUE) {
|
|
ret = acquire_data(mixerplugin_ctx, &in_frame, require_samples, &acquire_buf, read_buf);
|
|
if (ret != 0) {
|
|
continue;
|
|
}
|
|
dbg_write_data_to_file(mixerplugin_ctx, &acquire_buf, read_buf);
|
|
usleep(DELAY_2_MS);
|
|
dbg_print_data(&acquire_buf, read_buf);
|
|
}
|
|
|
|
if (read_buf != TD_NULL) {
|
|
free(read_buf);
|
|
}
|
|
return TD_NULL;
|
|
}
|
|
|
|
static td_void *backin_thread(td_void *args)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 require_size;
|
|
td_u8 *write_buf = TD_NULL;
|
|
sample_ctx *mixerplugin_ctx = (sample_ctx *)args;
|
|
uapi_audio_mixer_plugin_frame out_frame;
|
|
audio_buffer send_buf;
|
|
td_bool send_done = TD_TRUE;
|
|
#if DEBUG_TIME
|
|
struct timeval time_thread_start = {0};
|
|
struct timeval time_thread_end = {0};
|
|
long time_limit;
|
|
#endif
|
|
write_buf = (td_u8 *)malloc(mixerplugin_ctx->backin_frame_size);
|
|
if (write_buf == TD_NULL) {
|
|
printf("malloc write_buf buffer failed!\n");
|
|
return TD_NULL;
|
|
}
|
|
|
|
memset_s(&out_frame, sizeof(out_frame), 0, sizeof(uapi_audio_mixer_plugin_frame));
|
|
require_size = mixerplugin_ctx->backin_frame_size;
|
|
printf("backin require size %u\n", require_size);
|
|
while (mixerplugin_ctx->plugin_stop != TD_TRUE) {
|
|
#if DEBUG_TIME
|
|
gettimeofday(&time_thread_start, NULL);
|
|
#endif
|
|
memset_s(write_buf, mixerplugin_ctx->backin_frame_size, 0, mixerplugin_ctx->backin_frame_size);
|
|
if (send_done == TD_TRUE) {
|
|
read_backin_data_from_file(mixerplugin_ctx, write_buf);
|
|
}
|
|
|
|
ret = send_data(mixerplugin_ctx, &out_frame, require_size, &send_buf, write_buf);
|
|
if (ret != TD_SUCCESS) {
|
|
send_done = TD_FALSE;
|
|
} else {
|
|
send_done = TD_TRUE;
|
|
}
|
|
usleep(DELAY_1_MS);
|
|
|
|
#if DEBUG_TIME
|
|
gettimeofday(&time_thread_end, NULL);
|
|
time_limit = (time_thread_end.tv_sec - time_thread_start.tv_sec) * 1000000 - /* 1000000 is from s to us */
|
|
time_thread_start.tv_usec + time_thread_end.tv_usec;
|
|
printf("spend %ld us %s\n", time_limit, send_done ? "done" : "");
|
|
#endif
|
|
}
|
|
if (write_buf != TD_NULL) {
|
|
free(write_buf);
|
|
}
|
|
return TD_NULL;
|
|
}
|
|
|
|
static td_s32 sample_mixer_plugin_enable(sample_ctx *mixerplugin_ctx)
|
|
{
|
|
td_s32 ret;
|
|
#if DEBUG_FILE
|
|
mixerplugin_ctx->dbg_read = fopen("/mnt/read_file.pcm", "wb");
|
|
if (mixerplugin_ctx->dbg_read == TD_NULL) {
|
|
printf("open dbg file error!\n");
|
|
}
|
|
#endif
|
|
printf("mixer plugin enable\n");
|
|
ret = uapi_snd_set_mixer_plugin_enable(mixerplugin_ctx->snd, TD_TRUE);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_snd_set_mixer_plugin_enable failed(0x%x)\n", ret);
|
|
}
|
|
if (mixerplugin_ctx->plugin_stop == TD_FALSE) {
|
|
return TD_SUCCESS;
|
|
}
|
|
mixerplugin_ctx->plugin_stop = TD_FALSE;
|
|
pthread_create(&mixerplugin_ctx->mixer_frontout_thread, TD_NULL, frontout_thread, mixerplugin_ctx);
|
|
pthread_create(&mixerplugin_ctx->mixer_backin_thread, TD_NULL, backin_thread, mixerplugin_ctx);
|
|
return ret;
|
|
}
|
|
|
|
static td_s32 sample_mixer_plugin_disable(sample_ctx *mixerplugin_ctx)
|
|
{
|
|
td_s32 ret;
|
|
if (mixerplugin_ctx->plugin_stop == TD_TRUE) {
|
|
return TD_SUCCESS;
|
|
}
|
|
mixerplugin_ctx->plugin_stop = TD_TRUE;
|
|
pthread_join(mixerplugin_ctx->mixer_frontout_thread, TD_NULL);
|
|
pthread_join(mixerplugin_ctx->mixer_backin_thread, TD_NULL);
|
|
|
|
ret = uapi_snd_set_mixer_plugin_enable(mixerplugin_ctx->snd, TD_FALSE);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_snd_set_mixer_plugin_disable failed(0x%x)\n", ret);
|
|
}
|
|
printf("mixer plugin disable\n");
|
|
#if DEBUG_FILE
|
|
if (mixerplugin_ctx->dbg_read != TD_NULL) {
|
|
(td_void)fclose(mixerplugin_ctx->dbg_read);
|
|
mixerplugin_ctx->dbg_read = TD_NULL;
|
|
}
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static const eng_cmd_map g_eng_cmd_map[] = {
|
|
{"e", sample_mixer_plugin_enable},
|
|
{"d", sample_mixer_plugin_disable},
|
|
};
|
|
|
|
static td_void *play_thread(td_void *args)
|
|
{
|
|
td_s32 ret;
|
|
td_void *pcm_buf = TD_NULL;
|
|
sample_ctx *mixerplugin_ctx = (sample_ctx *)args;
|
|
uapi_audio_frame ao_frame;
|
|
td_bool send_pending = TD_FALSE;
|
|
td_u32 read_len;
|
|
|
|
if (mixerplugin_ctx->frame_size > (UAPI_AUDIO_SAMPLE_RATE_192K * UAPI_AUDIO_CHANNEL_16 * sizeof(td_s16))) {
|
|
return TD_NULL;
|
|
}
|
|
|
|
pcm_buf = (td_void *)malloc(mixerplugin_ctx->frame_size);
|
|
if (pcm_buf == TD_NULL) {
|
|
printf("malloc pcm buffer failed!\n");
|
|
return TD_NULL;
|
|
}
|
|
|
|
audio_frame_init(mixerplugin_ctx, &ao_frame);
|
|
ao_frame.pcm_buffer = (td_s32 *)(pcm_buf);
|
|
|
|
printf("play start, file: %s\n", mixerplugin_ctx->playback_file_name);
|
|
|
|
while (mixerplugin_ctx->playback_stop != TD_TRUE) {
|
|
if (send_pending == TD_FALSE) {
|
|
read_len = (td_u32)fread(pcm_buf, 1, mixerplugin_ctx->frame_size, mixerplugin_ctx->playback_stream);
|
|
if (read_len != mixerplugin_ctx->frame_size) {
|
|
printf("rewind play, file: %s\n", mixerplugin_ctx->playback_file_name);
|
|
rewind(mixerplugin_ctx->playback_stream);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
ret = uapi_snd_send_track_data(mixerplugin_ctx->track, &ao_frame);
|
|
if (ret == TD_SUCCESS) {
|
|
send_pending = TD_FALSE;
|
|
usleep(DELAY_1_MS);
|
|
continue;
|
|
} else if (ret == TD_FAILURE) {
|
|
printf("uapi_snd_send_track_data failed(0x%x)!\n", ret);
|
|
break;
|
|
} else {
|
|
usleep(PLAY_THREAD_SLEEP_TIME);
|
|
send_pending = TD_TRUE;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
free(pcm_buf);
|
|
printf("play stop, file: %s\n", mixerplugin_ctx->playback_file_name);
|
|
return TD_NULL;
|
|
}
|
|
|
|
static td_void sample_stop(sample_ctx *mixerplugin_ctx)
|
|
{
|
|
mixerplugin_ctx->playback_stop = TD_TRUE;
|
|
if (mixerplugin_ctx->playback_enable == TD_TRUE) {
|
|
pthread_join(mixerplugin_ctx->playback_thread, TD_NULL);
|
|
}
|
|
|
|
if (mixerplugin_ctx->plugin_stop == TD_FALSE) {
|
|
sample_mixer_plugin_disable(mixerplugin_ctx);
|
|
}
|
|
return;
|
|
}
|
|
|
|
static td_s32 sample_start(sample_ctx *mixerplugin_ctx)
|
|
{
|
|
mixerplugin_ctx->playback_stop = TD_FALSE;
|
|
printf("playback_enable %s\n", mixerplugin_ctx->playback_enable ? "enable" : "disable");
|
|
if (mixerplugin_ctx->playback_enable == TD_TRUE) {
|
|
pthread_create(&mixerplugin_ctx->playback_thread, TD_NULL, play_thread, mixerplugin_ctx);
|
|
}
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void track_deinit(sample_ctx *mixerplugin_ctx)
|
|
{
|
|
td_s32 ret;
|
|
if (mixerplugin_ctx->track == TD_INVALID_HANDLE) {
|
|
return;
|
|
}
|
|
|
|
ret = uapi_snd_destroy_track(mixerplugin_ctx->track);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_snd_destroy_track failed(0x%x)\n", ret);
|
|
return;
|
|
}
|
|
|
|
mixerplugin_ctx->track = TD_INVALID_HANDLE;
|
|
return;
|
|
}
|
|
|
|
static td_s32 track_init(sample_ctx *mixerplugin_ctx)
|
|
{
|
|
td_s32 ret;
|
|
uapi_audio_track_attr track_attr;
|
|
uapi_snd_gain gain = {
|
|
.linear_mode = TD_TRUE,
|
|
.gain = mixerplugin_ctx->volume,
|
|
};
|
|
|
|
ret = uapi_snd_get_default_track_attr(UAPI_SND_TRACK_TYPE_SLAVE, &track_attr);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("uapi_snd_get_default_track_attr failed(0x%x)\n", ret);
|
|
return ret;
|
|
}
|
|
ret = uapi_snd_create_track(mixerplugin_ctx->snd, &track_attr, &mixerplugin_ctx->track);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("uapi_snd_create_track failed(0x%x)!\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = uapi_snd_set_track_weight(mixerplugin_ctx->track, &gain);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("uapi_snd_set_track_weight failed(0x%x)!\n", ret);
|
|
goto out;
|
|
}
|
|
return TD_SUCCESS;
|
|
out:
|
|
track_deinit(mixerplugin_ctx);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
static const struct {
|
|
td_s32 (*init)(sample_ctx *mixerplugin_ctx);
|
|
td_void (*deinit)(sample_ctx *mixerplugin_ctx);
|
|
} g_sample_module[] = {
|
|
{snd_init, snd_deinit},
|
|
{track_init, track_deinit},
|
|
{sample_start, sample_stop},
|
|
};
|
|
|
|
static td_s32 sample_init(sample_ctx *mixerplugin_ctx)
|
|
{
|
|
td_s32 ret;
|
|
td_s32 module;
|
|
const td_s32 mixer_num = sizeof(g_sample_module) / sizeof(g_sample_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 < mixer_num; module++) {
|
|
ret = g_sample_module[module].init(mixerplugin_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_module[module].deinit(mixerplugin_ctx);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static td_void sample_deinit(sample_ctx *mixerplugin_ctx)
|
|
{
|
|
td_s32 ret;
|
|
td_s32 module;
|
|
const td_s32 num = sizeof(g_sample_module) / sizeof(g_sample_module[0]);
|
|
|
|
for (module = num - 1; module >= 0; module--) {
|
|
g_sample_module[module].deinit(mixerplugin_ctx);
|
|
}
|
|
|
|
ret = uapi_sys_deinit();
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call uapi_sys_deinit failed(0x%x)\n", ret);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static td_void usage(const input_arg *arg)
|
|
{
|
|
printf("usage: sample_mixerplugin playback file0 plugin file1 (playback file0 and set file1 plugin)\n");
|
|
printf("usage: sample_mixerplugin plugin file1 (only to set plugin enable or disable)\n");
|
|
printf("usage: cmd [e] (enable plugin)\n");
|
|
printf("usage: cmd [d] (disable plugin)\n");
|
|
printf("examples:\n");
|
|
printf("%s file0 file1\n", arg->sample);
|
|
printf("%s file1\n", arg->sample);
|
|
}
|
|
|
|
static td_s32 sample_ctx_init(td_s32 argc, td_char *argv[], sample_ctx *mixerplugin_ctx)
|
|
{
|
|
input_arg *arg = (input_arg *)argv;
|
|
|
|
if (argc > 2) { /* 2 is argc number */
|
|
mixerplugin_ctx->playback_file_name = arg->playback_file;
|
|
mixerplugin_ctx->playback_stream = fopen(arg->playback_file, "rb");
|
|
if (mixerplugin_ctx->playback_stream == TD_NULL) {
|
|
printf("open file %s failed\n", arg->playback_file);
|
|
return TD_FAILURE;
|
|
}
|
|
mixerplugin_ctx->playback_enable = TD_TRUE;
|
|
}
|
|
|
|
mixerplugin_ctx->plugin_file_name = arg->plugin_file;
|
|
mixerplugin_ctx->plugin_stream = fopen(arg->plugin_file, "rb");
|
|
if (mixerplugin_ctx->plugin_stream == TD_NULL) {
|
|
printf("open plugin file %s failed\n", arg->plugin_file);
|
|
if (mixerplugin_ctx->playback_enable == TD_TRUE) {
|
|
(td_void)fclose(mixerplugin_ctx->playback_stream);
|
|
mixerplugin_ctx->playback_stream = TD_NULL;
|
|
}
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
mixerplugin_ctx->volume = 100; /* volume is 100, can modify if too loud */
|
|
mixerplugin_ctx->sample_rate = 48000; /* sample rate, default 48000 */
|
|
mixerplugin_ctx->channels = 2; /* 2 channels */
|
|
mixerplugin_ctx->pcm_samples = 256; /* 256 samples per frame */
|
|
mixerplugin_ctx->frame_size = mixerplugin_ctx->pcm_samples * mixerplugin_ctx->channels * sizeof(td_s16);
|
|
|
|
mixerplugin_ctx->frontout_pcm_samples = 512; /* 512 samples per frame */
|
|
mixerplugin_ctx->frontout_max_ch = FRONTOUT_DEFAULT_MAX_CHANNEL;
|
|
mixerplugin_ctx->frontout_frame_size = mixerplugin_ctx->frontout_pcm_samples *
|
|
mixerplugin_ctx->frontout_max_ch * sizeof(td_s16);
|
|
|
|
mixerplugin_ctx->backin_frame_size = 13660; /* backin frame size is 13660 ai sound effect */
|
|
printf("Default out block size %u in block size %u\n", mixerplugin_ctx->frontout_frame_size,
|
|
mixerplugin_ctx->backin_frame_size);
|
|
mixerplugin_ctx->track = TD_INVALID_HANDLE;
|
|
mixerplugin_ctx->plugin_stop = TD_TRUE;
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void sample_ctx_deinit(sample_ctx *mixerplugin_ctx)
|
|
{
|
|
if (mixerplugin_ctx->playback_stream != TD_NULL) {
|
|
(td_void)fclose(mixerplugin_ctx->playback_stream);
|
|
}
|
|
mixerplugin_ctx->playback_file_name = TD_NULL;
|
|
|
|
if (mixerplugin_ctx->plugin_stream != TD_NULL) {
|
|
(td_void)fclose(mixerplugin_ctx->plugin_stream);
|
|
}
|
|
mixerplugin_ctx->plugin_file_name = TD_NULL;
|
|
}
|
|
|
|
static td_void sample_mixer_process_cmd(sample_ctx *mixerplugin_ctx, td_char *cmd, td_u32 cmd_len)
|
|
{
|
|
td_u32 i;
|
|
td_u32 num = sizeof(g_eng_cmd_map) / sizeof(g_eng_cmd_map[0]);
|
|
(td_void)(cmd_len);
|
|
for (i = 0; i < num; i++) {
|
|
if (strncmp(cmd, g_eng_cmd_map[i].cmd, strlen(g_eng_cmd_map[i].cmd)) == 0) {
|
|
g_eng_cmd_map[i].action(mixerplugin_ctx);
|
|
return;
|
|
}
|
|
}
|
|
printf("Invalid input\n");
|
|
}
|
|
|
|
td_s32 main(int argc, char *argv[])
|
|
{
|
|
td_s32 ret;
|
|
sample_ctx mixerplugin_ctx;
|
|
input_arg *arg = (input_arg *)argv;
|
|
td_char input_cmd[INPUT_CMD_LENGTH];
|
|
|
|
if (argc < 2) { /* 2 is argc number */
|
|
usage(arg);
|
|
return -1;
|
|
}
|
|
|
|
ret = memset_s(&mixerplugin_ctx, sizeof(mixerplugin_ctx), 0, sizeof(sample_ctx));
|
|
if (ret != EOK) {
|
|
printf("call memset_s failed(0x%x)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
mixerplugin_ctx.snd = UAPI_SND_0;
|
|
|
|
ret = sample_ctx_init(argc, argv, &mixerplugin_ctx);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call sample_ctx_init failed(0x%x)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = sample_init(&mixerplugin_ctx);
|
|
if (ret != TD_SUCCESS) {
|
|
printf("call sample_init failed(0x%x)\n", ret);
|
|
goto out;
|
|
}
|
|
|
|
while (1) {
|
|
printf("input e enable plugin\n");
|
|
printf("input d disable plugin\n");
|
|
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_mixer_process_cmd(&mixerplugin_ctx, input_cmd, INPUT_CMD_LENGTH - 1);
|
|
}
|
|
|
|
sample_deinit(&mixerplugin_ctx);
|
|
out:
|
|
sample_ctx_deinit(&mixerplugin_ctx);
|
|
return ret;
|
|
}
|