
#ifndef _RTP808HEAD_H_
#define _RTP808HEAD_H_

#include "MFSPublic.h"

namespace mfs
{
#define RTP_808_DATATYPE_I 0        // i帧
#define RTP_808_DATATYPE_P 1        // p帧
#define RTP_808_DATATYPE_B 2        // b帧
#define RTP_808_DATATYPE_A 3        // 音频帧
#define RTP_808_DATATYPE_T 4        // 透传数据

#define PAYLOAD_TYPE_MASK  ((1 << 7) - 1)
#define PAYLOAD_TYPE_G711A  6
#define PAYLOAD_TYPE_G711U  7
#define PAYLOAD_TYPE_G726  8
#define PAYLOAD_TYPE_LPCM  18
#define PAYLOAD_TYPE_AAC  19
#define PAYLOAD_TYPE_ADPCM  26
#define PAYLOAD_TYPE_AACLC  24
#define PAYLOAD_TYPE_G726_16  29         // 自定义负载类型说明 G726-16kbit
#define PAYLOAD_TYPE_G726_24  30         // 自定义负载类型说明 G726-24kbit
#define PAYLOAD_TYPE_G726_32  31         // 自定义负载类型说明 G726-32kbit
#define PAYLOAD_TYPE_G726_40  32         // 自定义负载类型说明 G726-40kbit
#define PAYLOAD_TYPE_H264     98         


    // 视频帧
    struct Rtp808HeadBaseV
    {
        char magic[4];
        uint8_t headCC: 4;                                                      // 固定1
        uint8_t headX: 1;                                                       // RTP头是否需要扩展位，固定0
        uint8_t headP: 1;                                                       // 固定 0
        uint8_t headV: 2;                                                       // 固定 2
        uint8_t headPT: 7;                                                      // 负载类型
        uint8_t headM: 1;                                                       // 标志位，确定是否是完整数据帧边界
        uint16_t number;                                                        // 包序号
        uint8_t simBcd[6];                                                      // sim卡号，BCD编码
        uint8_t logicChannel;                                                   // 逻辑通道号，按照 JT/T 1076 20 的表2
        uint8_t partFlag: 4;                                                    // 分包标记，0000：原子包，不可拆分、0001：分包处理第一包、0010：分包处理最后一包、0011：分包时中间包
        uint8_t dataType: 4;                                                    // 数据类型，0000：I帧、0001：P帧、0010：B帧、0011：音频帧、0100：透传数据
        uint8_t time[8];                                                        // 相对时间戳
        uint16_t lastIFrameTime;                                                // 与上一关键帧的时间间隔，单位毫秒，
        uint16_t lastFrameTime;                                                 // 与上一帧的时间间隔，单位毫秒，
        uint16_t dataLen;                                                       // 后续数据体长度（不含此字段）
        uint8_t data[0];                                                        // 数据体
    } __attribute__ ((packed));
    

    // 音频帧
    struct Rtp808HeadBaseA
    {
        char magic[4];
        uint8_t headCC: 4;                                                      // 固定1
        uint8_t headX: 1;                                                       // RTP头是否需要扩展位，固定0
        uint8_t headP: 1;                                                       // 固定 0
        uint8_t headV: 2;                                                       // 固定 2
        uint8_t headPT: 7;                                                      // 负载类型
        uint8_t headM: 1;                                                       // 标志位，确定是否是完整数据帧边界
        uint16_t number;                                                        // 包序号
        uint8_t simBcd[6];                                                      // sim卡号，BCD编码
        uint8_t logicChannel;                                                   // 逻辑通道号，按照 JT/T 1076 20 的表2
        uint8_t partFlag: 4;                                                    // 分包标记，0000：原子包，不可拆分、0001：分包处理第一包、0010：分包处理最后一包、0011：分包时中间包
        uint8_t dataType: 4;                                                    // 数据类型，0000：I帧、0001：P帧、0010：B帧、0011：音频帧、0100：透传数据
        uint8_t time[8];                                                        // 相对时间戳
        uint16_t dataLen;                                                       // 后续数据体长度（不含此字段）
        uint8_t data[0];                                                        // 数据体
    } __attribute__ ((__packed__));

