316 lines
11 KiB
C
316 lines
11 KiB
C
#ifdef SUPPORT_MS_EXTENSIONS
|
|
#pragma bss_seg(".linein_file.data.bss")
|
|
#pragma data_seg(".linein_file.data")
|
|
#pragma const_seg(".linein_file.text.const")
|
|
#pragma code_seg(".linein_file.text")
|
|
#endif
|
|
#include "source_node.h"
|
|
#include "asm/audio_adc.h"
|
|
#include "media/audio_splicing.h"
|
|
#include "linein_file.h"
|
|
#include "effects/effects_adj.h"
|
|
#include "sync/audio_clk_sync.h"
|
|
|
|
#if 1
|
|
#define adc_file_log printf
|
|
#else
|
|
#define adc_file_log(...)
|
|
#endif/*log_en*/
|
|
|
|
extern struct audio_adc_hdl adc_hdl;
|
|
extern const struct adc_platform_cfg adc_platform_cfg_table[AUDIO_ADC_MAX_NUM];
|
|
|
|
#define LINEIN_ADC_BUF_NUM 2 //linein_adc采样buf个数
|
|
|
|
static struct linein_file_cfg linein_cfg_g;
|
|
|
|
int adc_file_linein_open(struct adc_linein_ch *linein, int ch)
|
|
{
|
|
int ch_index = 0;
|
|
int linein_gain;
|
|
int linein_pre_gain;
|
|
const struct adc_platform_cfg *cfg_table = adc_platform_cfg_table;
|
|
struct linein_open_param linein_param = {0};
|
|
|
|
for (int i = 0; i < AUDIO_ADC_LINEIN_MAX_NUM; i++) {
|
|
if (ch == BIT(i)) {
|
|
ch_index = i;
|
|
break;
|
|
}
|
|
}
|
|
audio_linein_param_fill(&linein_param, &cfg_table[ch_index]);
|
|
linein_gain = linein_cfg_g.param[ch_index].mic_gain;
|
|
linein_pre_gain = linein_cfg_g.param[ch_index].mic_pre_gain;
|
|
printf(">> linein %d, linein_ain_sel %d, linein_mode %d, linein_dcc %d, linein_gain %d, linein_pre_gain %d", ch_index, linein_param.linein_ain_sel, linein_param.linein_mode, linein_param.linein_dcc, linein_gain, linein_pre_gain);
|
|
audio_adc_linein_open(linein, ch, &adc_hdl, &linein_param);
|
|
audio_adc_linein_set_gain(linein, ch, linein_gain);
|
|
audio_adc_linein_gain_boost(ch, linein_pre_gain);
|
|
return 0;
|
|
}
|
|
|
|
#if TCFG_AUDIO_LINEIN_ENABLE
|
|
|
|
|
|
void audio_linein_file_init()
|
|
{
|
|
char mode_index = 0;
|
|
char cfg_index = 0;//目标配置项序号
|
|
int len = jlstream_read_form_data(mode_index, "linein_adc", cfg_index, &linein_cfg_g);
|
|
if (len != sizeof(struct linein_file_cfg)) {
|
|
printf("linein_file read cfg data err !!!\n");
|
|
}
|
|
adc_file_log(" %s len %d, sizeof(cfg) %d\n", __func__, len, (int)sizeof(struct linein_file_cfg));
|
|
#if 1
|
|
adc_file_log(" linein_cfg_g.mic_en_map = %x\n", linein_cfg_g.mic_en_map);
|
|
for (int i = 0; i < AUDIO_ADC_LINEIN_MAX_NUM; i++) {
|
|
adc_file_log(" linein_cfg_g.param[%d].mic_gain = %d\n", i, linein_cfg_g.param[i].mic_gain);
|
|
adc_file_log(" linein_cfg_g.param[%d].mic_pre_gain = %d\n", i, linein_cfg_g.param[i].mic_pre_gain);
|
|
}
|
|
#endif
|
|
for (int i = 0; i < AUDIO_ADC_LINEIN_MAX_NUM; i++) {
|
|
if (linein_cfg_g.mic_en_map & BIT(i)) {
|
|
audio_adc_add_ch(&adc_hdl, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @brief LINEIN 的中断回调函数
|
|
*
|
|
* @param _hdl LINEIN 节点的操作句柄
|
|
* @param data LINEIN 中断采集到的数据地址
|
|
* @param len LINEIN 单个通道中断采集到的数据字节长度
|
|
*/
|
|
static void adc_linein_output_handler(void *_hdl, s16 *data, int len)
|
|
{
|
|
|
|
struct linein_file_hdl *hdl = (struct linein_file_hdl *)_hdl;
|
|
struct stream_frame *frame;
|
|
|
|
if (hdl->dump_cnt < 10) {
|
|
hdl->dump_cnt++;
|
|
return;
|
|
}
|
|
frame = source_plug_get_output_frame(hdl->source_node, (len * hdl->ch_num));
|
|
if (frame) {
|
|
if (hdl->ch_num != adc_hdl.max_adc_num) {
|
|
//printf("l:%d,%d,%d\n",hdl->adc_seq,hdl->ch_num,adc_hdl.max_adc_num);
|
|
if (adc_hdl.bit_width != ADC_BIT_WIDTH_16) {
|
|
s32 *s32_src = (s32 *)data;
|
|
s32 *s32_dst = (s32 *)frame->data;
|
|
for (int i = 0; i < len / 4; i++) {
|
|
for (int j = 0; j < hdl->ch_num; j++) {
|
|
s32_dst[hdl->ch_num * i + j] = s32_src[adc_hdl.max_adc_num * i + hdl->adc_seq + j];
|
|
}
|
|
}
|
|
} else {
|
|
s16 *s16_src = data;
|
|
s16 *s16_dst = (s16 *)frame->data;
|
|
for (int i = 0; i < len / 2; i++) {
|
|
for (int j = 0; j < hdl->ch_num; j++) {
|
|
s16_dst[hdl->ch_num * i + j] = s16_src[adc_hdl.max_adc_num * i + hdl->adc_seq + j];
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
memcpy(frame->data, data, (len * hdl->ch_num));
|
|
}
|
|
len *= hdl->ch_num;
|
|
if (hdl->mute_en) { //mute ADC
|
|
memset((u8 *)frame->data, 0x0, len);
|
|
}
|
|
if (hdl->output_fade_in) {
|
|
if (adc_hdl.bit_width == ADC_BIT_WIDTH_16) {
|
|
s16 tmp_data;
|
|
s16 *tmp_data_ptr = (s16 *)frame->data;
|
|
/* printf("fade:%d\n",hdl->output_fade_in_gain); */
|
|
for (int i = 0; i < len / 2; i++) {
|
|
tmp_data = tmp_data_ptr[i];
|
|
tmp_data_ptr[i] = tmp_data * hdl->output_fade_in_gain >> 8;
|
|
}
|
|
hdl->output_fade_in_gain += 1;
|
|
if (hdl->output_fade_in_gain >= 256) {
|
|
hdl->output_fade_in = 0;
|
|
}
|
|
} else {
|
|
s32 tmp_data;
|
|
s32 *tmp_data_ptr = (s32 *)frame->data;
|
|
/* printf("fade:%d\n",hdl->output_fade_in_gain); */
|
|
for (int i = 0; i < len / 4; i++) {
|
|
tmp_data = tmp_data_ptr[i];
|
|
tmp_data_ptr[i] = tmp_data * hdl->output_fade_in_gain >> 8;
|
|
}
|
|
hdl->output_fade_in_gain += 1;
|
|
if (hdl->output_fade_in_gain >= 256) {
|
|
hdl->output_fade_in = 0;
|
|
}
|
|
}
|
|
}
|
|
frame->len = len;
|
|
frame->flags = FRAME_FLAG_TIMESTAMP_ENABLE | FRAME_FLAG_PERIOD_SAMPLE | FRAME_FLAG_UPDATE_TIMESTAMP;
|
|
frame->timestamp = audio_jiffies_usec() * TIMESTAMP_US_DENOMINATOR;
|
|
source_plug_put_output_frame(hdl->source_node, frame);
|
|
}
|
|
}
|
|
|
|
static void *linein_init(void *source_node, struct stream_node *node)
|
|
{
|
|
struct linein_file_hdl *hdl = zalloc(sizeof(*hdl));
|
|
hdl->source_node = source_node;
|
|
node->type |= NODE_TYPE_IRQ;
|
|
|
|
for (int i = 0; i < AUDIO_ADC_LINEIN_MAX_NUM; i++) {
|
|
if (linein_cfg_g.mic_en_map & BIT(i)) {
|
|
hdl->ch_num++;
|
|
}
|
|
}
|
|
|
|
adc_file_log("adc ch_num %d\n", hdl->ch_num);
|
|
return hdl;
|
|
}
|
|
|
|
static void adc_ioc_get_fmt(struct linein_file_hdl *hdl, struct stream_fmt *fmt)
|
|
{
|
|
fmt->coding_type = AUDIO_CODING_PCM;
|
|
switch (hdl->ch_num) {
|
|
case 2:
|
|
fmt->sample_rate = 44100;
|
|
fmt->channel_mode = AUDIO_CH_LR;
|
|
break;
|
|
default:
|
|
fmt->sample_rate = 44100;
|
|
fmt->channel_mode = AUDIO_CH_L;
|
|
break;
|
|
}
|
|
hdl->sample_rate = fmt->sample_rate;
|
|
|
|
if (adc_hdl.bit_width == ADC_BIT_WIDTH_24) {
|
|
fmt->bit_wide = DATA_BIT_WIDE_24BIT;
|
|
} else {
|
|
fmt->bit_wide = DATA_BIT_WIDE_16BIT;
|
|
}
|
|
}
|
|
|
|
static int adc_ioc_set_fmt(struct linein_file_hdl *hdl, struct stream_fmt *fmt)
|
|
{
|
|
hdl->sample_rate = fmt->sample_rate;
|
|
return 0;
|
|
}
|
|
|
|
static int linein_file_ioc_update_parm(struct linein_file_hdl *hdl, int parm)
|
|
{
|
|
int ret = false;
|
|
struct linein_file_cfg *cfg = (struct linein_file_cfg *)parm;
|
|
if (hdl) {
|
|
for (int i = 0; i < AUDIO_ADC_LINEIN_MAX_NUM; i++) {
|
|
if (cfg->mic_en_map & BIT(i)) {
|
|
audio_adc_linein_set_gain(&hdl->linein_ch, BIT(i), cfg->param[i].mic_gain);
|
|
audio_adc_linein_gain_boost(BIT(i), cfg->param[i].mic_pre_gain);
|
|
}
|
|
}
|
|
ret = true;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int linein_ioctl(void *_hdl, int cmd, int arg)
|
|
{
|
|
int ret = 0;
|
|
struct linein_file_hdl *hdl = (struct linein_file_hdl *)_hdl;
|
|
switch (cmd) {
|
|
case NODE_IOC_GET_FMT:
|
|
adc_ioc_get_fmt(hdl, (struct stream_fmt *)arg);
|
|
break;
|
|
case NODE_IOC_SET_FMT:
|
|
ret = adc_ioc_set_fmt(hdl, (struct stream_fmt *)arg);
|
|
break;
|
|
case NODE_IOC_SET_PRIV_FMT:
|
|
hdl->irq_points = arg;
|
|
if (!adc_hdl.hw_buf) {
|
|
hdl->adc_buf = zalloc(LINEIN_ADC_BUF_NUM * hdl->irq_points * ((adc_hdl.bit_width == ADC_BIT_WIDTH_16) ? 2 : 4) * adc_hdl.max_adc_num);
|
|
}
|
|
if (!hdl->adc_buf) {
|
|
ret = -1;
|
|
}
|
|
adc_file_log("adc_buf points %d\n", hdl->irq_points);
|
|
break;
|
|
case NODE_IOC_START:
|
|
if (hdl->start == 0) {
|
|
hdl->output_fade_in = 1;
|
|
hdl->start = 1;
|
|
hdl->dump_cnt = 0;
|
|
int linein_en_map = 0;
|
|
for (int i = 0; i < AUDIO_ADC_LINEIN_MAX_NUM; i++) {
|
|
if (linein_cfg_g.mic_en_map & BIT(i)) {
|
|
adc_file_linein_open(&hdl->linein_ch, BIT(i));
|
|
linein_en_map |= BIT(i);
|
|
}
|
|
}
|
|
hdl->adc_seq = get_adc_seq(&adc_hdl, linein_en_map); //查询模拟linein对应的ADC通道
|
|
if (!hdl->adc_buf && !adc_hdl.hw_buf) { //避免没有设置ADC的中断点数,以及数据流stop之后重新start申请buffer
|
|
if (!hdl->irq_points) {
|
|
hdl->irq_points = 256;
|
|
}
|
|
hdl->adc_buf = zalloc(LINEIN_ADC_BUF_NUM * hdl->irq_points * ((adc_hdl.bit_width == ADC_BIT_WIDTH_16) ? 2 : 4) * (adc_hdl.max_adc_num));
|
|
if (!hdl->adc_buf) {
|
|
ret = -1;
|
|
break;
|
|
}
|
|
}
|
|
ret = audio_adc_linein_set_buffs(&hdl->linein_ch, hdl->adc_buf, hdl->irq_points * 2, LINEIN_ADC_BUF_NUM);
|
|
if (ret && hdl->adc_buf) {
|
|
free(hdl->adc_buf);
|
|
hdl->adc_buf = NULL;
|
|
}
|
|
audio_adc_linein_set_sample_rate(&hdl->linein_ch, hdl->sample_rate);
|
|
|
|
hdl->adc_output.priv = hdl;
|
|
hdl->adc_output.handler = adc_linein_output_handler;
|
|
audio_adc_add_output_handler(&adc_hdl, &hdl->adc_output);
|
|
|
|
audio_adc_linein_start(&hdl->linein_ch);
|
|
}
|
|
break;
|
|
case NODE_IOC_SUSPEND:
|
|
case NODE_IOC_STOP:
|
|
if (hdl->start) {
|
|
hdl->start = 0;
|
|
audio_adc_linein_close(&hdl->linein_ch);
|
|
if (!adc_hdl.hw_buf) {
|
|
hdl->adc_buf = NULL; //在adc 驱动中释放了这个buffer
|
|
}
|
|
audio_adc_del_output_handler(&adc_hdl, &hdl->adc_output);
|
|
}
|
|
break;
|
|
case NODE_IOC_SET_PARAM:
|
|
ret = linein_file_ioc_update_parm(hdl, arg);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void linein_release(void *_hdl)
|
|
{
|
|
struct linein_file_hdl *hdl = (struct linein_file_hdl *)_hdl;
|
|
if (hdl->adc_buf) {
|
|
/* free(hdl->adc_buf); */ //由adc 驱动释放buffer
|
|
}
|
|
free(hdl);
|
|
}
|
|
|
|
|
|
REGISTER_SOURCE_NODE_PLUG(linein_file_plug) = {
|
|
.uuid = NODE_UUID_LINEIN,
|
|
.init = linein_init,
|
|
.ioctl = linein_ioctl,
|
|
.release = linein_release,
|
|
};
|
|
|
|
REGISTER_ONLINE_ADJUST_TARGET(linein) = {
|
|
.uuid = NODE_UUID_LINEIN,
|
|
};
|
|
#endif/*TCFG_AUDIO_LINEIN_ENABLE*/
|