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);