/*
 * Copyright (c) 2019 Actions Semiconductor Co., Ltd
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file bluetooth tws observer interface
 */

#include "bluetooth_tws_observer.h"
#include "utils/acts_ringbuf.h"

#define SYS_LOG_NO_NEWLINE
#ifdef SYS_LOG_DOMAIN
#undef SYS_LOG_DOMAIN
#endif
#define SYS_LOG_DOMAIN "bt_tws"

/*
1、如果两边都处于等待播放状态，设备收到对方的splay后，
   若收到的对方的起始播放时钟小于当前bt时钟，则做出错处理
   包号相同，则用时间较晚的中断时钟作为开始播放时间，重新设置tws中断时间
   若包号不同，则以包号大的作为起始播放包号和时钟，设置为PLAYER_TWS_USE_LOCAL_SPLAY模式，丢弃包号小的码流包
2、如果当前设备已经开始播放，收到到对方的splay包，
   则从当前缓存的码流包中，挑选一个比较靠后的包，计算播放时间，给对方发一个PLAYER_TWS_USE_LOCAL_SPLAY
   若码流缓存信息不足，则向对方发送PLAYER_TWS_NEED_NEW_SPLAY，对方收到消息后，重新发送splay过来
*/

//tws中断启动最小间隔,us
#define TWS_MIN_INTERVAL     (20000)

/* splay_flag的说明
 * 1: 本端处于PLAYING状态, 暂时只支持对端处于WAIT PLAY状态, 希望对端重新发一次splay包过来, 因为本端缓存的包里面没有对端的包号
 * 2: 本端处于PLAYING状态, 希望对端以本端的包号和时间来播放
 * 3: 本端处于WAIT PLAY状态, 若对端不是PLAYING, 希望对端考虑是否接受本端的包号和时间, 若对端是PLAYING, 希望对端提供可以播放的包号和时间
 */
#define PLAYER_TWS_NEED_NEW_SPLAY    1
#define PLAYER_TWS_USE_LOCAL_SPLAY   2
#define PLAYER_TWS_USE_START_SPLAY   3

#define PLAYER_TWS_SYNCITEM_MAXNUM      10      /* TWS同步信息包最大缓存个数 */
#define PLAYER_TWS_ERRCOUNT_MAXNUM      10      /* TWS失去同步状态的超时时间 */
#define PLAYER_TWS_DATA_MAXNUM      5      /* 暂存从对端接收到的消息个数 */
#define PLAYER_TWS_MSG_MAXNUM      5      /* 暂存从中间件api接收到的消息个数 */
#define BT_TWS_TIMER_INTERVAL     (3)


typedef enum
{
    TWS_STARTPLAY_PKT = 1,       /* 启动播放包 */
    TWS_STARTSTOP_PKT,       /* 停止播放包 */
    TWS_SYNCINFO_PKT,    /* 同步信息包 */
    TWS_PLAYRATE_PKT,        /* 速度调节包 */
    TWS_INTTIME_PKT,         /* 中断时间包 */
    TWS_BTTIME_PKT,          /* 蓝牙时间包 */
} player_tws_type_e;

/* TWS数据包, 需和tws_sync_cmd_t保持一致
 */
typedef struct
{
    uint8_t group;  /* 参考 player_tws_group_e */
    uint8_t type;   /* 参考 player_tws_type_e */
    uint8_t reserve;
    uint8_t payload_len;
    uint8_t payload_data[16]; /* buf需要4字节对齐, 避免直接赋值导致死机 */
} player_tws_pkt_t;

typedef struct
{
    uint8_t scene; /* 播放场景, 避免不同场景的数据包误判, player_id_e */
    uint8_t splay_flag; /* 本端发送SPLAY的时候告知对端的操作类型, PLAYER_TWS_NEED_NEW_SPLAY... */
    uint16_t pkt_num; /* 开始播放的首包号 */
    uint64_t splay_time; /* 开始播放的时钟 us */
    uint32_t first_clk; /* 本端接收到第一个数据包时的时钟 */
} player_tws_startplay_pkt_t;

typedef struct
{
    uint8_t scene; /* 播放场景, 避免不同场景的数据包误判 */
    uint8_t reserve[3];
    uint64_t startstop_time; /* 开始播放的时钟 us */
} player_tws_startstop_pkt_t;

typedef struct
{
    uint8_t   scene;
    uint16_t  pkt_num; /* 表示播放的数据包号 */
    uint8_t   reserve;
    uint64_t  bttime_us; /* 表示播放对应包号时对应的蓝牙时钟 us */
} player_tws_syncinfo_pkt_t;

typedef struct
{
    uint8_t  scene;
    uint8_t  aps_level;
    uint8_t  reserve[2];
    uint64_t inttime;  /* 中断时间 us */
} player_tws_playrate_pkt_t;

typedef enum
{
    PLAYER_TWS_STATUS_INIT,     /* 执行init后的状态 */
    PLAYER_TWS_STATUS_WAIT,     /* 执行wait play后的状态 */
    PLAYER_TWS_STATUS_DEAL_WAIT,/* 执行deal start play后的状态 */
    PLAYER_TWS_STATUS_PLAY,     /* 真正播放数据的状态 */
} player_tws_status_e;

typedef struct
{
    uint16_t pkt_num; /* 包号 */
    uint16_t pkt_len; /* 包的数据长度 */
    uint16_t samples; /* 样点数 */
    uint64_t pkt_bttime_us; /* 蓝牙时钟 us */
} player_tws_pinfo_unit_t;

/* TWS消息
 */
typedef struct
{
    uint8_t type;   /* 参考 player_tws_type_e */
    uint8_t data[15];
} __attribute__((packed)) player_tws_msg_t;

typedef struct {
    bt_tws_observer_t tws_observer;
    media_observer_t *media_observer;
    struct k_timer timer;

    uint8_t format;
    uint16_t sample_rate;  //hz
    uint16_t first_pktnum;
    uint32_t first_clk;

    //以下信息会被中断函数访问
    uint8_t tws_status;
    int8_t aps_level_pending;   /* 即将要设置的aps等级 */
    uint64_t aps_inttime;

    //以下信息会被多线程访问
    struct acts_ringbuf tws_data_buffer;
    player_tws_pkt_t tws_data[PLAYER_TWS_DATA_MAXNUM];

    uint8_t tws_role;
    uint8_t last_sinfo_flag;
    uint8_t first_pkt_flag;
    uint8_t sync_error_count; /* 同步错误计数 */
    int8_t adjust_shake_flag;   /* 防抖，master和slave前后两个包的时间差一致 */
    uint64_t splay_local_time; /* 近端开始播放的时间 */
    uint64_t forbit_aps_time; /* 在此时间前禁止调节水位aps */
    
    struct acts_ringbuf sinfo_master_buffer;
    struct acts_ringbuf sinfo_slave_buffer;
    struct acts_ringbuf msg_buffer;
    player_tws_syncinfo_pkt_t sinfo_master[PLAYER_TWS_SYNCITEM_MAXNUM];
    player_tws_syncinfo_pkt_t sinfo_slave[PLAYER_TWS_SYNCITEM_MAXNUM];
    player_tws_msg_t msg_data[PLAYER_TWS_MSG_MAXNUM];

    /* 包信息单元
     */
    uint8_t pinfo_unit_idx;
    uint8_t save_pinfo_count; /* 包信息保存计数 */
    player_tws_pinfo_unit_t pinfo_unit[2];

    uint16_t BM_TWS_WPlay_Mintime;
    uint16_t BM_TWS_WPlay_Maxtime;
    uint16_t BM_TWS_Sync_interval;
} bt_tws_observer_inner_t;

static bt_tws_observer_inner_t observer_inner;


/*----------------------------------------------------------------------------------------------------*/
//callback from irq
static void _tws_irq_handle(uint64_t bt_clk_us)
{
    bt_tws_observer_inner_t *handle = &observer_inner;
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)handle->media_observer->tws_observer;
    
    if(handle->tws_status == PLAYER_TWS_STATUS_DEAL_WAIT)
    {
        handle->tws_status = PLAYER_TWS_STATUS_PLAY;
        handle->media_observer->start_playback(handle->media_observer->media_handle);
        printf("[ATW]start playback\n");
        return;
    }

    /* 调节速度中断(TWS播放时才有效)
     */
    if((handle->aps_level_pending >= 0)
        && (handle->aps_inttime == bt_clk_us)
        && (handle->tws_status == PLAYER_TWS_STATUS_PLAY))
    {
        handle->media_observer->set_base_aps_level(handle->media_observer->media_handle, handle->aps_level_pending);
        printf("[ATW]aps int:%d\n", handle->aps_level_pending);
        handle->aps_level_pending = -1;
    }
}

//callback from normal thread
static void _tws_recv_pkt_handle(void *buf, int32_t size)
{
    bt_tws_observer_inner_t *handle = &observer_inner;
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)handle->media_observer->tws_observer;
    player_tws_pkt_t *pkt = (player_tws_pkt_t*)buf;

    if(handle->tws_status == PLAYER_TWS_STATUS_INIT)
        return;
    if(size != sizeof(player_tws_pkt_t))
    {
        SYS_LOG_ERR("size: %d invalid, normal size: %d", size, sizeof(player_tws_pkt_t));
        return;
    }

    if(acts_ringbuf_space(&handle->tws_data_buffer) < sizeof(player_tws_pkt_t))
    {
        SYS_LOG_ERR("tws data buffer full");
        return;
    }
    
    acts_ringbuf_put(&handle->tws_data_buffer, buf, size);
}

/*----------------------------------------------------------------------------------------------------*/
static int32_t _tws_send_start_play(bt_tws_observer_inner_t *handle, player_tws_startplay_pkt_t *startplay)
{
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)handle->media_observer->tws_observer;
    player_tws_pkt_t pkt;
    int32_t ret;

    SYS_LOG_INF("set SPlay, pktnum: %d, time: %lld, fclk: %d, flag: %d",
        startplay->pkt_num, startplay->splay_time, startplay->first_clk, startplay->splay_flag);

    startplay->scene = handle->format;
    pkt.group = 0;
    pkt.type = TWS_STARTPLAY_PKT;
    pkt.payload_len = sizeof(player_tws_startplay_pkt_t);
    memcpy(pkt.payload_data, startplay, sizeof(player_tws_startplay_pkt_t));
    
    ret = observer->send_pkt(&pkt, sizeof(pkt));
    if(ret != sizeof(pkt))
        return -1;
    return 0;
}

/* 返回0: 表示数据包没有发送出去
 */
static int32_t _tws_send_start_stop(bt_tws_observer_inner_t *handle, player_tws_startstop_pkt_t *startstop)
{
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)handle->media_observer->tws_observer;
    player_tws_pkt_t pkt;
    int32_t ret;

    SYS_LOG_INF("set SStop: %lld", startstop->startstop_time);

    startstop->scene = handle->format;
    pkt.group = 0;
    pkt.type = TWS_STARTSTOP_PKT;
    pkt.payload_len = sizeof(player_tws_startstop_pkt_t);
    memcpy(pkt.payload_data, startstop, sizeof(player_tws_startstop_pkt_t));

    ret = observer->send_pkt(&pkt, sizeof(pkt));
    if(ret != sizeof(pkt))
        return -1;
    return 0;
}

/* 返回0: 表示数据包没有发送出去
 */
