b2161e7d58d922b4430bd19ac21983cafe2274a1
[reactos.git] / reactos / dll / directx / ksproxy / clockforward.cpp
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS WDM Streaming ActiveMovie Proxy
4 * FILE: dll/directx/ksproxy/clockforward.cpp
5 * PURPOSE: IKsClockForwarder interface
6 *
7 * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org)
8 */
9 #include "precomp.h"
10
11 const GUID IID_IKsClockForwarder = {0x877e4352, 0x6fea, 0x11d0, {0xb8, 0x63, 0x00, 0xaa, 0x00, 0xa2, 0x16, 0xa1}};
12
13 DWORD WINAPI CKsClockForwarder_ThreadStartup(LPVOID lpParameter);
14
15 class CKsClockForwarder : public IDistributorNotify,
16 public IKsObject
17 {
18 public:
19 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
20
21 STDMETHODIMP_(ULONG) AddRef()
22 {
23 InterlockedIncrement(&m_Ref);
24 return m_Ref;
25 }
26 STDMETHODIMP_(ULONG) Release()
27 {
28 InterlockedDecrement(&m_Ref);
29
30 if (!m_Ref)
31 {
32 delete this;
33 return 0;
34 }
35 return m_Ref;
36 }
37
38 // IDistributorNotify interface
39 HRESULT STDMETHODCALLTYPE Stop();
40 HRESULT STDMETHODCALLTYPE Pause();
41 HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart);
42 HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock);
43 HRESULT STDMETHODCALLTYPE NotifyGraphChange();
44
45 // IKsObject interface
46 HANDLE STDMETHODCALLTYPE KsGetObjectHandle();
47
48 CKsClockForwarder(HANDLE handle);
49 virtual ~CKsClockForwarder(){};
50 HRESULT STDMETHODCALLTYPE SetClockState(KSSTATE State);
51 protected:
52 LONG m_Ref;
53 HANDLE m_Handle;
54 IReferenceClock * m_Clock;
55 HANDLE m_hEvent;
56 HANDLE m_hThread;
57 BOOL m_ThreadStarted;
58 BOOL m_PendingStop;
59 BOOL m_ForceStart;
60 KSSTATE m_State;
61 REFERENCE_TIME m_Time;
62
63 friend DWORD WINAPI CKsClockForwarder_ThreadStartup(LPVOID lpParameter);
64 };
65
66 CKsClockForwarder::CKsClockForwarder(
67 HANDLE handle) : m_Ref(0),
68 m_Handle(handle),
69 m_Clock(0),
70 m_hEvent(NULL),
71 m_hThread(NULL),
72 m_ThreadStarted(FALSE),
73 m_PendingStop(FALSE),
74 m_ForceStart(FALSE),
75 m_State(KSSTATE_STOP),
76 m_Time(0)
77 {
78 }
79
80 HRESULT
81 STDMETHODCALLTYPE
82 CKsClockForwarder::QueryInterface(
83 IN REFIID refiid,
84 OUT PVOID* Output)
85 {
86 if (IsEqualGUID(refiid, IID_IUnknown))
87 {
88 *Output = PVOID(this);
89 reinterpret_cast<IUnknown*>(*Output)->AddRef();
90 return NOERROR;
91 }
92 if (IsEqualGUID(refiid, IID_IKsObject) ||
93 IsEqualGUID(refiid, IID_IKsClockForwarder))
94 {
95 *Output = (IKsObject*)(this);
96 reinterpret_cast<IKsObject*>(*Output)->AddRef();
97 return NOERROR;
98 }
99
100 if (IsEqualGUID(refiid, IID_IDistributorNotify))
101 {
102 *Output = (IDistributorNotify*)(this);
103 reinterpret_cast<IDistributorNotify*>(*Output)->AddRef();
104 return NOERROR;
105 }
106
107 return E_NOINTERFACE;
108 }
109
110 //-------------------------------------------------------------------
111 // IDistributorNotify interface
112 //
113
114
115 HRESULT
116 STDMETHODCALLTYPE
117 CKsClockForwarder::Stop()
118 {
119 #ifdef KSPROXY_TRACE
120 WCHAR Buffer[200];
121 swprintf(Buffer, L"CKsClockForwarder::Stop m_ThreadStarted %u m_PendingStop %u m_hThread %p m_hEvent %p m_Handle %p\n", m_ThreadStarted, m_PendingStop, m_hThread, m_hEvent, m_Handle);
122 OutputDebugStringW(Buffer);
123 #endif
124
125 m_Time = 0;
126 if (m_ThreadStarted)
127 {
128 // signal pending stop
129 m_PendingStop = true;
130
131 assert(m_hThread);
132 assert(m_hEvent);
133
134 // set stop event
135 SetEvent(m_hEvent);
136
137 // wait untill the thread has finished
138 WaitForSingleObject(m_hThread, INFINITE);
139
140 // close thread handle
141 CloseHandle(m_hThread);
142
143 // zero handle
144 m_hThread = NULL;
145 }
146
147 if (m_hEvent)
148 {
149 // close stop event
150 CloseHandle(m_hEvent);
151 m_hEvent = NULL;
152 }
153
154 m_PendingStop = false;
155
156 SetClockState(KSSTATE_STOP);
157 return NOERROR;
158 }
159
160 HRESULT
161 STDMETHODCALLTYPE
162 CKsClockForwarder::Pause()
163 {
164 #ifdef KSPROXY_TRACE
165 OutputDebugString("CKsClockForwarder::Pause\n");
166 #endif
167
168 if (!m_hEvent)
169 {
170 m_hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
171 if (!m_hEvent)
172 return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
173 }
174
175 if (m_State <= KSSTATE_PAUSE)
176 {
177 if (m_State == KSSTATE_STOP)
178 SetClockState(KSSTATE_ACQUIRE);
179
180 if (m_State == KSSTATE_ACQUIRE)
181 SetClockState(KSSTATE_PAUSE);
182 }
183 else
184 {
185 if (!m_ForceStart)
186 {
187 SetClockState(KSSTATE_PAUSE);
188 }
189 }
190
191 if (!m_hThread)
192 {
193 m_hThread = CreateThread(NULL, 0, CKsClockForwarder_ThreadStartup, (LPVOID)this, 0, NULL);
194 if (!m_hThread)
195 return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
196 }
197
198 return NOERROR;
199 }
200
201 HRESULT
202 STDMETHODCALLTYPE
203 CKsClockForwarder::Run(
204 REFERENCE_TIME tStart)
205 {
206 #ifdef KSPROXY_TRACE
207 OutputDebugString("CKsClockForwarder::Run\n");
208 #endif
209
210 m_Time = tStart;
211
212 if (!m_hEvent || !m_hThread)
213 {
214 m_ForceStart = TRUE;
215 HRESULT hr = Pause();
216 m_ForceStart = FALSE;
217
218 if (FAILED(hr))
219 return hr;
220 }
221
222 assert(m_hThread);
223
224 SetClockState(KSSTATE_RUN);
225 SetEvent(m_hEvent);
226
227 return NOERROR;
228 }
229
230 HRESULT
231 STDMETHODCALLTYPE
232 CKsClockForwarder::SetSyncSource(
233 IReferenceClock *pClock)
234 {
235 #ifdef KSPROXY_TRACE
236 OutputDebugString("CKsClockForwarder::SetSyncSource\n");
237 #endif
238
239 if (pClock)
240 pClock->AddRef();
241
242 if (m_Clock)
243 m_Clock->Release();
244
245
246 m_Clock = pClock;
247 return NOERROR;
248 }
249
250 HRESULT
251 STDMETHODCALLTYPE
252 CKsClockForwarder::NotifyGraphChange()
253 {
254 #ifdef KSPROXY_TRACE
255 OutputDebugString("CKsClockForwarder::NotifyGraphChange\n");
256 #endif
257
258 return NOERROR;
259 }
260
261 //-------------------------------------------------------------------
262 // IKsObject interface
263 //
264
265 HANDLE
266 STDMETHODCALLTYPE
267 CKsClockForwarder::KsGetObjectHandle()
268 {
269 return m_Handle;
270 }
271
272 //-------------------------------------------------------------------
273 HRESULT
274 STDMETHODCALLTYPE
275 CKsClockForwarder::SetClockState(KSSTATE State)
276 {
277 KSPROPERTY Property;
278 ULONG BytesReturned;
279
280 Property.Set = KSPROPSETID_Clock;
281 Property.Id = KSPROPERTY_CLOCK_STATE;
282 Property.Flags = KSPROPERTY_TYPE_SET;
283
284 HRESULT hr = KsSynchronousDeviceControl(m_Handle, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), &State, sizeof(KSSTATE), &BytesReturned);
285 if (SUCCEEDED(hr))
286 m_State = State;
287
288 #ifdef KSPROXY_TRACE
289 WCHAR Buffer[100];
290 swprintf(Buffer, L"CKsClockForwarder::SetClockState m_State %u State %u hr %lx\n", m_State, State, hr);
291 OutputDebugStringW(Buffer);
292 #endif
293
294 return hr;
295 }
296
297 DWORD
298 WINAPI
299 CKsClockForwarder_ThreadStartup(LPVOID lpParameter)
300 {
301 REFERENCE_TIME Time;
302 ULONG BytesReturned;
303
304 CKsClockForwarder * Fwd = (CKsClockForwarder*)lpParameter;
305
306 Fwd->m_ThreadStarted = TRUE;
307
308 do
309 {
310 if (Fwd->m_PendingStop)
311 break;
312
313 if (Fwd->m_State != KSSTATE_RUN)
314 WaitForSingleObject(Fwd->m_hEvent, INFINITE);
315
316 KSPROPERTY Property;
317 Property.Set = KSPROPSETID_Clock;
318 Property.Id = KSPROPERTY_CLOCK_TIME;
319 Property.Flags = KSPROPERTY_TYPE_SET;
320
321 Fwd->m_Clock->GetTime(&Time);
322 Time -= Fwd->m_Time;
323
324 KsSynchronousDeviceControl(Fwd->m_Handle, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), &Time, sizeof(REFERENCE_TIME), &BytesReturned);
325 }
326 while(TRUE);
327
328 Fwd->m_ThreadStarted = FALSE;
329 return NOERROR;
330 }
331
332 HRESULT
333 WINAPI
334 CKsClockForwarder_Constructor(
335 IUnknown * pUnkOuter,
336 REFIID riid,
337 LPVOID * ppv)
338 {
339 HRESULT hr;
340 HANDLE handle;
341
342 #ifdef KSPROXY_TRACE
343 OutputDebugStringW(L"CKsClockForwarder_Constructor\n");
344 #endif
345
346 // open default clock
347 hr = KsOpenDefaultDevice(KSCATEGORY_CLOCK, GENERIC_READ | GENERIC_WRITE, &handle);
348
349 if (hr != NOERROR)
350 {
351 #ifdef KSPROXY_TRACE
352 OutputDebugString("CKsClockForwarder_Constructor failed to open device\n");
353 #endif
354 return hr;
355 }
356
357 CKsClockForwarder * clock = new CKsClockForwarder(handle);
358
359 if (!clock)
360 {
361 // free clock handle
362 CloseHandle(handle);
363 return E_OUTOFMEMORY;
364 }
365
366 if (FAILED(clock->QueryInterface(riid, ppv)))
367 {
368 /* not supported */
369 delete clock;
370 return E_NOINTERFACE;
371 }
372
373 return NOERROR;
374 }