[PATCH 3/6] amstream: Implement AMAudioStream::EndOfStream.
Zebediah Figura
zfigura at codeweavers.com
Sun Apr 19 17:12:10 CDT 2020
On 4/18/20 9:34 AM, Anton Baskanov wrote:
> Signed-off-by: Anton Baskanov <baskanov at gmail.com>
> ---
> dlls/amstream/audiostream.c | 66 ++++++++++++++++++++++-
> dlls/amstream/tests/amstream.c | 99 ++++++++++++++++++++++++++++++++--
> 2 files changed, 159 insertions(+), 6 deletions(-)
>
> diff --git a/dlls/amstream/audiostream.c b/dlls/amstream/audiostream.c
> index 26d615ebf4..81cd2975c8 100644
> --- a/dlls/amstream/audiostream.c
> +++ b/dlls/amstream/audiostream.c
> @@ -166,6 +166,17 @@ static HRESULT audiostreamsample_create(IAudioMediaStream *parent, IAudioData *a
> return S_OK;
> }
>
> +enum queued_event_type
> +{
> + QET_END_OF_STREAM
> +};
> +
> +struct queued_event
> +{
> + struct list entry;
> + enum queued_event_type type;
> +};
> +
> struct audio_stream
> {
> IAMMediaStream IAMMediaStream_iface;
> @@ -185,8 +196,27 @@ struct audio_stream
> AM_MEDIA_TYPE mt;
> WAVEFORMATEX format;
> FILTER_STATE state;
> + BOOL eos;
> + struct list event_queue;
> };
>
> +static void remove_queued_event(struct queued_event *event)
> +{
> + list_remove(&event->entry);
> + HeapFree(GetProcessHeap(), 0, event);
> +}
> +
> +static void flush_event_queue(struct audio_stream *stream)
> +{
> + while (!list_empty(&stream->event_queue))
> + {
> + struct queued_event *event =
> + LIST_ENTRY(list_head(&stream->event_queue), struct queued_event, entry);
> +
> + remove_queued_event(event);
> + }
> +}
> +
> static inline struct audio_stream *impl_from_IAMMediaStream(IAMMediaStream *iface)
> {
> return CONTAINING_RECORD(iface, struct audio_stream, IAMMediaStream_iface);
> @@ -347,6 +377,11 @@ static HRESULT WINAPI audio_IAMMediaStream_SetState(IAMMediaStream *iface, FILTE
>
> EnterCriticalSection(&This->cs);
>
> + if (State_Stopped == state)
> + flush_event_queue(This);
> + if (State_Stopped == This->state)
> + This->eos = FALSE;
This works, but it feels a little clearer to me to have
if (state == State_Stopped)
{
flush_event_queue(This);
This->eos = FALSE;
}
> This->state = state;
>
> LeaveCriticalSection(&This->cs);
> @@ -919,8 +954,34 @@ static HRESULT WINAPI audio_sink_QueryInternalConnections(IPin *iface, IPin **pi
>
> static HRESULT WINAPI audio_sink_EndOfStream(IPin *iface)
> {
> - FIXME("iface %p, stub!\n", iface);
> - return E_NOTIMPL;
> + struct audio_stream *stream = impl_from_IPin(iface);
> + struct queued_event *event;
> +
> + TRACE("(%p/%p)->()\n", iface, stream);
> +
> + EnterCriticalSection(&stream->cs);
> +
> + if (stream->eos)
> + {
> + LeaveCriticalSection(&stream->cs);
> + return E_FAIL;
> + }
> +
> + event = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*event));
amstream is compiled with msvcrt, so this can be calloc().
> + if (!event)
> + {
> + LeaveCriticalSection(&stream->cs);
> + return E_OUTOFMEMORY;
> + }
> +
> + event->type = QET_END_OF_STREAM;
> + list_add_tail(&stream->event_queue, &event->entry);
> +
> + stream->eos = TRUE;
> +
> + LeaveCriticalSection(&stream->cs);
> +
> + return S_OK;
> }
>
> static HRESULT WINAPI audio_sink_BeginFlush(IPin *iface)
> @@ -1083,6 +1144,7 @@ HRESULT audio_stream_create(IMultiMediaStream *parent, const MSPID *purpose_id,
> object->parent = parent;
> object->purpose_id = *purpose_id;
> object->stream_type = stream_type;
> + list_init(&object->event_queue);
>
> *media_stream = &object->IAMMediaStream_iface;
>
> diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c
> index 472c6558fc..2ac492bc3c 100644
> --- a/dlls/amstream/tests/amstream.c
> +++ b/dlls/amstream/tests/amstream.c
> @@ -2381,10 +2381,21 @@ static HRESULT testsource_query_accept(struct strmbase_pin *iface, const AM_MEDI
> return S_OK;
> }
>
> -static HRESULT WINAPI testsource_DecideAllocator(struct strmbase_source *iface,
> - IMemInputPin *peer, IMemAllocator **allocator)
> +static HRESULT WINAPI testsource_decide_buffer_size(struct strmbase_source *iface,
> + IMemAllocator *alloc, ALLOCATOR_PROPERTIES *requested)
> {
> - return S_OK;
> + ALLOCATOR_PROPERTIES actual;
> +
> + if (!requested->cbAlign)
> + requested->cbAlign = 1;
> +
> + if (requested->cbBuffer < 4096)
> + requested->cbBuffer = 4096;
> +
> + if (!requested->cBuffers)
> + requested->cBuffers = 2;
> +
> + return IMemAllocator_SetProperties(alloc, requested, &actual);
> }
>
> static const struct strmbase_source_ops testsource_ops =
> @@ -2392,7 +2403,8 @@ static const struct strmbase_source_ops testsource_ops =
> .base.pin_query_accept = testsource_query_accept,
> .base.pin_get_media_type = strmbase_pin_get_media_type,
> .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
> - .pfnDecideAllocator = testsource_DecideAllocator,
> + .pfnDecideBufferSize = testsource_decide_buffer_size,
> + .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator,
> };
>
> static void testfilter_init(struct testfilter *filter)
> @@ -2814,6 +2826,84 @@ static void test_audiostream_set_state(void)
> ok(!ref, "Got outstanding refcount %d.\n", ref);
> }
>
> +void test_audiostream_end_of_stream(void)
> +{
> + static const WAVEFORMATEX format =
> + {
> + .wFormatTag = WAVE_FORMAT_PCM,
> + .nChannels = 1,
> + .nSamplesPerSec = 11025,
> + .wBitsPerSample = 16,
> + .nBlockAlign = 2,
> + .nAvgBytesPerSec = 2 * 11025,
> + };
> +
> + const AM_MEDIA_TYPE mt =
> + {
> + .majortype = MEDIATYPE_Audio,
> + .subtype = MEDIASUBTYPE_PCM,
> + .formattype = FORMAT_WaveFormatEx,
> + .cbFormat = sizeof(WAVEFORMATEX),
> + .pbFormat = (BYTE *)&format,
> + };
> +
> + IAMMultiMediaStream *mmstream = create_ammultimediastream();
> + struct testfilter source;
> + IGraphBuilder *graph;
> + IMediaStream *stream;
> + HRESULT hr;
> + ULONG ref;
> + IPin *pin;
> +
> + hr = IAMMultiMediaStream_Initialize(mmstream, STREAMTYPE_READ, 0, NULL);
> + ok(hr == S_OK, "Got hr %#x.\n", hr);
> + hr = IAMMultiMediaStream_AddMediaStream(mmstream, NULL, &MSPID_PrimaryAudio, 0, &stream);
> + ok(hr == S_OK, "Got hr %#x.\n", hr);
> + hr = IMediaStream_QueryInterface(stream, &IID_IPin, (void **)&pin);
> + ok(hr == S_OK, "Got hr %#x.\n", hr);
> + hr = IAMMultiMediaStream_GetFilterGraph(mmstream, &graph);
> + ok(hr == S_OK, "Got hr %#x.\n", hr);
> + ok(graph != NULL, "Expected non-null graph\n");
> + testfilter_init(&source);
> + hr = IGraphBuilder_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL);
> + ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> + hr = IGraphBuilder_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &mt);
> + ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> + hr = IPin_EndOfStream(pin);
> + ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> + hr = IPin_EndOfStream(pin);
> + ok(hr == E_FAIL, "Got hr %#x.\n", hr);
> +
> + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
> + ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> + hr = IPin_EndOfStream(pin);
> + ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> + hr = IPin_EndOfStream(pin);
> + ok(hr == E_FAIL, "Got hr %#x.\n", hr);
> +
> + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
> + ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> + hr = IPin_EndOfStream(pin);
> + ok(hr == E_FAIL, "Got hr %#x.\n", hr);
> +
> + IGraphBuilder_Disconnect(graph, pin);
> + IGraphBuilder_Disconnect(graph, &source.source.pin.IPin_iface);
> +
> + ref = IAMMultiMediaStream_Release(mmstream);
> + ok(!ref, "Got outstanding refcount %d.\n", ref);
> + ref = IGraphBuilder_Release(graph);
> + ok(!ref, "Got outstanding refcount %d.\n", ref);
> + IPin_Release(pin);
> + ref = IMediaStream_Release(stream);
> + ok(!ref, "Got outstanding refcount %d.\n", ref);
> +}
> +
> void test_mediastreamfilter_get_state(void)
> {
> IAMMultiMediaStream *mmstream = create_ammultimediastream();
> @@ -2986,6 +3076,7 @@ START_TEST(amstream)
> test_audiostream_set_format();
> test_audiostream_receive_connection();
> test_audiostream_set_state();
> + test_audiostream_end_of_stream();
>
> test_mediastreamfilter_get_state();
> test_mediastreamfilter_stop_pause_run();
>
More information about the wine-devel
mailing list