#ifndef __PSLSTREAMING_HEADER_INCLUDED__

#define __PSLSTREAMING_HEADER_INCLUDED__

/**
 *  PSLStreaming lib interface return value define and status define
 **/
#define PSLRET_SUCCESS            0

#define PSLRET_ERR_START_FAILED             -1
#define PSLRET_ERR_NO_MEDIA_ACTIVE          -2
#define PSLRET_ERR_GET_PUSHMODE_FAILED      -3
#define PSLRET_ERR_NULL_POINT               -4
#define PSLRET_ERR_NOT_INIT                 -5
#define PSLRET_ERR_INIT_PACKER_FAILED       -6
#define PSLRET_ERR_PSLSTREAMING_NOT_INIT    -100

#define PSLRET_ERR_PARAMS                   -10
#define PSLRET_ERR_PACKER_PARAMS            -11
#define PSLRET_ERR_AUDIO_PARAMS             -12
#define PSLRET_ERR_VIDEO_PARAMS             -13

#define PSLRET_ERR_MODE_NOT_EXIST           -30
#define PSLRET_ERR_TYPE_NOT_EXIST           -31
#define PSLRET_ERR_TRACK_NOT_EXIST          -32

#define PSLSTATUS_NETWORK_FAILED            21
#define PSLSTATUS_DELAY_TOO_LARGE           22
#define PSLSTATUS_NO_VIDEO_DATA             23
#define PSLSTATUS_NO_AUDIO_DATA             24
#define PSLSTATUS_NO_AV_DATA                25
#define PSLSTATUS_PERFORMANCE_NOT_ENOUGH    26

#define PSLTYPE_VIDEO_CAPTURE_QUEUE         31
#define PSLTYPE_VIDEO_ENCODE_QUEUE          32
#define PSLTYPE_AUDIO_CAPTURE_QUEUE         33
#define PSLTYPE_AUDIO_ENCODE_QUEUE          34

#define PSL_STOPREASON_EOS                  1
#define PSL_STOPREASON_SYSTEMINTERRUPT      0

typedef int (* CONTROLPROC)( void* pVOID, int ctltype, void* INTERFACE_PARAM, void* orig_INTERFACE_PARAM);

class PSLStreaming {
    
public:
	int     m_index;
    int     m_runningstat;
    bool    m_running_cpucheck;
    bool    m_running_check;
	void	*m_pTcsConfig;
	void	*m_pStreamInfo;
	void	*m_pINTERFACE_PARAM;
	void    * m_pencoder;
	CONTROLPROC	m_pfnControl;
    
    int64_t m_lastdatatime;
    int64_t m_lastvideostamp;
    int64_t m_lastaudiostamp;
    
    int     m_largedelaywarning_count;
    int     m_packernull_count;
    
    int    m_ipvxflag;

public:
	PSLStreaming();
	~PSLStreaming();

    static void PreLoadUrl(char *url);
    
    /**
     * called this function when network changed, such as, network changed from wifi to 4G, or from wifi to another wifi, or from 4G to wifi
     */
    static void OnNetWorkChanged();
    
    
    /**
     *  init PSLStreaming
     *  @param index
     *      set 0 if you only used one PSLStreaming point, or if you have a PSLStreaming point array, set array num
     *  @param inf_param
     *      set the point of struct INTERFACE_PARAMS, before this, init INTERFACE_PARAMS with your param
     *  @param logdir
     *      not used now
     *  @param lognum
     *      not used now
     *  @param extrainfo
     *      TODO
     *  @return
     *      PSLRET_SUCCESS for success
     *      PSLRET_ERR_PACKER_PARAMS for PSLStreaming struct params error
     *      PSLRET_ERR_AUDIO_PARAMS for audio params error
     *      PSLRET_ERR_VIDEO_PARAMS for video params error
     *      PSLRET_ERR_NO_MEDIA_ACTIVE  for no media need to push
     *      PSLRET_ERR_GET_PUSHMODE_FAILED for get push mode failed
     *      PSLRET_ERR_NULL_POINT for inf_param is NULL
     *      PSLRET_ERR_INIT_PACKER_FAILED for init output failed
     **/
	int Init(int index, void*inf_param, void*logdir, void*lognum, void *extrainfo);

