00001
00002
00003
00004
00005
00006 #include <streams.h>
00007 #include <limits.h>
00008
00009 #pragma warning(disable:4355)
00010
00011 STDMETHODIMP CBaseReferenceClock::NonDelegatingQueryInterface(
00012 REFIID riid,
00013 void ** ppv)
00014 {
00015 HRESULT hr;
00016
00017 if (riid == IID_IReferenceClock)
00018 {
00019 hr = GetInterface((IReferenceClock *) this, ppv);
00020 }
00021 else
00022 {
00023 hr = CUnknown::NonDelegatingQueryInterface(riid, ppv);
00024 }
00025 return hr;
00026 }
00027
00028 CBaseReferenceClock::~CBaseReferenceClock()
00029 {
00030
00031 if (m_TimerResolution) timeEndPeriod(m_TimerResolution);
00032
00033 m_pSchedule->DumpLinkedList();
00034
00035 if (m_hThread)
00036 {
00037 m_bAbort = TRUE;
00038 TriggerThread();
00039 WaitForSingleObject( m_hThread, INFINITE );
00040 EXECUTE_ASSERT( CloseHandle(m_hThread) );
00041 m_hThread = 0;
00042 EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) );
00043 delete m_pSchedule;
00044 }
00045 }
00046
00047 CBaseReferenceClock::CBaseReferenceClock( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pShed )
00048 : CUnknown( pName, pUnk )
00049 , m_rtLastGotTime(0)
00050 , m_TimerResolution(0)
00051 , m_bAbort( FALSE )
00052 , m_pSchedule( pShed ? pShed : new CAMSchedule(CreateEvent(NULL, FALSE, FALSE, NULL)) )
00053 , m_hThread(0)
00054 {
00055
00056 ASSERT(m_pSchedule);
00057 if (!m_pSchedule)
00058 {
00059 *phr = E_OUTOFMEMORY;
00060 }
00061 else
00062 {
00063
00064 TIMECAPS tc;
00065 m_TimerResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc)))
00066 ? tc.wPeriodMin
00067 : 1;
00068
00069 timeBeginPeriod(m_TimerResolution);
00070
00071
00072 m_dwPrevSystemTime = timeGetTime();
00073 m_rtPrivateTime = (UNITS / MILLISECONDS) * m_dwPrevSystemTime;
00074
00075 #ifdef PERF
00076 m_idGetSystemTime = MSR_REGISTER("CBaseReferenceClock::GetTime");
00077 #endif
00078
00079 if ( !pShed )
00080 {
00081 DWORD ThreadID;
00082 m_hThread = ::CreateThread(NULL,
00083 (DWORD) 0,
00084 AdviseThreadFunction,
00085 (LPVOID) this,
00086 (DWORD) 0,
00087 &ThreadID);
00088
00089 if (m_hThread)
00090 {
00091 SetThreadPriority( m_hThread, THREAD_PRIORITY_TIME_CRITICAL );
00092 }
00093 else
00094 {
00095 *phr = E_FAIL;
00096 EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) );
00097 delete m_pSchedule;
00098 }
00099 }
00100 }
00101 }
00102
00103 STDMETHODIMP CBaseReferenceClock::GetTime(REFERENCE_TIME *pTime)
00104 {
00105 HRESULT hr;
00106 if (pTime)
00107 {
00108 REFERENCE_TIME rtNow;
00109 Lock();
00110 rtNow = GetPrivateTime();
00111 if (rtNow > m_rtLastGotTime)
00112 {
00113 m_rtLastGotTime = rtNow;
00114 hr = S_OK;
00115 }
00116 else
00117 {
00118 hr = S_FALSE;
00119 }
00120 *pTime = m_rtLastGotTime;
00121 Unlock();
00122 MSR_INTEGER(m_idGetSystemTime, LONG((*pTime) / (UNITS/MILLISECONDS)) );
00123
00124 }
00125 else hr = E_POINTER;
00126
00127 return hr;
00128 }
00129
00130 STDMETHODIMP CBaseReferenceClock::AdviseTime(
00131 REFERENCE_TIME baseTime,
00132 REFERENCE_TIME streamTime,
00133 HEVENT hEvent,
00134 DWORD_PTR *pdwAdviseCookie)
00135 {
00136 CheckPointer(pdwAdviseCookie, E_POINTER);
00137 *pdwAdviseCookie = 0;
00138
00139
00140 ASSERT(WAIT_TIMEOUT == WaitForSingleObject(HANDLE(hEvent),0));
00141
00142 HRESULT hr;
00143
00144 const REFERENCE_TIME lRefTime = baseTime + streamTime;
00145 if ( lRefTime <= 0 || lRefTime == MAX_TIME )
00146 {
00147 hr = E_INVALIDARG;
00148 }
00149 else
00150 {
00151 *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( lRefTime, 0, HANDLE(hEvent), FALSE );
00152 hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY;
00153 }
00154 return hr;
00155 }
00156
00157 STDMETHODIMP CBaseReferenceClock::AdvisePeriodic(
00158 REFERENCE_TIME StartTime,
00159 REFERENCE_TIME PeriodTime,
00160 HSEMAPHORE hSemaphore,
00161 DWORD_PTR *pdwAdviseCookie)
00162 {
00163 CheckPointer(pdwAdviseCookie, E_POINTER);
00164 *pdwAdviseCookie = 0;
00165
00166 HRESULT hr;
00167 if (StartTime > 0 && PeriodTime > 0 && StartTime != MAX_TIME )
00168 {
00169 *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( StartTime, PeriodTime, HANDLE(hSemaphore), TRUE );
00170 hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY;
00171 }
00172 else hr = E_INVALIDARG;
00173
00174 return hr;
00175 }
00176
00177 STDMETHODIMP CBaseReferenceClock::Unadvise(DWORD_PTR dwAdviseCookie)
00178 {
00179 return m_pSchedule->Unadvise(dwAdviseCookie);
00180 }
00181
00182 REFERENCE_TIME CBaseReferenceClock::GetPrivateTime()
00183 {
00184 CAutoLock cObjectLock(this);
00185
00186
00187
00188 DWORD dwTime = timeGetTime();
00189 {
00190 m_rtPrivateTime += Int32x32To64(UNITS / MILLISECONDS, (DWORD)(dwTime - m_dwPrevSystemTime));
00191 m_dwPrevSystemTime = dwTime;
00192 }
00193
00194 return m_rtPrivateTime;
00195 }
00196
00197 STDMETHODIMP CBaseReferenceClock::SetTimeDelta(const REFERENCE_TIME & TimeDelta)
00198 {
00199 #ifdef DEBUG
00200
00201
00202 LONGLONG llDelta = TimeDelta > 0 ? TimeDelta : -TimeDelta;
00203 if (llDelta > UNITS * 1000) {
00204 DbgLog((LOG_TRACE, 0, TEXT("Bad Time Delta")));
00205 DebugBreak();
00206 }
00207
00208
00209
00210
00211 const LONG usDelta = LONG(TimeDelta/10);
00212
00213 DWORD delta = abs(usDelta);
00214
00215 int Severity = 8;
00216 while ( delta > 0 )
00217 {
00218 delta >>= 3;
00219 Severity--;
00220 }
00221
00222
00223 DbgLog((LOG_TIMING, Severity < 0 ? 0 : Severity,
00224 TEXT("Sev %2i: CSystemClock::SetTimeDelta(%8ld us) %lu -> %lu ms."),
00225 Severity, usDelta, DWORD(ConvertToMilliseconds(m_rtPrivateTime)),
00226 DWORD(ConvertToMilliseconds(TimeDelta+m_rtPrivateTime)) ));
00227
00228
00229 #ifdef BREAK_ON_SEVERE_TIME_DELTA
00230 if (Severity < 0)
00231 DbgBreakPoint(TEXT("SetTimeDelta > 16 seconds!"),
00232 TEXT(__FILE__),__LINE__);
00233 #endif
00234
00235 #endif
00236
00237 CAutoLock cObjectLock(this);
00238 m_rtPrivateTime += TimeDelta;
00239
00240
00241
00242
00243
00244
00245
00246 if ( TimeDelta > 5000 && m_pSchedule->GetAdviseCount() > 0 ) TriggerThread();
00247 return NOERROR;
00248 }
00249
00250 DWORD __stdcall CBaseReferenceClock::AdviseThreadFunction(LPVOID p)
00251 {
00252 return DWORD(reinterpret_cast<CBaseReferenceClock*>(p)->AdviseThread());
00253 }
00254
00255 HRESULT CBaseReferenceClock::AdviseThread()
00256 {
00257 DWORD dwWait = INFINITE;
00258
00259
00260
00261
00262
00263
00264
00265 while ( !m_bAbort )
00266 {
00267
00268 DbgLog((LOG_TIMING, 3, TEXT("CBaseRefClock::AdviseThread() Delay: %lu ms"), dwWait ));
00269 WaitForSingleObject(m_pSchedule->GetEvent(), dwWait);
00270 if (m_bAbort) break;
00271
00272
00273
00274
00275
00276
00277 const REFERENCE_TIME rtNow = GetPrivateTime();
00278
00279 DbgLog((LOG_TIMING, 3,
00280 TEXT("CBaseRefClock::AdviseThread() Woke at = %lu ms"),
00281 ConvertToMilliseconds(rtNow) ));
00282
00283
00284
00285
00286 m_rtNextAdvise = m_pSchedule->Advise( 10000 + rtNow );
00287 LONGLONG llWait = m_rtNextAdvise - rtNow;
00288
00289 ASSERT( llWait > 0 );
00290
00291 llWait = ConvertToMilliseconds(llWait);
00292
00293 dwWait = (llWait > REFERENCE_TIME(UINT_MAX)) ? UINT_MAX : DWORD(llWait);
00294 };
00295 return NOERROR;
00296 }