#include "asm/includes.h"
#include "media/includes.h"
#include "system/includes.h"
#include "app_config.h"
#include "audio_config.h"
#include "audio_dec.h"
#include "tone_player.h"
#include "sine_make.h"

#if TCFG_KEY_TONE_EN

// 按键提示音任务名
#define AUDIO_KEY_TONE_TASK_NAME				"key_tone"

// 按键提示音数字音量控制
#if SYS_DIGVOL_GROUP_EN
#define AUDIO_KEY_TONE_DIGVOL_EN				0
#define AUDIO_KEY_TONE_DIGVOL_NAME				"key_tone"
#else
#define AUDIO_KEY_TONE_DIGVOL_EN				0
#endif


//////////////////////////////////////////////////////////////////////////////

/*
 * 使用audio_dec_app.h里面的接口，可以实现普通文件、正弦波文件、正弦波数组播放
 */

// 参数
struct __key_tone_play_info {
    const char *file_name;			// 文件名
    struct audio_sin_param *sin;	// 正弦波数组
    u8 sin_num;						// 正弦波数组长度
    u8 preemption;					// 1-抢占，0-叠加
    void (*evt_handler)(void *priv, int flag);	// 事件回调
    void *evt_priv;					// 事件回调私有句柄
};

// 按键提示音
struct __key_tone {
    volatile u8	busy;		// 任务工作中
    volatile u8	start;		// 运行标志
    volatile u8 play;
#if AUDIO_KEY_TONE_DIGVOL_EN
    u8 volume;				// 音量
#endif
    struct __key_tone_play_info play_info;		// 输入参数
    struct audio_dec_sine_app_hdl *dec_sin;		// 文件播放句柄
    struct audio_dec_file_app_hdl *dec_file;	// sine播放句柄
    void (*evt_handler)(void *priv, int flag);	// 事件回调
    void *evt_priv;			// 事件回调私有句柄
    const char *evt_owner;	// 事件回调所在任务
};

//////////////////////////////////////////////////////////////////////////////

static struct __key_tone *key_tone = NULL;

//////////////////////////////////////////////////////////////////////////////

/*
*********************************************************************
*                  Audio Key Tone Get File Ext Name
* Description: 获取文件名后缀
* Arguments  : *name		文件名
* Return	 : 后缀
* Note(s)    : None.
*********************************************************************
*/
static char *get_file_ext_name(char *name)
{
    int len = strlen(name);
    char *ext = (char *)name;

    while (len--) {
        if (*ext++ == '.') {
            break;
        }
    }
    if (len <= 0) {
        ext = name + (strlen(name) - 3);
    }

    return ext;
}

/*
*********************************************************************
*                  Audio Key Tone Post Event
* Description: 解码事件
* Arguments  : *ktone		按键提示音解码句柄
*              end_flag		结束标志
* Return	 : true		成功
* Note(s)    : None.
*********************************************************************
*/
static int key_tone_dec_event_handler(struct __key_tone *ktone, u8 end_flag)
{
    int argv[4];
    if (!ktone->evt_handler) {
        log_i("evt_handler null\n");
        return false;
    }
    argv[0] = (int)ktone->evt_handler;
    argv[1] = 2;
    argv[2] = (int)ktone->evt_priv;
    argv[3] = (int)end_flag; //0正常关闭，1被打断关闭

    int ret = os_taskq_post_type(ktone->evt_owner, Q_CALLBACK, 4, argv);
    if (ret) {
        return false;
    }
    return true;
}

/*
*********************************************************************
*                  Audio Key Tone Reelease
* Description: 提示音解码器释放
* Arguments  : *ktone		按键提示音解码句柄
* Return	 : None.
* Note(s)    : None.
*********************************************************************
*/
static void key_tone_dec_hdl_release(struct __key_tone *ktone)
{
    if (ktone->dec_file) {
        audio_dec_file_app_close(ktone->dec_file);
        ktone->dec_file = NULL;
    }
    if (ktone->dec_sin) {
        audio_dec_sine_app_close(ktone->dec_sin);
        ktone->dec_sin = NULL;
    }
    /* app_audio_state_exit(APP_AUDIO_STATE_WTONE); */
    /* clock_remove_set(DEC_TONE_CLK); */
}

/*
*********************************************************************
*                  Audio Key Tone Init OK
* Description: 解码初始化完成
* Arguments  : *ktone		按键提示音解码句柄
* Return	 : None.
* Note(s)    : None.
*********************************************************************
*/
static void key_tone_dec_hdl_init_ok(struct __key_tone *ktone)
{
    /* app_audio_state_switch(APP_AUDIO_STATE_WTONE, get_tone_vol()); */
    /* clock_add_set(DEC_TONE_CLK); */
}

/*
*********************************************************************
*                  Audio Key Tone Close
* Description: 关闭提示音解码
* Arguments  : *ktone		按键提示音解码句柄
* Return	 : None.
* Note(s)    : None.
*********************************************************************
*/
static void key_tone_play_close(struct __key_tone *ktone)
{
    /* log_i("ktone:0x%x, sin:0x%x, file:0x%x \n", ktone, ktone->dec_file, ktone->dec_file); */
    if (ktone->dec_file || ktone->dec_sin) {
        key_tone_dec_hdl_release(ktone);
        key_tone_dec_event_handler(ktone, 1);
    }
}

/*
*********************************************************************
*                  Audio Key Tone Event Callback
* Description: 解码回调处理
* Arguments  : *ktone		按键提示音解码句柄
*              event		事件
*              *param		事件参数
* Return	 : 0	正常
* Note(s)    : None.
*********************************************************************
*/
static int key_tone_dec_app_evt_cb(struct __key_tone *ktone, enum audio_dec_app_event event, int *param)
{
    switch (event) {
    case AUDIO_DEC_APP_EVENT_START_INIT_OK:
        log_i("key_tone start init ok\n");
        key_tone_dec_hdl_init_ok(ktone);
        break;
    case AUDIO_DEC_APP_EVENT_PLAY_END:
        log_i("key_tone play end\n");
        key_tone_dec_hdl_release(ktone);
        key_tone_dec_event_handler(ktone, 0);
        break;
    case AUDIO_DEC_APP_EVENT_STREAM_OPEN: {
#if AUDIO_KEY_TONE_DIGVOL_EN
        struct audio_dec_stream_entries_hdl *entries_hdl = (struct audio_dec_stream_entries_hdl *)param;
        void *dvol_entry = NULL;
        audio_dig_vol_param temp_digvol_param = {
            .vol_start = ktone->volume,//get_max_sys_vol(),
            .vol_max =  get_max_sys_vol(),
            .ch_total = audio_output_channel_num(),
            .fade_en = 0,
            .fade_points_step = 5,
            .fade_gain_step = 10,
            .vol_list = NULL,
        };
        dvol_entry = sys_digvol_group_ch_open(AUDIO_KEY_TONE_DIGVOL_NAME, -1, &temp_digvol_param);
        (entries_hdl->entries_addr)[entries_hdl->entries_cnt++] = dvol_entry;
#endif // SYS_DIGVOL_GROUP_EN
    }
    break;

    case AUDIO_DEC_APP_EVENT_DEC_CLOSE:

#if AUDIO_KEY_TONE_DIGVOL_EN
        sys_digvol_group_ch_close(AUDIO_KEY_TONE_DIGVOL_NAME);
#endif // SYS_DIGVOL_GROUP_EN

        break;
    case AUDIO_DEC_APP_EVENT_STREAM_CLOSE: {
    }
    break;

    default :
        break;
    }

    return 0;
}

/*
*********************************************************************
*                  Audio Key Tone Sin Event Callback
* Description: sine提示音解码回调
* Arguments  : *priv		私有句柄
*              event		事件
*              *param		事件参数
* Return	 : 0	正常
* Note(s)    : None.
*********************************************************************
*/
static int key_tone_dec_sine_app_evt_cb(void *priv, enum audio_dec_app_event event, int *param)
{
    struct audio_dec_sine_app_hdl *sine_dec = priv;
    struct __key_tone *ktone = sine_dec->priv;
    switch (event) {
    case AUDIO_DEC_APP_EVENT_DEC_PROBE:
        if (sine_dec->sin_maker) {
            break;
        }
        audio_dec_sine_app_probe(sine_dec);
        if (!sine_dec->sin_maker) {
            return -ENOENT;
        }
        break;

    default :
        return key_tone_dec_app_evt_cb(ktone, event, param);
    }

    return 0;
}

