#ifndef __RTMP_H__
#define __RTMP_H__
/*
 *      Copyright (C) 2005-2008 Team XBMC
 *      http://www.xbmc.org
 *      Copyright (C) 2008-2009 Andrej Stepanchuk
 *      Copyright (C) 2009-2010 Howard Chu
 *
 *  This file is part of librtmp.
 *
 *  librtmp is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation; either version 2.1,
 *  or (at your option) any later version.
 *
 *  librtmp is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with librtmp see the file COPYING.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA  02110-1301, USA.
 *  http://www.gnu.org/copyleft/lgpl.html
 */

#if !defined(NO_CRYPTO) && !defined(CRYPTO)
#define CRYPTO
#endif

#include <errno.h>
#include <stdint.h>
#include <stddef.h>

#include "amf.h"

#ifdef __cplusplus
extern "C"
{
#endif

#define RTMP_LIB_VERSION    0x020300    /* 2.3 */

#define RTMP_FEATURE_HTTP    0x01
#define RTMP_FEATURE_ENC    0x02
#define RTMP_FEATURE_SSL    0x04
#define RTMP_FEATURE_MFP    0x08    /* not yet supported */
#define RTMP_FEATURE_WRITE    0x10    /* publish, not play */
#define RTMP_FEATURE_HTTP2    0x20    /* server-side rtmpt */

#define RTMP_PROTOCOL_UNDEFINED    -1
#define RTMP_PROTOCOL_RTMP      0
#define RTMP_PROTOCOL_RTMPE     RTMP_FEATURE_ENC
#define RTMP_PROTOCOL_RTMPT     RTMP_FEATURE_HTTP
#define RTMP_PROTOCOL_RTMPS     RTMP_FEATURE_SSL
#define RTMP_PROTOCOL_RTMPTE    (RTMP_FEATURE_HTTP|RTMP_FEATURE_ENC)
#define RTMP_PROTOCOL_RTMPTS    (RTMP_FEATURE_HTTP|RTMP_FEATURE_SSL)
#define RTMP_PROTOCOL_RTMFP     RTMP_FEATURE_MFP

#define RTMP_DEFAULT_CHUNKSIZE    128

/* needs to fit largest number of bytes recv() may return */
#define RTMP_BUFFER_CACHE_SIZE (16*1024)

#define    RTMP_CHANNELS    65600

extern const char RTMPProtocolStringsLower[][7];
extern const AVal RTMP_DefaultFlashVer;
extern int RTMP_ctrlC;

uint32_t RTMP_GetTime(void);

/*      RTMP_PACKET_TYPE_...                0x00 */
#define RTMP_PACKET_TYPE_CHUNK_SIZE         0x01
/*      RTMP_PACKET_TYPE_...                0x02 */
#define RTMP_PACKET_TYPE_BYTES_READ_REPORT  0x03
#define RTMP_PACKET_TYPE_CONTROL            0x04
#define RTMP_PACKET_TYPE_SERVER_BW          0x05
#define RTMP_PACKET_TYPE_CLIENT_BW          0x06
/*      RTMP_PACKET_TYPE_...                0x07 */
#define RTMP_PACKET_TYPE_AUDIO              0x08
#define RTMP_PACKET_TYPE_VIDEO              0x09
/*      RTMP_PACKET_TYPE_...                0x0A */
/*      RTMP_PACKET_TYPE_...                0x0B */
/*      RTMP_PACKET_TYPE_...                0x0C */
/*      RTMP_PACKET_TYPE_...                0x0D */
/*      RTMP_PACKET_TYPE_...                0x0E */
#define RTMP_PACKET_TYPE_FLEX_STREAM_SEND   0x0F
#define RTMP_PACKET_TYPE_FLEX_SHARED_OBJECT 0x10
#define RTMP_PACKET_TYPE_FLEX_MESSAGE       0x11
#define RTMP_PACKET_TYPE_INFO               0x12
#define RTMP_PACKET_TYPE_SHARED_OBJECT      0x13
#define RTMP_PACKET_TYPE_INVOKE             0x14
/*      RTMP_PACKET_TYPE_...                0x15 */
#define RTMP_PACKET_TYPE_FLASH_VIDEO        0x16

#define RTMP_MAX_HEADER_SIZE 18

#define RTMP_PACKET_SIZE_LARGE    0
#define RTMP_PACKET_SIZE_MEDIUM   1
#define RTMP_PACKET_SIZE_SMALL    2
#define RTMP_PACKET_SIZE_MINIMUM  3

typedef struct RTMPChunk {
    int c_headerSize;
    int c_chunkSize;
    char *c_chunk;
    char c_header[RTMP_MAX_HEADER_SIZE];
} RTMPChunk;

typedef struct RTMPPacket {
    uint8_t m_headerType;
    uint8_t m_packetType;
    uint8_t m_hasAbsTimestamp;    /* timestamp absolute or relative? */
    int m_nChannel;
    uint32_t m_nTimeStamp;    /* timestamp */
    int32_t m_nInfoField2;    /* last 4 bytes in a long header */
    uint32_t m_nBodySize;
    uint32_t m_nBytesRead;
    RTMPChunk *m_chunk;
    char *m_body;
} RTMPPacket;

typedef struct RTMPSockBuf {
    int sb_socket;
    int sb_size;        /* number of unprocessed bytes in buffer */
    char *sb_start;        /* pointer into sb_pBuffer of next byte to process */
    char sb_buf[RTMP_BUFFER_CACHE_SIZE];    /* data read from socket */
    int sb_timedout;
    void *sb_ssl;
} RTMPSockBuf;

void RTMPPacket_Reset(RTMPPacket *p);

void RTMPPacket_Dump(RTMPPacket *p);

int RTMPPacket_Alloc(RTMPPacket *p, uint32_t nSize);

void RTMPPacket_Free(RTMPPacket *p);

#define RTMPPacket_IsReady(a)    ((a)->m_nBytesRead == (a)->m_nBodySize)

typedef struct RTMP_LNK {
    AVal hostname;
    AVal sockshost;

    AVal playpath0;    /* parsed from URL */
    AVal playpath;    /* passed in explicitly */
    AVal tcUrl;
    AVal swfUrl;
    AVal pageUrl;
    AVal app;
    AVal auth;
    AVal flashVer;
    AVal subscribepath;
    AVal usherToken;
    AVal token;
    AVal pubUser;
    AVal pubPasswd;
    AMFObject extras;
    int edepth;

    int seekTime;
    int stopTime;

#define RTMP_LF_AUTH    0x0001    /* using auth param */
#define RTMP_LF_LIVE    0x0002    /* stream is live */
#define RTMP_LF_SWFV    0x0004    /* do SWF verification */
#define RTMP_LF_PLST    0x0008    /* send playlist before play */
#define RTMP_LF_BUFX    0x0010    /* toggle stream on BufferEmpty msg */
#define RTMP_LF_FTCU    0x0020    /* free tcUrl on close */
#define RTMP_LF_FAPU    0x0040    /* free app on close */
    int lFlags;

    int swfAge;

    int protocol;
    int timeout;        /* connection timeout in seconds */

    int pFlags;            /* unused, but kept to avoid breaking ABI */

    unsigned short socksport;
    unsigned short port;

#ifdef CRYPTO
#define RTMP_SWF_HASHLEN	32
    void *dh;			/* for encryption */
    void *rc4keyIn;
    void *rc4keyOut;

    uint32_t SWFSize;
    uint8_t SWFHash[RTMP_SWF_HASHLEN];
    char SWFVerificationResponse[RTMP_SWF_HASHLEN+10];
#endif
} RTMP_LNK;

/* state for read() wrapper */
typedef struct RTMP_READ {
    char *buf;
    char *bufpos;
    unsigned int buflen;
    uint32_t timestamp;
    uint8_t dataType;
    uint8_t flags;
#define RTMP_READ_HEADER    0x01
#define RTMP_READ_RESUME    0x02
#define RTMP_READ_NO_IGNORE    0x04
#define RTMP_READ_GOTKF        0x08
#define RTMP_READ_GOTFLVK    0x10
#define RTMP_READ_SEEKING    0x20
    int8_t status;
#define RTMP_READ_COMPLETE    -3
#define RTMP_READ_ERROR    -2
#define RTMP_READ_EOF    -1
#define RTMP_READ_IGNORE    0

    /* if bResume == TRUE */
    uint8_t initialFrameType;
    uint32_t nResumeTS;
    char *metaHeader;
    char *initialFrame;
    uint32_t nMetaHeaderSize;
    uint32_t nInitialFrameSize;
    uint32_t nIgnoredFrameCounter;
    uint32_t nIgnoredFlvFrameCounter;
} RTMP_READ;

typedef struct RTMP_METHOD {
    AVal name;
    int num;
} RTMP_METHOD;

typedef struct RTMP {
    int m_inChunkSize;
    int m_outChunkSize;
    int m_nBWCheckCounter;
    int m_nBytesIn;
    int m_nBytesInSent;
    int m_nBufferMS;
    int m_stream_id;        /* returned in _result from createStream */
    int m_mediaChannel;
    uint32_t m_mediaStamp;
    uint32_t m_pauseStamp;
    int m_pausing;
    int m_nServerBW;
    int m_nClientBW;
    uint8_t m_nClientBW2;
    uint8_t m_bPlaying;
    uint8_t m_bSendEncoding;
    uint8_t m_bSendCounter;

    int m_numInvokes;
    int m_numCalls;
    RTMP_METHOD *m_methodCalls;    /* remote method calls queue */

    int m_channelsAllocatedIn;
    int m_channelsAllocatedOut;
    RTMPPacket **m_vecChannelsIn;
    RTMPPacket **m_vecChannelsOut;
    int *m_channelTimestamp;    /* abs timestamp of last packet */

    double m_fAudioCodecs;    /* audioCodecs for the connect packet */
    double m_fVideoCodecs;    /* videoCodecs for the connect packet */
    double m_fEncoding;        /* AMF0 or AMF3 */

    double m_fDuration;        /* duration of stream in seconds */

    int m_msgCounter;        /* RTMPT stuff */
    int m_polling;
    int m_resplen;
    int m_unackd;
    AVal m_clientID;

    RTMP_READ m_read;
    RTMPPacket m_write;
    RTMPSockBuf m_sb;
    RTMP_LNK Link;
} RTMP;

int RTMP_ParseURL(const char *url, int *protocol, AVal *host,
                  unsigned int *port, AVal *playpath, AVal *app);

void RTMP_ParsePlaypath(AVal *in, AVal *out);

void RTMP_SetBufferMS(RTMP *r, int size);

void RTMP_UpdateBufferMS(RTMP *r);

int RTMP_SetOpt(RTMP *r, const AVal *opt, AVal *arg);

int RTMP_SetupURL(RTMP *r, char *url);

void RTMP_SetupStream(RTMP *r, int protocol,
                      AVal *hostname,
                      unsigned int port,
                      AVal *sockshost,
                      AVal *playpath,
                      AVal *tcUrl,
                      AVal *swfUrl,
                      AVal *pageUrl,
                      AVal *app,
                      AVal *auth,
                      AVal *swfSHA256Hash,
                      uint32_t swfSize,
                      AVal *flashVer,
                      AVal *subscribepath,
                      AVal *usherToken,
                      int dStart,
                      int dStop, int bLiveStream, long int timeout);

int RTMP_Connect(RTMP *r, RTMPPacket *cp);

struct sockaddr;

int RTMP_Connect0(RTMP *r, struct sockaddr *svc);

int RTMP_Connect1(RTMP *r, RTMPPacket *cp);

int RTMP_Serve(RTMP *r);

int RTMP_TLS_Accept(RTMP *r, void *ctx);

int RTMP_ReadPacket(RTMP *r, RTMPPacket *packet);

int RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue);

