csgo-2018-source/engine/demostreamhttp.h

252 lines
7.7 KiB
C
Raw Permalink Normal View History

2021-07-25 12:11:47 +08:00
//========= Copyright (c), Valve Corporation, All rights reserved. ============//
#ifndef HLTV_BROADCAST_PLAYER_HDR
#define HLTV_BROADCAST_PLAYER_HDR
#include "tier1/utlincrementalvector.h"
#include "steam/steam_api.h"
#include "steam/isteamhttp.h"
#include "tier1/utlhashtable.h"
#include "tier1/smartptr.h"
#include "demostream.h"
#include "demofile/gotvhttpstream.h"
struct HTTPRequestCompleted_t;
class CDemoStreamHttp: public IDemoStream
{
public:
CDemoStreamHttp();
void SetClient( IDemoStreamClient *pClient ) { m_pClient = pClient; }
struct SyncParams_t
{
SyncParams_t(int nStartFragment = 0) :m_nStartFragment( nStartFragment ){}
int m_nStartFragment;
void PrintSyncRequest(char *buffer, int nBufSize ) const;
};
void StartStreaming( const char *pUrl, SyncParams_t syncParams = SyncParams_t() );
void StartStreamingCached( const char *pUrl, int nFragment = 1);
bool PrepareForStreaming( const char * pUrl );
void SendSync( int nResync = 0 );
bool OnEngineGotvSyncPacket( const CEngineGotvSyncPacket *pPkt );
void StopStreaming();
bool IsIdle()const { return m_nState == STATE_IDLE; }
void Resync( );
void Update();
virtual const char* GetUrl( void ) OVERRIDE { return m_Url.Get(); }
virtual float GetTicksPerSecond( void )OVERRIDE { return m_SyncResponse.flTicksPerSecond; }
int GetDemoProtocol()const { return m_nDemoProtocol; }
virtual float GetTicksPerFrame( void ) OVERRIDE { return 1.0f; } // 1 network frame per 1 tick in broadcast - there's not much reason to do otherwise
virtual void Close() OVERRIDE { StopStreaming(); }
virtual int GetTotalTicks( void ) { return 0; }
enum FragmentTypeEnum_t
{
//FRAGMENT_START,
FRAGMENT_DELTA,
FRAGMENT_FULL,
FRAGMENT_COUNT
};
static const char *FragmentTypeToString( FragmentTypeEnum_t nType );
static const char *AsString( FragmentTypeEnum_t nType ){ return nType == FRAGMENT_DELTA ? "delta" : "full"; }
struct Buffer_t
{
Buffer_t()
{
m_nRefCount = 0;
m_nSize = 0;
}
static void AddRef( Buffer_t *pObj )
{
pObj->m_nRefCount++;
}
static void Release( Buffer_t *pObj )
{
if ( 0 == --pObj->m_nRefCount )
{
delete[]( uint8* )pObj;
}
}
uint m_nRefCount;
uint m_nSize;
uint8 *Base() { return ( uint8* )( this + 1 ); }
uint8 *End() { return Base() + m_nSize; }
};
typedef CSmartPtr< Buffer_t, Buffer_t > BufferRef;
Buffer_t *GetStreamSignupBuffer() { return m_pStreamSignup.GetObject(); }
Buffer_t *GetFragmentBuffer( int nFragment, FragmentTypeEnum_t nFragmentType );
void RequestFragment( int nFragment, FragmentTypeEnum_t nType );
void ReleaseFragment( int nFragment );
static GotvHttpStreamId_t GetStreamId( const char *pUrl );
float GetBroadcastKeyframeInterval() const { return m_flBroadcastKeyframeInterval; }
IDemoStreamClient::DemoStreamReference_t GetStreamStartReference( bool bLagCompensation = false );
void BeginBuffering( int nFragment );
protected:
struct SyncResponse_t
{
int nStartTick ;
float flKeyframeInterval;
float flRealTimeDelay ;
float flReceiveAge;
int nFragment ;
int nSignupFragment;
float flTicksPerSecond;
double dPlatTimeReceived;
};
bool OnSync( int nResync );
void OnStart( HTTPRequestHandle hRequest );
void OnFragmentRequestSuccess( HTTPRequestHandle hRequest, int nFragment, FragmentTypeEnum_t nType );
void OnFragmentRequestFailure( EHTTPStatusCode nErrorCode, int nFragment, FragmentTypeEnum_t nType );
bool OnSync( const char *pBuffer, int nBufferSize, int nResync );
void RequestDeltaFrame( int nFragment );
protected:
typedef void( CDemoStreamHttp::*FnHttpCallback )( const HTTPRequestCompleted_t * pResponse );
class CPendingRequest : public CCallbackBase
{
public:
CPendingRequest( );
void Init( CDemoStreamHttp *pParent, HTTPRequestHandle hRequest, SteamAPICall_t hCall );
virtual void Run( void *pvParam ) OVERRIDE; // success; HTTPRequestCompleted_t
virtual void Run( void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall ) OVERRIDE; // result; HTTPRequestCompleted_t
void Cancel();
virtual void OnSuccess( const HTTPRequestCompleted_t * pResponse ) = 0;
virtual void OnFailure( const HTTPRequestCompleted_t * pResponse );
public:
int m_nIncrementalVectorIndex;
protected:
~CPendingRequest(); // only this object can delete itself
virtual int GetCallbackSizeBytes() OVERRIDE { return sizeof( HTTPRequestCompleted_t ); }
CDemoStreamHttp *m_pParent;
HTTPRequestHandle m_hRequest;
SteamAPICall_t m_hCall;
};
friend class CPendingRequest;
class CSyncRequest : public CPendingRequest
{
int m_nResync;
SyncParams_t m_SyncParams;
public:
CSyncRequest( SyncParams_t syncParams, int nResync = 0 ) : m_nResync( nResync ), m_SyncParams( syncParams ) { }
virtual void OnSuccess( const HTTPRequestCompleted_t * pResponse ) OVERRIDE;
virtual void OnFailure( const HTTPRequestCompleted_t * pResponse ) OVERRIDE;
};
class CStartRequest : public CPendingRequest
{
public:
virtual void OnSuccess( const HTTPRequestCompleted_t * pResponse ) OVERRIDE;
//virtual void OnFailure( const HTTPRequestCompleted_t * pResponse ) OVERRIDE;
};
class CFragmentRequest : public CPendingRequest
{
int m_nFragment;
FragmentTypeEnum_t m_nType;
public:
CFragmentRequest( int nFragment , FragmentTypeEnum_t nType ) : m_nFragment( nFragment ), m_nType ( nType ){}
virtual void OnSuccess( const HTTPRequestCompleted_t * pResponse ) OVERRIDE;
virtual void OnFailure( const HTTPRequestCompleted_t * pResponse ) OVERRIDE;
};
enum StateEnum_t
{
STATE_IDLE,
STATE_SYNC,
STATE_RANDOM_WAIT_AND_SYNC,
STATE_START,
STATE_STREAMING
};
static Buffer_t *MakeBuffer( HTTPRequestHandle hRequest ); // returns a buffer with 0 refcount
struct Fragment_t
{
protected:
Buffer_t *m_pField[ FRAGMENT_COUNT ];
uint m_nStreaming;
public:
Fragment_t()
{
for ( int i = 0; i < FRAGMENT_COUNT; ++i )
m_pField[ i ] = NULL;
m_nStreaming = 0;
}
void ResetBuffers();
//const uint8 *Start() const { return pField[ FRAGMENT_START ] ? pField[ FRAGMENT_START ]->Base() : NULL; }
//uint StartSize()const { return pField[ FRAGMENT_START ] ? pField[ FRAGMENT_START ]->nSize : 0; }
void SetField( FragmentTypeEnum_t nFragment, Buffer_t *pBuffer );
Buffer_t *GetField( FragmentTypeEnum_t nFragment ) { return m_pField[ nFragment ]; }
const uint8 *Delta() const { return m_pField[ FRAGMENT_DELTA ] ? m_pField[ FRAGMENT_DELTA ]->Base() : NULL; }
uint DeltaSize()const { return m_pField[ FRAGMENT_DELTA ] ? m_pField[ FRAGMENT_DELTA ]->m_nSize : 0; }
const uint8 *Full() const { return m_pField[ FRAGMENT_FULL ] ? m_pField[ FRAGMENT_FULL ]->Base() : NULL; }
uint FullSize()const { return m_pField[ FRAGMENT_FULL ] ? m_pField[ FRAGMENT_FULL ]->m_nSize : 0; }
uint IsStreaming( FragmentTypeEnum_t nType ){ return ( m_nStreaming >> nType ) & 1; }
void SetStreaming( FragmentTypeEnum_t nType ){ m_nStreaming |= ( 1 << nType ); }
void ClearStreaming( FragmentTypeEnum_t nType ){ m_nStreaming &= ~( 1 << nType ); }
};
protected:
void SendGet( const char *pPath, CPendingRequest *pRequest );
Fragment_t &Fragment( int nFragment );
protected:
CUtlString m_Url;
bool m_bSyncFromGc;
CUtlIncrementalVector< CPendingRequest > m_PendingRequests;
StateEnum_t m_nState;
BufferRef m_pStreamSignup;
int m_nStreamSignupFragment; // the fragment where the signup/start fragment starts
int m_nDemoProtocol;
IDemoStreamClient *m_pClient;
CUtlHashtable< int, Fragment_t, IdentityHashFunctor > m_FragmentCache; // TODO: implement freeing old buffers
// STATE_SYNC : when to stop streaming
// STATE_RANDOM_WAIT_AND_SYNC: when to retry sync
double m_dSyncTimeoutEnd;
SyncParams_t m_SyncParams;
SyncResponse_t m_SyncResponse;
float m_flBroadcastKeyframeInterval;
//int m_nFragment;
};
#endif // HLTV_BROADCAST_PLAYER_HDR