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
23 #include "mf_private.h"
25 #include "mmdeviceapi.h"
26 #include "audioclient.h"
28 #include "wine/debug.h"
29 #include "wine/list.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
35 STREAM_STATE_STOPPED
= 0,
40 enum audio_renderer_flags
44 SAR_SAMPLE_REQUESTED
= 0x4,
47 enum queued_object_type
56 enum queued_object_type type
;
62 unsigned int frame_offset
;
66 MFSTREAMSINK_MARKER_TYPE type
;
74 IMFMediaSink IMFMediaSink_iface
;
75 IMFMediaSinkPreroll IMFMediaSinkPreroll_iface
;
76 IMFStreamSink IMFStreamSink_iface
;
77 IMFMediaTypeHandler IMFMediaTypeHandler_iface
;
78 IMFClockStateSink IMFClockStateSink_iface
;
79 IMFMediaEventGenerator IMFMediaEventGenerator_iface
;
80 IMFGetService IMFGetService_iface
;
81 IMFSimpleAudioVolume IMFSimpleAudioVolume_iface
;
82 IMFAudioStreamVolume IMFAudioStreamVolume_iface
;
83 IMFAudioPolicy IMFAudioPolicy_iface
;
84 IMFAsyncCallback render_callback
;
86 IMFMediaEventQueue
*event_queue
;
87 IMFMediaEventQueue
*stream_event_queue
;
88 IMFPresentationClock
*clock
;
89 IMFMediaType
*media_type
;
90 IMFMediaType
*current_media_type
;
92 IAudioClient
*audio_client
;
93 IAudioRenderClient
*audio_render_client
;
94 IAudioStreamVolume
*stream_volume
;
95 ISimpleAudioVolume
*audio_volume
;
101 HANDLE buffer_ready_event
;
102 MFWORKITEM_KEY buffer_ready_key
;
103 unsigned int frame_size
;
104 unsigned int queued_frames
;
105 unsigned int max_frames
;
107 enum stream_state state
;
112 static void release_pending_object(struct queued_object
*object
)
114 list_remove(&object
->entry
);
115 switch (object
->type
)
117 case OBJECT_TYPE_SAMPLE
:
118 if (object
->u
.sample
.sample
)
119 IMFSample_Release(object
->u
.sample
.sample
);
121 case OBJECT_TYPE_MARKER
:
122 PropVariantClear(&object
->u
.marker
.context
);
128 static struct audio_renderer
*impl_from_IMFMediaSink(IMFMediaSink
*iface
)
130 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFMediaSink_iface
);
133 static struct audio_renderer
*impl_from_IMFMediaSinkPreroll(IMFMediaSinkPreroll
*iface
)
135 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFMediaSinkPreroll_iface
);
138 static struct audio_renderer
*impl_from_IMFClockStateSink(IMFClockStateSink
*iface
)
140 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFClockStateSink_iface
);
143 static struct audio_renderer
*impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator
*iface
)
145 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFMediaEventGenerator_iface
);
148 static struct audio_renderer
*impl_from_IMFGetService(IMFGetService
*iface
)
150 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFGetService_iface
);
153 static struct audio_renderer
*impl_from_IMFSimpleAudioVolume(IMFSimpleAudioVolume
*iface
)
155 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFSimpleAudioVolume_iface
);
158 static struct audio_renderer
*impl_from_IMFAudioStreamVolume(IMFAudioStreamVolume
*iface
)
160 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFAudioStreamVolume_iface
);
163 static struct audio_renderer
*impl_from_IMFAudioPolicy(IMFAudioPolicy
*iface
)
165 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFAudioPolicy_iface
);
168 static struct audio_renderer
*impl_from_IMFStreamSink(IMFStreamSink
*iface
)
170 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFStreamSink_iface
);
173 static struct audio_renderer
*impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler
*iface
)
175 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFMediaTypeHandler_iface
);
178 static struct audio_renderer
*impl_from_render_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
180 return CONTAINING_RECORD(iface
, struct audio_renderer
, render_callback
);
183 static HRESULT WINAPI
audio_renderer_sink_QueryInterface(IMFMediaSink
*iface
, REFIID riid
, void **obj
)
185 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
187 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
189 if (IsEqualIID(riid
, &IID_IMFMediaSink
) ||
190 IsEqualIID(riid
, &IID_IUnknown
))
194 else if (IsEqualIID(riid
, &IID_IMFMediaSinkPreroll
))
196 *obj
= &renderer
->IMFMediaSinkPreroll_iface
;
198 else if (IsEqualIID(riid
, &IID_IMFClockStateSink
))
200 *obj
= &renderer
->IMFClockStateSink_iface
;
202 else if (IsEqualIID(riid
, &IID_IMFMediaEventGenerator
))
204 *obj
= &renderer
->IMFMediaEventGenerator_iface
;
206 else if (IsEqualIID(riid
, &IID_IMFGetService
))
208 *obj
= &renderer
->IMFGetService_iface
;
212 WARN("Unsupported %s.\n", debugstr_guid(riid
));
214 return E_NOINTERFACE
;
217 IUnknown_AddRef((IUnknown
*)*obj
);
222 static ULONG WINAPI
audio_renderer_sink_AddRef(IMFMediaSink
*iface
)
224 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
225 ULONG refcount
= InterlockedIncrement(&renderer
->refcount
);
226 TRACE("%p, refcount %lu.\n", iface
, refcount
);
230 static void audio_renderer_release_audio_client(struct audio_renderer
*renderer
)
232 struct queued_object
*obj
, *obj2
;
234 MFCancelWorkItem(renderer
->buffer_ready_key
);
235 LIST_FOR_EACH_ENTRY_SAFE(obj
, obj2
, &renderer
->queue
, struct queued_object
, entry
)
237 release_pending_object(obj
);
239 renderer
->queued_frames
= 0;
240 renderer
->buffer_ready_key
= 0;
241 if (renderer
->audio_client
)
243 IAudioClient_Stop(renderer
->audio_client
);
244 IAudioClient_Reset(renderer
->audio_client
);
245 IAudioClient_Release(renderer
->audio_client
);
247 renderer
->audio_client
= NULL
;
248 if (renderer
->audio_render_client
)
249 IAudioRenderClient_Release(renderer
->audio_render_client
);
250 renderer
->audio_render_client
= NULL
;
251 if (renderer
->stream_volume
)
252 IAudioStreamVolume_Release(renderer
->stream_volume
);
253 renderer
->stream_volume
= NULL
;
254 if (renderer
->audio_volume
)
255 ISimpleAudioVolume_Release(renderer
->audio_volume
);
256 renderer
->audio_volume
= NULL
;
257 renderer
->flags
&= ~SAR_PREROLLED
;
260 static ULONG WINAPI
audio_renderer_sink_Release(IMFMediaSink
*iface
)
262 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
263 ULONG refcount
= InterlockedDecrement(&renderer
->refcount
);
265 TRACE("%p, refcount %lu.\n", iface
, refcount
);
269 if (renderer
->event_queue
)
270 IMFMediaEventQueue_Release(renderer
->event_queue
);
271 if (renderer
->stream_event_queue
)
272 IMFMediaEventQueue_Release(renderer
->stream_event_queue
);
274 IMFPresentationClock_Release(renderer
->clock
);
275 if (renderer
->device
)
276 IMMDevice_Release(renderer
->device
);
277 if (renderer
->media_type
)
278 IMFMediaType_Release(renderer
->media_type
);
279 if (renderer
->current_media_type
)
280 IMFMediaType_Release(renderer
->current_media_type
);
281 audio_renderer_release_audio_client(renderer
);
282 CloseHandle(renderer
->buffer_ready_event
);
283 DeleteCriticalSection(&renderer
->cs
);
290 static HRESULT WINAPI
audio_renderer_sink_GetCharacteristics(IMFMediaSink
*iface
, DWORD
*flags
)
292 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
294 TRACE("%p, %p.\n", iface
, flags
);
296 if (renderer
->flags
& SAR_SHUT_DOWN
)
297 return MF_E_SHUTDOWN
;
299 *flags
= MEDIASINK_FIXED_STREAMS
| MEDIASINK_CAN_PREROLL
;
304 static HRESULT WINAPI
audio_renderer_sink_AddStreamSink(IMFMediaSink
*iface
, DWORD stream_sink_id
,
305 IMFMediaType
*media_type
, IMFStreamSink
**stream_sink
)
307 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
309 TRACE("%p, %#lx, %p, %p.\n", iface
, stream_sink_id
, media_type
, stream_sink
);
311 return renderer
->flags
& SAR_SHUT_DOWN
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
314 static HRESULT WINAPI
audio_renderer_sink_RemoveStreamSink(IMFMediaSink
*iface
, DWORD stream_sink_id
)
316 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
318 TRACE("%p, %#lx.\n", iface
, stream_sink_id
);
320 return renderer
->flags
& SAR_SHUT_DOWN
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
323 static HRESULT WINAPI
audio_renderer_sink_GetStreamSinkCount(IMFMediaSink
*iface
, DWORD
*count
)
325 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
327 TRACE("%p, %p.\n", iface
, count
);
332 if (renderer
->flags
& SAR_SHUT_DOWN
)
333 return MF_E_SHUTDOWN
;
340 static HRESULT WINAPI
audio_renderer_sink_GetStreamSinkByIndex(IMFMediaSink
*iface
, DWORD index
,
341 IMFStreamSink
**stream
)
343 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
346 TRACE("%p, %lu, %p.\n", iface
, index
, stream
);
348 EnterCriticalSection(&renderer
->cs
);
350 if (renderer
->flags
& SAR_SHUT_DOWN
)
353 hr
= MF_E_INVALIDINDEX
;
356 *stream
= &renderer
->IMFStreamSink_iface
;
357 IMFStreamSink_AddRef(*stream
);
360 LeaveCriticalSection(&renderer
->cs
);
365 static HRESULT WINAPI
audio_renderer_sink_GetStreamSinkById(IMFMediaSink
*iface
, DWORD stream_sink_id
,
366 IMFStreamSink
**stream
)
368 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
371 TRACE("%p, %#lx, %p.\n", iface
, stream_sink_id
, stream
);
373 EnterCriticalSection(&renderer
->cs
);
375 if (renderer
->flags
& SAR_SHUT_DOWN
)
377 else if (stream_sink_id
> 0)
378 hr
= MF_E_INVALIDSTREAMNUMBER
;
381 *stream
= &renderer
->IMFStreamSink_iface
;
382 IMFStreamSink_AddRef(*stream
);
385 LeaveCriticalSection(&renderer
->cs
);
390 static void audio_renderer_set_presentation_clock(struct audio_renderer
*renderer
, IMFPresentationClock
*clock
)
394 IMFPresentationClock_RemoveClockStateSink(renderer
->clock
, &renderer
->IMFClockStateSink_iface
);
395 IMFPresentationClock_Release(renderer
->clock
);
397 renderer
->clock
= clock
;
400 IMFPresentationClock_AddRef(renderer
->clock
);
401 IMFPresentationClock_AddClockStateSink(renderer
->clock
, &renderer
->IMFClockStateSink_iface
);
405 static HRESULT WINAPI
audio_renderer_sink_SetPresentationClock(IMFMediaSink
*iface
, IMFPresentationClock
*clock
)
407 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
410 TRACE("%p, %p.\n", iface
, clock
);
412 EnterCriticalSection(&renderer
->cs
);
414 if (renderer
->flags
& SAR_SHUT_DOWN
)
417 audio_renderer_set_presentation_clock(renderer
, clock
);
419 LeaveCriticalSection(&renderer
->cs
);
424 static HRESULT WINAPI
audio_renderer_sink_GetPresentationClock(IMFMediaSink
*iface
, IMFPresentationClock
**clock
)
426 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
429 TRACE("%p, %p.\n", iface
, clock
);
434 EnterCriticalSection(&renderer
->cs
);
436 if (renderer
->flags
& SAR_SHUT_DOWN
)
438 else if (renderer
->clock
)
440 *clock
= renderer
->clock
;
441 IMFPresentationClock_AddRef(*clock
);
446 LeaveCriticalSection(&renderer
->cs
);
451 static HRESULT WINAPI
audio_renderer_sink_Shutdown(IMFMediaSink
*iface
)
453 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
456 TRACE("%p.\n", iface
);
458 EnterCriticalSection(&renderer
->cs
);
460 if (renderer
->flags
& SAR_SHUT_DOWN
)
464 renderer
->flags
|= SAR_SHUT_DOWN
;
465 IMFMediaEventQueue_Shutdown(renderer
->event_queue
);
466 IMFMediaEventQueue_Shutdown(renderer
->stream_event_queue
);
467 audio_renderer_set_presentation_clock(renderer
, NULL
);
468 audio_renderer_release_audio_client(renderer
);
471 LeaveCriticalSection(&renderer
->cs
);
476 static const IMFMediaSinkVtbl audio_renderer_sink_vtbl
=
478 audio_renderer_sink_QueryInterface
,
479 audio_renderer_sink_AddRef
,
480 audio_renderer_sink_Release
,
481 audio_renderer_sink_GetCharacteristics
,
482 audio_renderer_sink_AddStreamSink
,
483 audio_renderer_sink_RemoveStreamSink
,
484 audio_renderer_sink_GetStreamSinkCount
,
485 audio_renderer_sink_GetStreamSinkByIndex
,
486 audio_renderer_sink_GetStreamSinkById
,
487 audio_renderer_sink_SetPresentationClock
,
488 audio_renderer_sink_GetPresentationClock
,
489 audio_renderer_sink_Shutdown
,
492 static void audio_renderer_preroll(struct audio_renderer
*renderer
)
496 if (renderer
->flags
& SAR_PREROLLED
)
499 for (i
= 0; i
< 2; ++i
)
500 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkRequestSample
, &GUID_NULL
, S_OK
, NULL
);
501 renderer
->flags
|= SAR_PREROLLED
;
504 static HRESULT WINAPI
audio_renderer_preroll_QueryInterface(IMFMediaSinkPreroll
*iface
, REFIID riid
, void **obj
)
506 struct audio_renderer
*renderer
= impl_from_IMFMediaSinkPreroll(iface
);
507 return IMFMediaSink_QueryInterface(&renderer
->IMFMediaSink_iface
, riid
, obj
);
510 static ULONG WINAPI
audio_renderer_preroll_AddRef(IMFMediaSinkPreroll
*iface
)
512 struct audio_renderer
*renderer
= impl_from_IMFMediaSinkPreroll(iface
);
513 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
516 static ULONG WINAPI
audio_renderer_preroll_Release(IMFMediaSinkPreroll
*iface
)
518 struct audio_renderer
*renderer
= impl_from_IMFMediaSinkPreroll(iface
);
519 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
522 static HRESULT WINAPI
audio_renderer_preroll_NotifyPreroll(IMFMediaSinkPreroll
*iface
, MFTIME start_time
)
524 struct audio_renderer
*renderer
= impl_from_IMFMediaSinkPreroll(iface
);
526 TRACE("%p, %s.\n", iface
, debugstr_time(start_time
));
528 if (renderer
->flags
& SAR_SHUT_DOWN
)
529 return MF_E_SHUTDOWN
;
531 audio_renderer_preroll(renderer
);
532 return IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkPrerolled
, &GUID_NULL
, S_OK
, NULL
);
535 static const IMFMediaSinkPrerollVtbl audio_renderer_preroll_vtbl
=
537 audio_renderer_preroll_QueryInterface
,
538 audio_renderer_preroll_AddRef
,
539 audio_renderer_preroll_Release
,
540 audio_renderer_preroll_NotifyPreroll
,
543 static HRESULT WINAPI
audio_renderer_events_QueryInterface(IMFMediaEventGenerator
*iface
, REFIID riid
, void **obj
)
545 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
546 return IMFMediaSink_QueryInterface(&renderer
->IMFMediaSink_iface
, riid
, obj
);
549 static ULONG WINAPI
audio_renderer_events_AddRef(IMFMediaEventGenerator
*iface
)
551 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
552 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
555 static ULONG WINAPI
audio_renderer_events_Release(IMFMediaEventGenerator
*iface
)
557 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
558 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
561 static HRESULT WINAPI
audio_renderer_events_GetEvent(IMFMediaEventGenerator
*iface
, DWORD flags
, IMFMediaEvent
**event
)
563 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
565 TRACE("%p, %#lx, %p.\n", iface
, flags
, event
);
567 return IMFMediaEventQueue_GetEvent(renderer
->event_queue
, flags
, event
);
570 static HRESULT WINAPI
audio_renderer_events_BeginGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncCallback
*callback
,
573 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
575 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
577 return IMFMediaEventQueue_BeginGetEvent(renderer
->event_queue
, callback
, state
);
580 static HRESULT WINAPI
audio_renderer_events_EndGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncResult
*result
,
581 IMFMediaEvent
**event
)
583 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
585 TRACE("%p, %p, %p.\n", iface
, result
, event
);
587 return IMFMediaEventQueue_EndGetEvent(renderer
->event_queue
, result
, event
);
590 static HRESULT WINAPI
audio_renderer_events_QueueEvent(IMFMediaEventGenerator
*iface
, MediaEventType event_type
,
591 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
593 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
595 TRACE("%p, %lu, %s, %#lx, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
597 return IMFMediaEventQueue_QueueEventParamVar(renderer
->event_queue
, event_type
, ext_type
, hr
, value
);
600 static const IMFMediaEventGeneratorVtbl audio_renderer_events_vtbl
=
602 audio_renderer_events_QueryInterface
,
603 audio_renderer_events_AddRef
,
604 audio_renderer_events_Release
,
605 audio_renderer_events_GetEvent
,
606 audio_renderer_events_BeginGetEvent
,
607 audio_renderer_events_EndGetEvent
,
608 audio_renderer_events_QueueEvent
,
611 static HRESULT WINAPI
audio_renderer_clock_sink_QueryInterface(IMFClockStateSink
*iface
, REFIID riid
, void **obj
)
613 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
614 return IMFMediaSink_QueryInterface(&renderer
->IMFMediaSink_iface
, riid
, obj
);
617 static ULONG WINAPI
audio_renderer_clock_sink_AddRef(IMFClockStateSink
*iface
)
619 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
620 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
623 static ULONG WINAPI
audio_renderer_clock_sink_Release(IMFClockStateSink
*iface
)
625 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
626 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
629 static HRESULT WINAPI
audio_renderer_clock_sink_OnClockStart(IMFClockStateSink
*iface
, MFTIME systime
, LONGLONG offset
)
631 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
634 TRACE("%p, %s, %s.\n", iface
, debugstr_time(systime
), debugstr_time(offset
));
636 EnterCriticalSection(&renderer
->cs
);
637 if (renderer
->audio_client
)
639 if (renderer
->state
== STREAM_STATE_STOPPED
)
641 if (FAILED(hr
= IAudioClient_Start(renderer
->audio_client
)))
642 WARN("Failed to start audio client, hr %#lx.\n", hr
);
643 renderer
->state
= STREAM_STATE_RUNNING
;
647 hr
= MF_E_NOT_INITIALIZED
;
649 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkStarted
, &GUID_NULL
, hr
, NULL
);
651 audio_renderer_preroll(renderer
);
652 LeaveCriticalSection(&renderer
->cs
);
657 static HRESULT WINAPI
audio_renderer_clock_sink_OnClockStop(IMFClockStateSink
*iface
, MFTIME systime
)
659 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
662 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
664 EnterCriticalSection(&renderer
->cs
);
665 if (renderer
->audio_client
)
667 if (renderer
->state
!= STREAM_STATE_STOPPED
)
669 if (SUCCEEDED(hr
= IAudioClient_Stop(renderer
->audio_client
)))
671 if (FAILED(hr
= IAudioClient_Reset(renderer
->audio_client
)))
672 WARN("Failed to reset audio client, hr %#lx.\n", hr
);
675 WARN("Failed to stop audio client, hr %#lx.\n", hr
);
676 renderer
->state
= STREAM_STATE_STOPPED
;
677 renderer
->flags
&= ~SAR_PREROLLED
;
681 hr
= MF_E_NOT_INITIALIZED
;
683 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkStopped
, &GUID_NULL
, hr
, NULL
);
684 LeaveCriticalSection(&renderer
->cs
);
689 static HRESULT WINAPI
audio_renderer_clock_sink_OnClockPause(IMFClockStateSink
*iface
, MFTIME systime
)
691 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
694 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
696 EnterCriticalSection(&renderer
->cs
);
697 if (renderer
->state
== STREAM_STATE_RUNNING
)
699 if (renderer
->audio_client
)
701 if (FAILED(hr
= IAudioClient_Stop(renderer
->audio_client
)))
702 WARN("Failed to stop audio client, hr %#lx.\n", hr
);
703 renderer
->state
= STREAM_STATE_PAUSED
;
706 hr
= MF_E_NOT_INITIALIZED
;
708 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkPaused
, &GUID_NULL
, hr
, NULL
);
711 hr
= MF_E_INVALID_STATE_TRANSITION
;
712 LeaveCriticalSection(&renderer
->cs
);
717 static HRESULT WINAPI
audio_renderer_clock_sink_OnClockRestart(IMFClockStateSink
*iface
, MFTIME systime
)
719 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
720 BOOL preroll
= FALSE
;
723 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
725 EnterCriticalSection(&renderer
->cs
);
726 if (renderer
->audio_client
)
728 if ((preroll
= (renderer
->state
!= STREAM_STATE_RUNNING
)))
730 if (FAILED(hr
= IAudioClient_Start(renderer
->audio_client
)))
731 WARN("Failed to start audio client, hr %#lx.\n", hr
);
732 renderer
->state
= STREAM_STATE_RUNNING
;
736 hr
= MF_E_NOT_INITIALIZED
;
738 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkStarted
, &GUID_NULL
, hr
, NULL
);
740 audio_renderer_preroll(renderer
);
742 LeaveCriticalSection(&renderer
->cs
);
747 static HRESULT WINAPI
audio_renderer_clock_sink_OnClockSetRate(IMFClockStateSink
*iface
, MFTIME systime
, float rate
)
749 FIXME("%p, %s, %f.\n", iface
, debugstr_time(systime
), rate
);
754 static const IMFClockStateSinkVtbl audio_renderer_clock_sink_vtbl
=
756 audio_renderer_clock_sink_QueryInterface
,
757 audio_renderer_clock_sink_AddRef
,
758 audio_renderer_clock_sink_Release
,
759 audio_renderer_clock_sink_OnClockStart
,
760 audio_renderer_clock_sink_OnClockStop
,
761 audio_renderer_clock_sink_OnClockPause
,
762 audio_renderer_clock_sink_OnClockRestart
,
763 audio_renderer_clock_sink_OnClockSetRate
,
766 static HRESULT WINAPI
audio_renderer_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
768 struct audio_renderer
*renderer
= impl_from_IMFGetService(iface
);
769 return IMFMediaSink_QueryInterface(&renderer
->IMFMediaSink_iface
, riid
, obj
);
772 static ULONG WINAPI
audio_renderer_get_service_AddRef(IMFGetService
*iface
)
774 struct audio_renderer
*renderer
= impl_from_IMFGetService(iface
);
775 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
778 static ULONG WINAPI
audio_renderer_get_service_Release(IMFGetService
*iface
)
780 struct audio_renderer
*renderer
= impl_from_IMFGetService(iface
);
781 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
784 static HRESULT WINAPI
audio_renderer_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
786 struct audio_renderer
*renderer
= impl_from_IMFGetService(iface
);
788 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
792 if (IsEqualGUID(service
, &MR_POLICY_VOLUME_SERVICE
) && IsEqualIID(riid
, &IID_IMFSimpleAudioVolume
))
794 *obj
= &renderer
->IMFSimpleAudioVolume_iface
;
796 else if (IsEqualGUID(service
, &MR_STREAM_VOLUME_SERVICE
) && IsEqualIID(riid
, &IID_IMFAudioStreamVolume
))
798 *obj
= &renderer
->IMFAudioStreamVolume_iface
;
800 else if (IsEqualGUID(service
, &MR_AUDIO_POLICY_SERVICE
) && IsEqualIID(riid
, &IID_IMFAudioPolicy
))
802 *obj
= &renderer
->IMFAudioPolicy_iface
;
805 FIXME("Unsupported service %s, interface %s.\n", debugstr_guid(service
), debugstr_guid(riid
));
808 IUnknown_AddRef((IUnknown
*)*obj
);
810 return *obj
? S_OK
: E_NOINTERFACE
;
813 static const IMFGetServiceVtbl audio_renderer_get_service_vtbl
=
815 audio_renderer_get_service_QueryInterface
,
816 audio_renderer_get_service_AddRef
,
817 audio_renderer_get_service_Release
,
818 audio_renderer_get_service_GetService
,
821 static HRESULT WINAPI
audio_renderer_simple_volume_QueryInterface(IMFSimpleAudioVolume
*iface
, REFIID riid
, void **obj
)
823 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
825 if (IsEqualIID(riid
, &IID_IMFSimpleAudioVolume
) ||
826 IsEqualIID(riid
, &IID_IUnknown
))
829 IMFSimpleAudioVolume_AddRef(iface
);
833 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
835 return E_NOINTERFACE
;
838 static ULONG WINAPI
audio_renderer_simple_volume_AddRef(IMFSimpleAudioVolume
*iface
)
840 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
841 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
844 static ULONG WINAPI
audio_renderer_simple_volume_Release(IMFSimpleAudioVolume
*iface
)
846 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
847 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
850 static HRESULT WINAPI
audio_renderer_simple_volume_SetMasterVolume(IMFSimpleAudioVolume
*iface
, float level
)
852 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
855 TRACE("%p, %f.\n", iface
, level
);
857 EnterCriticalSection(&renderer
->cs
);
858 if (renderer
->audio_volume
)
859 hr
= ISimpleAudioVolume_SetMasterVolume(renderer
->audio_volume
, level
, NULL
);
860 LeaveCriticalSection(&renderer
->cs
);
865 static HRESULT WINAPI
audio_renderer_simple_volume_GetMasterVolume(IMFSimpleAudioVolume
*iface
, float *level
)
867 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
870 TRACE("%p, %p.\n", iface
, level
);
877 EnterCriticalSection(&renderer
->cs
);
878 if (renderer
->audio_volume
)
879 hr
= ISimpleAudioVolume_GetMasterVolume(renderer
->audio_volume
, level
);
880 LeaveCriticalSection(&renderer
->cs
);
885 static HRESULT WINAPI
audio_renderer_simple_volume_SetMute(IMFSimpleAudioVolume
*iface
, BOOL mute
)
887 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
890 TRACE("%p, %d.\n", iface
, mute
);
892 EnterCriticalSection(&renderer
->cs
);
893 if (renderer
->audio_volume
)
894 hr
= ISimpleAudioVolume_SetMute(renderer
->audio_volume
, mute
, NULL
);
895 LeaveCriticalSection(&renderer
->cs
);
900 static HRESULT WINAPI
audio_renderer_simple_volume_GetMute(IMFSimpleAudioVolume
*iface
, BOOL
*mute
)
902 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
905 TRACE("%p, %p.\n", iface
, mute
);
912 EnterCriticalSection(&renderer
->cs
);
913 if (renderer
->audio_volume
)
914 hr
= ISimpleAudioVolume_GetMute(renderer
->audio_volume
, mute
);
915 LeaveCriticalSection(&renderer
->cs
);
920 static const IMFSimpleAudioVolumeVtbl audio_renderer_simple_volume_vtbl
=
922 audio_renderer_simple_volume_QueryInterface
,
923 audio_renderer_simple_volume_AddRef
,
924 audio_renderer_simple_volume_Release
,
925 audio_renderer_simple_volume_SetMasterVolume
,
926 audio_renderer_simple_volume_GetMasterVolume
,
927 audio_renderer_simple_volume_SetMute
,
928 audio_renderer_simple_volume_GetMute
,
931 static HRESULT WINAPI
audio_renderer_stream_volume_QueryInterface(IMFAudioStreamVolume
*iface
, REFIID riid
, void **obj
)
933 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
935 if (IsEqualIID(riid
, &IID_IMFAudioStreamVolume
) ||
936 IsEqualIID(riid
, &IID_IUnknown
))
939 IMFAudioStreamVolume_AddRef(iface
);
943 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
945 return E_NOINTERFACE
;
948 static ULONG WINAPI
audio_renderer_stream_volume_AddRef(IMFAudioStreamVolume
*iface
)
950 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
951 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
954 static ULONG WINAPI
audio_renderer_stream_volume_Release(IMFAudioStreamVolume
*iface
)
956 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
957 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
960 static HRESULT WINAPI
audio_renderer_stream_volume_GetChannelCount(IMFAudioStreamVolume
*iface
, UINT32
*count
)
962 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
965 TRACE("%p, %p.\n", iface
, count
);
972 EnterCriticalSection(&renderer
->cs
);
973 if (renderer
->stream_volume
)
974 hr
= IAudioStreamVolume_GetChannelCount(renderer
->stream_volume
, count
);
975 LeaveCriticalSection(&renderer
->cs
);
980 static HRESULT WINAPI
audio_renderer_stream_volume_SetChannelVolume(IMFAudioStreamVolume
*iface
, UINT32 index
, float level
)
982 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
985 TRACE("%p, %u, %f.\n", iface
, index
, level
);
987 EnterCriticalSection(&renderer
->cs
);
988 if (renderer
->stream_volume
)
989 hr
= IAudioStreamVolume_SetChannelVolume(renderer
->stream_volume
, index
, level
);
990 LeaveCriticalSection(&renderer
->cs
);
995 static HRESULT WINAPI
audio_renderer_stream_volume_GetChannelVolume(IMFAudioStreamVolume
*iface
, UINT32 index
, float *level
)
997 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
1000 TRACE("%p, %u, %p.\n", iface
, index
, level
);
1007 EnterCriticalSection(&renderer
->cs
);
1008 if (renderer
->stream_volume
)
1009 hr
= IAudioStreamVolume_GetChannelVolume(renderer
->stream_volume
, index
, level
);
1010 LeaveCriticalSection(&renderer
->cs
);
1015 static HRESULT WINAPI
audio_renderer_stream_volume_SetAllVolumes(IMFAudioStreamVolume
*iface
, UINT32 count
,
1016 const float *volumes
)
1018 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
1021 TRACE("%p, %u, %p.\n", iface
, count
, volumes
);
1023 EnterCriticalSection(&renderer
->cs
);
1024 if (renderer
->stream_volume
)
1025 hr
= IAudioStreamVolume_SetAllVolumes(renderer
->stream_volume
, count
, volumes
);
1026 LeaveCriticalSection(&renderer
->cs
);
1031 static HRESULT WINAPI
audio_renderer_stream_volume_GetAllVolumes(IMFAudioStreamVolume
*iface
, UINT32 count
, float *volumes
)
1033 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
1036 TRACE("%p, %u, %p.\n", iface
, count
, volumes
);
1042 memset(volumes
, 0, sizeof(*volumes
) * count
);
1044 EnterCriticalSection(&renderer
->cs
);
1045 if (renderer
->stream_volume
)
1046 hr
= IAudioStreamVolume_GetAllVolumes(renderer
->stream_volume
, count
, volumes
);
1047 LeaveCriticalSection(&renderer
->cs
);
1052 static const IMFAudioStreamVolumeVtbl audio_renderer_stream_volume_vtbl
=
1054 audio_renderer_stream_volume_QueryInterface
,
1055 audio_renderer_stream_volume_AddRef
,
1056 audio_renderer_stream_volume_Release
,
1057 audio_renderer_stream_volume_GetChannelCount
,
1058 audio_renderer_stream_volume_SetChannelVolume
,
1059 audio_renderer_stream_volume_GetChannelVolume
,
1060 audio_renderer_stream_volume_SetAllVolumes
,
1061 audio_renderer_stream_volume_GetAllVolumes
,
1064 static HRESULT WINAPI
audio_renderer_policy_QueryInterface(IMFAudioPolicy
*iface
, REFIID riid
, void **obj
)
1066 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1068 if (IsEqualIID(riid
, &IID_IMFAudioPolicy
) ||
1069 IsEqualIID(riid
, &IID_IUnknown
))
1072 IMFAudioPolicy_AddRef(iface
);
1076 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
1078 return E_NOINTERFACE
;
1081 static ULONG WINAPI
audio_renderer_policy_AddRef(IMFAudioPolicy
*iface
)
1083 struct audio_renderer
*renderer
= impl_from_IMFAudioPolicy(iface
);
1084 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
1087 static ULONG WINAPI
audio_renderer_policy_Release(IMFAudioPolicy
*iface
)
1089 struct audio_renderer
*renderer
= impl_from_IMFAudioPolicy(iface
);
1090 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
1093 static HRESULT WINAPI
audio_renderer_policy_SetGroupingParam(IMFAudioPolicy
*iface
, REFGUID param
)
1095 FIXME("%p, %s.\n", iface
, debugstr_guid(param
));
1100 static HRESULT WINAPI
audio_renderer_policy_GetGroupingParam(IMFAudioPolicy
*iface
, GUID
*param
)
1102 FIXME("%p, %p.\n", iface
, param
);
1107 static HRESULT WINAPI
audio_renderer_policy_SetDisplayName(IMFAudioPolicy
*iface
, const WCHAR
*name
)
1109 FIXME("%p, %s.\n", iface
, debugstr_w(name
));
1114 static HRESULT WINAPI
audio_renderer_policy_GetDisplayName(IMFAudioPolicy
*iface
, WCHAR
**name
)
1116 FIXME("%p, %p.\n", iface
, name
);
1121 static HRESULT WINAPI
audio_renderer_policy_SetIconPath(IMFAudioPolicy
*iface
, const WCHAR
*path
)
1123 FIXME("%p, %s.\n", iface
, debugstr_w(path
));
1128 static HRESULT WINAPI
audio_renderer_policy_GetIconPath(IMFAudioPolicy
*iface
, WCHAR
**path
)
1130 FIXME("%p, %p.\n", iface
, path
);
1135 static const IMFAudioPolicyVtbl audio_renderer_policy_vtbl
=
1137 audio_renderer_policy_QueryInterface
,
1138 audio_renderer_policy_AddRef
,
1139 audio_renderer_policy_Release
,
1140 audio_renderer_policy_SetGroupingParam
,
1141 audio_renderer_policy_GetGroupingParam
,
1142 audio_renderer_policy_SetDisplayName
,
1143 audio_renderer_policy_GetDisplayName
,
1144 audio_renderer_policy_SetIconPath
,
1145 audio_renderer_policy_GetIconPath
,
1148 static HRESULT
sar_create_mmdevice(IMFAttributes
*attributes
, struct audio_renderer
*renderer
)
1151 unsigned int length
, role
= eMultimedia
;
1152 IMMDeviceEnumerator
*devenum
;
1157 /* Mutually exclusive attributes. */
1158 if (SUCCEEDED(IMFAttributes_GetItem(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE
, NULL
)) &&
1159 SUCCEEDED(IMFAttributes_GetItem(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID
, NULL
)))
1161 return E_INVALIDARG
;
1165 if (FAILED(hr
= CoCreateInstance(&CLSID_MMDeviceEnumerator
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMMDeviceEnumerator
,
1166 (void **)&devenum
)))
1172 if (attributes
&& SUCCEEDED(IMFAttributes_GetUINT32(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE
, &role
)))
1173 TRACE("Specified role %d.\n", role
);
1175 if (attributes
&& SUCCEEDED(IMFAttributes_GetAllocatedString(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID
,
1176 &endpoint
, &length
)))
1178 TRACE("Specified end point %s.\n", debugstr_w(endpoint
));
1179 hr
= IMMDeviceEnumerator_GetDevice(devenum
, endpoint
, &renderer
->device
);
1180 CoTaskMemFree(endpoint
);
1183 hr
= IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum
, eRender
, role
, &renderer
->device
);
1185 /* Configuration attributes to be used later for audio client initialization. */
1188 IMFAttributes_GetUINT32(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_FLAGS
, &renderer
->stream_config
.flags
);
1189 IMFAttributes_GetGUID(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_SESSION_ID
, &renderer
->stream_config
.session_id
);
1193 hr
= MF_E_NO_AUDIO_PLAYBACK_DEVICE
;
1195 IMMDeviceEnumerator_Release(devenum
);
1200 static HRESULT WINAPI
audio_renderer_stream_QueryInterface(IMFStreamSink
*iface
, REFIID riid
, void **obj
)
1202 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1204 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1206 if (IsEqualIID(riid
, &IID_IMFStreamSink
) ||
1207 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
1208 IsEqualIID(riid
, &IID_IUnknown
))
1210 *obj
= &renderer
->IMFStreamSink_iface
;
1212 else if (IsEqualIID(riid
, &IID_IMFMediaTypeHandler
))
1214 *obj
= &renderer
->IMFMediaTypeHandler_iface
;
1218 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1220 return E_NOINTERFACE
;
1223 IUnknown_AddRef((IUnknown
*)*obj
);
1228 static ULONG WINAPI
audio_renderer_stream_AddRef(IMFStreamSink
*iface
)
1230 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1231 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
1234 static ULONG WINAPI
audio_renderer_stream_Release(IMFStreamSink
*iface
)
1236 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1237 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
1240 static HRESULT WINAPI
audio_renderer_stream_GetEvent(IMFStreamSink
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1242 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1244 TRACE("%p, %#lx, %p.\n", iface
, flags
, event
);
1246 if (renderer
->flags
& SAR_SHUT_DOWN
)
1247 return MF_E_STREAMSINK_REMOVED
;
1249 return IMFMediaEventQueue_GetEvent(renderer
->stream_event_queue
, flags
, event
);
1252 static HRESULT WINAPI
audio_renderer_stream_BeginGetEvent(IMFStreamSink
*iface
, IMFAsyncCallback
*callback
,
1255 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1257 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1259 if (renderer
->flags
& SAR_SHUT_DOWN
)
1260 return MF_E_STREAMSINK_REMOVED
;
1262 return IMFMediaEventQueue_BeginGetEvent(renderer
->stream_event_queue
, callback
, state
);
1265 static HRESULT WINAPI
audio_renderer_stream_EndGetEvent(IMFStreamSink
*iface
, IMFAsyncResult
*result
,
1266 IMFMediaEvent
**event
)
1268 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1270 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1272 if (renderer
->flags
& SAR_SHUT_DOWN
)
1273 return MF_E_STREAMSINK_REMOVED
;
1275 return IMFMediaEventQueue_EndGetEvent(renderer
->stream_event_queue
, result
, event
);
1278 static HRESULT WINAPI
audio_renderer_stream_QueueEvent(IMFStreamSink
*iface
, MediaEventType event_type
,
1279 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
1281 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1283 TRACE("%p, %lu, %s, %#lx, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1285 if (renderer
->flags
& SAR_SHUT_DOWN
)
1286 return MF_E_STREAMSINK_REMOVED
;
1288 return IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, event_type
, ext_type
, hr
, value
);
1291 static HRESULT WINAPI
audio_renderer_stream_GetMediaSink(IMFStreamSink
*iface
, IMFMediaSink
**sink
)
1293 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1295 TRACE("%p, %p.\n", iface
, sink
);
1297 if (renderer
->flags
& SAR_SHUT_DOWN
)
1298 return MF_E_STREAMSINK_REMOVED
;
1300 *sink
= &renderer
->IMFMediaSink_iface
;
1301 IMFMediaSink_AddRef(*sink
);
1306 static HRESULT WINAPI
audio_renderer_stream_GetIdentifier(IMFStreamSink
*iface
, DWORD
*identifier
)
1308 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1310 TRACE("%p, %p.\n", iface
, identifier
);
1312 if (renderer
->flags
& SAR_SHUT_DOWN
)
1313 return MF_E_STREAMSINK_REMOVED
;
1320 static HRESULT WINAPI
audio_renderer_stream_GetMediaTypeHandler(IMFStreamSink
*iface
, IMFMediaTypeHandler
**handler
)
1322 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1324 TRACE("%p, %p.\n", iface
, handler
);
1329 if (renderer
->flags
& SAR_SHUT_DOWN
)
1330 return MF_E_STREAMSINK_REMOVED
;
1332 *handler
= &renderer
->IMFMediaTypeHandler_iface
;
1333 IMFMediaTypeHandler_AddRef(*handler
);
1338 static HRESULT
stream_queue_sample(struct audio_renderer
*renderer
, IMFSample
*sample
)
1340 struct queued_object
*object
;
1341 DWORD sample_len
, sample_frames
;
1344 if (FAILED(hr
= IMFSample_GetTotalLength(sample
, &sample_len
)))
1347 sample_frames
= sample_len
/ renderer
->frame_size
;
1349 if (!(object
= calloc(1, sizeof(*object
))))
1350 return E_OUTOFMEMORY
;
1352 object
->type
= OBJECT_TYPE_SAMPLE
;
1353 object
->u
.sample
.sample
= sample
;
1354 IMFSample_AddRef(object
->u
.sample
.sample
);
1356 list_add_tail(&renderer
->queue
, &object
->entry
);
1357 renderer
->queued_frames
+= sample_frames
;
1362 static HRESULT WINAPI
audio_renderer_stream_ProcessSample(IMFStreamSink
*iface
, IMFSample
*sample
)
1364 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1367 TRACE("%p, %p.\n", iface
, sample
);
1372 EnterCriticalSection(&renderer
->cs
);
1374 if (renderer
->flags
& SAR_SHUT_DOWN
)
1375 hr
= MF_E_STREAMSINK_REMOVED
;
1378 if (renderer
->state
== STREAM_STATE_RUNNING
)
1379 hr
= stream_queue_sample(renderer
, sample
);
1380 renderer
->flags
&= ~SAR_SAMPLE_REQUESTED
;
1382 if (renderer
->queued_frames
< renderer
->max_frames
&& renderer
->state
== STREAM_STATE_RUNNING
)
1384 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkRequestSample
,
1385 &GUID_NULL
, S_OK
, NULL
);
1386 renderer
->flags
|= SAR_SAMPLE_REQUESTED
;
1390 LeaveCriticalSection(&renderer
->cs
);
1395 static HRESULT
stream_place_marker(struct audio_renderer
*renderer
, MFSTREAMSINK_MARKER_TYPE marker_type
,
1396 const PROPVARIANT
*context_value
)
1398 struct queued_object
*marker
;
1401 if (!(marker
= calloc(1, sizeof(*marker
))))
1402 return E_OUTOFMEMORY
;
1404 marker
->type
= OBJECT_TYPE_MARKER
;
1405 marker
->u
.marker
.type
= marker_type
;
1406 PropVariantInit(&marker
->u
.marker
.context
);
1408 hr
= PropVariantCopy(&marker
->u
.marker
.context
, context_value
);
1410 list_add_tail(&renderer
->queue
, &marker
->entry
);
1412 release_pending_object(marker
);
1417 static HRESULT WINAPI
audio_renderer_stream_PlaceMarker(IMFStreamSink
*iface
, MFSTREAMSINK_MARKER_TYPE marker_type
,
1418 const PROPVARIANT
*marker_value
, const PROPVARIANT
*context_value
)
1420 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1423 TRACE("%p, %d, %p, %p.\n", iface
, marker_type
, marker_value
, context_value
);
1425 EnterCriticalSection(&renderer
->cs
);
1427 if (renderer
->flags
& SAR_SHUT_DOWN
)
1428 hr
= MF_E_STREAMSINK_REMOVED
;
1430 hr
= stream_place_marker(renderer
, marker_type
, context_value
);
1432 LeaveCriticalSection(&renderer
->cs
);
1437 static HRESULT WINAPI
audio_renderer_stream_Flush(IMFStreamSink
*iface
)
1439 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1440 struct queued_object
*obj
, *obj2
;
1443 TRACE("%p.\n", iface
);
1445 EnterCriticalSection(&renderer
->cs
);
1446 if (renderer
->flags
& SAR_SHUT_DOWN
)
1447 hr
= MF_E_STREAMSINK_REMOVED
;
1450 LIST_FOR_EACH_ENTRY_SAFE(obj
, obj2
, &renderer
->queue
, struct queued_object
, entry
)
1452 if (obj
->type
== OBJECT_TYPE_MARKER
)
1454 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkMarker
,
1455 &GUID_NULL
, S_OK
, &obj
->u
.marker
.context
);
1457 release_pending_object(obj
);
1460 renderer
->queued_frames
= 0;
1461 LeaveCriticalSection(&renderer
->cs
);
1466 static const IMFStreamSinkVtbl audio_renderer_stream_vtbl
=
1468 audio_renderer_stream_QueryInterface
,
1469 audio_renderer_stream_AddRef
,
1470 audio_renderer_stream_Release
,
1471 audio_renderer_stream_GetEvent
,
1472 audio_renderer_stream_BeginGetEvent
,
1473 audio_renderer_stream_EndGetEvent
,
1474 audio_renderer_stream_QueueEvent
,
1475 audio_renderer_stream_GetMediaSink
,
1476 audio_renderer_stream_GetIdentifier
,
1477 audio_renderer_stream_GetMediaTypeHandler
,
1478 audio_renderer_stream_ProcessSample
,
1479 audio_renderer_stream_PlaceMarker
,
1480 audio_renderer_stream_Flush
,
1483 static HRESULT WINAPI
audio_renderer_stream_type_handler_QueryInterface(IMFMediaTypeHandler
*iface
, REFIID riid
,
1486 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1487 return IMFStreamSink_QueryInterface(&renderer
->IMFStreamSink_iface
, riid
, obj
);
1490 static ULONG WINAPI
audio_renderer_stream_type_handler_AddRef(IMFMediaTypeHandler
*iface
)
1492 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1493 return IMFStreamSink_AddRef(&renderer
->IMFStreamSink_iface
);
1496 static ULONG WINAPI
audio_renderer_stream_type_handler_Release(IMFMediaTypeHandler
*iface
)
1498 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1499 return IMFStreamSink_Release(&renderer
->IMFStreamSink_iface
);
1502 static HRESULT
check_media_type(IMFMediaType
*type
, IMFMediaType
*current
)
1504 static const GUID
*required_attrs
[] =
1506 &MF_MT_AUDIO_SAMPLES_PER_SECOND
,
1507 &MF_MT_AUDIO_NUM_CHANNELS
,
1508 &MF_MT_AUDIO_BITS_PER_SAMPLE
,
1509 &MF_MT_AUDIO_BLOCK_ALIGNMENT
,
1510 &MF_MT_AUDIO_AVG_BYTES_PER_SECOND
,
1518 if (FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major
)))
1520 if (!IsEqualGUID(&major
, &MFMediaType_Audio
))
1521 return MF_E_INVALIDMEDIATYPE
;
1523 for (i
= 0; SUCCEEDED(hr
) && i
< ARRAY_SIZE(required_attrs
); ++i
)
1525 PropVariantInit(&value
);
1526 hr
= IMFMediaType_GetItem(type
, required_attrs
[i
], &value
);
1528 hr
= IMFMediaType_CompareItem(current
, required_attrs
[i
], &value
, &result
);
1529 if (SUCCEEDED(hr
) && !result
)
1530 hr
= MF_E_INVALIDMEDIATYPE
;
1531 PropVariantClear(&value
);
1535 return MF_E_INVALIDMEDIATYPE
;
1540 static HRESULT WINAPI
audio_renderer_stream_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler
*iface
,
1541 IMFMediaType
*in_type
, IMFMediaType
**out_type
)
1543 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1546 TRACE("%p, %p, %p.\n", iface
, in_type
, out_type
);
1548 EnterCriticalSection(&renderer
->cs
);
1549 hr
= check_media_type(in_type
, renderer
->media_type
);
1550 LeaveCriticalSection(&renderer
->cs
);
1555 static HRESULT WINAPI
audio_renderer_stream_type_handler_GetMediaTypeCount(IMFMediaTypeHandler
*iface
, DWORD
*count
)
1557 TRACE("%p, %p.\n", iface
, count
);
1564 static HRESULT WINAPI
audio_renderer_stream_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler
*iface
, DWORD index
,
1565 IMFMediaType
**media_type
)
1567 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1569 TRACE("%p, %lu, %p.\n", iface
, index
, media_type
);
1572 return MF_E_NO_MORE_TYPES
;
1574 *media_type
= renderer
->media_type
;
1575 IMFMediaType_AddRef(*media_type
);
1579 static HRESULT
audio_renderer_create_audio_client(struct audio_renderer
*renderer
)
1581 IMFAsyncResult
*result
;
1586 audio_renderer_release_audio_client(renderer
);
1588 hr
= IMMDevice_Activate(renderer
->device
, &IID_IAudioClient
, CLSCTX_INPROC_SERVER
, NULL
,
1589 (void **)&renderer
->audio_client
);
1592 WARN("Failed to create audio client, hr %#lx.\n", hr
);
1596 /* FIXME: for now always use default format. */
1597 if (FAILED(hr
= IAudioClient_GetMixFormat(renderer
->audio_client
, &wfx
)))
1599 WARN("Failed to get audio format, hr %#lx.\n", hr
);
1603 renderer
->frame_size
= wfx
->wBitsPerSample
* wfx
->nChannels
/ 8;
1605 flags
= AUDCLNT_STREAMFLAGS_EVENTCALLBACK
;
1606 if (renderer
->stream_config
.flags
& MF_AUDIO_RENDERER_ATTRIBUTE_FLAGS_CROSSPROCESS
)
1607 flags
|= AUDCLNT_STREAMFLAGS_CROSSPROCESS
;
1608 if (renderer
->stream_config
.flags
& MF_AUDIO_RENDERER_ATTRIBUTE_FLAGS_NOPERSIST
)
1609 flags
|= AUDCLNT_STREAMFLAGS_NOPERSIST
;
1610 hr
= IAudioClient_Initialize(renderer
->audio_client
, AUDCLNT_SHAREMODE_SHARED
, flags
, 1000000, 0, wfx
,
1611 &renderer
->stream_config
.session_id
);
1615 WARN("Failed to initialize audio client, hr %#lx.\n", hr
);
1619 if (FAILED(hr
= IAudioClient_GetService(renderer
->audio_client
, &IID_IAudioStreamVolume
,
1620 (void **)&renderer
->stream_volume
)))
1622 WARN("Failed to get stream volume control, hr %#lx.\n", hr
);
1626 if (FAILED(hr
= IAudioClient_GetService(renderer
->audio_client
, &IID_ISimpleAudioVolume
, (void **)&renderer
->audio_volume
)))
1628 WARN("Failed to get audio volume control, hr %#lx.\n", hr
);
1632 if (FAILED(hr
= IAudioClient_GetService(renderer
->audio_client
, &IID_IAudioRenderClient
,
1633 (void **)&renderer
->audio_render_client
)))
1635 WARN("Failed to get audio render client, hr %#lx.\n", hr
);
1639 if (FAILED(hr
= IAudioClient_SetEventHandle(renderer
->audio_client
, renderer
->buffer_ready_event
)))
1641 WARN("Failed to set event handle, hr %#lx.\n", hr
);
1645 if (FAILED(hr
= IAudioClient_GetBufferSize(renderer
->audio_client
, &renderer
->max_frames
)))
1647 WARN("Failed to get buffer size, hr %#lx.\n", hr
);
1651 if (SUCCEEDED(hr
= MFCreateAsyncResult(NULL
, &renderer
->render_callback
, NULL
, &result
)))
1653 if (FAILED(hr
= MFPutWaitingWorkItem(renderer
->buffer_ready_event
, 0, result
, &renderer
->buffer_ready_key
)))
1654 WARN("Failed to submit wait item, hr %#lx.\n", hr
);
1655 IMFAsyncResult_Release(result
);
1661 static HRESULT WINAPI
audio_renderer_stream_type_handler_SetCurrentMediaType(IMFMediaTypeHandler
*iface
,
1662 IMFMediaType
*media_type
)
1664 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1665 BOOL compare_result
;
1668 TRACE("%p, %p.\n", iface
, media_type
);
1673 EnterCriticalSection(&renderer
->cs
);
1674 if (SUCCEEDED(hr
= check_media_type(media_type
, renderer
->media_type
)))
1676 if (renderer
->current_media_type
)
1677 IMFMediaType_Release(renderer
->current_media_type
);
1678 renderer
->current_media_type
= media_type
;
1679 IMFMediaType_AddRef(renderer
->current_media_type
);
1681 if (SUCCEEDED(hr
= audio_renderer_create_audio_client(renderer
)))
1683 if (SUCCEEDED(IMFMediaType_Compare(renderer
->media_type
, (IMFAttributes
*)media_type
, MF_ATTRIBUTES_MATCH_OUR_ITEMS
,
1684 &compare_result
)) && !compare_result
)
1686 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkFormatInvalidated
, &GUID_NULL
,
1688 audio_renderer_preroll(renderer
);
1693 hr
= MF_E_INVALIDMEDIATYPE
;
1694 LeaveCriticalSection(&renderer
->cs
);
1699 static HRESULT WINAPI
audio_renderer_stream_type_handler_GetCurrentMediaType(IMFMediaTypeHandler
*iface
,
1700 IMFMediaType
**media_type
)
1702 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1705 TRACE("%p, %p.\n", iface
, media_type
);
1707 EnterCriticalSection(&renderer
->cs
);
1708 if (renderer
->current_media_type
)
1710 *media_type
= renderer
->current_media_type
;
1711 IMFMediaType_AddRef(*media_type
);
1714 hr
= MF_E_NOT_INITIALIZED
;
1715 LeaveCriticalSection(&renderer
->cs
);
1720 static HRESULT WINAPI
audio_renderer_stream_type_handler_GetMajorType(IMFMediaTypeHandler
*iface
, GUID
*type
)
1722 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1724 TRACE("%p, %p.\n", iface
, type
);
1729 if (renderer
->flags
& SAR_SHUT_DOWN
)
1730 return MF_E_STREAMSINK_REMOVED
;
1732 memcpy(type
, &MFMediaType_Audio
, sizeof(*type
));
1736 static const IMFMediaTypeHandlerVtbl audio_renderer_stream_type_handler_vtbl
=
1738 audio_renderer_stream_type_handler_QueryInterface
,
1739 audio_renderer_stream_type_handler_AddRef
,
1740 audio_renderer_stream_type_handler_Release
,
1741 audio_renderer_stream_type_handler_IsMediaTypeSupported
,
1742 audio_renderer_stream_type_handler_GetMediaTypeCount
,
1743 audio_renderer_stream_type_handler_GetMediaTypeByIndex
,
1744 audio_renderer_stream_type_handler_SetCurrentMediaType
,
1745 audio_renderer_stream_type_handler_GetCurrentMediaType
,
1746 audio_renderer_stream_type_handler_GetMajorType
,
1749 static HRESULT
audio_renderer_collect_supported_types(struct audio_renderer
*renderer
)
1751 IAudioClient
*client
;
1752 WAVEFORMATEX
*format
;
1755 if (FAILED(hr
= MFCreateMediaType(&renderer
->media_type
)))
1758 hr
= IMMDevice_Activate(renderer
->device
, &IID_IAudioClient
, CLSCTX_INPROC_SERVER
, NULL
, (void **)&client
);
1761 WARN("Failed to create audio client, hr %#lx.\n", hr
);
1767 hr
= IAudioClient_GetMixFormat(client
, &format
);
1768 IAudioClient_Release(client
);
1771 WARN("Failed to get device audio format, hr %#lx.\n", hr
);
1775 hr
= MFInitMediaTypeFromWaveFormatEx(renderer
->media_type
, format
, format
->cbSize
+ sizeof(*format
));
1776 CoTaskMemFree(format
);
1779 WARN("Failed to initialize media type, hr %#lx.\n", hr
);
1786 static HRESULT WINAPI
audio_renderer_render_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
1788 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1790 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
1791 IsEqualIID(riid
, &IID_IUnknown
))
1794 IMFAsyncCallback_AddRef(iface
);
1798 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
1800 return E_NOINTERFACE
;
1803 static ULONG WINAPI
audio_renderer_render_callback_AddRef(IMFAsyncCallback
*iface
)
1805 struct audio_renderer
*renderer
= impl_from_render_callback_IMFAsyncCallback(iface
);
1806 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
1809 static ULONG WINAPI
audio_renderer_render_callback_Release(IMFAsyncCallback
*iface
)
1811 struct audio_renderer
*renderer
= impl_from_render_callback_IMFAsyncCallback(iface
);
1812 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
1815 static HRESULT WINAPI
audio_renderer_render_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
1820 static void audio_renderer_render(struct audio_renderer
*renderer
, IMFAsyncResult
*result
)
1822 unsigned int src_frames
, dst_frames
, max_frames
, pad_frames
;
1823 struct queued_object
*obj
, *obj2
;
1824 BOOL keep_sample
= FALSE
;
1825 IMFMediaBuffer
*buffer
;
1830 LIST_FOR_EACH_ENTRY_SAFE(obj
, obj2
, &renderer
->queue
, struct queued_object
, entry
)
1832 if (obj
->type
== OBJECT_TYPE_MARKER
)
1834 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkMarker
,
1835 &GUID_NULL
, S_OK
, &obj
->u
.marker
.context
);
1837 else if (obj
->type
== OBJECT_TYPE_SAMPLE
)
1839 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(obj
->u
.sample
.sample
, &buffer
)))
1841 if (SUCCEEDED(IMFMediaBuffer_Lock(buffer
, &src
, NULL
, &src_len
)))
1843 if ((src_frames
= src_len
/ renderer
->frame_size
))
1845 if (SUCCEEDED(IAudioClient_GetBufferSize(renderer
->audio_client
, &max_frames
)))
1847 if (SUCCEEDED(IAudioClient_GetCurrentPadding(renderer
->audio_client
, &pad_frames
)))
1849 max_frames
-= pad_frames
;
1850 src_frames
-= obj
->u
.sample
.frame_offset
;
1851 dst_frames
= min(src_frames
, max_frames
);
1853 if (SUCCEEDED(hr
= IAudioRenderClient_GetBuffer(renderer
->audio_render_client
, dst_frames
, &dst
)))
1855 memcpy(dst
, src
+ obj
->u
.sample
.frame_offset
* renderer
->frame_size
,
1856 dst_frames
* renderer
->frame_size
);
1858 IAudioRenderClient_ReleaseBuffer(renderer
->audio_render_client
, dst_frames
, 0);
1860 obj
->u
.sample
.frame_offset
+= dst_frames
;
1861 renderer
->queued_frames
-= dst_frames
;
1864 keep_sample
= FAILED(hr
) || src_frames
> max_frames
;
1868 IMFMediaBuffer_Unlock(buffer
);
1870 IMFMediaBuffer_Release(buffer
);
1877 list_remove(&obj
->entry
);
1878 release_pending_object(obj
);
1881 if (list_empty(&renderer
->queue
) && !(renderer
->flags
& SAR_SAMPLE_REQUESTED
))
1883 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkRequestSample
, &GUID_NULL
, S_OK
, NULL
);
1884 renderer
->flags
|= SAR_SAMPLE_REQUESTED
;
1887 if (FAILED(hr
= MFPutWaitingWorkItem(renderer
->buffer_ready_event
, 0, result
, &renderer
->buffer_ready_key
)))
1888 WARN("Failed to submit wait item, hr %#lx.\n", hr
);
1891 static HRESULT WINAPI
audio_renderer_render_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1893 struct audio_renderer
*renderer
= impl_from_render_callback_IMFAsyncCallback(iface
);
1895 EnterCriticalSection(&renderer
->cs
);
1896 if (!(renderer
->flags
& SAR_SHUT_DOWN
))
1897 audio_renderer_render(renderer
, result
);
1898 LeaveCriticalSection(&renderer
->cs
);
1903 static const IMFAsyncCallbackVtbl audio_renderer_render_callback_vtbl
=
1905 audio_renderer_render_callback_QueryInterface
,
1906 audio_renderer_render_callback_AddRef
,
1907 audio_renderer_render_callback_Release
,
1908 audio_renderer_render_callback_GetParameters
,
1909 audio_renderer_render_callback_Invoke
,
1912 static HRESULT
sar_create_object(IMFAttributes
*attributes
, void *user_context
, IUnknown
**obj
)
1914 struct audio_renderer
*renderer
;
1917 TRACE("%p, %p, %p.\n", attributes
, user_context
, obj
);
1919 if (!(renderer
= calloc(1, sizeof(*renderer
))))
1920 return E_OUTOFMEMORY
;
1922 renderer
->IMFMediaSink_iface
.lpVtbl
= &audio_renderer_sink_vtbl
;
1923 renderer
->IMFMediaSinkPreroll_iface
.lpVtbl
= &audio_renderer_preroll_vtbl
;
1924 renderer
->IMFStreamSink_iface
.lpVtbl
= &audio_renderer_stream_vtbl
;
1925 renderer
->IMFMediaTypeHandler_iface
.lpVtbl
= &audio_renderer_stream_type_handler_vtbl
;
1926 renderer
->IMFClockStateSink_iface
.lpVtbl
= &audio_renderer_clock_sink_vtbl
;
1927 renderer
->IMFMediaEventGenerator_iface
.lpVtbl
= &audio_renderer_events_vtbl
;
1928 renderer
->IMFGetService_iface
.lpVtbl
= &audio_renderer_get_service_vtbl
;
1929 renderer
->IMFSimpleAudioVolume_iface
.lpVtbl
= &audio_renderer_simple_volume_vtbl
;
1930 renderer
->IMFAudioStreamVolume_iface
.lpVtbl
= &audio_renderer_stream_volume_vtbl
;
1931 renderer
->IMFAudioPolicy_iface
.lpVtbl
= &audio_renderer_policy_vtbl
;
1932 renderer
->render_callback
.lpVtbl
= &audio_renderer_render_callback_vtbl
;
1933 renderer
->refcount
= 1;
1934 InitializeCriticalSection(&renderer
->cs
);
1935 renderer
->buffer_ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1936 list_init(&renderer
->queue
);
1938 if (FAILED(hr
= MFCreateEventQueue(&renderer
->event_queue
)))
1941 if (FAILED(hr
= MFCreateEventQueue(&renderer
->stream_event_queue
)))
1944 if (FAILED(hr
= sar_create_mmdevice(attributes
, renderer
)))
1947 if (FAILED(hr
= audio_renderer_collect_supported_types(renderer
)))
1950 *obj
= (IUnknown
*)&renderer
->IMFMediaSink_iface
;
1956 IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
1961 BOOL
mf_is_sar_sink(IMFMediaSink
*sink
)
1963 return sink
->lpVtbl
== &audio_renderer_sink_vtbl
;
1966 static void sar_shutdown_object(void *user_context
, IUnknown
*obj
)
1970 if (SUCCEEDED(IUnknown_QueryInterface(obj
, &IID_IMFMediaSink
, (void **)&sink
)))
1972 IMFMediaSink_Shutdown(sink
);
1973 IMFMediaSink_Release(sink
);
1977 static const struct activate_funcs sar_activate_funcs
=
1979 .create_object
= sar_create_object
,
1980 .shutdown_object
= sar_shutdown_object
,
1983 /***********************************************************************
1984 * MFCreateAudioRendererActivate (mf.@)
1986 HRESULT WINAPI
MFCreateAudioRendererActivate(IMFActivate
**activate
)
1988 TRACE("%p.\n", activate
);
1993 return create_activation_object(NULL
, &sar_activate_funcs
, activate
);
1996 /***********************************************************************
1997 * MFCreateAudioRenderer (mf.@)
1999 HRESULT WINAPI
MFCreateAudioRenderer(IMFAttributes
*attributes
, IMFMediaSink
**sink
)
2004 TRACE("%p, %p.\n", attributes
, sink
);
2006 if (SUCCEEDED(hr
= sar_create_object(attributes
, NULL
, &object
)))
2008 hr
= IUnknown_QueryInterface(object
, &IID_IMFMediaSink
, (void **)sink
);
2009 IUnknown_Release(object
);