/*
*********************************************************************
*                  Audio Key Tone File Event Callback
* Description: file提示音解码回调
* Arguments  : *priv		私有句柄
*              event		事件
*              *param		事件参数
* Return	 : 0	正常
* Note(s)    : None.
*********************************************************************
*/
static int key_tone_dec_file_app_evt_cb(void *priv, enum audio_dec_app_event event, int *param)
{
    struct audio_dec_file_app_hdl *file_dec = priv;
    struct __key_tone *ktone = file_dec->priv;
    switch (event) {
    case AUDIO_DEC_APP_EVENT_DEC_PROBE:
        break;
    default :
        return key_tone_dec_app_evt_cb(ktone, event, param);
    }

    return 0;
}

/*
*********************************************************************
*                  Audio Key Tone Run
* Description: 按键提示音运行
* Arguments  : *ktone		按键提示音解码句柄
* Return	 : 0	正常
* Note(s)    : None.
*********************************************************************
*/
static int key_tone_play_run(struct __key_tone *ktone)
{
    if (!ktone->start) {
        return -1;
    }

    struct __key_tone_play_info info = {0};
    local_irq_disable();
    if (!ktone->play) {
        local_irq_enable();
        return 0;
    }
    // 保存播放参数
    memcpy(&info, &ktone->play_info, sizeof(struct __key_tone_play_info));
    ktone->play = 0;
    local_irq_enable();

    // 关闭现有play
    key_tone_play_close(ktone);

    // 设置参数
    ktone->evt_handler = info.evt_handler;
    ktone->evt_priv = info.evt_priv;
    ktone->evt_owner = "app_core";

    // 正弦波数组播放
    if (info.sin && info.sin_num) {
        ktone->dec_sin = audio_dec_sine_app_create_by_parm(info.sin, info.sin_num, !info.preemption);
        if (ktone->dec_sin == NULL) {
            return -1;
        }
        ktone->dec_sin->dec->evt_cb = key_tone_dec_sine_app_evt_cb;
        ktone->dec_sin->priv = ktone;
        audio_dec_sine_app_open(ktone->dec_sin);
        return 0;
    }

    // 判断文件名后缀
    u8 file_name[16];
    char *format = NULL;
    FILE *file = fopen(info.file_name, "r");
    if (!file) {
        return -1;
    }
    fget_name(file, file_name, 16);
    format = get_file_ext_name((char *)file_name);
    fclose(file);

    // 正弦波文件播放
    if (ASCII_StrCmpNoCase(format, "sin", 3) == 0) {
        ktone->dec_sin = audio_dec_sine_app_create(info.file_name, !info.preemption);
        if (ktone->dec_sin == NULL) {
            return -1;
        }
        ktone->dec_sin->dec->evt_cb = key_tone_dec_sine_app_evt_cb;
        ktone->dec_sin->priv = ktone;
        audio_dec_sine_app_open(ktone->dec_sin);
        return 0;
    }

    // 普通文件播放
    ktone->dec_file = audio_dec_file_app_create(info.file_name, !info.preemption);
    if (ktone->dec_file == NULL) {
        return -1;
    }
    if (ktone->dec_file->dec->dec_type == AUDIO_CODING_SBC) {
        audio_dec_app_set_frame_info(ktone->dec_file->dec, 0x4e, ktone->dec_file->dec->dec_type);
    }
    ktone->dec_file->dec->evt_cb = key_tone_dec_file_app_evt_cb;
    ktone->dec_file->priv = ktone;
    audio_dec_file_app_open(ktone->dec_file);
    return 0;
}

/*
*********************************************************************
*                  Audio Key Tone Task Run
* Description: 按键提示音任务处理
* Arguments  : *p		按键提示音解码句柄
* Return	 : None.
* Note(s)    : None.
*********************************************************************
*/
static void key_tone_task_deal(void *p)
{
    int res = 0;
    int msg[16];
    struct __key_tone *ktone = (struct __key_tone *)p;
    ktone->start = 1;
    ktone->busy = 1;
    while (1) {
        __os_taskq_pend(msg, ARRAY_SIZE(msg), portMAX_DELAY);
        res = key_tone_play_run(ktone);
        if (res) {
            ///等待删除线程
            key_tone_play_close(ktone);
            ktone->busy = 0;
            while (1) {
                os_time_dly(10000);
            }
        }
    }
}

