467 lines
14 KiB
C
467 lines
14 KiB
C
|
|
#include "board_config.h"
|
|
#include "asm/dac.h"
|
|
#include "audio_common/audio_iis.h"
|
|
#include "media/includes.h"
|
|
#include "effectrs_sync.h"
|
|
#include "asm/gpio.h"
|
|
|
|
|
|
extern struct audio_dac_hdl dac_hdl;
|
|
extern int bt_media_sync_master(u8 type);
|
|
extern u8 bt_media_device_online(u8 dev);
|
|
extern void *bt_media_sync_open(void);
|
|
extern void bt_media_sync_close(void *);
|
|
extern int bt_send_audio_sync_data(void *, void *buf, u32 len);
|
|
extern void bt_media_sync_set_handler(void *, void *priv,
|
|
void (*event_handler)(void *, int *, int));
|
|
extern u32 get_bt_slot_time(u8 type, u32 time, int *ret_time, int (*local_us_time)(void));
|
|
|
|
|
|
const static struct audio_tws_conn_ops tws_conn_ops = {
|
|
.open = bt_media_sync_open,
|
|
.set_handler = bt_media_sync_set_handler,
|
|
.close = bt_media_sync_close,
|
|
.master = bt_media_sync_master,
|
|
.online = bt_media_device_online,
|
|
.send = bt_send_audio_sync_data,
|
|
};
|
|
|
|
extern struct audio_dac_channel default_dac;
|
|
struct audio_wireless_sync *a2dp_output_sync_open(int sample_rate, int output_sample_rate, u8 channels)
|
|
{
|
|
struct audio_wireless_sync_info info = {0};
|
|
struct audio_sample_sync *sample_sync;
|
|
struct audio_wireless_sync *a2dp_sync;
|
|
|
|
a2dp_sync = (struct audio_wireless_sync *)zalloc(sizeof(struct audio_wireless_sync));
|
|
if (!a2dp_sync) {
|
|
return NULL;
|
|
}
|
|
|
|
sample_sync = audio_sample_sync_open(0);
|
|
|
|
/*选择SYNC模块接入到DAC内部*/
|
|
/*audio_dac_add_sample_sync(&dac_hdl, sample_sync, 1);*/
|
|
|
|
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_IIS)
|
|
audio_iis_channel_sync_enable(sample_sync);
|
|
info.target = AUDIO_SYNC_TARGET_IIS;
|
|
#else
|
|
audio_dac_channel_sync_enable(&default_dac, sample_sync);
|
|
info.target = AUDIO_SYNC_TARGET_DAC;
|
|
#endif
|
|
|
|
info.tws_ops = &tws_conn_ops;
|
|
info.sample_ch = sample_sync;
|
|
info.protocol = WL_PROTOCOL_RTP;
|
|
info.sample_rate = sample_rate;
|
|
info.output_rate = output_sample_rate;
|
|
info.channel = channels;
|
|
|
|
a2dp_sync->context = audio_wireless_sync_open(&info, &a2dp_sync->entry);
|
|
|
|
a2dp_sync->sample_sync = sample_sync;
|
|
a2dp_sync->resample_entry = &sample_sync->entry;
|
|
|
|
return a2dp_sync;
|
|
}
|
|
|
|
void a2dp_output_sync_close(struct audio_wireless_sync *a2dp_sync)
|
|
{
|
|
if (a2dp_sync) {
|
|
audio_stream_del_entry(a2dp_sync->entry);
|
|
audio_stream_del_entry(a2dp_sync->resample_entry);
|
|
audio_wireless_sync_close(a2dp_sync->context);
|
|
/*audio_dac_remove_sample_sync(&dac_hdl, a2dp_sync->sample_sync);*/
|
|
|
|
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_IIS)
|
|
audio_iis_channel_sync_disable(a2dp_sync->sample_sync);
|
|
#else
|
|
audio_dac_channel_sync_disable(&default_dac, a2dp_sync->sample_sync);
|
|
#endif
|
|
|
|
audio_sample_sync_close(a2dp_sync->sample_sync);
|
|
free(a2dp_sync);
|
|
}
|
|
}
|
|
|
|
struct audio_wireless_sync *esco_output_sync_open(int sample_rate, int output_sample_rate, u8 channels)
|
|
{
|
|
struct audio_wireless_sync_info info = {0};
|
|
struct audio_sample_sync *sample_sync;
|
|
struct audio_wireless_sync *esco_sync;
|
|
|
|
esco_sync = (struct audio_wireless_sync *)zalloc(sizeof(struct audio_wireless_sync));
|
|
if (!esco_sync) {
|
|
return NULL;
|
|
}
|
|
|
|
sample_sync = audio_sample_sync_open(0);
|
|
|
|
/*选择SYNC模块接入到DAC内部*/
|
|
/*audio_dac_add_sample_sync(&dac_hdl, sample_sync, 1);*/
|
|
|
|
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_IIS)
|
|
audio_iis_channel_sync_enable(sample_sync);
|
|
info.target = AUDIO_SYNC_TARGET_IIS;
|
|
#else
|
|
audio_dac_channel_sync_enable(&default_dac, sample_sync);
|
|
info.target = AUDIO_SYNC_TARGET_DAC;
|
|
#endif
|
|
|
|
info.tws_ops = &tws_conn_ops;
|
|
info.sample_ch = sample_sync;
|
|
info.protocol = WL_PROTOCOL_SCO;
|
|
info.sample_rate = sample_rate;
|
|
info.output_rate = output_sample_rate;
|
|
info.channel = channels;
|
|
|
|
esco_sync->context = audio_wireless_sync_open(&info, &esco_sync->entry);
|
|
|
|
esco_sync->sample_sync = sample_sync;
|
|
esco_sync->resample_entry = &sample_sync->entry;
|
|
|
|
return esco_sync;
|
|
}
|
|
|
|
void esco_output_sync_close(struct audio_wireless_sync *esco_sync)
|
|
{
|
|
if (esco_sync) {
|
|
audio_stream_del_entry(esco_sync->entry);
|
|
audio_stream_del_entry(esco_sync->resample_entry);
|
|
audio_wireless_sync_close(esco_sync->context);
|
|
|
|
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_IIS)
|
|
audio_iis_channel_sync_disable(esco_sync->sample_sync);
|
|
#else
|
|
audio_dac_channel_sync_disable(&default_dac, esco_sync->sample_sync);
|
|
#endif
|
|
|
|
/*audio_dac_remove_sample_sync(&dac_hdl, esco_sync->sample_sync);*/
|
|
audio_sample_sync_close(esco_sync->sample_sync);
|
|
free(esco_sync);
|
|
}
|
|
}
|
|
|
|
#if TCFG_DEC2TWS_ENABLE
|
|
|
|
#include "classic/tws_api.h"
|
|
|
|
extern int tws_api_local_media_trans_get_total_buffer_size(void);
|
|
|
|
extern u8 is_tws_active_device(void);
|
|
|
|
static u8 local_tws_media_sync_no_check = 0;
|
|
void local_tws_sync_no_check_data_buf(u8 no_check)
|
|
{
|
|
local_tws_media_sync_no_check = no_check;
|
|
}
|
|
|
|
u8 local_tws_sync_no_check_data_buf_status(void)
|
|
{
|
|
return local_tws_media_sync_no_check;
|
|
}
|
|
|
|
int local_bt_media_sync_master(u8 type)
|
|
{
|
|
int state = tws_api_get_tws_state();
|
|
if (!(state & TWS_STA_SIBLING_CONNECTED)) {
|
|
return 1;
|
|
}
|
|
return is_tws_active_device() ? 1 : 0;
|
|
}
|
|
|
|
u8 local_bt_media_device_online(u8 type)
|
|
{
|
|
return bt_media_device_online(type);
|
|
}
|
|
|
|
const static struct audio_tws_conn_ops local_tws_conn_ops = {
|
|
.open = bt_media_sync_open,
|
|
.set_handler = bt_media_sync_set_handler,
|
|
.close = bt_media_sync_close,
|
|
.master = local_bt_media_sync_master,
|
|
.online = local_bt_media_device_online,
|
|
.send = bt_send_audio_sync_data,
|
|
};
|
|
|
|
struct audio_wireless_sync *audio_localtws_sync_open(int sample_rate, int output_sample_rate, u8 channels)
|
|
{
|
|
struct audio_wireless_sync_info info = {0};
|
|
struct audio_sample_sync *sample_sync;
|
|
struct audio_wireless_sync *localtws_sync;
|
|
|
|
localtws_sync = (struct audio_wireless_sync *)zalloc(sizeof(struct audio_wireless_sync));
|
|
if (!localtws_sync) {
|
|
return NULL;
|
|
}
|
|
|
|
sample_sync = audio_sample_sync_open(0);
|
|
/*选择SYNC模块接入到DAC内部*/
|
|
/*audio_dac_add_sample_sync(&dac_hdl, sample_sync, 1);*/
|
|
|
|
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_IIS)
|
|
audio_iis_channel_sync_enable(sample_sync);
|
|
info.target = AUDIO_SYNC_TARGET_IIS;
|
|
#else
|
|
audio_dac_channel_sync_enable(&default_dac, sample_sync);
|
|
info.target = AUDIO_SYNC_TARGET_DAC;
|
|
#endif
|
|
|
|
info.tws_ops = &local_tws_conn_ops;
|
|
info.sample_ch = sample_sync;
|
|
info.protocol = WL_PROTOCOL_RTP;
|
|
info.sample_rate = sample_rate;
|
|
info.output_rate = output_sample_rate;
|
|
info.channel = channels;
|
|
|
|
localtws_sync->context = audio_wireless_sync_open(&info, &localtws_sync->entry);
|
|
|
|
localtws_sync->sample_sync = sample_sync;
|
|
localtws_sync->resample_entry = &sample_sync->entry;
|
|
|
|
return localtws_sync;
|
|
}
|
|
|
|
void audio_localtws_sync_close(struct audio_wireless_sync *localtws_sync)
|
|
{
|
|
if (localtws_sync) {
|
|
audio_stream_del_entry(localtws_sync->resample_entry);
|
|
audio_stream_del_entry(localtws_sync->entry);
|
|
audio_wireless_sync_close(localtws_sync->context);
|
|
/*audio_dac_remove_sample_sync(&dac_hdl, localtws_sync->sample_sync);*/
|
|
|
|
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_IIS)
|
|
audio_iis_channel_sync_disable(localtws_sync->sample_sync);
|
|
#else
|
|
audio_dac_channel_sync_disable(&default_dac, localtws_sync->sample_sync);
|
|
#endif
|
|
audio_sample_sync_close(localtws_sync->sample_sync);
|
|
free(localtws_sync);
|
|
}
|
|
}
|
|
#if 0
|
|
void *local_tws_play_sync_open(struct audio_decoder *dec, u8 channel, u32 sample_rate, u32 output_rate)
|
|
{
|
|
struct audio_wireless_sync_info sync_param;
|
|
/*int total_size = tws_api_local_media_trans_get_total_buffer_size();*/
|
|
|
|
sync_param.channel = channel;
|
|
sync_param.tws_ops = &local_tws_conn_ops;
|
|
sync_param.sample_rate = sample_rate;
|
|
sync_param.output_rate = output_rate;
|
|
sync_param.reset_enable = 0;
|
|
|
|
#if 0
|
|
if (local_tws_media_sync_no_check) {
|
|
sync_param.data_top = total_size;
|
|
sync_param.data_bottom = 0;
|
|
} else {
|
|
sync_param.data_top = 70 * total_size / 100;
|
|
sync_param.data_bottom = 60 * total_size / 100;
|
|
}
|
|
sync_param.begin_size = 50 * total_size / 100;
|
|
sync_param.tws_together_time = SYNC_START_TIME;
|
|
printf("tws sync begin:%d, top:%d, bottom:%d \n", sync_param.begin_size, sync_param.data_top, sync_param.data_bottom);
|
|
#endif
|
|
|
|
sync_param.protocol = WL_PROTOCOL_RTP;
|
|
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_FM)
|
|
sync_param.target = AUDIO_SYNC_TARGET_FM;
|
|
sync_param.dev = NULL;
|
|
#else
|
|
sync_param.target = AUDIO_SYNC_TARGET_DAC;
|
|
sync_param.dev = &dac_hdl;
|
|
#endif
|
|
|
|
return audio_wireless_sync_open(&sync_param);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_FM)
|
|
#define FM_EMIT_BOTTOM 40
|
|
#define FM_EMIT_TOP 70
|
|
#define MAX_STEP 5
|
|
#define ONE_STEP_SIZE 512
|
|
|
|
#define FM_SYNC_SRC_OUTPUT_SIZE (256 + 16)
|
|
#define FM_SYNC_SRC_INPUT_SIZE (256)
|
|
#define MAX_COUNT_FOR_ADJUST 1
|
|
#define MAX_ADJUST_STEP 20
|
|
#define ABS(x) (x > 0 ? x : (-x))
|
|
|
|
struct local_fm_sync_handle {
|
|
int top_size;
|
|
int bottom_size;
|
|
u16 sample_rate;
|
|
u16 out_rate;
|
|
u16 base_out_rate;
|
|
u8 channel;
|
|
s8 step_dir_count;
|
|
void *src;
|
|
void *output_addr;
|
|
void *input_addr;
|
|
int output_len;
|
|
};
|
|
|
|
static int local_fm_sync_event_handler(void *priv, enum audio_src_event event, void *arg)
|
|
{
|
|
struct local_fm_sync_handle *fm_sync = (struct local_fm_sync_handle *)priv;
|
|
struct audio_src_buffer *b = (struct audio_src_buffer *)arg;
|
|
|
|
switch (event) {
|
|
case SRC_EVENT_GET_OUTPUT_BUF:
|
|
b->addr = fm_sync->output_addr;
|
|
b->len = FM_SYNC_SRC_OUTPUT_SIZE;
|
|
break;
|
|
case SRC_EVENT_OUTPUT_DONE:
|
|
case SRC_EVENT_INPUT_DONE:
|
|
case SRC_EVENT_ALL_DONE:
|
|
ASSERT(b->len < FM_SYNC_SRC_OUTPUT_SIZE, ", fm sync output err : %d\n", b->len);
|
|
fm_sync->output_len = b->len;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void *local_fm_sync_open(u16 sample_rate, u16 output_rate, u8 channel, u32 total_size)
|
|
{
|
|
struct local_fm_sync_handle *fm_sync;
|
|
|
|
fm_sync = (struct local_fm_sync_handle *)zalloc(sizeof(struct local_fm_sync_handle));
|
|
if (!fm_sync) {
|
|
return NULL;
|
|
}
|
|
|
|
fm_sync->top_size = total_size * FM_EMIT_TOP / 100;
|
|
fm_sync->bottom_size = total_size * FM_EMIT_BOTTOM / 100;
|
|
fm_sync->sample_rate = sample_rate;
|
|
fm_sync->out_rate = output_rate;
|
|
fm_sync->base_out_rate = output_rate;
|
|
fm_sync->channel = channel;
|
|
if (!fm_sync->src) {
|
|
fm_sync->src = zalloc(sizeof(struct audio_src_base_handle));
|
|
|
|
if (!fm_sync->src) {
|
|
goto __err;
|
|
}
|
|
}
|
|
fm_sync->input_addr = zalloc(FM_SYNC_SRC_INPUT_SIZE);
|
|
if (!fm_sync->input_addr) {
|
|
goto __err1;
|
|
}
|
|
fm_sync->output_addr = zalloc(FM_SYNC_SRC_OUTPUT_SIZE);
|
|
if (!fm_sync->output_addr) {
|
|
goto __err2;
|
|
}
|
|
|
|
audio_src_base_open(fm_sync->src, channel, SRC_TYPE_AUDIO_SYNC);
|
|
|
|
audio_src_base_set_rate(fm_sync->src, sample_rate, sample_rate);
|
|
|
|
audio_src_base_set_event_handler(fm_sync->src, fm_sync, local_fm_sync_event_handler);
|
|
|
|
audio_src_base_set_input_buff(fm_sync->src, fm_sync->input_addr, FM_SYNC_SRC_INPUT_SIZE);
|
|
|
|
return fm_sync;
|
|
|
|
__err2:
|
|
free(fm_sync->input_addr);
|
|
__err1:
|
|
free(fm_sync->src);
|
|
__err:
|
|
free(fm_sync);
|
|
return NULL;
|
|
}
|
|
|
|
int local_fm_sync_by_emitter(void *sync, void *data, int len, int emitter_data_len)
|
|
{
|
|
struct local_fm_sync_handle *fm_sync = (struct local_fm_sync_handle *)sync;
|
|
int diff = 0;
|
|
s8 step = 0;
|
|
|
|
if (emitter_data_len < fm_sync->bottom_size) {
|
|
diff = fm_sync->bottom_size - emitter_data_len;
|
|
step = 1;
|
|
} else if (emitter_data_len > fm_sync->top_size) {
|
|
diff = fm_sync->top_size - emitter_data_len;
|
|
step = -1;
|
|
} else {
|
|
if (fm_sync->out_rate < fm_sync->base_out_rate) {
|
|
step = 1;
|
|
} else if (fm_sync->out_rate > fm_sync->base_out_rate) {
|
|
step = -1;
|
|
}
|
|
}
|
|
|
|
step += diff / 512;
|
|
if (step < 0) {
|
|
fm_sync->step_dir_count--;
|
|
} else if (step > 0) {
|
|
fm_sync->step_dir_count++;
|
|
} else {
|
|
if (fm_sync->step_dir_count < 0) {
|
|
fm_sync->step_dir_count++;
|
|
} else if (fm_sync->step_dir_count > 0) {
|
|
fm_sync->step_dir_count--;
|
|
}
|
|
}
|
|
|
|
if (ABS(fm_sync->step_dir_count) >= MAX_COUNT_FOR_ADJUST) {
|
|
fm_sync->out_rate += step;
|
|
if (fm_sync->out_rate < fm_sync->base_out_rate - MAX_ADJUST_STEP) {
|
|
fm_sync->out_rate = fm_sync->base_out_rate - MAX_ADJUST_STEP;
|
|
} else if (fm_sync->out_rate > fm_sync->base_out_rate + MAX_ADJUST_STEP) {
|
|
fm_sync->out_rate = fm_sync->base_out_rate + MAX_ADJUST_STEP;
|
|
}
|
|
/*printf("--%d--\n", fm_sync->out_rate);*/
|
|
audio_src_base_set_rate(fm_sync->src, fm_sync->sample_rate, fm_sync->out_rate);
|
|
fm_sync->step_dir_count = 0;
|
|
}
|
|
|
|
audio_src_base_write(fm_sync->src, data, len);
|
|
audio_src_base_data_flush_out(fm_sync->src);
|
|
|
|
/*printf("%d - %d - %d\n", len, fm_sync->output_len, step);*/
|
|
return fm_sync->output_len;
|
|
}
|
|
|
|
void *local_fm_sync_output_addr(void *sync)
|
|
{
|
|
struct local_fm_sync_handle *fm_sync = (struct local_fm_sync_handle *)sync;
|
|
|
|
return fm_sync->output_addr;
|
|
}
|
|
|
|
void local_fm_sync_close(void *sync)
|
|
{
|
|
struct local_fm_sync_handle *fm_sync = (struct local_fm_sync_handle *)sync;
|
|
if (!fm_sync) {
|
|
return;
|
|
}
|
|
|
|
if (fm_sync->src) {
|
|
audio_src_base_stop(fm_sync->src);
|
|
audio_src_base_close(fm_sync->src);
|
|
free(fm_sync->src);
|
|
}
|
|
|
|
if (fm_sync->input_addr) {
|
|
free(fm_sync->input_addr);
|
|
}
|
|
|
|
if (fm_sync->output_addr) {
|
|
free(fm_sync->output_addr);
|
|
}
|
|
|
|
free(fm_sync);
|
|
}
|
|
|
|
#endif
|