AC63_BT_SDK/cpu/bd19/tone_player.c
2025-02-18 15:40:42 +08:00

1359 lines
32 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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"
#include "board_config.h"
#include "audio_digital_vol.h"
#if TCFG_APP_FM_EMITTER_EN
#include "fm_emitter/fm_emitter_manage.h"
#endif
#if TCFG_AUDIO_MUSIC_SIDETONE_ENABLE //播歌时侧耳监听功能
#include "audio_dec_mic2pcm.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 1 // 提示音叠加播放
#else
#define TONE_FILE_DEC_MIX 0
#endif
//软件数字音量(调节解码输出数据的音量),选择此音量类型需要把audio_digital_vol.h中BG_DVOL_FADE_ENABLE 这个宏置0
#define VOL_TYPE_DIGITAL 0
#define VOL_TYPE_NULL 1 //不使用音量
#define SYS_VOL_TYPE VOL_TYPE_NULL
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;
struct audio_mixer_ch mix_ch;
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_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 char *single_file[2] = {NULL};
struct tone_dec_handle *tone_dec;
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;
}
__attribute__((weak)) void audio_pwm_set_resume(void (*resume)(void *))
{
return;
}
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) {
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,
};
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
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->start) {
file_dec->start = 0;
}
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;
}
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_OPUS_ENABLE
{"opus", AUDIO_CODING_OPUS},
#endif/*TCFG_DEC_WTGV2_ENABLE*/
#if TCFG_DEC_SPEEX_ENABLE
{"speex", AUDIO_CODING_SPEEX},
#endif/*TCFG_DEC_WTGV2_ENABLE*/
#if TCFG_DEC_WTGV2_ENABLE
{"wts", AUDIO_CODING_WTGV2},
#endif/*TCFG_DEC_WTGV2_ENABLE*/
#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/*TCFG_WAV_TONE_MIX_ENABLE*/
};
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;
}
static int tone_final_output_handler(struct tone_file_handle *dec, s16 *data, int len)
{
#if 1
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
if (file_dec->dvol) {
audio_digital_vol_run(file_dec->dvol, data, len);
}
#endif
u32 wlen = audio_pwm_write(data, len);
if (wlen != len) {
/* putchar('W'); */
}
return wlen;
#else
put_buf(data, len);
return 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 (dec->remain == 0) {
//get_sine_data(&tmp_cnnt, data, len/2, 1);
}
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);
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;
/* dec->channel = AUDIO_CH_LR; */
dec->channel = AUDIO_CH_L;
audio_decoder_set_output_channel(&dec->decoder, dec->channel);
dec->ch_num = 1;
}
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; */
params.rout_sample_rate = 32000;
#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) {
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 {
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
}
void tone_play_resume_handler(void *priv)
{
if (file_dec) {
/* putchar('Z'); */
audio_decoder_resume(&file_dec->decoder);
}
}
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 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 (1) {//(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
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) {
printf("tone file get fmt err \n");
goto __err1;
}
tone_dec_set_output_channel(file_dec);
audio_pwm_set_resume((void (*)(void *))tone_play_resume_handler);
/* audio_pwm_start(); */
set_state(2);
file_dec->target_sample_rate = fmt->sample_rate;
__dec_start:
#if TCFG_USER_TWS_ENABLE
/* if (file_dec->tws) { */
/* file_decoder_syncts_setup(file_dec); */
/* } */
/* file_dec->tws_align_step = 0; */
#endif
/* sys_hi_timer_add(NULL,tone_play_resume_handler,3); */
#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
#endif
__err1:
audio_decoder_close(&file_dec->decoder);
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) {
printf(">>> %s %d\n", __func__, __LINE__);
err = tone_file_dec_start();
printf(">>> %s %d\n", __func__, __LINE__);
} else if (event == AUDIO_RES_PUT) {
printf(">>> %s %d\n", __func__, __LINE__);
tone_file_list_stop(0);
printf(">>> %s %d\n", __func__, __LINE__);
}
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);
/* extern void audio_pwm_close(void); */
/* audio_pwm_close(); */
#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
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");
/* audio_pwm_stop(); */
set_state(0);
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
};*/
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 (IS_REPEAT_BEGIN(list[0])) {
index = 1;
}
printf(">>> %s %d\n", __func__, __LINE__);
file = fopen(list[index], "r");
if (!file) {
return -EINVAL;
}
printf(">>> %s %d\n", __func__, __LINE__);
fget_name(file, file_name, 16);
format = get_file_ext_name((char *)file_name);
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;
printf(">>> %s %d\n", __func__, __LINE__);
/*AAC提示音默认打断播放*/
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 {
#if TONE_FILE_DEC_MIX
fadsf
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;
printf(">>> %s %d\n", __func__, __LINE__);
err = audio_decoder_task_add_wait(&decode_task, &tone_dec->wait);
printf(">>> %s %d\n", __func__, __LINE__);
#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
printf(">>> %s %d\n", __func__, __LINE__);
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();
}
}
printf(">>> %s %d\n", __func__, __LINE__);
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;
}
printf(">>> %s %d\n", __func__, __LINE__);
if (tone_dec == NULL) {
tone_dec = zalloc(sizeof(*tone_dec));
if (tone_dec == NULL) {
log_error("tone dec zalloc failed");
return -ENOMEM;
}
}
printf(">>> %s %d\n", __func__, __LINE__);
while (list[i] != NULL) {
i++;
}
printf(">>> %s %d\n", __func__, __LINE__);
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;
}
printf(">>> %s %d\n", __func__, __LINE__);
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");
}
printf(">>> %s %d\n", __func__, __LINE__);
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)
{
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)
{
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)
{
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)
{
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);
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]);
}
}
printf("tone_dec idle now\n");
return -1;
}