/*
*********************************************************************
*                  Audio Key Tone Destroy
* Description: 注销按键提示音播放
* Arguments  : None.
* Return	 : None.
* Note(s)    : None.
*********************************************************************
*/
void audio_key_tone_destroy(void)
{
    if (!key_tone) {
        return ;
    }

    key_tone->start = 0;

    while (key_tone->busy) {
        os_taskq_post_msg(AUDIO_KEY_TONE_TASK_NAME, 1, 0);
        os_time_dly(1);
    }

    task_kill(AUDIO_KEY_TONE_TASK_NAME);

    local_irq_disable();
    free(key_tone);
    key_tone = NULL;
    local_irq_enable();
}

/*
*********************************************************************
*                  Audio Key Tone Init
* Description: 按键提示音初始化
* Arguments  : None.
* Return	 : true		成功
* Note(s)    : None.
*********************************************************************
*/
int audio_key_tone_init(void)
{
    int err = 0;
    if (key_tone) {
        return true;
    }
    struct __key_tone *ktone = zalloc(sizeof(struct __key_tone));
    err = task_create(key_tone_task_deal, (void *)ktone, AUDIO_KEY_TONE_TASK_NAME);
    if (err != OS_NO_ERR) {
        log_e("%s creat fail %x\n", __FUNCTION__,  err);
        free(ktone);
        return false;
    }
#if AUDIO_KEY_TONE_DIGVOL_EN
    ktone->volume = get_max_sys_vol();
#endif
    key_tone = ktone;
    return true;
}

//////////////////////////////////////////////////////////////////////////////

// 正弦波序号
#define KTONE_SINE_NORAML           0

// 按键提示音序号
enum {
    KTONE_IDEX_NORAML = 0,
    KTONE_IDEX_NUM_0,
    KTONE_IDEX_NUM_1,

    KTONE_IDEX_MAX,
};

// 序号对应表
static const char *const key_tone_index[] = {
    [KTONE_IDEX_NORAML] 	= DEFAULT_SINE_TONE(KTONE_SINE_NORAML),
    [KTONE_IDEX_NUM_0] 		= SDFILE_RES_ROOT_PATH"tone/0.*",
    [KTONE_IDEX_NUM_1] 		= SDFILE_RES_ROOT_PATH"tone/1.*",
};

/*
 * 正弦波参数配置:
 * freq : 实际频率 * 512
 * points : 正弦波点数
 * win : 正弦窗
 * decay : 衰减系数(百分比), 正弦窗模式下为频率设置：频率*512
 */
static const struct sin_param sine_16k_normal[] = {
    /*{0, 1000, 0, 100},*/
    {200 << 9, 4000, 0, 100},
};


//////////////////////////////////////////////////////////////////////////////

/*
*********************************************************************
*                  Audio Key Tone Get Sine Param Data
* Description: 获取正弦波数组
* Arguments  : id		正弦波序号
*              *num		正弦波数组长度
* Return	 : 正弦波数组
* Note(s)    : None.
*********************************************************************
*/
static const struct sin_param *get_sine_param_data(u8 id, u8 *num)
{
    const struct sin_param *param_data = NULL;
    switch (id) {
    case KTONE_SINE_NORAML:
        param_data = sine_16k_normal;
        *num = ARRAY_SIZE(sine_16k_normal);
        break;
    default:
        return NULL;
    }
    return param_data;
};

