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 %u.\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 %u.\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, %#x, %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, %#x.\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, %u, %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, %#x, %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
);
455 TRACE("%p.\n", iface
);
457 if (renderer
->flags
& SAR_SHUT_DOWN
)
458 return MF_E_SHUTDOWN
;
460 EnterCriticalSection(&renderer
->cs
);
461 renderer
->flags
|= SAR_SHUT_DOWN
;
462 IMFMediaEventQueue_Shutdown(renderer
->event_queue
);
463 IMFMediaEventQueue_Shutdown(renderer
->stream_event_queue
);
464 audio_renderer_set_presentation_clock(renderer
, NULL
);
465 audio_renderer_release_audio_client(renderer
);
466 LeaveCriticalSection(&renderer
->cs
);
471 static const IMFMediaSinkVtbl audio_renderer_sink_vtbl
=
473 audio_renderer_sink_QueryInterface
,
474 audio_renderer_sink_AddRef
,
475 audio_renderer_sink_Release
,
476 audio_renderer_sink_GetCharacteristics
,
477 audio_renderer_sink_AddStreamSink
,
478 audio_renderer_sink_RemoveStreamSink
,
479 audio_renderer_sink_GetStreamSinkCount
,
480 audio_renderer_sink_GetStreamSinkByIndex
,
481 audio_renderer_sink_GetStreamSinkById
,
482 audio_renderer_sink_SetPresentationClock
,
483 audio_renderer_sink_GetPresentationClock
,
484 audio_renderer_sink_Shutdown
,
487 static void audio_renderer_preroll(struct audio_renderer
*renderer
)
491 if (renderer
->flags
& SAR_PREROLLED
)
494 for (i
= 0; i
< 2; ++i
)
495 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkRequestSample
, &GUID_NULL
, S_OK
, NULL
);
496 renderer
->flags
|= SAR_PREROLLED
;
499 static HRESULT WINAPI
audio_renderer_preroll_QueryInterface(IMFMediaSinkPreroll
*iface
, REFIID riid
, void **obj
)
501 struct audio_renderer
*renderer
= impl_from_IMFMediaSinkPreroll(iface
);
502 return IMFMediaSink_QueryInterface(&renderer
->IMFMediaSink_iface
, riid
, obj
);
505 static ULONG WINAPI
audio_renderer_preroll_AddRef(IMFMediaSinkPreroll
*iface
)
507 struct audio_renderer
*renderer
= impl_from_IMFMediaSinkPreroll(iface
);
508 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
511 static ULONG WINAPI
audio_renderer_preroll_Release(IMFMediaSinkPreroll
*iface
)
513 struct audio_renderer
*renderer
= impl_from_IMFMediaSinkPreroll(iface
);
514 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
517 static HRESULT WINAPI
audio_renderer_preroll_NotifyPreroll(IMFMediaSinkPreroll
*iface
, MFTIME start_time
)
519 struct audio_renderer
*renderer
= impl_from_IMFMediaSinkPreroll(iface
);
521 TRACE("%p, %s.\n", iface
, debugstr_time(start_time
));
523 if (renderer
->flags
& SAR_SHUT_DOWN
)
524 return MF_E_SHUTDOWN
;
526 audio_renderer_preroll(renderer
);
527 return IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkPrerolled
, &GUID_NULL
, S_OK
, NULL
);
530 static const IMFMediaSinkPrerollVtbl audio_renderer_preroll_vtbl
=
532 audio_renderer_preroll_QueryInterface
,
533 audio_renderer_preroll_AddRef
,
534 audio_renderer_preroll_Release
,
535 audio_renderer_preroll_NotifyPreroll
,
538 static HRESULT WINAPI
audio_renderer_events_QueryInterface(IMFMediaEventGenerator
*iface
, REFIID riid
, void **obj
)
540 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
541 return IMFMediaSink_QueryInterface(&renderer
->IMFMediaSink_iface
, riid
, obj
);
544 static ULONG WINAPI
audio_renderer_events_AddRef(IMFMediaEventGenerator
*iface
)
546 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
547 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
550 static ULONG WINAPI
audio_renderer_events_Release(IMFMediaEventGenerator
*iface
)
552 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
553 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
556 static HRESULT WINAPI
audio_renderer_events_GetEvent(IMFMediaEventGenerator
*iface
, DWORD flags
, IMFMediaEvent
**event
)
558 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
560 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
562 return IMFMediaEventQueue_GetEvent(renderer
->event_queue
, flags
, event
);
565 static HRESULT WINAPI
audio_renderer_events_BeginGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncCallback
*callback
,
568 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
570 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
572 return IMFMediaEventQueue_BeginGetEvent(renderer
->event_queue
, callback
, state
);
575 static HRESULT WINAPI
audio_renderer_events_EndGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncResult
*result
,
576 IMFMediaEvent
**event
)
578 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
580 TRACE("%p, %p, %p.\n", iface
, result
, event
);
582 return IMFMediaEventQueue_EndGetEvent(renderer
->event_queue
, result
, event
);
585 static HRESULT WINAPI
audio_renderer_events_QueueEvent(IMFMediaEventGenerator
*iface
, MediaEventType event_type
,
586 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
588 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
590 TRACE("%p, %u, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
592 return IMFMediaEventQueue_QueueEventParamVar(renderer
->event_queue
, event_type
, ext_type
, hr
, value
);
595 static const IMFMediaEventGeneratorVtbl audio_renderer_events_vtbl
=
597 audio_renderer_events_QueryInterface
,
598 audio_renderer_events_AddRef
,
599 audio_renderer_events_Release
,
600 audio_renderer_events_GetEvent
,
601 audio_renderer_events_BeginGetEvent
,
602 audio_renderer_events_EndGetEvent
,
603 audio_renderer_events_QueueEvent
,
606 static HRESULT WINAPI
audio_renderer_clock_sink_QueryInterface(IMFClockStateSink
*iface
, REFIID riid
, void **obj
)
608 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
609 return IMFMediaSink_QueryInterface(&renderer
->IMFMediaSink_iface
, riid
, obj
);
612 static ULONG WINAPI
audio_renderer_clock_sink_AddRef(IMFClockStateSink
*iface
)
614 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
615 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
618 static ULONG WINAPI
audio_renderer_clock_sink_Release(IMFClockStateSink
*iface
)
620 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
621 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
624 static HRESULT WINAPI
audio_renderer_clock_sink_OnClockStart(IMFClockStateSink
*iface
, MFTIME systime
, LONGLONG offset
)
626 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
629 TRACE("%p, %s, %s.\n", iface
, debugstr_time(systime
), debugstr_time(offset
));
631 EnterCriticalSection(&renderer
->cs
);
632 if (renderer
->audio_client
)
634 if (renderer
->state
== STREAM_STATE_STOPPED
)
636 if (FAILED(hr
= IAudioClient_Start(renderer
->audio_client
)))
637 WARN("Failed to start audio client, hr %#x.\n", hr
);
638 renderer
->state
= STREAM_STATE_RUNNING
;
642 hr
= MF_E_NOT_INITIALIZED
;
644 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkStarted
, &GUID_NULL
, hr
, NULL
);
646 audio_renderer_preroll(renderer
);
647 LeaveCriticalSection(&renderer
->cs
);
652 static HRESULT WINAPI
audio_renderer_clock_sink_OnClockStop(IMFClockStateSink
*iface
, MFTIME systime
)
654 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
657 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
659 EnterCriticalSection(&renderer
->cs
);
660 if (renderer
->audio_client
)
662 if (renderer
->state
!= STREAM_STATE_STOPPED
)
664 if (SUCCEEDED(hr
= IAudioClient_Stop(renderer
->audio_client
)))
666 if (FAILED(hr
= IAudioClient_Reset(renderer
->audio_client
)))
667 WARN("Failed to reset audio client, hr %#x.\n", hr
);
670 WARN("Failed to stop audio client, hr %#x.\n", hr
);
671 renderer
->state
= STREAM_STATE_STOPPED
;
672 renderer
->flags
&= ~SAR_PREROLLED
;
676 hr
= MF_E_NOT_INITIALIZED
;
678 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkStopped
, &GUID_NULL
, hr
, NULL
);
679 LeaveCriticalSection(&renderer
->cs
);
684 static HRESULT WINAPI
audio_renderer_clock_sink_OnClockPause(IMFClockStateSink
*iface
, MFTIME systime
)
686 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
689 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
691 EnterCriticalSection(&renderer
->cs
);
692 if (renderer
->state
== STREAM_STATE_RUNNING
)
694 if (renderer
->audio_client
)
696 if (FAILED(hr
= IAudioClient_Stop(renderer
->audio_client
)))
697 WARN("Failed to stop audio client, hr %#x.\n", hr
);
698 renderer
->state
= STREAM_STATE_PAUSED
;
701 hr
= MF_E_NOT_INITIALIZED
;
703 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkPaused
, &GUID_NULL
, hr
, NULL
);
706 hr
= MF_E_INVALID_STATE_TRANSITION
;
707 LeaveCriticalSection(&renderer
->cs
);
712 static HRESULT WINAPI
audio_renderer_clock_sink_OnClockRestart(IMFClockStateSink
*iface
, MFTIME systime
)
714 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
715 BOOL preroll
= FALSE
;
718 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
720 EnterCriticalSection(&renderer
->cs
);
721 if (renderer
->audio_client
)
723 if ((preroll
= (renderer
->state
!= STREAM_STATE_RUNNING
)))
725 if (FAILED(hr
= IAudioClient_Start(renderer
->audio_client
)))
726 WARN("Failed to start audio client, hr %#x.\n", hr
);
727 renderer
->state
= STREAM_STATE_RUNNING
;
731 hr
= MF_E_NOT_INITIALIZED
;
733 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkStarted
, &GUID_NULL
, hr
, NULL
);
735 audio_renderer_preroll(renderer
);
737 LeaveCriticalSection(&renderer
->cs
);
742 static HRESULT WINAPI
audio_renderer_clock_sink_OnClockSetRate(IMFClockStateSink
*iface
, MFTIME systime
, float rate
)
744 FIXME("%p, %s, %f.\n", iface
, debugstr_time(systime
), rate
);
749 static const IMFClockStateSinkVtbl audio_renderer_clock_sink_vtbl
=
751 audio_renderer_clock_sink_QueryInterface
,
752 audio_renderer_clock_sink_AddRef
,
753 audio_renderer_clock_sink_Release
,
754 audio_renderer_clock_sink_OnClockStart
,
755 audio_renderer_clock_sink_OnClockStop
,
756 audio_renderer_clock_sink_OnClockPause
,
757 audio_renderer_clock_sink_OnClockRestart
,
758 audio_renderer_clock_sink_OnClockSetRate
,
761 static HRESULT WINAPI
audio_renderer_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
763 struct audio_renderer
*renderer
= impl_from_IMFGetService(iface
);
764 return IMFMediaSink_QueryInterface(&renderer
->IMFMediaSink_iface
, riid
, obj
);
767 static ULONG WINAPI
audio_renderer_get_service_AddRef(IMFGetService
*iface
)
769 struct audio_renderer
*renderer
= impl_from_IMFGetService(iface
);
770 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
773 static ULONG WINAPI
audio_renderer_get_service_Release(IMFGetService
*iface
)
775 struct audio_renderer
*renderer
= impl_from_IMFGetService(iface
);
776 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
779 static HRESULT WINAPI
audio_renderer_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
781 struct audio_renderer
*renderer
= impl_from_IMFGetService(iface
);
783 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
787 if (IsEqualGUID(service
, &MR_POLICY_VOLUME_SERVICE
) && IsEqualIID(riid
, &IID_IMFSimpleAudioVolume
))
789 *obj
= &renderer
->IMFSimpleAudioVolume_iface
;
791 else if (IsEqualGUID(service
, &MR_STREAM_VOLUME_SERVICE
) && IsEqualIID(riid
, &IID_IMFAudioStreamVolume
))
793 *obj
= &renderer
->IMFAudioStreamVolume_iface
;
795 else if (IsEqualGUID(service
, &MR_AUDIO_POLICY_SERVICE
) && IsEqualIID(riid
, &IID_IMFAudioPolicy
))
797 *obj
= &renderer
->IMFAudioPolicy_iface
;
800 FIXME("Unsupported service %s, interface %s.\n", debugstr_guid(service
), debugstr_guid(riid
));
803 IUnknown_AddRef((IUnknown
*)*obj
);
805 return *obj
? S_OK
: E_NOINTERFACE
;
808 static const IMFGetServiceVtbl audio_renderer_get_service_vtbl
=
810 audio_renderer_get_service_QueryInterface
,
811 audio_renderer_get_service_AddRef
,
812 audio_renderer_get_service_Release
,
813 audio_renderer_get_service_GetService
,
816 static HRESULT WINAPI
audio_renderer_simple_volume_QueryInterface(IMFSimpleAudioVolume
*iface
, REFIID riid
, void **obj
)
818 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
820 if (IsEqualIID(riid
, &IID_IMFSimpleAudioVolume
) ||
821 IsEqualIID(riid
, &IID_IUnknown
))
824 IMFSimpleAudioVolume_AddRef(iface
);
828 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
830 return E_NOINTERFACE
;
833 static ULONG WINAPI
audio_renderer_simple_volume_AddRef(IMFSimpleAudioVolume
*iface
)
835 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
836 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
839 static ULONG WINAPI
audio_renderer_simple_volume_Release(IMFSimpleAudioVolume
*iface
)
841 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
842 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
845 static HRESULT WINAPI
audio_renderer_simple_volume_SetMasterVolume(IMFSimpleAudioVolume
*iface
, float level
)
847 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
850 TRACE("%p, %f.\n", iface
, level
);
852 EnterCriticalSection(&renderer
->cs
);
853 if (renderer
->audio_volume
)
854 hr
= ISimpleAudioVolume_SetMasterVolume(renderer
->audio_volume
, level
, NULL
);
855 LeaveCriticalSection(&renderer
->cs
);
860 static HRESULT WINAPI
audio_renderer_simple_volume_GetMasterVolume(IMFSimpleAudioVolume
*iface
, float *level
)
862 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
865 TRACE("%p, %p.\n", iface
, level
);
872 EnterCriticalSection(&renderer
->cs
);
873 if (renderer
->audio_volume
)
874 hr
= ISimpleAudioVolume_GetMasterVolume(renderer
->audio_volume
, level
);
875 LeaveCriticalSection(&renderer
->cs
);
880 static HRESULT WINAPI
audio_renderer_simple_volume_SetMute(IMFSimpleAudioVolume
*iface
, BOOL mute
)
882 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
885 TRACE("%p, %d.\n", iface
, mute
);
887 EnterCriticalSection(&renderer
->cs
);
888 if (renderer
->audio_volume
)
889 hr
= ISimpleAudioVolume_SetMute(renderer
->audio_volume
, mute
, NULL
);
890 LeaveCriticalSection(&renderer
->cs
);
895 static HRESULT WINAPI
audio_renderer_simple_volume_GetMute(IMFSimpleAudioVolume
*iface
, BOOL
*mute
)
897 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
900 TRACE("%p, %p.\n", iface
, mute
);
907 EnterCriticalSection(&renderer
->cs
);
908 if (renderer
->audio_volume
)
909 hr
= ISimpleAudioVolume_GetMute(renderer
->audio_volume
, mute
);
910 LeaveCriticalSection(&renderer
->cs
);
915 static const IMFSimpleAudioVolumeVtbl audio_renderer_simple_volume_vtbl
=
917 audio_renderer_simple_volume_QueryInterface
,
918 audio_renderer_simple_volume_AddRef
,
919 audio_renderer_simple_volume_Release
,
920 audio_renderer_simple_volume_SetMasterVolume
,
921 audio_renderer_simple_volume_GetMasterVolume
,
922 audio_renderer_simple_volume_SetMute
,
923 audio_renderer_simple_volume_GetMute
,
926 static HRESULT WINAPI
audio_renderer_stream_volume_QueryInterface(IMFAudioStreamVolume
*iface
, REFIID riid
, void **obj
)
928 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
930 if (IsEqualIID(riid
, &IID_IMFAudioStreamVolume
) ||
931 IsEqualIID(riid
, &IID_IUnknown
))
934 IMFAudioStreamVolume_AddRef(iface
);
938 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
940 return E_NOINTERFACE
;
943 static ULONG WINAPI
audio_renderer_stream_volume_AddRef(IMFAudioStreamVolume
*iface
)
945 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
946 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
949 static ULONG WINAPI
audio_renderer_stream_volume_Release(IMFAudioStreamVolume
*iface
)
951 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
952 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
955 static HRESULT WINAPI
audio_renderer_stream_volume_GetChannelCount(IMFAudioStreamVolume
*iface
, UINT32
*count
)
957 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
960 TRACE("%p, %p.\n", iface
, count
);
967 EnterCriticalSection(&renderer
->cs
);
968 if (renderer
->stream_volume
)
969 hr
= IAudioStreamVolume_GetChannelCount(renderer
->stream_volume
, count
);
970 LeaveCriticalSection(&renderer
->cs
);
975 static HRESULT WINAPI
audio_renderer_stream_volume_SetChannelVolume(IMFAudioStreamVolume
*iface
, UINT32 index
, float level
)
977 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
980 TRACE("%p, %u, %f.\n", iface
, index
, level
);
982 EnterCriticalSection(&renderer
->cs
);
983 if (renderer
->stream_volume
)
984 hr
= IAudioStreamVolume_SetChannelVolume(renderer
->stream_volume
, index
, level
);
985 LeaveCriticalSection(&renderer
->cs
);
990 static HRESULT WINAPI
audio_renderer_stream_volume_GetChannelVolume(IMFAudioStreamVolume
*iface
, UINT32 index
, float *level
)
992 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
995 TRACE("%p, %u, %p.\n", iface
, index
, level
);
1002 EnterCriticalSection(&renderer
->cs
);
1003 if (renderer
->stream_volume
)
1004 hr
= IAudioStreamVolume_GetChannelVolume(renderer
->stream_volume
, index
, level
);
1005 LeaveCriticalSection(&renderer
->cs
);
1010 static HRESULT WINAPI
audio_renderer_stream_volume_SetAllVolumes(IMFAudioStreamVolume
*iface
, UINT32 count
,
1011 const float *volumes
)
1013 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
1016 TRACE("%p, %u, %p.\n", iface
, count
, volumes
);
1018 EnterCriticalSection(&renderer
->cs
);
1019 if (renderer
->stream_volume
)
1020 hr
= IAudioStreamVolume_SetAllVolumes(renderer
->stream_volume
, count
, volumes
);
1021 LeaveCriticalSection(&renderer
->cs
);
1026 static HRESULT WINAPI
audio_renderer_stream_volume_GetAllVolumes(IMFAudioStreamVolume
*iface
, UINT32 count
, float *volumes
)
1028 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
1031 TRACE("%p, %u, %p.\n", iface
, count
, volumes
);
1037 memset(volumes
, 0, sizeof(*volumes
) * count
);
1039 EnterCriticalSection(&renderer
->cs
);
1040 if (renderer
->stream_volume
)
1041 hr
= IAudioStreamVolume_GetAllVolumes(renderer
->stream_volume
, count
, volumes
);
1042 LeaveCriticalSection(&renderer
->cs
);
1047 static const IMFAudioStreamVolumeVtbl audio_renderer_stream_volume_vtbl
=
1049 audio_renderer_stream_volume_QueryInterface
,
1050 audio_renderer_stream_volume_AddRef
,
1051 audio_renderer_stream_volume_Release
,
1052 audio_renderer_stream_volume_GetChannelCount
,
1053 audio_renderer_stream_volume_SetChannelVolume
,
1054 audio_renderer_stream_volume_GetChannelVolume
,
1055 audio_renderer_stream_volume_SetAllVolumes
,
1056 audio_renderer_stream_volume_GetAllVolumes
,
1059 static HRESULT WINAPI
audio_renderer_policy_QueryInterface(IMFAudioPolicy
*iface
, REFIID riid
, void **obj
)
1061 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1063 if (IsEqualIID(riid
, &IID_IMFAudioPolicy
) ||
1064 IsEqualIID(riid
, &IID_IUnknown
))
1067 IMFAudioPolicy_AddRef(iface
);
1071 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
1073 return E_NOINTERFACE
;
1076 static ULONG WINAPI
audio_renderer_policy_AddRef(IMFAudioPolicy
*iface
)
1078 struct audio_renderer
*renderer
= impl_from_IMFAudioPolicy(iface
);
1079 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
1082 static ULONG WINAPI
audio_renderer_policy_Release(IMFAudioPolicy
*iface
)
1084 struct audio_renderer
*renderer
= impl_from_IMFAudioPolicy(iface
);
1085 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
1088 static HRESULT WINAPI
audio_renderer_policy_SetGroupingParam(IMFAudioPolicy
*iface
, REFGUID param
)
1090 FIXME("%p, %s.\n", iface
, debugstr_guid(param
));
1095 static HRESULT WINAPI
audio_renderer_policy_GetGroupingParam(IMFAudioPolicy
*iface
, GUID
*param
)
1097 FIXME("%p, %p.\n", iface
, param
);
1102 static HRESULT WINAPI
audio_renderer_policy_SetDisplayName(IMFAudioPolicy
*iface
, const WCHAR
*name
)
1104 FIXME("%p, %s.\n", iface
, debugstr_w(name
));
1109 static HRESULT WINAPI
audio_renderer_policy_GetDisplayName(IMFAudioPolicy
*iface
, WCHAR
**name
)
1111 FIXME("%p, %p.\n", iface
, name
);
1116 static HRESULT WINAPI
audio_renderer_policy_SetIconPath(IMFAudioPolicy
*iface
, const WCHAR
*path
)
1118 FIXME("%p, %s.\n", iface
, debugstr_w(path
));
1123 static HRESULT WINAPI
audio_renderer_policy_GetIconPath(IMFAudioPolicy
*iface
, WCHAR
**path
)
1125 FIXME("%p, %p.\n", iface
, path
);
1130 static const IMFAudioPolicyVtbl audio_renderer_policy_vtbl
=
1132 audio_renderer_policy_QueryInterface
,
1133 audio_renderer_policy_AddRef
,
1134 audio_renderer_policy_Release
,
1135 audio_renderer_policy_SetGroupingParam
,
1136 audio_renderer_policy_GetGroupingParam
,
1137 audio_renderer_policy_SetDisplayName
,
1138 audio_renderer_policy_GetDisplayName
,
1139 audio_renderer_policy_SetIconPath
,
1140 audio_renderer_policy_GetIconPath
,
1143 static HRESULT
sar_create_mmdevice(IMFAttributes
*attributes
, struct audio_renderer
*renderer
)
1146 unsigned int length
, role
= eMultimedia
;
1147 IMMDeviceEnumerator
*devenum
;
1152 /* Mutually exclusive attributes. */
1153 if (SUCCEEDED(IMFAttributes_GetItem(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE
, NULL
)) &&
1154 SUCCEEDED(IMFAttributes_GetItem(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID
, NULL
)))
1156 return E_INVALIDARG
;
1160 if (FAILED(hr
= CoCreateInstance(&CLSID_MMDeviceEnumerator
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMMDeviceEnumerator
,
1161 (void **)&devenum
)))
1167 if (attributes
&& SUCCEEDED(IMFAttributes_GetUINT32(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE
, &role
)))
1168 TRACE("Specified role %d.\n", role
);
1170 if (attributes
&& SUCCEEDED(IMFAttributes_GetAllocatedString(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID
,
1171 &endpoint
, &length
)))
1173 TRACE("Specified end point %s.\n", debugstr_w(endpoint
));
1174 hr
= IMMDeviceEnumerator_GetDevice(devenum
, endpoint
, &renderer
->device
);
1175 CoTaskMemFree(endpoint
);
1178 hr
= IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum
, eRender
, role
, &renderer
->device
);
1180 /* Configuration attributes to be used later for audio client initialization. */
1183 IMFAttributes_GetUINT32(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_FLAGS
, &renderer
->stream_config
.flags
);
1184 IMFAttributes_GetGUID(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_SESSION_ID
, &renderer
->stream_config
.session_id
);
1188 hr
= MF_E_NO_AUDIO_PLAYBACK_DEVICE
;
1190 IMMDeviceEnumerator_Release(devenum
);
1195 static HRESULT WINAPI
audio_renderer_stream_QueryInterface(IMFStreamSink
*iface
, REFIID riid
, void **obj
)
1197 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1199 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1201 if (IsEqualIID(riid
, &IID_IMFStreamSink
) ||
1202 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
1203 IsEqualIID(riid
, &IID_IUnknown
))
1205 *obj
= &renderer
->IMFStreamSink_iface
;
1207 else if (IsEqualIID(riid
, &IID_IMFMediaTypeHandler
))
1209 *obj
= &renderer
->IMFMediaTypeHandler_iface
;
1213 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1215 return E_NOINTERFACE
;
1218 IUnknown_AddRef((IUnknown
*)*obj
);
1223 static ULONG WINAPI
audio_renderer_stream_AddRef(IMFStreamSink
*iface
)
1225 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1226 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
1229 static ULONG WINAPI
audio_renderer_stream_Release(IMFStreamSink
*iface
)
1231 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1232 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
1235 static HRESULT WINAPI
audio_renderer_stream_GetEvent(IMFStreamSink
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1237 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1239 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
1241 if (renderer
->flags
& SAR_SHUT_DOWN
)
1242 return MF_E_STREAMSINK_REMOVED
;
1244 return IMFMediaEventQueue_GetEvent(renderer
->stream_event_queue
, flags
, event
);
1247 static HRESULT WINAPI
audio_renderer_stream_BeginGetEvent(IMFStreamSink
*iface
, IMFAsyncCallback
*callback
,
1250 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1252 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1254 if (renderer
->flags
& SAR_SHUT_DOWN
)
1255 return MF_E_STREAMSINK_REMOVED
;
1257 return IMFMediaEventQueue_BeginGetEvent(renderer
->stream_event_queue
, callback
, state
);
1260 static HRESULT WINAPI
audio_renderer_stream_EndGetEvent(IMFStreamSink
*iface
, IMFAsyncResult
*result
,
1261 IMFMediaEvent
**event
)
1263 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1265 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1267 if (renderer
->flags
& SAR_SHUT_DOWN
)
1268 return MF_E_STREAMSINK_REMOVED
;
1270 return IMFMediaEventQueue_EndGetEvent(renderer
->stream_event_queue
, result
, event
);
1273 static HRESULT WINAPI
audio_renderer_stream_QueueEvent(IMFStreamSink
*iface
, MediaEventType event_type
,
1274 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
1276 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1278 TRACE("%p, %u, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1280 if (renderer
->flags
& SAR_SHUT_DOWN
)
1281 return MF_E_STREAMSINK_REMOVED
;
1283 return IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, event_type
, ext_type
, hr
, value
);
1286 static HRESULT WINAPI
audio_renderer_stream_GetMediaSink(IMFStreamSink
*iface
, IMFMediaSink
**sink
)
1288 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1290 TRACE("%p, %p.\n", iface
, sink
);
1292 if (renderer
->flags
& SAR_SHUT_DOWN
)
1293 return MF_E_STREAMSINK_REMOVED
;
1295 *sink
= &renderer
->IMFMediaSink_iface
;
1296 IMFMediaSink_AddRef(*sink
);
1301 static HRESULT WINAPI
audio_renderer_stream_GetIdentifier(IMFStreamSink
*iface
, DWORD
*identifier
)
1303 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1305 TRACE("%p, %p.\n", iface
, identifier
);
1307 if (renderer
->flags
& SAR_SHUT_DOWN
)
1308 return MF_E_STREAMSINK_REMOVED
;
1315 static HRESULT WINAPI
audio_renderer_stream_GetMediaTypeHandler(IMFStreamSink
*iface
, IMFMediaTypeHandler
**handler
)
1317 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1319 TRACE("%p, %p.\n", iface
, handler
);
1324 if (renderer
->flags
& SAR_SHUT_DOWN
)
1325 return MF_E_STREAMSINK_REMOVED
;
1327 *handler
= &renderer
->IMFMediaTypeHandler_iface
;
1328 IMFMediaTypeHandler_AddRef(*handler
);
1333 static HRESULT
stream_queue_sample(struct audio_renderer
*renderer
, IMFSample
*sample
)
1335 struct queued_object
*object
;
1336 DWORD sample_len
, sample_frames
;
1339 if (FAILED(hr
= IMFSample_GetTotalLength(sample
, &sample_len
)))
1342 sample_frames
= sample_len
/ renderer
->frame_size
;
1344 if (!(object
= calloc(1, sizeof(*object
))))
1345 return E_OUTOFMEMORY
;
1347 object
->type
= OBJECT_TYPE_SAMPLE
;
1348 object
->u
.sample
.sample
= sample
;
1349 IMFSample_AddRef(object
->u
.sample
.sample
);
1351 list_add_tail(&renderer
->queue
, &object
->entry
);
1352 renderer
->queued_frames
+= sample_frames
;
1357 static HRESULT WINAPI
audio_renderer_stream_ProcessSample(IMFStreamSink
*iface
, IMFSample
*sample
)
1359 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1362 TRACE("%p, %p.\n", iface
, sample
);
1367 if (renderer
->flags
& SAR_SHUT_DOWN
)
1368 return MF_E_STREAMSINK_REMOVED
;
1370 EnterCriticalSection(&renderer
->cs
);
1372 if (renderer
->state
== STREAM_STATE_RUNNING
)
1373 hr
= stream_queue_sample(renderer
, sample
);
1374 renderer
->flags
&= ~SAR_SAMPLE_REQUESTED
;
1376 if (renderer
->queued_frames
< renderer
->max_frames
&& renderer
->state
== STREAM_STATE_RUNNING
)
1378 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkRequestSample
, &GUID_NULL
, S_OK
, NULL
);
1379 renderer
->flags
|= SAR_SAMPLE_REQUESTED
;
1382 LeaveCriticalSection(&renderer
->cs
);
1387 static HRESULT
stream_place_marker(struct audio_renderer
*renderer
, MFSTREAMSINK_MARKER_TYPE marker_type
,
1388 const PROPVARIANT
*context_value
)
1390 struct queued_object
*marker
;
1393 if (!(marker
= calloc(1, sizeof(*marker
))))
1394 return E_OUTOFMEMORY
;
1396 marker
->type
= OBJECT_TYPE_MARKER
;
1397 marker
->u
.marker
.type
= marker_type
;
1398 PropVariantInit(&marker
->u
.marker
.context
);
1400 hr
= PropVariantCopy(&marker
->u
.marker
.context
, context_value
);
1402 list_add_tail(&renderer
->queue
, &marker
->entry
);
1404 release_pending_object(marker
);
1409 static HRESULT WINAPI
audio_renderer_stream_PlaceMarker(IMFStreamSink
*iface
, MFSTREAMSINK_MARKER_TYPE marker_type
,
1410 const PROPVARIANT
*marker_value
, const PROPVARIANT
*context_value
)
1412 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1415 TRACE("%p, %d, %p, %p.\n", iface
, marker_type
, marker_value
, context_value
);
1417 if (renderer
->flags
& SAR_SHUT_DOWN
)
1418 return MF_E_STREAMSINK_REMOVED
;
1420 EnterCriticalSection(&renderer
->cs
);
1421 hr
= stream_place_marker(renderer
, marker_type
, context_value
);
1422 LeaveCriticalSection(&renderer
->cs
);
1427 static HRESULT WINAPI
audio_renderer_stream_Flush(IMFStreamSink
*iface
)
1429 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1430 struct queued_object
*obj
, *obj2
;
1433 TRACE("%p.\n", iface
);
1435 EnterCriticalSection(&renderer
->cs
);
1436 if (renderer
->flags
& SAR_SHUT_DOWN
)
1437 hr
= MF_E_STREAMSINK_REMOVED
;
1440 LIST_FOR_EACH_ENTRY_SAFE(obj
, obj2
, &renderer
->queue
, struct queued_object
, entry
)
1442 if (obj
->type
== OBJECT_TYPE_MARKER
)
1444 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkMarker
,
1445 &GUID_NULL
, S_OK
, &obj
->u
.marker
.context
);
1447 release_pending_object(obj
);
1450 renderer
->queued_frames
= 0;
1451 LeaveCriticalSection(&renderer
->cs
);
1456 static const IMFStreamSinkVtbl audio_renderer_stream_vtbl
=
1458 audio_renderer_stream_QueryInterface
,
1459 audio_renderer_stream_AddRef
,
1460 audio_renderer_stream_Release
,
1461 audio_renderer_stream_GetEvent
,
1462 audio_renderer_stream_BeginGetEvent
,
1463 audio_renderer_stream_EndGetEvent
,
1464 audio_renderer_stream_QueueEvent
,
1465 audio_renderer_stream_GetMediaSink
,
1466 audio_renderer_stream_GetIdentifier
,
1467 audio_renderer_stream_GetMediaTypeHandler
,
1468 audio_renderer_stream_ProcessSample
,
1469 audio_renderer_stream_PlaceMarker
,
1470 audio_renderer_stream_Flush
,
1473 static HRESULT WINAPI
audio_renderer_stream_type_handler_QueryInterface(IMFMediaTypeHandler
*iface
, REFIID riid
,
1476 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1477 return IMFStreamSink_QueryInterface(&renderer
->IMFStreamSink_iface
, riid
, obj
);
1480 static ULONG WINAPI
audio_renderer_stream_type_handler_AddRef(IMFMediaTypeHandler
*iface
)
1482 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1483 return IMFStreamSink_AddRef(&renderer
->IMFStreamSink_iface
);
1486 static ULONG WINAPI
audio_renderer_stream_type_handler_Release(IMFMediaTypeHandler
*iface
)
1488 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1489 return IMFStreamSink_Release(&renderer
->IMFStreamSink_iface
);
1492 static HRESULT WINAPI
audio_renderer_stream_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler
*iface
,
1493 IMFMediaType
*in_type
, IMFMediaType
**out_type
)
1495 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1499 TRACE("%p, %p, %p.\n", iface
, in_type
, out_type
);
1501 EnterCriticalSection(&renderer
->cs
);
1502 hr
= IMFMediaType_IsEqual(renderer
->media_type
, in_type
, &flags
);
1503 LeaveCriticalSection(&renderer
->cs
);
1505 return hr
!= S_OK
? MF_E_INVALIDMEDIATYPE
: hr
;
1508 static HRESULT WINAPI
audio_renderer_stream_type_handler_GetMediaTypeCount(IMFMediaTypeHandler
*iface
, DWORD
*count
)
1510 TRACE("%p, %p.\n", iface
, count
);
1517 static HRESULT WINAPI
audio_renderer_stream_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler
*iface
, DWORD index
,
1518 IMFMediaType
**media_type
)
1520 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1522 TRACE("%p, %u, %p.\n", iface
, index
, media_type
);
1526 *media_type
= renderer
->media_type
;
1527 IMFMediaType_AddRef(*media_type
);
1533 static HRESULT
audio_renderer_create_audio_client(struct audio_renderer
*renderer
)
1535 IMFAsyncResult
*result
;
1540 audio_renderer_release_audio_client(renderer
);
1542 hr
= IMMDevice_Activate(renderer
->device
, &IID_IAudioClient
, CLSCTX_INPROC_SERVER
, NULL
,
1543 (void **)&renderer
->audio_client
);
1546 WARN("Failed to create audio client, hr %#x.\n", hr
);
1550 /* FIXME: for now always use default format. */
1551 if (FAILED(hr
= IAudioClient_GetMixFormat(renderer
->audio_client
, &wfx
)))
1553 WARN("Failed to get audio format, hr %#x.\n", hr
);
1557 renderer
->frame_size
= wfx
->wBitsPerSample
* wfx
->nChannels
/ 8;
1559 flags
= AUDCLNT_STREAMFLAGS_EVENTCALLBACK
;
1560 if (renderer
->stream_config
.flags
& MF_AUDIO_RENDERER_ATTRIBUTE_FLAGS_CROSSPROCESS
)
1561 flags
|= AUDCLNT_STREAMFLAGS_CROSSPROCESS
;
1562 if (renderer
->stream_config
.flags
& MF_AUDIO_RENDERER_ATTRIBUTE_FLAGS_NOPERSIST
)
1563 flags
|= AUDCLNT_STREAMFLAGS_NOPERSIST
;
1564 hr
= IAudioClient_Initialize(renderer
->audio_client
, AUDCLNT_SHAREMODE_SHARED
, flags
, 1000000, 0, wfx
,
1565 &renderer
->stream_config
.session_id
);
1569 WARN("Failed to initialize audio client, hr %#x.\n", hr
);
1573 if (FAILED(hr
= IAudioClient_GetService(renderer
->audio_client
, &IID_IAudioStreamVolume
,
1574 (void **)&renderer
->stream_volume
)))
1576 WARN("Failed to get stream volume control, hr %#x.\n", hr
);
1580 if (FAILED(hr
= IAudioClient_GetService(renderer
->audio_client
, &IID_ISimpleAudioVolume
, (void **)&renderer
->audio_volume
)))
1582 WARN("Failed to get audio volume control, hr %#x.\n", hr
);
1586 if (FAILED(hr
= IAudioClient_GetService(renderer
->audio_client
, &IID_IAudioRenderClient
,
1587 (void **)&renderer
->audio_render_client
)))
1589 WARN("Failed to get audio render client, hr %#x.\n", hr
);
1593 if (FAILED(hr
= IAudioClient_SetEventHandle(renderer
->audio_client
, renderer
->buffer_ready_event
)))
1595 WARN("Failed to set event handle, hr %#x.\n", hr
);
1599 if (FAILED(hr
= IAudioClient_GetBufferSize(renderer
->audio_client
, &renderer
->max_frames
)))
1601 WARN("Failed to get buffer size, hr %#x.\n", hr
);
1605 if (SUCCEEDED(hr
= MFCreateAsyncResult(NULL
, &renderer
->render_callback
, NULL
, &result
)))
1607 if (FAILED(hr
= MFPutWaitingWorkItem(renderer
->buffer_ready_event
, 0, result
, &renderer
->buffer_ready_key
)))
1608 WARN("Failed to submit wait item, hr %#x.\n", hr
);
1609 IMFAsyncResult_Release(result
);
1615 static HRESULT WINAPI
audio_renderer_stream_type_handler_SetCurrentMediaType(IMFMediaTypeHandler
*iface
,
1616 IMFMediaType
*media_type
)
1618 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1619 const unsigned int test_flags
= MF_MEDIATYPE_EQUAL_MAJOR_TYPES
| MF_MEDIATYPE_EQUAL_FORMAT_TYPES
;
1620 BOOL compare_result
;
1624 TRACE("%p, %p.\n", iface
, media_type
);
1629 EnterCriticalSection(&renderer
->cs
);
1630 if (SUCCEEDED(IMFMediaType_IsEqual(renderer
->media_type
, media_type
, &flags
)) && ((flags
& test_flags
) == test_flags
))
1632 if (renderer
->current_media_type
)
1633 IMFMediaType_Release(renderer
->current_media_type
);
1634 renderer
->current_media_type
= media_type
;
1635 IMFMediaType_AddRef(renderer
->current_media_type
);
1637 if (SUCCEEDED(hr
= audio_renderer_create_audio_client(renderer
)))
1639 if (SUCCEEDED(IMFMediaType_Compare(renderer
->media_type
, (IMFAttributes
*)media_type
, MF_ATTRIBUTES_MATCH_OUR_ITEMS
,
1640 &compare_result
)) && !compare_result
)
1642 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkFormatInvalidated
, &GUID_NULL
,
1644 audio_renderer_preroll(renderer
);
1649 hr
= MF_E_INVALIDMEDIATYPE
;
1650 LeaveCriticalSection(&renderer
->cs
);
1655 static HRESULT WINAPI
audio_renderer_stream_type_handler_GetCurrentMediaType(IMFMediaTypeHandler
*iface
,
1656 IMFMediaType
**media_type
)
1658 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1661 TRACE("%p, %p.\n", iface
, media_type
);
1663 EnterCriticalSection(&renderer
->cs
);
1664 if (renderer
->current_media_type
)
1666 *media_type
= renderer
->current_media_type
;
1667 IMFMediaType_AddRef(*media_type
);
1670 hr
= MF_E_NOT_INITIALIZED
;
1671 LeaveCriticalSection(&renderer
->cs
);
1676 static HRESULT WINAPI
audio_renderer_stream_type_handler_GetMajorType(IMFMediaTypeHandler
*iface
, GUID
*type
)
1678 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1680 TRACE("%p, %p.\n", iface
, type
);
1685 if (renderer
->flags
& SAR_SHUT_DOWN
)
1686 return MF_E_STREAMSINK_REMOVED
;
1688 memcpy(type
, &MFMediaType_Audio
, sizeof(*type
));
1692 static const IMFMediaTypeHandlerVtbl audio_renderer_stream_type_handler_vtbl
=
1694 audio_renderer_stream_type_handler_QueryInterface
,
1695 audio_renderer_stream_type_handler_AddRef
,
1696 audio_renderer_stream_type_handler_Release
,
1697 audio_renderer_stream_type_handler_IsMediaTypeSupported
,
1698 audio_renderer_stream_type_handler_GetMediaTypeCount
,
1699 audio_renderer_stream_type_handler_GetMediaTypeByIndex
,
1700 audio_renderer_stream_type_handler_SetCurrentMediaType
,
1701 audio_renderer_stream_type_handler_GetCurrentMediaType
,
1702 audio_renderer_stream_type_handler_GetMajorType
,
1705 static HRESULT
audio_renderer_collect_supported_types(struct audio_renderer
*renderer
)
1707 IAudioClient
*client
;
1708 WAVEFORMATEX
*format
;
1711 if (FAILED(hr
= MFCreateMediaType(&renderer
->media_type
)))
1714 hr
= IMMDevice_Activate(renderer
->device
, &IID_IAudioClient
, CLSCTX_INPROC_SERVER
, NULL
, (void **)&client
);
1717 WARN("Failed to create audio client, hr %#x.\n", hr
);
1723 hr
= IAudioClient_GetMixFormat(client
, &format
);
1724 IAudioClient_Release(client
);
1727 WARN("Failed to get device audio format, hr %#x.\n", hr
);
1731 hr
= MFInitMediaTypeFromWaveFormatEx(renderer
->media_type
, format
, format
->cbSize
+ sizeof(*format
));
1732 CoTaskMemFree(format
);
1735 WARN("Failed to initialize media type, hr %#x.\n", hr
);
1739 IMFMediaType_DeleteItem(renderer
->media_type
, &MF_MT_AUDIO_PREFER_WAVEFORMATEX
);
1744 static HRESULT WINAPI
audio_renderer_render_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
1746 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1748 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
1749 IsEqualIID(riid
, &IID_IUnknown
))
1752 IMFAsyncCallback_AddRef(iface
);
1756 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
1758 return E_NOINTERFACE
;
1761 static ULONG WINAPI
audio_renderer_render_callback_AddRef(IMFAsyncCallback
*iface
)
1763 struct audio_renderer
*renderer
= impl_from_render_callback_IMFAsyncCallback(iface
);
1764 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
1767 static ULONG WINAPI
audio_renderer_render_callback_Release(IMFAsyncCallback
*iface
)
1769 struct audio_renderer
*renderer
= impl_from_render_callback_IMFAsyncCallback(iface
);
1770 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
1773 static HRESULT WINAPI
audio_renderer_render_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
1778 static void audio_renderer_render(struct audio_renderer
*renderer
, IMFAsyncResult
*result
)
1780 unsigned int src_frames
, dst_frames
, max_frames
, pad_frames
, src_len
;
1781 struct queued_object
*obj
, *obj2
;
1782 BOOL keep_sample
= FALSE
;
1783 IMFMediaBuffer
*buffer
;
1787 LIST_FOR_EACH_ENTRY_SAFE(obj
, obj2
, &renderer
->queue
, struct queued_object
, entry
)
1789 if (obj
->type
== OBJECT_TYPE_MARKER
)
1791 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkMarker
,
1792 &GUID_NULL
, S_OK
, &obj
->u
.marker
.context
);
1794 else if (obj
->type
== OBJECT_TYPE_SAMPLE
)
1796 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(obj
->u
.sample
.sample
, &buffer
)))
1798 if (SUCCEEDED(IMFMediaBuffer_Lock(buffer
, &src
, NULL
, &src_len
)))
1800 if ((src_frames
= src_len
/ renderer
->frame_size
))
1802 if (SUCCEEDED(IAudioClient_GetBufferSize(renderer
->audio_client
, &max_frames
)))
1804 if (SUCCEEDED(IAudioClient_GetCurrentPadding(renderer
->audio_client
, &pad_frames
)))
1806 max_frames
-= pad_frames
;
1807 src_frames
-= obj
->u
.sample
.frame_offset
;
1808 dst_frames
= min(src_frames
, max_frames
);
1810 if (SUCCEEDED(hr
= IAudioRenderClient_GetBuffer(renderer
->audio_render_client
, dst_frames
, &dst
)))
1812 memcpy(dst
, src
+ obj
->u
.sample
.frame_offset
* renderer
->frame_size
,
1813 dst_frames
* renderer
->frame_size
);
1815 IAudioRenderClient_ReleaseBuffer(renderer
->audio_render_client
, dst_frames
, 0);
1817 obj
->u
.sample
.frame_offset
+= dst_frames
;
1818 renderer
->queued_frames
-= dst_frames
;
1821 keep_sample
= FAILED(hr
) || src_frames
> max_frames
;
1825 IMFMediaBuffer_Unlock(buffer
);
1827 IMFMediaBuffer_Release(buffer
);
1834 list_remove(&obj
->entry
);
1835 release_pending_object(obj
);
1838 if (list_empty(&renderer
->queue
) && !(renderer
->flags
& SAR_SAMPLE_REQUESTED
))
1840 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkRequestSample
, &GUID_NULL
, S_OK
, NULL
);
1841 renderer
->flags
|= SAR_SAMPLE_REQUESTED
;
1844 if (FAILED(hr
= MFPutWaitingWorkItem(renderer
->buffer_ready_event
, 0, result
, &renderer
->buffer_ready_key
)))
1845 WARN("Failed to submit wait item, hr %#x.\n", hr
);
1848 static HRESULT WINAPI
audio_renderer_render_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1850 struct audio_renderer
*renderer
= impl_from_render_callback_IMFAsyncCallback(iface
);
1852 EnterCriticalSection(&renderer
->cs
);
1853 if (!(renderer
->flags
& SAR_SHUT_DOWN
))
1854 audio_renderer_render(renderer
, result
);
1855 LeaveCriticalSection(&renderer
->cs
);
1860 static const IMFAsyncCallbackVtbl audio_renderer_render_callback_vtbl
=
1862 audio_renderer_render_callback_QueryInterface
,
1863 audio_renderer_render_callback_AddRef
,
1864 audio_renderer_render_callback_Release
,
1865 audio_renderer_render_callback_GetParameters
,
1866 audio_renderer_render_callback_Invoke
,
1869 static HRESULT
sar_create_object(IMFAttributes
*attributes
, void *user_context
, IUnknown
**obj
)
1871 struct audio_renderer
*renderer
;
1874 TRACE("%p, %p, %p.\n", attributes
, user_context
, obj
);
1876 if (!(renderer
= calloc(1, sizeof(*renderer
))))
1877 return E_OUTOFMEMORY
;
1879 renderer
->IMFMediaSink_iface
.lpVtbl
= &audio_renderer_sink_vtbl
;
1880 renderer
->IMFMediaSinkPreroll_iface
.lpVtbl
= &audio_renderer_preroll_vtbl
;
1881 renderer
->IMFStreamSink_iface
.lpVtbl
= &audio_renderer_stream_vtbl
;
1882 renderer
->IMFMediaTypeHandler_iface
.lpVtbl
= &audio_renderer_stream_type_handler_vtbl
;
1883 renderer
->IMFClockStateSink_iface
.lpVtbl
= &audio_renderer_clock_sink_vtbl
;
1884 renderer
->IMFMediaEventGenerator_iface
.lpVtbl
= &audio_renderer_events_vtbl
;
1885 renderer
->IMFGetService_iface
.lpVtbl
= &audio_renderer_get_service_vtbl
;
1886 renderer
->IMFSimpleAudioVolume_iface
.lpVtbl
= &audio_renderer_simple_volume_vtbl
;
1887 renderer
->IMFAudioStreamVolume_iface
.lpVtbl
= &audio_renderer_stream_volume_vtbl
;
1888 renderer
->IMFAudioPolicy_iface
.lpVtbl
= &audio_renderer_policy_vtbl
;
1889 renderer
->render_callback
.lpVtbl
= &audio_renderer_render_callback_vtbl
;
1890 renderer
->refcount
= 1;
1891 InitializeCriticalSection(&renderer
->cs
);
1892 renderer
->buffer_ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1893 list_init(&renderer
->queue
);
1895 if (FAILED(hr
= MFCreateEventQueue(&renderer
->event_queue
)))
1898 if (FAILED(hr
= MFCreateEventQueue(&renderer
->stream_event_queue
)))
1901 if (FAILED(hr
= sar_create_mmdevice(attributes
, renderer
)))
1904 if (FAILED(hr
= audio_renderer_collect_supported_types(renderer
)))
1907 *obj
= (IUnknown
*)&renderer
->IMFMediaSink_iface
;
1913 IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
1918 static void sar_shutdown_object(void *user_context
, IUnknown
*obj
)
1922 if (SUCCEEDED(IUnknown_QueryInterface(obj
, &IID_IMFMediaSink
, (void **)&sink
)))
1924 IMFMediaSink_Shutdown(sink
);
1925 IMFMediaSink_Release(sink
);
1929 static const struct activate_funcs sar_activate_funcs
=
1931 .create_object
= sar_create_object
,
1932 .shutdown_object
= sar_shutdown_object
,
1935 /***********************************************************************
1936 * MFCreateAudioRendererActivate (mf.@)
1938 HRESULT WINAPI
MFCreateAudioRendererActivate(IMFActivate
**activate
)
1940 TRACE("%p.\n", activate
);
1945 return create_activation_object(NULL
, &sar_activate_funcs
, activate
);
1948 /***********************************************************************
1949 * MFCreateAudioRenderer (mf.@)
1951 HRESULT WINAPI
MFCreateAudioRenderer(IMFAttributes
*attributes
, IMFMediaSink
**sink
)
1956 TRACE("%p, %p.\n", attributes
, sink
);
1958 if (SUCCEEDED(hr
= sar_create_object(attributes
, NULL
, &object
)))
1960 hr
= IUnknown_QueryInterface(object
, &IID_IMFMediaSink
, (void **)sink
);
1961 IUnknown_Release(object
);