1999 lines
50 KiB
C
Raw Normal View History

#include "system/includes.h"
#include "media/includes.h"
#include "tone_player.h"
#include "audio_config.h"
#include "app_main.h"
#include "btstack/avctp_user.h"
#include "aec_user.h"
#include "audio_digital_vol.h"
#include "audio_codec_clock.h"
#ifdef SUPPORT_MS_EXTENSIONS
#pragma const_seg( ".app_tone_const")
#pragma code_seg( ".app_tone_code")
#endif
#if TCFG_APP_FM_EMITTER_EN
#include "fm_emitter/fm_emitter_manage.h"
#endif
#ifdef CONFIG_LITE_AUDIO
#include "tone_player_api.h"
#endif /*CONFIG_LITE_AUDIO*/
#define LOG_TAG_CONST APP_TONE
#define LOG_TAG "[APP-TONE]"
#define LOG_ERROR_ENABLE
#define LOG_INFO_ENABLE
#define LOG_DUMP_ENABLE
#include "debug.h"
#define TONE_LIST_MAX_NUM 4
#if TCFG_USER_TWS_ENABLE
#include "media/bt_audio_timestamp.h"
#include "audio_syncts.h"
#include "bt_tws.h"
#define msecs_to_bt_time(m) (((m + 1)* 1000) / 625)
#define TWS_TONE_ALIGN_TIME 0
#define TWS_TONE_ALIGN_MIX 1
#define TONE_DEC_NOT_START 0
#define TONE_DEC_WAIT_ALIGN_TIME 1
#define TONE_DEC_WAIT_MIX 2
#define TONE_DEC_CONFIRM 3
#define TWS_TONE_CONFIRM_TIME 250 /*TWS提示音音频同步确认时间(也是音频解码主从确认超时时间)*/
#endif
#if TCFG_WAV_TONE_MIX_ENABLE
#define TONE_FILE_DEC_MIX TONE_WAV_MIX_EN
#else
#define TONE_FILE_DEC_MIX TONE_WTG_MIX_EN
#endif/*TCFG_WAV_TONE_MIX_ENABLE*/
#if !AUDIO_OUT_MIXER_ENABLE
#undef TONE_FILE_DEC_MIX
#define TONE_FILE_DEC_MIX 0
void audio_syncts_add(void *priv);
void audio_syncts_del(void *priv);
extern int audio_output_data(s16 *data, u16 len);
extern void audio_output_open(void *priv, u32 sample_rate);
extern void audio_output_close(void *priv);
#endif /*AUDIO_OUT_MIXER_ENABLE*/
#ifdef CONFIG_256K_FLASH
#define CONFIG_MINI_TONEPLAY_ENABLE 1
#else
#define CONFIG_MINI_TONEPLAY_ENABLE 0
#endif
static OS_MUTEX tone_mutex;
struct tone_file_handle {
u8 start;
u8 idx;
u8 repeat_begin;
u8 remain;
u8 tws;
u16 loop;
u32 magic;
void *file;
const char **list;
enum audio_channel channel;
struct audio_decoder decoder;
#if AUDIO_OUT_MIXER_ENABLE
struct audio_mixer_ch mix_ch;
#endif
u8 ch_num;
u16 target_sample_rate;
#if TCFG_USER_TWS_ENABLE
u32 wait_time;
u8 tws_align_step;
u8 ts_start;
void *audio_sync;
void *syncts;
void *ts_handle;
u32 time_base;
#endif
u32 mix_ch_event_params[3];
struct audio_src_handle *hw_src;
u32 clk_before_dec;
u8 dec_mix;
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
dvol_handle *dvol;
#endif
};
struct tone_sine_handle {
u8 start;
u8 repeat;
u32 sine_id;
u32 sine_offset;
void *sin_maker;
struct audio_decoder decoder;
#if AUDIO_OUT_MIXER_ENABLE
struct audio_mixer_ch mix_ch;
#endif
struct sin_param sin_dynamic_params[8];
u32 clk_before;
u8 dec_mix;
u8 remain;
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
dvol_handle *dvol;
#endif
};
struct tone_dec_handle {
u8 r_index;
u8 w_index;
u8 list_cnt;
u8 preemption;
const char **list[4];
struct audio_res_wait wait;
u8 dec_mix;
const char *user_evt_owner;
void (*user_evt_handler)(void *priv);
void *priv;
};
extern struct audio_mixer mixer;
extern struct audio_dac_hdl dac_hdl;
extern struct audio_decoder_task decode_task;
static struct tone_file_handle *file_dec;
static struct tone_sine_handle *sine_dec;
static char *single_file[2] = {NULL};
struct tone_dec_handle *tone_dec;
int sine_dec_close(void);
int tone_file_dec_start();
u16 get_source_sample_rate();
extern void audio_mix_ch_event_handler(void *priv, int event);
extern int bt_audio_sync_nettime_select(u8 basetime);
extern u32 bt_audio_sync_lat_time(void);
static void file_decoder_syncts_free(struct tone_file_handle *dec);
void tone_event_to_user(u8 event, const char *name);
void tone_event_clear()
{
struct sys_event e = {0};
e.type = SYS_DEVICE_EVENT;
e.arg = (void *)DEVICE_EVENT_FROM_TONE;
sys_event_clear(&e);
}
void tone_set_user_event_handler(struct tone_dec_handle *dec, void (*user_evt_handler)(void *priv), void *priv)
{
printf("tone_set_user_event_handler:%d\n", *(u8 *)priv);
dec->user_evt_owner = os_current_task();
dec->user_evt_handler = user_evt_handler;
dec->priv = priv;
}
int tone_event_handler(struct tone_dec_handle *dec, u8 end_flag)
{
int argv[4];
if (!dec->user_evt_handler) {
/* log_info("user_evt_handler null\n"); */
return -1;
}
if (strcmp(os_current_task(), dec->user_evt_owner) == 0) {
dec->user_evt_handler(dec->priv);
return 0;
}
/* dec->user_evt_handler(dec->priv); */
argv[0] = (int)dec->user_evt_handler;
argv[1] = 1;
argv[2] = (int)dec->priv;
argv[3] = (int)end_flag;//是否是被打断 关闭0正常关闭1被打断关闭, 模式切换时由file_dec->end_flag, 决定该值
return os_taskq_post_type(dec->user_evt_owner, Q_CALLBACK, 4, argv);
/* return 0; */
}
__attribute__((weak))
int audio_dac_stop(struct audio_dac_hdl *p)
{
return 0;
}
__attribute__((weak))
int audio_dac_write(struct audio_dac_hdl *dac, void *data, int len)
{
return len;
}
__attribute__((weak))
int audio_dac_get_sample_rate(struct audio_dac_hdl *p)
{
return 16000;
}
__attribute__((weak))
void audio_dac_clear(struct audio_dac_hdl *dac)
{
}
static u8 tone_dec_idle_query()
{
if (file_dec || sine_dec) {
return 0;
}
return 1;
}
REGISTER_LP_TARGET(tone_dec_lp_target) = {
.name = "tone_dec",
.is_idle = tone_dec_idle_query,
};
#if TCFG_USER_TWS_ENABLE
#define bt_time_before(t1, t2) \
(((t1 < t2) && ((t2 - t1) & 0x7ffffff) < 0xffff) || \
((t1 > t2) && ((t1 - t2) & 0x7ffffff) > 0xffff))
#define TWS_FUNC_ID_TONE_ALIGN \
(((u8)('T' + 'O' + 'N' + 'E') << (2 * 8)) | \
((u8)('P' + 'L' + 'A' + 'Y' + 'E' + 'R') << (1 * 8)) | \
((u8)('S' + 'Y' + 'N' + 'C') << (0 * 8)))
struct tws_tone_align {
u8 confirm;
u8 type;
union {
int time;
int position;
};
};
struct tws_tone_align tws_tone = {0};
/*static u8 tws_tone_align = 0;*/
/*static int tws_tone_align_time = 0;*/
static void tws_tone_play_rx_align_data(void *data, u16 len, bool rx)
{
local_irq_disable();
memcpy(&tws_tone, data, sizeof(tws_tone));
tws_tone.confirm = 1;
local_irq_enable();
y_printf("tone tws confirm rx : %d\n", tws_tone.time);
}
REGISTER_TWS_FUNC_STUB(tone_play_align) = {
.func_id = TWS_FUNC_ID_TONE_ALIGN,
.func = tws_tone_play_rx_align_data,
};
#if AUDIO_OUT_MIXER_ENABLE
static void tone_mixer_ch_event_handler(void *priv, int event)
{
struct tone_file_handle *dec = (struct tone_file_handle *)priv;
switch (event) {
case MIXER_EVENT_CH_OPEN:
break;
case MIXER_EVENT_CH_CLOSE:
case MIXER_EVENT_CH_RESET:
break;
default:
break;
}
}
#endif
#endif
void tone_event_to_user(u8 event, const char *name)
{
struct sys_event e;
e.type = SYS_DEVICE_EVENT;
e.arg = (void *)DEVICE_EVENT_FROM_TONE;
e.u.dev.event = event;
e.u.dev.value = (int)name;
sys_event_notify(&e);
}
static char *get_file_ext_name(char *name)
{
int len = strlen(name);
char *ext = (char *)name;
while (len--) {
if (*ext++ == '.') {
break;
}
}
return ext;
}
struct audio_dec_input tone_input;
static void tone_file_dec_release()
{
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
if ((tone_input.coding_type == AUDIO_CODING_WAV) && (tone_dec->preemption == 0)) {
audio_digital_vol_bg_fade(0);
}
audio_digital_vol_close(file_dec->dvol);
file_dec->dvol = NULL;
#endif
free(file_dec);
file_dec = NULL;
}
int tone_list_play_start(const char **list, u8 preemption, u8 tws);
static int tone_file_list_clean(u8 decoding)
{
int i = 0;
if (!tone_dec) {
return 0;
}
for (i = 0; i < TONE_LIST_MAX_NUM; i++) {
if (tone_dec->list[i]) {
if (decoding && i == tone_dec->r_index) {
continue;
}
free(tone_dec->list[i]);
tone_dec->list[i] = NULL;
}
}
if (decoding) {
tone_dec->w_index = tone_dec->r_index + 1;
if (tone_dec->w_index >= TONE_LIST_MAX_NUM) {
tone_dec->w_index = 0;
}
tone_dec->list_cnt = 1;
} else {
tone_dec->list_cnt = 0;
}
return 0;
}
void tone_dec_release()
{
if (!tone_dec) {
os_mutex_post(&tone_mutex);
return;
}
tone_event_handler(tone_dec, 0);
audio_decoder_task_del_wait(&decode_task, &tone_dec->wait);
tone_file_list_clean(0);
free(tone_dec);
tone_dec = NULL;
os_mutex_post(&tone_mutex);
}
void tone_dec_end_handler(int event, const char *name)
{
const char **list;
list = tone_dec->list[tone_dec->r_index];
if (++tone_dec->r_index >= TONE_LIST_MAX_NUM) {
tone_dec->r_index = 0;
}
if (--tone_dec->list_cnt > 0) {
tone_list_play_start(tone_dec->list[tone_dec->r_index], tone_dec->preemption, 1);
} else {
tone_dec_release();
}
tone_event_to_user(event, name);
}
static int tone_file_list_repeat(struct audio_decoder *decoder)
{
int err = 0;
file_dec->idx++;
if (!file_dec->list[file_dec->idx]) {
log_info("repeat end 1:idx end");
return 0;
}
if (IS_REPEAT_END(file_dec->list[file_dec->idx])) {
//log_info("repeat_loop:%d",file_dec->loop);
if (file_dec->loop) {
file_dec->loop--;
file_dec->idx = file_dec->repeat_begin;
} else {
file_dec->idx++;
if (!file_dec->list[file_dec->idx]) {
log_info("repeat end 2:idx end");
return 0;
}
}
}
if (IS_REPEAT_BEGIN(file_dec->list[file_dec->idx])) {
if (!file_dec->loop) {
file_dec->loop = TONE_REPEAT_COUNT(file_dec->list[file_dec->idx]);
log_info("repeat begin:%d", file_dec->loop);
}
file_dec->idx++;
file_dec->repeat_begin = file_dec->idx;
}
log_info("repeat idx:%d,%s", file_dec->idx, file_dec->list[file_dec->idx]);
file_dec->file = fopen(file_dec->list[file_dec->idx], "r");
if (!file_dec->file) {
log_error("repeat end:fopen repeat file faild");
return 0;
}
return 1;
}
static int tone_audio_res_close(u8 rpt)
{
if (file_dec->start) {
audio_decoder_close(&file_dec->decoder);
}
if (file_dec->hw_src) {
audio_hw_src_stop(file_dec->hw_src);
audio_hw_src_close(file_dec->hw_src);
free(file_dec->hw_src);
file_dec->hw_src = NULL;
}
if (file_dec->start) {
#if AUDIO_OUT_MIXER_ENABLE
audio_mixer_ch_close(&file_dec->mix_ch);
#else
audio_output_close(NULL);
#if TCFG_USER_TWS_ENABLE
if (file_dec->syncts) {
u32 mix_ch_event_params[3] = {0};
mix_ch_event_params[1] = (u32)file_dec->syncts;
audio_syncts_del(mix_ch_event_params);
}
#endif
#endif
file_dec->start = 0;
}
#if TCFG_USER_TWS_ENABLE
file_decoder_syncts_free(file_dec);
#endif
if (!rpt) {
if (app_audio_get_state() == APP_AUDIO_STATE_WTONE) {
app_audio_state_exit(APP_AUDIO_STATE_WTONE);
}
}
return 0;
}
static void tone_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
{
int repeat = 0;
switch (argv[0]) {
case AUDIO_DEC_EVENT_END:
case AUDIO_DEC_EVENT_ERR:
if (argv[1] != file_dec->magic) {
log_error("file_dec magic no match:%d-%d", argv[1], file_dec->magic);
break;
}
repeat = tone_file_list_repeat(decoder);
log_info("AUDIO_DEC_EVENT_END,err=%x,repeat=%d\n", argv[0], repeat);
if (repeat) {
tone_audio_res_close(repeat);
tone_file_dec_start();
} else {
tone_file_list_stop(0);
}
break;
default:
return;
}
}
int tone_get_status()
{
return tone_dec ? TONE_START : TONE_STOP;
}
int tone_get_dec_status()
{
if (tone_dec && file_dec && (file_dec->decoder.state != DEC_STA_WAIT_STOP)) {
return TONE_START;
}
if (tone_dec && sine_dec && (sine_dec->decoder.state != DEC_STA_WAIT_STOP)) {
return TONE_START;
}
return TONE_STOP;
}
int tone_dec_wait_stop(u32 timeout_ms)
{
u32 to_cnt = 0;
while (tone_get_dec_status()) {
/* putchar('t'); */
os_time_dly(1);
if (timeout_ms) {
to_cnt += 10;
if (to_cnt >= timeout_ms) {
break;
}
}
}
return tone_get_dec_status();
}
static int tone_fread(struct audio_decoder *decoder, void *buf, u32 len)
{
int rlen = 0;
if (!file_dec->file) {
return 0;
}
rlen = fread(file_dec->file, buf, len);
if (rlen < len) {
fclose(file_dec->file);
file_dec->file = NULL;
}
return rlen;
}
static int tone_fseek(struct audio_decoder *decoder, u32 offset, int seek_mode)
{
if (!file_dec->file) {
return 0;
}
return fseek(file_dec->file, offset, seek_mode);
}
static int tone_flen(struct audio_decoder *decoder)
{
void *tone_file = NULL;
int len = 0;
if (file_dec->file) {
len = flen(file_dec->file);
return len;
}
tone_file = fopen(file_dec->list[file_dec->idx], "r");
if (tone_file) {
len = flen(tone_file);
fclose(tone_file);
tone_file = NULL;
}
return len;
}
static int tone_fclose(void *file)
{
if (file_dec->file) {
fclose(file_dec->file);
file_dec->file = NULL;
}
file_dec->idx = 0;
return 0;
}
struct tone_format {
const char *fmt;
u32 coding_type;
};
const struct tone_format tone_fmt_support_list[] = {
{"wtg", AUDIO_CODING_G729},
{"msbc", AUDIO_CODING_MSBC},
{"sbc", AUDIO_CODING_SBC},
{"mty", AUDIO_CODING_MTY},
{"aac", AUDIO_CODING_AAC},
#if TCFG_DEC_WTGV2_ENABLE
{"wts", AUDIO_CODING_WTGV2},
#endif/*TCFG_DEC_WTGV2_ENABLE*/
#if TCFG_DEC_SPEEX_ENABLE
{"speex", AUDIO_CODING_SPEEX},
#endif
#if TCFG_DEC_OPUS_ENABLE
{"opus", AUDIO_CODING_OPUS},
#endif
#if TCFG_DEC_MP3_ENABLE
{"mp3", AUDIO_CODING_MP3},
#endif/*TCFG_DEC_MP3_ENABLE*/
#if (TCFG_WAV_TONE_MIX_ENABLE || TCFG_DEC_WAV_ENABLE)
{"wav", AUDIO_CODING_WAV},
#endif
};
static struct audio_dec_input tone_input = {
.coding_type = AUDIO_CODING_G729,
.data_type = AUDIO_INPUT_FILE,
.ops = {
.file = {
.fread = tone_fread,
.fseek = tone_fseek,
.flen = tone_flen,
}
}
};
static u32 tone_file_format_match(char *fmt)
{
int list_num = ARRAY_SIZE(tone_fmt_support_list);
int i = 0;
if (fmt == NULL) {
return AUDIO_CODING_UNKNOW;
}
for (i = 0; i < list_num; i++) {
if (ASCII_StrCmpNoCase(fmt, tone_fmt_support_list[i].fmt, 4) == 0) {
return tone_fmt_support_list[i].coding_type;
}
}
return AUDIO_CODING_UNKNOW;
}
static int tone_dec_probe_handler(struct audio_decoder *decoder)
{
struct tone_file_handle *dec = container_of(decoder, struct tone_file_handle, decoder);
int err = 0;
#if TCFG_USER_TWS_ENABLE
if (dec->tws_align_step == 0 && dec->ts_handle) {
if (!tws_file_timestamp_available(dec->ts_handle)) {
audio_decoder_suspend(decoder, 0);
return -EINVAL;
}
dec->tws_align_step = 1;
}
#endif
return 0;
}
int audio_output_data_tone(void *p, s16 *data, u16 len)
{
#if TCFG_USER_TWS_ENABLE
#if !AUDIO_OUT_MIXER_ENABLE
struct tone_file_handle *dec = p;
if ((dec->ts_start == 1) && dec->syncts) {
dec->ts_start = 2;
audio_output_open(NULL, dec->decoder.fmt.sample_rate);
audio_syncts_add(dec->mix_ch_event_params);
}
#endif
#endif/*TCFG_USER_TWS_ENABLE*/
return audio_output_data(data, len);
}
static int tone_final_output_handler(struct tone_file_handle *dec, s16 *data, int len)
{
#if AUDIO_OUT_MIXER_ENABLE
return audio_mixer_ch_write(&dec->mix_ch, data, len);
#else
return audio_output_data_tone(dec, data, len);
#endif
}
static int tone_output_after_syncts_filter(void *priv, void *data, int len)
{
struct tone_file_handle *dec = (struct tone_file_handle *)priv;
int wlen = 0;
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
if (dec->remain == 0) {
audio_digital_vol_run(dec->dvol, data, len);
}
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
if (dec->hw_src) {
wlen = audio_src_resample_write(dec->hw_src, data, len);
goto ret;
}
wlen = tone_final_output_handler(dec, data, len);
ret:
dec->remain = wlen < len ? 1 : 0;
return wlen;
}
static int tone_dec_output_handler(struct audio_decoder *decoder, s16 *data, int len, void *priv)
{
int wlen = 0;
int remain_len = len;
struct tone_file_handle *dec = container_of(decoder, struct tone_file_handle, decoder);
#if TCFG_USER_TWS_ENABLE
if (dec->syncts) {
if (dec->ts_handle) {
u32 timestamp = file_audio_timestamp_update(dec->ts_handle, audio_syncts_get_dts(dec->syncts));
audio_syncts_next_pts(dec->syncts, timestamp);
if (!dec->ts_start) {
dec->mix_ch_event_params[2] = timestamp;
dec->ts_start = 1;
}
}
wlen = audio_syncts_frame_filter(dec->syncts, data, len);
if (wlen < len) {
audio_syncts_trigger_resume(dec->syncts, decoder, (void (*)(void *))audio_decoder_resume);
}
return wlen;
}
#endif
return tone_output_after_syncts_filter(dec, data, len);
}
static int tone_dec_post_handler(struct audio_decoder *decoder)
{
return 0;
}
const struct audio_dec_handler tone_dec_handler = {
.dec_probe = tone_dec_probe_handler,
.dec_output = tone_dec_output_handler,
.dec_post = tone_dec_post_handler,
};
static void tone_dec_set_output_channel(struct tone_file_handle *dec)
{
int state;
enum audio_channel channel;
#if TCFG_APP_FM_EMITTER_EN
dec->channel = AUDIO_CH_LR;
audio_decoder_set_output_channel(&dec->decoder, dec->channel);
dec->ch_num = 2;
#else
int dac_output = audio_dac_get_channel(&dac_hdl);
dec->ch_num = 1;
if (dac_output == DAC_OUTPUT_LR) {
channel = AUDIO_CH_LR;
dec->ch_num = 2;
} else if (dac_output == DAC_OUTPUT_MONO_L) {
channel = AUDIO_CH_L;
} else if (dac_output == DAC_OUTPUT_MONO_R) {
channel = AUDIO_CH_R;
} else {
channel = AUDIO_CH_DIFF;
}
/* if (channel != dec->channel) { */
printf("set_channel: %d, dec_channel_num: %d\n", channel, dec->ch_num);
audio_decoder_set_output_channel(&dec->decoder, channel);
dec->channel = channel;
/* } */
#endif
}
static int file_decoder_syncts_setup(struct tone_file_handle *dec)
{
int err = 0;
#if TCFG_USER_TWS_ENABLE
if (dec->hw_src) {
audio_hw_src_close(dec->hw_src);
free(dec->hw_src);
dec->hw_src = NULL;
}
struct audio_syncts_params params = {0};
params.nch = dec->ch_num;
#if defined(TCFG_AUDIO_OUTPUT_IIS) && TCFG_AUDIO_OUTPUT_IIS
params.pcm_device = PCM_OUTSIDE_DAC;
params.rout_sample_rate = TCFG_IIS_SAMPLE_RATE;
#else
params.pcm_device = PCM_INSIDE_DAC;
params.rout_sample_rate = dec->target_sample_rate;
#endif
params.network = AUDIO_NETWORK_BT2_1;
params.rin_sample_rate = dec->decoder.fmt.sample_rate;
params.priv = dec;
params.factor = TIME_US_FACTOR;
params.output = tone_output_after_syncts_filter;
u8 base = 3;
int state = tws_api_get_tws_state();
if (state & TWS_STA_SIBLING_CONNECTED) {
base = dec->dec_mix ? 3 : 1;
}
bt_audio_sync_nettime_select(base);//3 - 优先选择远端主机为网络时钟
dec->ts_start = 0;
dec->ts_handle = file_audio_timestamp_create(0,
dec->decoder.fmt.sample_rate,
bt_audio_sync_lat_time(),
TWS_TONE_CONFIRM_TIME,
TIME_US_FACTOR);
err = audio_syncts_open(&dec->syncts, &params);
if (!err) {
#if AUDIO_OUT_MIXER_ENABLE
dec->mix_ch_event_params[0] = (u32)&dec->mix_ch;
dec->mix_ch_event_params[1] = (u32)dec->syncts;
audio_mixer_ch_set_event_handler(&dec->mix_ch, (void *)dec->mix_ch_event_params, audio_mix_ch_event_handler);
#else
dec->mix_ch_event_params[1] = (u32)dec->syncts;
#endif
} else {
log_e("tone audio syncts open err\n");
}
#endif
return err;
}
static void file_decoder_syncts_free(struct tone_file_handle *dec)
{
#if TCFG_USER_TWS_ENABLE
if (dec->ts_handle) {
file_audio_timestamp_close(dec->ts_handle);
dec->ts_handle = NULL;
}
if (dec->syncts) {
audio_syncts_close(dec->syncts);
dec->syncts = NULL;
}
#endif
}
int tone_file_dec_start() //到这里
{
int err;
struct audio_fmt *fmt;
u8 file_name[16];
if (!file_dec || !file_dec->file) {
return -EINVAL;
}
if (file_dec->start) {
return 0;
}
fget_name(file_dec->file, file_name, 16);
tone_input.coding_type = tone_file_format_match(get_file_ext_name((char *)file_name));
if (tone_input.coding_type == AUDIO_CODING_UNKNOW) {
log_e("unknow tone file format\n");
return -EINVAL;
}
#if !CONFIG_MINI_TONEPLAY_ENABLE
#if 0
if (tone_input.coding_type == AUDIO_CODING_AAC) {
file_dec->clk_before_dec = clk_get("sys");
if (get_call_status() == BT_CALL_HANGUP) {
puts("aac tone play:48M\n");
clk_set_sys_lock(48 * 1000000L, 1);
} else {
puts("aac tone play:64M\n");
clk_set_sys_lock(64 * 1000000L, 1);
}
} else if ((tone_input.coding_type == AUDIO_CODING_WAV) || (tone_input.coding_type == AUDIO_CODING_MP3)) {
/*当前时钟小于wav/mp3提示音播放需要得时钟则自动提高主频*/
file_dec->clk_before_dec = clk_get("sys");
u32 wav_tone_play_clk = 96 * 1000000L;
if (wav_tone_play_clk < file_dec->clk_before_dec) {
wav_tone_play_clk = file_dec->clk_before_dec;
}
printf("wav/mp3 tone play clk:%d->%d\n", file_dec->clk_before_dec, wav_tone_play_clk);
clk_set_sys_lock(wav_tone_play_clk, 1);
}
#else
audio_codec_clock_set(AUDIO_TONE_MODE, tone_input.coding_type, tone_dec->wait.preemption);
#endif
#endif /*CONFIG_MINI_TONEPLAY_ENABLE*/
err = audio_decoder_open(&file_dec->decoder, &tone_input, &decode_task);
if (err) {
return err;
}
audio_decoder_set_handler(&file_dec->decoder, &tone_dec_handler);
/*用于处理DEC_EVENT与当前解码的匹配*/
file_dec->magic = rand32();
audio_decoder_set_event_handler(&file_dec->decoder, tone_dec_event_handler, file_dec->magic);
err = audio_decoder_get_fmt(&file_dec->decoder, &fmt);
if (err) {
goto __err1;
}
tone_dec_set_output_channel(file_dec);
#if AUDIO_OUT_MIXER_ENABLE
audio_mixer_ch_open(&file_dec->mix_ch, &mixer);
audio_mixer_ch_set_resume_handler(&file_dec->mix_ch, (void *)&file_dec->decoder, (void (*)(void *))audio_decoder_resume);
#endif
#if TONE_FILE_DEC_MIX
int mixer_sample_rate = audio_mixer_get_sample_rate(&mixer);
#if TCFG_AUDIO_OUTPUT_IIS
if (!file_dec->tws) {
file_dec->target_sample_rate = TCFG_IIS_SAMPLE_RATE;
} else {
file_dec->target_sample_rate = fmt->sample_rate;
}
#else
file_dec->target_sample_rate = (file_dec->dec_mix && mixer_sample_rate) ? mixer_sample_rate : fmt->sample_rate;
#endif
audio_mixer_ch_set_sample_rate(&file_dec->mix_ch, file_dec->target_sample_rate);
printf("fmt->sample_rate %d\n", fmt->sample_rate);
/* printf("mixer sr:[%d]\n\n",audio_mixer_get_sample_rate(&mixer)); */
/* printf("\n sr:[%d];src sr:[%d] \n\n",fmt->sample_rate,file_dec->target_sample_rate); */
if (fmt->sample_rate != file_dec->target_sample_rate) {
printf("src->sr:%d, or:%d ", fmt->sample_rate, file_dec->target_sample_rate);
file_dec->hw_src = zalloc(sizeof(struct audio_src_handle));
if (file_dec->hw_src) {
audio_hw_src_open(file_dec->hw_src, file_dec->ch_num, SRC_TYPE_RESAMPLE);
audio_hw_src_set_rate(file_dec->hw_src, fmt->sample_rate, file_dec->target_sample_rate);
audio_src_set_output_handler(file_dec->hw_src, file_dec, tone_final_output_handler);
}
}
if (file_dec->dec_mix && (audio_mixer_get_ch_num(&mixer) > 1) && (SYS_VOL_TYPE != VOL_TYPE_DIGITAL)) {
goto __dec_start;
}
#else
#if AUDIO_OUT_MIXER_ENABLE
audio_mixer_ch_set_sample_rate(&file_dec->mix_ch, fmt->sample_rate);
#endif
file_dec->target_sample_rate = fmt->sample_rate;
#endif
#ifdef TCFG_WTONT_ONCE_VOL
extern u8 get_tone_once_vol(void);
app_audio_state_switch(APP_AUDIO_STATE_WTONE, get_tone_once_vol());
#else
app_audio_state_switch(APP_AUDIO_STATE_WTONE, get_tone_vol());
app_audio_set_volume(APP_AUDIO_STATE_WTONE, get_tone_vol(), 1);
#endif
__dec_start:
#if TCFG_USER_TWS_ENABLE
if (file_dec->tws) {
file_decoder_syncts_setup(file_dec);
}
file_dec->tws_align_step = 0;
#endif
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
if ((tone_input.coding_type == AUDIO_CODING_WAV) && (tone_dec->preemption == 0)) {
audio_digital_vol_bg_fade(1);
}
file_dec->dvol = audio_digital_vol_open(SYS_DEFAULT_TONE_VOL, SYS_MAX_VOL, 20);
#endif/*VOL_TYPE_DIGITAL*/
err = audio_decoder_start(&file_dec->decoder);
if (err) {
goto __err2;
}
file_dec->start = 1;
return 0;
__err2:
#if TCFG_APP_FM_EMITTER_EN
#else
#if AUDIO_OUT_MIXER_ENABLE
audio_mixer_ch_close(&file_dec->mix_ch);
#else
audio_output_close(NULL);
#if TCFG_USER_TWS_ENABLE
if (file_dec->syncts) {
u32 mix_ch_event_params[3] = {0};
mix_ch_event_params[1] = (u32)file_dec->syncts;
audio_syncts_del(mix_ch_event_params);
}
#endif
#endif
#if TCFG_USER_TWS_ENABLE
file_decoder_syncts_free(file_dec);
#endif
#endif
__err1:
audio_decoder_close(&file_dec->decoder);
if (file_dec->hw_src) {
audio_hw_src_stop(file_dec->hw_src);
audio_hw_src_close(file_dec->hw_src);
free(file_dec->hw_src);
file_dec->hw_src = NULL;
log_info("hw_src close end\n");
}
tone_file_dec_release();
return err;
}
static int tone_wait_res_handler(struct audio_res_wait *wait, int event)
{
int err = 0;
if (event == AUDIO_RES_GET) {
err = tone_file_dec_start();
} else if (event == AUDIO_RES_PUT) {
tone_file_list_stop(0);
}
return err;
}
int tone_file_list_stop(u8 no_end)
{
const char *name = NULL;
log_info("tone_file_list_stop\n");
os_mutex_pend(&tone_mutex, 0);
if (!file_dec) {
log_info("tone_file_list_stop out 0\n");
os_mutex_post(&tone_mutex);
return 0;
}
tone_audio_res_close(0);
#if !CONFIG_MINI_TONEPLAY_ENABLE
#if 0
if ((tone_input.coding_type == AUDIO_CODING_AAC) || (tone_input.coding_type == AUDIO_CODING_WAV)) {
printf("tone_play end,clk restore:%d", file_dec->clk_before_dec);
clk_set_sys_lock(file_dec->clk_before_dec, 2);
}
#else
audio_codec_clock_del(AUDIO_TONE_MODE);
#endif
#endif /*CONFIG_MINI_TONEPLAY_ENABLE*/
if (file_dec->list[file_dec->idx]) {
name = (const char *)file_dec->list[file_dec->idx];
} else if (file_dec->idx) {
name = (const char *)file_dec->list[file_dec->idx - 1];
}
if (file_dec->file) {
fclose(file_dec->file);
}
tone_file_dec_release();
tone_dec_end_handler(AUDIO_DEC_EVENT_END, name);
log_info("tone_file_list_stop out 1\n");
return 0;
}
/*static const u8 pcm_wav_header[] = {
'R', 'I', 'F', 'F', //rid
0xff, 0xff, 0xff, 0xff, //file length
'W', 'A', 'V', 'E', //wid
'f', 'm', 't', ' ', //fid
0x14, 0x00, 0x00, 0x00, //format size
0x01, 0x00, //format tag
0x01, 0x00, //channel num
0x80, 0x3e, 0x00, 0x00, //sr 16K
0x00, 0x7d, 0x00, 0x00, //avgbyte
0x02, 0x00, //blockalign
0x10, 0x00, //persample
0x02, 0x00,
0x00, 0x00,
'f', 'a', 'c', 't', //f2id
0x40, 0x00, 0x00, 0x00, //flen
0xff, 0xff, 0xff, 0xff, //datalen
'd', 'a', 't', 'a', //"data"
0xff, 0xff, 0xff, 0xff, //sameple size
};*/
static int sine_fread(struct audio_decoder *decoder, void *buf, u32 len)
{
int offset;
u8 *data = (u8 *)buf;
offset = sin_tone_make(sine_dec->sin_maker, data, len);
sine_dec->sine_offset += offset;
return offset;
}
static int sine_fseek(struct audio_decoder *decoder, u32 offset, int seek_mode)
{
sine_dec->sine_offset = 0;
return 0;
}
static int sine_flen(struct audio_decoder *decoder)
{
return sin_tone_points(sine_dec->sin_maker) * 2;
}
static const struct audio_dec_input sine_input = {
.coding_type = AUDIO_CODING_PCM,
.data_type = AUDIO_INPUT_FILE,
.ops = {
.file = {
.fread = sine_fread,
.fseek = sine_fseek,
.flen = sine_flen,
}
}
};
static void sine_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
{
log_info("sin_dec_event:%x", argv[0]);
switch (argv[0]) {
case AUDIO_DEC_EVENT_END:
case AUDIO_DEC_EVENT_ERR:
log_info("sine player end\n");
sine_dec_close();
break;
default:
return;
}
}
static void sine_param_resample(struct sin_param *dst, const struct sin_param *src, u32 sample_rate)
{
u32 coef = (sample_rate << 10) / DEFAULT_SINE_SAMPLE_RATE;
dst->freq = (src->freq << 10) / coef;
dst->points = ((u64)src->points * coef) >> 10;
dst->win = src->win;
if (src->win) {
dst->decay = ((u64)src->decay << 10) / coef;
} else {
dst->decay = ((u64)SINE_TOTAL_VOLUME * src->decay / 100) / (u32)dst->points;
}
}
static struct sin_param *get_default_sine_param(const struct sin_param *data, u32 sample_rate, u8 data_num)
{
int i = 0;
for (i = 0; i < data_num; i++) {
/*sin_dynamic_params[i].idx_increment = ((u64)data[i].idx_increment << 8) / coef;*/
sine_param_resample(&sine_dec->sin_dynamic_params[i], data + i, sample_rate);
}
return sine_dec->sin_dynamic_params;
}
struct sine_param_head {
u16 repeat_time;
u8 set_cnt;
u8 cur_cnt;
};
static struct sin_param *get_sine_file_param(const char *name, u32 sample_rate, u8 *data_num)
{
FILE *file;
struct sine_param_head head;
struct sin_param param;
int r_len = 0;
int i = 0;
file = fopen(name, "r");
if (!file) {
return NULL;
}
r_len = fread(file, (void *)&head, sizeof(head));
if (r_len != sizeof(head)) {
fclose(file);
return NULL;
}
do {
r_len = fread(file, (void *)&param, sizeof(param));
if (r_len != sizeof(param)) {
break;
}
/*
printf("sine param : \nfreq : %d\npoints : %d\nwin : %d\ndecay : %d\n",
param.freq, param.points, param.win, param.decay);
*/
if (!param.points) {
break;
}
if (!param.win) {
param.decay = param.decay * 100 / 32767;
}
sine_param_resample(&sine_dec->sin_dynamic_params[i], (const struct sin_param *)&param, sample_rate);
i++;
} while (1);
*data_num = i;
fclose(file);
return sine_dec->sin_dynamic_params;
}
#if 0
static const struct sin_param *get_sine_param_data(u8 id, u8 *num)
{
const struct sin_param *param_data;
switch (id) {
case SINE_WTONE_NORAML:
param_data = sine_16k_normal;
*num = ARRAY_SIZE(sine_16k_normal);
break;
#if CONFIG_USE_DEFAULT_SINE
case SINE_WTONE_TWS_CONNECT:
param_data = sine_tws_connect_16k;
*num = ARRAY_SIZE(sine_tws_connect_16k);
break;
case SINE_WTONE_TWS_DISCONNECT:
param_data = sine_tws_disconnect_16k;
*num = ARRAY_SIZE(sine_tws_disconnect_16k);
break;
case SINE_WTONE_LOW_POWER:
param_data = sine_low_power;
*num = ARRAY_SIZE(sine_low_power);
break;
case SINE_WTONE_RING:
param_data = sine_ring;
*num = ARRAY_SIZE(sine_ring);
break;
case SINE_WTONE_MAX_VOLUME:
param_data = sine_tws_max_volume;
*num = ARRAY_SIZE(sine_tws_max_volume);
break;
#ifdef SINE_WTONE_LOW_LATENRY_IN
case SINE_WTONE_LOW_LATENRY_IN:
param_data = sine_low_latency_in;
*num = ARRAY_SIZE(sine_low_latency_in);
break;
case SINE_WTONE_LOW_LATENRY_OUT:
param_data = sine_low_latency_out;
*num = ARRAY_SIZE(sine_low_latency_out);
break;
#endif
#endif
default:
return NULL;
}
return param_data;
}
#endif
static get_sine_param_t get_sine_param_data = NULL;
__BANK_INIT
void tone_play_set_sine_param_handler(get_sine_param_t handler)
{
get_sine_param_data = handler;
}
static struct sin_param *get_sine_param(u32 sine_id, u32 sample_rate, u8 *data_num)
{
const struct sin_param *sin_data_param;
u8 num = 0;
if (IS_DEFAULT_SINE(sine_id)) {
if (!get_sine_param_data) {
return NULL;
}
sin_data_param = get_sine_param_data(DEFAULT_SINE_ID(sine_id), &num);
if (!sin_data_param) {
return NULL;
}
*data_num = num;
return get_default_sine_param(sin_data_param, sample_rate, num);
} else {
return get_sine_file_param((const char *)sine_id, sample_rate, data_num);
}
}
static int sine_dec_probe_handler(struct audio_decoder *decoder)
{
u8 num = 0;
const struct sin_param *param;
if (!sine_dec->sin_maker) {
#ifdef CONFIG_CPU_BR18
int channel = 2;
#else
int channel = audio_dac_get_channel(&dac_hdl) == DAC_OUTPUT_LR ? 2 : 1;
#endif
#if AUDIO_OUT_MIXER_ENABLE
int sample_rate = audio_mixer_get_sample_rate(&mixer);
#else
int sample_rate = 0;
#endif
if (sample_rate == 0) {
sample_rate = 16000;
}
#if TCFG_AUDIO_OUTPUT_IIS
sample_rate = TCFG_IIS_SAMPLE_RATE;
#endif
printf("sine: %d, %d\n", sample_rate, channel);
param = get_sine_param(sine_dec->sine_id, sample_rate, &num);
if (!param) {
return -ENOENT;
}
sine_dec->sin_maker = sin_tone_open(param, num, channel, sine_dec->repeat);
if (!sine_dec->sin_maker) {
return -ENOENT;
}
#if AUDIO_OUT_MIXER_ENABLE
audio_mixer_ch_set_sample_rate(&sine_dec->mix_ch, sample_rate);
#endif
/*if (audio_dac_idle(&dac_hdl)) {
audio_dac_set_analog_vol(&dac_hdl, 20);
audio_dac_start(&dac_hdl);
}*/
}
return 0;
}
static int sine_dec_output_handler(struct audio_decoder *decoder, s16 *data, int len, void *priv)
{
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
if (sine_dec->remain == 0) {
audio_digital_vol_run(sine_dec->dvol, data, len);
}
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
#if AUDIO_OUT_MIXER_ENABLE
int wlen = audio_mixer_ch_write(&sine_dec->mix_ch, data, len);
#else
int wlen = audio_output_data(data, len);
#endif
if (wlen != len) {
sine_dec->remain = 1;
} else {
sine_dec->remain = 0;
}
return wlen;
}
static int sine_dec_post_handler(struct audio_decoder *decoder)
{
return 0;
}
const struct audio_dec_handler sine_dec_handler = {
.dec_probe = sine_dec_probe_handler,
.dec_output = sine_dec_output_handler,
.dec_post = sine_dec_post_handler,
};
static void sine_dec_release()
{
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_close(sine_dec->dvol);
sine_dec->dvol = NULL;
#endif/*VOL_TYPE_DIGITAL*/
free(sine_dec);
sine_dec = NULL;
}
int sine_dec_start()
{
int err;
int decode_task_state;
struct audio_fmt *fmt;
if (!sine_dec) {
return -EINVAL;
}
if (sine_dec->start) {
return 0;
}
printf("sine_dec_start: id = %x, repeat = %d\n", sine_dec->sine_id, sine_dec->repeat);
err = audio_decoder_open(&sine_dec->decoder, &sine_input, &decode_task);
if (err) {
return err;
}
err = audio_decoder_get_fmt(&sine_dec->decoder, &fmt);
decode_task_state = audio_decoder_task_wait_state(&decode_task);
/*
*
*(1)
*(2)
*/
if ((tone_dec->wait.preemption == 1) || (decode_task_state == 1)) {
app_audio_state_switch(APP_AUDIO_STATE_WTONE, SYS_DEFAULT_SIN_VOL);
}
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
sine_dec->dvol = audio_digital_vol_open(SYS_DEFAULT_SIN_VOL, SYS_MAX_VOL, 20);
#endif/*VOL_TYPE_DIGITAL*/
#if 0
/*
*
*
*/
if (tone_dec->wait.preemption == 0) {
u32 cur_clk = clk_get("sys");
u32 need_clk = cur_clk + 12000000L;
printf("sin_tone_clk_inc:%d->%d", cur_clk, need_clk);
sine_dec->clk_before = clk_get("sys");
clk_set_sys_lock(need_clk, 1);
}
#else
audio_codec_clock_set(AUDIO_TONE_MODE, AUDIO_CODING_PCM, tone_dec->wait.preemption);
#endif
audio_decoder_set_handler(&sine_dec->decoder, &sine_dec_handler);
audio_decoder_set_event_handler(&sine_dec->decoder, sine_dec_event_handler, 0);
#if AUDIO_OUT_MIXER_ENABLE
audio_mixer_ch_open(&sine_dec->mix_ch, &mixer);
#else
audio_output_open(NULL, 16000);
#endif
err = audio_decoder_start(&sine_dec->decoder);
if (err) {
goto __err2;
}
sine_dec->start = 1;
return 0;
__err2:
#if AUDIO_OUT_MIXER_ENABLE
audio_mixer_ch_close(&sine_dec->mix_ch);
#else
audio_output_close(NULL);
#endif
__err1:
audio_decoder_close(&sine_dec->decoder);
sine_dec_release();
return err;
}
static int sine_wait_res_handler(struct audio_res_wait *wait, int event)
{
int err = 0;
if (event == AUDIO_RES_GET) {
err = sine_dec_start();
} else if (event == AUDIO_RES_PUT) {
}
return err;
}
int sine_dec_open(u32 sine_id, u8 repeat, u8 preemption)
{
int err = 0;
if (sine_dec) {
sine_dec_close();
if (sine_dec) {
return -EINVAL;
}
}
sine_dec = zalloc(sizeof(*sine_dec));
if (!sine_dec) {
log_error("sine_dec zalloc failed");
return -ENOMEM;
}
#if !AUDIO_OUT_MIXER_ENABLE
preemption = 1;
#endif
sine_dec->repeat = repeat;
sine_dec->sine_id = sine_id;
tone_dec->wait.priority = 3;
tone_dec->wait.preemption = preemption;
tone_dec->wait.handler = sine_wait_res_handler;
printf("sine_dec_open,preemption = %d", preemption);
audio_decoder_task_add_wait(&decode_task, &tone_dec->wait);
if (sine_dec && preemption == 0 && sine_dec->start == 0) {
err = sine_dec_start();
}
return err;
}
int sine_dec_close(void)
{
if (!sine_dec) {
return 0;
}
puts("sine_dec_close\n");
audio_decoder_close(&sine_dec->decoder);
#if AUDIO_OUT_MIXER_ENABLE
audio_mixer_ch_close(&sine_dec->mix_ch);
#else
audio_output_close(NULL);
#endif
if (sine_dec->sin_maker) {
sin_tone_close(sine_dec->sin_maker);
}
if (app_audio_get_state() == APP_AUDIO_STATE_WTONE) {
app_audio_state_exit(APP_AUDIO_STATE_WTONE);
}
#if 0
if (tone_dec->wait.preemption == 0/* && (audio_aec_status() == 1)*/) {
//y_printf("clk_before2:%d",sine_dec->clk_before);
if (sine_dec->clk_before) {
clk_set_sys_lock(sine_dec->clk_before, 1);
sine_dec->clk_before = 0;
}
}
#else
audio_codec_clock_del(AUDIO_TONE_MODE);
#endif
sine_dec_release();
tone_dec_end_handler(AUDIO_DEC_EVENT_END, NULL);
return 0;
}
int audio_decoder_find_coding_type(struct audio_decoder_task *task, u32 coding_type);
int tone_list_play_start(const char **list, u8 preemption, u8 tws)
{
int err;
u8 file_name[16];
char *format = NULL;
FILE *file = NULL;
int index = 0;
#if !AUDIO_OUT_MIXER_ENABLE
preemption = 1;
#endif
if (IS_REPEAT_BEGIN(list[0])) {
index = 1;
}
if (IS_DEFAULT_SINE(list[index])) {
format = "sin";
} else {
file = fopen(list[index], "r");
if (!file) {
return -EINVAL;
}
fget_name(file, file_name, 16);
format = get_file_ext_name((char *)file_name);
}
if (ASCII_StrCmpNoCase(format, "sin", 3) == 0) {
if (file) {
fclose(file);
}
/*正弦波参数文件*/
return sine_dec_open((u32)list[index], index == 1, preemption);
} else {
file_dec = zalloc(sizeof(*file_dec));
file_dec->list = list;
file_dec->idx = index;
file_dec->file = file;
file_dec->tws = tws;
if (index == 1) {
file_dec->loop = TONE_REPEAT_COUNT(list[0]);
}
#if 0
if (!preemption) {
file_dec->dec_mix = 1;
tone_dec->wait.protect = 1;
}
#endif
tone_dec->wait.priority = 3;
tone_dec->wait.preemption = preemption;
/*AAC提示音默认打断播放*/
#if !CONFIG_MINI_TONEPLAY_ENABLE
if (ASCII_StrCmpNoCase(format, "aac", 3) == 0) {
printf("aac tone,preemption = 1\n");
tone_dec->wait.preemption = 1;
tone_dec->wait.format = AUDIO_CODING_AAC;
} else
#endif /*CONFIG_MINI_TONEPLAY_ENABLE*/
{
#if TONE_FILE_DEC_MIX
if (tone_dec->wait.preemption == 0) {
/*支持叠加的提示音解码文件格式*/
if ((ASCII_StrCmpNoCase(format, "wav", 3) == 0) || \
(ASCII_StrCmpNoCase(format, "mp3", 3) == 0) || \
(ASCII_StrCmpNoCase(format, "wtg", 3) == 0)) {
// 叠加播放
file_dec->dec_mix = 1;
/*tone_dec->wait.protect = 1;*/ //提示音播放不用来做低优先级的背景音
tone_dec->wait.preemption = 0;
}
} else {
file_dec->dec_mix = 0;
}
#endif
}
tone_dec->wait.handler = tone_wait_res_handler;
err = audio_decoder_task_add_wait(&decode_task, &tone_dec->wait);
#if 0
if (!err && file_dec->start == 0) {
/*decoder中有该解码器则强制使用打断方式防止overlay冲突*/
if (audio_decoder_find_coding_type(&decode_task, tone_file_format_match(format))) {
tone_dec->wait.preemption = 1;
err = audio_decoder_task_add_wait(&decode_task, &tone_dec->wait);
} else {
err = tone_file_dec_start();
}
}
#endif
if (err) {
if (tone_dec) {
audio_decoder_task_del_wait(&decode_task, &tone_dec->wait);
}
} else {
if (file_dec->dec_mix && !file_dec->start) {
err = tone_file_dec_start();
}
}
return err;
}
}
static int __tone_file_list_play(const char **list, u8 preemption, u8 tws)
{
int i = 0;
int err = 0;
if (!list) {
return -EINVAL;
}
if (tone_dec == NULL) {
tone_dec = zalloc(sizeof(*tone_dec));
if (tone_dec == NULL) {
log_error("tone dec zalloc failed");
return -ENOMEM;
}
}
while (list[i] != NULL) {
i++;
}
char **p = malloc(4 * (i + 1));
memcpy(p, list, 4 * (i + 1));
tone_dec->list[tone_dec->w_index++] = (const char **)p;
if (tone_dec->w_index >= TONE_LIST_MAX_NUM) {
tone_dec->w_index = 0;
}
tone_dec->list_cnt++;
tone_dec->preemption = preemption;
if (tone_dec->list_cnt == 1) {
err = tone_list_play_start(tone_dec->list[tone_dec->r_index], tone_dec->preemption, tws);
if (err == -EINVAL) {
free(p);
free(tone_dec);
tone_dec = NULL;
}
return err;
} else {
puts("tone_file_add_tail\n");
}
return 0;
}
int tone_file_list_play(const char **list, u8 preemption)
{
return __tone_file_list_play(list, preemption, 1);
}
int tone_file_list_play_with_callback(const char **list, u8 preemption, void (*user_evt_handler)(void *priv), void *priv)
{
int i = 0;
int err = 0;
putchar('A');
if (!list) {
return -EINVAL;
}
putchar('B');
if (tone_dec == NULL) {
tone_dec = zalloc(sizeof(*tone_dec));
if (tone_dec == NULL) {
log_error("tone dec zalloc failed");
return -ENOMEM;
}
}
putchar('C');
while (list[i] != NULL) {
i++;
}
char **p = malloc(4 * (i + 1));
memcpy(p, list, 4 * (i + 1));
tone_dec->list[tone_dec->w_index++] = (const char **)p;
if (tone_dec->w_index >= TONE_LIST_MAX_NUM) {
tone_dec->w_index = 0;
}
putchar('D');
if (user_evt_handler) {
tone_set_user_event_handler(tone_dec, user_evt_handler, priv);
}
tone_dec->list_cnt++;
tone_dec->preemption = preemption;
if (tone_dec->list_cnt == 1) {
err = tone_list_play_start(tone_dec->list[tone_dec->r_index], tone_dec->preemption, 1);
if (err == -EINVAL) {
free(p);
free(tone_dec);
tone_dec = NULL;
}
return err;
} else {
puts("tone_file_add_tail\n");
}
return 0;
}
static void tone_stop(u8 force);
int tone_play(const char *name, u8 preemption)
{
g_printf("tone_play:%s,preemption:%d", IS_DEFAULT_SINE(name) ? "sine" : name, preemption);
if (tone_dec) {
log_info("tone dec busy now,tone stop first");
tone_stop(0);
}
single_file[0] = (char *)name;
single_file[1] = NULL;
return tone_file_list_play((const char **)single_file, preemption);
}
int tone_play_no_tws(const char *name, u8 preemption)
{
g_printf("tone_play no tws:%s,preemption:%d", IS_DEFAULT_SINE(name) ? "sine" : name, preemption);
if (tone_dec) {
log_info("tone dec busy now,tone stop first");
tone_stop(0);
}
single_file[0] = (char *)name;
single_file[1] = NULL;
return __tone_file_list_play((const char **)single_file, preemption, 0);
}
int tone_play_with_callback(const char *name, u8 preemption, void (*user_evt_handler)(void *priv), void *priv)
{
g_printf("tone_play:%s,preemption:%d", IS_DEFAULT_SINE(name) ? "sine" : name, preemption);
if (tone_dec) {
tone_event_clear();
log_info("tone dec busy now,tone stop first");
tone_stop(0);
}
single_file[0] = (char *)name;
single_file[1] = NULL;
return tone_file_list_play_with_callback((const char **)single_file, preemption, user_evt_handler, priv);
}
int tone_play_add(const char *name, u8 preemption)
{
g_printf("tone_play_add:%s,preemption:%d", IS_DEFAULT_SINE(name) ? "sine" : name, preemption);
if (tone_dec) {
log_info("tone dec busy now,tone file add next");
//tone_stop(0);
}
single_file[0] = (char *)name;
single_file[1] = NULL;
return tone_file_list_play((const char **)single_file, preemption);
}
const char *get_playing_tone_name(u8 index)
{
if (tone_dec) {
const char **list = tone_dec->list[tone_dec->r_index + index];
if (list) {
return list[0];
}
}
return 0;
}
static void tone_stop(u8 force)
{
if (tone_dec == NULL) {
return;
}
if (force) {
tone_file_list_clean(1);
}
tone_file_list_stop(0);
sine_dec_close();
tone_dec_release();
}
static u8 audio_tone_idle_query()
{
if (tone_dec) {
return 0;
}
return 1;
}
REGISTER_LP_TARGET(audio_tone_lp_target) = {
.name = "audio_tone",
.is_idle = audio_tone_idle_query,
};
#if 0 //(USE_DMA_TONE)
static volatile u8 tone_play_falg = 0; //用于播放提示音后,作相应的动作
void set_tone_play_falg(u8 flag)
{
tone_play_falg = flag;
}
u8 get_tone_play_flag(void)
{
return tone_play_falg;
}
int tone_play_index_for_dma(u8 index, u8 flag)
{
set_tone_play_falg(flag);
return tone_play_index(index, 1);
}
static u32 dma_tone_arg_before = 0; //记录下按键的arg值
void set_dma_tone_arg_before(u32 arg)
{
dma_tone_arg_before = arg;
}
u32 get_dma_tone_arg_before(void)
{
return dma_tone_arg_before;
}
void clear_dma_tone_arg_before(void)
{
dma_tone_arg_before = 0;
}
#endif
static volatile s32 tone_play_end_cmd = TONE_PLAY_END_CB_CMD_NONE; //用于播放提示音后,作相应的动作
void tone_play_end_cb_cmd_set(int cmd)
{
tone_play_end_cmd = cmd;
}
s32 tone_play_end_cb_cmd_get(void)
{
return tone_play_end_cmd;
}
int tone_play_index_with_cb_cmd(u8 index, int flag)
{
tone_play_end_cb_cmd_set(flag);
return tone_play_index(index, 1);
}
static u32 tone_arg_storage = 0; //记录下按键的arg值
void tone_arg_store(u32 arg)
{
tone_arg_storage = arg;
}
u32 tone_arg_restore(void)
{
return tone_arg_storage;
}
void tone_arg_storage_clean(void)
{
tone_arg_storage = 0;
}
int tone_play_init(void)
{
os_mutex_create(&tone_mutex);
return 0;
}
int tone_play_stop(void)
{
log_info("tone_play_stop");
tone_stop(1);
return 0;
}
/*
*@brief:
*@return: 0
* 0
*@note:
*/
int tone_name_compare(const char *name)
{
if (tone_dec) {
if (file_dec) {
printf("file_name:%s,cmp_name:%s\n", file_dec->list[file_dec->idx], name);
return strcmp(name, file_dec->list[file_dec->idx]);
} else if (sine_dec) {
printf("sin_id:0x%x,cmp_id:0x%x\n", sine_dec->sine_id, (u32)name);
if (sine_dec->sine_id == (u32)name) {
return 0;
} else {
return -1;
}
}
}
printf("tone_dec idle now\n");
return -1;
}