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/heap.h"
30 #include "wine/list.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
36 STREAM_STATE_STOPPED
= 0,
41 enum audio_renderer_flags
45 SAR_SAMPLE_REQUESTED
= 0x4,
48 enum queued_object_type
57 enum queued_object_type type
;
63 unsigned int frame_offset
;
67 MFSTREAMSINK_MARKER_TYPE type
;
75 IMFMediaSink IMFMediaSink_iface
;
76 IMFMediaSinkPreroll IMFMediaSinkPreroll_iface
;
77 IMFStreamSink IMFStreamSink_iface
;
78 IMFMediaTypeHandler IMFMediaTypeHandler_iface
;
79 IMFClockStateSink IMFClockStateSink_iface
;
80 IMFMediaEventGenerator IMFMediaEventGenerator_iface
;
81 IMFGetService IMFGetService_iface
;
82 IMFSimpleAudioVolume IMFSimpleAudioVolume_iface
;
83 IMFAudioStreamVolume IMFAudioStreamVolume_iface
;
84 IMFAudioPolicy IMFAudioPolicy_iface
;
85 IMFAsyncCallback render_callback
;
87 IMFMediaEventQueue
*event_queue
;
88 IMFMediaEventQueue
*stream_event_queue
;
89 IMFPresentationClock
*clock
;
90 IMFMediaType
*media_type
;
91 IMFMediaType
*current_media_type
;
93 IAudioClient
*audio_client
;
94 IAudioRenderClient
*audio_render_client
;
95 IAudioStreamVolume
*stream_volume
;
96 ISimpleAudioVolume
*audio_volume
;
102 HANDLE buffer_ready_event
;
103 MFWORKITEM_KEY buffer_ready_key
;
104 unsigned int frame_size
;
106 enum stream_state state
;
111 static void release_pending_object(struct queued_object
*object
)
113 list_remove(&object
->entry
);
114 switch (object
->type
)
116 case OBJECT_TYPE_SAMPLE
:
117 if (object
->u
.sample
.sample
)
118 IMFSample_Release(object
->u
.sample
.sample
);
120 case OBJECT_TYPE_MARKER
:
121 PropVariantClear(&object
->u
.marker
.context
);
127 static struct audio_renderer
*impl_from_IMFMediaSink(IMFMediaSink
*iface
)
129 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFMediaSink_iface
);
132 static struct audio_renderer
*impl_from_IMFMediaSinkPreroll(IMFMediaSinkPreroll
*iface
)
134 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFMediaSinkPreroll_iface
);
137 static struct audio_renderer
*impl_from_IMFClockStateSink(IMFClockStateSink
*iface
)
139 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFClockStateSink_iface
);
142 static struct audio_renderer
*impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator
*iface
)
144 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFMediaEventGenerator_iface
);
147 static struct audio_renderer
*impl_from_IMFGetService(IMFGetService
*iface
)
149 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFGetService_iface
);
152 static struct audio_renderer
*impl_from_IMFSimpleAudioVolume(IMFSimpleAudioVolume
*iface
)
154 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFSimpleAudioVolume_iface
);
157 static struct audio_renderer
*impl_from_IMFAudioStreamVolume(IMFAudioStreamVolume
*iface
)
159 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFAudioStreamVolume_iface
);
162 static struct audio_renderer
*impl_from_IMFAudioPolicy(IMFAudioPolicy
*iface
)
164 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFAudioPolicy_iface
);
167 static struct audio_renderer
*impl_from_IMFStreamSink(IMFStreamSink
*iface
)
169 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFStreamSink_iface
);
172 static struct audio_renderer
*impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler
*iface
)
174 return CONTAINING_RECORD(iface
, struct audio_renderer
, IMFMediaTypeHandler_iface
);
177 static struct audio_renderer
*impl_from_render_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
179 return CONTAINING_RECORD(iface
, struct audio_renderer
, render_callback
);
182 static HRESULT WINAPI
audio_renderer_sink_QueryInterface(IMFMediaSink
*iface
, REFIID riid
, void **obj
)
184 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
186 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
188 if (IsEqualIID(riid
, &IID_IMFMediaSink
) ||
189 IsEqualIID(riid
, &IID_IUnknown
))
193 else if (IsEqualIID(riid
, &IID_IMFMediaSinkPreroll
))
195 *obj
= &renderer
->IMFMediaSinkPreroll_iface
;
197 else if (IsEqualIID(riid
, &IID_IMFClockStateSink
))
199 *obj
= &renderer
->IMFClockStateSink_iface
;
201 else if (IsEqualIID(riid
, &IID_IMFMediaEventGenerator
))
203 *obj
= &renderer
->IMFMediaEventGenerator_iface
;
205 else if (IsEqualIID(riid
, &IID_IMFGetService
))
207 *obj
= &renderer
->IMFGetService_iface
;
211 WARN("Unsupported %s.\n", debugstr_guid(riid
));
213 return E_NOINTERFACE
;
216 IUnknown_AddRef((IUnknown
*)*obj
);
221 static ULONG WINAPI
audio_renderer_sink_AddRef(IMFMediaSink
*iface
)
223 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
224 ULONG refcount
= InterlockedIncrement(&renderer
->refcount
);
225 TRACE("%p, refcount %u.\n", iface
, refcount
);
229 static void audio_renderer_release_audio_client(struct audio_renderer
*renderer
)
231 MFCancelWorkItem(renderer
->buffer_ready_key
);
232 renderer
->buffer_ready_key
= 0;
233 if (renderer
->audio_client
)
235 IAudioClient_Stop(renderer
->audio_client
);
236 IAudioClient_Reset(renderer
->audio_client
);
237 IAudioClient_Release(renderer
->audio_client
);
239 renderer
->audio_client
= NULL
;
240 if (renderer
->audio_render_client
)
241 IAudioRenderClient_Release(renderer
->audio_render_client
);
242 renderer
->audio_render_client
= NULL
;
243 if (renderer
->stream_volume
)
244 IAudioStreamVolume_Release(renderer
->stream_volume
);
245 renderer
->stream_volume
= NULL
;
246 if (renderer
->audio_volume
)
247 ISimpleAudioVolume_Release(renderer
->audio_volume
);
248 renderer
->audio_volume
= NULL
;
249 renderer
->flags
&= ~SAR_PREROLLED
;
252 static ULONG WINAPI
audio_renderer_sink_Release(IMFMediaSink
*iface
)
254 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
255 ULONG refcount
= InterlockedDecrement(&renderer
->refcount
);
256 struct queued_object
*obj
, *obj2
;
258 TRACE("%p, refcount %u.\n", iface
, refcount
);
262 if (renderer
->event_queue
)
263 IMFMediaEventQueue_Release(renderer
->event_queue
);
264 if (renderer
->stream_event_queue
)
265 IMFMediaEventQueue_Release(renderer
->stream_event_queue
);
267 IMFPresentationClock_Release(renderer
->clock
);
268 if (renderer
->device
)
269 IMMDevice_Release(renderer
->device
);
270 if (renderer
->media_type
)
271 IMFMediaType_Release(renderer
->media_type
);
272 if (renderer
->current_media_type
)
273 IMFMediaType_Release(renderer
->current_media_type
);
274 audio_renderer_release_audio_client(renderer
);
275 CloseHandle(renderer
->buffer_ready_event
);
276 LIST_FOR_EACH_ENTRY_SAFE(obj
, obj2
, &renderer
->queue
, struct queued_object
, entry
)
278 release_pending_object(obj
);
280 DeleteCriticalSection(&renderer
->cs
);
287 static HRESULT WINAPI
audio_renderer_sink_GetCharacteristics(IMFMediaSink
*iface
, DWORD
*flags
)
289 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
291 TRACE("%p, %p.\n", iface
, flags
);
293 if (renderer
->flags
& SAR_SHUT_DOWN
)
294 return MF_E_SHUTDOWN
;
296 *flags
= MEDIASINK_FIXED_STREAMS
| MEDIASINK_CAN_PREROLL
;
301 static HRESULT WINAPI
audio_renderer_sink_AddStreamSink(IMFMediaSink
*iface
, DWORD stream_sink_id
,
302 IMFMediaType
*media_type
, IMFStreamSink
**stream_sink
)
304 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
306 TRACE("%p, %#x, %p, %p.\n", iface
, stream_sink_id
, media_type
, stream_sink
);
308 return renderer
->flags
& SAR_SHUT_DOWN
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
311 static HRESULT WINAPI
audio_renderer_sink_RemoveStreamSink(IMFMediaSink
*iface
, DWORD stream_sink_id
)
313 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
315 TRACE("%p, %#x.\n", iface
, stream_sink_id
);
317 return renderer
->flags
& SAR_SHUT_DOWN
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
320 static HRESULT WINAPI
audio_renderer_sink_GetStreamSinkCount(IMFMediaSink
*iface
, DWORD
*count
)
322 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
324 TRACE("%p, %p.\n", iface
, count
);
329 if (renderer
->flags
& SAR_SHUT_DOWN
)
330 return MF_E_SHUTDOWN
;
337 static HRESULT WINAPI
audio_renderer_sink_GetStreamSinkByIndex(IMFMediaSink
*iface
, DWORD index
,
338 IMFStreamSink
**stream
)
340 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
343 TRACE("%p, %u, %p.\n", iface
, index
, stream
);
345 EnterCriticalSection(&renderer
->cs
);
347 if (renderer
->flags
& SAR_SHUT_DOWN
)
350 hr
= MF_E_INVALIDINDEX
;
353 *stream
= &renderer
->IMFStreamSink_iface
;
354 IMFStreamSink_AddRef(*stream
);
357 LeaveCriticalSection(&renderer
->cs
);
362 static HRESULT WINAPI
audio_renderer_sink_GetStreamSinkById(IMFMediaSink
*iface
, DWORD stream_sink_id
,
363 IMFStreamSink
**stream
)
365 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
368 TRACE("%p, %#x, %p.\n", iface
, stream_sink_id
, stream
);
370 EnterCriticalSection(&renderer
->cs
);
372 if (renderer
->flags
& SAR_SHUT_DOWN
)
374 else if (stream_sink_id
> 0)
375 hr
= MF_E_INVALIDSTREAMNUMBER
;
378 *stream
= &renderer
->IMFStreamSink_iface
;
379 IMFStreamSink_AddRef(*stream
);
382 LeaveCriticalSection(&renderer
->cs
);
387 static void audio_renderer_set_presentation_clock(struct audio_renderer
*renderer
, IMFPresentationClock
*clock
)
391 IMFPresentationClock_RemoveClockStateSink(renderer
->clock
, &renderer
->IMFClockStateSink_iface
);
392 IMFPresentationClock_Release(renderer
->clock
);
394 renderer
->clock
= clock
;
397 IMFPresentationClock_AddRef(renderer
->clock
);
398 IMFPresentationClock_AddClockStateSink(renderer
->clock
, &renderer
->IMFClockStateSink_iface
);
402 static HRESULT WINAPI
audio_renderer_sink_SetPresentationClock(IMFMediaSink
*iface
, IMFPresentationClock
*clock
)
404 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
407 TRACE("%p, %p.\n", iface
, clock
);
409 EnterCriticalSection(&renderer
->cs
);
411 if (renderer
->flags
& SAR_SHUT_DOWN
)
414 audio_renderer_set_presentation_clock(renderer
, clock
);
416 LeaveCriticalSection(&renderer
->cs
);
421 static HRESULT WINAPI
audio_renderer_sink_GetPresentationClock(IMFMediaSink
*iface
, IMFPresentationClock
**clock
)
423 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
426 TRACE("%p, %p.\n", iface
, clock
);
431 EnterCriticalSection(&renderer
->cs
);
433 if (renderer
->flags
& SAR_SHUT_DOWN
)
435 else if (renderer
->clock
)
437 *clock
= renderer
->clock
;
438 IMFPresentationClock_AddRef(*clock
);
443 LeaveCriticalSection(&renderer
->cs
);
448 static HRESULT WINAPI
audio_renderer_sink_Shutdown(IMFMediaSink
*iface
)
450 struct audio_renderer
*renderer
= impl_from_IMFMediaSink(iface
);
452 TRACE("%p.\n", iface
);
454 if (renderer
->flags
& SAR_SHUT_DOWN
)
455 return MF_E_SHUTDOWN
;
457 EnterCriticalSection(&renderer
->cs
);
458 renderer
->flags
|= SAR_SHUT_DOWN
;
459 IMFMediaEventQueue_Shutdown(renderer
->event_queue
);
460 IMFMediaEventQueue_Shutdown(renderer
->stream_event_queue
);
461 audio_renderer_set_presentation_clock(renderer
, NULL
);
462 audio_renderer_release_audio_client(renderer
);
463 LeaveCriticalSection(&renderer
->cs
);
468 static const IMFMediaSinkVtbl audio_renderer_sink_vtbl
=
470 audio_renderer_sink_QueryInterface
,
471 audio_renderer_sink_AddRef
,
472 audio_renderer_sink_Release
,
473 audio_renderer_sink_GetCharacteristics
,
474 audio_renderer_sink_AddStreamSink
,
475 audio_renderer_sink_RemoveStreamSink
,
476 audio_renderer_sink_GetStreamSinkCount
,
477 audio_renderer_sink_GetStreamSinkByIndex
,
478 audio_renderer_sink_GetStreamSinkById
,
479 audio_renderer_sink_SetPresentationClock
,
480 audio_renderer_sink_GetPresentationClock
,
481 audio_renderer_sink_Shutdown
,
484 static void audio_renderer_preroll(struct audio_renderer
*renderer
)
488 if (renderer
->flags
& SAR_PREROLLED
)
491 for (i
= 0; i
< 2; ++i
)
492 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkRequestSample
, &GUID_NULL
, S_OK
, NULL
);
493 renderer
->flags
|= SAR_PREROLLED
;
496 static HRESULT WINAPI
audio_renderer_preroll_QueryInterface(IMFMediaSinkPreroll
*iface
, REFIID riid
, void **obj
)
498 struct audio_renderer
*renderer
= impl_from_IMFMediaSinkPreroll(iface
);
499 return IMFMediaSink_QueryInterface(&renderer
->IMFMediaSink_iface
, riid
, obj
);
502 static ULONG WINAPI
audio_renderer_preroll_AddRef(IMFMediaSinkPreroll
*iface
)
504 struct audio_renderer
*renderer
= impl_from_IMFMediaSinkPreroll(iface
);
505 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
508 static ULONG WINAPI
audio_renderer_preroll_Release(IMFMediaSinkPreroll
*iface
)
510 struct audio_renderer
*renderer
= impl_from_IMFMediaSinkPreroll(iface
);
511 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
514 static HRESULT WINAPI
audio_renderer_preroll_NotifyPreroll(IMFMediaSinkPreroll
*iface
, MFTIME start_time
)
516 struct audio_renderer
*renderer
= impl_from_IMFMediaSinkPreroll(iface
);
518 TRACE("%p, %s.\n", iface
, debugstr_time(start_time
));
520 if (renderer
->flags
& SAR_SHUT_DOWN
)
521 return MF_E_SHUTDOWN
;
523 audio_renderer_preroll(renderer
);
524 return IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkPrerolled
, &GUID_NULL
, S_OK
, NULL
);
527 static const IMFMediaSinkPrerollVtbl audio_renderer_preroll_vtbl
=
529 audio_renderer_preroll_QueryInterface
,
530 audio_renderer_preroll_AddRef
,
531 audio_renderer_preroll_Release
,
532 audio_renderer_preroll_NotifyPreroll
,
535 static HRESULT WINAPI
audio_renderer_events_QueryInterface(IMFMediaEventGenerator
*iface
, REFIID riid
, void **obj
)
537 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
538 return IMFMediaSink_QueryInterface(&renderer
->IMFMediaSink_iface
, riid
, obj
);
541 static ULONG WINAPI
audio_renderer_events_AddRef(IMFMediaEventGenerator
*iface
)
543 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
544 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
547 static ULONG WINAPI
audio_renderer_events_Release(IMFMediaEventGenerator
*iface
)
549 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
550 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
553 static HRESULT WINAPI
audio_renderer_events_GetEvent(IMFMediaEventGenerator
*iface
, DWORD flags
, IMFMediaEvent
**event
)
555 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
557 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
559 return IMFMediaEventQueue_GetEvent(renderer
->event_queue
, flags
, event
);
562 static HRESULT WINAPI
audio_renderer_events_BeginGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncCallback
*callback
,
565 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
567 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
569 return IMFMediaEventQueue_BeginGetEvent(renderer
->event_queue
, callback
, state
);
572 static HRESULT WINAPI
audio_renderer_events_EndGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncResult
*result
,
573 IMFMediaEvent
**event
)
575 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
577 TRACE("%p, %p, %p.\n", iface
, result
, event
);
579 return IMFMediaEventQueue_EndGetEvent(renderer
->event_queue
, result
, event
);
582 static HRESULT WINAPI
audio_renderer_events_QueueEvent(IMFMediaEventGenerator
*iface
, MediaEventType event_type
,
583 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
585 struct audio_renderer
*renderer
= impl_from_IMFMediaEventGenerator(iface
);
587 TRACE("%p, %u, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
589 return IMFMediaEventQueue_QueueEventParamVar(renderer
->event_queue
, event_type
, ext_type
, hr
, value
);
592 static const IMFMediaEventGeneratorVtbl audio_renderer_events_vtbl
=
594 audio_renderer_events_QueryInterface
,
595 audio_renderer_events_AddRef
,
596 audio_renderer_events_Release
,
597 audio_renderer_events_GetEvent
,
598 audio_renderer_events_BeginGetEvent
,
599 audio_renderer_events_EndGetEvent
,
600 audio_renderer_events_QueueEvent
,
603 static HRESULT WINAPI
audio_renderer_clock_sink_QueryInterface(IMFClockStateSink
*iface
, REFIID riid
, void **obj
)
605 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
606 return IMFMediaSink_QueryInterface(&renderer
->IMFMediaSink_iface
, riid
, obj
);
609 static ULONG WINAPI
audio_renderer_clock_sink_AddRef(IMFClockStateSink
*iface
)
611 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
612 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
615 static ULONG WINAPI
audio_renderer_clock_sink_Release(IMFClockStateSink
*iface
)
617 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
618 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
621 static HRESULT WINAPI
audio_renderer_clock_sink_OnClockStart(IMFClockStateSink
*iface
, MFTIME systime
, LONGLONG offset
)
623 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
626 TRACE("%p, %s, %s.\n", iface
, debugstr_time(systime
), debugstr_time(offset
));
628 EnterCriticalSection(&renderer
->cs
);
629 if (renderer
->audio_client
)
631 if (renderer
->state
== STREAM_STATE_STOPPED
)
633 if (FAILED(hr
= IAudioClient_Start(renderer
->audio_client
)))
634 WARN("Failed to start audio client, hr %#x.\n", hr
);
635 renderer
->state
= STREAM_STATE_RUNNING
;
639 hr
= MF_E_NOT_INITIALIZED
;
641 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkStarted
, &GUID_NULL
, hr
, NULL
);
643 audio_renderer_preroll(renderer
);
644 LeaveCriticalSection(&renderer
->cs
);
649 static HRESULT WINAPI
audio_renderer_clock_sink_OnClockStop(IMFClockStateSink
*iface
, MFTIME systime
)
651 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
654 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
656 EnterCriticalSection(&renderer
->cs
);
657 if (renderer
->audio_client
)
659 if (renderer
->state
!= STREAM_STATE_STOPPED
)
661 if (SUCCEEDED(hr
= IAudioClient_Stop(renderer
->audio_client
)))
663 if (FAILED(hr
= IAudioClient_Reset(renderer
->audio_client
)))
664 WARN("Failed to reset audio client, hr %#x.\n", hr
);
667 WARN("Failed to stop audio client, hr %#x.\n", hr
);
668 renderer
->state
= STREAM_STATE_STOPPED
;
669 renderer
->flags
&= ~SAR_PREROLLED
;
673 hr
= MF_E_NOT_INITIALIZED
;
675 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkStopped
, &GUID_NULL
, hr
, NULL
);
676 LeaveCriticalSection(&renderer
->cs
);
681 static HRESULT WINAPI
audio_renderer_clock_sink_OnClockPause(IMFClockStateSink
*iface
, MFTIME systime
)
683 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
686 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
688 EnterCriticalSection(&renderer
->cs
);
689 if (renderer
->state
== STREAM_STATE_RUNNING
)
691 if (renderer
->audio_client
)
693 if (FAILED(hr
= IAudioClient_Stop(renderer
->audio_client
)))
694 WARN("Failed to stop audio client, hr %#x.\n", hr
);
695 renderer
->state
= STREAM_STATE_PAUSED
;
698 hr
= MF_E_NOT_INITIALIZED
;
700 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkPaused
, &GUID_NULL
, hr
, NULL
);
703 hr
= MF_E_INVALID_STATE_TRANSITION
;
704 LeaveCriticalSection(&renderer
->cs
);
709 static HRESULT WINAPI
audio_renderer_clock_sink_OnClockRestart(IMFClockStateSink
*iface
, MFTIME systime
)
711 struct audio_renderer
*renderer
= impl_from_IMFClockStateSink(iface
);
712 BOOL preroll
= FALSE
;
715 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
717 EnterCriticalSection(&renderer
->cs
);
718 if (renderer
->audio_client
)
720 if ((preroll
= (renderer
->state
!= STREAM_STATE_RUNNING
)))
722 if (FAILED(hr
= IAudioClient_Start(renderer
->audio_client
)))
723 WARN("Failed to start audio client, hr %#x.\n", hr
);
724 renderer
->state
= STREAM_STATE_RUNNING
;
728 hr
= MF_E_NOT_INITIALIZED
;
730 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkStarted
, &GUID_NULL
, hr
, NULL
);
732 audio_renderer_preroll(renderer
);
734 LeaveCriticalSection(&renderer
->cs
);
739 static HRESULT WINAPI
audio_renderer_clock_sink_OnClockSetRate(IMFClockStateSink
*iface
, MFTIME systime
, float rate
)
741 FIXME("%p, %s, %f.\n", iface
, debugstr_time(systime
), rate
);
746 static const IMFClockStateSinkVtbl audio_renderer_clock_sink_vtbl
=
748 audio_renderer_clock_sink_QueryInterface
,
749 audio_renderer_clock_sink_AddRef
,
750 audio_renderer_clock_sink_Release
,
751 audio_renderer_clock_sink_OnClockStart
,
752 audio_renderer_clock_sink_OnClockStop
,
753 audio_renderer_clock_sink_OnClockPause
,
754 audio_renderer_clock_sink_OnClockRestart
,
755 audio_renderer_clock_sink_OnClockSetRate
,
758 static HRESULT WINAPI
audio_renderer_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
760 struct audio_renderer
*renderer
= impl_from_IMFGetService(iface
);
761 return IMFMediaSink_QueryInterface(&renderer
->IMFMediaSink_iface
, riid
, obj
);
764 static ULONG WINAPI
audio_renderer_get_service_AddRef(IMFGetService
*iface
)
766 struct audio_renderer
*renderer
= impl_from_IMFGetService(iface
);
767 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
770 static ULONG WINAPI
audio_renderer_get_service_Release(IMFGetService
*iface
)
772 struct audio_renderer
*renderer
= impl_from_IMFGetService(iface
);
773 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
776 static HRESULT WINAPI
audio_renderer_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
778 struct audio_renderer
*renderer
= impl_from_IMFGetService(iface
);
780 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
784 if (IsEqualGUID(service
, &MR_POLICY_VOLUME_SERVICE
) && IsEqualIID(riid
, &IID_IMFSimpleAudioVolume
))
786 *obj
= &renderer
->IMFSimpleAudioVolume_iface
;
788 else if (IsEqualGUID(service
, &MR_STREAM_VOLUME_SERVICE
) && IsEqualIID(riid
, &IID_IMFAudioStreamVolume
))
790 *obj
= &renderer
->IMFAudioStreamVolume_iface
;
792 else if (IsEqualGUID(service
, &MR_AUDIO_POLICY_SERVICE
) && IsEqualIID(riid
, &IID_IMFAudioPolicy
))
794 *obj
= &renderer
->IMFAudioPolicy_iface
;
797 FIXME("Unsupported service %s, interface %s.\n", debugstr_guid(service
), debugstr_guid(riid
));
800 IUnknown_AddRef((IUnknown
*)*obj
);
802 return *obj
? S_OK
: E_NOINTERFACE
;
805 static const IMFGetServiceVtbl audio_renderer_get_service_vtbl
=
807 audio_renderer_get_service_QueryInterface
,
808 audio_renderer_get_service_AddRef
,
809 audio_renderer_get_service_Release
,
810 audio_renderer_get_service_GetService
,
813 static HRESULT WINAPI
audio_renderer_simple_volume_QueryInterface(IMFSimpleAudioVolume
*iface
, REFIID riid
, void **obj
)
815 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
817 if (IsEqualIID(riid
, &IID_IMFSimpleAudioVolume
) ||
818 IsEqualIID(riid
, &IID_IUnknown
))
821 IMFSimpleAudioVolume_AddRef(iface
);
825 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
827 return E_NOINTERFACE
;
830 static ULONG WINAPI
audio_renderer_simple_volume_AddRef(IMFSimpleAudioVolume
*iface
)
832 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
833 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
836 static ULONG WINAPI
audio_renderer_simple_volume_Release(IMFSimpleAudioVolume
*iface
)
838 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
839 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
842 static HRESULT WINAPI
audio_renderer_simple_volume_SetMasterVolume(IMFSimpleAudioVolume
*iface
, float level
)
844 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
847 TRACE("%p, %f.\n", iface
, level
);
849 EnterCriticalSection(&renderer
->cs
);
850 if (renderer
->audio_volume
)
851 hr
= ISimpleAudioVolume_SetMasterVolume(renderer
->audio_volume
, level
, NULL
);
852 LeaveCriticalSection(&renderer
->cs
);
857 static HRESULT WINAPI
audio_renderer_simple_volume_GetMasterVolume(IMFSimpleAudioVolume
*iface
, float *level
)
859 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
862 TRACE("%p, %p.\n", iface
, level
);
869 EnterCriticalSection(&renderer
->cs
);
870 if (renderer
->audio_volume
)
871 hr
= ISimpleAudioVolume_GetMasterVolume(renderer
->audio_volume
, level
);
872 LeaveCriticalSection(&renderer
->cs
);
877 static HRESULT WINAPI
audio_renderer_simple_volume_SetMute(IMFSimpleAudioVolume
*iface
, BOOL mute
)
879 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
882 TRACE("%p, %d.\n", iface
, mute
);
884 EnterCriticalSection(&renderer
->cs
);
885 if (renderer
->audio_volume
)
886 hr
= ISimpleAudioVolume_SetMute(renderer
->audio_volume
, mute
, NULL
);
887 LeaveCriticalSection(&renderer
->cs
);
892 static HRESULT WINAPI
audio_renderer_simple_volume_GetMute(IMFSimpleAudioVolume
*iface
, BOOL
*mute
)
894 struct audio_renderer
*renderer
= impl_from_IMFSimpleAudioVolume(iface
);
897 TRACE("%p, %p.\n", iface
, mute
);
904 EnterCriticalSection(&renderer
->cs
);
905 if (renderer
->audio_volume
)
906 hr
= ISimpleAudioVolume_GetMute(renderer
->audio_volume
, mute
);
907 LeaveCriticalSection(&renderer
->cs
);
912 static const IMFSimpleAudioVolumeVtbl audio_renderer_simple_volume_vtbl
=
914 audio_renderer_simple_volume_QueryInterface
,
915 audio_renderer_simple_volume_AddRef
,
916 audio_renderer_simple_volume_Release
,
917 audio_renderer_simple_volume_SetMasterVolume
,
918 audio_renderer_simple_volume_GetMasterVolume
,
919 audio_renderer_simple_volume_SetMute
,
920 audio_renderer_simple_volume_GetMute
,
923 static HRESULT WINAPI
audio_renderer_stream_volume_QueryInterface(IMFAudioStreamVolume
*iface
, REFIID riid
, void **obj
)
925 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
927 if (IsEqualIID(riid
, &IID_IMFAudioStreamVolume
) ||
928 IsEqualIID(riid
, &IID_IUnknown
))
931 IMFAudioStreamVolume_AddRef(iface
);
935 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
937 return E_NOINTERFACE
;
940 static ULONG WINAPI
audio_renderer_stream_volume_AddRef(IMFAudioStreamVolume
*iface
)
942 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
943 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
946 static ULONG WINAPI
audio_renderer_stream_volume_Release(IMFAudioStreamVolume
*iface
)
948 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
949 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
952 static HRESULT WINAPI
audio_renderer_stream_volume_GetChannelCount(IMFAudioStreamVolume
*iface
, UINT32
*count
)
954 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
957 TRACE("%p, %p.\n", iface
, count
);
964 EnterCriticalSection(&renderer
->cs
);
965 if (renderer
->stream_volume
)
966 hr
= IAudioStreamVolume_GetChannelCount(renderer
->stream_volume
, count
);
967 LeaveCriticalSection(&renderer
->cs
);
972 static HRESULT WINAPI
audio_renderer_stream_volume_SetChannelVolume(IMFAudioStreamVolume
*iface
, UINT32 index
, float level
)
974 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
977 TRACE("%p, %u, %f.\n", iface
, index
, level
);
979 EnterCriticalSection(&renderer
->cs
);
980 if (renderer
->stream_volume
)
981 hr
= IAudioStreamVolume_SetChannelVolume(renderer
->stream_volume
, index
, level
);
982 LeaveCriticalSection(&renderer
->cs
);
987 static HRESULT WINAPI
audio_renderer_stream_volume_GetChannelVolume(IMFAudioStreamVolume
*iface
, UINT32 index
, float *level
)
989 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
992 TRACE("%p, %u, %p.\n", iface
, index
, level
);
999 EnterCriticalSection(&renderer
->cs
);
1000 if (renderer
->stream_volume
)
1001 hr
= IAudioStreamVolume_GetChannelVolume(renderer
->stream_volume
, index
, level
);
1002 LeaveCriticalSection(&renderer
->cs
);
1007 static HRESULT WINAPI
audio_renderer_stream_volume_SetAllVolumes(IMFAudioStreamVolume
*iface
, UINT32 count
,
1008 const float *volumes
)
1010 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
1013 TRACE("%p, %u, %p.\n", iface
, count
, volumes
);
1015 EnterCriticalSection(&renderer
->cs
);
1016 if (renderer
->stream_volume
)
1017 hr
= IAudioStreamVolume_SetAllVolumes(renderer
->stream_volume
, count
, volumes
);
1018 LeaveCriticalSection(&renderer
->cs
);
1023 static HRESULT WINAPI
audio_renderer_stream_volume_GetAllVolumes(IMFAudioStreamVolume
*iface
, UINT32 count
, float *volumes
)
1025 struct audio_renderer
*renderer
= impl_from_IMFAudioStreamVolume(iface
);
1028 TRACE("%p, %u, %p.\n", iface
, count
, volumes
);
1034 memset(volumes
, 0, sizeof(*volumes
) * count
);
1036 EnterCriticalSection(&renderer
->cs
);
1037 if (renderer
->stream_volume
)
1038 hr
= IAudioStreamVolume_GetAllVolumes(renderer
->stream_volume
, count
, volumes
);
1039 LeaveCriticalSection(&renderer
->cs
);
1044 static const IMFAudioStreamVolumeVtbl audio_renderer_stream_volume_vtbl
=
1046 audio_renderer_stream_volume_QueryInterface
,
1047 audio_renderer_stream_volume_AddRef
,
1048 audio_renderer_stream_volume_Release
,
1049 audio_renderer_stream_volume_GetChannelCount
,
1050 audio_renderer_stream_volume_SetChannelVolume
,
1051 audio_renderer_stream_volume_GetChannelVolume
,
1052 audio_renderer_stream_volume_SetAllVolumes
,
1053 audio_renderer_stream_volume_GetAllVolumes
,
1056 static HRESULT WINAPI
audio_renderer_policy_QueryInterface(IMFAudioPolicy
*iface
, REFIID riid
, void **obj
)
1058 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1060 if (IsEqualIID(riid
, &IID_IMFAudioPolicy
) ||
1061 IsEqualIID(riid
, &IID_IUnknown
))
1064 IMFAudioPolicy_AddRef(iface
);
1068 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
1070 return E_NOINTERFACE
;
1073 static ULONG WINAPI
audio_renderer_policy_AddRef(IMFAudioPolicy
*iface
)
1075 struct audio_renderer
*renderer
= impl_from_IMFAudioPolicy(iface
);
1076 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
1079 static ULONG WINAPI
audio_renderer_policy_Release(IMFAudioPolicy
*iface
)
1081 struct audio_renderer
*renderer
= impl_from_IMFAudioPolicy(iface
);
1082 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
1085 static HRESULT WINAPI
audio_renderer_policy_SetGroupingParam(IMFAudioPolicy
*iface
, REFGUID param
)
1087 FIXME("%p, %s.\n", iface
, debugstr_guid(param
));
1092 static HRESULT WINAPI
audio_renderer_policy_GetGroupingParam(IMFAudioPolicy
*iface
, GUID
*param
)
1094 FIXME("%p, %p.\n", iface
, param
);
1099 static HRESULT WINAPI
audio_renderer_policy_SetDisplayName(IMFAudioPolicy
*iface
, const WCHAR
*name
)
1101 FIXME("%p, %s.\n", iface
, debugstr_w(name
));
1106 static HRESULT WINAPI
audio_renderer_policy_GetDisplayName(IMFAudioPolicy
*iface
, WCHAR
**name
)
1108 FIXME("%p, %p.\n", iface
, name
);
1113 static HRESULT WINAPI
audio_renderer_policy_SetIconPath(IMFAudioPolicy
*iface
, const WCHAR
*path
)
1115 FIXME("%p, %s.\n", iface
, debugstr_w(path
));
1120 static HRESULT WINAPI
audio_renderer_policy_GetIconPath(IMFAudioPolicy
*iface
, WCHAR
**path
)
1122 FIXME("%p, %p.\n", iface
, path
);
1127 static const IMFAudioPolicyVtbl audio_renderer_policy_vtbl
=
1129 audio_renderer_policy_QueryInterface
,
1130 audio_renderer_policy_AddRef
,
1131 audio_renderer_policy_Release
,
1132 audio_renderer_policy_SetGroupingParam
,
1133 audio_renderer_policy_GetGroupingParam
,
1134 audio_renderer_policy_SetDisplayName
,
1135 audio_renderer_policy_GetDisplayName
,
1136 audio_renderer_policy_SetIconPath
,
1137 audio_renderer_policy_GetIconPath
,
1140 static HRESULT
sar_create_mmdevice(IMFAttributes
*attributes
, struct audio_renderer
*renderer
)
1143 unsigned int length
, role
= eMultimedia
;
1144 IMMDeviceEnumerator
*devenum
;
1149 /* Mutually exclusive attributes. */
1150 if (SUCCEEDED(IMFAttributes_GetItem(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE
, NULL
)) &&
1151 SUCCEEDED(IMFAttributes_GetItem(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID
, NULL
)))
1153 return E_INVALIDARG
;
1157 if (FAILED(hr
= CoCreateInstance(&CLSID_MMDeviceEnumerator
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMMDeviceEnumerator
,
1158 (void **)&devenum
)))
1164 if (attributes
&& SUCCEEDED(IMFAttributes_GetUINT32(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE
, &role
)))
1165 TRACE("Specified role %d.\n", role
);
1167 if (attributes
&& SUCCEEDED(IMFAttributes_GetAllocatedString(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID
,
1168 &endpoint
, &length
)))
1170 TRACE("Specified end point %s.\n", debugstr_w(endpoint
));
1171 hr
= IMMDeviceEnumerator_GetDevice(devenum
, endpoint
, &renderer
->device
);
1172 CoTaskMemFree(endpoint
);
1175 hr
= IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum
, eRender
, role
, &renderer
->device
);
1177 /* Configuration attributes to be used later for audio client initialization. */
1180 IMFAttributes_GetUINT32(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_FLAGS
, &renderer
->stream_config
.flags
);
1181 IMFAttributes_GetGUID(attributes
, &MF_AUDIO_RENDERER_ATTRIBUTE_SESSION_ID
, &renderer
->stream_config
.session_id
);
1185 hr
= MF_E_NO_AUDIO_PLAYBACK_DEVICE
;
1187 IMMDeviceEnumerator_Release(devenum
);
1192 static HRESULT WINAPI
audio_renderer_stream_QueryInterface(IMFStreamSink
*iface
, REFIID riid
, void **obj
)
1194 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1196 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1198 if (IsEqualIID(riid
, &IID_IMFStreamSink
) ||
1199 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
1200 IsEqualIID(riid
, &IID_IUnknown
))
1202 *obj
= &renderer
->IMFStreamSink_iface
;
1204 else if (IsEqualIID(riid
, &IID_IMFMediaTypeHandler
))
1206 *obj
= &renderer
->IMFMediaTypeHandler_iface
;
1210 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1212 return E_NOINTERFACE
;
1215 IUnknown_AddRef((IUnknown
*)*obj
);
1220 static ULONG WINAPI
audio_renderer_stream_AddRef(IMFStreamSink
*iface
)
1222 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1223 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
1226 static ULONG WINAPI
audio_renderer_stream_Release(IMFStreamSink
*iface
)
1228 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1229 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
1232 static HRESULT WINAPI
audio_renderer_stream_GetEvent(IMFStreamSink
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1234 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1236 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
1238 if (renderer
->flags
& SAR_SHUT_DOWN
)
1239 return MF_E_STREAMSINK_REMOVED
;
1241 return IMFMediaEventQueue_GetEvent(renderer
->stream_event_queue
, flags
, event
);
1244 static HRESULT WINAPI
audio_renderer_stream_BeginGetEvent(IMFStreamSink
*iface
, IMFAsyncCallback
*callback
,
1247 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1249 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1251 if (renderer
->flags
& SAR_SHUT_DOWN
)
1252 return MF_E_STREAMSINK_REMOVED
;
1254 return IMFMediaEventQueue_BeginGetEvent(renderer
->stream_event_queue
, callback
, state
);
1257 static HRESULT WINAPI
audio_renderer_stream_EndGetEvent(IMFStreamSink
*iface
, IMFAsyncResult
*result
,
1258 IMFMediaEvent
**event
)
1260 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1262 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1264 if (renderer
->flags
& SAR_SHUT_DOWN
)
1265 return MF_E_STREAMSINK_REMOVED
;
1267 return IMFMediaEventQueue_EndGetEvent(renderer
->stream_event_queue
, result
, event
);
1270 static HRESULT WINAPI
audio_renderer_stream_QueueEvent(IMFStreamSink
*iface
, MediaEventType event_type
,
1271 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
1273 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1275 TRACE("%p, %u, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1277 if (renderer
->flags
& SAR_SHUT_DOWN
)
1278 return MF_E_STREAMSINK_REMOVED
;
1280 return IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, event_type
, ext_type
, hr
, value
);
1283 static HRESULT WINAPI
audio_renderer_stream_GetMediaSink(IMFStreamSink
*iface
, IMFMediaSink
**sink
)
1285 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1287 TRACE("%p, %p.\n", iface
, sink
);
1289 if (renderer
->flags
& SAR_SHUT_DOWN
)
1290 return MF_E_STREAMSINK_REMOVED
;
1292 *sink
= &renderer
->IMFMediaSink_iface
;
1293 IMFMediaSink_AddRef(*sink
);
1298 static HRESULT WINAPI
audio_renderer_stream_GetIdentifier(IMFStreamSink
*iface
, DWORD
*identifier
)
1300 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1302 TRACE("%p, %p.\n", iface
, identifier
);
1304 if (renderer
->flags
& SAR_SHUT_DOWN
)
1305 return MF_E_STREAMSINK_REMOVED
;
1312 static HRESULT WINAPI
audio_renderer_stream_GetMediaTypeHandler(IMFStreamSink
*iface
, IMFMediaTypeHandler
**handler
)
1314 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1316 TRACE("%p, %p.\n", iface
, handler
);
1321 if (renderer
->flags
& SAR_SHUT_DOWN
)
1322 return MF_E_STREAMSINK_REMOVED
;
1324 *handler
= &renderer
->IMFMediaTypeHandler_iface
;
1325 IMFMediaTypeHandler_AddRef(*handler
);
1330 static HRESULT
stream_queue_sample(struct audio_renderer
*renderer
, IMFSample
*sample
)
1332 struct queued_object
*object
;
1334 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1335 return E_OUTOFMEMORY
;
1337 object
->type
= OBJECT_TYPE_SAMPLE
;
1338 object
->u
.sample
.sample
= sample
;
1339 IMFSample_AddRef(object
->u
.sample
.sample
);
1341 list_add_tail(&renderer
->queue
, &object
->entry
);
1346 static HRESULT WINAPI
audio_renderer_stream_ProcessSample(IMFStreamSink
*iface
, IMFSample
*sample
)
1348 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1351 TRACE("%p, %p.\n", iface
, sample
);
1356 if (renderer
->flags
& SAR_SHUT_DOWN
)
1357 return MF_E_STREAMSINK_REMOVED
;
1359 EnterCriticalSection(&renderer
->cs
);
1360 if (renderer
->state
== STREAM_STATE_RUNNING
)
1361 hr
= stream_queue_sample(renderer
, sample
);
1362 renderer
->flags
&= ~SAR_SAMPLE_REQUESTED
;
1363 LeaveCriticalSection(&renderer
->cs
);
1368 static HRESULT
stream_place_marker(struct audio_renderer
*renderer
, MFSTREAMSINK_MARKER_TYPE marker_type
,
1369 const PROPVARIANT
*context_value
)
1371 struct queued_object
*marker
;
1374 if (!(marker
= heap_alloc_zero(sizeof(*marker
))))
1375 return E_OUTOFMEMORY
;
1377 marker
->type
= OBJECT_TYPE_MARKER
;
1378 marker
->u
.marker
.type
= marker_type
;
1379 PropVariantInit(&marker
->u
.marker
.context
);
1381 hr
= PropVariantCopy(&marker
->u
.marker
.context
, context_value
);
1383 list_add_tail(&renderer
->queue
, &marker
->entry
);
1385 release_pending_object(marker
);
1390 static HRESULT WINAPI
audio_renderer_stream_PlaceMarker(IMFStreamSink
*iface
, MFSTREAMSINK_MARKER_TYPE marker_type
,
1391 const PROPVARIANT
*marker_value
, const PROPVARIANT
*context_value
)
1393 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1396 TRACE("%p, %d, %p, %p.\n", iface
, marker_type
, marker_value
, context_value
);
1398 if (renderer
->flags
& SAR_SHUT_DOWN
)
1399 return MF_E_STREAMSINK_REMOVED
;
1401 EnterCriticalSection(&renderer
->cs
);
1402 hr
= stream_place_marker(renderer
, marker_type
, context_value
);
1403 LeaveCriticalSection(&renderer
->cs
);
1408 static HRESULT WINAPI
audio_renderer_stream_Flush(IMFStreamSink
*iface
)
1410 struct audio_renderer
*renderer
= impl_from_IMFStreamSink(iface
);
1411 struct queued_object
*obj
, *obj2
;
1414 TRACE("%p.\n", iface
);
1416 EnterCriticalSection(&renderer
->cs
);
1417 if (renderer
->flags
& SAR_SHUT_DOWN
)
1418 hr
= MF_E_STREAMSINK_REMOVED
;
1421 LIST_FOR_EACH_ENTRY_SAFE(obj
, obj2
, &renderer
->queue
, struct queued_object
, entry
)
1423 if (obj
->type
== OBJECT_TYPE_MARKER
)
1425 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkMarker
,
1426 &GUID_NULL
, S_OK
, &obj
->u
.marker
.context
);
1428 release_pending_object(obj
);
1431 LeaveCriticalSection(&renderer
->cs
);
1436 static const IMFStreamSinkVtbl audio_renderer_stream_vtbl
=
1438 audio_renderer_stream_QueryInterface
,
1439 audio_renderer_stream_AddRef
,
1440 audio_renderer_stream_Release
,
1441 audio_renderer_stream_GetEvent
,
1442 audio_renderer_stream_BeginGetEvent
,
1443 audio_renderer_stream_EndGetEvent
,
1444 audio_renderer_stream_QueueEvent
,
1445 audio_renderer_stream_GetMediaSink
,
1446 audio_renderer_stream_GetIdentifier
,
1447 audio_renderer_stream_GetMediaTypeHandler
,
1448 audio_renderer_stream_ProcessSample
,
1449 audio_renderer_stream_PlaceMarker
,
1450 audio_renderer_stream_Flush
,
1453 static HRESULT WINAPI
audio_renderer_stream_type_handler_QueryInterface(IMFMediaTypeHandler
*iface
, REFIID riid
,
1456 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1457 return IMFStreamSink_QueryInterface(&renderer
->IMFStreamSink_iface
, riid
, obj
);
1460 static ULONG WINAPI
audio_renderer_stream_type_handler_AddRef(IMFMediaTypeHandler
*iface
)
1462 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1463 return IMFStreamSink_AddRef(&renderer
->IMFStreamSink_iface
);
1466 static ULONG WINAPI
audio_renderer_stream_type_handler_Release(IMFMediaTypeHandler
*iface
)
1468 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1469 return IMFStreamSink_Release(&renderer
->IMFStreamSink_iface
);
1472 static HRESULT WINAPI
audio_renderer_stream_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler
*iface
,
1473 IMFMediaType
*in_type
, IMFMediaType
**out_type
)
1475 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1479 TRACE("%p, %p, %p.\n", iface
, in_type
, out_type
);
1481 EnterCriticalSection(&renderer
->cs
);
1482 hr
= renderer
->current_media_type
&& IMFMediaType_IsEqual(renderer
->current_media_type
, in_type
, &flags
) == S_OK
?
1483 S_OK
: MF_E_INVALIDMEDIATYPE
;
1484 LeaveCriticalSection(&renderer
->cs
);
1489 static HRESULT WINAPI
audio_renderer_stream_type_handler_GetMediaTypeCount(IMFMediaTypeHandler
*iface
, DWORD
*count
)
1491 TRACE("%p, %p.\n", iface
, count
);
1498 static HRESULT WINAPI
audio_renderer_stream_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler
*iface
, DWORD index
,
1499 IMFMediaType
**media_type
)
1501 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1503 TRACE("%p, %u, %p.\n", iface
, index
, media_type
);
1507 *media_type
= renderer
->media_type
;
1508 IMFMediaType_AddRef(*media_type
);
1514 static HRESULT
audio_renderer_create_audio_client(struct audio_renderer
*renderer
)
1516 IMFAsyncResult
*result
;
1521 audio_renderer_release_audio_client(renderer
);
1523 hr
= IMMDevice_Activate(renderer
->device
, &IID_IAudioClient
, CLSCTX_INPROC_SERVER
, NULL
,
1524 (void **)&renderer
->audio_client
);
1527 WARN("Failed to create audio client, hr %#x.\n", hr
);
1531 /* FIXME: for now always use default format. */
1532 if (FAILED(hr
= IAudioClient_GetMixFormat(renderer
->audio_client
, &wfx
)))
1534 WARN("Failed to get audio format, hr %#x.\n", hr
);
1538 renderer
->frame_size
= wfx
->wBitsPerSample
* wfx
->nChannels
/ 8;
1540 flags
= AUDCLNT_STREAMFLAGS_EVENTCALLBACK
;
1541 if (renderer
->stream_config
.flags
& MF_AUDIO_RENDERER_ATTRIBUTE_FLAGS_CROSSPROCESS
)
1542 flags
|= AUDCLNT_STREAMFLAGS_CROSSPROCESS
;
1543 if (renderer
->stream_config
.flags
& MF_AUDIO_RENDERER_ATTRIBUTE_FLAGS_NOPERSIST
)
1544 flags
|= AUDCLNT_STREAMFLAGS_NOPERSIST
;
1545 hr
= IAudioClient_Initialize(renderer
->audio_client
, AUDCLNT_SHAREMODE_SHARED
, flags
, 1000000, 0, wfx
,
1546 &renderer
->stream_config
.session_id
);
1550 WARN("Failed to initialize audio client, hr %#x.\n", hr
);
1554 if (FAILED(hr
= IAudioClient_GetService(renderer
->audio_client
, &IID_IAudioStreamVolume
,
1555 (void **)&renderer
->stream_volume
)))
1557 WARN("Failed to get stream volume control, hr %#x.\n", hr
);
1561 if (FAILED(hr
= IAudioClient_GetService(renderer
->audio_client
, &IID_ISimpleAudioVolume
, (void **)&renderer
->audio_volume
)))
1563 WARN("Failed to get audio volume control, hr %#x.\n", hr
);
1567 if (FAILED(hr
= IAudioClient_GetService(renderer
->audio_client
, &IID_IAudioRenderClient
,
1568 (void **)&renderer
->audio_render_client
)))
1570 WARN("Failed to get audio render client, hr %#x.\n", hr
);
1574 if (FAILED(hr
= IAudioClient_SetEventHandle(renderer
->audio_client
, renderer
->buffer_ready_event
)))
1576 WARN("Failed to set event handle, hr %#x.\n", hr
);
1580 if (SUCCEEDED(hr
= MFCreateAsyncResult(NULL
, &renderer
->render_callback
, NULL
, &result
)))
1582 if (FAILED(hr
= MFPutWaitingWorkItem(renderer
->buffer_ready_event
, 0, result
, &renderer
->buffer_ready_key
)))
1583 WARN("Failed to submit wait item, hr %#x.\n", hr
);
1584 IMFAsyncResult_Release(result
);
1590 static HRESULT WINAPI
audio_renderer_stream_type_handler_SetCurrentMediaType(IMFMediaTypeHandler
*iface
,
1591 IMFMediaType
*media_type
)
1593 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1594 const unsigned int test_flags
= MF_MEDIATYPE_EQUAL_MAJOR_TYPES
| MF_MEDIATYPE_EQUAL_FORMAT_TYPES
;
1595 BOOL compare_result
;
1599 TRACE("%p, %p.\n", iface
, media_type
);
1604 EnterCriticalSection(&renderer
->cs
);
1605 if (SUCCEEDED(IMFMediaType_IsEqual(renderer
->media_type
, media_type
, &flags
)) && ((flags
& test_flags
) == test_flags
))
1607 if (renderer
->current_media_type
)
1608 IMFMediaType_Release(renderer
->current_media_type
);
1609 renderer
->current_media_type
= media_type
;
1610 IMFMediaType_AddRef(renderer
->current_media_type
);
1612 if (SUCCEEDED(hr
= audio_renderer_create_audio_client(renderer
)))
1614 if (SUCCEEDED(IMFMediaType_Compare(renderer
->media_type
, (IMFAttributes
*)media_type
, MF_ATTRIBUTES_MATCH_OUR_ITEMS
,
1615 &compare_result
)) && !compare_result
)
1617 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkFormatInvalidated
, &GUID_NULL
,
1619 audio_renderer_preroll(renderer
);
1624 hr
= MF_E_INVALIDMEDIATYPE
;
1625 LeaveCriticalSection(&renderer
->cs
);
1630 static HRESULT WINAPI
audio_renderer_stream_type_handler_GetCurrentMediaType(IMFMediaTypeHandler
*iface
,
1631 IMFMediaType
**media_type
)
1633 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1636 TRACE("%p, %p.\n", iface
, media_type
);
1638 EnterCriticalSection(&renderer
->cs
);
1639 if (renderer
->current_media_type
)
1641 *media_type
= renderer
->current_media_type
;
1642 IMFMediaType_AddRef(*media_type
);
1645 hr
= MF_E_NOT_INITIALIZED
;
1646 LeaveCriticalSection(&renderer
->cs
);
1651 static HRESULT WINAPI
audio_renderer_stream_type_handler_GetMajorType(IMFMediaTypeHandler
*iface
, GUID
*type
)
1653 struct audio_renderer
*renderer
= impl_from_IMFMediaTypeHandler(iface
);
1655 TRACE("%p, %p.\n", iface
, type
);
1660 if (renderer
->flags
& SAR_SHUT_DOWN
)
1661 return MF_E_STREAMSINK_REMOVED
;
1663 memcpy(type
, &MFMediaType_Audio
, sizeof(*type
));
1667 static const IMFMediaTypeHandlerVtbl audio_renderer_stream_type_handler_vtbl
=
1669 audio_renderer_stream_type_handler_QueryInterface
,
1670 audio_renderer_stream_type_handler_AddRef
,
1671 audio_renderer_stream_type_handler_Release
,
1672 audio_renderer_stream_type_handler_IsMediaTypeSupported
,
1673 audio_renderer_stream_type_handler_GetMediaTypeCount
,
1674 audio_renderer_stream_type_handler_GetMediaTypeByIndex
,
1675 audio_renderer_stream_type_handler_SetCurrentMediaType
,
1676 audio_renderer_stream_type_handler_GetCurrentMediaType
,
1677 audio_renderer_stream_type_handler_GetMajorType
,
1680 static HRESULT
audio_renderer_collect_supported_types(struct audio_renderer
*renderer
)
1682 IAudioClient
*client
;
1683 WAVEFORMATEX
*format
;
1686 if (FAILED(hr
= MFCreateMediaType(&renderer
->media_type
)))
1689 hr
= IMMDevice_Activate(renderer
->device
, &IID_IAudioClient
, CLSCTX_INPROC_SERVER
, NULL
, (void **)&client
);
1692 WARN("Failed to create audio client, hr %#x.\n", hr
);
1698 hr
= IAudioClient_GetMixFormat(client
, &format
);
1699 IAudioClient_Release(client
);
1702 WARN("Failed to get device audio format, hr %#x.\n", hr
);
1706 hr
= MFInitMediaTypeFromWaveFormatEx(renderer
->media_type
, format
, format
->cbSize
+ sizeof(*format
));
1707 CoTaskMemFree(format
);
1710 WARN("Failed to initialize media type, hr %#x.\n", hr
);
1714 IMFMediaType_DeleteItem(renderer
->media_type
, &MF_MT_AUDIO_PREFER_WAVEFORMATEX
);
1719 static HRESULT WINAPI
audio_renderer_render_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
1721 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1723 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
1724 IsEqualIID(riid
, &IID_IUnknown
))
1727 IMFAsyncCallback_AddRef(iface
);
1731 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
1733 return E_NOINTERFACE
;
1736 static ULONG WINAPI
audio_renderer_render_callback_AddRef(IMFAsyncCallback
*iface
)
1738 struct audio_renderer
*renderer
= impl_from_render_callback_IMFAsyncCallback(iface
);
1739 return IMFMediaSink_AddRef(&renderer
->IMFMediaSink_iface
);
1742 static ULONG WINAPI
audio_renderer_render_callback_Release(IMFAsyncCallback
*iface
)
1744 struct audio_renderer
*renderer
= impl_from_render_callback_IMFAsyncCallback(iface
);
1745 return IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
1748 static HRESULT WINAPI
audio_renderer_render_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
1753 static HRESULT WINAPI
audio_renderer_render_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1755 struct audio_renderer
*renderer
= impl_from_render_callback_IMFAsyncCallback(iface
);
1756 unsigned int src_frames
, dst_frames
, max_frames
, src_len
;
1757 struct queued_object
*obj
, *obj2
;
1758 BOOL keep_sample
= FALSE
;
1759 IMFMediaBuffer
*buffer
;
1763 EnterCriticalSection(&renderer
->cs
);
1765 LIST_FOR_EACH_ENTRY_SAFE(obj
, obj2
, &renderer
->queue
, struct queued_object
, entry
)
1767 if (obj
->type
== OBJECT_TYPE_MARKER
)
1769 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkMarker
,
1770 &GUID_NULL
, S_OK
, &obj
->u
.marker
.context
);
1772 else if (obj
->type
== OBJECT_TYPE_SAMPLE
)
1774 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(obj
->u
.sample
.sample
, &buffer
)))
1776 if (SUCCEEDED(IMFMediaBuffer_Lock(buffer
, &src
, NULL
, &src_len
)))
1778 if ((src_frames
= src_len
/ renderer
->frame_size
))
1780 if (SUCCEEDED(IAudioClient_GetBufferSize(renderer
->audio_client
, &max_frames
)))
1782 src_frames
-= obj
->u
.sample
.frame_offset
;
1783 dst_frames
= min(src_frames
, max_frames
);
1785 if (SUCCEEDED(hr
= IAudioRenderClient_GetBuffer(renderer
->audio_render_client
, dst_frames
, &dst
)))
1787 memcpy(dst
, src
+ obj
->u
.sample
.frame_offset
* renderer
->frame_size
,
1788 dst_frames
* renderer
->frame_size
);
1790 IAudioRenderClient_ReleaseBuffer(renderer
->audio_render_client
, dst_frames
, 0);
1792 obj
->u
.sample
.frame_offset
+= dst_frames
;
1795 keep_sample
= FAILED(hr
) || src_frames
> max_frames
;
1798 IMFMediaBuffer_Unlock(buffer
);
1800 IMFMediaBuffer_Release(buffer
);
1807 list_remove(&obj
->entry
);
1808 release_pending_object(obj
);
1811 if (list_empty(&renderer
->queue
) && !(renderer
->flags
& SAR_SAMPLE_REQUESTED
))
1813 IMFMediaEventQueue_QueueEventParamVar(renderer
->stream_event_queue
, MEStreamSinkRequestSample
, &GUID_NULL
, S_OK
, NULL
);
1814 renderer
->flags
|= SAR_SAMPLE_REQUESTED
;
1817 if (FAILED(hr
= MFPutWaitingWorkItem(renderer
->buffer_ready_event
, 0, result
, &renderer
->buffer_ready_key
)))
1818 WARN("Failed to submit wait item, hr %#x.\n", hr
);
1820 LeaveCriticalSection(&renderer
->cs
);
1825 static const IMFAsyncCallbackVtbl audio_renderer_render_callback_vtbl
=
1827 audio_renderer_render_callback_QueryInterface
,
1828 audio_renderer_render_callback_AddRef
,
1829 audio_renderer_render_callback_Release
,
1830 audio_renderer_render_callback_GetParameters
,
1831 audio_renderer_render_callback_Invoke
,
1834 static HRESULT
sar_create_object(IMFAttributes
*attributes
, void *user_context
, IUnknown
**obj
)
1836 struct audio_renderer
*renderer
;
1839 TRACE("%p, %p, %p.\n", attributes
, user_context
, obj
);
1841 if (!(renderer
= heap_alloc_zero(sizeof(*renderer
))))
1842 return E_OUTOFMEMORY
;
1844 renderer
->IMFMediaSink_iface
.lpVtbl
= &audio_renderer_sink_vtbl
;
1845 renderer
->IMFMediaSinkPreroll_iface
.lpVtbl
= &audio_renderer_preroll_vtbl
;
1846 renderer
->IMFStreamSink_iface
.lpVtbl
= &audio_renderer_stream_vtbl
;
1847 renderer
->IMFMediaTypeHandler_iface
.lpVtbl
= &audio_renderer_stream_type_handler_vtbl
;
1848 renderer
->IMFClockStateSink_iface
.lpVtbl
= &audio_renderer_clock_sink_vtbl
;
1849 renderer
->IMFMediaEventGenerator_iface
.lpVtbl
= &audio_renderer_events_vtbl
;
1850 renderer
->IMFGetService_iface
.lpVtbl
= &audio_renderer_get_service_vtbl
;
1851 renderer
->IMFSimpleAudioVolume_iface
.lpVtbl
= &audio_renderer_simple_volume_vtbl
;
1852 renderer
->IMFAudioStreamVolume_iface
.lpVtbl
= &audio_renderer_stream_volume_vtbl
;
1853 renderer
->IMFAudioPolicy_iface
.lpVtbl
= &audio_renderer_policy_vtbl
;
1854 renderer
->render_callback
.lpVtbl
= &audio_renderer_render_callback_vtbl
;
1855 renderer
->refcount
= 1;
1856 InitializeCriticalSection(&renderer
->cs
);
1857 renderer
->buffer_ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1858 list_init(&renderer
->queue
);
1860 if (FAILED(hr
= MFCreateEventQueue(&renderer
->event_queue
)))
1863 if (FAILED(hr
= MFCreateEventQueue(&renderer
->stream_event_queue
)))
1866 if (FAILED(hr
= sar_create_mmdevice(attributes
, renderer
)))
1869 if (FAILED(hr
= audio_renderer_collect_supported_types(renderer
)))
1872 *obj
= (IUnknown
*)&renderer
->IMFMediaSink_iface
;
1878 IMFMediaSink_Release(&renderer
->IMFMediaSink_iface
);
1883 static void sar_shutdown_object(void *user_context
, IUnknown
*obj
)
1887 if (SUCCEEDED(IUnknown_QueryInterface(obj
, &IID_IMFMediaSink
, (void **)&sink
)))
1889 IMFMediaSink_Shutdown(sink
);
1890 IMFMediaSink_Release(sink
);
1894 static const struct activate_funcs sar_activate_funcs
=
1896 .create_object
= sar_create_object
,
1897 .shutdown_object
= sar_shutdown_object
,
1900 /***********************************************************************
1901 * MFCreateAudioRendererActivate (mf.@)
1903 HRESULT WINAPI
MFCreateAudioRendererActivate(IMFActivate
**activate
)
1905 TRACE("%p.\n", activate
);
1910 return create_activation_object(NULL
, &sar_activate_funcs
, activate
);
1913 /***********************************************************************
1914 * MFCreateAudioRenderer (mf.@)
1916 HRESULT WINAPI
MFCreateAudioRenderer(IMFAttributes
*attributes
, IMFMediaSink
**sink
)
1921 TRACE("%p, %p.\n", attributes
, sink
);
1923 if (SUCCEEDED(hr
= sar_create_object(attributes
, NULL
, &object
)))
1925 hr
= IUnknown_QueryInterface(object
, &IID_IMFMediaSink
, (void **)sink
);
1926 IUnknown_Release(object
);