/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: ppffsrc.h,v 1.1.1.1.38.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 _PPFFSRC_H_
#define _PPFFSRC_H_

#include "ntptime.h"
#include "hxmon.h" // IHXRegistry
#include "ppffstrm.h"

#define DISTRIBUTE_SYNC		0
#define DISTRIBUTE_SYNCANCHOR	1
#define DISTRIBUTE_STARTTIME	2

enum PortType
{
    RTP_PORT    = 1,
    RTCP_PORT   = 2
};

const UINT8 RTP_VERSION = 2;

/****** Classes ***********************************************************/

class CPurePlayFileFormat;
class ReceptionReport;
class CRTCPInterval;


/****************************************************************************
 *
 *  CPurePlaySource Class
 *
 *  Handles I/O and stream data
 */
#define PP_DEPEND_END			0xFFFF

class CPurePlaySource : public IHXResolverResponse
{
private:	
    class CRTPResponseHandler : public IHXUDPResponse
    {
    	~CRTPResponseHandler() {}
    	PRIVATE_DESTRUCTORS_ARE_NOT_A_CRIME       // Avoids GCC warning
    	
    public:
    	CRTPResponseHandler(CPurePlaySource* pParent, PortType portType)
	    : m_lRefCount(0)
	    , m_pStream(pParent)
	    , m_portType(portType)
    	    { /* Don't AddRef pStream, private class */ }
    	
    	/*******************************************************************
    	*  IUnknown COM Interface Methods                      ref:  hxcom.h
    	*/
    	STDMETHOD (QueryInterface ) (THIS_ REFIID ID, void** ppInterfaceObj);
    	STDMETHOD_(UINT32, AddRef ) (THIS);
    	STDMETHOD_(UINT32, Release) (THIS);
    
    	/*
     	*	IHXUDPPResponse methods
     	*/
    
    	STDMETHOD(ReadDone)	(THIS_
			    	HX_RESULT	status,
			    	IHXBuffer*	pBuffer,
			    	ULONG32		ulAddr,
			    	UINT16		nPort);
    
    private:
    	INT32			m_lRefCount;
    	CPurePlaySource*	m_pStream;
    	PortType		m_portType;
    };
    
    class RuleInfo
    {
    public:
	RuleInfo();
	~RuleInfo();

	BOOL			m_bRuleOn;
	BOOL			m_bSyncOK;
	BOOL			m_bRecvOn;
	UINT16*			m_pOnDepends;
    };

    class CRTCPSendStatusCallback : public IHXCallback
    {
	~CRTCPSendStatusCallback();
	PRIVATE_DESTRUCTORS_ARE_NOT_A_CRIME
	
    public:
	CRTCPSendStatusCallback(CPurePlaySource* pParent, int lEvent)
	    : m_lRefCount(0)
	    , m_pStream(pParent)
	    , m_lEvent(lEvent)
	    {}
	    

    	/*******************************************************************
    	*  IUnknown COM Interface Methods                      ref:  hxcom.h
    	*/
    	STDMETHOD (QueryInterface ) (THIS_ REFIID ID, void** ppInterfaceObj);
    	STDMETHOD_(UINT32, AddRef ) (THIS);
    	STDMETHOD_(UINT32, Release) (THIS);
    
    	/*
     	 *	IHXCallback methods
     	 */
    
    	STDMETHOD(Func)		(THIS_);

    private:
	INT32			m_lRefCount;
	CPurePlaySource*	m_pStream;
	int			m_lEvent;
    };

public:
    CPurePlaySource( CPurePlayFileFormat* pPlugin,
		IHXValues* pHeader,
    		UINT16 iStream,
    		UINT32 ulRTPFactor,
    		UINT32 ulHXFactor,
		BOOL bIsRMSource);    
    ~CPurePlaySource();

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

    STDMETHOD_(ULONG32,AddRef)	(THIS);

    STDMETHOD_(ULONG32,Release)	(THIS);


    /************************************************************************
     *  IHXResolverResponse Interface Methods               ref:  hxengin.h
     */
    STDMETHOD(GetHostByNameDone)	(THIS_
					HX_RESULT status,
					ULONG32 ulAddr);

    HX_RESULT   Init		(IUnknown* pContext,
    				const char* pMultiAddr,
    				UINT32 ulInterfaceAddr,
    				UINT16 ulMultiPort);

    void	Cleanup		(void);    				
    HX_RESULT	Close		(void);
    			    
    void	Begin		(void);
    			    
