/***************************************************************************************
 *
 *  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
 *
 *  By downloading, copying, installing or using the software you agree to this license.
 *  If you do not agree to this license, do not download, install, 
 *  copy or use the software.
 *
 *  Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
 *
 *  Redistribution and use in binary forms, with or without modification, are permitted.
 *
 *  Unless required by applicable law or agreed to in writing, software distributed 
 *  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 *  CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
 *  language governing permissions and limitations under the License.
 *
****************************************************************************************/

#ifndef RTSP_CLN_H
#define RTSP_CLN_H

#include "sys_buf.h"
#include "rtsp_rcua.h"
#include "media_format.h"
#include "h264_rtp_rx.h"
#include "mjpeg_rtp_rx.h"
#include "h265_rtp_rx.h"
#include "mpeg4_rtp_rx.h"
#include "aac_rtp_rx.h"
#include "pcm_rtp_rx.h"


typedef int (*notify_cb)(int, void *);
typedef int (*video_cb)(uint8 *, int, uint32, uint16, void *);
typedef int (*audio_cb)(uint8 *, int, uint32, uint16, void *);
typedef int (*rtcp_cb)(uint8 *, int, int, void *);
typedef int (*metadata_cb)(uint8 *, int, uint32, uint16, void *);


#define RTSP_EVE_STOPPED    0           // stopped
#define RTSP_EVE_CONNECTING 1           // connecting
#define RTSP_EVE_CONNFAIL   2           // connect failed
#define RTSP_EVE_CONNSUCC   3           // connect success
#define RTSP_EVE_NOSIGNAL   4           // no signal
#define RTSP_EVE_RESUME     5           // resume 
#define RTSP_EVE_AUTHFAILED 6           // authentication failed
#define RTSP_EVE_NODATA   	7           // No data received within the timeout period

#define RTSP_RX_FAIL        -1          // rtsp data receive failed
#define RTSP_RX_TIMEOUT     1           // rtsp data receive timeout
#define RTSP_RX_SUCC        2           // rtsp data receive success

#define RTSP_PARSE_FAIL		-1          // rtsp message parse failed 
#define RTSP_PARSE_MOREDATA 0           // need more data to parse rtsp message
#define RTSP_PARSE_SUCC		1           // rtsp message parse success



class CRtspClient
{
public:
	CRtspClient(void);
	~CRtspClient(void);

public:
	BOOL    rtsp_start(const char * suffix, const char * ip, int port, const char * user, const char * pass);
	BOOL    rtsp_start(const char * url, const char * user, const char * pass);
	BOOL    rtsp_play(int npt_start = 0);
	BOOL    rtsp_stop();
	BOOL    rtsp_pause();
	BOOL    rtsp_close();

	RCUA *  get_rua() {return &m_rua;}
	char *  get_url() {return m_url;}
	char *  get_ip() {return  m_ip;}
	int     get_port() {return m_nport;}
	char *  get_user() {return m_rua.auth_info.auth_name;}
	char *  get_pass() {return m_rua.auth_info.auth_pwd;}
	void    set_notify_cb(notify_cb notify, void * userdata);
	void    set_video_cb(video_cb cb);
	void    set_audio_cb(audio_cb cb);
	void    set_metadata_cb(metadata_cb cb);
	void    set_rtcp_cb(rtcp_cb cb);

    /**
      * @desc : set channel flags  
      * @params :
      *    channel: 
      *         AV_VIDEO_CH : video channel
      *         AV_AUDIO_CH : audio channel
      *         AV_METADATA_CH : metadata channel
      *         AV_BACK_CH : audio back channel
      *
      *    flag : 1 - If the SDP description has the channel information, then SETUP this channel, 
      *           0 - DO NOT SETUP THIS CHANNEL 
      *
      *    note : All channels are setup by default 
      */
	void    set_channel(int channel, int flag);

	/**
      * @desc : Set rtp multicast 
      * @params :
      *    flag : 1 - enable rtp multcast, 0 - disable rtp multcast
      */
	void    set_rtp_multicast(int flag);

