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