int RTMP_SendChunk(RTMP *r, RTMPChunk *chunk);

int RTMP_IsConnected(RTMP *r);

int RTMP_Socket(RTMP *r);

int RTMP_IsTimedout(RTMP *r);

double RTMP_GetDuration(RTMP *r);

int RTMP_ToggleStream(RTMP *r);

int RTMP_ConnectStream(RTMP *r, int seekTime);

int RTMP_ReconnectStream(RTMP *r, int seekTime);

void RTMP_DeleteStream(RTMP *r);

int RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet);

int RTMP_ClientPacket(RTMP *r, RTMPPacket *packet);

void RTMP_Init(RTMP *r);

void RTMP_Close(RTMP *r);

RTMP *RTMP_Alloc(void);

void RTMP_Free(RTMP *r);

void RTMP_EnableWrite(RTMP *r);

void *RTMP_TLS_AllocServerContext(const char *cert, const char *key);

void RTMP_TLS_FreeServerContext(void *ctx);

int RTMP_LibVersion(void);

void RTMP_UserInterrupt(void);    /* user typed Ctrl-C */

int RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject,
                  unsigned int nTime);

/* caller probably doesn't know current timestamp, should
 * just use RTMP_Pause instead
 */
int RTMP_SendPause(RTMP *r, int DoPause, int dTime);

int RTMP_Pause(RTMP *r, int DoPause);

int RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name,
                                   AMFObjectProperty *p);

int RTMPSockBuf_Fill(RTMPSockBuf *sb);

int RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len);

int RTMPSockBuf_Close(RTMPSockBuf *sb);

int RTMP_SendCreateStream(RTMP *r);

int RTMP_SendSeek(RTMP *r, int dTime);

int RTMP_SendServerBW(RTMP *r);

int RTMP_SendClientBW(RTMP *r);

void RTMP_DropRequest(RTMP *r, int i, int freeit);

int RTMP_Read(RTMP *r, char *buf, int size);

int RTMP_Write(RTMP *r, const char *buf, int size);

/* hashswf.c */
int RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash,
                 int age);

#ifdef __cplusplus
};
#endif

#endif