	/**
      * @desc : Set rtp over udp 
      * @params :
      *    flag : 1 - enable rtp over udp, 0 - disable rtp over udp
      */
	void    set_rtp_over_udp(int flag);

	/**
      * @desc : Set rtsp over http 
      * @params :
      *    flag : 1 - enable rtsp over http, 0 - disable rtsp over http
      *    port : if flag = 1, specify the http port
      */
	void    set_rtsp_over_http(int flag, int port);

    /**
      * @desc : Set rtsp over websocket 
      * @params :
      *    flag : 1 - enable rtsp over websocket, 0 - disable rtsp over websocket
      *    ws_uri : if flag = 1, specify the websocket port
      */
	void    set_rtsp_over_ws(int flag, int port);
	
    /**
      * @desc : Set the data rx timeout, if the data is not received within the specified time, 
      *         send RTSP_EVE_NODATA notification
      * @params :
      *    timeout : Timeout value, unit is second
      */
	void    set_rx_timeout(int timeout);

    /**
      * @desc : Set the connect timeout
      * @params :
      *    timeout : Timeout value, unit is second
      */
	void    set_conn_timeout(int timeout);

	/**
      * @desc : Get H264, SPS, PPS parameters, and return through the video callback function
      */
	void 	get_h264_params();

	/**
      * @desc : Get H264, SPS, PPS parameters
      * @params
      *     p_sps : Receive H264 SPS data, the buffer size is not less than 256
      *     sps_len : Receive H264 SPS buffer length
      *     p_pps : Receive H264 PPS data, the buffer size is not less than 256
      *     pps_len : Receive H264 PPS buffer length
      */
	BOOL 	get_h264_params(uint8 * p_sps, int * sps_len, uint8 * p_pps, int * pps_len);

	/**
      * @desc : Get H265, VPS, SPS, PPS parameters, and return through the video callback function
      */
	void 	get_h265_params();

	/**
      * @desc : Get H265, VPS, SPS, PPS parameters
      * @params
      *     p_sps : Receive H264 SPS data, the buffer size is not less than 256
      *     sps_len : Receive H264 SPS buffer length
      *     p_pps : Receive H264 PPS data, the buffer size is not less than 256
      *     pps_len : Receive H264 PPS buffer length
      *     p_vps : Receive H264 VPS data, the buffer size is not less than 256
      *     vps_len : Receive H264 VPS buffer length
      */
	BOOL    get_h265_params(uint8 * p_sps, int * sps_len, uint8 * p_pps, int * pps_len, uint8 * p_vps, int * vps_len);

    /**
      * @desc : If the describe request response returned by the server has an H264 SDP description, get the H264 SDP description
      * @params
      *     p_sdp : Receive H264 SDP description
      *     max_len : Maximum length of buffer p_sdp
      */
	BOOL    get_h264_sdp_desc(char * p_sdp, int max_len);

	/**
      * @desc : If the describe request response returned by the server has an H265 SDP description, get the H265 SDP description
      * @params
      *     p_sdp : Receive H265 SDP description
      *     max_len : Maximum length of buffer p_sdp
      */
	BOOL    get_h265_sdp_desc(char * p_sdp, int max_len);

	/**
      * @desc : If the describe request response returned by the server has an H265 SDP description, get the MP4 SDP description
      * @params
      *     p_sdp : Receive MP4 SDP description
      *     max_len : Maximum length of buffer p_sdp
      */
	BOOL    get_mp4_sdp_desc(char * p_sdp, int max_len);

	/**
      * @desc : If the describe request response returned by the server has an H265 SDP description, get the AAC SDP description
      * @params
      *     p_sdp : Receive AAC SDP description
      *     max_len : Maximum length of buffer p_sdp
      */
	BOOL    get_aac_sdp_desc(char * p_sdp, int max_len);

    /**
      * @desc : Get video codec
      * @retrun : reference the media_format.h, VIDEO_CODEC_H264, ...
      */
	int     audio_codec() {return m_rua.audio_codec;}

	/**
      * @desc : Get audio codec
      * @retrun : reference the media_format.h, AUDIO_CODEC_AAC, ...
      */
	int     video_codec() {return m_rua.video_codec;}

	/**
      * @desc : Get audio sample rate
      */
	int     get_audio_samplerate() {return m_rua.sample_rate;}

	/**
      * @desc : Get audio channel numbers
      */
	int     get_audio_channels() {return m_rua.audio_channels;}

    /**
      * @desc : Get audio bits per sample, for G726 decoder
      */
    int     get_audio_bitpersample() {return m_rua.bit_per_sample;}
    
	/**
      * @desc : Get audio config data, for AAC
      */
	uint8 * get_audio_config() {return m_rua.audio_spec;}

	/**
      * @desc : Get audio config data length, for AAC
      */
	int     get_audio_config_len() {return m_rua.audio_spec_len;}

    /**
      * @desc : get the audio backchannel flag
      */
    int     get_bc_flag();

    /**
      * @desc : set the audio backchannel flag
      * @params
      *    flag : 1 - enable audio backchannel; 0 - disable audio backchannel
      */
    void    set_bc_flag(int flag);

    /**
      * @desc : get the audio backchannel data sending flag
      */
    int     get_bc_data_flag();

    /**
      * @desc : set the audio backchannel data sending flag
      * @params
      *    flag : 1 - enable audio backchannel data sending; 0 - disable audio backchannel data sending
      */
    void    set_bc_data_flag(int flag);

    /**
      * @desc : set the audio backchannel audio capture device index
      * @params
      *    index : audio capture device index
      */
    void    set_audio_device(int index);

    /**
      * @desc : get the replay flag
      */
    int     get_replay_flag();

    /**
      * @desc : set the replay flag
      * @params
      *    flag : 1 - enable replay; 0 - disable replay
      */
    void    set_replay_flag(int flag);

    /**
      * @desc : set the scale info
      * @params
      *    scale : when not set the rata control flag, the scale is valid.
      *            It shall be either 1.0 or -1.0, to indicate forward or reverse playback respectively. 
      *            If it is not present, forward playback is assumed
      */
    void    set_scale(double scale);

    /**
      * @desc : set the rate control flag
      * @params
      *    flag : 
      *        1-the stream is delivered in real time using standard RTP timing mechanisms
      *        0-the stream is delivered as fast as possible, using only the flow control provided by the transport to limit the delivery rate
      */
    void    set_rate_control_flag(int flag);

    /**
      * @desc : set the immediate flag
      * @params
      *    flag : 
      *        1 - immediately start playing from the new location, cancelling any existing PLAY command.
      *            The first packet sent from the new location shall have the D (discontinuity) bit set in its RTP extension header. 
      */
    void    set_immediate_flag(int flag);

    /**
      * @desc : set the frame flag
      * @params
      *    flag : 
      *      0 - all frames
      *      1 - I-frame and P-frame
      *      2 - I-frame
      * interval : 
      *      when flag = 2, set the I-frame interval
      */
    void    set_frames_flag(int flag, int interval);

    /**
      * @desc : set replay range
      * @params
      *    start : the replay start timestamp
      *    end : the replay end timestamp
      */
    void    set_replay_range(time_t start, time_t end);

    void    tcp_rx_thread();
    void    udp_rx_thread();
    void    rtsp_video_data_cb(uint8 * p_data, int len, uint32 ts, uint32 seq);
    void    rtsp_audio_data_cb(uint8 * p_data, int len, uint32 ts, uint32 seq);
    void    rtsp_meta_data_cb(uint8 * p_data, int len, uint32 ts, uint32 seq);
    
private:
    void    set_default();
    BOOL    rtsp_client_start();
	void    rtsp_client_stop(RCUA * p_rua);
	BOOL    rtsp_client_state(RCUA * p_rua, HRTSP_MSG * rx_msg);
	int     rtsp_epoll_rx();
	int     rtsp_tcp_data_rx(RCUA * p_rua);
	int     rtsp_over_tcp_rx(RCUA * p_rua);
    int     rtsp_tcp_rx();
    int     rtsp_udp_rx();
    int     rtsp_msg_parser(RCUA * p_rua);
    void    rtsp_keep_alive();
    BOOL    rtsp_setup_channel(RCUA * p_rua, int av_t);
    
