mf: Add initial implementation of SAR stream type handler.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2020-04-20 19:24:59 +03:00 committed by Alexandre Julliard
parent 198fa490a4
commit d2c736e1ba
2 changed files with 138 additions and 24 deletions

View File

@ -24,6 +24,7 @@
#include "mf_private.h" #include "mf_private.h"
#include "initguid.h" #include "initguid.h"
#include "mmdeviceapi.h" #include "mmdeviceapi.h"
#include "audioclient.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/heap.h" #include "wine/heap.h"
@ -46,6 +47,9 @@ struct audio_renderer
IMFMediaEventQueue *event_queue; IMFMediaEventQueue *event_queue;
IMFMediaEventQueue *stream_event_queue; IMFMediaEventQueue *stream_event_queue;
IMFPresentationClock *clock; IMFPresentationClock *clock;
IMFMediaType *media_type;
IMFMediaType *current_media_type;
IMMDevice *device;
BOOL is_shut_down; BOOL is_shut_down;
CRITICAL_SECTION cs; CRITICAL_SECTION cs;
}; };
@ -162,6 +166,12 @@ static ULONG WINAPI audio_renderer_sink_Release(IMFMediaSink *iface)
IMFMediaEventQueue_Release(renderer->stream_event_queue); IMFMediaEventQueue_Release(renderer->stream_event_queue);
if (renderer->clock) if (renderer->clock)
IMFPresentationClock_Release(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); DeleteCriticalSection(&renderer->cs);
heap_free(renderer); heap_free(renderer);
} }
@ -814,7 +824,7 @@ static const IMFAudioPolicyVtbl audio_renderer_policy_vtbl =
audio_renderer_policy_GetIconPath, 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; WCHAR *endpoint;
unsigned int length, role = eMultimedia; unsigned int length, role = eMultimedia;
@ -845,11 +855,11 @@ static HRESULT sar_create_mmdevice(IMFAttributes *attributes, IMMDevice **device
&endpoint, &length))) &endpoint, &length)))
{ {
TRACE("Specified end point %s.\n", debugstr_w(endpoint)); TRACE("Specified end point %s.\n", debugstr_w(endpoint));
hr = IMMDeviceEnumerator_GetDevice(devenum, endpoint, device); hr = IMMDeviceEnumerator_GetDevice(devenum, endpoint, &renderer->device);
CoTaskMemFree(endpoint); CoTaskMemFree(endpoint);
} }
else else
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, eRender, role, device); hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, eRender, role, &renderer->device);
if (FAILED(hr)) if (FAILED(hr))
hr = MF_E_NO_AUDIO_PLAYBACK_DEVICE; 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, static HRESULT WINAPI audio_renderer_stream_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler *iface,
IMFMediaType *in_type, IMFMediaType **out_type) 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) 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, static HRESULT WINAPI audio_renderer_stream_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *iface, DWORD index,
IMFMediaType **media_type) 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, static HRESULT WINAPI audio_renderer_stream_type_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface,
IMFMediaType *media_type) 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, static HRESULT WINAPI audio_renderer_stream_type_handler_GetCurrentMediaType(IMFMediaTypeHandler *iface,
IMFMediaType **media_type) 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) 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, 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) static HRESULT sar_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj)
{ {
struct audio_renderer *renderer; struct audio_renderer *renderer;
IMMDevice *device;
HRESULT hr; HRESULT hr;
TRACE("%p, %p, %p.\n", attributes, user_context, obj); 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))) if (FAILED(hr = MFCreateEventQueue(&renderer->stream_event_queue)))
goto failed; goto failed;
if (FAILED(hr = sar_create_mmdevice(attributes, &device))) if (FAILED(hr = sar_create_mmdevice(attributes, renderer)))
goto failed; goto failed;
IMMDevice_Release(device); if (FAILED(hr = audio_renderer_collect_supported_types(renderer)))
goto failed;
*obj = (IUnknown *)&renderer->IMFMediaSink_iface; *obj = (IUnknown *)&renderer->IMFMediaSink_iface;