static int32_t _tws_send_sync_info(bt_tws_observer_inner_t *handle, player_tws_syncinfo_pkt_t *syncinfo)
{
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)handle->media_observer->tws_observer;
    player_tws_pkt_t pkt;
    int32_t ret;

    SYS_LOG_INF("set SInfo, pktnum: %d, time: %lld", syncinfo->pkt_num, syncinfo->bttime_us);

    syncinfo->scene = handle->format;
    pkt.group = 0;
    pkt.type = TWS_SYNCINFO_PKT;
    pkt.payload_len = sizeof(player_tws_syncinfo_pkt_t);
    memcpy(pkt.payload_data, syncinfo, sizeof(player_tws_syncinfo_pkt_t));

    ret = observer->send_pkt(&pkt, sizeof(pkt));
    if(ret != sizeof(pkt))
        return -1;
    return 0;
}

/* 返回0: 表示数据包没有发送出去
 */
static int32_t _tws_send_play_rate(bt_tws_observer_inner_t *handle, player_tws_playrate_pkt_t *playrate)
{
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)handle->media_observer->tws_observer;
    player_tws_pkt_t pkt;
    int32_t ret;

    SYS_LOG_INF("set PRate, aps: %d, time: %lld\n", playrate->aps_level, playrate->inttime);

    playrate->scene = handle->format;
    pkt.group = 0;
    pkt.type = TWS_PLAYRATE_PKT;
    pkt.payload_len = sizeof(player_tws_playrate_pkt_t);
    memcpy(pkt.payload_data, (uint8_t *)playrate, sizeof(player_tws_playrate_pkt_t));

    ret = observer->send_pkt(&pkt, sizeof(pkt));
    if(ret != sizeof(pkt))
        return -1;
    return 0;
}

/* 检测包信息: 0 表示不保存包信息单元, -1 表示需要重启播放器, 1 表示正常存储包信息单元
 */
static int32_t _tws_check_pinfo_unit(bt_tws_observer_inner_t *handle, uint16_t cur_pkt_num, uint16_t cur_pkt_len, uint16_t samples)
{
    if(cur_pkt_len == 0)
        return 0;

    if((cur_pkt_num == handle->pinfo_unit[handle->pinfo_unit_idx].pkt_num)
        && (handle->pinfo_unit[handle->pinfo_unit_idx].pkt_len != 0))
    {
        handle->pinfo_unit[handle->pinfo_unit_idx].samples += samples;
        return 0;
    }

    if(cur_pkt_num != (handle->pinfo_unit[handle->pinfo_unit_idx].pkt_num + 1))
    {
        /* 正在播放如果包号不连续立即重启播放(!=1:避免包号循环, !=0:避免包号开始)
         */
        if((cur_pkt_num != 1) && (handle->pinfo_unit[handle->pinfo_unit_idx].pkt_num != 0))
            return -1;
    }

    return 1;
}

static int32_t _tws_update_sync_info(bt_tws_observer_inner_t *handle, tws_pkt_info_t *pkt_info)
{
    /* 更新idx及其内容
     */
    handle->pinfo_unit_idx ++;
    if(handle->pinfo_unit_idx > 1)
        handle->pinfo_unit_idx = 0;

    handle->pinfo_unit[handle->pinfo_unit_idx].pkt_len = pkt_info->pkt_len;
    handle->pinfo_unit[handle->pinfo_unit_idx].pkt_num = pkt_info->pkt_num;
    handle->pinfo_unit[handle->pinfo_unit_idx].samples = pkt_info->samples;
    handle->pinfo_unit[handle->pinfo_unit_idx].pkt_bttime_us = pkt_info->pkt_bttime_us;

    /* 确保3次之后才处理SPLAY包避免开始的包不全导致计算对端播放时间出错
     */
    handle->save_pinfo_count ++;
    if(handle->save_pinfo_count > 3)
        handle->save_pinfo_count = 3;

    return 0;
}

/* 返回-1:slave_pool或maste_pool没有item
   返回 0:遍历完后没有找到相同包号的item
   返回 1:找到相同包号的item并从参数传出来
 */
static int32_t _tws_search_sinfo_item(bt_tws_observer_inner_t *handle, player_tws_syncinfo_pkt_t *slave, player_tws_syncinfo_pkt_t *maste)
{
    uint8_t slave_keep = 1, maste_keep = 1;
    player_tws_syncinfo_pkt_t slave_item, maste_item;
    uint8_t item_size = sizeof(player_tws_syncinfo_pkt_t);
    struct acts_ringbuf *slave_pool = &handle->sinfo_slave_buffer;
    struct acts_ringbuf *maste_pool = &handle->sinfo_master_buffer;

    for(;;)
    {
        if(slave_keep == 1)
        {
            if(acts_ringbuf_length(slave_pool) < item_size)
                return -1;
            
            slave_keep = 0;
            acts_ringbuf_peek(slave_pool, &slave_item, item_size);
        }

        if(maste_keep == 1)
        {
            if(acts_ringbuf_length(maste_pool) < item_size)
                return -1;
            
            maste_keep = 0;
            acts_ringbuf_peek(maste_pool, &maste_item, item_size);
        }

        if(slave_item.pkt_num > maste_item.pkt_num)
        {
            maste_keep = 1;
            acts_ringbuf_get(maste_pool, NULL, item_size);
            printf("[ATW]item mkp:%d_%d\n", maste_item.pkt_num, slave_item.pkt_num);
        }
        else if(slave_item.pkt_num < maste_item.pkt_num)
        {
            slave_keep = 1;
            acts_ringbuf_get(slave_pool, NULL, item_size);
            printf("[ATW]item skp:%d_%d\n", maste_item.pkt_num, slave_item.pkt_num);
        }
        else
        {
            printf("[ATW]item get:%d\n", maste_item.pkt_num);
            acts_ringbuf_get(maste_pool, NULL, item_size);
            acts_ringbuf_get(slave_pool, NULL, item_size);
            memcpy(slave, &slave_item, item_size);
            memcpy(maste, &maste_item, item_size);

            break;
        }
    }

    return 1;
}

static int32_t _tws_align_samples(bt_tws_observer_inner_t *handle)
{
    player_tws_syncinfo_pkt_t slave_item, maste_item;
    int32_t clk_diff;
    int32_t result = 0;
    uint8_t item_size = sizeof(player_tws_syncinfo_pkt_t);
    int8_t shake_flag;

    result = _tws_search_sinfo_item(handle, &slave_item, &maste_item);
    if(result <= 0)
    {
        handle->sync_error_count = (result == 0) ? (handle->sync_error_count + 1) : 0;
        if(handle->sync_error_count >= PLAYER_TWS_ERRCOUNT_MAXNUM)
        {
            SYS_LOG_ERR("long time no sync info");
            handle->sync_error_count = 0;
            //todo: restart playback
        }
        return 0;
    }
    
    handle->sync_error_count = 0;
    if(slave_item.bttime_us == maste_item.bttime_us)
        return 0;

    clk_diff = (int32_t)(maste_item.bttime_us - slave_item.bttime_us);
    shake_flag = (clk_diff < 0) ? 1 : -1;

    if((slave_item.pkt_num % handle->BM_TWS_Sync_interval) == 0)
    {
        handle->adjust_shake_flag = shake_flag;
        printf("[ATW]adjust e1:%d_%d\n",  slave_item.pkt_num, clk_diff);
        return 0;
    }

    if(handle->adjust_shake_flag == 0)
        return 0;
    
    if(handle->adjust_shake_flag == shake_flag)
    {
        printf("[ATW]adjust e2:%d_%d\n",  slave_item.pkt_num, clk_diff);
        handle->media_observer->notify_time_diff(handle->media_observer->media_handle, clk_diff);
    }
    
    handle->adjust_shake_flag = 0;
    return 0;
}

/* 根据本端和对端的当前信息计算对端的SPLAY
 */
static int32_t _tws_calculate_new_splay(bt_tws_observer_inner_t *handle, player_tws_startplay_pkt_t *startplay)
{
    uint8_t first_idx = (handle->pinfo_unit_idx == 1) ? 0 : 1;

    /* 要求对端以指定帧播放(当本端还没有足够的播放信息时, 让对端重新发起SPLAY)
     */
    if(handle->save_pinfo_count < 3)
    {
        printf("[ATW]need new splay\n");
        startplay->splay_flag = PLAYER_TWS_NEED_NEW_SPLAY;
        return 0;
    }
    
    startplay->splay_flag = PLAYER_TWS_USE_LOCAL_SPLAY;
    startplay->first_clk = handle->first_clk;
    if(startplay->pkt_num < (handle->pinfo_unit[handle->pinfo_unit_idx].pkt_num + 10))
        startplay->pkt_num = handle->pinfo_unit[handle->pinfo_unit_idx].pkt_num + 10;

    //todo: 根据已经接收的码流计算时间，sbc包长可能会变
    startplay->splay_time = handle->pinfo_unit[first_idx].pkt_bttime_us
        + (startplay->pkt_num - handle->pinfo_unit[first_idx].pkt_num)
        * handle->pinfo_unit[first_idx].samples * 1000000ll / handle->sample_rate;

    printf("[ATW]new splay:%u_%u_%u_%u, %u_%u_%u\n",
        startplay->pkt_num, startplay->first_clk,
        (uint32_t)(startplay->splay_time >> 32) & 0xffffffff,
        (uint32_t)startplay->splay_time & 0xffffffff,
        handle->pinfo_unit[first_idx].pkt_num,
        handle->first_clk,
        handle->pinfo_unit[first_idx].samples);

    return 0;
}

/* 对端要求本端发相同的SPLAY过去
 */
static int32_t _tws_handle_newly_splay(bt_tws_observer_inner_t *handle, player_tws_startplay_pkt_t *startplay, uint64_t *bttus)
{
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)handle->media_observer->tws_observer;

    if((handle->tws_status == PLAYER_TWS_STATUS_PLAY)
        || (handle->tws_status == PLAYER_TWS_STATUS_DEAL_WAIT))
    {
        SYS_LOG_ERR("%u_%u, %u_%u, %u_%u",
            startplay->pkt_num, handle->first_pktnum,
            (uint32_t)(handle->splay_local_time >> 32) & 0xffffffff,
            (uint32_t)handle->splay_local_time & 0xffffffff,
            (uint32_t)(startplay->splay_time >> 32) & 0xffffffff,
            (uint32_t)startplay->splay_time & 0xffffffff);
        return 0;
    }

    startplay->splay_flag = PLAYER_TWS_USE_START_SPLAY;
    startplay->pkt_num = handle->first_pktnum;
    startplay->splay_time = bttus + handle->BM_TWS_WPlay_Mintime * 1000;
    startplay->first_clk = handle->first_clk;
    if(_tws_send_start_play(handle, &startplay) < 0)
    {
        SYS_LOG_ERR("_tws_send_start_play fail.");
        return -1;
    }

    handle->splay_local_time = startplay->splay_time;
    handle->forbit_aps_time = startplay->splay_time + 1500000;
    observer->set_interrupt_time(startplay.splay_time);

    printf("[ATW]handle new splay:%u_%u_%u\n",
        handle->first_pktnum,
        (uint32_t)(startplay->splay_time >> 32) & 0xffffffff,
        (uint32_t)startplay->splay_time & 0xffffffff);
    return 0;
}

/* 对端要求本端解码指定的包播放
 */
