From d2c736e1bad29f246a69f1070e42c2d19158dab9 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Mon, 20 Apr 2020 19:24:59 +0300 Subject: [PATCH] mf: Add initial implementation of SAR stream type handler. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/mf/sar.c | 133 +++++++++++++++++++++++++++++++++++++++------ dlls/mf/tests/mf.c | 29 +++++++--- 2 files changed, 138 insertions(+), 24 deletions(-) diff --git a/dlls/mf/sar.c b/dlls/mf/sar.c index 3edaf06f01f..80cfd94952c 100644 --- a/dlls/mf/sar.c +++ b/dlls/mf/sar.c @@ -24,6 +24,7 @@ #include "mf_private.h" #include "initguid.h" #include "mmdeviceapi.h" +#include "audioclient.h" #include "wine/debug.h" #include "wine/heap.h" @@ -46,6 +47,9 @@ struct audio_renderer IMFMediaEventQueue *event_queue; IMFMediaEventQueue *stream_event_queue; IMFPresentationClock *clock; + IMFMediaType *media_type; + IMFMediaType *current_media_type; + IMMDevice *device; BOOL is_shut_down; CRITICAL_SECTION cs; }; @@ -162,6 +166,12 @@ static ULONG WINAPI audio_renderer_sink_Release(IMFMediaSink *iface) IMFMediaEventQueue_Release(renderer->stream_event_queue); if (renderer->clock) IMFPresentationClock_Release(renderer->clock); + if (renderer->device) + IMMDevice_Release(renderer->device); + if (renderer->media_type) + IMFMediaType_Release(renderer->media_type); + if (renderer->current_media_type) + IMFMediaType_Release(renderer->current_media_type); DeleteCriticalSection(&renderer->cs); heap_free(renderer); } @@ -814,7 +824,7 @@ static const IMFAudioPolicyVtbl audio_renderer_policy_vtbl = audio_renderer_policy_GetIconPath, }; -static HRESULT sar_create_mmdevice(IMFAttributes *attributes, IMMDevice **device) +static HRESULT sar_create_mmdevice(IMFAttributes *attributes, struct audio_renderer *renderer) { WCHAR *endpoint; unsigned int length, role = eMultimedia; @@ -845,11 +855,11 @@ static HRESULT sar_create_mmdevice(IMFAttributes *attributes, IMMDevice **device &endpoint, &length))) { TRACE("Specified end point %s.\n", debugstr_w(endpoint)); - hr = IMMDeviceEnumerator_GetDevice(devenum, endpoint, device); + hr = IMMDeviceEnumerator_GetDevice(devenum, endpoint, &renderer->device); CoTaskMemFree(endpoint); } else - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, eRender, role, device); + hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, eRender, role, &renderer->device); if (FAILED(hr)) hr = MF_E_NO_AUDIO_PLAYBACK_DEVICE; @@ -1057,40 +1067,92 @@ static ULONG WINAPI audio_renderer_stream_type_handler_Release(IMFMediaTypeHandl static HRESULT WINAPI audio_renderer_stream_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler *iface, IMFMediaType *in_type, IMFMediaType **out_type) { - FIXME("%p, %p, %p.\n", iface, in_type, out_type); + struct audio_renderer *renderer = impl_from_IMFMediaTypeHandler(iface); + unsigned int flags; + HRESULT hr; - return E_NOTIMPL; + TRACE("%p, %p, %p.\n", iface, in_type, out_type); + + EnterCriticalSection(&renderer->cs); + hr = renderer->current_media_type && IMFMediaType_IsEqual(renderer->current_media_type, in_type, &flags) == S_OK ? + S_OK : MF_E_INVALIDMEDIATYPE; + LeaveCriticalSection(&renderer->cs); + + return hr; } static HRESULT WINAPI audio_renderer_stream_type_handler_GetMediaTypeCount(IMFMediaTypeHandler *iface, DWORD *count) { - FIXME("%p, %p.\n", iface, count); + TRACE("%p, %p.\n", iface, count); - return E_NOTIMPL; + *count = 1; + + return S_OK; } static HRESULT WINAPI audio_renderer_stream_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *iface, DWORD index, IMFMediaType **media_type) { - FIXME("%p, %u, %p.\n", iface, index, media_type); + struct audio_renderer *renderer = impl_from_IMFMediaTypeHandler(iface); - return E_NOTIMPL; + TRACE("%p, %u, %p.\n", iface, index, media_type); + + if (index == 0) + { + *media_type = renderer->media_type; + IMFMediaType_AddRef(*media_type); + } + + return S_OK; } static HRESULT WINAPI audio_renderer_stream_type_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface, IMFMediaType *media_type) { - FIXME("%p, %p.\n", iface, media_type); + struct audio_renderer *renderer = impl_from_IMFMediaTypeHandler(iface); + const unsigned int test_flags = MF_MEDIATYPE_EQUAL_MAJOR_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_TYPES; + unsigned int flags; + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("%p, %p.\n", iface, media_type); + + if (!media_type) + return E_POINTER; + + EnterCriticalSection(&renderer->cs); + if (SUCCEEDED(IMFMediaType_IsEqual(renderer->media_type, media_type, &flags)) && ((flags & test_flags) == test_flags)) + { + if (renderer->current_media_type) + IMFMediaType_Release(renderer->current_media_type); + renderer->current_media_type = media_type; + IMFMediaType_AddRef(renderer->current_media_type); + } + else + hr = MF_E_INVALIDMEDIATYPE; + LeaveCriticalSection(&renderer->cs); + + return hr; } static HRESULT WINAPI audio_renderer_stream_type_handler_GetCurrentMediaType(IMFMediaTypeHandler *iface, IMFMediaType **media_type) { - FIXME("%p, %p.\n", iface, media_type); + struct audio_renderer *renderer = impl_from_IMFMediaTypeHandler(iface); + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("%p, %p.\n", iface, media_type); + + EnterCriticalSection(&renderer->cs); + if (renderer->current_media_type) + { + *media_type = renderer->current_media_type; + IMFMediaType_AddRef(*media_type); + } + else + hr = MF_E_NOT_INITIALIZED; + LeaveCriticalSection(&renderer->cs); + + return hr; } static HRESULT WINAPI audio_renderer_stream_type_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type) @@ -1122,10 +1184,48 @@ static const IMFMediaTypeHandlerVtbl audio_renderer_stream_type_handler_vtbl = audio_renderer_stream_type_handler_GetMajorType, }; +static HRESULT audio_renderer_collect_supported_types(struct audio_renderer *renderer) +{ + IAudioClient *client; + WAVEFORMATEX *format; + HRESULT hr; + + if (FAILED(hr = MFCreateMediaType(&renderer->media_type))) + return hr; + + hr = IMMDevice_Activate(renderer->device, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void **)&client); + if (FAILED(hr)) + { + WARN("Failed to create audio client, hr %#x.\n", hr); + return hr; + } + + /* FIXME: */ + + hr = IAudioClient_GetMixFormat(client, &format); + IAudioClient_Release(client); + if (FAILED(hr)) + { + WARN("Failed to get device audio format, hr %#x.\n", hr); + return hr; + } + + hr = MFInitMediaTypeFromWaveFormatEx(renderer->media_type, format, format->cbSize + sizeof(*format)); + CoTaskMemFree(format); + if (FAILED(hr)) + { + WARN("Failed to initialize media type, hr %#x.\n", hr); + return hr; + } + + IMFMediaType_DeleteItem(renderer->media_type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX); + + return hr; +} + static HRESULT sar_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj) { struct audio_renderer *renderer; - IMMDevice *device; HRESULT hr; TRACE("%p, %p, %p.\n", attributes, user_context, obj); @@ -1152,10 +1252,11 @@ static HRESULT sar_create_object(IMFAttributes *attributes, void *user_context, if (FAILED(hr = MFCreateEventQueue(&renderer->stream_event_queue))) goto failed; - if (FAILED(hr = sar_create_mmdevice(attributes, &device))) + if (FAILED(hr = sar_create_mmdevice(attributes, renderer))) goto failed; - IMMDevice_Release(device); + if (FAILED(hr = audio_renderer_collect_supported_types(renderer))) + goto failed; *obj = (IUnknown *)&renderer->IMFMediaSink_iface; diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 8933ea717c5..511c6a8eb92 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -2722,9 +2722,10 @@ static void test_quality_manager(void) static void test_sar(void) { IMFPresentationClock *present_clock, *present_clock2; + IMFMediaType *mediatype, *mediatype2, *mediatype3; IMFMediaTypeHandler *handler, *handler2; IMFPresentationTimeSource *time_source; - IMFMediaType *mediatype, *mediatype2; + IMFSimpleAudioVolume *simple_volume; IMFClockStateSink *state_sink; IMFMediaSink *sink, *sink2; IMFStreamSink *stream_sink; @@ -2736,6 +2737,7 @@ static void test_sar(void) IUnknown *unk; HRESULT hr; GUID guid; + BOOL mute; hr = CoInitialize(NULL); ok(hr == S_OK, "Failed to initialize, hr %#x.\n", hr); @@ -2865,13 +2867,9 @@ todo_wine count = 0; hr = IMFMediaTypeHandler_GetMediaTypeCount(handler, &count); -todo_wine { ok(hr == S_OK, "Failed to get type count, hr %#x.\n", hr); ok(!!count, "Unexpected type count %u.\n", count); -} -if (SUCCEEDED(hr)) -{ hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &mediatype); ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr); @@ -2879,6 +2877,7 @@ if (SUCCEEDED(hr)) ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr); hr = IMFMediaTypeHandler_IsMediaTypeSupported(handler, mediatype, NULL); +todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#x.\n", hr); IMFMediaType_SetGUID(mediatype, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); @@ -2891,6 +2890,11 @@ if (SUCCEEDED(hr)) hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, 0, &mediatype2); ok(hr == S_OK, "Failed to get media type, hr %#x.\n", hr); + hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, 0, &mediatype3); + ok(hr == S_OK, "Failed to get media type, hr %#x.\n", hr); + ok(mediatype2 == mediatype3, "Unexpected instance.\n"); + IMFMediaType_Release(mediatype3); + hr = IMFMediaTypeHandler_IsMediaTypeSupported(handler, mediatype2, NULL); ok(hr == MF_E_INVALIDMEDIATYPE, "Unexpected hr %#x.\n", hr); @@ -2904,6 +2908,10 @@ if (SUCCEEDED(hr)) ok(mediatype == mediatype2, "Unexpected instance.\n"); IMFMediaType_Release(mediatype); + /* Type is validated against current type. */ + hr = IMFMediaTypeHandler_IsMediaTypeSupported(handler, mediatype2, NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + IMFMediaType_Release(mediatype2); /* Set partial type. */ @@ -2938,13 +2946,18 @@ if (SUCCEEDED(hr)) ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); IMFMediaTypeHandler_Release(handler); -} + IMFStreamSink_Release(stream_sink); /* Volume control */ - hr = MFGetService((IUnknown *)sink, &MR_POLICY_VOLUME_SERVICE, &IID_IMFSimpleAudioVolume, (void **)&unk); + hr = MFGetService((IUnknown *)sink, &MR_POLICY_VOLUME_SERVICE, &IID_IMFSimpleAudioVolume, (void **)&simple_volume); ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr); - IUnknown_Release(unk); + + hr = IMFSimpleAudioVolume_GetMute(simple_volume, &mute); +todo_wine + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + IMFSimpleAudioVolume_Release(simple_volume); hr = MFGetService((IUnknown *)sink, &MR_STREAM_VOLUME_SERVICE, &IID_IMFAudioStreamVolume, (void **)&unk); ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr);