1999 lines
50 KiB
C
1999 lines
50 KiB
C
#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, ¶ms);
|
||
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 *)¶m, 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 *)¶m, 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;
|
||
}
|