 
            From: Paul Gofman pgofman@codeweavers.com
--- dlls/windows.media.speech/private.h | 1 + dlls/windows.media.speech/synthesizer.c | 153 ++++++++++++++++++++++- dlls/windows.media.speech/tests/speech.c | 7 +- 3 files changed, 159 insertions(+), 2 deletions(-)
diff --git a/dlls/windows.media.speech/private.h b/dlls/windows.media.speech/private.h index fb5b936fb01..e7921370f11 100644 --- a/dlls/windows.media.speech/private.h +++ b/dlls/windows.media.speech/private.h @@ -33,6 +33,7 @@
#define WIDL_using_Windows_Foundation #define WIDL_using_Windows_Foundation_Collections +#define WIDL_using_Windows_Storage_Streams #include "windows.foundation.h" #define WIDL_using_Windows_Globalization #include "windows.globalization.h" diff --git a/dlls/windows.media.speech/synthesizer.c b/dlls/windows.media.speech/synthesizer.c index 80968333c8a..c2bed2e45b9 100644 --- a/dlls/windows.media.speech/synthesizer.c +++ b/dlls/windows.media.speech/synthesizer.c @@ -151,10 +151,10 @@ static struct voice_information_vector all_voices = * ISpeechSynthesisStream * */ - struct synthesis_stream { ISpeechSynthesisStream ISpeechSynthesisStream_iface; + IRandomAccessStream IRandomAccessStream_iface; LONG ref;
IVector_IMediaMarker *markers; @@ -180,6 +180,13 @@ HRESULT WINAPI synthesis_stream_QueryInterface( ISpeechSynthesisStream *iface, R return S_OK; }
+ if (IsEqualGUID(iid, &IID_IRandomAccessStream)) + { + IRandomAccessStream_AddRef(&impl->IRandomAccessStream_iface); + *out = &impl->IRandomAccessStream_iface; + return S_OK; + } + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); *out = NULL; return E_NOINTERFACE; @@ -246,6 +253,149 @@ static const struct ISpeechSynthesisStreamVtbl synthesis_stream_vtbl = };
+static inline struct synthesis_stream *impl_from_IRandomAccessStream( IRandomAccessStream *iface ) +{ + return CONTAINING_RECORD(iface, struct synthesis_stream, IRandomAccessStream_iface); +} + +static HRESULT WINAPI synthesis_stream_random_access_QueryInterface( IRandomAccessStream *iface, REFIID iid, void **out ) +{ + struct synthesis_stream *impl = impl_from_IRandomAccessStream(iface); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out ); + + return ISpeechSynthesisStream_QueryInterface( &impl->ISpeechSynthesisStream_iface, iid, out ); +} + +static ULONG WINAPI synthesis_stream_random_access_AddRef( IRandomAccessStream *iface ) +{ + struct synthesis_stream *impl = impl_from_IRandomAccessStream(iface); + + TRACE( "iface %p.\n", iface ); + return ISpeechSynthesisStream_AddRef( &impl->ISpeechSynthesisStream_iface ); +} + +static ULONG WINAPI synthesis_stream_random_access_Release( IRandomAccessStream *iface ) +{ + struct synthesis_stream *impl = impl_from_IRandomAccessStream(iface); + + TRACE( "iface %p.\n", iface ); + return ISpeechSynthesisStream_Release( &impl->ISpeechSynthesisStream_iface ); +} + +static HRESULT WINAPI synthesis_stream_random_access_GetIids( IRandomAccessStream *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub.\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI synthesis_stream_random_access_GetRuntimeClassName( IRandomAccessStream *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub.\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI synthesis_stream_random_access_GetTrustLevel( IRandomAccessStream *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub.\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI synthesis_stream_random_access_get_Size( IRandomAccessStream *iface, UINT64 *value ) +{ + FIXME( "iface %p, value %p stub.\n", iface, value ); + + *value = 0; + return S_OK; +} + +static HRESULT WINAPI synthesis_stream_random_access_put_Size( IRandomAccessStream *iface, UINT64 value ) +{ + FIXME( "iface %p, value %I64u stub.\n", iface, value ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI synthesis_stream_random_access_GetInputStreamAt( IRandomAccessStream *iface, UINT64 position, + IInputStream **stream ) +{ + FIXME( "iface %p, position %I64u, stream %p stub.\n", iface, position, stream ); + + *stream = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI synthesis_stream_random_access_GetOutputStreamAt( IRandomAccessStream *iface, UINT64 position, + IOutputStream **stream ) +{ + FIXME( "iface %p, position %I64u, stream %p stub.\n", iface, position, stream ); + + *stream = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI synthesis_stream_random_access_get_Position( IRandomAccessStream *iface, UINT64 *value ) +{ + FIXME( "iface %p, value %p stub.\n", iface, value ); + + *value = 0; + return E_NOTIMPL; +} + +static HRESULT WINAPI synthesis_stream_random_access_Seek( IRandomAccessStream *iface, UINT64 position ) +{ + FIXME( "iface %p, position %I64u stub.\n", iface, position ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI synthesis_stream_random_access_CloneStream( IRandomAccessStream *iface, IRandomAccessStream **stream ) +{ + FIXME( "iface %p, stream %p stub.\n", iface, stream ); + + *stream = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI synthesis_stream_random_access_get_CanRead( IRandomAccessStream *iface, BOOLEAN *value ) +{ + FIXME( "iface %p, value %p stub.\n", iface, value ); + + *value = FALSE; + return E_NOTIMPL; +} + +static HRESULT WINAPI synthesis_stream_random_access_get_CanWrite( IRandomAccessStream *iface, BOOLEAN *value ) +{ + FIXME( "iface %p, value %p stub.\n", iface, value ); + + *value = FALSE; + return E_NOTIMPL; +} + +static const struct IRandomAccessStreamVtbl synthesis_stream_random_access_vtbl = +{ + /* IUnknown methods */ + synthesis_stream_random_access_QueryInterface, + synthesis_stream_random_access_AddRef, + synthesis_stream_random_access_Release, + /* IInspectable methods */ + synthesis_stream_random_access_GetIids, + synthesis_stream_random_access_GetRuntimeClassName, + synthesis_stream_random_access_GetTrustLevel, + /* IRandomAccessStream methods */ + synthesis_stream_random_access_get_Size, + synthesis_stream_random_access_put_Size, + synthesis_stream_random_access_GetInputStreamAt, + synthesis_stream_random_access_GetOutputStreamAt, + synthesis_stream_random_access_get_Position, + synthesis_stream_random_access_Seek, + synthesis_stream_random_access_CloneStream, + synthesis_stream_random_access_get_CanRead, + synthesis_stream_random_access_get_CanWrite, +}; + + static HRESULT synthesis_stream_create( ISpeechSynthesisStream **out ) { struct synthesis_stream *impl; @@ -267,6 +417,7 @@ static HRESULT synthesis_stream_create( ISpeechSynthesisStream **out ) }
impl->ISpeechSynthesisStream_iface.lpVtbl = &synthesis_stream_vtbl; + impl->IRandomAccessStream_iface.lpVtbl = &synthesis_stream_random_access_vtbl; impl->ref = 1; if (FAILED(hr = vector_inspectable_create(&markers_iids, (IVector_IInspectable**)&impl->markers))) goto error; diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 422df544d59..719c97a52e2 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -29,6 +29,7 @@
#define WIDL_using_Windows_Foundation #define WIDL_using_Windows_Foundation_Collections +#define WIDL_using_Windows_Storage_Streams #include "windows.foundation.h" #define WIDL_using_Windows_Globalization #include "windows.globalization.h" @@ -36,7 +37,6 @@ #include "windows.media.speechrecognition.h" #define WIDL_using_Windows_Media_SpeechSynthesis #include "windows.media.speechsynthesis.h" - #include "wine/test.h"
#define AsyncStatus_Closed 4 @@ -788,6 +788,7 @@ static void test_SpeechSynthesizer(void) IVectorView_VoiceInformation *voices = NULL; IInstalledVoicesStatic *voices_static = NULL; ISpeechSynthesisStream *ss_stream = NULL, *tmp; + IRandomAccessStream *ra_stream; IVoiceInformation *voice; IInspectable *inspectable = NULL, *tmp_inspectable = NULL; IAgileObject *agile_object = NULL, *tmp_agile_object = NULL; @@ -943,6 +944,10 @@ static void test_SpeechSynthesizer(void) hr = IAsyncOperation_SpeechSynthesisStream_GetResults(operation_ss_stream, &ss_stream); ok(hr == S_OK, "IAsyncOperation_SpeechSynthesisStream_GetResults failed, hr %#lx\n", hr);
+ hr = ISpeechSynthesisStream_QueryInterface(ss_stream, &IID_IRandomAccessStream, (void **)&ra_stream); + ok(hr == S_OK, "QueryInteface(&IID_IRandomAccessStream) failed, hr %#lx\n", hr); + IRandomAccessStream_Release(ra_stream); + tmp = (void *)0xdeadbeef; hr = IAsyncOperation_SpeechSynthesisStream_GetResults(operation_ss_stream, &tmp); ok(hr == S_OK, "IAsyncOperation_SpeechSynthesisStream_GetResults failed, hr %#lx\n", hr);
 
            From: Paul Gofman pgofman@codeweavers.com
--- dlls/windows.media.speech/private.h | 1 + dlls/windows.media.speech/synthesizer.c | 79 ++++++++++++++++++++++++ dlls/windows.media.speech/tests/speech.c | 9 +++ 3 files changed, 89 insertions(+)
diff --git a/dlls/windows.media.speech/private.h b/dlls/windows.media.speech/private.h index e7921370f11..6597468e932 100644 --- a/dlls/windows.media.speech/private.h +++ b/dlls/windows.media.speech/private.h @@ -34,6 +34,7 @@ #define WIDL_using_Windows_Foundation #define WIDL_using_Windows_Foundation_Collections #define WIDL_using_Windows_Storage_Streams +#define WIDL_using_Windows_Foundation #include "windows.foundation.h" #define WIDL_using_Windows_Globalization #include "windows.globalization.h" diff --git a/dlls/windows.media.speech/synthesizer.c b/dlls/windows.media.speech/synthesizer.c index c2bed2e45b9..206b4007943 100644 --- a/dlls/windows.media.speech/synthesizer.c +++ b/dlls/windows.media.speech/synthesizer.c @@ -155,6 +155,7 @@ struct synthesis_stream { ISpeechSynthesisStream ISpeechSynthesisStream_iface; IRandomAccessStream IRandomAccessStream_iface; + IInputStream IInputStream_iface; LONG ref;
IVector_IMediaMarker *markers; @@ -187,6 +188,13 @@ HRESULT WINAPI synthesis_stream_QueryInterface( ISpeechSynthesisStream *iface, R return S_OK; }
+ if (IsEqualGUID(iid, &IID_IInputStream)) + { + IInputStream_AddRef(&impl->IInputStream_iface); + *out = &impl->IInputStream_iface; + return S_OK; + } + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); *out = NULL; return E_NOINTERFACE; @@ -396,6 +404,76 @@ static const struct IRandomAccessStreamVtbl synthesis_stream_random_access_vtbl };
+static inline struct synthesis_stream *impl_from_IInputStream( IInputStream *iface ) +{ + return CONTAINING_RECORD(iface, struct synthesis_stream, IInputStream_iface); +} + +static HRESULT WINAPI synthesis_stream_input_QueryInterface( IInputStream *iface, REFIID iid, void **out ) +{ + struct synthesis_stream *impl = impl_from_IInputStream(iface); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out ); + + return ISpeechSynthesisStream_QueryInterface( &impl->ISpeechSynthesisStream_iface, iid, out ); +} + +static ULONG WINAPI synthesis_stream_input_AddRef( IInputStream *iface ) +{ + struct synthesis_stream *impl = impl_from_IInputStream(iface); + + TRACE( "iface %p.\n", iface ); + return ISpeechSynthesisStream_AddRef( &impl->ISpeechSynthesisStream_iface ); +} + +static ULONG WINAPI synthesis_stream_input_Release( IInputStream *iface ) +{ + struct synthesis_stream *impl = impl_from_IInputStream(iface); + + TRACE( "iface %p.\n", iface ); + return ISpeechSynthesisStream_Release( &impl->ISpeechSynthesisStream_iface ); +} + +static HRESULT WINAPI synthesis_stream_input_GetIids( IInputStream *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub.\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI synthesis_stream_input_GetRuntimeClassName( IInputStream *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub.\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI synthesis_stream_input_GetTrustLevel( IInputStream *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub.\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI synthesis_stream_input_ReadAsync( IInputStream *iface, IBuffer *buffer, UINT32 count, + InputStreamOptions options, IAsyncOperationWithProgress_IBuffer_UINT32 **operation) +{ + FIXME( "iface %p, buffer %p, count %u, options %d, operation %p stub.\n", iface, buffer, count, options, operation ); + return E_NOTIMPL; +} + +static const struct IInputStreamVtbl synthesis_stream_input_vtbl = +{ + /* IUnknown methods */ + synthesis_stream_input_QueryInterface, + synthesis_stream_input_AddRef, + synthesis_stream_input_Release, + /* IInspectable methods */ + synthesis_stream_input_GetIids, + synthesis_stream_input_GetRuntimeClassName, + synthesis_stream_input_GetTrustLevel, + /* IInputStream methods */ + synthesis_stream_input_ReadAsync +}; + + static HRESULT synthesis_stream_create( ISpeechSynthesisStream **out ) { struct synthesis_stream *impl; @@ -418,6 +496,7 @@ static HRESULT synthesis_stream_create( ISpeechSynthesisStream **out )
impl->ISpeechSynthesisStream_iface.lpVtbl = &synthesis_stream_vtbl; impl->IRandomAccessStream_iface.lpVtbl = &synthesis_stream_random_access_vtbl; + impl->IInputStream_iface.lpVtbl = &synthesis_stream_input_vtbl; impl->ref = 1; if (FAILED(hr = vector_inspectable_create(&markers_iids, (IVector_IInspectable**)&impl->markers))) goto error; diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 719c97a52e2..16e80dee036 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -789,6 +789,7 @@ static void test_SpeechSynthesizer(void) IInstalledVoicesStatic *voices_static = NULL; ISpeechSynthesisStream *ss_stream = NULL, *tmp; IRandomAccessStream *ra_stream; + IInputStream *inp_stream; IVoiceInformation *voice; IInspectable *inspectable = NULL, *tmp_inspectable = NULL; IAgileObject *agile_object = NULL, *tmp_agile_object = NULL; @@ -798,6 +799,7 @@ static void test_SpeechSynthesizer(void) struct async_inspectable_handler async_inspectable_handler; HMODULE hdll; HSTRING str, str2; + UINT64 value; HRESULT hr; UINT32 size; ULONG ref; @@ -946,8 +948,15 @@ static void test_SpeechSynthesizer(void)
hr = ISpeechSynthesisStream_QueryInterface(ss_stream, &IID_IRandomAccessStream, (void **)&ra_stream); ok(hr == S_OK, "QueryInteface(&IID_IRandomAccessStream) failed, hr %#lx\n", hr); + hr = IRandomAccessStream_get_Size(ra_stream, &value); + ok(hr == S_OK, "_get_Size failed, hr %#lx\n", hr); + todo_wine ok(value, "got 0.\n"); IRandomAccessStream_Release(ra_stream);
+ hr = ISpeechSynthesisStream_QueryInterface(ss_stream, &IID_IInputStream, (void **)&inp_stream); + ok(hr == S_OK, "QueryInteface(&IID_IRandomAccessStream) failed, hr %#lx\n", hr); + IInputStream_Release(inp_stream); + tmp = (void *)0xdeadbeef; hr = IAsyncOperation_SpeechSynthesisStream_GetResults(operation_ss_stream, &tmp); ok(hr == S_OK, "IAsyncOperation_SpeechSynthesisStream_GetResults failed, hr %#lx\n", hr);
 
            From: Paul Gofman pgofman@codeweavers.com
--- dlls/windows.media.speech/synthesizer.c | 167 ++++++++++++++++++++++- dlls/windows.media.speech/tests/speech.c | 27 ++++ 2 files changed, 193 insertions(+), 1 deletion(-)
diff --git a/dlls/windows.media.speech/synthesizer.c b/dlls/windows.media.speech/synthesizer.c index 206b4007943..75e05f15aeb 100644 --- a/dlls/windows.media.speech/synthesizer.c +++ b/dlls/windows.media.speech/synthesizer.c @@ -404,6 +404,171 @@ static const struct IRandomAccessStreamVtbl synthesis_stream_random_access_vtbl };
+struct synthesis_stream_async_operation +{ + IAsyncOperationWithProgress_IBuffer_UINT32 ISynthesisSteamBufferAsync_iface; + IBuffer *buffer; + IInputStream *inp_stream; + + LONG ref; +}; + +static inline struct synthesis_stream_async_operation *impl_from_ISynthesisSteamBufferAsync( IAsyncOperationWithProgress_IBuffer_UINT32 *iface ) +{ + return CONTAINING_RECORD( iface, struct synthesis_stream_async_operation, ISynthesisSteamBufferAsync_iface ); +} + +static HRESULT WINAPI async_with_progress_uint32_QueryInterface( IAsyncOperationWithProgress_IBuffer_UINT32 *iface, REFIID iid, void **out ) +{ + struct synthesis_stream_async_operation *impl = impl_from_ISynthesisSteamBufferAsync( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IAsyncOperationWithProgress_IBuffer_UINT32 )) + { + *out = &impl->ISynthesisSteamBufferAsync_iface; + IAsyncOperationWithProgress_IBuffer_UINT32_AddRef( &impl->ISynthesisSteamBufferAsync_iface ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid) ); + return E_NOINTERFACE; +} + +static ULONG WINAPI async_with_progress_uint32_AddRef( IAsyncOperationWithProgress_IBuffer_UINT32 *iface ) +{ + struct synthesis_stream_async_operation *impl = impl_from_ISynthesisSteamBufferAsync( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI async_with_progress_uint32_Release( IAsyncOperationWithProgress_IBuffer_UINT32 *iface ) +{ + struct synthesis_stream_async_operation *impl = impl_from_ISynthesisSteamBufferAsync( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + + if (!ref) + { + /* guard against re-entry if inner releases an outer iface */ + IBuffer_Release( impl->buffer ); + IInputStream_Release( impl->inp_stream ); + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI async_with_progress_uint32_GetIids( IAsyncOperationWithProgress_IBuffer_UINT32 *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI async_with_progress_uint32_GetRuntimeClassName( IAsyncOperationWithProgress_IBuffer_UINT32 *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub.\n", iface, class_name ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI async_with_progress_uint32_GetTrustLevel( IAsyncOperationWithProgress_IBuffer_UINT32 *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI async_with_progress_uint32_put_Progress( IAsyncOperationWithProgress_IBuffer_UINT32 *iface, + IAsyncOperationProgressHandler_IBuffer_UINT32 *handler ) +{ + FIXME( "iface %p, handler %p stub.\n", iface, handler ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI async_with_progress_uint32_get_Progress( IAsyncOperationWithProgress_IBuffer_UINT32 *iface, + IAsyncOperationProgressHandler_IBuffer_UINT32 **handler ) +{ + FIXME( "iface %p, handler %p stub.\n", iface, handler ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI async_with_progress_uint32_put_Completed( IAsyncOperationWithProgress_IBuffer_UINT32 *iface, + IAsyncOperationWithProgressCompletedHandler_IBuffer_UINT32 *handler ) +{ + FIXME( "iface %p, handler %p stub.\n", iface, handler ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI async_with_progress_uint32_get_Completed( IAsyncOperationWithProgress_IBuffer_UINT32 *iface, + IAsyncOperationWithProgressCompletedHandler_IBuffer_UINT32 **handler ) +{ + FIXME( "iface %p, handler %p stub.\n", iface, handler ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI async_with_progress_uint32_GetResults( IAsyncOperationWithProgress_IBuffer_UINT32 *iface, + IBuffer **results ) +{ + struct synthesis_stream_async_operation *impl = impl_from_ISynthesisSteamBufferAsync( iface ); + + TRACE( "iface %p, results %p.\n", iface, results ); + + IBuffer_AddRef( impl->buffer ); + *results = impl->buffer; + return S_OK; +} + +IAsyncOperationWithProgress_IBuffer_UINT32Vtbl async_with_progress_uint32_vtbl = +{ + /* IUnknown methods */ + async_with_progress_uint32_QueryInterface, + async_with_progress_uint32_AddRef, + async_with_progress_uint32_Release, + /* IInspectable methods */ + async_with_progress_uint32_GetIids, + async_with_progress_uint32_GetRuntimeClassName, + async_with_progress_uint32_GetTrustLevel, + /* IAsyncOperationWithProgress<Windows.Storage.Streams.IBuffer *,UINT32> */ + async_with_progress_uint32_put_Progress, + async_with_progress_uint32_get_Progress, + async_with_progress_uint32_put_Completed, + async_with_progress_uint32_get_Completed, + async_with_progress_uint32_GetResults, +}; + +static HRESULT async_operation_with_progress_buffer_uint32_create( IInputStream *inp_stream, + IBuffer *buffer, + IAsyncOperationWithProgress_IBuffer_UINT32 **out) +{ + struct synthesis_stream_async_operation *impl; + + if (!inp_stream || !buffer || !out) return E_POINTER; + + *out = NULL; + if (!(impl = calloc(1, sizeof(*impl)))) + return E_OUTOFMEMORY; + + impl->ref = 1; + IBuffer_AddRef( buffer ); + impl->buffer = buffer; + IInputStream_AddRef( inp_stream ); + impl->inp_stream = inp_stream; + impl->ISynthesisSteamBufferAsync_iface.lpVtbl = &async_with_progress_uint32_vtbl; + *out = &impl->ISynthesisSteamBufferAsync_iface; + return S_OK; +} + + static inline struct synthesis_stream *impl_from_IInputStream( IInputStream *iface ) { return CONTAINING_RECORD(iface, struct synthesis_stream, IInputStream_iface); @@ -456,7 +621,7 @@ static HRESULT WINAPI synthesis_stream_input_ReadAsync( IInputStream *iface, IBu InputStreamOptions options, IAsyncOperationWithProgress_IBuffer_UINT32 **operation) { FIXME( "iface %p, buffer %p, count %u, options %d, operation %p stub.\n", iface, buffer, count, options, operation ); - return E_NOTIMPL; + return async_operation_with_progress_buffer_uint32_create( iface, buffer, operation ); }
static const struct IInputStreamVtbl synthesis_stream_input_vtbl = diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 16e80dee036..f652a0c832c 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -782,14 +782,18 @@ static void test_SpeechSynthesizer(void) static const WCHAR *speech_synthesizer_name = L"Windows.Media.SpeechSynthesis.SpeechSynthesizer"; static const WCHAR *speech_synthesizer_name2 = L"windows.media.speechsynthesis.speechsynthesizer"; static const WCHAR *unknown_class_name = L"Unknown.Class"; + static const WCHAR *buffer_class_name = L"Windows.Storage.Streams.Buffer"; IActivationFactory *factory = NULL, *factory2 = NULL; + IBufferFactory *buffer_factory = NULL; IAsyncOperation_SpeechSynthesisStream *operation_ss_stream = NULL; + IAsyncOperationWithProgress_IBuffer_UINT32 *operation_read_async = NULL; IVectorView_IMediaMarker *media_markers = NULL; IVectorView_VoiceInformation *voices = NULL; IInstalledVoicesStatic *voices_static = NULL; ISpeechSynthesisStream *ss_stream = NULL, *tmp; IRandomAccessStream *ra_stream; IInputStream *inp_stream; + IBuffer *buffer = NULL, *buffer2 = NULL; IVoiceInformation *voice; IInspectable *inspectable = NULL, *tmp_inspectable = NULL; IAgileObject *agile_object = NULL, *tmp_agile_object = NULL; @@ -953,9 +957,32 @@ static void test_SpeechSynthesizer(void) todo_wine ok(value, "got 0.\n"); IRandomAccessStream_Release(ra_stream);
+ hr = WindowsCreateString(buffer_class_name, wcslen(buffer_class_name), &str2); + ok(hr == S_OK, "WindowsCreateString failed, hr %#lx.\n", hr); + hr = RoGetActivationFactory(str2, &IID_IActivationFactory, (void **)&factory2); + ok(hr == S_OK, "RoGetActivationFactory failed, hr %#lx.\n", hr); + WindowsDeleteString(str2); + + hr = IActivationFactory_QueryInterface(factory2, &IID_IBufferFactory, (void **)&buffer_factory); + ok(hr == S_OK, "QueryInterface IID_IBufferFactory failed, hr %#lx.\n", hr); + IActivationFactory_Release(factory2); + hr = IBufferFactory_Create(buffer_factory, value, &buffer); + ok(hr == S_OK, "IBufferFactory_Create failed, hr %#lx.\n", hr); + IBufferFactory_Release(buffer_factory); + hr = ISpeechSynthesisStream_QueryInterface(ss_stream, &IID_IInputStream, (void **)&inp_stream); ok(hr == S_OK, "QueryInteface(&IID_IRandomAccessStream) failed, hr %#lx\n", hr); + hr = IInputStream_ReadAsync(inp_stream, buffer, value, InputStreamOptions_ReadAhead, &operation_read_async); + ok(hr == S_OK, "_ReadAsync failed, hr %#lx\n", hr); IInputStream_Release(inp_stream); + IAsyncOperationWithProgress_IBuffer_UINT32_GetResults(operation_read_async, &buffer2); + ok(hr == S_OK, "_GetResults failed, hr %#lx\n", hr); + ok(buffer2 == buffer, "got %p, %p.\n", buffer, buffer2); + IBuffer_Release(buffer); + ref = IAsyncOperationWithProgress_IBuffer_UINT32_Release(operation_read_async); + ok(!ref, "got refcount %ld.\n", ref); + ref = IBuffer_Release(buffer2); + ok(!ref, "got refcount %ld.\n", ref);
tmp = (void *)0xdeadbeef; hr = IAsyncOperation_SpeechSynthesisStream_GetResults(operation_ss_stream, &tmp);
 
            From: Paul Gofman pgofman@codeweavers.com
--- dlls/windows.media.speech/synthesizer.c | 68 ++++++++++++++++++++++++ dlls/windows.media.speech/tests/speech.c | 1 + 2 files changed, 69 insertions(+)
diff --git a/dlls/windows.media.speech/synthesizer.c b/dlls/windows.media.speech/synthesizer.c index 75e05f15aeb..67f028dc52f 100644 --- a/dlls/windows.media.speech/synthesizer.c +++ b/dlls/windows.media.speech/synthesizer.c @@ -407,6 +407,7 @@ static const struct IRandomAccessStreamVtbl synthesis_stream_random_access_vtbl struct synthesis_stream_async_operation { IAsyncOperationWithProgress_IBuffer_UINT32 ISynthesisSteamBufferAsync_iface; + IAsyncInfo IAsyncInfo_iface; IBuffer *buffer; IInputStream *inp_stream;
@@ -434,6 +435,13 @@ static HRESULT WINAPI async_with_progress_uint32_QueryInterface( IAsyncOperation return S_OK; }
+ if (IsEqualGUID( iid, &IID_IAsyncInfo )) + { + *out = &impl->IAsyncInfo_iface; + IAsyncInfo_AddRef( &impl->IAsyncInfo_iface ); + return S_OK; + } + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid) ); return E_NOINTERFACE; } @@ -546,6 +554,65 @@ IAsyncOperationWithProgress_IBuffer_UINT32Vtbl async_with_progress_uint32_vtbl = async_with_progress_uint32_GetResults, };
+DEFINE_IINSPECTABLE(async_info, IAsyncInfo, struct synthesis_stream_async_operation, ISynthesisSteamBufferAsync_iface) + +static HRESULT WINAPI async_info_get_Id( IAsyncInfo *iface, UINT32 *id ) +{ + TRACE( "iface %p, id %p.\n", iface, id ); + + *id = 1; + return S_OK; +} + +static HRESULT WINAPI async_info_get_Status( IAsyncInfo *iface, AsyncStatus *status ) +{ + TRACE( "iface %p, status %p.\n", iface, status ); + + *status = Completed; + return S_OK; +} + +static HRESULT WINAPI async_info_get_ErrorCode( IAsyncInfo *iface, HRESULT *error_code ) +{ + FIXME( "iface %p, error_code %p.\n", iface, error_code ); + + *error_code = S_OK; + return S_OK; +} + +static HRESULT WINAPI async_info_Cancel( IAsyncInfo *iface ) +{ + FIXME( "iface %p.\n", iface ); + + return S_OK; +} + +static HRESULT WINAPI async_info_Close( IAsyncInfo *iface ) +{ + FIXME( "iface %p.\n", iface ); + + return S_OK; +} + + +static const struct IAsyncInfoVtbl async_info_vtbl = +{ + /* IUnknown methods */ + async_info_QueryInterface, + async_info_AddRef, + async_info_Release, + /* IInspectable methods */ + async_info_GetIids, + async_info_GetRuntimeClassName, + async_info_GetTrustLevel, + /* IAsyncInfo */ + async_info_get_Id, + async_info_get_Status, + async_info_get_ErrorCode, + async_info_Cancel, + async_info_Close, +}; + static HRESULT async_operation_with_progress_buffer_uint32_create( IInputStream *inp_stream, IBuffer *buffer, IAsyncOperationWithProgress_IBuffer_UINT32 **out) @@ -564,6 +631,7 @@ static HRESULT async_operation_with_progress_buffer_uint32_create( IInputStream IInputStream_AddRef( inp_stream ); impl->inp_stream = inp_stream; impl->ISynthesisSteamBufferAsync_iface.lpVtbl = &async_with_progress_uint32_vtbl; + impl->IAsyncInfo_iface.lpVtbl = &async_info_vtbl; *out = &impl->ISynthesisSteamBufferAsync_iface; return S_OK; } diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index f652a0c832c..b1362678212 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -975,6 +975,7 @@ static void test_SpeechSynthesizer(void) hr = IInputStream_ReadAsync(inp_stream, buffer, value, InputStreamOptions_ReadAhead, &operation_read_async); ok(hr == S_OK, "_ReadAsync failed, hr %#lx\n", hr); IInputStream_Release(inp_stream); + check_async_info((IInspectable *)operation_read_async, 1, Completed, S_OK); IAsyncOperationWithProgress_IBuffer_UINT32_GetResults(operation_read_async, &buffer2); ok(hr == S_OK, "_GetResults failed, hr %#lx\n", hr); ok(buffer2 == buffer, "got %p, %p.\n", buffer, buffer2);
 
            This fixes Assassin's Creed Shadow which now crashes on initial config screen. It will try to suggest screen reading in that screen and when it goes as far as successfully creating synthesis stream (with the present speech synthesis stubs) it won't tolerate any failure on the way forward (would it be missing interface or an error return from functions it calls from it) and will crash either trying to dereference missing interface from QueryInterface or from exception fired on method's error return.
The tests added on the way cover everything the game calls.
As the test suggests, the IAsyncOperationWithProgress_IBuffer_UINT32 async returned from synthesis_stream_input_ReadAsync() is not really async: the success result is available immediately after getting the async interface without waiting for it. I think it makes sense because the method(s) to get the synthesis stream for the given text string are already async (also in the present stubs) and IAsyncOperationWithProgress_IBuffer_UINT32 async should only return already prepared buffer data. So I suppose it doesn't worth it to have a helper to queue that async (like for stream creating asyncs) which would make it really async and it is more straightforward to just add the sync implementation directly linked to the synthesis class. Once actual synthesis is implemented the implementation would (asynchronously) create the stream with ready data and the present stubs will only need to hook up the stored buffer data.