static int32_t _tws_handle_local_splay(bt_tws_observer_inner_t *handle, player_tws_startplay_pkt_t *startplay, uint64_t *bttus)
{
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)handle->media_observer->tws_observer;

    if((handle->tws_status == PLAYER_TWS_STATUS_PLAY)
        || (handle->tws_status == PLAYER_TWS_STATUS_DEAL_WAIT))
    {
        SYS_LOG_ERR("%u_%u, %u_%u, %u_%u",
            startplay->pkt_num, handle->first_pktnum,
            (uint32_t)(handle->splay_local_time >> 32) & 0xffffffff,
            (uint32_t)handle->splay_local_time & 0xffffffff,
            (uint32_t)(startplay->splay_time >> 32) & 0xffffffff,
            (uint32_t)startplay->splay_time & 0xffffffff);
        return 0;
    }
    
    /* 对端的包号小于本端则对端需要继续播放并重新指定解码包
     */
    if((startplay->pkt_num < handle->first_pktnum)
        || (bttus >= (startplay->splay_time - TWS_MIN_INTERVAL)))
    {
        SYS_LOG_ERR("%u_%u, %u_%u, %u_%u",
            startplay->pkt_num, handle->first_pktnum,
            (uint32_t)(bttus >> 32) & 0xffffffff,
            (uint32_t)bttus & 0xffffffff,
            (uint32_t)(startplay->splay_time >> 32) & 0xffffffff,
            (uint32_t)startplay->splay_time & 0xffffffff);
        return _tws_handle_newly_splay(handle, startplay, bttus);
    }

    handle->splay_local_time = startplay.splay_time;
    handle->first_pktnum = startplay.pkt_num;
    observer->set_interrupt_time(startplay.splay_time);

    printf("[ATW]handle local splay:%u_%u_%u\n",
        handle->first_pktnum,
        (uint32_t)(startplay->splay_time >> 32) & 0xffffffff,
        (uint32_t)startplay->splay_time & 0xffffffff);

    return 0;
}

/* 对端告诉本端正在启动播放
 */
static int32_t _tws_handle_start_splay(bt_tws_observer_inner_t *handle, player_tws_startplay_pkt_t *startplay, uint64_t *bttus)
{
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)handle->media_observer->tws_observer;
    uint32_t flags;

    if((handle->tws_status == PLAYER_TWS_STATUS_PLAY)
        || (handle->tws_status == PLAYER_TWS_STATUS_DEAL_WAIT))
    {
        /* 确定对端开始播放的蓝牙时钟
         */
        if(_tws_calculate_new_splay(handle, startplay) < 0)
        {
            SYS_LOG_ERR("_tws_calculate_new_splay fail");
            return -1;
        }

        /* 发送给对端样机
         */
        if(_tws_send_start_play(handle, startplay) < 0)
        {
            SYS_LOG_ERR("_tws_send_start_play fail.");
            return -1;
        }
        
        flags = irq_lock();
        //有接入时一段时间不能进行缓冲区调节
        handle->forbit_aps_time = bttus + 1500000;
        handle->aps_level_pending = -1;
        //对端接入后使用基准时钟播放
        handle->media_observer->set_base_aps_level(handle->media_observer->media_handle, 0xFF);
        irq_unlock(flags);

        printf("[ATW]handle start splay @1\n");
        return 0;
    }

    /* 对端包号小于当前包号, 使用当前包号, 否则使用对端包号和时间)
     */
    if((startplay->pkt_num > handle->first_pktnum)
        || ((startplay->pkt_num == handle->first_pktnum)
        && (handle->splay_local_time < startplay->splay_time)))
    {
        handle->first_pktnum = startplay->pkt_num;
        handle->splay_local_time = startplay->splay_time;
        observer->set_interrupt_time(startplay->splay_time);

        printf("[ATW]handle start splay @2:%u_%u_%u\n",
            (uint32_t)(startplay->splay_time >> 32) & 0xffffffff,
            (uint32_t)startplay->splay_time & 0xffffffff,
            startplay->pkt_num);
    }

    return 0;
}

/* 返回-1: 表示失败, 需重启播放器
 */
static void _tws_deal_startplay(bt_tws_observer_inner_t *handle, player_tws_pkt_t *tws_pkt)
{
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)handle->media_observer->tws_observer;
    player_tws_startplay_pkt_t *startplay = (player_tws_startplay_pkt_t *)(tws_pkt->payload_data);
    uint64_t bt_clk;

    if((startplay->scene != handle->format) || (tws_pkt->type != TWS_STARTPLAY_PKT))
        return;

    bt_clk = observer->get_bt_clk_us();
    if(bt_clk == 0)
    {
        SYS_LOG_ERR("get_bt_clk_us fail");
        return;
    }

    printf("[ATW]deal SPlay:%u_%u_%u_%u_%u, %u_%u_%u_%u_%u\n",
        startplay->pkt_num, startplay->first_clk,
        (uint32_t)(startplay->splay_time >> 32) & 0xffffffff, (uint32_t)startplay->splay_time & 0xffffffff,
        startplay->splay_flag,
        handle->first_pktnum, handle->first_clk,
        (uint32_t)(handle->splay_local_time >> 32) & 0xffffffff, (uint32_t)handle->splay_local_time & 0xffffffff,
        handle->tws_status);

    switch(startplay->splay_flag)
    {
    case PLAYER_TWS_NEED_NEW_SPLAY:
        _tws_handle_newly_splay(handle, startplay, bt_clk);
        break;

    case PLAYER_TWS_USE_LOCAL_SPLAY:
        _tws_handle_local_splay(handle, startplay, bt_clk);
        break;

    case PLAYER_TWS_USE_START_SPLAY:
        _tws_handle_start_splay(handle, startplay, bt_clk);
        break;

    default:
        SYS_LOG_ERR("splay_flag invalid");
        break;
    }
}

/* 返回-1: 表示失败, 需重启播放器
 */
static int32_t _tws_deal_startstop(bt_tws_observer_inner_t *handle, player_tws_pkt_t *tws_pkt)
{
    //todo
    return 0;
}

static int32_t _tws_deal_syncinfo(bt_tws_observer_inner_t *handle, player_tws_pkt_t *tws_pkt)
{
    player_tws_syncinfo_pkt_t *syncinfo = (player_tws_syncinfo_pkt_t *)(tws_pkt->payload_data);

    if((syncinfo->scene != handle->format) || (tws_pkt->type != TWS_SYNCINFO_PKT))
        return 0;

    printf("[ATW]deal SInfo:%d_%u_%u_%d\n",
        syncinfo->pkt_num,
        (uint32_t)(syncinfo->bttime_us >> 32) & 0xffffffff,
        (uint32_t) syncinfo->bttime_us & 0xffffffff,
        handle->tws_status);

    if(handle->tws_status != PLAYER_TWS_STATUS_PLAY)
        return -1;

    if(acts_ringbuf_space(&handle->sinfo_master_buffer) < sizeof(player_tws_syncinfo_pkt_t))
    {
        SYS_LOG_ERR("sinfo_master_buffer full");
        acts_ringbuf_get(&handle->sinfo_master_buffer, NULL, sizeof(player_tws_syncinfo_pkt_t));
    }
    
    acts_ringbuf_put(&handle->sinfo_master_buffer, syncinfo, sizeof(player_tws_syncinfo_pkt_t));

    return 1;
}

static int32_t _tws_deal_playrate(bt_tws_observer_inner_t *handle, player_tws_pkt_t *tws_pkt)
{
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)handle->media_observer->tws_observer;
    player_tws_playrate_pkt_t *playrate = (player_tws_playrate_pkt_t *)(tws_pkt->payload_data);
    uint32_t flags;

    if((playrate->scene != handle->format) || (tws_pkt->type != TWS_PLAYRATE_PKT))
        return 0;

    printf("[ATW]deal APSInfo:%u_%u_%u_%u\n",
        (uint32_t)(playrate->inttime >> 32) & 0xffffffff,
        (uint32_t)playrate->inttime & 0xffffffff,
        handle->tws_status,
        playrate->aps_level);

    if(handle->tws_status != PLAYER_TWS_STATUS_PLAY)
        return 0;

    /* 设置中断
     */
    observer->set_interrupt_time(playrate->inttime);

    /* 加入中断信号队列
     */
    flags = irq_lock();
    handle->aps_level_pending = playrate->aps_level;
    handle->aps_inttime = playrate.inttime;
    irq_unlock(flags);

    return 0;
}

static int32_t _tws_handle_aps_change_request(bt_tws_observer_inner_t *handle, uint8_t level)
{
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)handle->media_observer->tws_observer;
    player_tws_playrate_pkt_t playrate;
    uint32_t flags;

    if((handle->tws_role == BTSRV_TWS_SLAVE)
        || (handle->tws_status != PLAYER_TWS_STATUS_PLAY)
        || (handle->aps_level_pending == level))
        return 0;
    if(handle->tws_role == BTSRV_TWS_NONE)
        goto ERROUT;

    /* 获取蓝牙时钟
     */
    playrate.inttime = observer->get_bt_clk_us();
    if(playrate.inttime == 0)
    {
        SYS_LOG_ERR("get_bt_clk_us fail.");
        goto ERROUT;
    }
    if(playrate.inttime < handle->forbit_aps_time)
        return 0;

    /* 告诉对端调节速度
     */
    playrate.aps_level = level;
    playrate.inttime += 150000; /* 150 ms */
    if(_tws_send_play_rate(handle, &playrate) < 0)
    {
        SYS_LOG_ERR("_tws_send_play_rate fail.");
        goto ERROUT;
    }

    /* 设置中断
     */
    observer->set_interrupt_time(playrate.inttime);

    /* 加入中断信号队列
     */
    flags = irq_lock();
    handle->aps_level_pending = level;
    handle->aps_inttime = playrate.inttime;
    irq_unlock(flags);
    return 0;

ERROUT:
    handle->media_observer->set_base_aps_level(handle->media_observer->media_handle, level);
    return 0;
}

static int32_t _tws_handle_new_pkt_info(bt_tws_observer_inner_t *handle, tws_pkt_info_t *info)
{
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)handle->media_observer->tws_observer;
    int32_t ret;

    if(handle->tws_status != PLAYER_TWS_STATUS_PLAY)
        return 0;
    
    //aac两包一帧，第一包解码没有输出，清除包信息，避免时间计算不准确
    if(info->samples == 0)
    {
        SYS_LOG_INF("AAC output 0");
        goto ERROUT;
    }

    //丢弃不完整的包避免统计时间不正确
    if(handle->first_pkt_flag)
    {
        if(handle->first_pkt_flag == 1)
        {
            handle->first_pktnum = info->pkt_num;
            handle->first_pkt_flag = 2;
        }
        
        if(info->pkt_num == handle->first_pktnum)
            return 0;

        handle->first_pkt_flag = 0;
    }
    
    /* 检查包头信息
     */
    ret = _tws_check_pinfo_unit(handle, info->pkt_num, info->pkt_len, info->samples);
    if(ret == 0)
        return 0;
    if(ret < 0)
    {
        SYS_LOG_ERR("pkt miss, restart: %u_%u",
            info->pkt_num, handle->pinfo_unit[handle->pinfo_unit_idx].pkt_num);
        goto ERROUT;
    }
    
    _tws_update_sync_info(handle, info);

    if(((info->pkt_num % handle->BM_TWS_Sync_interval) == 0) || (handle->last_sinfo_flag == 1))
    {
        player_tws_syncinfo_pkt_t syncinfo;

        if(handle->last_sinfo_flag == 1)
            handle->last_sinfo_flag = 0;
        if((info->pkt_num % handle->BM_TWS_Sync_interval) == 0)
            handle->last_sinfo_flag = 1;

        memset(&syncinfo, 0, sizeof(player_tws_syncinfo_pkt_t));
        syncinfo.pkt_num = info->pkt_num;
        syncinfo.bttime_us = handle->pinfo_unit[handle->pinfo_unit_idx].pkt_bttime_us;

        if(acts_ringbuf_space(&handle->sinfo_slave_buffer) < sizeof(player_tws_syncinfo_pkt_t))
            acts_ringbuf_get(&handle->sinfo_slave_buffer, NULL, sizeof(player_tws_syncinfo_pkt_t));
        acts_ringbuf_put(&handle->sinfo_slave_buffer, &syncinfo, sizeof(player_tws_syncinfo_pkt_t));

        if(handle->tws_role == BTSRV_TWS_MASTER)
            _tws_send_sync_info(handle, &syncinfo);

        printf("[ATW]SInfo:%u_%d_%u_%u\n", info->pkt_num, info->pkt_len,
            (uint32_t)(syncinfo.bttime_us >> 32) & 0xffffffff, (uint32_t)syncinfo.bttime_us & 0xffffffff);
    }

    return 0;

ERROUT:
    handle->pinfo_unit_idx = 0;
    handle->save_pinfo_count = 0;
    memset(handle->pinfo_unit, 0, sizeof(handle->pinfo_unit));

    //丢包重启播放
    if((info->samples != 0) && (handle->tws_role != BTSRV_TWS_NONE))
        ;//todo: restart playback
    return 0;
}

static void _bt_tws_loop(struct k_timer *timer)
{
    bt_tws_observer_inner_t *handle = &observer_inner;
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)handle->media_observer->tws_observer;
    int32_t role;

    role = observer->get_role();
    if(role != handle->tws_role)
    {
        acts_ringbuf_drop_all(&handle->sinfo_master_buffer);
        
        handle->aps_level_pending = -1;
        handle->forbit_aps_time = observer->get_bt_clk_us() + 1500000;
        handle->tws_role = role;
    }

    while(acts_ringbuf_length(&handle->tws_data_buffer) >= sizeof(tws_pkt))
    {
        player_tws_pkt_t tws_pkt;
        
        acts_ringbuf_get(&handle->tws_data_buffer, &tws_pkt, sizeof(tws_pkt));
      
        switch(tws_pkt.type)
        {
        case TWS_STARTPLAY_PKT:
            _tws_deal_startplay(handle, tws_pkt);
            break;
        case TWS_STARTSTOP_PKT:
            _tws_deal_startstop(handle, tws_pkt);
            break;
        case TWS_SYNCINFO_PKT:
            if(role == BTSRV_TWS_SLAVE)
                _tws_deal_syncinfo(handle, tws_pkt);
            break;
        case TWS_PLAYRATE_PKT:
            if(role == BTSRV_TWS_SLAVE)
                _tws_deal_playrate(handle, tws_pkt);
            break;
        default:
            SYS_LOG_ERR("recv invalid pkt, group: %d, type: %d, len: %d",
                tws_pkt.group, tws_pkt.type, tws_pkt.payload_len);
            break;
        }
    }

    while(acts_ringbuf_length(&handle->msg_buffer) >= sizeof(player_tws_msg_t))
    {
        player_tws_msg_t tws_msg;
        
        acts_ringbuf_get(&handle->msg_buffer, &tws_msg, sizeof(tws_msg));
      
        switch(tws_msg.type)
        {
        case TWS_SYNCINFO_PKT:
            _tws_handle_new_pkt_info(handle, (tws_pkt_info_t*)tws_msg.data);
            break;
        case TWS_PLAYRATE_PKT:
            _tws_handle_aps_change_request(handle, tws_msg.data[0]);
            break;
        default:
            SYS_LOG_ERR("recv invalid msg, type: %d", tws_msg.type);
            break;
        }
    }

    if((handle->tws_status == PLAYER_TWS_STATUS_PLAY) && (role == BTSRV_TWS_SLAVE))
        _tws_align_samples(handle);

    if(handle->tws_status == PLAYER_TWS_STATUS_WAIT)
    {
        uint64_t bt_clk;
        
        bt_clk = observer->get_bt_clk_us();
        if(bt_clk == 0)
        {
            SYS_LOG_ERR("get_bt_clk_us fail");
            return;
        }

        bt_clk += TWS_MIN_INTERVAL;
        if(bt_clk >= handle->splay_local_time)
        {
            handle->tws_status == PLAYER_TWS_STATUS_DEAL_WAIT;
            handle->media_observer->set_start_pkt_num(handle->media_observer, handle->first_pktnum);
        }
    }
}

/*----------------------------------------------------------------------------------------------------*/

static uint64_t _bt_tws_get_bt_clk_us(void)
{
    bt_tws_observer_inner_t *handle = &observer_inner;
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)handle->media_observer->tws_observer;

    return observer->get_bt_clk_us();
}

static uint8_t _bt_tws_get_role(void)
{
    bt_tws_observer_inner_t *handle = &observer_inner;
    return handle->tws_role;
}