    BOOL    make_prepare_play();
    BOOL    rtsp_unauth_res(RCUA * p_rua, HRTSP_MSG * rx_msg);
    BOOL    rtsp_options_res(RCUA * p_rua, HRTSP_MSG * rx_msg);
    BOOL    rtsp_describe_res(RCUA * p_rua, HRTSP_MSG * rx_msg);
    BOOL    rtsp_setup_res(RCUA * p_rua, HRTSP_MSG * rx_msg, int av_t);
    BOOL    rtsp_play_res(RCUA * p_rua, HRTSP_MSG * rx_msg);

    BOOL    rtsp_init_backchannel(RCUA * p_rua);
    BOOL    rtsp_get_bc_media_info();

    void    send_notify(int event);

    BOOL    rtsp_get_transport_info(RCUA * p_rua, HRTSP_MSG * rx_msg, int av_type);
    void    rtsp_get_video_size(int * w, int * h);
    BOOL 	rtsp_get_video_media_info();
    BOOL 	rtsp_get_audio_media_info();
    
	void 	tcp_data_rx(uint8 * lpData, int rlen);
	void 	udp_data_rx(uint8 * lpData, int rlen, int type);
	void    rtcp_data_rx(uint8 * lpData, int rlen, int type);
		
	void 	rtsp_send_h264_params(RCUA * p_rua);    
	void    rtsp_send_h265_params(RCUA * p_rua);
	void	rtsp_get_mpeg4_config(RCUA * p_rua);
	void    rtsp_get_aac_config(RCUA * p_rua);

    int     rtsp_build_http_get_req(void * p_user, char * bufs, int buflen, char * cookie);
    int     rtsp_build_http_post_req(void * p_user, char * bufs, int buflen, char * cookie);
    BOOL    rtsp_over_http_start();
    int     rtsp_over_http_rx(RCUA * p_rua);
    
    int     rtsp_build_ws_req(void * p_user, char * bufs, int buflen);
    BOOL    rtsp_over_ws_start();
    BOOL    rtsp_ws_ping_process(RCUA * p_rua, char * p_buff, int len);
    BOOL    rtsp_ws_rtsp_process(RCUA * p_rua, char * p_buff, int len);
    BOOL    rtsp_ws_data_process(RCUA * p_rua);
    int     rtsp_over_ws_rx(RCUA * p_rua);
    
private:
	RCUA		    m_rua;
	char            m_url[256];
	char            m_ip[128];
	char            m_suffix[128];
	int             m_nport;

    int				m_ep_fd;
	struct epoll_event * m_ep_events;
	int             m_ep_event_num;

	notify_cb       m_pNotify;
	void *          m_pUserdata;
	video_cb        m_pVideoCB;
	audio_cb        m_pAudioCB;
	rtcp_cb         m_pRtcpCB;
	metadata_cb     m_pMetadataCB;
	void *			m_pMutex;
	int             m_nRxTimeout;
	int             m_nConnTimeout;
    int             m_nWidth;
    int             m_nHeight;
    
    union {
	    H264RXI     h264rxi;
	    H265RXI     h265rxi;
	    MJPEGRXI    mjpegrxi;
	    MPEG4RXI    mpeg4rxi;
	};

    union {
        AACRXI      aacrxi;
        PCMRXI      pcmrxi;
    };

    PCMRXI          metadatarxi;
	
	BOOL            m_bRunning;
	pthread_t       m_tcpRxTid;
	pthread_t       m_udpRxTid;
};



#endif	// RTSP_CLN_H



