From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/tests/mf.c | 215 +++++++++++++++++++++++++++++++++++--- dlls/mf/tests/resource.rc | 17 +++ 2 files changed, 217 insertions(+), 15 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 11dd143cb55..9142673f2e0 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -1879,17 +1879,20 @@ static IMFAsyncCallback *create_test_callback(BOOL check_media_event) return &callback->IMFAsyncCallback_iface; }
-#define wait_next_media_event(a, b, c, d, e, f) wait_next_media_event_(__LINE__, a, b, c, d, e, f) +#define wait_next_media_event(a, b, c, d, e, f) wait_next_media_event_(__LINE__, a, b, c, d, e, f, FALSE) static HRESULT wait_next_media_event_(int line, IMFMediaSession *session, IMFAsyncCallback *callback, - DWORD timeout, MediaEventType *type, GUID *guid, PROPVARIANT *value) + DWORD timeout, MediaEventType *type, GUID *guid, PROPVARIANT *value, BOOL timed_out) { struct test_callback *impl = impl_from_IMFAsyncCallback(callback); HRESULT hr = S_OK, status; DWORD ret;
- hr = IMFMediaSession_BeginGetEvent(session, &impl->IMFAsyncCallback_iface, (IUnknown *)session); + if (!timed_out) + hr = IMFMediaSession_BeginGetEvent(session, &impl->IMFAsyncCallback_iface, (IUnknown *)session); ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); ret = WaitForSingleObject(impl->event, timeout); + if (ret == WAIT_TIMEOUT) + return WAIT_TIMEOUT; ok_(__FILE__, line)(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", ret); hr = IMFMediaEvent_GetType(impl->media_event, type); ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -1903,9 +1906,9 @@ static HRESULT wait_next_media_event_(int line, IMFMediaSession *session, IMFAsy return status; }
-#define wait_media_event(a, b, c, d, e) wait_media_event_(__LINE__, a, b, c, d, e) +#define wait_media_event(a, b, c, d, e) wait_media_event_(__LINE__, a, b, c, d, e, FALSE) static HRESULT wait_media_event_(int line, IMFMediaSession *session, IMFAsyncCallback *callback, - MediaEventType expect_type, DWORD timeout, PROPVARIANT *value) + MediaEventType expect_type, DWORD timeout, PROPVARIANT *value, BOOL timed_out) { MediaEventType type; HRESULT status; @@ -1914,7 +1917,10 @@ static HRESULT wait_media_event_(int line, IMFMediaSession *session, IMFAsyncCal do { PropVariantClear(value); - status = wait_next_media_event_(line, session, callback, timeout, &type, &guid, value); + status = wait_next_media_event_(line, session, callback, timeout, &type, &guid, value, timed_out); + if (status == WAIT_TIMEOUT) + return status; + timed_out = FALSE; } while (type != expect_type);
ok_(__FILE__, line)(IsEqualGUID(&guid, &GUID_NULL), "got extended type %s\n", debugstr_guid(&guid)); @@ -1997,15 +2003,20 @@ static void test_media_session_events(void) IMFMediaType *input_type, *output_type; IMFTopologyNode *src_node, *sink_node; IMFPresentationDescriptor *pd; + MediaEventType event_type; IMFMediaSession *session; + BOOL selected, timed_out; IMFStreamDescriptor *sd; IMFAsyncResult *result; IMFMediaSource *source; + IMFMediaSink *renderer; + IMFStreamSink *stream; IMFTopology *topology; IMFMediaEvent *event; PROPVARIANT propvar; HRESULT hr; ULONG ref; + GUID guid;
stream_sink.handler = &handler.IMFMediaTypeHandler_iface; stream_sink.media_sink = &media_sink.IMFMediaSink_iface; @@ -2371,20 +2382,14 @@ static void test_media_session_events(void) /* sometimes briefly leaking */ IMFMediaSession_Release(session);
- IMFAsyncCallback_Release(callback); - if (handler.current_type) IMFMediaType_Release(handler.current_type); handler.current_type = NULL;
- hr = IMFTopology_Clear(topology); + hr = IMFTopologyNode_DeleteAllItems(src_node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_DeleteAllItems(sink_node); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ref = IMFTopologyNode_Release(src_node); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopologyNode_Release(sink_node); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopology_Release(topology); - ok(ref == 0, "Release returned %ld\n", ref);
ref = IMFMediaSource_Release(source); ok(ref == 0, "Release returned %ld\n", ref); @@ -2396,6 +2401,186 @@ static void test_media_session_events(void) ok(ref == 0, "Release returned %ld\n", ref);
+ /* MFMediaSource playback */ + + source = create_media_source(L"audiodata.wav", L"audio/wav"); + hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 0, &selected, &sd); + ok(selected, "got selected %u.\n", !!selected); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_source_node(source, -1, src_node, pd, sd); + + hr = MFCreateAudioRenderer(NULL, &renderer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSink_GetStreamSinkByIndex(renderer, 0, &stream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_sink_node(stream, -1, sink_node); + IMFStreamSink_Release(stream); + IMFMediaSink_Release(renderer); + + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar); + hr = wait_media_event(session, callback, MESessionStarted, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + hr = wait_media_event(session, callback, MEEndOfPresentation, 5000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + hr = wait_media_event(session, callback, MESessionEnded, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + + hr = IMFMediaSession_Close(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionClosed, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSource_Shutdown(source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* sometimes briefly leaking */ + IMFMediaSession_Release(session); + IMFMediaSource_Release(source); + IMFPresentationDescriptor_Release(pd); + IMFStreamDescriptor_Release(sd); + + + /* test successive commands */ + + source = create_media_source(L"audiodata.wav", L"audio/wav"); + hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 0, &selected, &sd); + ok(selected, "got selected %u.\n", !!selected); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_source_node(source, -1, src_node, pd, sd); + + hr = MFCreateAudioRenderer(NULL, &renderer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSink_GetStreamSinkByIndex(renderer, 0, &stream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_sink_node(stream, -1, sink_node); + IMFStreamSink_Release(stream); + IMFMediaSink_Release(renderer); + + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_Pause(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_Stop(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar); + hr = wait_media_event(session, callback, MESessionStarted, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + hr = wait_media_event(session, callback, MESessionPaused, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + hr = wait_media_event(session, callback, MESessionStarted, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + hr = wait_media_event(session, callback, MESessionStopped, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + hr = wait_media_event(session, callback, MESessionStarted, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + + /* FIXME: sometimes (rarely) triggers a Wine race condition */ + hr = wait_next_media_event(session, callback, 2000, &event_type, &guid, &propvar); + timed_out = (hr == WAIT_TIMEOUT); + todo_wine_if(timed_out) + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (!timed_out) + { + ok(IsEqualGUID(&guid, &GUID_NULL), "got guid %s\n", debugstr_guid(&guid)); + ok(event_type == MEEndOfPresentation, "got type %lu\n", event_type); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + hr = wait_media_event(session, callback, MESessionEnded, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + } + + hr = IMFMediaSession_Pause(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_(__LINE__, session, callback, MESessionPaused, 1000, &propvar, timed_out); + todo_wine_if(timed_out) + ok(hr == MF_E_SESSION_PAUSEWHILESTOPPED, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + + hr = IMFMediaSession_Close(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionClosed, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSource_Shutdown(source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* sometimes briefly leaking */ + IMFMediaSession_Release(session); + IMFMediaSource_Release(source); + IMFPresentationDescriptor_Release(pd); + IMFStreamDescriptor_Release(sd); + + + hr = IMFTopology_Clear(topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ref = IMFTopologyNode_Release(src_node); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopologyNode_Release(sink_node); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + + /* sometimes briefly leaking */ + IMFAsyncCallback_Release(callback); + hr = MFShutdown(); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); } diff --git a/dlls/mf/tests/resource.rc b/dlls/mf/tests/resource.rc index 25768d21983..e9e13565bf8 100644 --- a/dlls/mf/tests/resource.rc +++ b/dlls/mf/tests/resource.rc @@ -20,9 +20,26 @@
#include "windef.h"
+/* Generated with: + * gst-launch-1.0 audiomixer name=mix ! \ + * audio/x-raw,format=F32LE,rate=22050,channels=2 ! \ + * filesink location=dlls/mf/tests/audiodata.bin \ + * audiotestsrc freq=400 volume=0.2 num-buffers=1 \ + * samplesperbuffer=22050 ! mix. \ + * audiotestsrc freq=600 volume=0.2 num-buffers=1 \ + * samplesperbuffer=22050 timestamp-offset=20000000 ! mix. + */ /* @makedep: audiodata.bin */ audiodata.bin RCDATA audiodata.bin
+/* Generated with: + * gst-launch-1.0 filesrc location=dlls/mf/tests/audiodata.bin num-buffers=10 ! \ + * audio/x-raw,format=F32LE,rate=22050,channels=2,layout=interleaved ! \ + * wavenc ! filesink location=dlls/mf/tests/audiodata.wav + */ +/* @makedep: audiodata.wav */ +audiodata.wav RCDATA audiodata.wav + /* @makedep: audioconvdata.bin */ audioconvdata.bin RCDATA audioconvdata.bin