static int32_t _bt_tws_set_stream_info(uint8_t format, uint16_t first_pktnum, uint16_t sample_rate)
{
    bt_tws_observer_inner_t *handle = &observer_inner;
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)handle->media_observer->tws_observer;
    player_tws_startplay_pkt_t startplay;

    if(handle->tws_status != PLAYER_TWS_STATUS_INIT)
    {
        SYS_LOG_ERR("bt tws status: %d", handle->tws_status);
        return -1;
    }
    
    handle->format = format;
    handle->first_pktnum = first_pktnum;
    handle->sample_rate = sample_rate;
    handle->first_clk = observer->get_first_pkt_clk();
    
    handle->tws_status = PLAYER_TWS_STATUS_WAIT;
    handle->aps_level_pending = -1;
    handle->first_pkt_flag = 1;
    
    if(format == MSBC_TYPE || format == CVSD_TYPE)
    {
        handle->BM_TWS_WPlay_Mintime = 80;
        handle->BM_TWS_WPlay_Maxtime = 600;
        handle->BM_TWS_Sync_interval = 200;
    }
    else
    {
        handle->BM_TWS_WPlay_Mintime = 100;
        handle->BM_TWS_WPlay_Maxtime = 1000;
        handle->BM_TWS_Sync_interval = 40;
    }

    if(handle->tws_role == BTSRV_TWS_NONE)
        goto ERROUT;

    startplay.splay_flag = PLAYER_TWS_USE_START_SPLAY;
    startplay.pkt_num = first_pktnum;
    startplay.splay_time = observer->get_bt_clk_us() + handle->BM_TWS_WPlay_Mintime * 1000;
    startplay.first_clk = handle->first_clk;
    if(_tws_send_start_play(handle, &startplay) < 0)
    {
        SYS_LOG_ERR("_tws_send_start_play fail.");
        goto ERROUT;
    }

    handle->splay_local_time = startplay.splay_time;
    handle->forbit_aps_time = startplay.splay_time + 1500000;
    observer->set_interrupt_time(startplay.splay_time);

    os_timer_start(&handle->timer, BT_TWS_TIMER_INTERVAL, BT_TWS_TIMER_INTERVAL);
    
    return 0;

ERROUT:
    handle->tws_status = PLAYER_TWS_STATUS_PLAY;
    handle->media_observer->set_start_pkt_num(handle->media_observer->media_handle, first_pktnum);
    handle->media_observer->start_playback(handle->media_observer->media_handle);
    return 0;
}

static int32_t _bt_tws_aps_change_request(uint8_t level)
{
    bt_tws_observer_inner_t *handle = &observer_inner;
    player_tws_msg_t tws_msg;
    int32_t wait_time = 5;

    if(handle->tws_status == PLAYER_TWS_STATUS_INIT)
        return -1;

    tws_msg.type = TWS_PLAYRATE_PKT;
    tws_msg.data[0] = level;

    while(acts_ringbuf_space(&handle->msg_buffer) < sizeof(player_tws_msg_t))
    {
        if(wait_time <= 0)
        {
            SYS_LOG_ERR("msg buffer full");
            return -1;
        }
        
        os_sleep(1);
        wait_time--;
    }
    
    acts_ringbuf_put(&handle->msg_buffer, &tws_msg, sizeof(tws_msg));
    return 0;
}

static int32_t _bt_tws_set_pkt_info(tws_pkt_info_t *info)
{
    bt_tws_observer_inner_t *handle = &observer_inner;
    player_tws_msg_t tws_msg;
    int32_t wait_time = 5;

    if(handle->tws_status == PLAYER_TWS_STATUS_INIT)
        return -1;

    tws_msg.type = TWS_SYNCINFO_PKT;
    memcpy(tws_msg.data, info, sizeof(tws_pkt_info_t));

    while(acts_ringbuf_space(&handle->msg_buffer) < sizeof(player_tws_msg_t))
    {
        if(wait_time <= 0)
        {
            SYS_LOG_ERR("msg buffer full");
            return -1;
        }
        
        os_sleep(1);
        wait_time--;
    }
    
    acts_ringbuf_put(&handle->msg_buffer, &tws_msg, sizeof(tws_msg));
    return 0;
}

bt_tws_observer_t* bluetooth_tws_observer_init(media_observer_t *media_observer)
{
    bt_tws_observer_inner_t *handle = &observer_inner;
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)media_observer->tws_observer;

    memset(handle, 0, sizeof(bt_tws_observer_inner_t));
    
    acts_ringbuf_init(&handle->tws_data_buffer, handle->tws_data, sizeof(handle->tws_data));
    acts_ringbuf_init(&handle->sinfo_master_buffer, handle->sinfo_master, sizeof(handle->sinfo_master));
    acts_ringbuf_init(&handle->sinfo_slave_buffer, handle->sinfo_slave, sizeof(handle->sinfo_slave));
    acts_ringbuf_init(&handle->msg_buffer, handle->msg_data, sizeof(handle->msg_data));
    
    handle->media_observer = media_observer;
    handle->tws_observer.get_bt_clk_us = _bt_tws_get_bt_clk_us;
    handle->tws_observer.get_role = _bt_tws_get_role;
    handle->tws_observer.set_stream_info = _bt_tws_set_stream_info;
    handle->tws_observer.aps_change_request = _bt_tws_aps_change_request;
    handle->tws_observer.set_pkt_info = _bt_tws_set_pkt_info;
    handle->tws_status = PLAYER_TWS_STATUS_INIT;
    handle->aps_level_pending = -1;
    handle->tws_role = observer->get_role();
    os_timer_init(&handle->timer, _bt_tws_loop, NULL);

    observer->set_interrupt_cb(_tws_irq_handle);
    observer->set_recv_pkt_cb(_tws_recv_pkt_handle);
    SYS_LOG_ERR("sizeof(player_tws_msg_t): %d, %d", sizeof(player_tws_msg_t), sizeof(tws_pkt_info_t));

    return &handle->tws_observer;
}

void bluetooth_tws_observer_deinit(bt_tws_observer_t *tws_observer)
{
    bt_tws_observer_inner_t *handle = &observer_inner;
    tws_runtime_observer_t *observer = (tws_runtime_observer_t *)media_observer->tws_observer;
    uint32_t flags;

    flags = irq_lock();
    handle->aps_level_pending = -1;
    handle->tws_status = PLAYER_TWS_STATUS_INIT;
    irq_unlock(flags);

    os_timer_stop(&handle->timer);
    observer->set_interrupt_time(0);
    observer->set_interrupt_cb(NULL);
    observer->set_recv_pkt_cb(NULL);
}