    // 透传数据
    struct Rtp808HeadBaseT
    {
        char magic[4];
        uint8_t headCC: 4;                                                      // 固定1
        uint8_t headX: 1;                                                       // RTP头是否需要扩展位，固定0
        uint8_t headP: 1;                                                       // 固定 0
        uint8_t headV: 2;                                                       // 固定 2
        uint8_t headPT: 7;                                                      // 负载类型
        uint8_t headM: 1;                                                       // 标志位，确定是否是完整数据帧边界
        uint16_t number;                                                        // 包序号
        uint8_t simBcd[6];                                                      // sim卡号，BCD编码
        uint8_t logicChannel;                                                   // 逻辑通道号，按照 JT/T 1076 20 的表2
        uint8_t partFlag: 4;                                                    // 分包标记，0000：原子包，不可拆分、0001：分包处理第一包、0010：分包处理最后一包、0011：分包时中间包
        uint8_t dataType: 4;                                                    // 数据类型，0000：I帧、0001：P帧、0010：B帧、0011：音频帧、0100：透传数据
        uint16_t dataLen;                                                       // 后续数据体长度（不含此字段）
        uint8_t data[0];                                                        // 数据体
    } __attribute__ ((__packed__));

    // 视频帧
    struct Rtp808HeadBaseV_YB
    {
        char magic[4];
        uint8_t headCC: 4;                                                      // 固定1
        uint8_t headX: 1;                                                       // RTP头是否需要扩展位，固定0
        uint8_t headP: 1;                                                       // 固定 0
        uint8_t headV: 2;                                                       // 固定 2
        uint8_t headPT: 7;                                                      // 负载类型
        uint8_t headM: 1;                                                       // 标志位，确定是否是完整数据帧边界
        uint16_t number;                                                        // 包序号
        uint8_t simBcd[10];                                                      // sim卡号，BCD编码
        uint8_t logicChannel;                                                   // 逻辑通道号，按照 JT/T 1076 20 的表2
        uint8_t partFlag: 4;                                                    // 分包标记，0000：原子包，不可拆分、0001：分包处理第一包、0010：分包处理最后一包、0011：分包时中间包
        uint8_t dataType: 4;                                                    // 数据类型，0000：I帧、0001：P帧、0010：B帧、0011：音频帧、0100：透传数据
        uint8_t time[8];                                                        // 相对时间戳
        uint16_t lastIFrameTime;                                                // 与上一关键帧的时间间隔，单位毫秒，
        uint16_t lastFrameTime;                                                 // 与上一帧的时间间隔，单位毫秒，
        uint16_t dataLen;                                                       // 后续数据体长度（不含此字段）
        uint8_t data[0];                                                        // 数据体
    } __attribute__ ((packed));
    

    // 音频帧
    struct Rtp808HeadBaseA_YB
    {
        char magic[4];
        uint8_t headCC: 4;                                                      // 固定1
        uint8_t headX: 1;                                                       // RTP头是否需要扩展位，固定0
        uint8_t headP: 1;                                                       // 固定 0
        uint8_t headV: 2;                                                       // 固定 2
        uint8_t headPT: 7;                                                      // 负载类型
        uint8_t headM: 1;                                                       // 标志位，确定是否是完整数据帧边界
        uint16_t number;                                                        // 包序号
        uint8_t simBcd[10];                                                      // sim卡号，BCD编码
        uint8_t logicChannel;                                                   // 逻辑通道号，按照 JT/T 1076 20 的表2
        uint8_t partFlag: 4;                                                    // 分包标记，0000：原子包，不可拆分、0001：分包处理第一包、0010：分包处理最后一包、0011：分包时中间包
        uint8_t dataType: 4;                                                    // 数据类型，0000：I帧、0001：P帧、0010：B帧、0011：音频帧、0100：透传数据
        uint8_t time[8];                                                        // 相对时间戳
        uint16_t dataLen;                                                       // 后续数据体长度（不含此字段）
        uint8_t data[0];                                                        // 数据体
    } __attribute__ ((__packed__));