    void	GetHeader	(REF(IHXValues*) pHeader, UINT16 unStreamNumber);
    HX_RESULT	UpdateStatistics(IHXRegistry* pReg, ULONG32 ulTimeNow);

    inline static HX_RESULT DistributeToStream(CStream* pStream,
					       ULONG32 ulDistributionMode,
					       ULONG32 ulVal1,
					       ULONG32 ulVal2);
    HX_RESULT Distribute(ULONG32 ulDistributionMode,
			 ULONG32 ulVal1,
			 ULONG32 ulVal2);

    inline BOOL	IsRMSource(void);
    inline BOOL IsEncryptedSource(void)	{ return m_bIsEncryptedSource; }
    inline CStream::StreamType GetStreamType(void)
    {
	return m_StreamType;
    }
    BOOL	IsDependOK	(BOOL bOn, UINT16 uRule);
    BOOL	AreDependenciesOK(UINT16 uRule);
    void	SetSyncOK	(UINT16 uRule, BOOL bOK = TRUE);
    void	RecvRule	(BOOL bOn, UINT16 uRule);

    HX_RESULT	HandleRTPMsg	(HX_RESULT status, IHXBuffer* pBuf);
    HX_RESULT	HandleRTCPMsg	(HX_RESULT status, IHXBuffer* pBuf);

    void	Schedule(UINT32 ulNextTime, int lEvent);    
    void	OnExpire(INT32 lEvent);
    UINT32	SendRecvReport	(void);
    BOOL	ScheduleBye(void);
    BOOL	MakeBye(REF(IHXBuffer*) pPkt);
    void	SendBye (void);

    BOOL	GetStreamBySSRC(UINT32 ulSsrc, CStream*& pStrm);
    BOOL	GetMember(UINT32 ulSsrc, CMember*& pMember);
    CStream*	GetStreamByStrmId(UINT32 ulId);
    BOOL	RemoveSource(UINT32 ulSsrc);
    BOOL	RemoveMember(UINT32 ulSsrc, BOOL bRemoveFromBin = TRUE);
    BOOL	AddNewEntryToMap(UINT32 ulSsrc, CStream*& pStrm);
    BOOL	AddNewMember(UINT32 ulSsrc, CMember*& pMember);
    BOOL	MarkAsEnd(UINT32 ulSsrc);
    UINT16	SetBaseStreamNum(UINT16 unBaseStreamNum);

    void	CleanupMemberTable(void);
    
    HX_RESULT   StopBuffering();
    HX_RESULT   MakeRR(REF(RTCPPacket) pktRR);
    HX_RESULT   MakeSsrc();

    inline BOOL	  SetPendingFlag(UINT16 unStreamNumber, BOOL bFlag);
    inline BOOL   GetPendingFlag(UINT16 unStreamNumber);

    // We need to keep track of two diff. number of sources
    // 1: #sources that made the FileHeaderTimeOut only
    // 2: #sources that incluldes #sources that did not make the cut! 
    //	  (We received them too late)
    inline UINT32 GetNumSrc(void) { return m_StrmIdToStrm.GetCount(); }
    inline UINT32 GetTrueNumSrc(void) { return m_SsrcToStream.GetCount(); }
    inline UINT32 GetStartedSourceCount(void) { return m_ulStartedSourceCount; }
    
    inline UINT32 GetBandwidth(void) { return m_ulBandwidth; }

    inline BOOL   IsTimeStampDelivery() { return m_bTimeStampDelivery; }
public:
#ifdef XXXGo_DEBUG
    FILE*   m_pLogFile;
    FILE*   m_pFFLog;
#endif

    UINT16		    m_iStream;
    BOOL		    m_bIsRMSource;
    BOOL		    m_bIsEncryptedSource;
    BOOL		    m_bInitialPacket;
    INT8		    m_chRTPPayload;
    INT32		    m_lHXOffset;
    UINT32		    m_ulLost;
    UINT32		    m_ulClipBandwidthID;
    const UINT32	    m_ulRTPFactor;
    const UINT32	    m_ulHXFactor;
    CallbackHandle	    m_hStatusCallbackID;
    UINT32		    m_ulBeginClockTick;
private:
    INT32		    m_lRefCount;
    CPurePlayFileFormat*    m_pPlugin;
    IHXValues*		    m_pHeader;
    IHXNetworkServices*    m_pNet;
    IHXResolver*	    m_pResolver;
    IHXScheduler*	    m_pScheduler;
    
    IHXUDPSocket*	    m_pRTPSock;
    IHXUDPSocket*	    m_pRTCPSock;

    CRTPResponseHandler*    m_pRTPResp;
    CRTPResponseHandler*    m_pRTCPResp;

    RuleInfo*		    m_pRules;
    UINT16		    m_cRules;

    UINT32		    m_ulMultiAddr;
    UINT16		    m_uMultiPort;
    UINT8		    m_chTTL;
    UINT32		    m_ulInterfaceAddr;
    
    BOOL		    m_bBeginPending;
    
    UINT32		    m_ulBandwidth;
    ULONG32		    m_ulStartedSourceCount;

    UINT32		    m_ulThisSrcID;
    CRTCPInterval* 	    m_pRTCPInterval;

    BOOL		    m_bTimeStampDelivery;
    IHXBuffer*		    m_pCName;
    IHXBuffer*		    m_pName;
    IHXBuffer*		    m_pTool;
    IHXBuffer*		    m_pEmail;

    CStream::StreamType	    m_StreamType;

    /*
    **	m_SsrcToStream:
    **	  - senders in RTP session
    **	  - entry will be added when we receive a pkt w/ unknown SSRC
    **	  - entry will be removed when BYE is received for that entry
    **	  
    **	m_StrmIdToStrm:
    **	  - streams in client core
    **	  - ones that made the FileHeaderTimeOut cut
    **	  - never add another stream once FileHeaderTimeout cut is reached
    **	  - entry will be removed when corresponding senders in m_SsrdToStream receives a 
    **	    BYE msg and this stream is not RA
    */

    CHXMapLongToObj	    m_SsrcToStream;
    CHXMapLongToObj	    m_StrmIdToStrm;
    CHXMapLongToObj	    m_SsrcToMember;

    CTimeoutBin		    m_MemberTimeoutBins;
    BOOL		    m_bClosed;
   
    enum ALGORITHM
    {
	ALGORITHM_A,
	ALGORITHM_B,
	ALGORITHM_C
    } m_algorithm;

    // Sync tracking
    ULONG32 m_ulHXMasterTime;
    ULONG32 m_lHXOffsetToMaster ;
    BOOL m_bSyncDistributed;
    ULONG32 m_ulHXAnchorTime;
    ULONG32 m_ulNTPHXTime;
    BOOL m_bSyncAnchorDistributed;
    ULONG32 m_ulStartTime;
    BOOL m_bStartTimeDistributed;

    // if this is not NULL, BYE pkt is pending
    IHXBuffer*		    m_pByePkt;

    BOOL		    m_bRTCPSent;
};


/****************************************************************************************
 *	Inline functions
 */
HX_RESULT 
CPurePlaySource::DistributeToStream(CStream* pStream,
				    ULONG32 ulDistributionMode,
				    ULONG32 ulVal1,
				    ULONG32 ulVal2)
{
    HX_RESULT retVal = HXR_UNEXPECTED;

    if (pStream)
    {
	switch (ulDistributionMode)
	{
	case DISTRIBUTE_SYNC:
	    retVal = pStream->m_Syncer.HandleMasterSync(ulVal1, 
						        ((LONG32) ulVal2));
	    break;
	    
	case DISTRIBUTE_SYNCANCHOR:
	    retVal = pStream->m_Syncer.AnchorSync(ulVal1, 
						  ulVal2);
	    break;
	    
	case DISTRIBUTE_STARTTIME:
	    retVal = pStream->m_Syncer.SetStartTime(ulVal1, TRUE);
	    break;
	    
	default:
	    // nothing to do
	    break;
	}
    }

    return retVal;
}

inline BOOL
CPurePlaySource::IsRMSource()
{
    return m_bIsRMSource;
}

inline BOOL
CPurePlaySource::SetPendingFlag(UINT16 unStreamNumber, BOOL bFlag)
{
    CStream* pStrm = NULL;
    if (m_StrmIdToStrm.Lookup(unStreamNumber, (void*&)pStrm))
    {   	
    	pStrm->SetPendingFlag(bFlag);
   	return TRUE;
    }
    else
    {
	// not in the map
    	return FALSE;
    }
}

inline BOOL
CPurePlaySource::GetPendingFlag(UINT16 unStreamNumber)
{
    CStream* pStrm = NULL;
    if (m_StrmIdToStrm.Lookup(unStreamNumber, (void*&)pStrm))
    {
	return pStrm->m_bPending;
    }
    else
    {
//    	HX_ASSERT(FALSE && "Map is not ready\n");
    	return FALSE;
    }
    
}

#endif	// _PPFFSRC_H_


