Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/sar.c | 107 +++++++++++++++++++++++++++++++++++++++++---- dlls/mf/tests/mf.c | 38 +++++++++++++++- 2 files changed, 135 insertions(+), 10 deletions(-)
diff --git a/dlls/mf/sar.c b/dlls/mf/sar.c index 6da66f136a..93ecc6cb47 100644 --- a/dlls/mf/sar.c +++ b/dlls/mf/sar.c @@ -31,6 +31,13 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+enum stream_state +{ + STREAM_STATE_STOPPED = 0, + STREAM_STATE_RUNNING, + STREAM_STATE_PAUSED, +}; + struct audio_renderer { IMFMediaSink IMFMediaSink_iface; @@ -52,6 +59,7 @@ struct audio_renderer IMMDevice *device; IAudioClient *audio_client; HANDLE buffer_ready_event; + enum stream_state state; BOOL is_shut_down; CRITICAL_SECTION cs; }; @@ -500,30 +508,113 @@ static ULONG WINAPI audio_renderer_clock_sink_Release(IMFClockStateSink *iface)
static HRESULT WINAPI audio_renderer_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset) { - FIXME("%p, %s, %s.\n", iface, debugstr_time(systime), debugstr_time(offset)); + struct audio_renderer *renderer = impl_from_IMFClockStateSink(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), debugstr_time(offset)); + + EnterCriticalSection(&renderer->cs); + if (renderer->audio_client) + { + if (renderer->state == STREAM_STATE_STOPPED) + { + if (FAILED(hr = IAudioClient_Start(renderer->audio_client))) + WARN("Failed to start audio client, hr %#x.\n", hr); + renderer->state = STREAM_STATE_RUNNING; + } + } + else + hr = MF_E_NOT_INITIALIZED; + + IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, hr, NULL); + LeaveCriticalSection(&renderer->cs); + + return hr; }
static HRESULT WINAPI audio_renderer_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime) { - FIXME("%p, %s.\n", iface, debugstr_time(systime)); + struct audio_renderer *renderer = impl_from_IMFClockStateSink(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %s.\n", iface, debugstr_time(systime)); + + EnterCriticalSection(&renderer->cs); + if (renderer->audio_client) + { + if (renderer->state != STREAM_STATE_STOPPED) + { + if (SUCCEEDED(hr = IAudioClient_Stop(renderer->audio_client))) + { + if (FAILED(hr = IAudioClient_Reset(renderer->audio_client))) + WARN("Failed to reset audio client, hr %#x.\n", hr); + } + else + WARN("Failed to stop audio client, hr %#x.\n", hr); + renderer->state = STREAM_STATE_STOPPED; + } + } + else + hr = MF_E_NOT_INITIALIZED; + + IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStopped, &GUID_NULL, hr, NULL); + LeaveCriticalSection(&renderer->cs); + + return hr; }
static HRESULT WINAPI audio_renderer_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime) { - FIXME("%p, %s.\n", iface, debugstr_time(systime)); + struct audio_renderer *renderer = impl_from_IMFClockStateSink(iface); + HRESULT hr;
- return E_NOTIMPL; + TRACE("%p, %s.\n", iface, debugstr_time(systime)); + + EnterCriticalSection(&renderer->cs); + if (renderer->state == STREAM_STATE_RUNNING) + { + if (renderer->audio_client) + { + if (FAILED(hr = IAudioClient_Stop(renderer->audio_client))) + WARN("Failed to stop audio client, hr %#x.\n", hr); + renderer->state = STREAM_STATE_PAUSED; + } + else + hr = MF_E_NOT_INITIALIZED; + + IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkPaused, &GUID_NULL, hr, NULL); + } + else + hr = MF_E_INVALID_STATE_TRANSITION; + LeaveCriticalSection(&renderer->cs); + + return hr; }
static HRESULT WINAPI audio_renderer_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime) { - FIXME("%p, %s.\n", iface, debugstr_time(systime)); + struct audio_renderer *renderer = impl_from_IMFClockStateSink(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %s.\n", iface, debugstr_time(systime)); + + EnterCriticalSection(&renderer->cs); + if (renderer->audio_client) + { + if (renderer->state == STREAM_STATE_PAUSED) + { + if (FAILED(hr = IAudioClient_Start(renderer->audio_client))) + WARN("Failed to start audio client, hr %#x.\n", hr); + renderer->state = STREAM_STATE_RUNNING; + } + } + else + hr = MF_E_NOT_INITIALIZED; + + IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, hr, NULL); + LeaveCriticalSection(&renderer->cs); + + return hr; }
static HRESULT WINAPI audio_renderer_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 511c6a8eb9..f95d088c5c 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -2811,9 +2811,13 @@ if (SUCCEEDED(hr)) IUnknown_Release(unk);
/* Clock */ - hr = IMFMediaSink_QueryInterface(sink, &IID_IMFClockStateSink, (void **)&unk); + hr = IMFMediaSink_QueryInterface(sink, &IID_IMFClockStateSink, (void **)&state_sink); ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr); - IUnknown_Release(unk); + + hr = IMFClockStateSink_OnClockStart(state_sink, 0, 0); + ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr); + + IMFClockStateSink_Release(state_sink);
hr = IMFMediaSink_SetPresentationClock(sink, NULL); ok(hr == S_OK, "Unexpected hr %#x.\n", hr); @@ -2947,6 +2951,36 @@ todo_wine
IMFMediaTypeHandler_Release(handler);
+ /* State change with initialized stream. */ + hr = IMFMediaSink_QueryInterface(sink, &IID_IMFClockStateSink, (void **)&state_sink); + ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr); + + hr = IMFClockStateSink_OnClockStart(state_sink, 0, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFClockStateSink_OnClockStart(state_sink, 0, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFClockStateSink_OnClockPause(state_sink, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFClockStateSink_OnClockStop(state_sink, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFClockStateSink_OnClockStop(state_sink, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFClockStateSink_OnClockPause(state_sink, 0); + ok(hr == MF_E_INVALID_STATE_TRANSITION, "Unexpected hr %#x.\n", hr); + + hr = IMFClockStateSink_OnClockRestart(state_sink, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFClockStateSink_OnClockRestart(state_sink, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + IMFClockStateSink_Release(state_sink); + IMFStreamSink_Release(stream_sink);
/* Volume control */