/*---------------------------------------------------------------------------*/
/* jitter_buffer.h                                                           */
/* copyright (c) innovaphone 2017                                            */
/*---------------------------------------------------------------------------*/

#define JB_MAX_DESCRIPTORS_EXP 9
#define JB_MAX_DESCRIPTORS  (1 << JB_MAX_DESCRIPTORS_EXP)
#define JB_DESCRIPTORS_MASK (~(((dword) -1) << JB_MAX_DESCRIPTORS_EXP))
#define JB_MAX_TIME         (400*8)
#define JB_MAX_PLAYOUT_TIME (100*8) /* To keep buffers in the playout queue untouched */
#define JB_XMIT_SIZE        ((JB_MAX_TIME + JB_MAX_PLAYOUT_TIME) * 48 / (5*8/2)) /* Account for OPUS high sample rates */
#define JB_RECV_SIZE        2048

class jitter_buffer : public IJitterBuffer {
    class UJitterBuffer * user;

    byte xmit_buffer[JB_XMIT_SIZE];
    byte linear_buffer[JB_RECV_SIZE];

    struct {
        byte payload_type;
        byte control;
        word time;
        word length;
        word buffer_pos;
    } xmit_descriptors[JB_MAX_DESCRIPTORS];

    enum AudioCoder coder;
    byte payload_type;
    unsigned min_buffer;
    unsigned initial_buffers;
    unsigned max_buffer;
    dword config_pending;
    dword write_descriptor_ex;
    dword read_descriptor_ex;
    unsigned timestamp_rate_multiplier;
    unsigned descriptors_num;
    int descriptor_time;
    unsigned descriptor_size;
    dword next_timestamp;
    unsigned count;
    unsigned count_min;
    unsigned count_max;
    int adjusts;
    unsigned adjust_count;
    unsigned adjust_interval;
    bool timestamp_set;

    unsigned get_head(const void *buf, size_t len, unsigned *pos, byte *get_buf, unsigned get_len);

public:
    jitter_buffer(class UJitterBuffer * user);

    unsigned Configure(enum AudioCoder coder, unsigned mediaPacketizationMs, unsigned pullInterval8khz,
        unsigned minBufferMs, unsigned initialBufferMs, unsigned maxBufferMs);
    void Adjust(unsigned initialBufferMs);
    unsigned GetDelay() { int n = count + adjusts * descriptor_time; return ((n >= 0) ? n : 0); };
    void Push(const void * buf, size_t len, dword timestamp);
    bool Pull(bool discard);
};

