/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: rtspclnt.h,v 1.22.2.3 2004/07/13 17:15:04 ping Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

#ifndef _RTSPCLNT_H_
#define _RTSPCLNT_H_

#include "rtspif.h"
#include "rtspbase.h"
#include "rtsptran.h"
#include "rtptran.h"
#include "rtspmdsc.h"
#include "sdptypes.h"	// SdpFileType
#include "hxpreftr.h"
#include "hxbufctl.h" // IHXTransportBufferLimit
#include "hxrtsp2.h"

class RTSPClientState;
class RTSPOptionsMessage;
class RTSPTeardownMessage;
class RTSPGetParamMessage;
class RTSPSetParamMessage;
class RTSPSetupMessage;
class RTSPAnnounceMessage;
class RTSPPlayMessage;
class RTSPRedirectMessage;
class RTSPParser;
class RTSPClientProtocol;
class CByteGrowingQueue;
class HXMutex;
class MIMEHeader;

struct IHXKeyValueList;
struct IHXValues;
struct IHXStreamDescription;
struct IHXPacket;
struct IHXConnectionlessControl;
struct IHXInterruptState;

#if defined(HELIX_CONFIG_NOSTATICS)
#include "globals/hxglobalptr.h"
#define RTSPClientSessionManagerType const RTSPClientSessionManager* const
#else
#define RTSPClientSessionManagerType RTSPClientSessionManager*
#endif /* defined(HELIX_CONFIG_NOSTATICS) */

typedef enum
{    
    ALTERNATE_SERVER,
    ALTERNATE_PROXY
} ReconnectType;

typedef enum
{
    ENTER_PREFETCH = 0,
    LEAVE_PREFETCH,
    ENTER_FASTSTART,
    LEAVE_FASTSTART,
    PAUSE_BUFFER,
    RESUME_BUFFER
} TRANSPORT_MSG;

typedef struct _ReconnectInfo
{
    CHXString	m_server;
    UINT32	m_ulPort;
} ReconnectInfo;

typedef struct _RTSPClientProtocolInfo
{
    RTSPClientProtocol*	m_pProt;
    CHXSimpleList	m_seqNoList;
    CHXMapLongToObj     m_interleaveMap;
} RTSPClientProtocolInfo;

typedef enum _RTSPIndex
{
    SETUP	    = 0,
    REDIRECT	    = 1,
    PLAY	    = 2,
    PAUSE	    = 3,
    SET_PARAM	    = 4,
    GET_PARAM	    = 5,
    OPTIONS	    = 6,
    DESCRIBE	    = 7, 
    TEARDOWN	    = 8,
    RECORD	    = 9,
    ANNOUNCE	    = 10
} RTSPIndex;
const UINT32 RTSP_TABLE_SIZE = 11;

struct RTSPTableEntry
{
    const char* pMethod;
    RTSPIndex	index;
};

class RTSPTransportInfo
{
public:
    RTSPTransportInfo           ();
    ~RTSPTransportInfo          ();
    BOOL containsStreamNumber	(UINT16 streamNumber);
    void addStreamNumber	(UINT16 streamNumber);
    RTSPTransport*              m_pTransport;
    RTCPBaseTransport*		m_pRTCPTransport;
    UINT16                      m_sPort;
    UINT16                      m_sResendPort;

private:
    CHXSimpleList               m_streamNumberList;
};

class RTSPTransportRequest
{
public:
    RTSPTransportRequest        (RTSPTransportTypeEnum tType, UINT16 sPort);
    ~RTSPTransportRequest       ();
    HX_RESULT addTransportInfo  (RTSPTransport* pTransport, 
				RTCPBaseTransport* pRTCPTransport,
				UINT16 streamNumber,
				UINT16 sPort);
    RTSPTransportInfo*		getTransportInfo(UINT16 streamNumber);
    void			ResetTransports();
    RTSPTransportInfo*		getFirstTransportInfo();
    RTSPTransportInfo*		getNextTransportInfo();

    RTSPTransportTypeEnum       m_lTransportType;
    UINT16                      m_sPort;
    UINT16			m_sResendPort;
    INT8			m_tcpInterleave;
    BOOL			m_bDelete;

private:
    CHXSimpleList               m_transportInfoList;
    LISTPOSITION		m_lListPos;
};