View File

@ -2722,9 +2722,10 @@ static void test_quality_manager(void)
static void test_sar(void) static void test_sar(void)
{ {
IMFPresentationClock *present_clock, *present_clock2; IMFPresentationClock *present_clock, *present_clock2;
IMFMediaType *mediatype, *mediatype2, *mediatype3;
IMFMediaTypeHandler *handler, *handler2; IMFMediaTypeHandler *handler, *handler2;
IMFPresentationTimeSource *time_source; IMFPresentationTimeSource *time_source;
IMFMediaType *mediatype, *mediatype2; IMFSimpleAudioVolume *simple_volume;
IMFClockStateSink *state_sink; IMFClockStateSink *state_sink;
IMFMediaSink *sink, *sink2; IMFMediaSink *sink, *sink2;
IMFStreamSink *stream_sink; IMFStreamSink *stream_sink;
@ -2736,6 +2737,7 @@ static void test_sar(void)
IUnknown *unk; IUnknown *unk;
HRESULT hr; HRESULT hr;
GUID guid; GUID guid;
BOOL mute;
hr = CoInitialize(NULL); hr = CoInitialize(NULL);
ok(hr == S_OK, "Failed to initialize, hr %#x.\n", hr); ok(hr == S_OK, "Failed to initialize, hr %#x.\n", hr);
@ -2865,13 +2867,9 @@ todo_wine
count = 0; count = 0;
hr = IMFMediaTypeHandler_GetMediaTypeCount(handler, &count); hr = IMFMediaTypeHandler_GetMediaTypeCount(handler, &count);
todo_wine {
ok(hr == S_OK, "Failed to get type count, hr %#x.\n", hr); ok(hr == S_OK, "Failed to get type count, hr %#x.\n", hr);
ok(!!count, "Unexpected type count %u.\n", count); ok(!!count, "Unexpected type count %u.\n", count);
}
if (SUCCEEDED(hr))
{
hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &mediatype); hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &mediatype);
ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr); 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); ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr);
hr = IMFMediaTypeHandler_IsMediaTypeSupported(handler, mediatype, NULL); hr = IMFMediaTypeHandler_IsMediaTypeSupported(handler, mediatype, NULL);
todo_wine
ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#x.\n", hr); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#x.\n", hr);
IMFMediaType_SetGUID(mediatype, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); IMFMediaType_SetGUID(mediatype, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
@ -2891,6 +2890,11 @@ if (SUCCEEDED(hr))
hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, 0, &mediatype2); hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, 0, &mediatype2);
ok(hr == S_OK, "Failed to get media type, hr %#x.\n", hr); 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); hr = IMFMediaTypeHandler_IsMediaTypeSupported(handler, mediatype2, NULL);
ok(hr == MF_E_INVALIDMEDIATYPE, "Unexpected hr %#x.\n", hr); ok(hr == MF_E_INVALIDMEDIATYPE, "Unexpected hr %#x.\n", hr);
@ -2904,6 +2908,10 @@ if (SUCCEEDED(hr))
ok(mediatype == mediatype2, "Unexpected instance.\n"); ok(mediatype == mediatype2, "Unexpected instance.\n");
IMFMediaType_Release(mediatype); 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); IMFMediaType_Release(mediatype2);
/* Set partial type. */ /* Set partial type. */
@ -2938,13 +2946,18 @@ if (SUCCEEDED(hr))
ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
IMFMediaTypeHandler_Release(handler); IMFMediaTypeHandler_Release(handler);
}
IMFStreamSink_Release(stream_sink); IMFStreamSink_Release(stream_sink);
/* Volume control */ /* 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); 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); hr = MFGetService((IUnknown *)sink, &MR_STREAM_VOLUME_SERVICE, &IID_IMFAudioStreamVolume, (void **)&unk);
ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr); ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr);