From d81bb88366c8ab340b6159b3f905b2ad4be6c940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Tue, 7 Jun 2022 21:59:32 +0200 Subject: [PATCH] windows.media.speech: Add stub ISpeechSynthesisStream iface. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on a patch by Connor McAdams Silences a warning about narrator being broken in Forza Horizon 5. Signed-off-by: Bernhard Kölbl --- dlls/windows.media.speech/synthesizer.c | 142 ++++++++++++++++++++++- dlls/windows.media.speech/tests/speech.c | 37 +++--- 2 files changed, 153 insertions(+), 26 deletions(-) diff --git a/dlls/windows.media.speech/synthesizer.c b/dlls/windows.media.speech/synthesizer.c index 7e1d19cb4c1..ce257c7c355 100644 --- a/dlls/windows.media.speech/synthesizer.c +++ b/dlls/windows.media.speech/synthesizer.c @@ -146,6 +146,140 @@ static struct voice_information_vector all_voices = 0 }; +/* + * + * ISpeechSynthesisStream + * + */ + +struct synthesis_stream +{ + ISpeechSynthesisStream ISpeechSynthesisStream_iface; + LONG ref; + + IVector_IMediaMarker *markers; +}; + +static inline struct synthesis_stream *impl_from_ISpeechSynthesisStream( ISpeechSynthesisStream *iface ) +{ + return CONTAINING_RECORD(iface, struct synthesis_stream, ISpeechSynthesisStream_iface); +} + +HRESULT WINAPI synthesis_stream_QueryInterface( ISpeechSynthesisStream *iface, REFIID iid, void **out ) +{ + struct synthesis_stream *impl = impl_from_ISpeechSynthesisStream(iface); + + TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_IAgileObject) || + IsEqualGUID(iid, &IID_ISpeechSynthesisStream)) + { + IInspectable_AddRef((*out = &impl->ISpeechSynthesisStream_iface)); + return S_OK; + } + + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +ULONG WINAPI synthesis_stream_AddRef( ISpeechSynthesisStream *iface ) +{ + struct synthesis_stream *impl = impl_from_ISpeechSynthesisStream(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + return ref; +} + +ULONG WINAPI synthesis_stream_Release( ISpeechSynthesisStream *iface ) +{ + struct synthesis_stream *impl = impl_from_ISpeechSynthesisStream(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + + TRACE("iface %p, ref %lu.\n", iface, ref); + + if (!ref) + free(impl); + + return ref; +} + +HRESULT WINAPI synthesis_stream_GetIids( ISpeechSynthesisStream *iface, ULONG *iid_count, IID **iids ) +{ + FIXME("iface %p, iid_count %p, iids %p stub.\n", iface, iid_count, iids); + return E_NOTIMPL; +} + +HRESULT WINAPI synthesis_stream_GetRuntimeClassName( ISpeechSynthesisStream *iface, HSTRING *class_name ) +{ + FIXME("iface %p, class_name %p stub.\n", iface, class_name); + return E_NOTIMPL; +} + +HRESULT WINAPI synthesis_stream_GetTrustLevel( ISpeechSynthesisStream *iface, TrustLevel *trust_level ) +{ + FIXME("iface %p, trust_level %p stub.\n", iface, trust_level); + return E_NOTIMPL; +} + +HRESULT WINAPI synthesis_stream_get_Markers( ISpeechSynthesisStream *iface, IVectorView_IMediaMarker **value ) +{ + struct synthesis_stream *impl = impl_from_ISpeechSynthesisStream(iface); + FIXME("iface %p, value %p stub!\n", iface, value); + return IVector_IMediaMarker_GetView(impl->markers, value); +} + +static const struct ISpeechSynthesisStreamVtbl synthesis_stream_vtbl = +{ + /* IUnknown methods */ + synthesis_stream_QueryInterface, + synthesis_stream_AddRef, + synthesis_stream_Release, + /* IInspectable methods */ + synthesis_stream_GetIids, + synthesis_stream_GetRuntimeClassName, + synthesis_stream_GetTrustLevel, + /* ISpeechSynthesisStream methods */ + synthesis_stream_get_Markers +}; + + +static HRESULT synthesis_stream_create( ISpeechSynthesisStream **out ) +{ + struct synthesis_stream *impl; + struct vector_iids markers_iids = + { + .iterable = &IID_IIterable_IMediaMarker, + .iterator = &IID_IIterator_IMediaMarker, + .vector = &IID_IVector_IMediaMarker, + .view = &IID_IVectorView_IMediaMarker, + }; + HRESULT hr; + + TRACE("out %p.\n", out); + + if (!(impl = calloc(1, sizeof(*impl)))) + { + *out = NULL; + return E_OUTOFMEMORY; + } + + impl->ISpeechSynthesisStream_iface.lpVtbl = &synthesis_stream_vtbl; + impl->ref = 1; + if (FAILED(hr = vector_inspectable_create(&markers_iids, (IVector_IInspectable**)&impl->markers))) + goto error; + + TRACE("created ISpeechSynthesisStream %p.\n", impl); + *out = &impl->ISpeechSynthesisStream_iface; + return S_OK; + +error: + free(impl); + return hr; +} + /* * * SpeechSynthesizer runtimeclass @@ -243,26 +377,26 @@ static HRESULT WINAPI synthesizer_GetTrustLevel( ISpeechSynthesizer *iface, Trus static HRESULT CALLBACK text_to_stream_operation( IInspectable *invoker, IInspectable **result ) { - return S_OK; + return synthesis_stream_create((ISpeechSynthesisStream **)result); } static HRESULT WINAPI synthesizer_SynthesizeTextToStreamAsync( ISpeechSynthesizer *iface, HSTRING text, IAsyncOperation_SpeechSynthesisStream **operation ) { - FIXME("iface %p, text %p, operation %p stub.\n", iface, text, operation); + TRACE("iface %p, text %p, operation %p.\n", iface, text, operation); return async_operation_inspectable_create(&IID_IAsyncOperation_SpeechSynthesisStream, NULL, text_to_stream_operation, (IAsyncOperation_IInspectable **)operation); } static HRESULT CALLBACK ssml_to_stream_operation( IInspectable *invoker, IInspectable **result ) { - return S_OK; + return synthesis_stream_create((ISpeechSynthesisStream **)result); } static HRESULT WINAPI synthesizer_SynthesizeSsmlToStreamAsync( ISpeechSynthesizer *iface, HSTRING ssml, IAsyncOperation_SpeechSynthesisStream **operation ) { - FIXME("iface %p, text %p, operation %p stub.\n", iface, ssml, operation); + TRACE("iface %p, ssml %p, operation %p.\n", iface, ssml, operation); return async_operation_inspectable_create(&IID_IAsyncOperation_SpeechSynthesisStream, NULL, ssml_to_stream_operation, (IAsyncOperation_IInspectable **)operation); } diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index bea3c5104b1..0d67c8b7cdb 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -947,22 +947,19 @@ static void test_SpeechSynthesizer(void) check_interface(operation_ss_stream, &IID_IAgileObject, TRUE); hr = IAsyncOperation_SpeechSynthesisStream_GetResults(operation_ss_stream, &ss_stream); - todo_wine ok(hr == S_OK, "IAsyncOperation_SpeechSynthesisStream_GetResults failed, hr %#lx\n", hr); + ok(hr == S_OK, "IAsyncOperation_SpeechSynthesisStream_GetResults failed, hr %#lx\n", hr); - if (hr == S_OK) - { - hr = ISpeechSynthesisStream_get_Markers(ss_stream, &media_markers); - todo_wine ok(hr == S_OK, "ISpeechSynthesisStream_get_Markers failed, hr %#lx\n", hr); - check_interface(media_markers, &IID_IVectorView_IMediaMarker, TRUE); - check_interface(media_markers, &IID_IIterable_IMediaMarker, TRUE); - check_interface(media_markers, &IID_IAgileObject, TRUE); + hr = ISpeechSynthesisStream_get_Markers(ss_stream, &media_markers); + ok(hr == S_OK, "ISpeechSynthesisStream_get_Markers failed, hr %#lx\n", hr); + check_interface(media_markers, &IID_IVectorView_IMediaMarker, TRUE); + check_interface(media_markers, &IID_IIterable_IMediaMarker, TRUE); + check_interface(media_markers, &IID_IAgileObject, TRUE); - ref = IVectorView_IMediaMarker_Release(media_markers); - todo_wine ok(ref == 0, "Got unexpected ref %lu.\n", ref); + ref = IVectorView_IMediaMarker_Release(media_markers); + ok(ref == 0, "Got unexpected ref %lu.\n", ref); - ref = ISpeechSynthesisStream_Release(ss_stream); - todo_wine ok(ref == 0, "Got unexpected ref %lu.\n", ref); - } + ref = ISpeechSynthesisStream_Release(ss_stream); + ok(ref == 0, "Got unexpected ref %lu.\n", ref); IAsyncOperation_SpeechSynthesisStream_Release(operation_ss_stream); @@ -981,16 +978,12 @@ static void test_SpeechSynthesizer(void) check_interface(operation_ss_stream, &IID_IAgileObject, TRUE); hr = IAsyncOperation_SpeechSynthesisStream_GetResults(operation_ss_stream, &ss_stream); - todo_wine ok(hr == S_OK, "IAsyncOperation_SpeechSynthesisStream_GetResults failed, hr %#lx\n", hr); + ok(hr == S_OK, "IAsyncOperation_SpeechSynthesisStream_GetResults failed, hr %#lx\n", hr); + check_interface(ss_stream, &IID_ISpeechSynthesisStream, TRUE); + check_interface(ss_stream, &IID_IAgileObject, TRUE); - if (hr == S_OK) - { - check_interface(ss_stream, &IID_ISpeechSynthesisStream, TRUE); - check_interface(ss_stream, &IID_IAgileObject, TRUE); - - ref = ISpeechSynthesisStream_Release(ss_stream); - ok(ref == 0, "Got unexpected ref %lu.\n", ref); - } + ref = ISpeechSynthesisStream_Release(ss_stream); + ok(ref == 0, "Got unexpected ref %lu.\n", ref); IAsyncOperation_SpeechSynthesisStream_Release(operation_ss_stream);