class RTSPClientSession	: public IHXTCPResponse, 
			  public IHXInterruptSafe
{
public:
    RTSPClientSession			    ();
    virtual ~RTSPClientSession			    ();

    HX_RESULT Done			    ();
    HX_RESULT Init			    (IUnknown* pContext,
    					RTSPClientProtocol* pProt,
    					const char* pHostName,
					UINT16 uPort, 
					UINT32 ulActualAddr,
					BOOL bUseProxy,
					BOOL bHTTPCloak,
					UINT16 uCloakPort);

    /*
     * IUnknown methods
     */

    STDMETHOD(QueryInterface)           (THIS_
					REFIID riid,
					void** ppvObj);

    STDMETHOD_(ULONG32,AddRef)          (THIS);

    STDMETHOD_(ULONG32,Release)         (THIS);

    /*
     *  IHXTCPResponse methods
     */

    STDMETHOD(ConnectDone)              (THIS_
					HX_RESULT status);

    STDMETHOD(ReadDone)                 (THIS_
					HX_RESULT status,
					IHXBuffer* pBuffer);

    STDMETHOD(WriteReady)               (THIS_
					HX_RESULT status);

    STDMETHOD(Closed)                   (THIS_
					HX_RESULT status);

    /*
     *	IHXInterruptSafe methods
     */
    STDMETHOD_(BOOL,IsInterruptSafe)	(THIS) {return TRUE;};

    HX_RESULT addProtocol		    (RTSPClientProtocol* pProt);
    HX_RESULT removeProtocol	    (RTSPClientProtocol* pProt);
    int getProtocolCount		    ();

    HX_RESULT setProtocolInterleave	    (RTSPClientProtocol* pProt, 
					    INT8 interleave);
    HX_RESULT setProtocolSeqNo	    (RTSPClientProtocol* pProt, 
					    UINT32 seqNo);
    HX_RESULT removeProtocolSeqNo	    (RTSPClientProtocol* pProt,
					    UINT32 seqNo);
    BOOL isEmpty			    ();
    IHXTCPSocket* getSocket	    ();
    HX_RESULT closeSocket		    ();
    HX_RESULT reopenSocket		    (RTSPClientProtocol* pProt);
    UINT32 getNextSeqNo		    (RTSPClientProtocol* pProt);
    BOOL HttpOnly			    ();

    BOOL				    m_bIgnoreSession;
    BOOL				    m_bUseProxy;	
    char*				    m_pForeignHost;
    UINT16				    m_uForeignPort;
    UINT32				    m_ulActualAddr;
    char*				    m_pActualHost;
    UINT16				    m_uActualPort;
    UINT16				    m_uCloakPort;
    BOOL				    m_bReopenSocket;
    IUnknown*				    m_pContext;

    BOOL				    m_bHTTPOnly;
    BOOL				    m_bChallengeDone;
    BOOL				    m_bChallengeMet;
    VOLATILE BOOL			    m_bIsValidChallengeT;
    void ReportError(HX_RESULT);


private:
    HX_RESULT handleInput		    (BYTE* pData, UINT32 dataLen);
    RTSPClientProtocol* 
	findProtocolFromInterleave	    (INT8 interleave);
    RTSPClientProtocol* 
	findProtocolFromSeqNo	    (UINT32 seqNo);
    RTSPClientProtocol*
	findProtocolFromSessionID	    (CHXString* pszSessionID);

    void getSessionID		    (RTSPMessage* pMsg, CHXString* pszSessionID);

    IHXNetworkServices*		    m_pNetworkServices;
    IHXTCPSocket*			    m_pSessionSocket;
    CHXSimpleList			    m_protList;
    INT32			            m_lRefCount;
    UINT32				    m_ulLastSeqNo;
    CByteGrowingQueue*		    m_pInQueue;
    RTSPParser*			    m_pParser;
    BOOL				    m_bSessionDone;
    BOOL				    m_bSetSessionCalled;

    // used in Connect/ConnectDone
    RTSPClientProtocol*		    m_pConnectingProt;
    HXMutex*			    m_pMutex;
};
	
class RTSPClientSessionManager : public IUnknown
{
public:
    					~RTSPClientSessionManager();
    static RTSPClientSessionManager*	instance();
    BOOL isValid			() { return SessionManGlobal() != NULL; }

    /*
     * IUnknown methods
     */

    STDMETHOD(QueryInterface)           (THIS_
					REFIID riid,
					void** ppvObj);

    STDMETHOD_(ULONG32,AddRef)          (THIS);

    STDMETHOD_(ULONG32,Release)         (THIS);

    /*
     * RTSPClientSessionManager methods
     */

    virtual HX_RESULT newSession	(IUnknown* pContext,
    					RTSPClientProtocol* pProt,
    					const char* pHostName,
					UINT16 uPort, 
					UINT32 ulActualAddr,
					BOOL bUseProxy,
					BOOL bHTTPOnly,
					UINT16 uCloakPort);

    HX_RESULT removeFromSession		(RTSPClientProtocol* pProt,
					RTSPClientSession* pSessionRemoved);

    RTSPClientSession* 
	findSession			(UINT32 ulActualAddr,
					UINT16 uActualPort,
					BOOL bUseProxy,
					const char* pForeignHost,
					UINT16 uForeignPort,
					IUnknown* pContext = NULL);
    CHXSimpleList* getSessionList	() { return &m_sessionList; }
    int	    getSessionCount		();
    BOOL    MatchPlayerContext		(IUnknown* pNewContext, IUnknown* pKnownContext);

protected:
					RTSPClientSessionManager();


