1d87a7f0047d244aefddf723c0b285fa4e462b4a
[reactos.git] / reactos / dll / directx / quartz / dsoundrender.c
1 /*
2 * Direct Sound Audio Renderer
3 *
4 * Copyright 2004 Christian Costa
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "config.h"
22
23 #include "quartz_private.h"
24 #include "control_private.h"
25 #include "pin.h"
26
27 #include "uuids.h"
28 #include "vfwmsgs.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "dshow.h"
32 #include "evcode.h"
33 #include "strmif.h"
34 #include "dsound.h"
35 #include "amaudio.h"
36
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
41
42 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
43
44 static const IBaseFilterVtbl DSoundRender_Vtbl;
45 static const IPinVtbl DSoundRender_InputPin_Vtbl;
46 static const IBasicAudioVtbl IBasicAudio_Vtbl;
47 static const IReferenceClockVtbl IReferenceClock_Vtbl;
48 static const IMediaSeekingVtbl IMediaSeeking_Vtbl;
49 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl;
50
51 typedef struct DSoundRenderImpl
52 {
53 const IBaseFilterVtbl * lpVtbl;
54 const IBasicAudioVtbl *IBasicAudio_vtbl;
55 const IReferenceClockVtbl *IReferenceClock_vtbl;
56 const IAMDirectSoundVtbl *IAMDirectSound_vtbl;
57
58 LONG refCount;
59 CRITICAL_SECTION csFilter;
60 FILTER_STATE state;
61 REFERENCE_TIME rtStreamStart, rtLastStop;
62 IReferenceClock * pClock;
63 FILTER_INFO filterInfo;
64
65 InputPin * pInputPin;
66
67 IDirectSound8 *dsound;
68 LPDIRECTSOUNDBUFFER dsbuffer;
69 DWORD buf_size;
70 DWORD write_pos;
71 DWORD write_loops;
72
73 DWORD last_play_pos;
74 DWORD play_loops;
75
76 REFERENCE_TIME play_time;
77 MediaSeekingImpl mediaSeeking;
78
79 HANDLE state_change, blocked;
80
81 long volume;
82 long pan;
83 } DSoundRenderImpl;
84
85 /* Seeking is not needed for a renderer, rely on newsegment for the appropriate changes */
86 static HRESULT sound_mod_stop(IBaseFilter *iface)
87 {
88 TRACE("(%p)\n", iface);
89 return S_OK;
90 }
91
92 static HRESULT sound_mod_start(IBaseFilter *iface)
93 {
94 TRACE("(%p)\n", iface);
95
96 return S_OK;
97 }
98
99 static HRESULT sound_mod_rate(IBaseFilter *iface)
100 {
101 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
102
103 WAVEFORMATEX *format = (WAVEFORMATEX*)This->pInputPin->pin.mtCurrent.pbFormat;
104 DWORD freq = format->nSamplesPerSec;
105 double rate = This->mediaSeeking.dRate;
106
107 freq = (DWORD)((double)freq * rate);
108
109 TRACE("(%p)\n", iface);
110
111 if (freq > DSBFREQUENCY_MAX)
112 return VFW_E_UNSUPPORTED_AUDIO;
113
114 if (freq < DSBFREQUENCY_MIN)
115 return VFW_E_UNSUPPORTED_AUDIO;
116
117 return S_OK;
118 }
119
120 static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, REFERENCE_TIME *pRefTime)
121 {
122 HRESULT hr;
123
124 EnterCriticalSection(&This->csFilter);
125 {
126 DWORD state;
127 DWORD write_pos;
128
129 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
130 if (SUCCEEDED(hr) && !(state & DSBSTATUS_PLAYING) && This->state == State_Running)
131 {
132 TRACE("Not playing, kickstarting the engine\n");
133
134 hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING);
135 if (FAILED(hr))
136 ERR("Can't play sound buffer (%x)\n", hr);
137 }
138
139 if (SUCCEEDED(hr))
140 hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, &write_pos);
141 if (hr == S_OK)
142 {
143 DWORD play_pos = *pPlayPos;
144
145 if (play_pos < This->last_play_pos)
146 This->play_loops++;
147 This->last_play_pos = play_pos;
148
149 /* If we really fell behind, start at the next possible position
150 * Also happens when just starting playback for the first time,
151 * or when flushing
152 */
153 if ((This->play_loops*This->buf_size)+play_pos >=
154 (This->write_loops*This->buf_size)+This->write_pos)
155 This->write_pos = write_pos;
156
157 if (pRefTime)
158 {
159 REFERENCE_TIME play_time;
160 play_time = ((REFERENCE_TIME)This->play_loops*10000000) +
161 ((REFERENCE_TIME)play_pos*10000000/This->buf_size);
162
163 /* Don't let time run backwards */
164 if(play_time-This->play_time > 0)
165 This->play_time = play_time;
166 else
167 hr = S_FALSE;
168
169 *pRefTime = This->play_time;
170 }
171 }
172 }
173 LeaveCriticalSection(&This->csFilter);
174
175 return hr;
176 }
177
178 static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *data, DWORD size)
179 {
180 HRESULT hr = S_OK;
181 LPBYTE lpbuf1 = NULL;
182 LPBYTE lpbuf2 = NULL;
183 DWORD dwsize1 = 0;
184 DWORD dwsize2 = 0;
185 DWORD size2;
186 DWORD play_pos,buf_free;
187
188 do {
189
190 hr = DSoundRender_GetPos(This, &play_pos, NULL);
191 if (hr != DS_OK)
192 {
193 ERR("GetPos returned error: %x\n", hr);
194 break;
195 }
196 if (This->write_pos <= play_pos)
197 buf_free = play_pos-This->write_pos;
198 else
199 buf_free = This->buf_size - This->write_pos + play_pos;
200
201 /* Wait for enough of the buffer to empty before filling it */
202 if(buf_free < This->buf_size/4)
203 {
204 Sleep(50);
205 continue;
206 }
207
208 size2 = min(buf_free, size);
209 hr = IDirectSoundBuffer_Lock(This->dsbuffer, This->write_pos, size2, (LPVOID *)&lpbuf1, &dwsize1, (LPVOID *)&lpbuf2, &dwsize2, 0);
210 if (hr != DS_OK) {
211 ERR("Unable to lock sound buffer! (%x)\n", hr);
212 break;
213 }
214 /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
215
216 memcpy(lpbuf1, data, dwsize1);
217 if (dwsize2)
218 memcpy(lpbuf2, data + dwsize1, dwsize2);
219
220 hr = IDirectSoundBuffer_Unlock(This->dsbuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
221 if (hr != DS_OK)
222 ERR("Unable to unlock sound buffer! (%x)\n", hr);
223
224 size -= dwsize1 + dwsize2;
225 data += dwsize1 + dwsize2;
226 This->write_pos += dwsize1 + dwsize2;
227 if (This->write_pos >= This->buf_size)
228 {
229 This->write_pos -= This->buf_size;
230 This->write_loops++;
231 }
232 } while (size && This->state == State_Running);
233
234 return hr;
235 }
236
237 static HRESULT DSoundRender_Sample(LPVOID iface, IMediaSample * pSample)
238 {
239 DSoundRenderImpl *This = iface;
240 LPBYTE pbSrcStream = NULL;
241 long cbSrcStream = 0;
242 REFERENCE_TIME tStart, tStop;
243 HRESULT hr;
244 AM_MEDIA_TYPE *amt;
245
246 TRACE("%p %p\n", iface, pSample);
247
248 /* Slightly incorrect, Pause completes when a frame is received so we should signal
249 * pause completion here, but for sound playing a single frame doesn't make sense
250 */
251
252 EnterCriticalSection(&This->csFilter);
253
254 if (This->pInputPin->end_of_stream || This->pInputPin->flushing)
255 {
256 LeaveCriticalSection(&This->csFilter);
257 return S_FALSE;
258 }
259
260 if (This->state == State_Stopped)
261 {
262 LeaveCriticalSection(&This->csFilter);
263 return VFW_E_WRONG_STATE;
264 }
265
266 if (IMediaSample_GetMediaType(pSample, &amt) == S_OK)
267 {
268 AM_MEDIA_TYPE *orig = &This->pInputPin->pin.mtCurrent;
269 WAVEFORMATEX *origfmt = (WAVEFORMATEX *)orig->pbFormat;
270 WAVEFORMATEX *newfmt = (WAVEFORMATEX *)amt->pbFormat;
271
272 if (origfmt->wFormatTag == newfmt->wFormatTag &&
273 origfmt->nChannels == newfmt->nChannels &&
274 origfmt->nBlockAlign == newfmt->nBlockAlign &&
275 origfmt->wBitsPerSample == newfmt->wBitsPerSample &&
276 origfmt->cbSize == newfmt->cbSize)
277 {
278 if (origfmt->nSamplesPerSec != newfmt->nSamplesPerSec)
279 {
280 hr = IDirectSoundBuffer_SetFrequency(This->dsbuffer,
281 newfmt->nSamplesPerSec);
282 if (FAILED(hr))
283 {
284 LeaveCriticalSection(&This->csFilter);
285 return VFW_E_TYPE_NOT_ACCEPTED;
286 }
287 FreeMediaType(orig);
288 CopyMediaType(orig, amt);
289 IMediaSample_SetMediaType(pSample, NULL);
290 }
291 }
292 else
293 {
294 LeaveCriticalSection(&This->csFilter);
295 return VFW_E_TYPE_NOT_ACCEPTED;
296 }
297 }
298
299 SetEvent(This->state_change);
300
301 hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
302 if (FAILED(hr))
303 {
304 ERR("Cannot get pointer to sample data (%x)\n", hr);
305 LeaveCriticalSection(&This->csFilter);
306 return hr;
307 }
308
309 hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
310 if (FAILED(hr))
311 ERR("Cannot get sample time (%x)\n", hr);
312
313 if (This->rtLastStop != tStart && (IMediaSample_IsDiscontinuity(pSample) == S_FALSE))
314 WARN("Unexpected discontinuity: Last: %u.%03u, tStart: %u.%03u\n",
315 (DWORD)(This->rtLastStop / 10000000), (DWORD)((This->rtLastStop / 10000)%1000),
316 (DWORD)(tStart / 10000000), (DWORD)((tStart / 10000)%1000));
317 This->rtLastStop = tStop;
318
319 if (IMediaSample_IsPreroll(pSample) == S_OK)
320 {
321 TRACE("Preroll!\n");
322 LeaveCriticalSection(&This->csFilter);
323 return S_OK;
324 }
325
326 if (This->state == State_Paused)
327 {
328 LeaveCriticalSection(&This->csFilter);
329 WaitForSingleObject(This->blocked, INFINITE);
330 EnterCriticalSection(&This->csFilter);
331 if (This->state == State_Stopped)
332 {
333 LeaveCriticalSection(&This->csFilter);
334 return VFW_E_WRONG_STATE;
335 }
336
337 if (This->state == State_Paused)
338 {
339 /* Assuming we return because of flushing */
340 TRACE("Flushing\n");
341 LeaveCriticalSection(&This->csFilter);
342 return S_OK;
343 }
344 }
345
346 cbSrcStream = IMediaSample_GetActualDataLength(pSample);
347 TRACE("Sample data ptr = %p, size = %ld\n", pbSrcStream, cbSrcStream);
348
349 #if 0 /* For debugging purpose */
350 {
351 int i;
352 for(i = 0; i < cbSrcStream; i++)
353 {
354 if ((i!=0) && !(i%16))
355 TRACE("\n");
356 TRACE("%02x ", pbSrcStream[i]);
357 }
358 TRACE("\n");
359 }
360 #endif
361
362 hr = DSoundRender_SendSampleData(This, pbSrcStream, cbSrcStream);
363 LeaveCriticalSection(&This->csFilter);
364 return hr;
365 }
366
367 static HRESULT DSoundRender_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
368 {
369 WAVEFORMATEX* format;
370
371 if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio))
372 return S_FALSE;
373
374 format = (WAVEFORMATEX*)pmt->pbFormat;
375 TRACE("Format = %p\n", format);
376 TRACE("wFormatTag = %x %x\n", format->wFormatTag, WAVE_FORMAT_PCM);
377 TRACE("nChannels = %d\n", format->nChannels);
378 TRACE("nSamplesPerSec = %d\n", format->nAvgBytesPerSec);
379 TRACE("nAvgBytesPerSec = %d\n", format->nAvgBytesPerSec);
380 TRACE("nBlockAlign = %d\n", format->nBlockAlign);
381 TRACE("wBitsPerSample = %d\n", format->wBitsPerSample);
382
383 if (!IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_PCM))
384 return S_FALSE;
385
386 return S_OK;
387 }
388
389 HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv)
390 {
391 HRESULT hr;
392 PIN_INFO piInput;
393 DSoundRenderImpl * pDSoundRender;
394
395 TRACE("(%p, %p)\n", pUnkOuter, ppv);
396
397 *ppv = NULL;
398
399 if (pUnkOuter)
400 return CLASS_E_NOAGGREGATION;
401
402 pDSoundRender = CoTaskMemAlloc(sizeof(DSoundRenderImpl));
403 if (!pDSoundRender)
404 return E_OUTOFMEMORY;
405 ZeroMemory(pDSoundRender, sizeof(DSoundRenderImpl));
406
407 pDSoundRender->lpVtbl = &DSoundRender_Vtbl;
408 pDSoundRender->IBasicAudio_vtbl = &IBasicAudio_Vtbl;
409 pDSoundRender->IReferenceClock_vtbl = &IReferenceClock_Vtbl;
410 pDSoundRender->IAMDirectSound_vtbl = &IAMDirectSound_Vtbl;
411 pDSoundRender->refCount = 1;
412 InitializeCriticalSection(&pDSoundRender->csFilter);
413 pDSoundRender->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DSoundRenderImpl.csFilter");
414 pDSoundRender->state = State_Stopped;
415
416 /* construct input pin */
417 piInput.dir = PINDIR_INPUT;
418 piInput.pFilter = (IBaseFilter *)pDSoundRender;
419 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
420 hr = InputPin_Construct(&DSoundRender_InputPin_Vtbl, &piInput, DSoundRender_Sample, pDSoundRender, DSoundRender_QueryAccept, NULL, &pDSoundRender->csFilter, NULL, (IPin **)&pDSoundRender->pInputPin);
421
422 if (SUCCEEDED(hr))
423 {
424 hr = DirectSoundCreate8(NULL, &pDSoundRender->dsound, NULL);
425 if (FAILED(hr))
426 ERR("Cannot create Direct Sound object (%x)\n", hr);
427 else
428 IDirectSound_SetCooperativeLevel(pDSoundRender->dsound, GetDesktopWindow(), DSSCL_PRIORITY);
429 }
430
431 if (SUCCEEDED(hr))
432 {
433 MediaSeekingImpl_Init((IBaseFilter*)pDSoundRender, sound_mod_stop, sound_mod_start, sound_mod_rate, &pDSoundRender->mediaSeeking, &pDSoundRender->csFilter);
434 pDSoundRender->mediaSeeking.lpVtbl = &IMediaSeeking_Vtbl;
435
436 pDSoundRender->state_change = CreateEventW(NULL, TRUE, TRUE, NULL);
437 pDSoundRender->blocked = CreateEventW(NULL, FALSE, FALSE, NULL);
438
439 if (!pDSoundRender->state_change || !pDSoundRender->blocked)
440 {
441 IUnknown_Release((IUnknown *)pDSoundRender);
442 return HRESULT_FROM_WIN32(GetLastError());
443 }
444
445 *ppv = pDSoundRender;
446 }
447 else
448 {
449 if (pDSoundRender->pInputPin)
450 IPin_Release((IPin*)pDSoundRender->pInputPin);
451 pDSoundRender->csFilter.DebugInfo->Spare[0] = 0;
452 DeleteCriticalSection(&pDSoundRender->csFilter);
453 CoTaskMemFree(pDSoundRender);
454 }
455
456 return hr;
457 }
458
459 static HRESULT WINAPI DSoundRender_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
460 {
461 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
462 TRACE("(%p, %p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
463
464 *ppv = NULL;
465
466 if (IsEqualIID(riid, &IID_IUnknown))
467 *ppv = This;
468 else if (IsEqualIID(riid, &IID_IPersist))
469 *ppv = This;
470 else if (IsEqualIID(riid, &IID_IMediaFilter))
471 *ppv = This;
472 else if (IsEqualIID(riid, &IID_IBaseFilter))
473 *ppv = This;
474 else if (IsEqualIID(riid, &IID_IBasicAudio))
475 *ppv = &This->IBasicAudio_vtbl;
476 else if (IsEqualIID(riid, &IID_IReferenceClock))
477 *ppv = &This->IReferenceClock_vtbl;
478 else if (IsEqualIID(riid, &IID_IMediaSeeking))
479 *ppv = &This->mediaSeeking.lpVtbl;
480 else if (IsEqualIID(riid, &IID_IAMDirectSound))
481 *ppv = &This->IAMDirectSound_vtbl;
482
483 if (*ppv)
484 {
485 IUnknown_AddRef((IUnknown *)(*ppv));
486 return S_OK;
487 }
488
489 if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
490 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
491
492 return E_NOINTERFACE;
493 }
494
495 static ULONG WINAPI DSoundRender_AddRef(IBaseFilter * iface)
496 {
497 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
498 ULONG refCount = InterlockedIncrement(&This->refCount);
499
500 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
501
502 return refCount;
503 }
504
505 static ULONG WINAPI DSoundRender_Release(IBaseFilter * iface)
506 {
507 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
508 ULONG refCount = InterlockedDecrement(&This->refCount);
509
510 TRACE("(%p)->() Release from %d\n", This, refCount + 1);
511
512 if (!refCount)
513 {
514 IPin *pConnectedTo;
515
516 if (This->pClock)
517 IReferenceClock_Release(This->pClock);
518
519 if (This->dsbuffer)
520 IDirectSoundBuffer_Release(This->dsbuffer);
521 This->dsbuffer = NULL;
522 if (This->dsound)
523 IDirectSound_Release(This->dsound);
524 This->dsound = NULL;
525
526 if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
527 {
528 IPin_Disconnect(pConnectedTo);
529 IPin_Release(pConnectedTo);
530 }
531 IPin_Disconnect((IPin *)This->pInputPin);
532
533 IPin_Release((IPin *)This->pInputPin);
534
535 This->lpVtbl = NULL;
536 This->IBasicAudio_vtbl = NULL;
537
538 This->csFilter.DebugInfo->Spare[0] = 0;
539 DeleteCriticalSection(&This->csFilter);
540
541 CloseHandle(This->state_change);
542 CloseHandle(This->blocked);
543
544 TRACE("Destroying Audio Renderer\n");
545 CoTaskMemFree(This);
546
547 return 0;
548 }
549 else
550 return refCount;
551 }
552
553 /** IPersist methods **/
554
555 static HRESULT WINAPI DSoundRender_GetClassID(IBaseFilter * iface, CLSID * pClsid)
556 {
557 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
558 TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
559
560 *pClsid = CLSID_DSoundRender;
561
562 return S_OK;
563 }
564
565 /** IMediaFilter methods **/
566
567 static HRESULT WINAPI DSoundRender_Stop(IBaseFilter * iface)
568 {
569 HRESULT hr = S_OK;
570 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
571
572 TRACE("(%p/%p)->()\n", This, iface);
573
574 EnterCriticalSection(&This->csFilter);
575 {
576 DWORD state = 0;
577 if (This->dsbuffer)
578 {
579 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
580 if (SUCCEEDED(hr))
581 {
582 if (state & DSBSTATUS_PLAYING)
583 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
584 }
585 }
586 if (SUCCEEDED(hr))
587 This->state = State_Stopped;
588
589 /* Complete our transition */
590 SetEvent(This->state_change);
591 SetEvent(This->blocked);
592 }
593 LeaveCriticalSection(&This->csFilter);
594
595 return hr;
596 }
597
598 static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface)
599 {
600 HRESULT hr = S_OK;
601 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
602
603 TRACE("(%p/%p)->()\n", This, iface);
604
605 EnterCriticalSection(&This->csFilter);
606 if (This->state != State_Paused)
607 {
608 DWORD state = 0;
609 if (This->state == State_Stopped)
610 {
611 This->pInputPin->end_of_stream = 0;
612 }
613
614 if (This->dsbuffer)
615 {
616 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
617 if (SUCCEEDED(hr))
618 {
619 if (state & DSBSTATUS_PLAYING)
620 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
621 }
622 }
623 if (SUCCEEDED(hr))
624 This->state = State_Paused;
625
626 ResetEvent(This->blocked);
627 ResetEvent(This->state_change);
628 }
629 LeaveCriticalSection(&This->csFilter);
630
631 return hr;
632 }
633
634 static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
635 {
636 HRESULT hr = S_OK;
637 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
638
639 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
640
641 EnterCriticalSection(&This->csFilter);
642 {
643 This->rtStreamStart = tStart;
644 if (This->state == State_Paused)
645 {
646 /* Unblock our thread, state changing from paused to running doesn't need a reset for state change */
647 SetEvent(This->blocked);
648 }
649 else if (This->state == State_Stopped)
650 {
651 ResetEvent(This->state_change);
652 This->pInputPin->end_of_stream = 0;
653 }
654
655 This->state = State_Running;
656 }
657 LeaveCriticalSection(&This->csFilter);
658
659 return hr;
660 }
661
662 static HRESULT WINAPI DSoundRender_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
663 {
664 HRESULT hr;
665 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
666
667 TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
668
669 if (WaitForSingleObject(This->state_change, dwMilliSecsTimeout) == WAIT_TIMEOUT)
670 hr = VFW_S_STATE_INTERMEDIATE;
671 else
672 hr = S_OK;
673
674 EnterCriticalSection(&This->csFilter);
675 {
676 *pState = This->state;
677 }
678 LeaveCriticalSection(&This->csFilter);
679
680 return S_OK;
681 }
682
683 static HRESULT WINAPI DSoundRender_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
684 {
685 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
686
687 TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
688
689 EnterCriticalSection(&This->csFilter);
690 {
691 if (This->pClock)
692 IReferenceClock_Release(This->pClock);
693 This->pClock = pClock;
694 if (This->pClock)
695 IReferenceClock_AddRef(This->pClock);
696 }
697 LeaveCriticalSection(&This->csFilter);
698
699 return S_OK;
700 }
701
702 static HRESULT WINAPI DSoundRender_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
703 {
704 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
705
706 TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
707
708 EnterCriticalSection(&This->csFilter);
709 {
710 *ppClock = This->pClock;
711 if (This->pClock)
712 IReferenceClock_AddRef(This->pClock);
713 }
714 LeaveCriticalSection(&This->csFilter);
715
716 return S_OK;
717 }
718
719 /** IBaseFilter implementation **/
720
721 static HRESULT DSoundRender_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
722 {
723 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
724
725 /* Our pins are static, not changing so setting static tick count is ok */
726 *lastsynctick = 0;
727
728 if (pos >= 1)
729 return S_FALSE;
730
731 *pin = (IPin *)This->pInputPin;
732 IPin_AddRef(*pin);
733 return S_OK;
734 }
735
736 static HRESULT WINAPI DSoundRender_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
737 {
738 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
739
740 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
741
742 return IEnumPinsImpl_Construct(ppEnum, DSoundRender_GetPin, iface);
743 }
744
745 static HRESULT WINAPI DSoundRender_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
746 {
747 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
748
749 TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_w(Id), ppPin);
750
751 FIXME("DSoundRender::FindPin(...)\n");
752
753 /* FIXME: critical section */
754
755 return E_NOTIMPL;
756 }
757
758 static HRESULT WINAPI DSoundRender_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
759 {
760 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
761
762 TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
763
764 strcpyW(pInfo->achName, This->filterInfo.achName);
765 pInfo->pGraph = This->filterInfo.pGraph;
766
767 if (pInfo->pGraph)
768 IFilterGraph_AddRef(pInfo->pGraph);
769
770 return S_OK;
771 }
772
773 static HRESULT WINAPI DSoundRender_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
774 {
775 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
776
777 TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
778
779 EnterCriticalSection(&This->csFilter);
780 {
781 if (pName)
782 strcpyW(This->filterInfo.achName, pName);
783 else
784 *This->filterInfo.achName = '\0';
785 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
786 }
787 LeaveCriticalSection(&This->csFilter);
788
789 return S_OK;
790 }
791
792 static HRESULT WINAPI DSoundRender_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
793 {
794 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
795 TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
796 return E_NOTIMPL;
797 }
798
799 static const IBaseFilterVtbl DSoundRender_Vtbl =
800 {
801 DSoundRender_QueryInterface,
802 DSoundRender_AddRef,
803 DSoundRender_Release,
804 DSoundRender_GetClassID,
805 DSoundRender_Stop,
806 DSoundRender_Pause,
807 DSoundRender_Run,
808 DSoundRender_GetState,
809 DSoundRender_SetSyncSource,
810 DSoundRender_GetSyncSource,
811 DSoundRender_EnumPins,
812 DSoundRender_FindPin,
813 DSoundRender_QueryFilterInfo,
814 DSoundRender_JoinFilterGraph,
815 DSoundRender_QueryVendorInfo
816 };
817
818 static HRESULT WINAPI DSoundRender_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
819 {
820 InputPin *This = (InputPin *)iface;
821 PIN_DIRECTION pindirReceive;
822 DSoundRenderImpl *DSImpl;
823 HRESULT hr = S_OK;
824
825 TRACE("(%p)->(%p, %p)\n", This, pReceivePin, pmt);
826 dump_AM_MEDIA_TYPE(pmt);
827
828 EnterCriticalSection(This->pin.pCritSec);
829 {
830 DSImpl = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
831 DSImpl->rtLastStop = -1;
832
833 if (This->pin.pConnectedTo)
834 hr = VFW_E_ALREADY_CONNECTED;
835
836 if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)
837 hr = VFW_E_TYPE_NOT_ACCEPTED;
838
839 if (SUCCEEDED(hr))
840 {
841 IPin_QueryDirection(pReceivePin, &pindirReceive);
842
843 if (pindirReceive != PINDIR_OUTPUT)
844 {
845 ERR("Can't connect from non-output pin\n");
846 hr = VFW_E_INVALID_DIRECTION;
847 }
848 }
849
850 if (SUCCEEDED(hr))
851 {
852 WAVEFORMATEX *format;
853 DSBUFFERDESC buf_desc;
854
855 TRACE("MajorType %s\n", debugstr_guid(&pmt->majortype));
856 TRACE("SubType %s\n", debugstr_guid(&pmt->subtype));
857 TRACE("Format %s\n", debugstr_guid(&pmt->formattype));
858 TRACE("Size %d\n", pmt->cbFormat);
859
860 format = (WAVEFORMATEX*)pmt->pbFormat;
861
862 DSImpl->buf_size = format->nAvgBytesPerSec;
863
864 memset(&buf_desc,0,sizeof(DSBUFFERDESC));
865 buf_desc.dwSize = sizeof(DSBUFFERDESC);
866 buf_desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN |
867 DSBCAPS_CTRLFREQUENCY |
868 DSBCAPS_GETCURRENTPOSITION2;
869 buf_desc.dwBufferBytes = DSImpl->buf_size;
870 buf_desc.lpwfxFormat = format;
871 hr = IDirectSound_CreateSoundBuffer(DSImpl->dsound, &buf_desc, &DSImpl->dsbuffer, NULL);
872 if (FAILED(hr))
873 ERR("Can't create sound buffer (%x)\n", hr);
874 }
875
876 if (SUCCEEDED(hr))
877 {
878 hr = IDirectSoundBuffer_SetVolume(DSImpl->dsbuffer, DSImpl->volume);
879 if (FAILED(hr))
880 ERR("Can't set volume to %ld (%x)\n", DSImpl->volume, hr);
881
882 hr = IDirectSoundBuffer_SetPan(DSImpl->dsbuffer, DSImpl->pan);
883 if (FAILED(hr))
884 ERR("Can't set pan to %ld (%x)\n", DSImpl->pan, hr);
885
886 DSImpl->write_pos = 0;
887 hr = S_OK;
888 }
889
890 if (SUCCEEDED(hr))
891 {
892 CopyMediaType(&This->pin.mtCurrent, pmt);
893 This->pin.pConnectedTo = pReceivePin;
894 IPin_AddRef(pReceivePin);
895 }
896 else if (hr != VFW_E_ALREADY_CONNECTED)
897 {
898 if (DSImpl->dsbuffer)
899 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
900 DSImpl->dsbuffer = NULL;
901 }
902 }
903 LeaveCriticalSection(This->pin.pCritSec);
904
905 return hr;
906 }
907
908 static HRESULT WINAPI DSoundRender_InputPin_Disconnect(IPin * iface)
909 {
910 IPinImpl *This = (IPinImpl*)iface;
911 DSoundRenderImpl *DSImpl;
912
913 TRACE("(%p)->()\n", iface);
914
915 DSImpl = (DSoundRenderImpl*)This->pinInfo.pFilter;
916 if (DSImpl->dsbuffer)
917 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
918 DSImpl->dsbuffer = NULL;
919
920 return IPinImpl_Disconnect(iface);
921 }
922
923 static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface)
924 {
925 InputPin* This = (InputPin*)iface;
926 DSoundRenderImpl *me = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
927 IMediaEventSink* pEventSink;
928 HRESULT hr;
929
930 EnterCriticalSection(This->pin.pCritSec);
931
932 TRACE("(%p/%p)->()\n", This, iface);
933 hr = InputPin_EndOfStream(iface);
934 if (hr != S_OK)
935 {
936 ERR("%08x\n", hr);
937 LeaveCriticalSection(This->pin.pCritSec);
938 return hr;
939 }
940
941 hr = IFilterGraph_QueryInterface(me->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
942 if (SUCCEEDED(hr))
943 {
944 BYTE * silence;
945
946 silence = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, me->buf_size);
947 if (silence)
948 {
949 memset(silence, 0, me->buf_size);
950 DSoundRender_SendSampleData((DSoundRenderImpl*)This->pin.pinInfo.pFilter, silence, me->buf_size);
951 HeapFree(GetProcessHeap(), 0, silence);
952 }
953
954 hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0);
955 IMediaEventSink_Release(pEventSink);
956 }
957 LeaveCriticalSection(This->pin.pCritSec);
958
959 return hr;
960 }
961
962 static HRESULT WINAPI DSoundRender_InputPin_BeginFlush(IPin * iface)
963 {
964 InputPin *This = (InputPin *)iface;
965 DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
966 HRESULT hr;
967 LPBYTE buffer;
968 DWORD size;
969
970 TRACE("\n");
971
972 EnterCriticalSection(This->pin.pCritSec);
973 hr = InputPin_BeginFlush(iface);
974
975 if (pFilter->dsbuffer)
976 {
977 IDirectSoundBuffer_Stop(pFilter->dsbuffer);
978
979 /* Force a reset */
980 IDirectSoundBuffer_SetCurrentPosition(pFilter->dsbuffer, 0);
981 pFilter->write_pos = pFilter->last_play_pos = 0;
982 ++pFilter->play_loops;
983 pFilter->write_loops = pFilter->play_loops;
984
985 IDirectSoundBuffer_Lock(pFilter->dsbuffer, 0, 0, (LPVOID *)&buffer, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER);
986 memset(buffer, 0, size);
987 IDirectSoundBuffer_Unlock(pFilter->dsbuffer, buffer, size, NULL, 0);
988 }
989
990 if (pFilter->state == State_Paused)
991 SetEvent(pFilter->blocked);
992 LeaveCriticalSection(This->pin.pCritSec);
993
994 return hr;
995 }
996
997 static HRESULT WINAPI DSoundRender_InputPin_EndFlush(IPin * iface)
998 {
999 InputPin *This = (InputPin *)iface;
1000 DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
1001 HRESULT hr;
1002
1003 TRACE("\n");
1004
1005 EnterCriticalSection(This->pin.pCritSec);
1006 hr = InputPin_EndFlush(iface);
1007
1008 if (pFilter->state == State_Paused)
1009 SetEvent(pFilter->blocked);
1010 LeaveCriticalSection(This->pin.pCritSec);
1011
1012 return hr;
1013 }
1014
1015 static const IPinVtbl DSoundRender_InputPin_Vtbl =
1016 {
1017 InputPin_QueryInterface,
1018 IPinImpl_AddRef,
1019 InputPin_Release,
1020 InputPin_Connect,
1021 DSoundRender_InputPin_ReceiveConnection,
1022 DSoundRender_InputPin_Disconnect,
1023 IPinImpl_ConnectedTo,
1024 IPinImpl_ConnectionMediaType,
1025 IPinImpl_QueryPinInfo,
1026 IPinImpl_QueryDirection,
1027 IPinImpl_QueryId,
1028 IPinImpl_QueryAccept,
1029 IPinImpl_EnumMediaTypes,
1030 IPinImpl_QueryInternalConnections,
1031 DSoundRender_InputPin_EndOfStream,
1032 DSoundRender_InputPin_BeginFlush,
1033 DSoundRender_InputPin_EndFlush,
1034 InputPin_NewSegment
1035 };
1036
1037 /*** IUnknown methods ***/
1038 static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface,
1039 REFIID riid,
1040 LPVOID*ppvObj) {
1041 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1042
1043 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1044
1045 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1046 }
1047
1048 static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) {
1049 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1050
1051 TRACE("(%p/%p)->()\n", This, iface);
1052
1053 return DSoundRender_AddRef((IBaseFilter*)This);
1054 }
1055
1056 static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) {
1057 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1058
1059 TRACE("(%p/%p)->()\n", This, iface);
1060
1061 return DSoundRender_Release((IBaseFilter*)This);
1062 }
1063
1064 /*** IDispatch methods ***/
1065 static HRESULT WINAPI Basicaudio_GetTypeInfoCount(IBasicAudio *iface,
1066 UINT*pctinfo) {
1067 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1068
1069 TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1070
1071 return S_OK;
1072 }
1073
1074 static HRESULT WINAPI Basicaudio_GetTypeInfo(IBasicAudio *iface,
1075 UINT iTInfo,
1076 LCID lcid,
1077 ITypeInfo**ppTInfo) {
1078 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1079
1080 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1081
1082 return S_OK;
1083 }
1084
1085 static HRESULT WINAPI Basicaudio_GetIDsOfNames(IBasicAudio *iface,
1086 REFIID riid,
1087 LPOLESTR*rgszNames,
1088 UINT cNames,
1089 LCID lcid,
1090 DISPID*rgDispId) {
1091 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1092
1093 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1094
1095 return S_OK;
1096 }
1097
1098 static HRESULT WINAPI Basicaudio_Invoke(IBasicAudio *iface,
1099 DISPID dispIdMember,
1100 REFIID riid,
1101 LCID lcid,
1102 WORD wFlags,
1103 DISPPARAMS*pDispParams,
1104 VARIANT*pVarResult,
1105 EXCEPINFO*pExepInfo,
1106 UINT*puArgErr) {
1107 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1108
1109 TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
1110
1111 return S_OK;
1112 }
1113
1114 /*** IBasicAudio methods ***/
1115 static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface,
1116 LONG lVolume) {
1117 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1118
1119 TRACE("(%p/%p)->(%d)\n", This, iface, lVolume);
1120
1121 if (lVolume > DSBVOLUME_MAX || lVolume < DSBVOLUME_MIN)
1122 return E_INVALIDARG;
1123
1124 if (This->dsbuffer) {
1125 if (FAILED(IDirectSoundBuffer_SetVolume(This->dsbuffer, lVolume)))
1126 return E_FAIL;
1127 }
1128
1129 This->volume = lVolume;
1130 return S_OK;
1131 }
1132
1133 static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface,
1134 LONG *plVolume) {
1135 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1136
1137 TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
1138
1139 if (!plVolume)
1140 return E_POINTER;
1141
1142 *plVolume = This->volume;
1143 return S_OK;
1144 }
1145
1146 static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface,
1147 LONG lBalance) {
1148 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1149
1150 TRACE("(%p/%p)->(%d)\n", This, iface, lBalance);
1151
1152 if (lBalance < DSBPAN_LEFT || lBalance > DSBPAN_RIGHT)
1153 return E_INVALIDARG;
1154
1155 if (This->dsbuffer) {
1156 if (FAILED(IDirectSoundBuffer_SetPan(This->dsbuffer, lBalance)))
1157 return E_FAIL;
1158 }
1159
1160 This->pan = lBalance;
1161 return S_OK;
1162 }
1163
1164 static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface,
1165 LONG *plBalance) {
1166 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1167
1168 TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
1169
1170 if (!plBalance)
1171 return E_POINTER;
1172
1173 *plBalance = This->pan;
1174 return S_OK;
1175 }
1176
1177 static const IBasicAudioVtbl IBasicAudio_Vtbl =
1178 {
1179 Basicaudio_QueryInterface,
1180 Basicaudio_AddRef,
1181 Basicaudio_Release,
1182 Basicaudio_GetTypeInfoCount,
1183 Basicaudio_GetTypeInfo,
1184 Basicaudio_GetIDsOfNames,
1185 Basicaudio_Invoke,
1186 Basicaudio_put_Volume,
1187 Basicaudio_get_Volume,
1188 Basicaudio_put_Balance,
1189 Basicaudio_get_Balance
1190 };
1191
1192
1193 /*** IUnknown methods ***/
1194 static HRESULT WINAPI ReferenceClock_QueryInterface(IReferenceClock *iface,
1195 REFIID riid,
1196 LPVOID*ppvObj)
1197 {
1198 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1199
1200 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1201
1202 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1203 }
1204
1205 static ULONG WINAPI ReferenceClock_AddRef(IReferenceClock *iface)
1206 {
1207 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1208
1209 TRACE("(%p/%p)->()\n", This, iface);
1210
1211 return DSoundRender_AddRef((IBaseFilter*)This);
1212 }
1213
1214 static ULONG WINAPI ReferenceClock_Release(IReferenceClock *iface)
1215 {
1216 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1217
1218 TRACE("(%p/%p)->()\n", This, iface);
1219
1220 return DSoundRender_Release((IBaseFilter*)This);
1221 }
1222
1223 /*** IReferenceClock methods ***/
1224 static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface,
1225 REFERENCE_TIME *pTime)
1226 {
1227 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1228 HRESULT hr = E_FAIL;
1229 DWORD play_pos;
1230
1231 TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
1232
1233 if (This->dsbuffer)
1234 hr = DSoundRender_GetPos(This, &play_pos, pTime);
1235 if (FAILED(hr))
1236 ERR("Could not get reference time (%x)!\n", hr);
1237
1238 return hr;
1239 }
1240
1241 static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface,
1242 REFERENCE_TIME rtBaseTime,
1243 REFERENCE_TIME rtStreamTime,
1244 HEVENT hEvent,
1245 DWORD_PTR *pdwAdviseCookie)
1246 {
1247 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1248
1249 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hEvent, pdwAdviseCookie);
1250
1251 return E_NOTIMPL;
1252 }
1253
1254 static HRESULT WINAPI ReferenceClock_AdvisePeriodic(IReferenceClock *iface,
1255 REFERENCE_TIME rtBaseTime,
1256 REFERENCE_TIME rtStreamTime,
1257 HSEMAPHORE hSemaphore,
1258 DWORD_PTR *pdwAdviseCookie)
1259 {
1260 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1261
1262 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hSemaphore, pdwAdviseCookie);
1263
1264 return E_NOTIMPL;
1265 }
1266
1267 static HRESULT WINAPI ReferenceClock_Unadvise(IReferenceClock *iface,
1268 DWORD_PTR dwAdviseCookie)
1269 {
1270 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1271
1272 FIXME("(%p/%p)->(%p): stub!\n", This, iface, (void*)dwAdviseCookie);
1273
1274 return S_FALSE;
1275 }
1276
1277 static const IReferenceClockVtbl IReferenceClock_Vtbl =
1278 {
1279 ReferenceClock_QueryInterface,
1280 ReferenceClock_AddRef,
1281 ReferenceClock_Release,
1282 ReferenceClock_GetTime,
1283 ReferenceClock_AdviseTime,
1284 ReferenceClock_AdvisePeriodic,
1285 ReferenceClock_Unadvise
1286 };
1287
1288 static inline DSoundRenderImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
1289 {
1290 return (DSoundRenderImpl *)((char*)iface - FIELD_OFFSET(DSoundRenderImpl, mediaSeeking.lpVtbl));
1291 }
1292
1293 static HRESULT WINAPI sound_seek_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
1294 {
1295 DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1296
1297 return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
1298 }
1299
1300 static ULONG WINAPI sound_seek_AddRef(IMediaSeeking * iface)
1301 {
1302 DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1303
1304 return IUnknown_AddRef((IUnknown *)This);
1305 }
1306
1307 static ULONG WINAPI sound_seek_Release(IMediaSeeking * iface)
1308 {
1309 DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1310
1311 return IUnknown_Release((IUnknown *)This);
1312 }
1313
1314 static const IMediaSeekingVtbl IMediaSeeking_Vtbl =
1315 {
1316 sound_seek_QueryInterface,
1317 sound_seek_AddRef,
1318 sound_seek_Release,
1319 MediaSeekingImpl_GetCapabilities,
1320 MediaSeekingImpl_CheckCapabilities,
1321 MediaSeekingImpl_IsFormatSupported,
1322 MediaSeekingImpl_QueryPreferredFormat,
1323 MediaSeekingImpl_GetTimeFormat,
1324 MediaSeekingImpl_IsUsingTimeFormat,
1325 MediaSeekingImpl_SetTimeFormat,
1326 MediaSeekingImpl_GetDuration,
1327 MediaSeekingImpl_GetStopPosition,
1328 MediaSeekingImpl_GetCurrentPosition,
1329 MediaSeekingImpl_ConvertTimeFormat,
1330 MediaSeekingImpl_SetPositions,
1331 MediaSeekingImpl_GetPositions,
1332 MediaSeekingImpl_GetAvailable,
1333 MediaSeekingImpl_SetRate,
1334 MediaSeekingImpl_GetRate,
1335 MediaSeekingImpl_GetPreroll
1336 };
1337
1338 /*** IUnknown methods ***/
1339 static HRESULT WINAPI AMDirectSound_QueryInterface(IAMDirectSound *iface,
1340 REFIID riid,
1341 LPVOID*ppvObj)
1342 {
1343 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1344
1345 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1346
1347 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1348 }
1349
1350 static ULONG WINAPI AMDirectSound_AddRef(IAMDirectSound *iface)
1351 {
1352 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1353
1354 TRACE("(%p/%p)->()\n", This, iface);
1355
1356 return DSoundRender_AddRef((IBaseFilter*)This);
1357 }
1358
1359 static ULONG WINAPI AMDirectSound_Release(IAMDirectSound *iface)
1360 {
1361 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1362
1363 TRACE("(%p/%p)->()\n", This, iface);
1364
1365 return DSoundRender_Release((IBaseFilter*)This);
1366 }
1367
1368 /*** IAMDirectSound methods ***/
1369 static HRESULT WINAPI AMDirectSound_GetDirectSoundInterface(IAMDirectSound *iface, IDirectSound **ds)
1370 {
1371 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1372
1373 FIXME("(%p/%p)->(%p): stub\n", This, iface, ds);
1374
1375 return E_NOTIMPL;
1376 }
1377
1378 static HRESULT WINAPI AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf)
1379 {
1380 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1381
1382 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1383
1384 return E_NOTIMPL;
1385 }
1386
1387 static HRESULT WINAPI AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf)
1388 {
1389 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1390
1391 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1392
1393 return E_NOTIMPL;
1394 }
1395
1396 static HRESULT WINAPI AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound *iface, IDirectSound *ds)
1397 {
1398 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1399
1400 FIXME("(%p/%p)->(%p): stub\n", This, iface, ds);
1401
1402 return E_NOTIMPL;
1403 }
1404
1405 static HRESULT WINAPI AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf)
1406 {
1407 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1408
1409 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1410
1411 return E_NOTIMPL;
1412 }
1413
1414 static HRESULT WINAPI AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf)
1415 {
1416 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1417
1418 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1419
1420 return E_NOTIMPL;
1421 }
1422
1423 static HRESULT WINAPI AMDirectSound_SetFocusWindow(IAMDirectSound *iface, HWND hwnd, BOOL bgsilent)
1424 {
1425 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1426
1427 FIXME("(%p/%p)->(%p,%d): stub\n", This, iface, hwnd, bgsilent);
1428
1429 return E_NOTIMPL;
1430 }
1431
1432 static HRESULT WINAPI AMDirectSound_GetFocusWindow(IAMDirectSound *iface, HWND hwnd)
1433 {
1434 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1435
1436 FIXME("(%p/%p)->(%p): stub\n", This, iface, hwnd);
1437
1438 return E_NOTIMPL;
1439 }
1440
1441 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl =
1442 {
1443 AMDirectSound_QueryInterface,
1444 AMDirectSound_AddRef,
1445 AMDirectSound_Release,
1446 AMDirectSound_GetDirectSoundInterface,
1447 AMDirectSound_GetPrimaryBufferInterface,
1448 AMDirectSound_GetSecondaryBufferInterface,
1449 AMDirectSound_ReleaseDirectSoundInterface,
1450 AMDirectSound_ReleasePrimaryBufferInterface,
1451 AMDirectSound_ReleaseSecondaryBufferInterface,
1452 AMDirectSound_SetFocusWindow,
1453 AMDirectSound_GetFocusWindow
1454 };