    /**
     *  start PSLStreaming
     *  @return
     *      PSLRET_SUCCESS for success
     *      PSLRET_ERR_START_FAILED for start failed, mostly it's caused by init function failed
     **/
	int Start();
    
    /**
     *  stop PSLStreaming
     *  @param
     *      reason:     PSL_STOPREASON_EOS: End of Streaming, means "APP workflow close it".
     *                  PSL_STOPREASON_SYSTEMINTERRUPT: interrupt by system or something
     *  @return
     *      PSLRET_SUCCESS for success
     **/
	int Stop(int reason);
    
    /**
     *  app switch to background
     **/
    void    PLtoBackground();
    
    /**
     *  app switch to foreground
     **/
    void    PLtoForeground();
    
    /**
     *  only used in IOS_VERSION
     *  @param encoder
     *      if used videotoolbox for encoder, transfer VTCompressionSessionRef* to PSLStreaming,
     *      if not, transfer null
     **/
    void SetEncoderPoint(void* encoder);
    
    /**
     *
     * call getEncodeProperty before encode frame. get the property struct for encode.
     * for IOS version, property is CFDictionaryRef
     *
     **/
    int getEncodeProperty(void **property);
    
    /**
     *  set callback function
     *  @return
     *      PSLRET_SUCCESS for success
     *      PSLRET_ERR_PARAMS for tcs is not NULL, this Err used by iOS
     **/
	int SetControlFunc(void*tcs, CONTROLPROC pFUNC);
    
    /**
     *  Insert audio/video data to push
     *  @param buf
     *      audio/video data point
     *  @param SAMPLE
     *      BUFFER_INFO struct point, info for audio/video data
     *
     *  @return
     *      PSLRET_SUCCESS for success
     *      PSLRET_ERR_PARAMS for params error
     *      PSLRET_ERR_NULL_POINT for some point is NULL
     *      PSLRET_ERR_START_FAILED for PSLStreaming not started
     *      PSLSTATUS_NO_AUDIO_DATA for no audio data
     *      PSLSTATUS_NO_VIDEO_DATA for no video data
     *      PSLSTATUS_DELAY_TOO_LARGE for delay is large than set
     *      PSLSTATUS_NETWORK_FAILED for push failed
     **/
	int InsertSample(unsigned char*buf, void*SAMPLE);
    
    //only for Android
    void RunCpuCheck();
    
    //main check
    void RunCheck();
    
    /**
     *  @return
     *      PSLRET_SUCCESS for normal
     *      PSLSTATUS_NO_AV_DATA     for input haven't audio and video data
     **/
    int  getdatastatus();
    
    /**
     * get the current delay,  unit: ms
     * @return
     *      PSLRET_SUCCESS for ok
     **/
    int     get_status_delay(unsigned int *delay);
    
    /**
     * get the current data bitrate,  unit: kbps
     * @return
     *      PSLRET_SUCCESS for ok
     **/
    int     get_status_data_br(unsigned int *databr);
    
    /**
     * get the current network bitrate,  unit: kbps
     * @return
     *      PSLRET_SUCCESS for ok
     **/
    int     get_status_network_br(unsigned int *networkbr);
    
    /**
     * get the current server node ip that stream pushing to
     * @param size should not less than 128
     * @return
            PSLRET_SUCCESS for ok
            other for error
     */
    int     get_node_ip(char *nodeip, int size);
    
    /**
     * set IntraRefresh to let encoder output key frame
     * @return
     PSLRET_SUCCESS for ok
     other for error
     */
    int     setIntraRefresh(bool flag);
	
	/**
     * set capture queue max and encoder queue max to pslstreaming
     * @param type 
                PSLTYPE_AUDIO_CAPTURE_QUEUE for audio capture
                PSLTYPE_AUDIO_ENCODE_QUEUE for audio encoder
                PSLTYPE_VIDEO_CAPTURE_QUEUE for video capture
                PSLTYPE_VIDEO_ENCODE_QUEUE for video encoder
     * @param queuelength the num of frame in queue
     **/
    void     setQueueLength(int type, int queuelength);
    
    /**
     *   set MSC server to start or stop stitching the substream into mosaic stream.
     *   @input
     *      userno                 assist broadcaster index
     *      userserial  			assist broadcaster serialno
     *      flag					0: invisible  1: visible
     *
     *   @remark
     *          assist broadcaster push stream url:
     *              http://......./publish/trans/{group-id}/mlinks{$userno$}_{$userserial$}/{stream-id}
     *   @return
     *      PSLRET_SUCCESS      success
     *      others				failed
     */
    int ControlUserVisible(unsigned int userno, unsigned int userserial, unsigned int flag);
    
private:
    int InitOutput();
    int StartOutput();
    int StopAndReleaseOutput();
    
    void    *hThread;
    
    pthread_mutex_t m_packermutex;
    
    void    *cThread;
    void 	*m_pPacker;
    void    *m_adjust;
    
    int     m_adatacount;
    int     m_vdatacount;
    int     m_current_pushmode;
    bool    m_bwaitI;
    //bool    m_brestartPackerFlag;
    
};


extern "C"{
/**
 *  preload url, for start streaming faster.
 */
void    PLGlobalInit(unsigned short tcp_svrport=8000, unsigned short ptcp_svrport=7788, unsigned short ptcp_svrphyport=12345, char* logpath=NULL);
void    PLSetDevicePoint(void* Device);


/**
 *  used berore create PSLStreaming, preload push url
 **/
void     PSLStreamingPreLoad(char* url);

/**
 *  create PSLStreaming
 *  @return
 *      PSLStreaming Point
 **/
void*    PSLStreamingCreate();

/**
 *  init PSLStreaming
 *  @param pPSLStreaming PSLStreaming Point get from PSLStreamingCreate
 *  @param index
 *      set 0 if you only used one PSLStreaming point, or if you have a PSLStreaming point array, set array num
 *  @param inf_param
 *      set the point of struct INTERFACE_PARAMS, before this, init INTERFACE_PARAMS with your param
 *  @param logdir
 *      not used now
 *  @param lognum
 *      not used now
 *  @param extrainfo
 *      TODO
 *  @return
 *      PSLRET_ERR_PSLSTREAMING_NOT_INIT for PSLStreaming not created
 *      PSLRET_SUCCESS for success
 *      PSLRET_ERR_PACKER_PARAMS for PSLStreaming struct params error
 *      PSLRET_ERR_AUDIO_PARAMS for audio params error
 *      PSLRET_ERR_VIDEO_PARAMS for video params error
 *      PSLRET_ERR_NO_MEDIA_ACTIVE  for no media need to push
 *      PSLRET_ERR_GET_PUSHMODE_FAILED for get push mode failed
 *      PSLRET_ERR_NULL_POINT for inf_param is NULL
 *      PSLRET_ERR_INIT_PACKER_FAILED for init output failed
 **/
int      PSLStreamingInit(void* pPSLStreaming, int index, void*inf_param, void*logdir, void*lognum, void *extrainfo);

/**
 *  start PSLStreaming
 *  @param pPSLStreaming PSLStreaming Point get from PSLStreamingCreate
 *  @return
 *      PSLRET_ERR_PSLSTREAMING_NOT_INIT for PSLStreaming not created
 *      PSLRET_SUCCESS for success
 *      PSLRET_ERR_START_FAILED for start failed, mostly it's caused by init function failed
 **/
int      PSLStreamingStart(void* pPSLStreaming);

/**
 *  stop PSLStreaming
 *  @param pPSLStreaming PSLStreaming Point get from PSLStreamingCreate
 *  @param
 *      reason:     PSL_STOPREASON_EOS: End of Streaming, means "APP workflow close it".
 *                  PSL_STOPREASON_SYSTEMINTERRUPT: interrupt by system or something
 *  @return
 *      PSLRET_ERR_PSLSTREAMING_NOT_INIT for PSLStreaming not created
 *      PSLRET_SUCCESS for success
 **/
int      PSLStreamingStop(void* pPSLStreaming, int reason);

/**
 *  app switch to background
 **/
void    PSLStreamingtoBackground(void* pPSLStreaming);

/**
 *  app switch to foreground
 *  called PSLStreamingInit before this
 **/
void    PSLStreamingtoForeground(void* pPSLStreaming);

/**
 *  only used in IOS_VERSION
 *  @param pPSLStreaming PSLStreaming Point get from PSLStreamingCreate
 *  @param encoder
 *      if used videotoolbox for encoder, transfer VTCompressionSessionRef* to PSLStreaming,
 *      if not, transfer null
 **/
void     PSLStreamingSetEncoderPoint(void* pPSLStreaming, void* encoder);

/**
 * @brief call getEncodeProperty before encode frame. get the property struct for encode.
 * @param pPSLStreaming PSLStreaming Point get from PSLStreamingCreate
 * @param property for IOS version, property is (void**)(&CFDictionaryRef)
 * @return
 *      PSLRET_ERR_PSLSTREAMING_NOT_INIT for PSLStreaming not created
 *      PSLRET_ERR_NOT_INIT for packer is not created
        PSLRET_SUCCESS for success
 **/
int      PSLStreamingGetEncodeProperty(void* pPSLStreaming, void **property);

/**
 *  set callback function
 *  @param pPSLStreaming PSLStreaming Point get from PSLStreamingCreate
 *  @return
 *      PSLRET_ERR_PSLSTREAMING_NOT_INIT for PSLStreaming not created
 *      PSLRET_SUCCESS for success
 *      PSLRET_ERR_PARAMS for tcs is not NULL, this Err used by iOS
 **/
int     PSLStreamingSetControlFunc(void* pPSLStreaming, void*tcs, CONTROLPROC pFUNC);

/**
 *  Insert audio/video data to push
 *  @param pPSLStreaming PSLStreaming Point get from PSLStreamingCreate
 *  @param buf
 *      audio/video data point
 *  @param SAMPLE
 *      BUFFER_INFO struct point, info for audio/video data
 *
 *  @return
 *      PSLRET_ERR_PSLSTREAMING_NOT_INIT for PSLStreaming not created
 *      PSLRET_SUCCESS for success
 *      PSLRET_ERR_PARAMS for params error
 *      PSLRET_ERR_NULL_POINT for some point is NULL
 *      PSLRET_ERR_START_FAILED for PSLStreaming not started
 *      PSLSTATUS_NO_AUDIO_DATA for no audio data
 *      PSLSTATUS_NO_VIDEO_DATA for no video data
 *      PSLSTATUS_DELAY_TOO_LARGE for delay is large than set
 *      PSLSTATUS_NETWORK_FAILED for push failed
 **/
int     PSLStreamingInsertSample(void* pPSLStreaming, unsigned char*buf, void*SAMPLE);

/**
 *  @return
 *      PSLRET_ERR_PSLSTREAMING_NOT_INIT for PSLStreaming not created
 *      PSLRET_SUCCESS for normal
 *      PSLSTATUS_NO_AV_DATA     for input haven't audio and video data
 **/
int     PSLStreamingGetdatastatus(void* pPSLStreaming);

/**
 * get the current delay,  unit: ms
 * @return
 *      PSLRET_ERR_PSLSTREAMING_NOT_INIT for PSLStreaming not created
 *      PSLRET_SUCCESS for ok
 **/
int     PSLStreamingGet_status_delay(void* pPSLStreaming, unsigned int *delay);

/**
 * get the current data bitrate,  unit: kbps
 * @return
 *      PSLRET_ERR_PSLSTREAMING_NOT_INIT for PSLStreaming not created
 *      PSLRET_SUCCESS for ok
 **/
int     PSLStreamingGet_status_data_br(void* pPSLStreaming, unsigned int *databr);

/**
 * get the current network bitrate,  unit: kbps
 * @return
 *      PSLRET_ERR_PSLSTREAMING_NOT_INIT for PSLStreaming not created
 *      PSLRET_SUCCESS for ok
 **/
int     PSLStreamingGet_status_network_br(void* pPSLStreaming, unsigned int *networkbr);

/**
 *   set MSC server to start or stop stitching the substream into mosaic stream.
 *   @input
 *      pPSLStreaming		PSLStreaming object pointer, returned by PSLStreamingCreate
 *      userno                 assist broadcaster index
 *      userserial  			assist broadcaster serialno
 *      flag					0: invisible  1: visible
 *
 *   @remark
 *          assist broadcaster push stream url:
 *              http://......./publish/trans/{group-id}/mlinks{$userno$}_{$userserial$}/{stream-id}
 *   @return
 *      PSLRET_SUCCESS      success
 *      others				failed
 */
int PSLStreamingControlUserVisible(void* pPSLStreaming, unsigned int userno, unsigned int userserial, unsigned int flag);
    
/**
 * release PSLStreaming
 **/
void    PSLStreamingRelease(void* pPSLStreaming);
};

#endif