    // 透传数据
    struct Rtp808HeadBaseT_YB
    {
        char magic[4];
        uint8_t headCC: 4;                                                      // 固定1
        uint8_t headX: 1;                                                       // RTP头是否需要扩展位，固定0
        uint8_t headP: 1;                                                       // 固定 0
        uint8_t headV: 2;                                                       // 固定 2
        uint8_t headPT: 7;                                                      // 负载类型
        uint8_t headM: 1;                                                       // 标志位，确定是否是完整数据帧边界
        uint16_t number;                                                        // 包序号
        uint8_t simBcd[10];                                                      // sim卡号，BCD编码
        uint8_t logicChannel;                                                   // 逻辑通道号，按照 JT/T 1076 20 的表2
        uint8_t partFlag: 4;                                                    // 分包标记，0000：原子包，不可拆分、0001：分包处理第一包、0010：分包处理最后一包、0011：分包时中间包
        uint8_t dataType: 4;                                                    // 数据类型，0000：I帧、0001：P帧、0010：B帧、0011：音频帧、0100：透传数据
        uint16_t dataLen;                                                       // 后续数据体长度（不含此字段）
        uint8_t data[0];                                                        // 数据体
    } __attribute__ ((__packed__));

    // template<typename TT, typename TV, typename TA>
    class Rtp808FrameParser
    {
        private:
            uint8_t* _data;
            // uint8_t* _payloadData;
            
            int _number = -1;                                       // 当前包序号
            std::string _simNumber;                                 // 当前SIM卡号
            int _logicChannel = -1;                                 // 通道序号
            int _currentState = -1;                                 // 分包标记
            int _currentType = -1;                                  // 数据类型
            std::string _url;                                       // 当前url，/SIM卡号/通道号
            int _payloadDataLen = -1;                               // 当前rtp包有效载荷数据长度
            int _currentHeadLen = -1;                               // 当前rtp包头数据长度
            int _rtpFrameLen = -1;                                  // 当前rtp包完整数据长度
            int _payloadType = -1;                                  // 有效载荷类型

            std::string _errorMsg;
            std::string _errorField;
            
            bool _isYuebiao = false;                                                    // 是否粤标
            bool _isSubHead = true;
            
            void getSimNumber(std::pair<std::vector<uint8_t>, int>& ptrBuffer, int framePos, std::string& str, bool subSimnumber);
        public:
            Rtp808FrameParser(){}
            // 0:成功;-1:失败且需要退出;其它:失败不需要退出
            int loadData(std::pair<std::vector<uint8_t>, int>& ptrBuffer, int framePos);
            void setTime(uint64_t v);

            static std::unique_ptr<uint8_t[]> encodeMessage(std::string content, int& size);

            // inline uint8_t* payloadData(){return _payloadData;}
            inline uint8_t* data(){return _data;}
            inline int number(){return _number;}
            inline const std::string& simNumber(){return _simNumber;}
            inline int logicChannel(){return _logicChannel;}
            inline int currentState(){return _currentState;}
            inline int currentType(){return _currentType;}
            inline const std::string& url(){return _url;}
            inline int rtpFrameLen(){return _rtpFrameLen;}
            inline int currentHeadLen(){ return _currentHeadLen;}
            inline int payloadDataLen(){return _payloadDataLen;}
            inline int payloadType(){return _payloadType;}

            inline const std::string& errorMessage(){return _errorMsg;}
            inline const std::string& errorField(){return _errorMsg;}

            


            bool isYuebiao(){return _isYuebiao;}
            void isYuebiao(bool v){_isYuebiao=v;}

            void getSimNumberBCD(std::string& str);
    };


}
#endif