    static RTSPClientSessionManagerType zm_pSessionManager;

    static RTSPClientSessionManager*& SessionManGlobal();

    HXMutex*				m_pMutex;
    CHXSimpleList			m_sessionList;

private:
    IHXResolver*		        m_pResolver;
    INT32				m_lRefCount;
};

class RTSPClientProtocol: public RTSPBaseProtocol, 
                          public IHXRTSPClientProtocol,
                          public IHXRTSPClientTransportResponse,
                          public IHXPendingStatus,
                          public IHXStatistics,
			  public IHXResolverResponse,
			  public IHXThinnableSource,
			  public IHXPacketResend,
			  public IHXInterruptSafe,
			  public IHXResendBufferControl,
			  public IHXTransportSyncServer,
			  public IHXTransportBufferLimit
{
public:
    RTSPClientProtocol			();
    ~RTSPClientProtocol			();

    enum State
    {
	INIT,
	READY,
	PLAYING,
	RECORDING
    };

    class UDPResponseHelper: public IHXUDPResponse,
			     public IHXInterruptSafe
    {
    private:
	LONG32			m_lRefCount;
	UINT16			m_nPort;
	RTSPClientProtocol* 	m_pOwner;

    public:
	UDPResponseHelper(RTSPClientProtocol* pParent, UINT16 nPort);
	~UDPResponseHelper();

	/* IUnknown Interfaces */

	STDMETHOD(QueryInterface)	(THIS_
					REFIID riid,
					void** ppvObj);

	STDMETHOD_(ULONG32,AddRef)	(THIS);

	STDMETHOD_(ULONG32,Release)	(THIS);

	/*
	*	IHXInterruptSafe methods
	*/
	STDMETHOD_(BOOL,IsInterruptSafe)(THIS) {return TRUE;};

	/*
	*	IHXUDPSocket methods
	*/
	STDMETHOD(ReadDone)		(THIS_
    					HX_RESULT status,
					IHXBuffer* pBuffer,
					UINT32 ulAddr,
					UINT16 nPort);
    };

    class ConnectionCheckCallback : public IHXCallback
    {
    public:
	ConnectionCheckCallback(RTSPClientProtocol* pOwner);
	~ConnectionCheckCallback();

    /* IUnknown Interfaces */

	STDMETHOD(QueryInterface)	(THIS_
					REFIID riid,
					void** ppvObj);

	STDMETHOD_(ULONG32,AddRef)	(THIS);

	STDMETHOD_(ULONG32,Release)	(THIS);

	STDMETHOD(Func)			(THIS);

    private:
	LONG32			m_lRefCount;
	RTSPClientProtocol* 	m_pOwner;
    };

#ifdef _MACINTOSH
    class RTSPClientProtocolCallback : public IHXCallback
    {
    public:
	RTSPClientProtocolCallback(RTSPClientProtocol* pOwner);
	~RTSPClientProtocolCallback();

    /* IUnknown Interfaces */

	STDMETHOD(QueryInterface)	(THIS_
					REFIID riid,
					void** ppvObj);

	STDMETHOD_(ULONG32,AddRef)	(THIS);

	STDMETHOD_(ULONG32,Release)	(THIS);

	STDMETHOD(Func)			(THIS);

	LONG32			m_lRefCount;
	RTSPClientProtocol* 	m_pOwner;
	BOOL			m_bIsCallbackPending;
	CallbackHandle		m_Handle;
	IHXValues*		m_pPendingRequestHeaders;
	CHXString		m_PendingDescURL;
    };

    friend class RTSPClientProtocolCallback;
#endif /* _MACINTOSH */

    /*
     * IUnknown methods
     */

    STDMETHOD(QueryInterface)           (THIS_
                                        REFIID riid,
                                        void** ppvObj);

    STDMETHOD_(ULONG32,AddRef)          (THIS);

    STDMETHOD_(ULONG32,Release)         (THIS);

    /*
     * IHXRTSPClientProtocol methods
     */

    STDMETHOD(Init)			(THIS_
					IUnknown*   pContext,
					const char* pHostName,
					UINT16	    foreignPort,
					IHXRTSPClientProtocolResponse* pClient,
					UINT32	    initializationType,
					IHXValues* pSessionHeaders,
					IHXValues* pInfo,
					BOOL	    bHTTPCloak,
					UINT16	    uCloakPort,
					BOOL	    bNoReuseConnection);
    STDMETHOD(SetBuildVersion)		(THIS_
    					const char* pVersionString);
    STDMETHOD(Done)			(THIS);
    STDMETHOD(SendStreamDescriptionRequest)		
					(THIS_
    					const char* pURL,
					IHXValues* pRequestHeaders);
    STDMETHOD(SendStreamRecordDescriptionRequest)
    					(THIS_
					const char* pURL,
					IHXValues* pFileHeader,
					CHXSimpleList* pStreams,
					IHXValues* pRequestHeaders);
    STDMETHOD(SendSetupRequest)
    (
	THIS_
	RTSPTransportType* pTransType,
	UINT16 nTransTypes,
	IHXValues* pIHXValuesRequestHeaders
    );

    STDMETHOD(SendPlayRequest)		(THIS_
					UINT32 lFrom,
					UINT32 lTo,
					CHXSimpleList* pSubscriptions);
    STDMETHOD(SendRecordRequest)	(THIS);
    STDMETHOD(SendPauseRequest)		(THIS);
    STDMETHOD(SendResumeRequest)	(THIS);
    STDMETHOD(SendTeardownRequest)	(THIS);
    STDMETHOD(SendSetParameterRequest)	(THIS_
    					UINT32 lParamType,
					const char* pParamName,
					IHXBuffer* pParamValue);
    STDMETHOD(SendSetParameterRequest)	(THIS_
	    				const char* pParamName,
					const char* pParamValue,
					const char* pMimeType,
					const char* pContent);
    STDMETHOD(SendGetParameterRequest)	(THIS_
    					UINT32 lParamType,
					const char* pParamName);
    STDMETHOD(SendPacket)		(THIS_
					BasePacket* pPacket);
    STDMETHOD(SendStreamDone)		(THIS_
					UINT16 streamNumber);
    STDMETHOD(SendPlayerStats)		(THIS_
					const char* pStats);
    STDMETHOD(SendKeepAlive)		(THIS);
    STDMETHOD(GetPacket)		(THIS_
					UINT16 uStreamNumber,
					REF(IHXPacket*) pPacket);
    STDMETHOD(StartPackets)		(THIS_
					UINT16 uStreamNumber);
    STDMETHOD(StopPackets)		(THIS_
					UINT16 uStreamNumber);
    STDMETHOD(SetProxy)			(THIS_
					const char* pProxyHost,
					UINT16 proxyPort);
    STDMETHOD(SetResponse)		(THIS_
					IHXRTSPClientProtocolResponse* pResp);

    /*
     * IHXThinnableSource methods.
     */

    /************************************************************************
     *	Method:
     *	    IHXThinnableSource::DropByN
     *  Purpose:
     *
     *	Implemented by protocols that allow infinite thinnability through
     *      LimitBandwidthByDropping
     */

    STDMETHOD(LimitBandwidthByDropping)	(THIS_
					UINT32 ulStreamNo,
					UINT32 ulBandwidthLimit);

    STDMETHOD(SetDeliveryBandwidth)	(THIS_
					UINT32 ulBandwidth,
					UINT32 ulMsBackoff);

    /*
     * XXX...The following 3 functions had better be removed under
     *       full IRMA
     */

    STDMETHOD_(IHXPendingStatus*, GetPendingStatus)	(THIS);
    STDMETHOD_(IHXStatistics*, GetStatistics)		(THIS);
    STDMETHOD_(BOOL, HttpOnly)				(THIS);

    STDMETHOD(Subscribe)		(THIS_
    					CHXSimpleList* pSubscriptions);
    STDMETHOD(Unsubscribe)		(THIS_
    					CHXSimpleList* pUnsubscriptions);
    STDMETHOD(RuleChange)		(THIS_
    					CHXSimpleList* pRuleChanges);
    STDMETHOD(BackChannelPacketReady)	(THIS_
    					IHXPacket* pPacket);
    STDMETHOD(SendRTTRequest)		(THIS);

    STDMETHOD(SendBWReport)		(THIS_
    					INT32 aveBandwidth,
					INT32 packetLoss,
					INT32 bandwidthWanted);
    STDMETHOD(SetFirstSeqNum)		(THIS_
					UINT16 uStreamNumber,
					UINT16 uSeqNum);

    STDMETHOD(SetRTPInfo)		(THIS_
					UINT16 uStreamNumber,
					UINT16 uSeqNum,
					UINT32 ulRTPTime,
					RTPInfoEnum info
					);
					
    STDMETHOD(InitSockets)		(THIS);

    STDMETHOD(GetCurrentBuffering)	(THIS_
					UINT16	    uStreamNumber,
					REF(INT64)  llLowestTimestamp, 
					REF(INT64)  llHighestTimestamp,
					REF(UINT32) ulNumBytes,
					REF(BOOL)   bDone);

    STDMETHOD(SeekFlush)		(THIS);

    STDMETHOD_(BOOL, IsDataReceived)	(THIS);
    
    STDMETHOD_(BOOL,IsSourceDone)	(THIS);

    /*
     *	IHXInterruptSafe methods
     */
    STDMETHOD_(BOOL,IsInterruptSafe)	(THIS) {return TRUE;};

    /*
     * IHXRTSPClientTransportResponse methods
     */

    STDMETHOD(PacketReady)		(THIS_
					HX_RESULT status,
					const char* pSessionID,
					IHXPacket* pPacket);

    STDMETHOD(OnRTTRequest)     	(THIS_
                                	HX_RESULT status,
					const char* pSessionID
					);

    STDMETHOD(OnRTTResponse)		(THIS_
    					HX_RESULT status,
					const char* pSessionID,
					UINT32 ulSecs,
					UINT32 ulUSecs);

    STDMETHOD(OnBWReport)	     	(THIS_
                                	HX_RESULT status,
					const char* pSessionID,
					INT32 aveBandwidth,
					INT32 packetLoss,
					INT32 bandwidthWanted
					);

    STDMETHOD(OnCongestion)		(THIS_
    					HX_RESULT status,
					const char* pSessionID,
					INT32 xmitMultiplier,
					INT32 recvMultiplier);

    STDMETHOD(OnACK)			(THIS_
					HX_RESULT status,
					RTSPResendBuffer* pResendBuffer,
					UINT16 uStreamNumber,
					const char* pSessionID,
					UINT16* pAckList,
					UINT32 uAckListCount,
					UINT16* pNakList,
					UINT32 uNakListCount);

    STDMETHOD(OnStreamDone)		(THIS_
					HX_RESULT status,
					UINT16 uStreamNumber);

    STDMETHOD(OnSourceDone)		(THIS);


    STDMETHOD(OnProtocolError)		(THIS_
					HX_RESULT status);

    /*
     * IHXPendingStatus methods
     */

    STDMETHOD(GetStatus)		(THIS_
					REF(UINT16) uStatusCode, 
					REF(IHXBuffer*) pStatusDesc, 
					REF(UINT16) ulPercentDone);
    /*
     * IHXResolverResponse methods
     */

    STDMETHOD(GetHostByNameDone)	(THIS_
					HX_RESULT status,
					UINT32 ulAddr);

    /*
     *	IHXStatistics methods
     */

    STDMETHOD (InitializeStatistics)	(THIS_
					UINT32	/*IN*/ ulRegistryID);

    STDMETHOD (UpdateStatistics)	(THIS);

    STDMETHOD(OnPacket)			(THIS_
					UINT16 uStreamNumber,
					BasePacket** ppPacket);

    STDMETHOD(SetConnectionTimeout)	(THIS_
					UINT32 uSeconds);

    STDMETHOD_(UINT16, GetProtocolType)	(THIS) {return m_uProtocolType;};

    STDMETHOD(InitPacketFilter)		(THIS_
					RawPacketFilter* pFilter);

    STDMETHOD(SetResendBufferDepth)	(THIS_
					UINT32 uSeconds);

    /*
     * IHXTransportSyncServer methods
     */
    STDMETHOD(DistributeSyncAnchor) (THIS_
				    ULONG32 ulHXTime, 
				    ULONG32 ulNTPTime);

    STDMETHOD(DistributeSync)	    (ULONG32 ulHXTime, 
				    LONG32 lHXTimeOffset);

    STDMETHOD(DistributeStartTime)  (ULONG32 ulHXRefTime);

    /*
     * IHXTransportBufferLimit methods
     */

    /************************************************************************
     *	Method:
     *	    IHXTransportBufferLimit::SetByteLimit
     *	Purpose:
     *      Sets the maximum number of bytes that can be buffered in the
     *      transport buffer. If incomming packets would put us over this
     *      limit, then they are replaced with lost packets. A byte limit
     *      of 0 means unlimited buffering.
     */
    STDMETHOD(SetByteLimit) (THIS_ UINT16 uStreamNumber, 
			     UINT32 uByteLimit);

    /************************************************************************
     *	Method:
     *	    IHXTransportBufferLimit::GetByteLimit
     *	Purpose:
     *      Returns the current byte limit in effect. A value of 0 means
     *      unlimited buffering is allowed
     */
    STDMETHOD_(UINT32,GetByteLimit) (THIS_ UINT16 uStreamNumber);

    /*
     *  RTSPClientProtocol public methods
     */

    HX_RESULT(ReadDoneWithToPort)	(
    					HX_RESULT status,
					IHXBuffer* pBuffer,
					UINT32 ulAddr,
					UINT16 nFromPort,
					UINT16 nToPort);

    HX_RESULT HandleUnexpected		(RTSPMessage* pMsg);
    HX_RESULT HandleBadVersion		(RTSPMessage* pMsg);
    HX_RESULT HandleOptions		(RTSPOptionsMessage* pMsg);
    HX_RESULT HandleTeardown		(RTSPTeardownMessage* pMsg);
    HX_RESULT HandleGetParam		(RTSPGetParamMessage* pMsg);
    HX_RESULT HandleSetParam		(RTSPSetParamMessage* pMsg);
    HX_RESULT HandleRedirect		(RTSPRedirectMessage* pMsg);
    HX_RESULT HandleUseProxy		(RTSPResponseMessage* pMsg);
    void      SessionCreated		(RTSPClientSession* pSession);
    void      SessionSucceeded		(RTSPClientSession* pSession, 
					IHXTCPSocket* pSocket);
    void      SessionFailed		(RTSPClientSession* pSession,
					IHXTCPSocket* pSocket);
    HX_RESULT InitDone			(HX_RESULT status);
    void DoConnectionCheck		();
    void GetForeignHostPort		(char*& pHost, UINT16* pPort);
    void SetSplitterConsumer		(BOOL);
    void EnterPrefetch			(void) { m_bPrefetch = TRUE; };
    void LeavePrefetch			(void);
    void EnterFastStart			(void);
    void LeaveFastStart			(void);
    void InitCloak			(UINT16* pCloakPorts, UINT8 nCloakPorts, IHXValues* pValues);
    UINT16 GetCloakPortSucceeded	(void);
    HX_RESULT SetStatistics		(UINT16 uStreamNumber, STREAM_STATS* pStats);
    BOOL   IsSessionSucceeded()         {return m_bSessionSucceeded;};
    
	    HX_RESULT	InitExt(IUnknown*   pContext,
				const char* pHostName,
				UINT16	    foreignPort,
				IHXRTSPClientProtocolResponse* pClient,
				UINT32	    initializationType,
				IHXValues* pSessionHeaders,
				IHXValues* pInfo,
				BOOL	    bHTTPCloak,
				UINT16	    uCloakPort,
				BOOL	    bNoReuseConnection);

    virtual UINT16	GetRDTFeatureLevel(void){ return 0; };

    friend class RTSPClientSession;

    void ReportError( HX_RESULT theErr );
protected:
    HX_RESULT handleMessage		(RTSPMessage* pMsg);
    HX_RESULT handleTCPData		(BYTE* pData, UINT16 dataLen, UINT16 channel);
    HX_RESULT handleOptionsResponse	(RTSPResponseMessage* pMsg);
    HX_RESULT handleGetParamResponse	(RTSPResponseMessage* pMsg);
    HX_RESULT handleSetParamResponse	(RTSPResponseMessage* pMsg);
    HX_RESULT handleTeardownResponse	(RTSPResponseMessage* pMsg);
    HX_RESULT handlePlayResponse	(RTSPResponseMessage* pMsg,
					RTSPPlayMessage* pPlayMsg);
    HX_RESULT handleRecordResponse	(RTSPResponseMessage* pMsg);
    HX_RESULT handlePauseResponse	(RTSPResponseMessage* pMsg);
    HX_RESULT handleSetupResponse	(RTSPResponseMessage* pMsg,
    					RTSPSetupMessage* pSetupMsg);
    HX_RESULT handleDescribeResponse	(RTSPResponseMessage* pMsg);
    HX_RESULT handleAnnounceResponse	(RTSPResponseMessage* pMsg);
    HX_RESULT HandleRedirectResponse	(RTSPResponseMessage* pMsg);   
    HX_RESULT sendInitialMessage	(RTSPClientSession* pSession,
					IHXTCPSocket* pSocket);
    HX_RESULT addTransportMimeType	(MIMEHeaderValue* pValue,
					UINT16 streamNumber);
    HX_RESULT sendFirstSetupRequest
    (
	IHXValues* pIHXValuesRequestHeaders
    );
    HX_RESULT sendRemainingSetupRequests();
    HX_RESULT sendSetupRequestMessage	
    (
	RTSPStreamInfo* pStreamInfo,
	IHXValues* pIHXValuesRequestHeaders,
	BOOL bFirstSetup
    );
    const char* allowedMethods		();
    void messageDebugFileOut            (const char* pMsg, BOOL bIncoming);
    RTSPTransportRequest* getTransportRequest(MIMEHeaderValue* pValue);
    void reset();
    void clearTransportRequestList	();
    void clearStreamInfoList		();
    void clearUDPResponseHelperList	();
    void clearSocketStreamMap(CHXMapLongToObj*& pSocketStreamMap);
    HX_RESULT getStreamDescriptionMimeType  (char*& pMimeType);
    IHXStreamDescription* 
              getStreamDescriptionInstance(const char* pMimeType);

    HX_RESULT closeSocket		();
    HX_RESULT reopenSocket		();
    HX_RESULT ReopenSocketDone		(HX_RESULT status);

    HX_RESULT sendPendingStreamDescription(const char* pURL,
					   IHXValues* pRequestHeaders);

    // only for [RTP|RDT]/TCP
    void mapTransportChannel		(RTSPTransport* pTran, UINT16 nChannel);

    // Interop - control number could be anything...
    void mapControlToStreamNo		(const char* pControl, UINT16 uStreamNo);
    BOOL getStreamNoFromControl		(const char* pControl, REF(UINT16) uStreamNo);

    void    setSetupRequestURL		(RTSPSetupMessage* pMsg, RTSPStreamInfo* );
    RTSPStreamInfo* getStreamInfoFromSetupRequestURL(const char* pUrl);

    /* interop							       */
    /* since Allow doesn't deal with encoder stuff, just do it here    */
    /* depending on the result, we will use either old or new sdp file */
    SdpFileType     GetSdpFileTypeWeNeed(IHXValues* pHeaders);

    HX_RESULT       GetStreamDescriptionInfo(IUnknown* pUnknown, CHXString& mimeTypes);
    void            SendMsgToTransport(TRANSPORT_MSG msg);
    void            AddCommonHeaderToMsg(RTSPRequestMessage* pMsg);
    HX_RESULT       SendMsgToServer(RTSPMethod msg);

    HX_RESULT extractRealmInformation(RTSPResponseMessage* pMsg);
    HX_RESULT extractExistingAuthorizationInformation(IHXValues* pIHXValuesRequestHeaders);
    void appendAuthorizationHeaders(/*RTSPDescribeMessage*/ RTSPMessage* pMsg);

    HX_RESULT	RetrieveReconnectInfo(MIMEHeader*   pHeader,
				      ReconnectType reconnectType,
				      IHXValues*&  pReconnectValues);

    HX_RESULT	handleAuthentication(RTSPResponseMessage* pMsg);

    HX_RESULT   ParseSDP(const char* pszContentType, IHXBuffer* pSDPBuffer);
    void        RemoveSDPHeaders(void);

#if defined(HELIX_FEATURE_TRANSPORT_MULTICAST)
    BOOL        DetermineIfRMPresentation(IHXValues** ppStrmHeaders,
				          UINT32 ulNumStreams);

    BOOL        GetSubscriptionBW(IHXValues*    pFileHeader, 
			          IHXValues**   ppStrmHeaders,
			          UINT16        unNumStrmHeaders,
			          REF(UINT32*)  pulSubscriptionBW,
			          UINT32        ulNumStreams);					  

    BOOL        GetRightHeaders(REF(IHXValues**)    ppRealHeaders, // out
     			        UINT32		    ulNumStreams,
	     		        IHXValues**	    ppHeaders,
     			        UINT32		    cHeaders,
     			        UINT32*             pulSubscriptionBW);
#endif /* HELIX_FEATURE_TRANSPORT_MULTICAST */

    BOOL        GetStreamCountNoTrust(IHXValues**   ppHeaders, 
				      UINT16        unNumHeader,
				      REF(UINT32)   ulNumStream);

    HX_RESULT   CreateUDPSockets(UINT32 ulStream, UINT16 ulPort);

    virtual BOOL	IsRealServer(void);
    virtual HX_RESULT   RetrieveChallenge(RTSPResponseMessage* pMessage);
    virtual HX_RESULT	sendSetupRequestMessageExt(RTSPStreamInfo* pStreamInfo, 
						   IHXValues*& pIHXValuesRequestHeaders,
						   BOOL bFirstSetup,
						   RTSPSetupMessage*& pMsg);
    virtual HX_RESULT	handleSetupResponseExt(RTSPStreamInfo* pStreamInfo,
					       RTSPResponseMessage* pMsg, 
					       RTSPSetupMessage* pSetupMsg);
    virtual HX_RESULT	DoSendRTTRequest(void);
    virtual HX_RESULT	DoSendBWReport(INT32 aveBandwidth,
				       INT32 packetLoss,
				       INT32 bandwidthWanted);
    void addUAProfHeaders(IHXValues *pHeaders);

    RTSPTransportBuffer* getTransportBuffer(UINT16 uStreamNumber);

    virtual HX_RESULT	sendRequest(RTSPRequestMessage* pMsg, UINT32 seqNo);
    virtual HX_RESULT	sendRequest(RTSPRequestMessage* pMsg,
                                    const char* pContent,
                                    const char* pMimeType, UINT32 seqNo);


    LONG32                              m_lRefCount;
    UINT16				m_foreignPort;
    UINT32				m_foreignAddr;
    UINT32                              m_ulConnectToAddr;
    UINT16				m_setupResponseCount;    
    IHXInterruptState*			m_pInterruptState;
    IHXRTSPClientProtocolResponse*	m_pResp;
    RTSPClientSessionManager*		m_pSessionManager;
    RTSPClientSession*  m_pSession;
    RTSPClientProtocol::State		m_state;
    IHXScheduler*			m_pScheduler;
    IHXValues*				m_pSessionHeaders;
    IHXValues*				m_pCloakValues;
    IHXKeyValueList*			m_pResponseHeaders;
    IHXResolver*			m_pResolver;
    IHXRegistry*			m_pRegistry;

    CHXString				m_versionString;
    CHXString				m_url;
    CHXString				m_contentBase;
    CHXString				m_headerControl;
    CHXString				m_challenge;
    CHXString				m_hostName;
    CHXString				m_proxyHost;
    CHXString                           m_sessionHost;
    UINT16				m_proxyPort;
    UINT16*				m_pCloakPorts;
    UINT8				m_nCloakPorts;
    CHXString				m_sessionID;
    IHXValues*				m_pFileHeader;
    CHXSimpleList			m_streamInfoList;
    CHXSimpleList 			m_transportRequestList;
    CHXSimpleList			m_UDPResponseHelperList;
    CHXSimpleList			m_sessionList;
    CHXMapLongToObj*			m_pTransportStreamMap;	// map streamID->trans
    CHXMapLongToObj*			m_pTransportPortMap;	// map port->trans
    CHXMapLongToObj*			m_pTransportMPortMap;	// map multicast port->trans
    CHXMapLongToObj*			m_pTransportChannelMap; // map channel->trans (only in TCP)
    CHXMapLongToObj*			m_pUDPSocketStreamMap;	// map streamID->socket
    CHXMapLongToObj*			m_pRTCPSocketStreamMap;	// map streamID->socket
    CHXMapStringToOb*			m_pControlToStreamNoMap; // streamID->streamNumber
    BOOL				m_bSeqValueReceived;
    BOOL				m_bSetupRecord;
    BOOL				m_bClientDone;
    BOOL                                m_bMessageDebug;
    BOOL				m_bUseProxy;
    BOOL				m_bUseHTTPProxy;
    BOOL				m_bHTTPOnly;
    BOOL				m_bNoReuseConnection;
    BOOL				m_bLoadTest;
    BOOL				m_bPrefetch;
    BOOL				m_bFastStart;
    BOOL                                m_bPaused;
    BOOL				m_bSessionSucceeded;
    IHXConnectionlessControl*		m_pConnectionlessControl;
    BOOL				m_bConnectionlessControl;
    ConnectionCheckCallback*		m_pConnectionCheckCallback;    
    UINT32				m_uConnectionCheckCallbackHandle;
    BOOL				m_bConnectionAlive;
    UINT32				m_uConnectionTimeout;
    BOOL				m_bEntityRequired;
    UINT16				m_uCloakPort;
    CHXString                           m_messageDebugFileName;
    HXMutex*				m_pMutex;
    UINT16				m_uProtocolType;
    TransportMode			m_currentTransport;

    UINT32				m_ulBufferDepth;
    BOOL				m_bSplitterConsumer;
    RawPacketFilter* 			m_pPacketFilter;

    BOOL				m_bHasSyncMasterStream;

    IHXNetworkServices*		        m_pNetworkServices;
    IHXPreferences*			m_pPreferences;
    IHXBuffer*				m_pUAProfURI;
    IHXBuffer*				m_pUAProfDiff;

    /* Interop */
    
    // TRUE iff a server we are talking is not RS...This implies RTP..
    BOOL				m_bNonRSRTP;
    IHXValues*				m_pSetupRequestHeader;
    BOOL				m_bPlayJustSent;
    BOOL				m_bIPTV;
    BOOL				m_bColumbia;
    BOOL				m_bNoKeepAlive;   
    BOOL				m_bForceUCaseTransportMimeType;
    BOOL				m_bReportedSuccessfulTransport;
    
    BOOL                                m_bSDPInitiated;
    BOOL                                m_bMulticast;
    UINT32                              m_ulMulticastAddress;
    IHXValues*                          m_pSDPFileHeader;
    CHXSimpleList*                      m_pSDPStreamHeaders;

    BOOL				m_pIsMethodSupported[RTSP_TABLE_SIZE];
    static const RTSPTableEntry		zm_pRTSPTable[RTSP_TABLE_SIZE];

    class TimeoutCallback : public IHXCallback
    {
    public:
	TimeoutCallback(RTSPClientProtocol* pOwner);
	~TimeoutCallback();

	STDMETHOD(QueryInterface)	(THIS_
					REFIID riid,
					void** ppvObj);

	STDMETHOD_(ULONG32,AddRef)	(THIS);

	STDMETHOD_(ULONG32,Release)	(THIS);

	STDMETHOD(Func)			(THIS);

    private:
	LONG32			        m_lRefCount;
	RTSPClientProtocol* 	        m_pOwner;
    };


    CHXKeepAlive*                       m_pSessionTimeout;
    TimeoutCallback*                    m_pTimeoutCallback;
    BOOL                                m_bUseLegacyTimeOutMsg;
    BOOL                                m_bKeepAlivePending;
    UINT32                              m_ulServerTimeOut;
    UINT32                              m_ulCurrentTimeOut;

#if defined(_MACINTOSH)
    RTSPClientProtocolCallback*		m_pCallback;
#endif /* _MACINTOSH */
};

#endif /* _RTSPCLNT_H_ */
