| //------------------------------------------------------------------------------ | |
| // File: RefClock.h | |
| // | |
| // Desc: DirectShow base classes - defines the IReferenceClock interface. | |
| // | |
| // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. | |
| //------------------------------------------------------------------------------ | |
| #ifndef __BASEREFCLOCK__ | |
| #define __BASEREFCLOCK__ | |
| #include "Schedule.h" | |
| const UINT RESOLUTION = 1; /* High resolution timer */ | |
| const INT ADVISE_CACHE = 4; /* Default cache size */ | |
| const LONGLONG MAX_TIME = 0x7FFFFFFFFFFFFFFF; /* Maximum LONGLONG value */ | |
| inline LONGLONG WINAPI ConvertToMilliseconds(const REFERENCE_TIME& RT) | |
| { | |
| /* This converts an arbitrary value representing a reference time | |
| into a MILLISECONDS value for use in subsequent system calls */ | |
| return (RT / (UNITS / MILLISECONDS)); | |
| } | |
| /* This class hierarchy will support an IReferenceClock interface so | |
| that an audio card (or other externally driven clock) can update the | |
| system wide clock that everyone uses. | |
| The interface will be pretty thin with probably just one update method | |
| This interface has not yet been defined. | |
| */ | |
| /* This abstract base class implements the IReferenceClock | |
| * interface. Classes that actually provide clock signals (from | |
| * whatever source) have to be derived from this class. | |
| * | |
| * The abstract class provides implementations for: | |
| * CUnknown support | |
| * locking support (CCritSec) | |
| * client advise code (creates a thread) | |
| * | |
| * Question: what can we do about quality? Change the timer | |
| * resolution to lower the system load? Up the priority of the | |
| * timer thread to force more responsive signals? | |
| * | |
| * During class construction we create a worker thread that is destroyed during | |
| * destuction. This thread executes a series of WaitForSingleObject calls, | |
| * waking up when a command is given to the thread or the next wake up point | |
| * is reached. The wakeup points are determined by clients making Advise | |
| * calls. | |
| * | |
| * Each advise call defines a point in time when they wish to be notified. A | |
| * periodic advise is a series of these such events. We maintain a list of | |
| * advise links and calculate when the nearest event notification is due for. | |
| * We then call WaitForSingleObject with a timeout equal to this time. The | |
| * handle we wait on is used by the class to signal that something has changed | |
| * and that we must reschedule the next event. This typically happens when | |
| * someone comes in and asks for an advise link while we are waiting for an | |
| * event to timeout. | |
| * | |
| * While we are modifying the list of advise requests we | |
| * are protected from interference through a critical section. Clients are NOT | |
| * advised through callbacks. One shot clients have an event set, while | |
| * periodic clients have a semaphore released for each event notification. A | |
| * semaphore allows a client to be kept up to date with the number of events | |
| * actually triggered and be assured that they can't miss multiple events being | |
| * set. | |
| * | |
| * Keeping track of advises is taken care of by the CAMSchedule class. | |
| */ | |
| class CBaseReferenceClock | |
| : public CUnknown, public IReferenceClock, public CCritSec, public IReferenceClockTimerControl | |
| { | |
| protected: | |
| virtual ~CBaseReferenceClock(); // Don't let me be created on the stack! | |
| public: | |
| CBaseReferenceClock(__in_opt LPCTSTR pName, | |
| __inout_opt LPUNKNOWN pUnk, | |
| __inout HRESULT *phr, | |
| __inout_opt CAMSchedule * pSched = 0 ); | |
| STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); | |
| DECLARE_IUNKNOWN | |
| /* IReferenceClock methods */ | |
| // Derived classes must implement GetPrivateTime(). All our GetTime | |
| // does is call GetPrivateTime and then check so that time does not | |
| // go backwards. A return code of S_FALSE implies that the internal | |
| // clock has gone backwards and GetTime time has halted until internal | |
| // time has caught up. (Don't know if this will be much use to folk, | |
| // but it seems odd not to use the return code for something useful.) | |
| STDMETHODIMP GetTime(__out REFERENCE_TIME *pTime); | |
| // When this is called, it sets m_rtLastGotTime to the time it returns. | |
| /* Provide standard mechanisms for scheduling events */ | |
| /* Ask for an async notification that a time has elapsed */ | |
| STDMETHODIMP AdviseTime( | |
| REFERENCE_TIME baseTime, // base reference time | |
| REFERENCE_TIME streamTime, // stream offset time | |
| HEVENT hEvent, // advise via this event | |
| __out DWORD_PTR *pdwAdviseCookie// where your cookie goes | |
| ); | |
| /* Ask for an asynchronous periodic notification that a time has elapsed */ | |
| STDMETHODIMP AdvisePeriodic( | |
| REFERENCE_TIME StartTime, // starting at this time | |
| REFERENCE_TIME PeriodTime, // time between notifications | |
| HSEMAPHORE hSemaphore, // advise via a semaphore | |
| __out DWORD_PTR *pdwAdviseCookie// where your cookie goes | |
| ); | |
| /* Cancel a request for notification(s) - if the notification was | |
| * a one shot timer then this function doesn't need to be called | |
| * as the advise is automatically cancelled, however it does no | |
| * harm to explicitly cancel a one-shot advise. It is REQUIRED that | |
| * clients call Unadvise to clear a Periodic advise setting. | |
| */ | |
| STDMETHODIMP Unadvise(DWORD_PTR dwAdviseCookie); | |
| /* Methods for the benefit of derived classes or outer objects */ | |
| // GetPrivateTime() is the REAL clock. GetTime is just a cover for | |
| // it. Derived classes will probably override this method but not | |
| // GetTime() itself. | |
| // The important point about GetPrivateTime() is it's allowed to go | |
| // backwards. Our GetTime() will keep returning the LastGotTime | |
| // until GetPrivateTime() catches up. | |
| virtual REFERENCE_TIME GetPrivateTime(); | |
| /* Provide a method for correcting drift */ | |
| STDMETHODIMP SetTimeDelta( const REFERENCE_TIME& TimeDelta ); | |
| CAMSchedule * GetSchedule() const { return m_pSchedule; } | |
| // IReferenceClockTimerControl methods | |
| // | |
| // Setting a default of 0 disables the default of 1ms | |
| STDMETHODIMP SetDefaultTimerResolution( | |
| REFERENCE_TIME timerResolution // in 100ns | |
| ); | |
| STDMETHODIMP GetDefaultTimerResolution( | |
| __out REFERENCE_TIME* pTimerResolution // in 100ns | |
| ); | |
| private: | |
| REFERENCE_TIME m_rtPrivateTime; // Current best estimate of time | |
| DWORD m_dwPrevSystemTime; // Last vaule we got from timeGetTime | |
| REFERENCE_TIME m_rtLastGotTime; // Last time returned by GetTime | |
| REFERENCE_TIME m_rtNextAdvise; // Time of next advise | |
| UINT m_TimerResolution; | |
| #ifdef PERF | |
| int m_idGetSystemTime; | |
| #endif | |
| // Thread stuff | |
| public: | |
| void TriggerThread() // Wakes thread up. Need to do this if | |
| { // time to next advise needs reevaluating. | |
| EXECUTE_ASSERT(SetEvent(m_pSchedule->GetEvent())); | |
| } | |
| private: | |
| BOOL m_bAbort; // Flag used for thread shutdown | |
| HANDLE m_hThread; // Thread handle | |
| HRESULT AdviseThread(); // Method in which the advise thread runs | |
| static DWORD __stdcall AdviseThreadFunction(__in LPVOID); // Function used to get there | |
| protected: | |
| CAMSchedule * m_pSchedule; | |
| void Restart (IN REFERENCE_TIME rtMinTime = 0I64) ; | |
| }; | |
| #endif | |