[PATCH 1/5] amstream: Wait for the state transition to complete in AMMultiMediaStream::SetState.

Zebediah Figura zfigura at codeweavers.com
Fri Oct 23 11:12:27 CDT 2020


On 10/22/20 2:06 PM, Anton Baskanov wrote:
> Signed-off-by: Anton Baskanov <baskanov at gmail.com>
> ---
>  dlls/amstream/multimedia.c     |  4 ++
>  dlls/amstream/tests/amstream.c | 84 ++++++++++++++++++++++++++++++++++
>  2 files changed, 88 insertions(+)
> 
> diff --git a/dlls/amstream/multimedia.c b/dlls/amstream/multimedia.c
> index 82ef4822344..967baacb747 100644
> --- a/dlls/amstream/multimedia.c
> +++ b/dlls/amstream/multimedia.c
> @@ -156,7 +156,11 @@ static HRESULT WINAPI multimedia_stream_SetState(IAMMultiMediaStream *iface, STR
>      {
>          hr = IMediaControl_Run(This->media_control);
>          if (SUCCEEDED(hr))
> +        {
> +            FILTER_STATE state;
> +            IMediaControl_GetState(This->media_control, INFINITE, (OAFilterState *)&state);
>              hr = S_OK;
> +        }
>      }
>      else if (new_state == STREAMSTATE_STOP)
>          hr = IMediaControl_Stop(This->media_control);
> diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c
> index b436840e407..cb2b3dd76db 100644
> --- a/dlls/amstream/tests/amstream.c
> +++ b/dlls/amstream/tests/amstream.c
> @@ -924,11 +924,13 @@ struct testfilter
>      LONGLONG current_position;
>      LONGLONG stop_position;
>      const AM_MEDIA_TYPE *preferred_mt;
> +    CONDITION_VARIABLE wait_state_cv;
>      HRESULT get_duration_hr;
>      HRESULT get_stop_position_hr;
>      HRESULT set_positions_hr;
>      HRESULT init_stream_hr;
>      HRESULT cleanup_stream_hr;
> +    HRESULT wait_state_hr;
>  };
>  
>  static inline struct testfilter *impl_from_BaseFilter(struct strmbase_filter *iface)
> @@ -971,12 +973,37 @@ static HRESULT testfilter_cleanup_stream(struct strmbase_filter *iface)
>      return filter->cleanup_stream_hr;
>  }
>  
> +static HRESULT testfilter_wait_state(struct strmbase_filter *iface, DWORD timeout)
> +{
> +    struct testfilter *filter = impl_from_BaseFilter(iface);
> +    DWORD start_time = GetTickCount();
> +    DWORD elapsed = 0;
> +    HRESULT hr;
> +
> +    EnterCriticalSection(&filter->filter.csFilter);

strmbase actually already grabs this.

> +
> +    while (filter->wait_state_hr == VFW_S_STATE_INTERMEDIATE && elapsed < timeout)
> +    {
> +        DWORD sleep_time = timeout - elapsed;
> +        if (!SleepConditionVariableCS(&filter->wait_state_cv, &filter->filter.csFilter, sleep_time))
> +            break;
> +        elapsed = GetTickCount() - start_time;
> +    }

This is fine, though it'd also be fine, and perhaps a little simpler, to
use an event.

(I know I may sound inconsistent. I do think that the usage patterns in
prior patches are ideal for condition variables, where the condition
needs to be rechecked *anyway*, and there may be multiple threads trying
to use the same resource. The fact that condition variables are "fast"
in Wine, at least on some platforms, is also a benefit for
implementation code. Here the usage pattern is a little different, i.e.
much more linear and controlled, so using an event gets a little easier,
and of course speed doesn't matter as much.)

> +
> +    hr = filter->wait_state_hr;
> +
> +    LeaveCriticalSection(&filter->filter.csFilter);
> +
> +    return hr;
> +}
> +
>  static const struct strmbase_filter_ops testfilter_ops =
>  {
>      .filter_get_pin = testfilter_get_pin,
>      .filter_destroy = testfilter_destroy,
>      .filter_init_stream = testfilter_init_stream,
>      .filter_cleanup_stream = testfilter_cleanup_stream,
> +    .filter_wait_state = testfilter_wait_state,
>  };
>  
>  static inline struct testfilter *impl_from_base_pin(struct strmbase_pin *iface)
> @@ -1060,6 +1087,7 @@ static void testfilter_init(struct testfilter *filter)
>      strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops);
>      strmbase_source_init(&filter->source, &filter->filter, L"", &testsource_ops);
>      filter->stop_position = 0x8000000000000000ULL;
> +    InitializeConditionVariable(&filter->wait_state_cv);
>  }
>  
>  static inline struct testfilter *impl_from_IMediaSeeking(IMediaSeeking *iface)
> @@ -2319,11 +2347,25 @@ static void test_initialize(void)
>      IUnknown_Release(graph_inner_unk);
>  }
>  
> +static IAMMultiMediaStream *mmstream_mmstream;
> +static STREAM_STATE mmstream_state;
> +
> +static DWORD CALLBACK mmstream_set_state(void *param)
> +{
> +    HRESULT hr;
> +
> +    hr = IAMMultiMediaStream_SetState(mmstream_mmstream, mmstream_state);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> +    return 0;
> +}
> +
>  static void test_set_state(void)
>  {
>      IAMMultiMediaStream *mmstream = create_ammultimediastream();
>      struct testfilter source;
>      IGraphBuilder *graph;
> +    HANDLE thread;
>      HRESULT hr;
>      ULONG ref;
>  
> @@ -2353,6 +2395,41 @@ static void test_set_state(void)
>      hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
>      ok(hr == S_OK, "Got hr %#x.\n", hr);
>  
> +    source.wait_state_hr = E_FAIL;
> +    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +    source.wait_state_hr = S_OK;
> +    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> +    source.wait_state_hr = VFW_S_STATE_INTERMEDIATE;
> +
> +    mmstream_mmstream = mmstream;
> +    mmstream_state = STREAMSTATE_RUN;
> +    thread = CreateThread(NULL, 0, mmstream_set_state, NULL, 0, NULL);
> +
> +    ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "SetState returned prematurely.\n");
> +
> +    EnterCriticalSection(&source.filter.csFilter);
> +    source.wait_state_hr = S_OK;
> +    WakeAllConditionVariable(&source.wait_state_cv);
> +    LeaveCriticalSection(&source.filter.csFilter);
> +
> +    ok(!WaitForSingleObject(thread, 2000), "Wait timed out.\n");
> +    CloseHandle(thread);
> +
> +    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> +    source.init_stream_hr = E_FAIL;
> +    source.wait_state_hr = VFW_S_STATE_INTERMEDIATE;
> +    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
> +    ok(hr == E_FAIL, "Got hr %#x.\n", hr);
> +    source.init_stream_hr = S_OK;
> +    source.wait_state_hr = S_OK;
> +    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
>      hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
>      ok(hr == S_OK, "Got hr %#x.\n", hr);
>      source.cleanup_stream_hr = E_FAIL;
> @@ -2369,6 +2446,13 @@ static void test_set_state(void)
>      ok(hr == S_FALSE, "Got hr %#x.\n", hr);
>      source.cleanup_stream_hr = S_OK;
>  
> +    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +    source.wait_state_hr = VFW_S_STATE_INTERMEDIATE;
> +    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +    source.wait_state_hr = S_OK;
> +
>      ref = IAMMultiMediaStream_Release(mmstream);
>      ok(!ref, "Got outstanding refcount %d.\n", ref);
>      ref = IGraphBuilder_Release(graph);
> 

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20201023/d930eeb6/attachment-0001.sig>


More information about the wine-devel mailing list