vkd3d: Disable printf format checks.
[wine.git] / dlls / dmsynth / synthsink.c
blob9263ff56349693913706df5ffc7cf8a46f0398db
1 /*
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"
23 #include "initguid.h"
24 #include "uuids.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(dmsynth);
28 #define BUFFER_SUBDIVISIONS 100
30 struct synth_sink
32 IDirectMusicSynthSink IDirectMusicSynthSink_iface;
33 IKsControl IKsControl_iface;
34 IReferenceClock IReferenceClock_iface;
35 LONG ref;
37 IReferenceClock *master_clock;
38 IDirectMusicSynth *synth; /* No reference hold! */
39 IDirectSound *dsound;
40 IDirectSoundBuffer *dsound_buffer;
42 BOOL active;
43 REFERENCE_TIME activate_time;
45 CRITICAL_SECTION cs;
46 REFERENCE_TIME latency_time;
48 DWORD written; /* number of bytes written out */
49 HANDLE stop_event;
50 HANDLE render_thread;
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);
61 HRESULT hr;
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;
70 if (This->synth)
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;
81 void *data1, *data2;
82 HRESULT hr;
84 TRACE("sink %p, data %p, size %#lx\n", sink, data, size);
86 current_pos = sink->written % caps->dwBufferBytes;
88 if (sink->written)
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);
109 return hr;
112 if (!data)
114 memset(data1, format->wBitsPerSample == 8 ? 128 : 0, size1);
115 memset(data2, format->wBitsPerSample == 8 ? 128 : 0, size2);
117 else
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);
127 return hr;
130 sink->written += size;
131 TRACE("Written size %#lx, total %#lx\n", size, sink->written);
132 return S_OK;
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;
139 HRESULT hr;
141 if (FAILED(hr = IDirectSoundBuffer_GetCurrentPosition(buffer, &start_pos, NULL)))
143 ERR("IDirectSoundBuffer_GetCurrentPosition failed, hr %#lx\n", hr);
144 return 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;
151 for (;;)
153 DWORD ret;
155 if (FAILED(hr = IDirectSoundBuffer_GetCurrentPosition(buffer, &play_pos, NULL)))
157 ERR("IDirectSoundBuffer_GetCurrentPosition failed, hr %#lx\n", hr);
158 return 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);
169 break;
172 start_pos = play_pos;
175 return S_OK;
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;
182 HRESULT hr;
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);
196 return hr;
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;
215 WAVEFORMATEX format;
216 HANDLE buffer_event;
217 DWORD samples_size;
218 short *samples;
219 HRESULT hr;
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,
234 (void **)&notify)))
235 ERR("Failed to query IDirectSoundNotify iface, hr %#lx.\n", hr);
236 else
238 DSBPOSITIONNOTIFY positions[BUFFER_SUBDIVISIONS] = {{.dwOffset = 0, .hEventNotify = buffer_event}};
239 int i;
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");
258 goto done;
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};
271 DWORD ret;
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);
281 break;
285 if (FAILED(hr))
287 ERR("Thread unexpected termination, hr %#lx\n", hr);
288 return hr;
291 synth_sink_wait_play_end(sink, buffer, &caps, &format, buffer_event);
292 free(samples);
294 done:
295 IDirectSoundBuffer_Release(buffer);
296 IDirectMusicSynth_Release(synth);
297 CloseHandle(buffer_event);
299 return 0;
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;
307 WAVEFORMATEX format;
308 HRESULT hr;
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);
320 else
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, &params.buffer, NULL)))
331 ERR("Failed to create sound buffer, hr %#lx.\n", hr);
332 return hr;
336 params.sink = This;
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, &params, 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);
348 return hr;
351 WaitForSingleObject(params.started_event, INFINITE);
352 CloseHandle(params.started_event);
353 This->active = TRUE;
354 return S_OK;
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;
366 return S_OK;
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);
380 *ret_iface = iface;
381 return S_OK;
383 else if (IsEqualIID(riid, &IID_IKsControl))
385 IUnknown_AddRef(iface);
386 *ret_iface = &This->IKsControl_iface;
387 return S_OK;
390 *ret_iface = NULL;
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);
404 return 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);
414 if (!ref) {
415 if (This->active)
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);
424 free(This);
427 return ref;
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. */
439 This->synth = synth;
441 return S_OK;
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);
451 if (!clock)
452 return E_POINTER;
454 if (This->master_clock) IReferenceClock_Release(This->master_clock);
455 IReferenceClock_AddRef(clock);
456 This->master_clock = clock;
458 return S_OK;
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);
468 if (!clock)
469 return E_POINTER;
471 *clock = &This->IReferenceClock_iface;
472 IReferenceClock_AddRef(*clock);
474 return S_OK;
477 static HRESULT WINAPI synth_sink_Activate(IDirectMusicSynthSink *iface,
478 BOOL enable)
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);
491 WAVEFORMATEX format;
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;
500 return S_OK;
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);
507 WAVEFORMATEX format;
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;
517 return S_OK;
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);
530 This->dsound = NULL;
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);
539 return S_OK;
542 static HRESULT WINAPI synth_sink_GetDesiredBufferSize(IDirectMusicSynthSink *iface,
543 DWORD *size)
545 struct synth_sink *This = impl_from_IDirectMusicSynthSink(iface);
546 WAVEFORMATEX format;
547 DWORD fmtsize = sizeof(format);
549 TRACE("(%p, %p)\n", This, size);
551 if (!size)
552 return E_POINTER;
553 if (!This->synth)
554 return DMUS_E_SYNTHNOTCONFIGURED;
556 if (FAILED(IDirectMusicSynth_GetFormat(This->synth, &format, &fmtsize)))
557 return E_UNEXPECTED;
558 *size = format.nSamplesPerSec * format.nChannels * 4;
560 return S_OK;
563 static const IDirectMusicSynthSinkVtbl synth_sink_vtbl =
565 synth_sink_QueryInterface,
566 synth_sink_AddRef,
567 synth_sink_Release,
568 synth_sink_Init,
569 synth_sink_SetMasterClock,
570 synth_sink_GetLatencyClock,
571 synth_sink_Activate,
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);
614 return S_FALSE;
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);
625 else
627 FIXME("Unknown property %s\n", debugstr_guid(&Property->Set));
628 *(DWORD*)PropertyData = FALSE;
629 *BytesReturned = sizeof(DWORD);
632 return S_OK;
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);
640 return E_NOTIMPL;
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);
648 return E_NOTIMPL;
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);
675 *out = iface;
676 return S_OK;
679 FIXME("no interface for %s\n", debugstr_dmguid(iid));
680 *out = NULL;
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);
709 return S_OK;
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);
716 return E_NOTIMPL;
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);
723 return E_NOTIMPL;
726 static HRESULT WINAPI latency_clock_Unadvise(IReferenceClock *iface, DWORD_PTR cookie)
728 FIXME("(%p, %#Ix): stub\n", iface, cookie);
729 return E_NOTIMPL;
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);
749 *ret_iface = NULL;
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;
754 obj->ref = 1;
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;
762 return S_OK;