#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; }