mf: Preroll on sink start.
[wine.git] / dlls / mf / sar.c
blob5f035a801ce03f51b59f47f018e2146d3e182a6e
1 /*
2 * Copyright 2019 Nikolay Sivov for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include "mfapi.h"
22 #include "mfidl.h"
23 #include "mferror.h"
24 #include "mf_private.h"
25 #include "initguid.h"
26 #include "mmdeviceapi.h"
27 #include "audioclient.h"
29 #include "wine/debug.h"
30 #include "wine/heap.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
34 enum stream_state
36 STREAM_STATE_STOPPED = 0,
37 STREAM_STATE_RUNNING,
38 STREAM_STATE_PAUSED,
41 enum audio_renderer_flags
43 SAR_SHUT_DOWN = 0x1,
44 SAR_PREROLLED = 0x2,
47 struct audio_renderer
49 IMFMediaSink IMFMediaSink_iface;
50 IMFMediaSinkPreroll IMFMediaSinkPreroll_iface;
51 IMFStreamSink IMFStreamSink_iface;
52 IMFMediaTypeHandler IMFMediaTypeHandler_iface;
53 IMFClockStateSink IMFClockStateSink_iface;
54 IMFMediaEventGenerator IMFMediaEventGenerator_iface;
55 IMFGetService IMFGetService_iface;
56 IMFSimpleAudioVolume IMFSimpleAudioVolume_iface;
57 IMFAudioStreamVolume IMFAudioStreamVolume_iface;
58 IMFAudioPolicy IMFAudioPolicy_iface;
59 LONG refcount;
60 IMFMediaEventQueue *event_queue;
61 IMFMediaEventQueue *stream_event_queue;
62 IMFPresentationClock *clock;
63 IMFMediaType *media_type;
64 IMFMediaType *current_media_type;
65 IMMDevice *device;
66 IAudioClient *audio_client;
67 IAudioStreamVolume *stream_volume;
68 ISimpleAudioVolume *audio_volume;
69 HANDLE buffer_ready_event;
70 enum stream_state state;
71 unsigned int flags;
72 CRITICAL_SECTION cs;
75 static struct audio_renderer *impl_from_IMFMediaSink(IMFMediaSink *iface)
77 return CONTAINING_RECORD(iface, struct audio_renderer, IMFMediaSink_iface);
80 static struct audio_renderer *impl_from_IMFMediaSinkPreroll(IMFMediaSinkPreroll *iface)
82 return CONTAINING_RECORD(iface, struct audio_renderer, IMFMediaSinkPreroll_iface);
85 static struct audio_renderer *impl_from_IMFClockStateSink(IMFClockStateSink *iface)
87 return CONTAINING_RECORD(iface, struct audio_renderer, IMFClockStateSink_iface);
90 static struct audio_renderer *impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator *iface)
92 return CONTAINING_RECORD(iface, struct audio_renderer, IMFMediaEventGenerator_iface);
95 static struct audio_renderer *impl_from_IMFGetService(IMFGetService *iface)
97 return CONTAINING_RECORD(iface, struct audio_renderer, IMFGetService_iface);
100 static struct audio_renderer *impl_from_IMFSimpleAudioVolume(IMFSimpleAudioVolume *iface)
102 return CONTAINING_RECORD(iface, struct audio_renderer, IMFSimpleAudioVolume_iface);
105 static struct audio_renderer *impl_from_IMFAudioStreamVolume(IMFAudioStreamVolume *iface)
107 return CONTAINING_RECORD(iface, struct audio_renderer, IMFAudioStreamVolume_iface);
110 static struct audio_renderer *impl_from_IMFAudioPolicy(IMFAudioPolicy *iface)
112 return CONTAINING_RECORD(iface, struct audio_renderer, IMFAudioPolicy_iface);
115 static struct audio_renderer *impl_from_IMFStreamSink(IMFStreamSink *iface)
117 return CONTAINING_RECORD(iface, struct audio_renderer, IMFStreamSink_iface);
120 static struct audio_renderer *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler *iface)
122 return CONTAINING_RECORD(iface, struct audio_renderer, IMFMediaTypeHandler_iface);
125 static HRESULT WINAPI audio_renderer_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj)
127 struct audio_renderer *renderer = impl_from_IMFMediaSink(iface);
129 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
131 if (IsEqualIID(riid, &IID_IMFMediaSink) ||
132 IsEqualIID(riid, &IID_IUnknown))
134 *obj = iface;
136 else if (IsEqualIID(riid, &IID_IMFMediaSinkPreroll))
138 *obj = &renderer->IMFMediaSinkPreroll_iface;
140 else if (IsEqualIID(riid, &IID_IMFClockStateSink))
142 *obj = &renderer->IMFClockStateSink_iface;
144 else if (IsEqualIID(riid, &IID_IMFMediaEventGenerator))
146 *obj = &renderer->IMFMediaEventGenerator_iface;
148 else if (IsEqualIID(riid, &IID_IMFGetService))
150 *obj = &renderer->IMFGetService_iface;
152 else
154 WARN("Unsupported %s.\n", debugstr_guid(riid));
155 *obj = NULL;
156 return E_NOINTERFACE;
159 IUnknown_AddRef((IUnknown *)*obj);
161 return S_OK;
164 static ULONG WINAPI audio_renderer_sink_AddRef(IMFMediaSink *iface)
166 struct audio_renderer *renderer = impl_from_IMFMediaSink(iface);
167 ULONG refcount = InterlockedIncrement(&renderer->refcount);
168 TRACE("%p, refcount %u.\n", iface, refcount);
169 return refcount;
172 static void audio_renderer_release_audio_client(struct audio_renderer *renderer)
174 if (renderer->audio_client)
175 IAudioClient_Release(renderer->audio_client);
176 renderer->audio_client = NULL;
177 if (renderer->stream_volume)
178 IAudioStreamVolume_Release(renderer->stream_volume);
179 renderer->stream_volume = NULL;
180 if (renderer->audio_volume)
181 ISimpleAudioVolume_Release(renderer->audio_volume);
182 renderer->audio_volume = NULL;
183 renderer->flags &= ~SAR_PREROLLED;
186 static ULONG WINAPI audio_renderer_sink_Release(IMFMediaSink *iface)
188 struct audio_renderer *renderer = impl_from_IMFMediaSink(iface);
189 ULONG refcount = InterlockedDecrement(&renderer->refcount);
191 TRACE("%p, refcount %u.\n", iface, refcount);
193 if (!refcount)
195 if (renderer->event_queue)
196 IMFMediaEventQueue_Release(renderer->event_queue);
197 if (renderer->stream_event_queue)
198 IMFMediaEventQueue_Release(renderer->stream_event_queue);
199 if (renderer->clock)
200 IMFPresentationClock_Release(renderer->clock);
201 if (renderer->device)
202 IMMDevice_Release(renderer->device);
203 if (renderer->media_type)
204 IMFMediaType_Release(renderer->media_type);
205 if (renderer->current_media_type)
206 IMFMediaType_Release(renderer->current_media_type);
207 CloseHandle(renderer->buffer_ready_event);
208 audio_renderer_release_audio_client(renderer);
209 DeleteCriticalSection(&renderer->cs);
210 heap_free(renderer);
213 return refcount;
216 static HRESULT WINAPI audio_renderer_sink_GetCharacteristics(IMFMediaSink *iface, DWORD *flags)
218 struct audio_renderer *renderer = impl_from_IMFMediaSink(iface);
220 TRACE("%p, %p.\n", iface, flags);
222 if (renderer->flags & SAR_SHUT_DOWN)
223 return MF_E_SHUTDOWN;
225 *flags = MEDIASINK_FIXED_STREAMS | MEDIASINK_CAN_PREROLL;
227 return S_OK;
230 static HRESULT WINAPI audio_renderer_sink_AddStreamSink(IMFMediaSink *iface, DWORD stream_sink_id,
231 IMFMediaType *media_type, IMFStreamSink **stream_sink)
233 struct audio_renderer *renderer = impl_from_IMFMediaSink(iface);
235 TRACE("%p, %#x, %p, %p.\n", iface, stream_sink_id, media_type, stream_sink);
237 return renderer->flags & SAR_SHUT_DOWN ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
240 static HRESULT WINAPI audio_renderer_sink_RemoveStreamSink(IMFMediaSink *iface, DWORD stream_sink_id)
242 struct audio_renderer *renderer = impl_from_IMFMediaSink(iface);
244 TRACE("%p, %#x.\n", iface, stream_sink_id);
246 return renderer->flags & SAR_SHUT_DOWN ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
249 static HRESULT WINAPI audio_renderer_sink_GetStreamSinkCount(IMFMediaSink *iface, DWORD *count)
251 struct audio_renderer *renderer = impl_from_IMFMediaSink(iface);
253 TRACE("%p, %p.\n", iface, count);
255 if (!count)
256 return E_POINTER;
258 if (renderer->flags & SAR_SHUT_DOWN)
259 return MF_E_SHUTDOWN;
261 *count = 1;
263 return S_OK;
266 static HRESULT WINAPI audio_renderer_sink_GetStreamSinkByIndex(IMFMediaSink *iface, DWORD index,
267 IMFStreamSink **stream)
269 struct audio_renderer *renderer = impl_from_IMFMediaSink(iface);
270 HRESULT hr = S_OK;
272 TRACE("%p, %u, %p.\n", iface, index, stream);
274 EnterCriticalSection(&renderer->cs);
276 if (renderer->flags & SAR_SHUT_DOWN)
277 hr = MF_E_SHUTDOWN;
278 else if (index > 0)
279 hr = MF_E_INVALIDINDEX;
280 else
282 *stream = &renderer->IMFStreamSink_iface;
283 IMFStreamSink_AddRef(*stream);
286 LeaveCriticalSection(&renderer->cs);
288 return hr;
291 static HRESULT WINAPI audio_renderer_sink_GetStreamSinkById(IMFMediaSink *iface, DWORD stream_sink_id,
292 IMFStreamSink **stream)
294 struct audio_renderer *renderer = impl_from_IMFMediaSink(iface);
295 HRESULT hr = S_OK;
297 TRACE("%p, %#x, %p.\n", iface, stream_sink_id, stream);
299 EnterCriticalSection(&renderer->cs);
301 if (renderer->flags & SAR_SHUT_DOWN)
302 hr = MF_E_SHUTDOWN;
303 else if (stream_sink_id > 0)
304 hr = MF_E_INVALIDSTREAMNUMBER;
305 else
307 *stream = &renderer->IMFStreamSink_iface;
308 IMFStreamSink_AddRef(*stream);
311 LeaveCriticalSection(&renderer->cs);
313 return hr;
316 static void audio_renderer_set_presentation_clock(struct audio_renderer *renderer, IMFPresentationClock *clock)
318 if (renderer->clock)
320 IMFPresentationClock_RemoveClockStateSink(renderer->clock, &renderer->IMFClockStateSink_iface);
321 IMFPresentationClock_Release(renderer->clock);
323 renderer->clock = clock;
324 if (renderer->clock)
326 IMFPresentationClock_AddRef(renderer->clock);
327 IMFPresentationClock_AddClockStateSink(renderer->clock, &renderer->IMFClockStateSink_iface);
331 static HRESULT WINAPI audio_renderer_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock)
333 struct audio_renderer *renderer = impl_from_IMFMediaSink(iface);
334 HRESULT hr = S_OK;
336 TRACE("%p, %p.\n", iface, clock);
338 EnterCriticalSection(&renderer->cs);
340 if (renderer->flags & SAR_SHUT_DOWN)
341 hr = MF_E_SHUTDOWN;
342 else
343 audio_renderer_set_presentation_clock(renderer, clock);
345 LeaveCriticalSection(&renderer->cs);
347 return hr;
350 static HRESULT WINAPI audio_renderer_sink_GetPresentationClock(IMFMediaSink *iface, IMFPresentationClock **clock)
352 struct audio_renderer *renderer = impl_from_IMFMediaSink(iface);
353 HRESULT hr = S_OK;
355 TRACE("%p, %p.\n", iface, clock);
357 if (!clock)
358 return E_POINTER;
360 EnterCriticalSection(&renderer->cs);
362 if (renderer->flags & SAR_SHUT_DOWN)
363 hr = MF_E_SHUTDOWN;
364 else if (renderer->clock)
366 *clock = renderer->clock;
367 IMFPresentationClock_AddRef(*clock);
369 else
370 hr = MF_E_NO_CLOCK;
372 LeaveCriticalSection(&renderer->cs);
374 return hr;
377 static HRESULT WINAPI audio_renderer_sink_Shutdown(IMFMediaSink *iface)
379 struct audio_renderer *renderer = impl_from_IMFMediaSink(iface);
381 TRACE("%p.\n", iface);
383 if (renderer->flags & SAR_SHUT_DOWN)
384 return MF_E_SHUTDOWN;
386 EnterCriticalSection(&renderer->cs);
387 renderer->flags |= SAR_SHUT_DOWN;
388 IMFMediaEventQueue_Shutdown(renderer->event_queue);
389 IMFMediaEventQueue_Shutdown(renderer->stream_event_queue);
390 audio_renderer_set_presentation_clock(renderer, NULL);
391 LeaveCriticalSection(&renderer->cs);
393 return S_OK;
396 static const IMFMediaSinkVtbl audio_renderer_sink_vtbl =
398 audio_renderer_sink_QueryInterface,
399 audio_renderer_sink_AddRef,
400 audio_renderer_sink_Release,
401 audio_renderer_sink_GetCharacteristics,
402 audio_renderer_sink_AddStreamSink,
403 audio_renderer_sink_RemoveStreamSink,
404 audio_renderer_sink_GetStreamSinkCount,
405 audio_renderer_sink_GetStreamSinkByIndex,
406 audio_renderer_sink_GetStreamSinkById,
407 audio_renderer_sink_SetPresentationClock,
408 audio_renderer_sink_GetPresentationClock,
409 audio_renderer_sink_Shutdown,
412 static void audio_renderer_preroll(struct audio_renderer *renderer)
414 unsigned int i;
416 if (renderer->flags & SAR_PREROLLED)
417 return;
419 for (i = 0; i < 2; ++i)
420 IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL);
421 renderer->flags |= SAR_PREROLLED;
424 static HRESULT WINAPI audio_renderer_preroll_QueryInterface(IMFMediaSinkPreroll *iface, REFIID riid, void **obj)
426 struct audio_renderer *renderer = impl_from_IMFMediaSinkPreroll(iface);
427 return IMFMediaSink_QueryInterface(&renderer->IMFMediaSink_iface, riid, obj);
430 static ULONG WINAPI audio_renderer_preroll_AddRef(IMFMediaSinkPreroll *iface)
432 struct audio_renderer *renderer = impl_from_IMFMediaSinkPreroll(iface);
433 return IMFMediaSink_AddRef(&renderer->IMFMediaSink_iface);
436 static ULONG WINAPI audio_renderer_preroll_Release(IMFMediaSinkPreroll *iface)
438 struct audio_renderer *renderer = impl_from_IMFMediaSinkPreroll(iface);
439 return IMFMediaSink_Release(&renderer->IMFMediaSink_iface);
442 static HRESULT WINAPI audio_renderer_preroll_NotifyPreroll(IMFMediaSinkPreroll *iface, MFTIME start_time)
444 struct audio_renderer *renderer = impl_from_IMFMediaSinkPreroll(iface);
446 TRACE("%p, %s.\n", iface, debugstr_time(start_time));
448 if (renderer->flags & SAR_SHUT_DOWN)
449 return MF_E_SHUTDOWN;
451 audio_renderer_preroll(renderer);
452 return IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkPrerolled, &GUID_NULL, S_OK, NULL);
455 static const IMFMediaSinkPrerollVtbl audio_renderer_preroll_vtbl =
457 audio_renderer_preroll_QueryInterface,
458 audio_renderer_preroll_AddRef,
459 audio_renderer_preroll_Release,
460 audio_renderer_preroll_NotifyPreroll,
463 static HRESULT WINAPI audio_renderer_events_QueryInterface(IMFMediaEventGenerator *iface, REFIID riid, void **obj)
465 struct audio_renderer *renderer = impl_from_IMFMediaEventGenerator(iface);
466 return IMFMediaSink_QueryInterface(&renderer->IMFMediaSink_iface, riid, obj);
469 static ULONG WINAPI audio_renderer_events_AddRef(IMFMediaEventGenerator *iface)
471 struct audio_renderer *renderer = impl_from_IMFMediaEventGenerator(iface);
472 return IMFMediaSink_AddRef(&renderer->IMFMediaSink_iface);
475 static ULONG WINAPI audio_renderer_events_Release(IMFMediaEventGenerator *iface)
477 struct audio_renderer *renderer = impl_from_IMFMediaEventGenerator(iface);
478 return IMFMediaSink_Release(&renderer->IMFMediaSink_iface);
481 static HRESULT WINAPI audio_renderer_events_GetEvent(IMFMediaEventGenerator *iface, DWORD flags, IMFMediaEvent **event)
483 struct audio_renderer *renderer = impl_from_IMFMediaEventGenerator(iface);
485 TRACE("%p, %#x, %p.\n", iface, flags, event);
487 return IMFMediaEventQueue_GetEvent(renderer->event_queue, flags, event);
490 static HRESULT WINAPI audio_renderer_events_BeginGetEvent(IMFMediaEventGenerator *iface, IMFAsyncCallback *callback,
491 IUnknown *state)
493 struct audio_renderer *renderer = impl_from_IMFMediaEventGenerator(iface);
495 TRACE("%p, %p, %p.\n", iface, callback, state);
497 return IMFMediaEventQueue_BeginGetEvent(renderer->event_queue, callback, state);
500 static HRESULT WINAPI audio_renderer_events_EndGetEvent(IMFMediaEventGenerator *iface, IMFAsyncResult *result,
501 IMFMediaEvent **event)
503 struct audio_renderer *renderer = impl_from_IMFMediaEventGenerator(iface);
505 TRACE("%p, %p, %p.\n", iface, result, event);
507 return IMFMediaEventQueue_EndGetEvent(renderer->event_queue, result, event);
510 static HRESULT WINAPI audio_renderer_events_QueueEvent(IMFMediaEventGenerator *iface, MediaEventType event_type,
511 REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
513 struct audio_renderer *renderer = impl_from_IMFMediaEventGenerator(iface);
515 TRACE("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
517 return IMFMediaEventQueue_QueueEventParamVar(renderer->event_queue, event_type, ext_type, hr, value);
520 static const IMFMediaEventGeneratorVtbl audio_renderer_events_vtbl =
522 audio_renderer_events_QueryInterface,
523 audio_renderer_events_AddRef,
524 audio_renderer_events_Release,
525 audio_renderer_events_GetEvent,
526 audio_renderer_events_BeginGetEvent,
527 audio_renderer_events_EndGetEvent,
528 audio_renderer_events_QueueEvent,
531 static HRESULT WINAPI audio_renderer_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj)
533 struct audio_renderer *renderer = impl_from_IMFClockStateSink(iface);
534 return IMFMediaSink_QueryInterface(&renderer->IMFMediaSink_iface, riid, obj);
537 static ULONG WINAPI audio_renderer_clock_sink_AddRef(IMFClockStateSink *iface)
539 struct audio_renderer *renderer = impl_from_IMFClockStateSink(iface);
540 return IMFMediaSink_AddRef(&renderer->IMFMediaSink_iface);
543 static ULONG WINAPI audio_renderer_clock_sink_Release(IMFClockStateSink *iface)
545 struct audio_renderer *renderer = impl_from_IMFClockStateSink(iface);
546 return IMFMediaSink_Release(&renderer->IMFMediaSink_iface);
549 static HRESULT WINAPI audio_renderer_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset)
551 struct audio_renderer *renderer = impl_from_IMFClockStateSink(iface);
552 HRESULT hr = S_OK;
554 TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), debugstr_time(offset));
556 EnterCriticalSection(&renderer->cs);
557 if (renderer->audio_client)
559 if (renderer->state == STREAM_STATE_STOPPED)
561 if (FAILED(hr = IAudioClient_Start(renderer->audio_client)))
562 WARN("Failed to start audio client, hr %#x.\n", hr);
563 renderer->state = STREAM_STATE_RUNNING;
566 else
567 hr = MF_E_NOT_INITIALIZED;
569 IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, hr, NULL);
570 if (SUCCEEDED(hr))
571 audio_renderer_preroll(renderer);
572 LeaveCriticalSection(&renderer->cs);
574 return hr;
577 static HRESULT WINAPI audio_renderer_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime)
579 struct audio_renderer *renderer = impl_from_IMFClockStateSink(iface);
580 HRESULT hr = S_OK;
582 TRACE("%p, %s.\n", iface, debugstr_time(systime));
584 EnterCriticalSection(&renderer->cs);
585 if (renderer->audio_client)
587 if (renderer->state != STREAM_STATE_STOPPED)
589 if (SUCCEEDED(hr = IAudioClient_Stop(renderer->audio_client)))
591 if (FAILED(hr = IAudioClient_Reset(renderer->audio_client)))
592 WARN("Failed to reset audio client, hr %#x.\n", hr);
594 else
595 WARN("Failed to stop audio client, hr %#x.\n", hr);
596 renderer->state = STREAM_STATE_STOPPED;
597 renderer->flags &= ~SAR_PREROLLED;
600 else
601 hr = MF_E_NOT_INITIALIZED;
603 IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStopped, &GUID_NULL, hr, NULL);
604 LeaveCriticalSection(&renderer->cs);
606 return hr;
609 static HRESULT WINAPI audio_renderer_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime)
611 struct audio_renderer *renderer = impl_from_IMFClockStateSink(iface);
612 HRESULT hr;
614 TRACE("%p, %s.\n", iface, debugstr_time(systime));
616 EnterCriticalSection(&renderer->cs);
617 if (renderer->state == STREAM_STATE_RUNNING)
619 if (renderer->audio_client)
621 if (FAILED(hr = IAudioClient_Stop(renderer->audio_client)))
622 WARN("Failed to stop audio client, hr %#x.\n", hr);
623 renderer->state = STREAM_STATE_PAUSED;
625 else
626 hr = MF_E_NOT_INITIALIZED;
628 IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkPaused, &GUID_NULL, hr, NULL);
630 else
631 hr = MF_E_INVALID_STATE_TRANSITION;
632 LeaveCriticalSection(&renderer->cs);
634 return hr;
637 static HRESULT WINAPI audio_renderer_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime)
639 struct audio_renderer *renderer = impl_from_IMFClockStateSink(iface);
640 BOOL preroll = FALSE;
641 HRESULT hr = S_OK;
643 TRACE("%p, %s.\n", iface, debugstr_time(systime));
645 EnterCriticalSection(&renderer->cs);
646 if (renderer->audio_client)
648 if ((preroll = (renderer->state != STREAM_STATE_RUNNING)))
650 if (FAILED(hr = IAudioClient_Start(renderer->audio_client)))
651 WARN("Failed to start audio client, hr %#x.\n", hr);
652 renderer->state = STREAM_STATE_RUNNING;
655 else
656 hr = MF_E_NOT_INITIALIZED;
658 IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, hr, NULL);
659 if (preroll)
660 audio_renderer_preroll(renderer);
662 LeaveCriticalSection(&renderer->cs);
664 return hr;
667 static HRESULT WINAPI audio_renderer_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate)
669 FIXME("%p, %s, %f.\n", iface, debugstr_time(systime), rate);
671 return E_NOTIMPL;
674 static const IMFClockStateSinkVtbl audio_renderer_clock_sink_vtbl =
676 audio_renderer_clock_sink_QueryInterface,
677 audio_renderer_clock_sink_AddRef,
678 audio_renderer_clock_sink_Release,
679 audio_renderer_clock_sink_OnClockStart,
680 audio_renderer_clock_sink_OnClockStop,
681 audio_renderer_clock_sink_OnClockPause,
682 audio_renderer_clock_sink_OnClockRestart,
683 audio_renderer_clock_sink_OnClockSetRate,
686 static HRESULT WINAPI audio_renderer_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
688 struct audio_renderer *renderer = impl_from_IMFGetService(iface);
689 return IMFMediaSink_QueryInterface(&renderer->IMFMediaSink_iface, riid, obj);
692 static ULONG WINAPI audio_renderer_get_service_AddRef(IMFGetService *iface)
694 struct audio_renderer *renderer = impl_from_IMFGetService(iface);
695 return IMFMediaSink_AddRef(&renderer->IMFMediaSink_iface);
698 static ULONG WINAPI audio_renderer_get_service_Release(IMFGetService *iface)
700 struct audio_renderer *renderer = impl_from_IMFGetService(iface);
701 return IMFMediaSink_Release(&renderer->IMFMediaSink_iface);
704 static HRESULT WINAPI audio_renderer_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
706 struct audio_renderer *renderer = impl_from_IMFGetService(iface);
708 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
710 *obj = NULL;
712 if (IsEqualGUID(service, &MR_POLICY_VOLUME_SERVICE) && IsEqualIID(riid, &IID_IMFSimpleAudioVolume))
714 *obj = &renderer->IMFSimpleAudioVolume_iface;
716 else if (IsEqualGUID(service, &MR_STREAM_VOLUME_SERVICE) && IsEqualIID(riid, &IID_IMFAudioStreamVolume))
718 *obj = &renderer->IMFAudioStreamVolume_iface;
720 else if (IsEqualGUID(service, &MR_AUDIO_POLICY_SERVICE) && IsEqualIID(riid, &IID_IMFAudioPolicy))
722 *obj = &renderer->IMFAudioPolicy_iface;
724 else
725 FIXME("Unsupported service %s, interface %s.\n", debugstr_guid(service), debugstr_guid(riid));
727 if (*obj)
728 IUnknown_AddRef((IUnknown *)*obj);
730 return *obj ? S_OK : E_NOINTERFACE;
733 static const IMFGetServiceVtbl audio_renderer_get_service_vtbl =
735 audio_renderer_get_service_QueryInterface,
736 audio_renderer_get_service_AddRef,
737 audio_renderer_get_service_Release,
738 audio_renderer_get_service_GetService,
741 static HRESULT WINAPI audio_renderer_simple_volume_QueryInterface(IMFSimpleAudioVolume *iface, REFIID riid, void **obj)
743 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
745 if (IsEqualIID(riid, &IID_IMFSimpleAudioVolume) ||
746 IsEqualIID(riid, &IID_IUnknown))
748 *obj = iface;
749 IMFSimpleAudioVolume_AddRef(iface);
750 return S_OK;
753 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
754 *obj = NULL;
755 return E_NOINTERFACE;
758 static ULONG WINAPI audio_renderer_simple_volume_AddRef(IMFSimpleAudioVolume *iface)
760 struct audio_renderer *renderer = impl_from_IMFSimpleAudioVolume(iface);
761 return IMFMediaSink_AddRef(&renderer->IMFMediaSink_iface);
764 static ULONG WINAPI audio_renderer_simple_volume_Release(IMFSimpleAudioVolume *iface)
766 struct audio_renderer *renderer = impl_from_IMFSimpleAudioVolume(iface);
767 return IMFMediaSink_Release(&renderer->IMFMediaSink_iface);
770 static HRESULT WINAPI audio_renderer_simple_volume_SetMasterVolume(IMFSimpleAudioVolume *iface, float level)
772 struct audio_renderer *renderer = impl_from_IMFSimpleAudioVolume(iface);
773 HRESULT hr = S_OK;
775 TRACE("%p, %f.\n", iface, level);
777 EnterCriticalSection(&renderer->cs);
778 if (renderer->audio_volume)
779 hr = ISimpleAudioVolume_SetMasterVolume(renderer->audio_volume, level, NULL);
780 LeaveCriticalSection(&renderer->cs);
782 return hr;
785 static HRESULT WINAPI audio_renderer_simple_volume_GetMasterVolume(IMFSimpleAudioVolume *iface, float *level)
787 struct audio_renderer *renderer = impl_from_IMFSimpleAudioVolume(iface);
788 HRESULT hr = S_OK;
790 TRACE("%p, %p.\n", iface, level);
792 if (!level)
793 return E_POINTER;
795 *level = 0.0f;
797 EnterCriticalSection(&renderer->cs);
798 if (renderer->audio_volume)
799 hr = ISimpleAudioVolume_GetMasterVolume(renderer->audio_volume, level);
800 LeaveCriticalSection(&renderer->cs);
802 return hr;
805 static HRESULT WINAPI audio_renderer_simple_volume_SetMute(IMFSimpleAudioVolume *iface, BOOL mute)
807 struct audio_renderer *renderer = impl_from_IMFSimpleAudioVolume(iface);
808 HRESULT hr = S_OK;
810 TRACE("%p, %d.\n", iface, mute);
812 EnterCriticalSection(&renderer->cs);
813 if (renderer->audio_volume)
814 hr = ISimpleAudioVolume_SetMute(renderer->audio_volume, mute, NULL);
815 LeaveCriticalSection(&renderer->cs);
817 return hr;
820 static HRESULT WINAPI audio_renderer_simple_volume_GetMute(IMFSimpleAudioVolume *iface, BOOL *mute)
822 struct audio_renderer *renderer = impl_from_IMFSimpleAudioVolume(iface);
823 HRESULT hr = S_OK;
825 TRACE("%p, %p.\n", iface, mute);
827 if (!mute)
828 return E_POINTER;
830 *mute = FALSE;
832 EnterCriticalSection(&renderer->cs);
833 if (renderer->audio_volume)
834 hr = ISimpleAudioVolume_GetMute(renderer->audio_volume, mute);
835 LeaveCriticalSection(&renderer->cs);
837 return hr;
840 static const IMFSimpleAudioVolumeVtbl audio_renderer_simple_volume_vtbl =
842 audio_renderer_simple_volume_QueryInterface,
843 audio_renderer_simple_volume_AddRef,
844 audio_renderer_simple_volume_Release,
845 audio_renderer_simple_volume_SetMasterVolume,
846 audio_renderer_simple_volume_GetMasterVolume,
847 audio_renderer_simple_volume_SetMute,
848 audio_renderer_simple_volume_GetMute,
851 static HRESULT WINAPI audio_renderer_stream_volume_QueryInterface(IMFAudioStreamVolume *iface, REFIID riid, void **obj)
853 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
855 if (IsEqualIID(riid, &IID_IMFAudioStreamVolume) ||
856 IsEqualIID(riid, &IID_IUnknown))
858 *obj = iface;
859 IMFAudioStreamVolume_AddRef(iface);
860 return S_OK;
863 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
864 *obj = NULL;
865 return E_NOINTERFACE;
868 static ULONG WINAPI audio_renderer_stream_volume_AddRef(IMFAudioStreamVolume *iface)
870 struct audio_renderer *renderer = impl_from_IMFAudioStreamVolume(iface);
871 return IMFMediaSink_AddRef(&renderer->IMFMediaSink_iface);
874 static ULONG WINAPI audio_renderer_stream_volume_Release(IMFAudioStreamVolume *iface)
876 struct audio_renderer *renderer = impl_from_IMFAudioStreamVolume(iface);
877 return IMFMediaSink_Release(&renderer->IMFMediaSink_iface);
880 static HRESULT WINAPI audio_renderer_stream_volume_GetChannelCount(IMFAudioStreamVolume *iface, UINT32 *count)
882 struct audio_renderer *renderer = impl_from_IMFAudioStreamVolume(iface);
883 HRESULT hr = S_OK;
885 TRACE("%p, %p.\n", iface, count);
887 if (!count)
888 return E_POINTER;
890 *count = 0;
892 EnterCriticalSection(&renderer->cs);
893 if (renderer->stream_volume)
894 hr = IAudioStreamVolume_GetChannelCount(renderer->stream_volume, count);
895 LeaveCriticalSection(&renderer->cs);
897 return hr;
900 static HRESULT WINAPI audio_renderer_stream_volume_SetChannelVolume(IMFAudioStreamVolume *iface, UINT32 index, float level)
902 struct audio_renderer *renderer = impl_from_IMFAudioStreamVolume(iface);
903 HRESULT hr = S_OK;
905 TRACE("%p, %u, %f.\n", iface, index, level);
907 EnterCriticalSection(&renderer->cs);
908 if (renderer->stream_volume)
909 hr = IAudioStreamVolume_SetChannelVolume(renderer->stream_volume, index, level);
910 LeaveCriticalSection(&renderer->cs);
912 return hr;
915 static HRESULT WINAPI audio_renderer_stream_volume_GetChannelVolume(IMFAudioStreamVolume *iface, UINT32 index, float *level)
917 struct audio_renderer *renderer = impl_from_IMFAudioStreamVolume(iface);
918 HRESULT hr = S_OK;
920 TRACE("%p, %u, %p.\n", iface, index, level);
922 if (!level)
923 return E_POINTER;
925 *level = 0.0f;
927 EnterCriticalSection(&renderer->cs);
928 if (renderer->stream_volume)
929 hr = IAudioStreamVolume_GetChannelVolume(renderer->stream_volume, index, level);
930 LeaveCriticalSection(&renderer->cs);
932 return hr;
935 static HRESULT WINAPI audio_renderer_stream_volume_SetAllVolumes(IMFAudioStreamVolume *iface, UINT32 count,
936 const float *volumes)
938 struct audio_renderer *renderer = impl_from_IMFAudioStreamVolume(iface);
939 HRESULT hr = S_OK;
941 TRACE("%p, %u, %p.\n", iface, count, volumes);
943 EnterCriticalSection(&renderer->cs);
944 if (renderer->stream_volume)
945 hr = IAudioStreamVolume_SetAllVolumes(renderer->stream_volume, count, volumes);
946 LeaveCriticalSection(&renderer->cs);
948 return hr;
951 static HRESULT WINAPI audio_renderer_stream_volume_GetAllVolumes(IMFAudioStreamVolume *iface, UINT32 count, float *volumes)
953 struct audio_renderer *renderer = impl_from_IMFAudioStreamVolume(iface);
954 HRESULT hr = S_OK;
956 TRACE("%p, %u, %p.\n", iface, count, volumes);
958 if (!volumes)
959 return E_POINTER;
961 if (count)
962 memset(volumes, 0, sizeof(*volumes) * count);
964 EnterCriticalSection(&renderer->cs);
965 if (renderer->stream_volume)
966 hr = IAudioStreamVolume_GetAllVolumes(renderer->stream_volume, count, volumes);
967 LeaveCriticalSection(&renderer->cs);
969 return hr;
972 static const IMFAudioStreamVolumeVtbl audio_renderer_stream_volume_vtbl =
974 audio_renderer_stream_volume_QueryInterface,
975 audio_renderer_stream_volume_AddRef,
976 audio_renderer_stream_volume_Release,
977 audio_renderer_stream_volume_GetChannelCount,
978 audio_renderer_stream_volume_SetChannelVolume,
979 audio_renderer_stream_volume_GetChannelVolume,
980 audio_renderer_stream_volume_SetAllVolumes,
981 audio_renderer_stream_volume_GetAllVolumes,
984 static HRESULT WINAPI audio_renderer_policy_QueryInterface(IMFAudioPolicy *iface, REFIID riid, void **obj)
986 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
988 if (IsEqualIID(riid, &IID_IMFAudioPolicy) ||
989 IsEqualIID(riid, &IID_IUnknown))
991 *obj = iface;
992 IMFAudioPolicy_AddRef(iface);
993 return S_OK;
996 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
997 *obj = NULL;
998 return E_NOINTERFACE;
1001 static ULONG WINAPI audio_renderer_policy_AddRef(IMFAudioPolicy *iface)
1003 struct audio_renderer *renderer = impl_from_IMFAudioPolicy(iface);
1004 return IMFMediaSink_AddRef(&renderer->IMFMediaSink_iface);
1007 static ULONG WINAPI audio_renderer_policy_Release(IMFAudioPolicy *iface)
1009 struct audio_renderer *renderer = impl_from_IMFAudioPolicy(iface);
1010 return IMFMediaSink_Release(&renderer->IMFMediaSink_iface);
1013 static HRESULT WINAPI audio_renderer_policy_SetGroupingParam(IMFAudioPolicy *iface, REFGUID param)
1015 FIXME("%p, %s.\n", iface, debugstr_guid(param));
1017 return E_NOTIMPL;
1020 static HRESULT WINAPI audio_renderer_policy_GetGroupingParam(IMFAudioPolicy *iface, GUID *param)
1022 FIXME("%p, %p.\n", iface, param);
1024 return E_NOTIMPL;
1027 static HRESULT WINAPI audio_renderer_policy_SetDisplayName(IMFAudioPolicy *iface, const WCHAR *name)
1029 FIXME("%p, %s.\n", iface, debugstr_w(name));
1031 return E_NOTIMPL;
1034 static HRESULT WINAPI audio_renderer_policy_GetDisplayName(IMFAudioPolicy *iface, WCHAR **name)
1036 FIXME("%p, %p.\n", iface, name);
1038 return E_NOTIMPL;
1041 static HRESULT WINAPI audio_renderer_policy_SetIconPath(IMFAudioPolicy *iface, const WCHAR *path)
1043 FIXME("%p, %s.\n", iface, debugstr_w(path));
1045 return E_NOTIMPL;
1048 static HRESULT WINAPI audio_renderer_policy_GetIconPath(IMFAudioPolicy *iface, WCHAR **path)
1050 FIXME("%p, %p.\n", iface, path);
1052 return E_NOTIMPL;
1055 static const IMFAudioPolicyVtbl audio_renderer_policy_vtbl =
1057 audio_renderer_policy_QueryInterface,
1058 audio_renderer_policy_AddRef,
1059 audio_renderer_policy_Release,
1060 audio_renderer_policy_SetGroupingParam,
1061 audio_renderer_policy_GetGroupingParam,
1062 audio_renderer_policy_SetDisplayName,
1063 audio_renderer_policy_GetDisplayName,
1064 audio_renderer_policy_SetIconPath,
1065 audio_renderer_policy_GetIconPath,
1068 static HRESULT sar_create_mmdevice(IMFAttributes *attributes, struct audio_renderer *renderer)
1070 WCHAR *endpoint;
1071 unsigned int length, role = eMultimedia;
1072 IMMDeviceEnumerator *devenum;
1073 HRESULT hr;
1075 if (attributes)
1077 /* Mutually exclusive attributes. */
1078 if (SUCCEEDED(IMFAttributes_GetItem(attributes, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, NULL)) &&
1079 SUCCEEDED(IMFAttributes_GetItem(attributes, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID, NULL)))
1081 return E_INVALIDARG;
1085 if (FAILED(hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator,
1086 (void **)&devenum)))
1088 return hr;
1091 role = eMultimedia;
1092 if (attributes && SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, &role)))
1093 TRACE("Specified role %d.\n", role);
1095 if (attributes && SUCCEEDED(IMFAttributes_GetAllocatedString(attributes, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID,
1096 &endpoint, &length)))
1098 TRACE("Specified end point %s.\n", debugstr_w(endpoint));
1099 hr = IMMDeviceEnumerator_GetDevice(devenum, endpoint, &renderer->device);
1100 CoTaskMemFree(endpoint);
1102 else
1103 hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, eRender, role, &renderer->device);
1105 if (FAILED(hr))
1106 hr = MF_E_NO_AUDIO_PLAYBACK_DEVICE;
1108 IMMDeviceEnumerator_Release(devenum);
1110 return hr;
1113 static HRESULT WINAPI audio_renderer_stream_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj)
1115 struct audio_renderer *renderer = impl_from_IMFStreamSink(iface);
1117 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1119 if (IsEqualIID(riid, &IID_IMFStreamSink) ||
1120 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
1121 IsEqualIID(riid, &IID_IUnknown))
1123 *obj = &renderer->IMFStreamSink_iface;
1125 else if (IsEqualIID(riid, &IID_IMFMediaTypeHandler))
1127 *obj = &renderer->IMFMediaTypeHandler_iface;
1129 else
1131 WARN("Unsupported %s.\n", debugstr_guid(riid));
1132 *obj = NULL;
1133 return E_NOINTERFACE;
1136 IUnknown_AddRef((IUnknown *)*obj);
1138 return S_OK;
1141 static ULONG WINAPI audio_renderer_stream_AddRef(IMFStreamSink *iface)
1143 struct audio_renderer *renderer = impl_from_IMFStreamSink(iface);
1144 return IMFMediaSink_AddRef(&renderer->IMFMediaSink_iface);
1147 static ULONG WINAPI audio_renderer_stream_Release(IMFStreamSink *iface)
1149 struct audio_renderer *renderer = impl_from_IMFStreamSink(iface);
1150 return IMFMediaSink_Release(&renderer->IMFMediaSink_iface);
1153 static HRESULT WINAPI audio_renderer_stream_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event)
1155 struct audio_renderer *renderer = impl_from_IMFStreamSink(iface);
1157 TRACE("%p, %#x, %p.\n", iface, flags, event);
1159 if (renderer->flags & SAR_SHUT_DOWN)
1160 return MF_E_STREAMSINK_REMOVED;
1162 return IMFMediaEventQueue_GetEvent(renderer->stream_event_queue, flags, event);
1165 static HRESULT WINAPI audio_renderer_stream_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback,
1166 IUnknown *state)
1168 struct audio_renderer *renderer = impl_from_IMFStreamSink(iface);
1170 TRACE("%p, %p, %p.\n", iface, callback, state);
1172 if (renderer->flags & SAR_SHUT_DOWN)
1173 return MF_E_STREAMSINK_REMOVED;
1175 return IMFMediaEventQueue_BeginGetEvent(renderer->stream_event_queue, callback, state);
1178 static HRESULT WINAPI audio_renderer_stream_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result,
1179 IMFMediaEvent **event)
1181 struct audio_renderer *renderer = impl_from_IMFStreamSink(iface);
1183 TRACE("%p, %p, %p.\n", iface, result, event);
1185 if (renderer->flags & SAR_SHUT_DOWN)
1186 return MF_E_STREAMSINK_REMOVED;
1188 return IMFMediaEventQueue_EndGetEvent(renderer->stream_event_queue, result, event);
1191 static HRESULT WINAPI audio_renderer_stream_QueueEvent(IMFStreamSink *iface, MediaEventType event_type,
1192 REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
1194 struct audio_renderer *renderer = impl_from_IMFStreamSink(iface);
1196 TRACE("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1198 if (renderer->flags & SAR_SHUT_DOWN)
1199 return MF_E_STREAMSINK_REMOVED;
1201 return IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, event_type, ext_type, hr, value);
1204 static HRESULT WINAPI audio_renderer_stream_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink)
1206 struct audio_renderer *renderer = impl_from_IMFStreamSink(iface);
1208 TRACE("%p, %p.\n", iface, sink);
1210 if (renderer->flags & SAR_SHUT_DOWN)
1211 return MF_E_STREAMSINK_REMOVED;
1213 *sink = &renderer->IMFMediaSink_iface;
1214 IMFMediaSink_AddRef(*sink);
1216 return S_OK;
1219 static HRESULT WINAPI audio_renderer_stream_GetIdentifier(IMFStreamSink *iface, DWORD *identifier)
1221 struct audio_renderer *renderer = impl_from_IMFStreamSink(iface);
1223 TRACE("%p, %p.\n", iface, identifier);
1225 if (renderer->flags & SAR_SHUT_DOWN)
1226 return MF_E_STREAMSINK_REMOVED;
1228 *identifier = 0;
1230 return S_OK;
1233 static HRESULT WINAPI audio_renderer_stream_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler)
1235 struct audio_renderer *renderer = impl_from_IMFStreamSink(iface);
1237 TRACE("%p, %p.\n", iface, handler);
1239 if (!handler)
1240 return E_POINTER;
1242 if (renderer->flags & SAR_SHUT_DOWN)
1243 return MF_E_STREAMSINK_REMOVED;
1245 *handler = &renderer->IMFMediaTypeHandler_iface;
1246 IMFMediaTypeHandler_AddRef(*handler);
1248 return S_OK;
1251 static HRESULT WINAPI audio_renderer_stream_ProcessSample(IMFStreamSink *iface, IMFSample *sample)
1253 FIXME("%p, %p.\n", iface, sample);
1255 return E_NOTIMPL;
1258 static HRESULT WINAPI audio_renderer_stream_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type,
1259 const PROPVARIANT *marker_value, const PROPVARIANT *context_value)
1261 FIXME("%p, %d, %p, %p.\n", iface, marker_type, marker_value, context_value);
1263 return E_NOTIMPL;
1266 static HRESULT WINAPI audio_renderer_stream_Flush(IMFStreamSink *iface)
1268 FIXME("%p.\n", iface);
1270 return E_NOTIMPL;
1273 static const IMFStreamSinkVtbl audio_renderer_stream_vtbl =
1275 audio_renderer_stream_QueryInterface,
1276 audio_renderer_stream_AddRef,
1277 audio_renderer_stream_Release,
1278 audio_renderer_stream_GetEvent,
1279 audio_renderer_stream_BeginGetEvent,
1280 audio_renderer_stream_EndGetEvent,
1281 audio_renderer_stream_QueueEvent,
1282 audio_renderer_stream_GetMediaSink,
1283 audio_renderer_stream_GetIdentifier,
1284 audio_renderer_stream_GetMediaTypeHandler,
1285 audio_renderer_stream_ProcessSample,
1286 audio_renderer_stream_PlaceMarker,
1287 audio_renderer_stream_Flush,
1290 static HRESULT WINAPI audio_renderer_stream_type_handler_QueryInterface(IMFMediaTypeHandler *iface, REFIID riid,
1291 void **obj)
1293 struct audio_renderer *renderer = impl_from_IMFMediaTypeHandler(iface);
1294 return IMFStreamSink_QueryInterface(&renderer->IMFStreamSink_iface, riid, obj);
1297 static ULONG WINAPI audio_renderer_stream_type_handler_AddRef(IMFMediaTypeHandler *iface)
1299 struct audio_renderer *renderer = impl_from_IMFMediaTypeHandler(iface);
1300 return IMFStreamSink_AddRef(&renderer->IMFStreamSink_iface);
1303 static ULONG WINAPI audio_renderer_stream_type_handler_Release(IMFMediaTypeHandler *iface)
1305 struct audio_renderer *renderer = impl_from_IMFMediaTypeHandler(iface);
1306 return IMFStreamSink_Release(&renderer->IMFStreamSink_iface);
1309 static HRESULT WINAPI audio_renderer_stream_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler *iface,
1310 IMFMediaType *in_type, IMFMediaType **out_type)
1312 struct audio_renderer *renderer = impl_from_IMFMediaTypeHandler(iface);
1313 unsigned int flags;
1314 HRESULT hr;
1316 TRACE("%p, %p, %p.\n", iface, in_type, out_type);
1318 EnterCriticalSection(&renderer->cs);
1319 hr = renderer->current_media_type && IMFMediaType_IsEqual(renderer->current_media_type, in_type, &flags) == S_OK ?
1320 S_OK : MF_E_INVALIDMEDIATYPE;
1321 LeaveCriticalSection(&renderer->cs);
1323 return hr;
1326 static HRESULT WINAPI audio_renderer_stream_type_handler_GetMediaTypeCount(IMFMediaTypeHandler *iface, DWORD *count)
1328 TRACE("%p, %p.\n", iface, count);
1330 *count = 1;
1332 return S_OK;
1335 static HRESULT WINAPI audio_renderer_stream_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *iface, DWORD index,
1336 IMFMediaType **media_type)
1338 struct audio_renderer *renderer = impl_from_IMFMediaTypeHandler(iface);
1340 TRACE("%p, %u, %p.\n", iface, index, media_type);
1342 if (index == 0)
1344 *media_type = renderer->media_type;
1345 IMFMediaType_AddRef(*media_type);
1348 return S_OK;
1351 static HRESULT audio_renderer_create_audio_client(struct audio_renderer *renderer)
1353 WAVEFORMATEX *wfx;
1354 HRESULT hr;
1356 audio_renderer_release_audio_client(renderer);
1358 hr = IMMDevice_Activate(renderer->device, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL,
1359 (void **)&renderer->audio_client);
1360 if (FAILED(hr))
1362 WARN("Failed to create audio client, hr %#x.\n", hr);
1363 return hr;
1366 /* FIXME: use SAR configuration for flags and session id. */
1368 /* FIXME: for now always use default format. */
1369 if (FAILED(hr = IAudioClient_GetMixFormat(renderer->audio_client, &wfx)))
1371 WARN("Failed to get audio format, hr %#x.\n", hr);
1372 return hr;
1375 hr = IAudioClient_Initialize(renderer->audio_client, AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
1376 1000000, 0, wfx, NULL);
1377 CoTaskMemFree(wfx);
1378 if (FAILED(hr))
1380 WARN("Failed to initialize audio client, hr %#x.\n", hr);
1381 return hr;
1384 if (FAILED(hr = IAudioClient_GetService(renderer->audio_client, &IID_IAudioStreamVolume,
1385 (void **)&renderer->stream_volume)))
1387 WARN("Failed to get stream volume control, hr %#x.\n", hr);
1388 return hr;
1391 if (FAILED(hr = IAudioClient_GetService(renderer->audio_client, &IID_ISimpleAudioVolume, (void **)&renderer->audio_volume)))
1393 WARN("Failed to get audio volume control, hr %#x.\n", hr);
1394 return hr;
1397 if (FAILED(hr = IAudioClient_SetEventHandle(renderer->audio_client, renderer->buffer_ready_event)))
1399 WARN("Failed to set event handle, hr %#x.\n", hr);
1400 return hr;
1403 return hr;
1406 static HRESULT WINAPI audio_renderer_stream_type_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface,
1407 IMFMediaType *media_type)
1409 struct audio_renderer *renderer = impl_from_IMFMediaTypeHandler(iface);
1410 const unsigned int test_flags = MF_MEDIATYPE_EQUAL_MAJOR_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_TYPES;
1411 BOOL compare_result;
1412 unsigned int flags;
1413 HRESULT hr = S_OK;
1415 TRACE("%p, %p.\n", iface, media_type);
1417 if (!media_type)
1418 return E_POINTER;
1420 EnterCriticalSection(&renderer->cs);
1421 if (SUCCEEDED(IMFMediaType_IsEqual(renderer->media_type, media_type, &flags)) && ((flags & test_flags) == test_flags))
1423 if (renderer->current_media_type)
1424 IMFMediaType_Release(renderer->current_media_type);
1425 renderer->current_media_type = media_type;
1426 IMFMediaType_AddRef(renderer->current_media_type);
1428 if (SUCCEEDED(hr = audio_renderer_create_audio_client(renderer)))
1430 if (SUCCEEDED(IMFMediaType_Compare(renderer->media_type, (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS,
1431 &compare_result)) && !compare_result)
1433 IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkFormatInvalidated, &GUID_NULL,
1434 S_OK, NULL);
1435 audio_renderer_preroll(renderer);
1439 else
1440 hr = MF_E_INVALIDMEDIATYPE;
1441 LeaveCriticalSection(&renderer->cs);
1443 return hr;
1446 static HRESULT WINAPI audio_renderer_stream_type_handler_GetCurrentMediaType(IMFMediaTypeHandler *iface,
1447 IMFMediaType **media_type)
1449 struct audio_renderer *renderer = impl_from_IMFMediaTypeHandler(iface);
1450 HRESULT hr = S_OK;
1452 TRACE("%p, %p.\n", iface, media_type);
1454 EnterCriticalSection(&renderer->cs);
1455 if (renderer->current_media_type)
1457 *media_type = renderer->current_media_type;
1458 IMFMediaType_AddRef(*media_type);
1460 else
1461 hr = MF_E_NOT_INITIALIZED;
1462 LeaveCriticalSection(&renderer->cs);
1464 return hr;
1467 static HRESULT WINAPI audio_renderer_stream_type_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type)
1469 struct audio_renderer *renderer = impl_from_IMFMediaTypeHandler(iface);
1471 TRACE("%p, %p.\n", iface, type);
1473 if (!type)
1474 return E_POINTER;
1476 if (renderer->flags & SAR_SHUT_DOWN)
1477 return MF_E_STREAMSINK_REMOVED;
1479 memcpy(type, &MFMediaType_Audio, sizeof(*type));
1480 return S_OK;
1483 static const IMFMediaTypeHandlerVtbl audio_renderer_stream_type_handler_vtbl =
1485 audio_renderer_stream_type_handler_QueryInterface,
1486 audio_renderer_stream_type_handler_AddRef,
1487 audio_renderer_stream_type_handler_Release,
1488 audio_renderer_stream_type_handler_IsMediaTypeSupported,
1489 audio_renderer_stream_type_handler_GetMediaTypeCount,
1490 audio_renderer_stream_type_handler_GetMediaTypeByIndex,
1491 audio_renderer_stream_type_handler_SetCurrentMediaType,
1492 audio_renderer_stream_type_handler_GetCurrentMediaType,
1493 audio_renderer_stream_type_handler_GetMajorType,
1496 static HRESULT audio_renderer_collect_supported_types(struct audio_renderer *renderer)
1498 IAudioClient *client;
1499 WAVEFORMATEX *format;
1500 HRESULT hr;
1502 if (FAILED(hr = MFCreateMediaType(&renderer->media_type)))
1503 return hr;
1505 hr = IMMDevice_Activate(renderer->device, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void **)&client);
1506 if (FAILED(hr))
1508 WARN("Failed to create audio client, hr %#x.\n", hr);
1509 return hr;
1512 /* FIXME: */
1514 hr = IAudioClient_GetMixFormat(client, &format);
1515 IAudioClient_Release(client);
1516 if (FAILED(hr))
1518 WARN("Failed to get device audio format, hr %#x.\n", hr);
1519 return hr;
1522 hr = MFInitMediaTypeFromWaveFormatEx(renderer->media_type, format, format->cbSize + sizeof(*format));
1523 CoTaskMemFree(format);
1524 if (FAILED(hr))
1526 WARN("Failed to initialize media type, hr %#x.\n", hr);
1527 return hr;
1530 IMFMediaType_DeleteItem(renderer->media_type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX);
1532 return hr;
1535 static HRESULT sar_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj)
1537 struct audio_renderer *renderer;
1538 HRESULT hr;
1540 TRACE("%p, %p, %p.\n", attributes, user_context, obj);
1542 if (!(renderer = heap_alloc_zero(sizeof(*renderer))))
1543 return E_OUTOFMEMORY;
1545 renderer->IMFMediaSink_iface.lpVtbl = &audio_renderer_sink_vtbl;
1546 renderer->IMFMediaSinkPreroll_iface.lpVtbl = &audio_renderer_preroll_vtbl;
1547 renderer->IMFStreamSink_iface.lpVtbl = &audio_renderer_stream_vtbl;
1548 renderer->IMFMediaTypeHandler_iface.lpVtbl = &audio_renderer_stream_type_handler_vtbl;
1549 renderer->IMFClockStateSink_iface.lpVtbl = &audio_renderer_clock_sink_vtbl;
1550 renderer->IMFMediaEventGenerator_iface.lpVtbl = &audio_renderer_events_vtbl;
1551 renderer->IMFGetService_iface.lpVtbl = &audio_renderer_get_service_vtbl;
1552 renderer->IMFSimpleAudioVolume_iface.lpVtbl = &audio_renderer_simple_volume_vtbl;
1553 renderer->IMFAudioStreamVolume_iface.lpVtbl = &audio_renderer_stream_volume_vtbl;
1554 renderer->IMFAudioPolicy_iface.lpVtbl = &audio_renderer_policy_vtbl;
1555 renderer->refcount = 1;
1556 InitializeCriticalSection(&renderer->cs);
1557 renderer->buffer_ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1559 if (FAILED(hr = MFCreateEventQueue(&renderer->event_queue)))
1560 goto failed;
1562 if (FAILED(hr = MFCreateEventQueue(&renderer->stream_event_queue)))
1563 goto failed;
1565 if (FAILED(hr = sar_create_mmdevice(attributes, renderer)))
1566 goto failed;
1568 if (FAILED(hr = audio_renderer_collect_supported_types(renderer)))
1569 goto failed;
1571 *obj = (IUnknown *)&renderer->IMFMediaSink_iface;
1573 return S_OK;
1575 failed:
1577 IMFMediaSink_Release(&renderer->IMFMediaSink_iface);
1579 return hr;
1582 static void sar_shutdown_object(void *user_context, IUnknown *obj)
1584 IMFMediaSink *sink;
1586 if (SUCCEEDED(IUnknown_QueryInterface(obj, &IID_IMFMediaSink, (void **)&sink)))
1588 IMFMediaSink_Shutdown(sink);
1589 IMFMediaSink_Release(sink);
1593 static void sar_free_private(void *user_context)
1597 static const struct activate_funcs sar_activate_funcs =
1599 sar_create_object,
1600 sar_shutdown_object,
1601 sar_free_private,
1604 /***********************************************************************
1605 * MFCreateAudioRendererActivate (mf.@)
1607 HRESULT WINAPI MFCreateAudioRendererActivate(IMFActivate **activate)
1609 TRACE("%p.\n", activate);
1611 if (!activate)
1612 return E_POINTER;
1614 return create_activation_object(NULL, &sar_activate_funcs, activate);
1617 /***********************************************************************
1618 * MFCreateAudioRenderer (mf.@)
1620 HRESULT WINAPI MFCreateAudioRenderer(IMFAttributes *attributes, IMFMediaSink **sink)
1622 IUnknown *object;
1623 HRESULT hr;
1625 TRACE("%p, %p.\n", attributes, sink);
1627 if (SUCCEEDED(hr = sar_create_object(attributes, NULL, &object)))
1629 hr = IUnknown_QueryInterface(object, &IID_IMFMediaSink, (void **)sink);
1630 IUnknown_Release(object);
1633 return hr;