/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: ppffplin.h,v 1.2.36.1 2004/07/19 21:04:16 hubbe 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 _PPLYPLIN_H_
#define _PPLYPLIN_H_

#include "hxengin.h"
#include "hxplugn.h"	// IHXPlugin
#include "hxformt.h"   // IHXFileFormatObject
#include "hxfiles.h"   // IHXFile objects
#include "hxmap.h"	// CHXMapStringToOb
#include "hxstrutl.h"	// new_string()
#include "hxslist.h"	// CHXSimpleList
#include "hxsdesc.h"   // IHXStreamDescription
#include "hxpends.h"	// IHXPendingStatus
#include "hxasm.h"	// IHXASMSource
#include "carray.h"	// CHXPtrArray
#include "ntptime.h"	// NTPTime
#include "hxcore.h"	// IHXPlayer
#include "hxfwrtr.h"	// IHXPropertyAdviser
#include "rtspif.h"

// #define XXXGo_DEBUG
#define BW_BASED

// XXXGH was 10000
#define PP_SYNC_TIMEOUT_MS		6000
#define PP_RM_TIMEOUT_MS		100

#define DEFAULT_TTL			127

#define PROP_MULTI_ADDRESS		"MulticastAddress"
#define DEFAULT_MULTI_ADDRESS		0xEA050607 // XXXST Registry? UI?

#define PROP_MULTI_TTL			"MulticastTTL"
#define DEFAULT_MULTI_TTL		127

#define PROP_MULTI_PORT			"Port"
#define DEFAULT_MULTI_PORT		5050

#define PROP_MULTI_RANGE		"MulticastRange"

#define PROP_RTP_PAYLOAD		"RTPPayloadType"
#define PROP_RTP_FACTOR			"RTPTimestampConversionFactor"
#define PROP_HX_FACTOR			"HXTimestampConversionFactor"
#define PROP_MIMETYPE			"MimeType"

#define REG_CNAME			"RTCPCanonicalName"
#define REG_USERNAME			"RTCPUserName"
#define REG_EMAIL			"RTCPEmailName"
#define REG_TOOL			"RTCPToolName"
#define REG_TTL				"RTCPTimeToLive"

// XXXST Move to cross platform resource
#define DEFAULT_USERNAME		"RealNetworks User"
#define DEFAULT_TOOL			"RealNetworks Scalable Multicast Plugin"

#define NO_EXIST			-1

// return TRUE iff TS1 <= TS2, taking care of rollover...
#define IS_TS1_LESS_THAN_EQUAL_TS2(ts1, ts2) (((LONG32) (ts2 - ts1)) >= 0)

#define READ_SIZE 65536

enum PurePlayFFState
{
    Init,
    InitHeader,
    Closed,
    Ready,
    PendingFileHeader,
    PendingRecvPacket,
    PendingSeek
};

enum TryUnicast
{
    NO_TRY,
    TIMEOUT,
    SOCKET_FAIL,
    NO_MULTICAST
};

class	STREAM_STATS;
class	CPurePlaySource;
class	CStream;

/****************************************************************************
 *
 *  CPurePlayFileFormat Class
 *
 *  An IHXPacketSink multicast redirecter that provides virtual SDP 
 *  descriptions
 */
class CPurePlayFileFormat : public IHXPlugin,
			    public IHXFileFormatObject, 
			    public IHXFileResponse,
			    public IHXASMSource,
			    public IHXPendingStatus,
			    public IHXPropertyAdviser,
			    public IHXTransportSyncServer
{

    /****** Private Class Methods ******************************************/
    ~CPurePlayFileFormat();

    PRIVATE_DESTRUCTORS_ARE_NOT_A_CRIME       // Avoids GCC compiler warning

public:
    /****** Public Class Methods ******************************************/
    CPurePlayFileFormat();

    //inline BOOL GetNtpStartTime(NTPTime& ntp);
    //inline BOOL GetStartRmaTime(UINT32& ulTime);
				
    // *** IUnknown methods ***
    STDMETHOD(QueryInterface)	(THIS_
				REFIID riid,
				void** ppvObj);

    STDMETHOD_(ULONG32,AddRef)	(THIS);

    STDMETHOD_(ULONG32,Release)	(THIS);


    /************************************************************************
     *  IHXFileFormatObject Interface Methods               ref:  hxformt.h
     */
    STDMETHOD(GetFileFormatInfo)
	(THIS_
	 REF(const char**) pFileMimeTypes,
	 REF(const char**) pFileExtensions,
	 REF(const char**) pFileOpenNames
	);

    STDMETHOD(InitFileFormat)
	(THIS_
	 IHXRequest*        pRequest,
	 IHXFormatResponse* pFormatResponse,
	 IHXFileObject*     pFileObject
	);

    STDMETHOD(GetFileHeader  ) (THIS);
    STDMETHOD(GetStreamHeader) (THIS_ UINT16 streamNo);
    STDMETHOD(GetPacket      ) (THIS_ UINT16 streamNo);
    STDMETHOD(Seek           ) (THIS_ UINT32 requestedTime);
    STDMETHOD(Close          ) (THIS);


    /************************************************************************
    *  IHXFileResponse Interface Methods                   ref:  hxfiles.h
    */
    STDMETHOD(InitDone ) (THIS_ HX_RESULT status);
    STDMETHOD(SeekDone ) (THIS_ HX_RESULT status);
    STDMETHOD(ReadDone ) (THIS_ HX_RESULT status, IHXBuffer* pBuffer);
    STDMETHOD(WriteDone) (THIS_ HX_RESULT status);
    STDMETHOD(CloseDone) (THIS_ HX_RESULT status);

    /************************************************************************
     *  IHXASMSource Interface Methods                        ref:  hxasm.h
     */
    STDMETHOD (Subscribe)   (THIS_ UINT16 uStreamNumber, UINT16 uRuleNumber);
    STDMETHOD (Unsubscribe) (THIS_ UINT16 uStreamNumber, UINT16	uRuleNumber);


    /************************************************************************
     *  IHXPlugin Interface Methods                         ref:  hxplugn.h
     */
    STDMETHOD(GetPluginInfo)
	(THIS_ 
	 REF(BOOL)        bLoadMultiple,
	 REF(const char*) pDescription,
	 REF(const char*) pCopyright,
	 REF(const char*) pMoreInfoURL,
	 REF(UINT32)      versionNumber
	);
    STDMETHOD(InitPlugin) (THIS_ IUnknown* pHXCore);

    /************************************************************************
     *  IHXPendingStatus Interface Methods                  ref:  hxpends.h
     */
    STDMETHOD(GetStatus)	(THIS_
				REF(UINT16) uStatusCode, 
				REF(IHXBuffer*) pStatusDesc, 
				REF(UINT16) ulPercentDone);


    HX_RESULT ProcessPendingPackets(BOOL bUseAutoTime = TRUE,
									ULONG32 ulTimeNow = 0);
    HX_RESULT StreamDone	    (HX_RESULT status, UINT16 iStream);

    HX_RESULT GetCName		(REF(IHXBuffer*) pCName);
    HX_RESULT GetUserName	(REF(IHXBuffer*) pUserName);
    HX_RESULT GetTool		(REF(IHXBuffer*) pTool);
    HX_RESULT GetEmailName	(REF(IHXBuffer*) pEmail);


    /************************************************************************
     *  IHXPropertyAdviser Interface Methods		    ref:  hxfwrtr.h
     */
    STDMETHOD(GetPropertyULONG32)	(THIS_
					const char*      pPropertyName,
					REF(ULONG32)     ulPropertyValue
					);
    
    STDMETHOD(GetPropertyBuffer)	(THIS_
					const char*      pPropertyName,
					REF(IHXBuffer*) pPropertyValue
					);

    STDMETHOD(GetPropertyCString)	(THIS_
					const char*      pPropertyName,
					REF(IHXBuffer*) pPropertyValue
					);

    STDMETHOD(GetPropertySet)		(THIS_
					const char*	 pPropertySetName,
					REF(IHXValues*) pPropertySet
					);

    /************************************************************************
     *  IHXTransportSyncServer methods		    ref:  rtspif.h
     */
    STDMETHOD(DistributeSyncAnchor) (THIS_
				    ULONG32 ulHXTime, 
				    ULONG32 ulNTPTime);

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

    STDMETHOD(DistributeStartTime)  (ULONG32 ulHXRefTime);
    
private:
    /****** Private Methods ************************************************/
    
    HX_RESULT GetSocket     (UINT32 ulAddr, UINT16 uPort, UINT16 iStream, 
			    REF(IHXUDPSocket*) pSock, 
			    REF(IHXUDPResponse*) pResp,
			    REF(BOOL) bNewSocket);
			    
    HX_RESULT HandleRTPMsg	    (HX_RESULT status, IHXBuffer* pBuf, UINT16 iStream);
    HX_RESULT HandleRTCPMsg	    (HX_RESULT status, IHXBuffer* pBuf, UINT16 iStream);

    HX_RESULT SyncStreams	    (void);

    HX_RESULT ProcessFileHeaderCallback(void);
    BOOL      IsFileHeaderReady(CHXPtrArray* prgStreams, REF(UINT32) ulTimeoutVal);
    UINT32    AssignStreamNumbers(UINT32 ulNumInterfacesReady,
	CHXPtrArray** ppInterfacesReady);

    HX_RESULT SwitchToUnicast	    (void);
    BOOL      GetSourceObj(REF(CPurePlaySource*)pSrc, UINT32 i);
    BOOL      GetStreamObj(REF(CStream*)pStrm, UINT32 i);

    HX_RESULT Distribute(ULONG32 ulDistributionMode,
			 ULONG32 ulVal1, 
			 ULONG32 ulVal2 = 0);

    // for stats
    void      statistics_cat	    (char* pStats, UINT32 ulStatsBufLen, LONG32 lData);
    BOOL      GetRAStreamNum	    (REF(UINT32) ulRAStreamNum);
    BOOL      SendStatistics	    (void);

    HX_RESULT BeginPost		    (CHAR* pszStats);

private:
    /****** Private Class Variables ****************************************/
    INT32			m_lRefCount;
    IUnknown*			m_pContext;
    IHXStreamDescription*	m_pStreamDesc;
    IHXRTPPayloadInfo*		m_pRTPInfo;
    IHXErrorMessages*		m_pLog;
    IHXScheduler*		m_pScheduler;
    IHXRegistry*		m_pRegistry;
    IHXCommonClassFactory*	m_pClassFactory;


    /*
    *	needed for switching to unicast
    */
public:    
    TryUnicast			m_tryUnicast;
    CHXString			m_strLastErr;

private:
    IHXFileObject*		m_pFileObject;
    CHXSimpleList*              m_pFileBufferList;
    IHXBuffer*			m_pSDPDesc;
    
    IHXValues*			m_pFileHeader;

    CHXPtrArray			m_rgStreams;
    CStream*			m_pMasterSyncStream;

    IHXFormatResponse*		m_pFFResponse;

    //PurePlayFFState		m_state;

    BOOL			m_bInitialPacket;

    UINT16			m_uActiveStreams;
    CallbackHandle		m_hFileHeader;
    ULONG32			m_ulFileHeaderWaitStartTime;
    ULONG32			m_ulListeningWaitStartTime;
    BOOL			m_bOneMoreTry;

    // this time out value is taken from the player preference    
    UINT32			m_ulServerTimeout;
    // this is teaken from SDP if present, otherwise it is assigned the
    // same value as m_ulServerTimeout
    UINT32			m_ulFailoverTimeout;
    
    UINT16			m_uStatusCode;
    IHXBuffer*			m_pStatusDesc;

    IHXBuffer*			m_pCName;
    IHXBuffer*			m_pUserName;
    IHXBuffer*			m_pTool;
    IHXBuffer*			m_pEmail;
    
    BOOL			m_bSourceAdmissionClosed;

    BOOL			m_bRMPresentation;
    BOOL			m_bDisableOffsetting;
    INT32 			m_lSmallestTSStrm;
    ULONG32			m_ulSmallestTS;

    ULONG32			m_ulHXOffset;

    ULONG32			m_ulStartTimeMS;
    UINT32			m_ulFirstTSSent;
    BOOL			m_bFirstPktSent;
	BOOL			m_bFirstPktRcvd;
    
    IHXRequest*		m_pRequest;    

    INT32			m_lRAStreamNum;
    BOOL			m_bWantClientStats;

    BOOL			m_bAttempMulticast;

    CHXPtrArray**		m_ppInterfacesReady;
    ULONG32			m_ulNumInterfacesReady;

    /*
     *	class to deal with multiple NICs.  Will be deleted as soon as 
     *  we decide a NIC to use...
     */
    class InterfaceManager
    {
    public:
	InterfaceManager(UINT32 ulNumInterfaces);
	~InterfaceManager();

	/* set it in Host byte order */
	void SetInterface(UINT32 ulInterfaceNo, UINT32 ulInterface);
	CHXPtrArray* GetSession(UINT32 ulInterfaceNo);
	void SetSession(UINT32 ulInterfaceNo, CHXPtrArray* pSession);
	
	UINT32		m_ulNumInterfaces;
	UINT32*		m_pulInterfaces;

	// holds an CHXPtrArray*s of CPurePlaySource*s
	CHXPtrArray	m_rgInterfaceSessions;
    };    

    InterfaceManager*		m_pInterfaceMgr;
    
    // for stats
    static const char*		zm_pRegistryEntryies[];    
           
#ifdef BW_BASED
    INT32			m_lRuleNumber;
#endif    

#ifdef _DEBUG
    BOOL			m_bFileHeaderReadyCalled;
#endif    

#ifdef XXXGo_DEBUG
    FILE*			m_file;
#endif
public:
	PurePlayFFState		m_state;
public:
    /****** Public functions************************************************/
    HX_RESULT	GetLogger(REF(IHXErrorMessages*) pLog);
    BOOL        IsSourceAdmissionClosed() { return m_bSourceAdmissionClosed; }
    inline	PurePlayFFState GetCurrentState(void);
    
    BOOL   	IsRMPresentation(void) { return m_bRMPresentation; }
    BOOL	IsRAStream(UINT32 ulStrmNum);
    BOOL	WantClientStats() { return m_bWantClientStats; }

    void	SetMasterSyncStream(CStream* pSyncStream)
    {
	m_pMasterSyncStream = pSyncStream;
    }

    CStream*	GetMasterSyncStream(void) 
    { 
	return m_pMasterSyncStream; 
    }

    BOOL	HasMasterSyncStream(void) 
    { 
	return (m_pMasterSyncStream != NULL); 
    }
    
    // error reporting
    void      ReportError	    (UINT32 ulErrID, const UINT8 chSeverity, HX_RESULT ulHXCode);
    void      ReportErrorWithFormat (UINT32 ulErrID, REF(CHXString) strText, const UINT8 chSeverity, HX_RESULT ulHXCode);


private:
    HX_RESULT	MakeHeader(HX_RESULT status);

    BOOL    GetStreamCountNoTrust(IHXValues** ppHeaders, 
				  UINT16 unNumHeader,
				  REF(ULONG32) ulNumStream);
    BOOL    DetermineIfRMPresentation(IHXValues* pFileHeader,
				      IHXValues** ppStrmHeaders,
				      ULONG32 ulNumStreams);
    BOOL    GetSubscriptionBW(IHXValues* pFileHeader, 
			      IHXValues** ppStrmHeaders,
			      UINT16 unNumStrmHeaders,
			      REF(UINT32*) pulSubscriptionBW,
			      UINT32 ulNumStreams,
			      IHXBuffer* pBandwidth);					  

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

    // error reporting
    HX_RESULT GetResourceErrorString(UINT32 ulErrID, REF(CHXString) strErr);
    void      GetDefaultErrorString(UINT32 ulErrID, REF(CHXString) strErr);
    void      ClearFileBufferList();
    HX_RESULT AggregateBuffers(REF(IHXBuffer*) rpBuffer);

private:
    /**************************************************************************
    * Callback to figure out the number of streams
    */
    class CFileHeaderCallback : public IHXCallback
    {
    public:
	CFileHeaderCallback(CPurePlayFileFormat* pFF);
	~CFileHeaderCallback();

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

	STDMETHOD_(ULONG32,AddRef)	(THIS);

	STDMETHOD_(ULONG32,Release)	(THIS);

	STDMETHOD(Func)			(THIS);

    private:
	INT32			    m_lRefCount;
	CPurePlayFileFormat*	    m_pFF;
    };
    friend class CFileHeaderCallback;


    friend class CPurePlaySource;
private:
    /****** Private Static Class Variables *********************************/
    static const char*		zm_pDescription;
    static const char*		zm_pCopyright;
    static const char*		zm_pMoreInfoURL;
    static const char*		zm_pFileMimeTypes[];
    static const char*		zm_pFileExtensions[];
    static const char*		zm_pFileOpenNames[];
};

_INTERFACE IHXHyperNavigate;

class CUnicastCallback: public IHXCallback
{
public:
    CUnicastCallback(IHXScheduler* pScheduler, 
		     IHXPlayer* pPlayer, 
		     IHXHyperNavigate* pHyperNavigate,
		     const char* pURL);
    ~CUnicastCallback();

    // *** IUnknown methods ***
    STDMETHOD(QueryInterface)	(THIS_
				 REFIID riid,
				 void** ppvObj);
    
    STDMETHOD_(ULONG32,AddRef)	(THIS);
    
    STDMETHOD_(ULONG32,Release)	(THIS);
    
    STDMETHOD(Func)		(THIS);
    
private:
    INT32			m_lRefCount;
    IHXScheduler*		m_pScheduler;
    IHXPlayer*			m_pPlayer;
    IHXHyperNavigate*		m_pHyperNavigate;
    CHXString			m_strURL;
};

#endif // ndef _PPLYPLIN_H_

