2 * IDirectMusicSynthSink Implementation
4 * Copyright (C) 2003-2004 Rok Mandeljc
5 * Copyright (C) 2012 Christian Costa
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "dmsynth_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(dmsynth
);
28 #define BUFFER_SUBDIVISIONS 100
32 IDirectMusicSynthSink IDirectMusicSynthSink_iface
;
33 IKsControl IKsControl_iface
;
34 IReferenceClock IReferenceClock_iface
;
37 IReferenceClock
*master_clock
;
38 IDirectMusicSynth
*synth
; /* No reference hold! */
40 IDirectSoundBuffer
*dsound_buffer
;
43 REFERENCE_TIME activate_time
;
46 REFERENCE_TIME latency_time
;
48 DWORD written
; /* number of bytes written out */
53 static inline struct synth_sink
*impl_from_IDirectMusicSynthSink(IDirectMusicSynthSink
*iface
)
55 return CONTAINING_RECORD(iface
, struct synth_sink
, IDirectMusicSynthSink_iface
);
58 static void synth_sink_get_format(struct synth_sink
*This
, WAVEFORMATEX
*format
)
60 DWORD size
= sizeof(*format
);
63 format
->wFormatTag
= WAVE_FORMAT_PCM
;
64 format
->nChannels
= 2;
65 format
->wBitsPerSample
= 16;
66 format
->nSamplesPerSec
= 22050;
67 format
->nBlockAlign
= format
->nChannels
* format
->wBitsPerSample
/ 8;
68 format
->nAvgBytesPerSec
= format
->nSamplesPerSec
* format
->nBlockAlign
;
72 if (FAILED(hr
= IDirectMusicSynth_GetFormat(This
->synth
, format
, &size
)))
73 WARN("Failed to get synth buffer format, hr %#lx\n", hr
);
77 static HRESULT
synth_sink_write_data(struct synth_sink
*sink
, IDirectSoundBuffer
*buffer
,
78 DSBCAPS
*caps
, WAVEFORMATEX
*format
, const void *data
, DWORD size
)
80 DWORD write_end
, size1
, size2
, current_pos
;
84 TRACE("sink %p, data %p, size %#lx\n", sink
, data
, size
);
86 current_pos
= sink
->written
% caps
->dwBufferBytes
;
90 DWORD play_pos
, write_pos
;
92 if (FAILED(hr
= IDirectSoundBuffer_GetCurrentPosition(buffer
, &play_pos
, &write_pos
))) return hr
;
94 if (current_pos
- play_pos
<= write_pos
- play_pos
)
96 ERR("Underrun detected, sink %p, play pos %#lx, write pos %#lx, current pos %#lx!\n",
97 buffer
, play_pos
, write_pos
, current_pos
);
98 current_pos
= write_pos
;
101 write_end
= (current_pos
+ size
) % caps
->dwBufferBytes
;
102 if (write_end
- current_pos
>= play_pos
- current_pos
) return S_FALSE
;
105 if (FAILED(hr
= IDirectSoundBuffer_Lock(buffer
, current_pos
, size
,
106 &data1
, &size1
, &data2
, &size2
, 0)))
108 ERR("IDirectSoundBuffer_Lock failed, hr %#lx\n", hr
);
114 memset(data1
, format
->wBitsPerSample
== 8 ? 128 : 0, size1
);
115 memset(data2
, format
->wBitsPerSample
== 8 ? 128 : 0, size2
);
119 memcpy(data1
, data
, size1
);
120 data
= (char *)data
+ size1
;
121 memcpy(data2
, data
, size2
);
124 if (FAILED(hr
= IDirectSoundBuffer_Unlock(buffer
, data1
, size1
, data2
, size2
)))
126 ERR("IDirectSoundBuffer_Unlock failed, hr %#lx\n", hr
);
130 sink
->written
+= size
;
131 TRACE("Written size %#lx, total %#lx\n", size
, sink
->written
);
135 static HRESULT
synth_sink_wait_play_end(struct synth_sink
*sink
, IDirectSoundBuffer
*buffer
,
136 DSBCAPS
*caps
, WAVEFORMATEX
*format
, HANDLE buffer_event
)
138 DWORD current_pos
, start_pos
, play_pos
, written
, played
= 0;
141 if (FAILED(hr
= IDirectSoundBuffer_GetCurrentPosition(buffer
, &start_pos
, NULL
)))
143 ERR("IDirectSoundBuffer_GetCurrentPosition failed, hr %#lx\n", hr
);
147 current_pos
= sink
->written
% caps
->dwBufferBytes
;
148 written
= current_pos
- start_pos
+ (current_pos
< start_pos
? caps
->dwBufferBytes
: 0);
149 if (FAILED(hr
= synth_sink_write_data(sink
, buffer
, caps
, format
, NULL
, caps
->dwBufferBytes
/ 2))) return hr
;
155 if (FAILED(hr
= IDirectSoundBuffer_GetCurrentPosition(buffer
, &play_pos
, NULL
)))
157 ERR("IDirectSoundBuffer_GetCurrentPosition failed, hr %#lx\n", hr
);
161 played
+= play_pos
- start_pos
+ (play_pos
< start_pos
? caps
->dwBufferBytes
: 0);
162 if (played
>= written
) break;
164 TRACE("Waiting for EOS, start_pos %#lx, play_pos %#lx, written %#lx, played %#lx\n",
165 start_pos
, play_pos
, written
, played
);
166 if ((ret
= WaitForMultipleObjects(1, &buffer_event
, FALSE
, INFINITE
)))
168 ERR("WaitForMultipleObjects returned %#lx\n", ret
);
172 start_pos
= play_pos
;
178 static HRESULT
synth_sink_render_data(struct synth_sink
*sink
, IDirectMusicSynth
*synth
,
179 IDirectSoundBuffer
*buffer
, WAVEFORMATEX
*format
, short *samples
, DWORD samples_size
)
181 REFERENCE_TIME sample_time
;
184 if (FAILED(hr
= IDirectMusicSynth_Render(synth
, samples
, samples_size
/ format
->nBlockAlign
,
185 sink
->written
/ format
->nBlockAlign
)))
186 ERR("Failed to render synthesizer samples, hr %#lx\n", hr
);
188 if (FAILED(hr
= IDirectMusicSynthSink_SampleToRefTime(&sink
->IDirectMusicSynthSink_iface
,
189 (sink
->written
+ samples_size
) / format
->nBlockAlign
, &sample_time
)))
190 ERR("Failed to convert sample position to time, hr %#lx\n", hr
);
192 EnterCriticalSection(&sink
->cs
);
193 sink
->latency_time
= sample_time
;
194 LeaveCriticalSection(&sink
->cs
);
199 struct render_thread_params
201 struct synth_sink
*sink
;
202 IDirectMusicSynth
*synth
;
203 IDirectSoundBuffer
*buffer
;
204 HANDLE started_event
;
207 static DWORD CALLBACK
synth_sink_render_thread(void *args
)
209 struct render_thread_params
*params
= args
;
210 DSBCAPS caps
= {.dwSize
= sizeof(DSBCAPS
)};
211 IDirectSoundBuffer
*buffer
= params
->buffer
;
212 IDirectMusicSynth
*synth
= params
->synth
;
213 struct synth_sink
*sink
= params
->sink
;
214 IDirectSoundNotify
*notify
;
221 TRACE("Starting thread, args %p\n", args
);
222 SetThreadDescription(GetCurrentThread(), L
"wine_dmsynth_sink");
224 if (FAILED(hr
= IDirectSoundBuffer_Stop(buffer
)))
225 ERR("Failed to stop sound buffer, hr %#lx.\n", hr
);
227 if (!(buffer_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
)))
228 ERR("Failed to create buffer event, error %lu\n", GetLastError());
229 else if (FAILED(hr
= IDirectSoundBuffer_GetCaps(buffer
, &caps
)))
230 ERR("Failed to query sound buffer caps, hr %#lx.\n", hr
);
231 else if (FAILED(hr
= IDirectSoundBuffer_GetFormat(buffer
, &format
, sizeof(format
), NULL
)))
232 ERR("Failed to query sound buffer format, hr %#lx.\n", hr
);
233 else if (FAILED(hr
= IDirectSoundBuffer_QueryInterface(buffer
, &IID_IDirectSoundNotify
,
235 ERR("Failed to query IDirectSoundNotify iface, hr %#lx.\n", hr
);
238 DSBPOSITIONNOTIFY positions
[BUFFER_SUBDIVISIONS
] = {{.dwOffset
= 0, .hEventNotify
= buffer_event
}};
241 for (i
= 1; i
< ARRAY_SIZE(positions
); ++i
)
243 positions
[i
] = positions
[i
- 1];
244 positions
[i
].dwOffset
+= caps
.dwBufferBytes
/ ARRAY_SIZE(positions
);
247 if (FAILED(hr
= IDirectSoundNotify_SetNotificationPositions(notify
,
248 ARRAY_SIZE(positions
), positions
)))
249 ERR("Failed to set notification positions, hr %#lx\n", hr
);
251 IDirectSoundNotify_Release(notify
);
254 samples_size
= caps
.dwBufferBytes
/ BUFFER_SUBDIVISIONS
;
255 if (!(samples
= malloc(samples_size
)))
257 ERR("Failed to allocate memory for samples\n");
261 if (FAILED(hr
= synth_sink_render_data(sink
, synth
, buffer
, &format
, samples
, samples_size
)))
262 ERR("Failed to render initial buffer data, hr %#lx.\n", hr
);
263 if (FAILED(hr
= IDirectSoundBuffer_Play(buffer
, 0, 0, DSBPLAY_LOOPING
)))
264 ERR("Failed to start sound buffer, hr %#lx.\n", hr
);
265 SetEvent(params
->started_event
);
267 while (SUCCEEDED(hr
) && SUCCEEDED(hr
= synth_sink_write_data(sink
, buffer
,
268 &caps
, &format
, samples
, samples_size
)))
270 HANDLE handles
[] = {sink
->stop_event
, buffer_event
};
273 if (hr
== S_OK
) /* if successfully written, render more data */
274 hr
= synth_sink_render_data(sink
, synth
, buffer
, &format
, samples
, samples_size
);
276 if (!(ret
= WaitForMultipleObjects(ARRAY_SIZE(handles
), handles
, FALSE
, INFINITE
))
277 || ret
>= ARRAY_SIZE(handles
))
279 ERR("WaitForMultipleObjects returned %lu\n", ret
);
280 hr
= HRESULT_FROM_WIN32(ret
);
287 ERR("Thread unexpected termination, hr %#lx\n", hr
);
291 synth_sink_wait_play_end(sink
, buffer
, &caps
, &format
, buffer_event
);
295 IDirectSoundBuffer_Release(buffer
);
296 IDirectMusicSynth_Release(synth
);
297 CloseHandle(buffer_event
);
302 static HRESULT
synth_sink_activate(struct synth_sink
*This
)
304 IDirectMusicSynthSink
*iface
= &This
->IDirectMusicSynthSink_iface
;
305 DSBUFFERDESC desc
= {.dwSize
= sizeof(DSBUFFERDESC
)};
306 struct render_thread_params params
;
310 if (!This
->synth
) return DMUS_E_SYNTHNOTCONFIGURED
;
311 if (!This
->dsound
) return DMUS_E_DSOUND_NOT_SET
;
312 if (!This
->master_clock
) return DMUS_E_NO_MASTER_CLOCK
;
313 if (This
->active
) return DMUS_E_SYNTHACTIVE
;
315 if (FAILED(hr
= IReferenceClock_GetTime(This
->master_clock
, &This
->activate_time
))) return hr
;
316 This
->latency_time
= This
->activate_time
;
318 if ((params
.buffer
= This
->dsound_buffer
))
319 IDirectMusicBuffer_AddRef(params
.buffer
);
322 synth_sink_get_format(This
, &format
);
323 desc
.lpwfxFormat
= &format
;
324 desc
.dwBufferBytes
= format
.nAvgBytesPerSec
;
325 if (FAILED(hr
= IDirectMusicSynthSink_GetDesiredBufferSize(iface
, &desc
.dwBufferBytes
)))
326 ERR("Failed to get desired buffer size, hr %#lx\n", hr
);
328 desc
.dwFlags
= DSBCAPS_GLOBALFOCUS
| DSBCAPS_GETCURRENTPOSITION2
| DSBCAPS_CTRLPOSITIONNOTIFY
;
329 if (FAILED(hr
= IDirectSound8_CreateSoundBuffer(This
->dsound
, &desc
, ¶ms
.buffer
, NULL
)))
331 ERR("Failed to create sound buffer, hr %#lx.\n", hr
);
337 params
.synth
= This
->synth
;
338 IDirectMusicSynth_AddRef(This
->synth
);
340 if (!(params
.started_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
))
341 || !(This
->render_thread
= CreateThread(NULL
, 0, synth_sink_render_thread
, ¶ms
, 0, NULL
)))
343 ERR("Failed to create render thread, error %lu\n", GetLastError());
344 hr
= HRESULT_FROM_WIN32(GetLastError());
345 IDirectSoundBuffer_Release(params
.buffer
);
346 IDirectMusicSynth_Release(params
.synth
);
347 CloseHandle(params
.started_event
);
351 WaitForSingleObject(params
.started_event
, INFINITE
);
352 CloseHandle(params
.started_event
);
357 static HRESULT
synth_sink_deactivate(struct synth_sink
*This
)
359 if (!This
->active
) return S_OK
;
361 SetEvent(This
->stop_event
);
362 WaitForSingleObject(This
->render_thread
, INFINITE
);
363 This
->render_thread
= NULL
;
364 This
->active
= FALSE
;
369 static HRESULT WINAPI
synth_sink_QueryInterface(IDirectMusicSynthSink
*iface
,
370 REFIID riid
, void **ret_iface
)
372 struct synth_sink
*This
= impl_from_IDirectMusicSynthSink(iface
);
374 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_dmguid(riid
), ret_iface
);
376 if (IsEqualIID (riid
, &IID_IUnknown
) ||
377 IsEqualIID (riid
, &IID_IDirectMusicSynthSink
))
379 IUnknown_AddRef(iface
);
383 else if (IsEqualIID(riid
, &IID_IKsControl
))
385 IUnknown_AddRef(iface
);
386 *ret_iface
= &This
->IKsControl_iface
;
392 WARN("(%p)->(%s, %p): not found\n", iface
, debugstr_dmguid(riid
), ret_iface
);
394 return E_NOINTERFACE
;
397 static ULONG WINAPI
synth_sink_AddRef(IDirectMusicSynthSink
*iface
)
399 struct synth_sink
*This
= impl_from_IDirectMusicSynthSink(iface
);
400 ULONG ref
= InterlockedIncrement(&This
->ref
);
402 TRACE("(%p): new ref = %lu\n", This
, ref
);
407 static ULONG WINAPI
synth_sink_Release(IDirectMusicSynthSink
*iface
)
409 struct synth_sink
*This
= impl_from_IDirectMusicSynthSink(iface
);
410 ULONG ref
= InterlockedDecrement(&This
->ref
);
412 TRACE("(%p): new ref = %lu\n", This
, ref
);
416 IDirectMusicSynthSink_Activate(iface
, FALSE
);
417 if (This
->master_clock
)
418 IReferenceClock_Release(This
->master_clock
);
420 This
->cs
.DebugInfo
->Spare
[0] = 0;
421 DeleteCriticalSection(&This
->cs
);
422 CloseHandle(This
->stop_event
);
430 static HRESULT WINAPI
synth_sink_Init(IDirectMusicSynthSink
*iface
,
431 IDirectMusicSynth
*synth
)
433 struct synth_sink
*This
= impl_from_IDirectMusicSynthSink(iface
);
435 TRACE("(%p)->(%p)\n", This
, synth
);
437 /* Not holding a reference to avoid circular dependencies.
438 The synth will release the sink during the synth's destruction. */
444 static HRESULT WINAPI
synth_sink_SetMasterClock(IDirectMusicSynthSink
*iface
,
445 IReferenceClock
*clock
)
447 struct synth_sink
*This
= impl_from_IDirectMusicSynthSink(iface
);
449 TRACE("(%p)->(%p)\n", This
, clock
);
454 if (This
->master_clock
) IReferenceClock_Release(This
->master_clock
);
455 IReferenceClock_AddRef(clock
);
456 This
->master_clock
= clock
;
461 static HRESULT WINAPI
synth_sink_GetLatencyClock(IDirectMusicSynthSink
*iface
,
462 IReferenceClock
**clock
)
464 struct synth_sink
*This
= impl_from_IDirectMusicSynthSink(iface
);
466 TRACE("(%p)->(%p)\n", iface
, clock
);
471 *clock
= &This
->IReferenceClock_iface
;
472 IReferenceClock_AddRef(*clock
);
477 static HRESULT WINAPI
synth_sink_Activate(IDirectMusicSynthSink
*iface
,
480 struct synth_sink
*This
= impl_from_IDirectMusicSynthSink(iface
);
482 FIXME("(%p)->(%d): semi-stub\n", This
, enable
);
484 return enable
? synth_sink_activate(This
) : synth_sink_deactivate(This
);
487 static HRESULT WINAPI
synth_sink_SampleToRefTime(IDirectMusicSynthSink
*iface
,
488 LONGLONG sample_time
, REFERENCE_TIME
*ref_time
)
490 struct synth_sink
*This
= impl_from_IDirectMusicSynthSink(iface
);
493 TRACE("(%p)->(%I64d, %p)\n", This
, sample_time
, ref_time
);
495 if (!ref_time
) return E_POINTER
;
497 synth_sink_get_format(This
, &format
);
498 *ref_time
= This
->activate_time
+ ((sample_time
* 10000) / format
.nSamplesPerSec
) * 1000;
503 static HRESULT WINAPI
synth_sink_RefTimeToSample(IDirectMusicSynthSink
*iface
,
504 REFERENCE_TIME ref_time
, LONGLONG
*sample_time
)
506 struct synth_sink
*This
= impl_from_IDirectMusicSynthSink(iface
);
509 TRACE("(%p)->(%I64d, %p)\n", This
, ref_time
, sample_time
);
511 if (!sample_time
) return E_POINTER
;
513 synth_sink_get_format(This
, &format
);
514 ref_time
-= This
->activate_time
;
515 *sample_time
= ((ref_time
/ 1000) * format
.nSamplesPerSec
) / 10000;
520 static HRESULT WINAPI
synth_sink_SetDirectSound(IDirectMusicSynthSink
*iface
,
521 IDirectSound
*dsound
, IDirectSoundBuffer
*dsound_buffer
)
523 struct synth_sink
*This
= impl_from_IDirectMusicSynthSink(iface
);
525 TRACE("(%p)->(%p, %p)\n", This
, dsound
, dsound_buffer
);
527 if (This
->active
) return DMUS_E_SYNTHACTIVE
;
529 if (This
->dsound
) IDirectSound_Release(This
->dsound
);
531 if (This
->dsound_buffer
) IDirectSoundBuffer_Release(This
->dsound_buffer
);
532 This
->dsound_buffer
= NULL
;
533 if (!dsound
) return S_OK
;
535 if (!This
->synth
) return DMUS_E_SYNTHNOTCONFIGURED
;
536 if ((This
->dsound
= dsound
)) IDirectSound_AddRef(This
->dsound
);
537 if ((This
->dsound_buffer
= dsound_buffer
)) IDirectSoundBuffer_AddRef(This
->dsound_buffer
);
542 static HRESULT WINAPI
synth_sink_GetDesiredBufferSize(IDirectMusicSynthSink
*iface
,
545 struct synth_sink
*This
= impl_from_IDirectMusicSynthSink(iface
);
547 DWORD fmtsize
= sizeof(format
);
549 TRACE("(%p, %p)\n", This
, size
);
554 return DMUS_E_SYNTHNOTCONFIGURED
;
556 if (FAILED(IDirectMusicSynth_GetFormat(This
->synth
, &format
, &fmtsize
)))
558 *size
= format
.nSamplesPerSec
* format
.nChannels
* 4;
563 static const IDirectMusicSynthSinkVtbl synth_sink_vtbl
=
565 synth_sink_QueryInterface
,
569 synth_sink_SetMasterClock
,
570 synth_sink_GetLatencyClock
,
572 synth_sink_SampleToRefTime
,
573 synth_sink_RefTimeToSample
,
574 synth_sink_SetDirectSound
,
575 synth_sink_GetDesiredBufferSize
,
578 static inline struct synth_sink
*impl_from_IKsControl(IKsControl
*iface
)
580 return CONTAINING_RECORD(iface
, struct synth_sink
, IKsControl_iface
);
583 static HRESULT WINAPI
synth_sink_control_QueryInterface(IKsControl
* iface
, REFIID riid
, LPVOID
*ppobj
)
585 struct synth_sink
*This
= impl_from_IKsControl(iface
);
587 return synth_sink_QueryInterface(&This
->IDirectMusicSynthSink_iface
, riid
, ppobj
);
590 static ULONG WINAPI
synth_sink_control_AddRef(IKsControl
* iface
)
592 struct synth_sink
*This
= impl_from_IKsControl(iface
);
594 return synth_sink_AddRef(&This
->IDirectMusicSynthSink_iface
);
597 static ULONG WINAPI
synth_sink_control_Release(IKsControl
* iface
)
599 struct synth_sink
*This
= impl_from_IKsControl(iface
);
601 return synth_sink_Release(&This
->IDirectMusicSynthSink_iface
);
604 static HRESULT WINAPI
synth_sink_control_KsProperty(IKsControl
* iface
, PKSPROPERTY Property
,
605 ULONG PropertyLength
, LPVOID PropertyData
, ULONG DataLength
, ULONG
* BytesReturned
)
607 TRACE("(%p, %p, %lu, %p, %lu, %p)\n", iface
, Property
, PropertyLength
, PropertyData
, DataLength
, BytesReturned
);
609 TRACE("Property = %s - %lu - %lu\n", debugstr_guid(&Property
->Set
), Property
->Id
, Property
->Flags
);
611 if (Property
->Flags
!= KSPROPERTY_TYPE_GET
)
613 FIXME("Property flags %lu not yet supported\n", Property
->Flags
);
617 if (DataLength
< sizeof(DWORD
))
618 return E_NOT_SUFFICIENT_BUFFER
;
620 if (IsEqualGUID(&Property
->Set
, &GUID_DMUS_PROP_SinkUsesDSound
))
622 *(DWORD
*)PropertyData
= TRUE
;
623 *BytesReturned
= sizeof(DWORD
);
627 FIXME("Unknown property %s\n", debugstr_guid(&Property
->Set
));
628 *(DWORD
*)PropertyData
= FALSE
;
629 *BytesReturned
= sizeof(DWORD
);
635 static HRESULT WINAPI
synth_sink_control_KsMethod(IKsControl
* iface
, PKSMETHOD Method
,
636 ULONG MethodLength
, LPVOID MethodData
, ULONG DataLength
, ULONG
* BytesReturned
)
638 FIXME("(%p, %p, %lu, %p, %lu, %p): stub\n", iface
, Method
, MethodLength
, MethodData
, DataLength
, BytesReturned
);
643 static HRESULT WINAPI
synth_sink_control_KsEvent(IKsControl
* iface
, PKSEVENT Event
,
644 ULONG EventLength
, LPVOID EventData
, ULONG DataLength
, ULONG
* BytesReturned
)
646 FIXME("(%p, %p, %lu, %p, %lu, %p): stub\n", iface
, Event
, EventLength
, EventData
, DataLength
, BytesReturned
);
652 static const IKsControlVtbl synth_sink_control
=
654 synth_sink_control_QueryInterface
,
655 synth_sink_control_AddRef
,
656 synth_sink_control_Release
,
657 synth_sink_control_KsProperty
,
658 synth_sink_control_KsMethod
,
659 synth_sink_control_KsEvent
,
662 static inline struct synth_sink
*impl_from_IReferenceClock(IReferenceClock
*iface
)
664 return CONTAINING_RECORD(iface
, struct synth_sink
, IReferenceClock_iface
);
667 static HRESULT WINAPI
latency_clock_QueryInterface(IReferenceClock
*iface
, REFIID iid
, void **out
)
669 TRACE("(%p, %s, %p)\n", iface
, debugstr_dmguid(iid
), out
);
671 if (IsEqualIID(iid
, &IID_IUnknown
)
672 || IsEqualIID(iid
, &IID_IReferenceClock
))
674 IUnknown_AddRef(iface
);
679 FIXME("no interface for %s\n", debugstr_dmguid(iid
));
681 return E_NOINTERFACE
;
684 static ULONG WINAPI
latency_clock_AddRef(IReferenceClock
*iface
)
686 struct synth_sink
*This
= impl_from_IReferenceClock(iface
);
687 return IDirectMusicSynthSink_AddRef(&This
->IDirectMusicSynthSink_iface
);
690 static ULONG WINAPI
latency_clock_Release(IReferenceClock
*iface
)
692 struct synth_sink
*This
= impl_from_IReferenceClock(iface
);
693 return IDirectMusicSynthSink_Release(&This
->IDirectMusicSynthSink_iface
);
696 static HRESULT WINAPI
latency_clock_GetTime(IReferenceClock
*iface
, REFERENCE_TIME
*time
)
698 struct synth_sink
*This
= impl_from_IReferenceClock(iface
);
700 TRACE("(%p, %p)\n", iface
, time
);
702 if (!time
) return E_INVALIDARG
;
703 if (!This
->active
) return E_FAIL
;
705 EnterCriticalSection(&This
->cs
);
706 *time
= This
->latency_time
;
707 LeaveCriticalSection(&This
->cs
);
712 static HRESULT WINAPI
latency_clock_AdviseTime(IReferenceClock
*iface
, REFERENCE_TIME base
,
713 REFERENCE_TIME offset
, HEVENT event
, DWORD_PTR
*cookie
)
715 FIXME("(%p, %I64d, %I64d, %#Ix, %p): stub\n", iface
, base
, offset
, event
, cookie
);
719 static HRESULT WINAPI
latency_clock_AdvisePeriodic(IReferenceClock
*iface
, REFERENCE_TIME start
,
720 REFERENCE_TIME period
, HSEMAPHORE semaphore
, DWORD_PTR
*cookie
)
722 FIXME("(%p, %I64d, %I64d, %#Ix, %p): stub\n", iface
, start
, period
, semaphore
, cookie
);
726 static HRESULT WINAPI
latency_clock_Unadvise(IReferenceClock
*iface
, DWORD_PTR cookie
)
728 FIXME("(%p, %#Ix): stub\n", iface
, cookie
);
732 static const IReferenceClockVtbl latency_clock_vtbl
=
734 latency_clock_QueryInterface
,
735 latency_clock_AddRef
,
736 latency_clock_Release
,
737 latency_clock_GetTime
,
738 latency_clock_AdviseTime
,
739 latency_clock_AdvisePeriodic
,
740 latency_clock_Unadvise
,
743 HRESULT
synth_sink_create(IUnknown
**ret_iface
)
745 struct synth_sink
*obj
;
747 TRACE("(%p)\n", ret_iface
);
750 if (!(obj
= calloc(1, sizeof(*obj
)))) return E_OUTOFMEMORY
;
751 obj
->IDirectMusicSynthSink_iface
.lpVtbl
= &synth_sink_vtbl
;
752 obj
->IKsControl_iface
.lpVtbl
= &synth_sink_control
;
753 obj
->IReferenceClock_iface
.lpVtbl
= &latency_clock_vtbl
;
756 obj
->stop_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
757 InitializeCriticalSection(&obj
->cs
);
758 obj
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": cs");
760 TRACE("Created DirectMusicSynthSink %p\n", obj
);
761 *ret_iface
= (IUnknown
*)&obj
->IDirectMusicSynthSink_iface
;