1175 lines
32 KiB
C
1175 lines
32 KiB
C
/*
|
||
* Copyright (c) CompanyNameMagicTag 2019-2020. All rights reserved.
|
||
* Description: encode sample
|
||
* Author: audio
|
||
* Create: 2019-09-17
|
||
*/
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <unistd.h>
|
||
|
||
#include "thread_os.h"
|
||
#include "osal_list.h"
|
||
#include "securec.h"
|
||
#include "soc_uapi_adp.h"
|
||
#include "soc_uapi_aenc.h"
|
||
#include "soc_uapi_sound.h"
|
||
#include "sample_audio_api.h"
|
||
#include "sample_audio_utils.h"
|
||
|
||
#ifdef __cplusplus
|
||
#if __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
#endif
|
||
|
||
#define DEFAULT_AMRWB_BIT_RATE 0
|
||
|
||
#define DYNAMIC_SET_PARAM_ARG_NUM 3
|
||
#define PARAM_TYPE_INDEX 1
|
||
#define PARAM_VALUE_INDEX 2
|
||
|
||
#define PLC_TEST_ARG_NUM 9
|
||
#define PKG_LOSS_MODE_INDEX 6
|
||
#define PKG_LOSS_PERIOD_INDEX 7
|
||
#define PKG_LOSS_RATE_INDEX 8
|
||
|
||
typedef enum {
|
||
SAMPLE_PKG_LOSS_OFF,
|
||
SAMPLE_PKG_LOSS_INTERMITTENT,
|
||
SAMPLE_PKG_LOSS_CONTINUAL
|
||
} sample_pkg_loss_mode;
|
||
|
||
typedef struct {
|
||
sample_pkg_loss_mode pkg_loss_mode;
|
||
td_u32 pkg_loss_period;
|
||
td_u32 pkg_loss_rate;
|
||
} sample_encode_play_plc_arg;
|
||
|
||
typedef struct {
|
||
td_char *sample_encode;
|
||
td_char *in_stream;
|
||
td_char *encode_type;
|
||
td_char *sample_rate;
|
||
td_char *bit_depth;
|
||
td_char *channels;
|
||
} sample_encode_arg;
|
||
|
||
typedef struct sample_encode_inst {
|
||
td_bool task_active;
|
||
td_bool task_out_active;
|
||
athread_handle task_in;
|
||
athread_handle task_out;
|
||
|
||
FILE *h_file_in;
|
||
FILE *h_file_out;
|
||
td_u8 frame_buf[0x1000];
|
||
td_u32 frame_size;
|
||
data_info read_data;
|
||
data_info write_data;
|
||
td_u32 (*read_frame)(struct sample_encode_inst *inst, uapi_audio_frame *frame);
|
||
td_u32 (*write_frame)(struct sample_encode_inst *inst, const td_u8 *from, td_u32 len);
|
||
|
||
td_handle h_adp_in;
|
||
td_handle h_adp_out;
|
||
td_handle h_adp_play;
|
||
td_handle h_aenc;
|
||
|
||
td_u32 plc_count;
|
||
sample_encode_play_plc_arg plc_arg;
|
||
|
||
sample_acodec_arg aenc_arg;
|
||
struct osal_list_head node;
|
||
} sample_encode_inst;
|
||
|
||
static OSAL_LIST_HEAD(g_sample_encode_list);
|
||
|
||
static sample_encode_inst *sample_encode_alloc_inst(td_void)
|
||
{
|
||
sample_encode_inst *inst = (sample_encode_inst *)malloc(sizeof(sample_encode_inst));
|
||
if (inst == TD_NULL) {
|
||
return TD_NULL;
|
||
}
|
||
|
||
(td_void)memset_s(inst, sizeof(*inst), 0, sizeof(sample_encode_inst));
|
||
|
||
osal_list_add_tail(&inst->node, &g_sample_encode_list);
|
||
return inst;
|
||
}
|
||
|
||
static td_void sample_encode_free_inst(sample_encode_inst *inst)
|
||
{
|
||
if (inst == TD_NULL) {
|
||
return;
|
||
}
|
||
|
||
osal_list_del(&inst->node);
|
||
free(inst);
|
||
}
|
||
|
||
static sample_encode_inst *sample_encode_get_inst(td_void)
|
||
{
|
||
if (osal_list_empty(&g_sample_encode_list) != TD_FALSE) {
|
||
return TD_NULL;
|
||
}
|
||
|
||
return osal_list_first_entry(&g_sample_encode_list, sample_encode_inst, node);
|
||
}
|
||
|
||
static td_u32 sample_encode_write_flash(sample_encode_inst *aenc, const td_u8 *from, td_u32 len)
|
||
{
|
||
circ_buf *cb = &aenc->write_data.cb;
|
||
if (circ_buf_query_free(cb) <= len) {
|
||
sap_printf("Warning: ES data enough\n");
|
||
return 0;
|
||
}
|
||
|
||
return circ_buf_write(cb, from, len);
|
||
}
|
||
|
||
static td_u32 sample_encode_write_file(sample_encode_inst *inst, const td_u8 *from, td_u32 len)
|
||
{
|
||
td_u32 write;
|
||
|
||
write = fwrite(from, 1, len, inst->h_file_out);
|
||
return write;
|
||
}
|
||
|
||
static td_void encode_reader_reset(sample_encode_inst *aenc)
|
||
{
|
||
circ_buf *cb = &aenc->read_data.cb;
|
||
circ_buf_flush(cb);
|
||
circ_buf_update_write_pos(cb, cb->size - sizeof(td_s16));
|
||
}
|
||
|
||
static td_u32 sample_encode_read_flash(sample_encode_inst *inst, uapi_audio_frame *frame)
|
||
{
|
||
const td_u32 len = frame->bits_bytes;
|
||
circ_buf *cb = &inst->read_data.cb;
|
||
|
||
if (len > cb->size) {
|
||
sap_printf("Fatal Error: data not enough\n");
|
||
return 0;
|
||
}
|
||
|
||
if (circ_buf_query_busy(cb) < len) {
|
||
sap_printf("reset read\n");
|
||
encode_reader_reset(inst);
|
||
}
|
||
|
||
return circ_buf_read(cb, (td_u8 *)frame->bits_buffer, len);
|
||
}
|
||
|
||
static td_u32 sample_encode_read_file(sample_encode_inst *inst, uapi_audio_frame *frame)
|
||
{
|
||
td_u32 len;
|
||
|
||
len = fread(frame->bits_buffer, 1, frame->bits_bytes, inst->h_file_in);
|
||
if (len == 0) {
|
||
sap_printf("reset read\n");
|
||
rewind(inst->h_file_in);
|
||
return 0;
|
||
}
|
||
|
||
return len;
|
||
}
|
||
|
||
static td_u32 g_vector_read = 0;
|
||
|
||
static td_u32 sample_encode_read_array(sample_encode_inst *inst, uapi_audio_frame *frame)
|
||
{
|
||
td_u32 i, j;
|
||
td_u16 *buf = (td_u16 *)(td_uintptr_t)frame->bits_buffer;
|
||
const td_u16 *vector_16k_1ch_16bit = sample_get_vector_16k_1ch_16bit();
|
||
const td_u32 verctor_size = sample_get_vector_size();
|
||
|
||
for (i = 0; i < inst->aenc_arg.pcm_format.sample_per_frame; i++) {
|
||
for (j = 0; j < inst->aenc_arg.pcm_format.channels; ++j) {
|
||
*buf++ = vector_16k_1ch_16bit[g_vector_read]; /* duplicate each channel */
|
||
}
|
||
g_vector_read = saturate_add(g_vector_read, 1, verctor_size);
|
||
}
|
||
|
||
return inst->frame_size;
|
||
}
|
||
|
||
static td_void sample_encode_build_frame(const sample_encode_inst *inst, uapi_audio_frame *frame)
|
||
{
|
||
clear_obj(frame);
|
||
frame->interleaved = TD_TRUE;
|
||
frame->channels = inst->aenc_arg.pcm_format.channels;
|
||
frame->bit_depth = inst->aenc_arg.pcm_format.bit_depth;
|
||
frame->sample_rate = inst->aenc_arg.pcm_format.sample_rate;
|
||
frame->bits_buffer = (td_s32 *)inst->frame_buf;
|
||
frame->bits_bytes = inst->frame_size;
|
||
frame->pkg_loss = TD_FALSE;
|
||
}
|
||
|
||
static td_void encode_adp_data_send_proc(td_void *args)
|
||
{
|
||
td_s32 ret;
|
||
td_u32 len;
|
||
td_u32 read_len;
|
||
uapi_audio_frame input_frame;
|
||
sample_encode_inst *inst = (sample_encode_inst *)args;
|
||
|
||
sample_encode_build_frame(inst, &input_frame);
|
||
encode_reader_reset(inst);
|
||
|
||
sap_err_log_info("thread enter.");
|
||
while (inst->task_active) {
|
||
uapi_adp_query_free(inst->h_adp_in, &read_len);
|
||
if (read_len < FILE_READ_LEN_MIN) {
|
||
sap_msleep(THREAD_SLEEP_5MS);
|
||
continue;
|
||
}
|
||
|
||
read_len = circ_buf_min(read_len, inst->frame_size);
|
||
input_frame.bits_bytes = read_len;
|
||
|
||
len = inst->read_frame(inst, &input_frame);
|
||
if (len == 0) {
|
||
continue;
|
||
}
|
||
input_frame.bits_bytes = len;
|
||
|
||
while (inst->task_active) {
|
||
ret = uapi_adp_send_frame(inst->h_adp_in, &input_frame);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_msleep(THREAD_SLEEP_10MS);
|
||
continue;
|
||
}
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
sap_err_log_info("thread exit.");
|
||
athread_set_exit(inst->task_in, TD_TRUE);
|
||
}
|
||
|
||
static td_void encode_adp_data_recv_proc(td_void *args)
|
||
{
|
||
td_s32 ret;
|
||
td_u32 len;
|
||
uapi_stream_buf stream;
|
||
sample_encode_inst *inst = (sample_encode_inst *)args;
|
||
|
||
sap_err_log_info("thread enter.");
|
||
while (inst->task_out_active) {
|
||
ret = uapi_adp_acquire_stream(inst->h_adp_out, &stream);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_msleep(THREAD_SLEEP_10MS);
|
||
continue;
|
||
}
|
||
|
||
len = inst->write_frame(inst, (const td_u8 *)stream.data, stream.size);
|
||
if (len == 0) {
|
||
inst->task_out_active = TD_FALSE;
|
||
break;
|
||
}
|
||
|
||
ret = uapi_adp_release_stream(inst->h_adp_out, &stream);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_adp_release_stream, ret);
|
||
}
|
||
|
||
sap_msleep(THREAD_SLEEP_10MS);
|
||
}
|
||
|
||
sap_err_log_info("thread exit.");
|
||
athread_set_exit(inst->task_out, TD_TRUE);
|
||
}
|
||
|
||
static td_void sample_encode_play_start_pkg_loss(sample_encode_inst *inst, uapi_stream_buf *stream)
|
||
{
|
||
if (inst->plc_arg.pkg_loss_mode == SAMPLE_PKG_LOSS_OFF || inst->plc_arg.pkg_loss_rate == 0) {
|
||
return;
|
||
}
|
||
|
||
if (inst->plc_arg.pkg_loss_mode == SAMPLE_PKG_LOSS_INTERMITTENT) {
|
||
if (inst->plc_count >= inst->plc_arg.pkg_loss_period + inst->plc_arg.pkg_loss_rate) {
|
||
inst->plc_count -= inst->plc_arg.pkg_loss_period;
|
||
} else if (inst->plc_count >= inst->plc_arg.pkg_loss_period) {
|
||
stream->data = TD_NULL;
|
||
stream->pkg_loss = TD_TRUE;
|
||
}
|
||
} else if (inst->plc_arg.pkg_loss_mode == SAMPLE_PKG_LOSS_CONTINUAL) {
|
||
if (inst->plc_count < inst->plc_arg.pkg_loss_rate) {
|
||
stream->data = TD_NULL;
|
||
stream->pkg_loss = TD_TRUE;
|
||
} else if (inst->plc_count >= inst->plc_arg.pkg_loss_period) {
|
||
inst->plc_count = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
static td_void sample_encode_play_stop_pkg_loss(sample_encode_inst *inst, uapi_stream_buf *stream)
|
||
{
|
||
stream->pkg_loss = TD_FALSE;
|
||
if (inst->plc_arg.pkg_loss_mode == SAMPLE_PKG_LOSS_OFF || inst->plc_arg.pkg_loss_rate == 0) {
|
||
return;
|
||
}
|
||
|
||
if (inst->plc_arg.pkg_loss_mode == SAMPLE_PKG_LOSS_INTERMITTENT) {
|
||
inst->plc_count += inst->plc_arg.pkg_loss_rate;
|
||
} else if (inst->plc_arg.pkg_loss_mode == SAMPLE_PKG_LOSS_CONTINUAL) {
|
||
inst->plc_count++;
|
||
}
|
||
}
|
||
|
||
static td_void encode_adp_data_play_proc(td_void *args)
|
||
{
|
||
td_s32 ret;
|
||
td_u32 read_len;
|
||
uapi_stream_buf stream;
|
||
sample_encode_inst *inst = (sample_encode_inst *)args;
|
||
|
||
sap_err_log_info("thread enter.");
|
||
while (inst->task_out_active) {
|
||
ret = uapi_adp_acquire_stream(inst->h_adp_out, &stream);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_msleep(THREAD_SLEEP_10MS);
|
||
continue;
|
||
}
|
||
|
||
uapi_adp_query_free(inst->h_adp_play, &read_len);
|
||
if (read_len < FILE_READ_LEN_MIN) {
|
||
sap_msleep(THREAD_SLEEP_5MS);
|
||
continue;
|
||
}
|
||
stream.size = circ_buf_min(stream.size, read_len);
|
||
|
||
while (inst->task_out_active) {
|
||
sample_encode_play_start_pkg_loss(inst, &stream);
|
||
ret = uapi_adp_send_stream(inst->h_adp_play, &stream);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_msleep(THREAD_SLEEP_10MS);
|
||
continue;
|
||
}
|
||
sample_encode_play_stop_pkg_loss(inst, &stream);
|
||
break;
|
||
}
|
||
|
||
ret = uapi_adp_release_stream(inst->h_adp_out, &stream);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_adp_release_stream, ret);
|
||
}
|
||
}
|
||
|
||
sap_err_log_info("thread exit.");
|
||
athread_set_exit(inst->task_out, TD_TRUE);
|
||
}
|
||
|
||
static td_s32 sample_encode_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_aenc_init();
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_init, ret);
|
||
(td_void)uapi_adp_deinit();
|
||
return ret;
|
||
}
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
static td_void sample_encode_sys_deinit(td_void)
|
||
{
|
||
td_s32 ret;
|
||
|
||
ret = uapi_aenc_deinit();
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_deinit, ret);
|
||
}
|
||
|
||
ret = uapi_adp_deinit();
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_adp_deinit, ret);
|
||
}
|
||
}
|
||
|
||
static td_void sample_encode_close_adp_input(sample_encode_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
|
||
if (inst->h_adp_in == 0) {
|
||
return;
|
||
}
|
||
|
||
ret = uapi_adp_detach_output(inst->h_adp_in, inst->h_aenc);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_adp_detach_output, ret);
|
||
}
|
||
|
||
ret = uapi_adp_destroy(inst->h_adp_in);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_adp_destroy, ret);
|
||
}
|
||
|
||
inst->h_adp_in = 0;
|
||
}
|
||
|
||
static td_s32 sample_encode_open_adp_input(sample_encode_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
td_s32 err;
|
||
uapi_adp_attr adp_attr;
|
||
|
||
inst->h_adp_in = 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_in, &adp_attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_adp_create, ret);
|
||
return ret;
|
||
}
|
||
|
||
ret = uapi_adp_attach_output(inst->h_adp_in, inst->h_aenc);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_adp_attach_output, ret);
|
||
goto out;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
out:
|
||
err = uapi_adp_destroy(inst->h_adp_in);
|
||
if (err != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_adp_destroy, err);
|
||
}
|
||
|
||
inst->h_adp_in = 0;
|
||
return ret;
|
||
}
|
||
|
||
static td_void sample_encode_close_adp_output(sample_encode_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
|
||
if (inst->h_adp_out == 0) {
|
||
return;
|
||
}
|
||
|
||
ret = uapi_adp_destroy(inst->h_adp_out);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_adp_destroy, ret);
|
||
}
|
||
|
||
inst->h_adp_out = 0;
|
||
}
|
||
|
||
static td_s32 sample_encode_open_adp_output(sample_encode_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
uapi_adp_attr adp_attr;
|
||
|
||
inst->h_adp_out = 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_out, &adp_attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_adp_create, ret);
|
||
return ret;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
static td_void sample_encode_close_aenc(sample_encode_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
|
||
if (inst->h_aenc == 0) {
|
||
return;
|
||
}
|
||
|
||
ret = uapi_aenc_detach_output(inst->h_aenc, inst->h_adp_out);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_detach_output, ret);
|
||
}
|
||
|
||
ret = uapi_aenc_destroy(inst->h_aenc);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_destroy, ret);
|
||
}
|
||
|
||
inst->h_aenc = 0;
|
||
}
|
||
|
||
static td_s32 sample_encode_open_aenc(sample_encode_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
td_s32 err;
|
||
td_u32 bit_rate;
|
||
uapi_aenc_attr aenc_attr;
|
||
|
||
inst->h_aenc = 0;
|
||
ret = uapi_aenc_create(&inst->h_aenc);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_create, ret);
|
||
return ret;
|
||
}
|
||
|
||
ret = uapi_aenc_get_attr(inst->h_aenc, &aenc_attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_get_attr, ret);
|
||
goto out;
|
||
}
|
||
|
||
aenc_attr.codec_id = inst->aenc_arg.acodec_id;
|
||
aenc_attr.param.interleaved = TD_TRUE;
|
||
aenc_attr.param.channels = inst->aenc_arg.pcm_format.channels;
|
||
aenc_attr.param.bit_depth = inst->aenc_arg.pcm_format.bit_depth;
|
||
aenc_attr.param.sample_rate = inst->aenc_arg.pcm_format.sample_rate;
|
||
aenc_attr.param.samples_per_frame = inst->aenc_arg.pcm_format.sample_per_frame;
|
||
aenc_attr.param.private_data = TD_NULL;
|
||
aenc_attr.param.private_data_size = 0;
|
||
|
||
ret = uapi_aenc_set_attr(inst->h_aenc, &aenc_attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_set_attr, ret);
|
||
goto out;
|
||
}
|
||
|
||
if (aenc_attr.codec_id == UAPI_ACODEC_ID_AMRWB) {
|
||
bit_rate = DEFAULT_AMRWB_BIT_RATE;
|
||
ret = uapi_aenc_set_param(inst->h_aenc, UAPI_AENC_PARAM_BIT_RATE, &bit_rate, sizeof(bit_rate));
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_set_param, ret);
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
ret = uapi_aenc_attach_output(inst->h_aenc, inst->h_adp_out);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_attach_output, ret);
|
||
goto out;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
out:
|
||
err = uapi_aenc_destroy(inst->h_aenc);
|
||
if (err != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_destroy, err);
|
||
}
|
||
|
||
inst->h_aenc = 0;
|
||
return ret;
|
||
}
|
||
|
||
static td_void sample_encode_close_inst(sample_encode_inst *inst)
|
||
{
|
||
sample_encode_close_adp_input(inst);
|
||
sample_encode_close_aenc(inst);
|
||
sample_encode_close_adp_output(inst);
|
||
sample_encode_sys_deinit();
|
||
}
|
||
|
||
static td_s32 sample_encode_open_inst(sample_encode_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
|
||
ret = sample_encode_sys_init();
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_encode_sys_init, ret);
|
||
return ret;
|
||
}
|
||
|
||
/*
|
||
* 数据流向 adp_in --> aenc --> adp_out
|
||
* 按照数据流向反方向打开实例
|
||
* 按照数据方向attach output
|
||
*/
|
||
ret = sample_encode_open_adp_output(inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_encode_open_adp_output, ret);
|
||
goto out0;
|
||
}
|
||
|
||
ret = sample_encode_open_aenc(inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_encode_open_aenc, ret);
|
||
goto out1;
|
||
}
|
||
|
||
ret = sample_encode_open_adp_input(inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_encode_open_adp_input, ret);
|
||
goto out2;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
out2:
|
||
sample_encode_close_aenc(inst);
|
||
out1:
|
||
sample_encode_close_adp_output(inst);
|
||
out0:
|
||
sample_encode_sys_deinit();
|
||
return ret;
|
||
}
|
||
|
||
static td_void sample_encode_stop_inst(sample_encode_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
|
||
inst->task_active = TD_FALSE;
|
||
if (inst->task_in != TD_NULL) {
|
||
athread_exit(inst->task_in);
|
||
inst->task_in = TD_NULL;
|
||
}
|
||
|
||
inst->task_out_active = TD_FALSE;
|
||
if (inst->task_out != TD_NULL) {
|
||
athread_exit(inst->task_out);
|
||
inst->task_out = TD_NULL;
|
||
}
|
||
|
||
ret = uapi_aenc_stop(inst->h_aenc);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_stop, ret);
|
||
}
|
||
}
|
||
|
||
static td_s32 sample_encode_start_inst(sample_encode_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
athread_attr attr;
|
||
|
||
ret = uapi_aenc_start(inst->h_aenc);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_start, ret);
|
||
}
|
||
|
||
/* Create Task for ADP instance to send audio data */
|
||
inst->task_active = TD_TRUE;
|
||
attr.priority = ATHREAD_PRIORITY_NORMAL;
|
||
attr.stack_size = 0x1000; /* 4k */
|
||
attr.name = "sample_aenc_send";
|
||
ret = athread_create(&inst->task_in, encode_adp_data_send_proc, (td_void *)inst, &attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(athread_create, ret);
|
||
}
|
||
|
||
inst->task_out_active = TD_TRUE;
|
||
attr.priority = ATHREAD_PRIORITY_NORMAL;
|
||
attr.stack_size = 0x1000; /* 4k */
|
||
attr.name = "sample_aenc_recv";
|
||
ret = athread_create(&inst->task_out, encode_adp_data_recv_proc, (td_void *)inst, &attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(athread_create, ret);
|
||
}
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
static td_void sample_encode_close_file(sample_encode_inst *inst)
|
||
{
|
||
if (inst->h_file_out != TD_NULL) {
|
||
fclose(inst->h_file_out);
|
||
inst->h_file_out = TD_NULL;
|
||
}
|
||
|
||
if (inst->h_file_in != TD_NULL) {
|
||
fclose(inst->h_file_in);
|
||
inst->h_file_in = TD_NULL;
|
||
}
|
||
}
|
||
|
||
static td_s32 sample_encode_open_file(sample_encode_inst *inst, const sample_encode_arg *arg)
|
||
{
|
||
/* open input file */
|
||
inst->h_file_in = TD_NULL;
|
||
if (strcmp(arg->in_stream, "null") != 0) {
|
||
inst->h_file_in = fopen(arg->in_stream, "rb");
|
||
if (inst->h_file_in == TD_NULL) {
|
||
sap_printf("open file %s error!\n", arg->in_stream);
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
/* open output file */
|
||
inst->h_file_out = TD_NULL;
|
||
if (strcmp(arg->sample_encode, "sample_encode_play") == 0) {
|
||
return 0;
|
||
}
|
||
|
||
if (strcmp(arg->in_stream, "null") != 0) {
|
||
td_s32 ret;
|
||
td_char file_path[FILE_PATH_LEN];
|
||
ret = snprintf_s(file_path, FILE_PATH_LEN - 1, FILE_PATH_LEN - 1, "%s.%s", arg->in_stream, arg->encode_type);
|
||
if (ret < 0) {
|
||
sap_err_log_fun(snprintf_s, ret);
|
||
if (inst->h_file_in != TD_NULL) {
|
||
fclose(inst->h_file_in);
|
||
inst->h_file_in = TD_NULL;
|
||
}
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
inst->h_file_out = fopen(file_path, "wb");
|
||
if (inst->h_file_out == TD_NULL) {
|
||
sap_printf("open file %s error!\n", file_path);
|
||
if (inst->h_file_in != TD_NULL) {
|
||
fclose(inst->h_file_in);
|
||
inst->h_file_in = TD_NULL;
|
||
}
|
||
return EXT_FAILURE;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static td_s32 sample_encode_open_in_stream(sample_encode_inst *inst, const sample_encode_arg *arg)
|
||
{
|
||
td_s32 ret;
|
||
inst->frame_size = calc_pcm_frame_size(&inst->aenc_arg.pcm_format);
|
||
|
||
inst->h_file_in = TD_NULL;
|
||
inst->h_file_out = TD_NULL;
|
||
data_info_init(&inst->read_data, FPGA_FLASH_PCM_DATA_ADDR, FPGA_FLASH_PCM_SIZE);
|
||
data_info_init(&inst->write_data, FPGA_SAVE_DATA_ADDR, FPGA_SAVE_DATA_SIZE);
|
||
|
||
if (strcmp(arg->in_stream, "array") == 0 || arg->in_stream == TD_NULL) {
|
||
inst->read_frame = sample_encode_read_array;
|
||
inst->write_frame = sample_encode_write_flash;
|
||
sap_err_log_info("sample_ao read data from array.");
|
||
} else if (strcmp(arg->in_stream, "flash") == 0 || strcmp(arg->in_stream, "null") == 0) {
|
||
inst->read_frame = sample_encode_read_flash;
|
||
inst->write_frame = sample_encode_write_flash;
|
||
sap_err_log_info("sample_ao read data from flash.");
|
||
} else {
|
||
ret = sample_encode_open_file(inst, arg);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_encode_open_file, ret);
|
||
return ret;
|
||
}
|
||
|
||
inst->read_frame = sample_encode_read_file;
|
||
inst->write_frame = sample_encode_write_file;
|
||
sap_err_log_info("sample_ao read data from file.");
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static td_s32 sample_encode_ctx_init(const sample_encode_arg *arg, sample_acodec_arg *ctx)
|
||
{
|
||
td_s32 ret;
|
||
clear_obj(ctx);
|
||
|
||
if (strcmp(arg->in_stream, "null") == 0) {
|
||
ctx->file = TD_NULL;
|
||
} else {
|
||
ctx->file = arg->in_stream;
|
||
}
|
||
|
||
ctx->acodec_id = UAPI_ACODEC_ID_MAX;
|
||
|
||
ret = sample_audio_get_acodec_id(arg->encode_type, &ctx->acodec_id);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_audio_get_acodec_id, ret);
|
||
return ret;
|
||
}
|
||
|
||
ctx->pcm_format.channels = (td_u32)strtoul(arg->channels, TD_NULL, 0);
|
||
ctx->pcm_format.bit_depth = (td_u32)strtoul(arg->bit_depth, TD_NULL, 0);
|
||
ctx->pcm_format.sample_rate = (td_u32)strtoul(arg->sample_rate, TD_NULL, 0);
|
||
ctx->pcm_format.sample_per_frame = ctx->pcm_format.sample_rate / 100; /* 100 --> 10ms */
|
||
|
||
sap_err_log_u32(ctx->pcm_format.channels);
|
||
sap_err_log_u32(ctx->pcm_format.bit_depth);
|
||
sap_err_log_u32(ctx->pcm_format.sample_rate);
|
||
sap_err_log_u32(ctx->pcm_format.sample_per_frame);
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
static td_void sample_encode_usage(const td_char *name)
|
||
{
|
||
sap_printf("if you won't to test PLC:\n");
|
||
sap_printf("usage: %s pcm_file codec sample_rate bit_depth channels\n", name);
|
||
sap_printf("examples:\n");
|
||
sap_printf(" %s /mnt/test.pcm sbc 48000 16 2\n", name);
|
||
sap_printf(" %s null msbc 16000 16 1\n", name);
|
||
sap_printf("\n");
|
||
sap_printf("if you want to test PLC:\n");
|
||
sap_printf("usage: %s pcm_file codec sample_rate bit_depth channels plc_mode plc_period plc_rate\n", name);
|
||
sap_printf("examples:\n");
|
||
sap_printf(" %s /user/stream/PCM_8k_1ch_16bit.pcm pcm 8000 16 1 off 100 10\n", name);
|
||
sap_printf(" %s /user/stream/PCM_8k_1ch_16bit.pcm pcm 8000 16 1 int 10 1\n", name);
|
||
sap_printf(" %s /user/stream/PCM_8k_1ch_16bit.pcm pcm 8000 16 1 con 100 20\n", name);
|
||
sap_printf("\n");
|
||
sap_printf("if you want to set param dynamically:\n");
|
||
sap_printf("usage: %s param_type param_value\n", name);
|
||
sap_printf("examples:\n");
|
||
sap_printf(" %s bit_rate 6\n", name);
|
||
}
|
||
|
||
static td_s32 sample_encode_entry(td_s32 argc, td_char *argv[])
|
||
{
|
||
td_s32 ret;
|
||
sample_encode_arg *arg = (sample_encode_arg *)argv;
|
||
sample_encode_inst *encode_inst = sample_encode_get_inst();
|
||
if (encode_inst != TD_NULL) {
|
||
sap_printf("%s is already running", argv[0]);
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
if (argc < (td_s32)(sizeof(*arg) / sizeof(td_char *))) {
|
||
sample_encode_usage(argv[0]);
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
encode_inst = sample_encode_alloc_inst();
|
||
if (encode_inst == TD_NULL) {
|
||
sap_printf("sample_encode_alloc_inst failed");
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
ret = sample_encode_ctx_init(arg, &encode_inst->aenc_arg);
|
||
if (ret != EXT_SUCCESS) {
|
||
goto out0;
|
||
}
|
||
|
||
ret = sample_encode_open_in_stream(encode_inst, arg);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_encode_open_in_stream, ret);
|
||
goto out0;
|
||
}
|
||
|
||
ret = sample_encode_open_inst(encode_inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_encode_open_inst, ret);
|
||
goto out1;
|
||
}
|
||
|
||
ret = sample_encode_start_inst(encode_inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_encode_start_inst, ret);
|
||
goto out2;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
out2:
|
||
sample_encode_close_inst(encode_inst);
|
||
out1:
|
||
sample_encode_close_file(encode_inst);
|
||
out0:
|
||
sample_encode_free_inst(encode_inst);
|
||
return ret;
|
||
}
|
||
|
||
static td_s32 sample_encode_exit(td_void)
|
||
{
|
||
sample_encode_inst *inst = sample_encode_get_inst();
|
||
if (inst != TD_NULL) {
|
||
sample_encode_stop_inst(inst);
|
||
sample_encode_close_inst(inst);
|
||
sample_encode_close_file(inst);
|
||
sample_encode_free_inst(inst);
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
/*
|
||
* 编码sample
|
||
* 从文件或者内存读入pcm数据,执行编码操作
|
||
* 编码后的ES流写入文件或者写入内存
|
||
*/
|
||
td_s32 sample_encode(td_s32 argc, td_char *argv[])
|
||
{
|
||
if (argc <= 1) {
|
||
sample_encode_usage(argv[0]);
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
if (strcmp(argv[1], "q") == 0) {
|
||
return sample_encode_exit();
|
||
} else {
|
||
return sample_encode_entry(argc, argv);
|
||
}
|
||
}
|
||
|
||
static td_s32 sample_encode_play_parse_plc_mode(td_char *argv[], sample_encode_inst *inst)
|
||
{
|
||
td_u32 i;
|
||
const struct {
|
||
td_char *mode_name;
|
||
sample_pkg_loss_mode pkg_loss_mode;
|
||
} optional_pkg_loss_mode[] = {
|
||
{"off", SAMPLE_PKG_LOSS_OFF},
|
||
{"int", SAMPLE_PKG_LOSS_INTERMITTENT},
|
||
{"con", SAMPLE_PKG_LOSS_CONTINUAL}
|
||
};
|
||
|
||
for (i = 0; i < sizeof(optional_pkg_loss_mode) / sizeof(optional_pkg_loss_mode[0]); i++) {
|
||
if (strcmp(argv[PKG_LOSS_MODE_INDEX], optional_pkg_loss_mode[i].mode_name) == 0) {
|
||
inst->plc_arg.pkg_loss_mode = optional_pkg_loss_mode[i].pkg_loss_mode;
|
||
return EXT_SUCCESS;
|
||
}
|
||
}
|
||
sap_printf("invalid pkg_loss mode : %s\n", argv[PKG_LOSS_MODE_INDEX]);
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
static td_s32 sample_encode_play_parse_plc_arg(td_s32 argc, td_char *argv[], sample_encode_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
|
||
if (argc < PLC_TEST_ARG_NUM) {
|
||
sample_encode_usage(argv[0]);
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
ret = sample_encode_play_parse_plc_mode(argv, inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
return ret;
|
||
}
|
||
|
||
inst->plc_arg.pkg_loss_period = (td_u32)strtoul(argv[PKG_LOSS_PERIOD_INDEX], TD_NULL, 0);
|
||
inst->plc_arg.pkg_loss_rate = (td_u32)strtoul(argv[PKG_LOSS_RATE_INDEX], TD_NULL, 0);
|
||
if (inst->plc_arg.pkg_loss_period < inst->plc_arg.pkg_loss_rate) {
|
||
sap_printf("pkg_loss period(%u) < rate(%u)!\n", inst->plc_arg.pkg_loss_period, inst->plc_arg.pkg_loss_rate);
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
static td_s32 sample_encode_play_parse_param_type(td_char *argv[], uapi_aenc_param_type *param_type)
|
||
{
|
||
td_u32 i;
|
||
const struct {
|
||
td_char *param_name;
|
||
uapi_aenc_param_type param_type;
|
||
} optional_param_type[] = {
|
||
{"bit_rate", UAPI_AENC_PARAM_BIT_RATE},
|
||
};
|
||
|
||
for (i = 0; i < sizeof(optional_param_type) / sizeof(optional_param_type[0]); i++) {
|
||
if (strcmp(argv[PARAM_TYPE_INDEX], optional_param_type[i].param_name) == 0) {
|
||
*param_type = optional_param_type[i].param_type;
|
||
return EXT_SUCCESS;
|
||
}
|
||
}
|
||
sap_printf("invalid param type : %s\n", argv[PARAM_TYPE_INDEX]);
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
static td_s32 sample_encode_dynamic_set_param(td_char *argv[], sample_encode_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
td_u32 bit_rate;
|
||
uapi_aenc_param_type param_type;
|
||
|
||
ret = sample_encode_play_parse_param_type(argv, ¶m_type);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_encode_play_parse_param_type, ret);
|
||
return ret;
|
||
}
|
||
|
||
switch (param_type) {
|
||
case UAPI_AENC_PARAM_BIT_RATE:
|
||
bit_rate = (td_u32)strtoul(argv[PARAM_VALUE_INDEX], TD_NULL, 0);
|
||
ret = uapi_aenc_set_param(inst->h_aenc, param_type, &bit_rate, sizeof(bit_rate));
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_set_param, ret);
|
||
return ret;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
static td_s32 sample_encode_play_start_inst(sample_encode_inst *inst)
|
||
{
|
||
td_s32 ret;
|
||
athread_attr attr;
|
||
|
||
ret = uapi_aenc_start(inst->h_aenc);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(uapi_aenc_start, ret);
|
||
}
|
||
|
||
/* 创建线程为aenc输入adp输送pcm数据 */
|
||
inst->task_active = TD_TRUE;
|
||
attr.priority = ATHREAD_PRIORITY_NORMAL;
|
||
attr.stack_size = 0x1000; /* 4k */
|
||
attr.name = "sample_aenc_send";
|
||
ret = athread_create(&inst->task_in, encode_adp_data_send_proc, (td_void *)inst, &attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(athread_create, ret);
|
||
}
|
||
|
||
inst->task_out_active = TD_TRUE;
|
||
attr.priority = ATHREAD_PRIORITY_NORMAL;
|
||
attr.stack_size = 0x1000; /* 4k */
|
||
attr.name = "sample_aenc_play";
|
||
/* 创建线程获取编码后的es流,并送给esplay播放器去播放 */
|
||
ret = athread_create(&inst->task_out, encode_adp_data_play_proc, (td_void *)inst, &attr);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(athread_create, ret);
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
static td_s32 sample_encode_play_open(sample_encode_inst *inst, const sample_encode_arg *arg)
|
||
{
|
||
td_s32 ret;
|
||
|
||
/* 按照输入的采样率、声道、位宽,打开一个esplay播放器 */
|
||
ret = sample_esplay_open(&inst->aenc_arg, &inst->h_adp_play, UAPI_SND_AEF_PROFILE_NONE);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_esplay_open, ret);
|
||
return ret;
|
||
}
|
||
|
||
ret = sample_encode_open_in_stream(inst, arg);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_encode_open_in_stream, ret);
|
||
goto out0;
|
||
}
|
||
|
||
/* 打开编码通路所有实例 */
|
||
ret = sample_encode_open_inst(inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_encode_open_inst, ret);
|
||
goto out1;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
out1:
|
||
sample_encode_close_file(inst);
|
||
out0:
|
||
sample_esplay_close();
|
||
return ret;
|
||
}
|
||
|
||
static td_void sample_encode_play_close(sample_encode_inst *inst)
|
||
{
|
||
sample_encode_close_inst(inst);
|
||
sample_encode_close_file(inst);
|
||
sample_esplay_close();
|
||
}
|
||
|
||
static td_s32 sample_encode_play_entry(td_s32 argc, td_char *argv[])
|
||
{
|
||
td_s32 ret;
|
||
sample_encode_arg *arg = (sample_encode_arg *)argv;
|
||
sample_encode_inst *inst = sample_encode_get_inst();
|
||
if (inst != TD_NULL) {
|
||
if (argc == DYNAMIC_SET_PARAM_ARG_NUM) {
|
||
ret = sample_encode_dynamic_set_param(argv, inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_encode_dynamic_set_param, ret);
|
||
}
|
||
return ret;
|
||
} else {
|
||
sap_printf("%s is already running", argv[0]);
|
||
return EXT_FAILURE;
|
||
}
|
||
}
|
||
|
||
if (argc < (td_s32)(sizeof(*arg) / sizeof(td_char *))) {
|
||
sample_encode_usage(argv[0]);
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
inst = sample_encode_alloc_inst();
|
||
if (inst == TD_NULL) {
|
||
sap_printf("sample_encode_alloc_inst failed");
|
||
return EXT_FAILURE;
|
||
}
|
||
|
||
if (argc > (td_s32)(sizeof(*arg) / sizeof(td_char *))) { /* parse plc arg when arg num greater than 6 */
|
||
ret = sample_encode_play_parse_plc_arg(argc, argv, inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
goto out0;
|
||
}
|
||
}
|
||
|
||
ret = sample_encode_ctx_init(arg, &inst->aenc_arg);
|
||
if (ret != EXT_SUCCESS) {
|
||
goto out0;
|
||
}
|
||
|
||
ret = sample_encode_play_open(inst, arg);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_encode_play_open, ret);
|
||
goto out0;
|
||
}
|
||
|
||
/* start编码通道所有实例 */
|
||
ret = sample_encode_play_start_inst(inst);
|
||
if (ret != EXT_SUCCESS) {
|
||
sap_err_log_fun(sample_encode_play_start_inst, ret);
|
||
goto out1;
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
out1:
|
||
sample_encode_play_close(inst);
|
||
out0:
|
||
sample_encode_free_inst(inst);
|
||
return ret;
|
||
}
|
||
|
||
static td_s32 sample_encode_play_exit(td_void)
|
||
{
|
||
sample_encode_inst *inst = sample_encode_get_inst();
|
||
if (inst != TD_NULL) {
|
||
sample_encode_stop_inst(inst);
|
||
sample_encode_close_inst(inst);
|
||
sample_encode_close_file(inst);
|
||
sample_esplay_close();
|
||
sample_encode_free_inst(inst);
|
||
}
|
||
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
/*
|
||
* 编码同时播放sample
|
||
* 从文件或者内存读入pcm数据,执行编码操作
|
||
* 编码后的ES流通过一个esplay播放器播放
|
||
*/
|
||
td_s32 sample_encode_play(td_s32 argc, td_char *argv[])
|
||
{
|
||
if (argc <= 1) {
|
||
sample_encode_usage(argv[0]);
|
||
return EXT_SUCCESS;
|
||
}
|
||
|
||
if (strcmp(argv[1], "q") == 0) {
|
||
return sample_encode_play_exit();
|
||
} else {
|
||
return sample_encode_play_entry(argc, argv);
|
||
}
|
||
}
|
||
|
||
#ifdef __cplusplus
|
||
#if __cplusplus
|
||
}
|
||
#endif
|
||
#endif
|