/*
*********************************************************************
*                  Audio Key Tone Open With Callback
* Description: 打开文件播放
* Arguments  : *file_name		文件名
*              *sin				正弦波数组
*              sin_num			正弦波数组长度
*              preemption		1-抢断播放；0-叠加播放
*              evt_handler		事件回调
*              evt_priv			事件回调参数
* Return	 : 0	正常
* Note(s)    : None.
*********************************************************************
*/
static int ktone_play_open_with_callback_base(const char *file_name, struct audio_sin_param *sin, u8 sin_num, u8 preemption, void (*evt_handler)(void *priv, int flag), void *evt_priv)
{
    struct __key_tone *ktone = key_tone;
    if ((!ktone) || (!ktone->start)) {
        return -1;
    }

    struct __key_tone_play_info info = {0};
    info.preemption = preemption;
    info.evt_handler = evt_handler;
    info.evt_priv = evt_priv;
    if (sin && sin_num) {
        info.sin = sin;
        info.sin_num = sin_num;
    } else {
        info.file_name = file_name;
        if (IS_DEFAULT_SINE(file_name)) {
            info.sin = get_sine_param_data(DEFAULT_SINE_ID(file_name), &info.sin_num);
        }
    }

    local_irq_disable();
    memcpy(&ktone->play_info, &info, sizeof(struct __key_tone_play_info));
    ktone->play = 1;
    local_irq_enable();

    os_taskq_post_msg(AUDIO_KEY_TONE_TASK_NAME, 1, 0);

    return 0;
}

/*
*********************************************************************
*                  Audio Key Tone Play Sine
* Description: 播放正弦波数组
* Arguments  : *sin				正弦波数组
*              sin_num			正弦波数组长度
*              preemption		1-抢断播放；0-叠加播放
* Return	 : 0	正常
* Note(s)    : None.
*********************************************************************
*/
int audio_key_tone_play_sin(struct audio_sin_param *sin, u8 sin_num, u8 preemption)
{
    /* y_printf("n:0x%x \n", name); */
    return ktone_play_open_with_callback_base(NULL, sin, sin_num, preemption, NULL, NULL);
}

/*
*********************************************************************
*                  Audio Key Tone Play File
* Description: 播放文件
* Arguments  : *name			文件名
*              preemption		1-抢断播放；0-叠加播放
* Return	 : 0	正常
* Note(s)    : None.
*********************************************************************
*/
int audio_key_tone_play_name(const char *name, u8 preemption)
{
    /* y_printf("n:0x%x \n", name); */
    return ktone_play_open_with_callback_base(name, NULL, 0, preemption, NULL, NULL);
}

/*
*********************************************************************
*                  Audio Key Tone Play Index
* Description: 按序号播放文件
* Arguments  : index			序号
*              preemption		1-抢断播放；0-叠加播放
* Return	 : 0	正常
* Note(s)    : 使用key_tone_index[]数组
*********************************************************************
*/
int audio_key_tone_play_index(u8 index, u8 preemption)
{
    if (index >= KTONE_IDEX_MAX) {
        return -1;
    }
    return audio_key_tone_play_name(key_tone_index[index], preemption);
}

/*
*********************************************************************
*                  Audio Key Tone Play
* Description: 按键提示音播放
* Arguments  : None.
* Return	 : None.
* Note(s)    : 默认播放
*********************************************************************
*/
void audio_key_tone_play(void)
{
    audio_key_tone_play_index(KTONE_IDEX_NORAML, 0);
    /* audio_key_tone_play_index(KTONE_IDEX_NUM_0, 0); */
    /* audio_key_tone_play_sin(sine_16k_normal, ARRAY_SIZE(sine_16k_normal), 0); */
}

/*
*********************************************************************
*                  Audio Key Tone Check Play
* Description: 检测按键提示音是否在播放
* Arguments  : None.
* Return	 : true		正在播放
* Note(s)    : None.
*********************************************************************
*/
int audio_key_tone_is_play(void)
{
    if ((!key_tone) || (!key_tone->start)) {
        return false;
    }
    if (key_tone->dec_file || key_tone->dec_sin) {
        return true;
    }
    return false;
}

/*
*********************************************************************
*                  Audio Key Tone Set Digvol
* Description: 设置按键提示音的音量
* Arguments  : volume		音量
* Return	 : None.
* Note(s)    : None.
*********************************************************************
*/
void audio_key_tone_digvol_set(u8 volume)
{
#if AUDIO_KEY_TONE_DIGVOL_EN
    log_i("vol:%d \n", volume);
    if (!key_tone) {
        return ;
    }
    key_tone->volume = volume;
    void *vol_hdl = audio_dig_vol_group_hdl_get(sys_digvol_group, AUDIO_KEY_TONE_DIGVOL_NAME);
    if (vol_hdl == NULL) {
        return;
    }
    audio_dig_vol_set(vol_hdl, AUDIO_DIG_VOL_ALL_CH, volume);
#endif
}


#endif

