2 * Speech API (SAPI) text-to-speech tests.
4 * Copyright 2019 Jactry Zeng for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/test.h"
28 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
29 static void _expect_ref(IUnknown
*obj
, ULONG ref
, int line
)
33 rc
= IUnknown_Release(obj
);
34 ok_(__FILE__
,line
)(rc
== ref
, "Unexpected refcount %ld, expected %ld.\n", rc
, ref
);
37 static void test_interfaces(void)
39 ISpeechVoice
*speech_voice
, *speech_voice2
;
40 IConnectionPointContainer
*container
;
41 ISpTTSEngineSite
*site
;
42 ISpVoice
*spvoice
, *spvoice2
;
47 hr
= CoCreateInstance(&CLSID_SpVoice
, NULL
, CLSCTX_INPROC_SERVER
,
48 &IID_ISpeechVoice
, (void **)&speech_voice
);
49 ok(hr
== S_OK
, "Failed to create ISpeechVoice interface: %#lx.\n", hr
);
50 EXPECT_REF(speech_voice
, 1);
52 hr
= CoCreateInstance(&CLSID_SpVoice
, NULL
, CLSCTX_INPROC_SERVER
,
53 &IID_IDispatch
, (void **)&dispatch
);
54 ok(hr
== S_OK
, "Failed to create IDispatch interface: %#lx.\n", hr
);
55 EXPECT_REF(dispatch
, 1);
56 EXPECT_REF(speech_voice
, 1);
57 IDispatch_Release(dispatch
);
59 hr
= CoCreateInstance(&CLSID_SpVoice
, NULL
, CLSCTX_INPROC_SERVER
,
60 &IID_IUnknown
, (void **)&unk
);
61 ok(hr
== S_OK
, "Failed to create IUnknown interface: %#lx.\n", hr
);
63 EXPECT_REF(speech_voice
, 1);
64 IUnknown_Release(unk
);
66 hr
= CoCreateInstance(&CLSID_SpVoice
, NULL
, CLSCTX_INPROC_SERVER
,
67 &IID_ISpVoice
, (void **)&spvoice
);
68 ok(hr
== S_OK
, "Failed to create ISpVoice interface: %#lx.\n", hr
);
69 EXPECT_REF(spvoice
, 1);
70 EXPECT_REF(speech_voice
, 1);
72 hr
= ISpVoice_QueryInterface(spvoice
, &IID_ISpeechVoice
, (void **)&speech_voice2
);
73 ok(hr
== S_OK
, "ISpVoice_QueryInterface failed: %#lx.\n", hr
);
74 EXPECT_REF(speech_voice2
, 2);
75 EXPECT_REF(spvoice
, 2);
76 EXPECT_REF(speech_voice
, 1);
77 ISpeechVoice_Release(speech_voice2
);
79 hr
= ISpeechVoice_QueryInterface(speech_voice
, &IID_ISpVoice
, (void **)&spvoice2
);
80 ok(hr
== S_OK
, "ISpeechVoice_QueryInterface failed: %#lx.\n", hr
);
81 EXPECT_REF(speech_voice
, 2);
82 EXPECT_REF(spvoice2
, 2);
83 EXPECT_REF(spvoice
, 1);
84 ISpVoice_Release(spvoice2
);
85 ISpVoice_Release(spvoice
);
87 hr
= ISpeechVoice_QueryInterface(speech_voice
, &IID_IConnectionPointContainer
,
89 ok(hr
== S_OK
, "ISpeechVoice_QueryInterface failed: %#lx.\n", hr
);
90 EXPECT_REF(speech_voice
, 2);
91 EXPECT_REF(container
, 2);
92 IConnectionPointContainer_Release(container
);
94 hr
= ISpeechVoice_QueryInterface(speech_voice
, &IID_ISpTTSEngineSite
,
96 ok(hr
== E_NOINTERFACE
, "ISpeechVoice_QueryInterface for ISpTTSEngineSite returned: %#lx.\n", hr
);
98 ISpeechVoice_Release(speech_voice
);
101 #define TESTENGINE_CLSID L"{57C7E6B1-2FC2-4E8E-B968-1410A39E7198}"
102 static const GUID CLSID_TestEngine
= {0x57C7E6B1,0x2FC2,0x4E8E,{0xB9,0x68,0x14,0x10,0xA3,0x9E,0x71,0x98}};
106 ISpTTSEngine ISpTTSEngine_iface
;
107 ISpObjectWithToken ISpObjectWithToken_iface
;
109 ISpObjectToken
*token
;
114 SPVTEXTFRAG
*frag_list
;
119 static void copy_frag_list(const SPVTEXTFRAG
*frag_list
, SPVTEXTFRAG
**ret_frag_list
)
121 SPVTEXTFRAG
*frag
, *prev
= NULL
;
125 *ret_frag_list
= NULL
;
131 frag
= malloc(sizeof(*frag
) + frag_list
->ulTextLen
* sizeof(WCHAR
));
132 memcpy(frag
, frag_list
, sizeof(*frag
));
134 if (frag_list
->pTextStart
)
136 frag
->pTextStart
= (WCHAR
*)(frag
+ 1);
137 memcpy(frag
+ 1, frag_list
->pTextStart
, frag
->ulTextLen
* sizeof(WCHAR
));
145 *ret_frag_list
= frag
;
148 frag_list
= frag_list
->pNext
;
152 static void reset_engine_params(struct test_engine
*engine
)
154 SPVTEXTFRAG
*frag
, *next
;
156 engine
->speak_called
= FALSE
;
157 engine
->flags
= 0xdeadbeef;
158 memset(&engine
->fmtid
, 0xde, sizeof(engine
->fmtid
));
159 engine
->rate
= 0xdeadbeef;
160 engine
->volume
= 0xbeef;
162 for (frag
= engine
->frag_list
; frag
; frag
= next
)
167 engine
->frag_list
= NULL
;
170 static inline struct test_engine
*impl_from_ISpTTSEngine(ISpTTSEngine
*iface
)
172 return CONTAINING_RECORD(iface
, struct test_engine
, ISpTTSEngine_iface
);
175 static inline struct test_engine
*impl_from_ISpObjectWithToken(ISpObjectWithToken
*iface
)
177 return CONTAINING_RECORD(iface
, struct test_engine
, ISpObjectWithToken_iface
);
180 static HRESULT WINAPI
test_engine_QueryInterface(ISpTTSEngine
*iface
, REFIID iid
, void **obj
)
182 struct test_engine
*engine
= impl_from_ISpTTSEngine(iface
);
184 if (IsEqualIID(iid
, &IID_IUnknown
) || IsEqualIID(iid
, &IID_ISpTTSEngine
))
185 *obj
= &engine
->ISpTTSEngine_iface
;
186 else if (IsEqualIID(iid
, &IID_ISpObjectWithToken
))
187 *obj
= &engine
->ISpObjectWithToken_iface
;
191 return E_NOINTERFACE
;
194 IUnknown_AddRef((IUnknown
*)*obj
);
198 static ULONG WINAPI
test_engine_AddRef(ISpTTSEngine
*iface
)
203 static ULONG WINAPI
test_engine_Release(ISpTTSEngine
*iface
)
208 static HRESULT WINAPI
test_engine_Speak(ISpTTSEngine
*iface
, DWORD flags
, REFGUID fmtid
,
209 const WAVEFORMATEX
*wfx
, const SPVTEXTFRAG
*frag_list
,
210 ISpTTSEngineSite
*site
)
212 struct test_engine
*engine
= impl_from_ISpTTSEngine(iface
);
218 engine
->flags
= flags
;
219 engine
->fmtid
= *fmtid
;
220 copy_frag_list(frag_list
, &engine
->frag_list
);
221 engine
->speak_called
= TRUE
;
223 actions
= ISpTTSEngineSite_GetActions(site
);
224 ok(actions
== (SPVES_CONTINUE
| SPVES_RATE
| SPVES_VOLUME
), "got %#lx.\n", actions
);
226 hr
= ISpTTSEngineSite_GetRate(site
, &engine
->rate
);
227 ok(hr
== S_OK
, "got %#lx.\n", hr
);
228 actions
= ISpTTSEngineSite_GetActions(site
);
229 ok(actions
== (SPVES_CONTINUE
| SPVES_VOLUME
), "got %#lx.\n", actions
);
231 hr
= ISpTTSEngineSite_GetVolume(site
, &engine
->volume
);
232 ok(hr
== S_OK
, "got %#lx.\n", hr
);
233 actions
= ISpTTSEngineSite_GetActions(site
);
234 ok(actions
== SPVES_CONTINUE
, "got %#lx.\n", actions
);
236 buf
= calloc(1, 22050 * 2 / 5);
237 for (i
= 0; i
< 5; i
++)
239 if (ISpTTSEngineSite_GetActions(site
) & SPVES_ABORT
)
241 hr
= ISpTTSEngineSite_Write(site
, buf
, 22050 * 2 / 5, NULL
);
242 ok(hr
== S_OK
|| hr
== SP_AUDIO_STOPPED
, "got %#lx.\n", hr
);
250 static HRESULT WINAPI
test_engine_GetOutputFormat(ISpTTSEngine
*iface
, const GUID
*fmtid
,
251 const WAVEFORMATEX
*wfx
, GUID
*out_fmtid
,
252 WAVEFORMATEX
**out_wfx
)
254 *out_fmtid
= SPDFID_WaveFormatEx
;
255 *out_wfx
= CoTaskMemAlloc(sizeof(WAVEFORMATEX
));
256 (*out_wfx
)->wFormatTag
= WAVE_FORMAT_PCM
;
257 (*out_wfx
)->nChannels
= 1;
258 (*out_wfx
)->nSamplesPerSec
= 22050;
259 (*out_wfx
)->wBitsPerSample
= 16;
260 (*out_wfx
)->nBlockAlign
= 2;
261 (*out_wfx
)->nAvgBytesPerSec
= 22050 * 2;
262 (*out_wfx
)->cbSize
= 0;
267 static ISpTTSEngineVtbl test_engine_vtbl
=
269 test_engine_QueryInterface
,
273 test_engine_GetOutputFormat
,
276 static HRESULT WINAPI
objwithtoken_QueryInterface(ISpObjectWithToken
*iface
, REFIID iid
, void **obj
)
278 struct test_engine
*engine
= impl_from_ISpObjectWithToken(iface
);
280 return ISpTTSEngine_QueryInterface(&engine
->ISpTTSEngine_iface
, iid
, obj
);
283 static ULONG WINAPI
objwithtoken_AddRef(ISpObjectWithToken
*iface
)
288 static ULONG WINAPI
objwithtoken_Release(ISpObjectWithToken
*iface
)
293 static HRESULT WINAPI
objwithtoken_SetObjectToken(ISpObjectWithToken
*iface
, ISpObjectToken
*token
)
295 struct test_engine
*engine
= impl_from_ISpObjectWithToken(iface
);
300 ISpObjectToken_AddRef(token
);
301 engine
->token
= token
;
306 static HRESULT WINAPI
objwithtoken_GetObjectToken(ISpObjectWithToken
*iface
, ISpObjectToken
**token
)
308 struct test_engine
*engine
= impl_from_ISpObjectWithToken(iface
);
310 *token
= engine
->token
;
312 ISpObjectToken_AddRef(*token
);
317 static const ISpObjectWithTokenVtbl objwithtoken_vtbl
=
319 objwithtoken_QueryInterface
,
321 objwithtoken_Release
,
322 objwithtoken_SetObjectToken
,
323 objwithtoken_GetObjectToken
326 static struct test_engine test_engine
= {{&test_engine_vtbl
}, {&objwithtoken_vtbl
}};
328 static HRESULT WINAPI
ClassFactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **ppv
)
330 if (IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_IClassFactory
, riid
))
337 return E_NOINTERFACE
;
340 static ULONG WINAPI
ClassFactory_AddRef(IClassFactory
*iface
)
345 static ULONG WINAPI
ClassFactory_Release(IClassFactory
*iface
)
350 static HRESULT WINAPI
ClassFactory_CreateInstance(IClassFactory
*iface
,
351 IUnknown
*pUnkOuter
, REFIID riid
, void **ppv
)
353 ok(pUnkOuter
== NULL
, "pUnkOuter != NULL.\n");
354 ok(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ISpTTSEngine
),
355 "riid = %s.\n", wine_dbgstr_guid(riid
));
357 *ppv
= &test_engine
.ISpTTSEngine_iface
;
361 static HRESULT WINAPI
ClassFactory_LockServer(IClassFactory
*iface
, BOOL fLock
)
363 ok(0, "unexpected call.\n");
367 static const IClassFactoryVtbl ClassFactoryVtbl
= {
368 ClassFactory_QueryInterface
,
370 ClassFactory_Release
,
371 ClassFactory_CreateInstance
,
372 ClassFactory_LockServer
375 static IClassFactory test_engine_cf
= { &ClassFactoryVtbl
};
377 static void test_spvoice(void)
379 static const WCHAR test_token_id
[] = L
"HKEY_LOCAL_MACHINE\\Software\\Wine\\Winetest\\sapi\\tts\\TestEngine";
380 static const WCHAR test_text
[] = L
"Hello! This is a test sentence.";
383 ISpMMSysAudio
*audio_out
;
384 ISpObjectTokenCategory
*token_cat
;
385 ISpObjectToken
*token
;
386 WCHAR
*token_id
= NULL
, *default_token_id
= NULL
;
387 ISpDataKey
*attrs_key
;
392 DWORD start
, duration
;
395 if (waveOutGetNumDevs() == 0) {
396 skip("no wave out devices.\n");
400 hr
= CoCreateInstance(&CLSID_SpVoice
, NULL
, CLSCTX_INPROC_SERVER
,
401 &IID_ISpVoice
, (void **)&voice
);
402 ok(hr
== S_OK
, "Failed to create SpVoice: %#lx.\n", hr
);
404 hr
= ISpVoice_SetOutput(voice
, NULL
, TRUE
);
405 ok(hr
== S_OK
, "got %#lx.\n", hr
);
407 hr
= CoCreateInstance(&CLSID_SpMMAudioOut
, NULL
, CLSCTX_INPROC_SERVER
,
408 &IID_ISpMMSysAudio
, (void **)&audio_out
);
409 ok(hr
== S_OK
, "Failed to create SpMMAudioOut: %#lx.\n", hr
);
411 hr
= ISpVoice_SetOutput(voice
, (IUnknown
*)audio_out
, TRUE
);
412 todo_wine
ok(hr
== S_FALSE
, "got %#lx.\n", hr
);
414 hr
= ISpVoice_SetVoice(voice
, NULL
);
415 todo_wine
ok(hr
== S_OK
, "got %#lx.\n", hr
);
417 hr
= ISpVoice_GetVoice(voice
, &token
);
418 todo_wine
ok(hr
== S_OK
, "got %#lx.\n", hr
);
422 hr
= ISpObjectToken_GetId(token
, &token_id
);
423 ok(hr
== S_OK
, "got %#lx.\n", hr
);
425 hr
= CoCreateInstance(&CLSID_SpObjectTokenCategory
, NULL
, CLSCTX_INPROC_SERVER
,
426 &IID_ISpObjectTokenCategory
, (void **)&token_cat
);
427 ok(hr
== S_OK
, "Failed to create SpObjectTokenCategory: %#lx.\n", hr
);
429 hr
= ISpObjectTokenCategory_SetId(token_cat
, SPCAT_VOICES
, FALSE
);
430 ok(hr
== S_OK
, "got %#lx.\n", hr
);
431 hr
= ISpObjectTokenCategory_GetDefaultTokenId(token_cat
, &default_token_id
);
432 ok(hr
== S_OK
, "got %#lx.\n", hr
);
434 ok(!wcscmp(token_id
, default_token_id
), "token_id != default_token_id\n");
436 CoTaskMemFree(token_id
);
437 CoTaskMemFree(default_token_id
);
438 ISpObjectToken_Release(token
);
439 ISpObjectTokenCategory_Release(token_cat
);
443 hr
= ISpVoice_GetRate(voice
, &rate
);
444 ok(hr
== S_OK
, "got %#lx.\n", hr
);
445 ok(rate
== 0, "rate = %ld\n", rate
);
447 hr
= ISpVoice_SetRate(voice
, 1);
448 ok(hr
== S_OK
, "got %#lx.\n", hr
);
451 hr
= ISpVoice_GetRate(voice
, &rate
);
452 ok(hr
== S_OK
, "got %#lx.\n", hr
);
453 ok(rate
== 1, "rate = %ld\n", rate
);
455 hr
= ISpVoice_SetRate(voice
, -1000);
456 ok(hr
== S_OK
, "got %#lx.\n", hr
);
459 hr
= ISpVoice_GetRate(voice
, &rate
);
460 ok(hr
== S_OK
, "got %#lx.\n", hr
);
461 ok(rate
== -1000, "rate = %ld\n", rate
);
463 hr
= ISpVoice_SetRate(voice
, 1000);
464 ok(hr
== S_OK
, "got %#lx.\n", hr
);
467 hr
= ISpVoice_GetRate(voice
, &rate
);
468 ok(hr
== S_OK
, "got %#lx.\n", hr
);
469 ok(rate
== 1000, "rate = %ld\n", rate
);
472 hr
= ISpVoice_GetVolume(voice
, &volume
);
473 ok(hr
== S_OK
, "got %#lx.\n", hr
);
474 ok(volume
== 100, "volume = %d\n", volume
);
476 hr
= ISpVoice_SetVolume(voice
, 0);
477 ok(hr
== S_OK
, "got %#lx.\n", hr
);
480 hr
= ISpVoice_GetVolume(voice
, &volume
);
481 ok(hr
== S_OK
, "got %#lx.\n", hr
);
482 ok(volume
== 0, "volume = %d\n", volume
);
484 hr
= ISpVoice_SetVolume(voice
, 100);
485 ok(hr
== S_OK
, "got %#lx.\n", hr
);
488 hr
= ISpVoice_GetVolume(voice
, &volume
);
489 ok(hr
== S_OK
, "got %#lx.\n", hr
);
490 ok(volume
== 100, "volume = %d\n", volume
);
492 hr
= ISpVoice_SetVolume(voice
, 101);
493 ok(hr
== E_INVALIDARG
, "got %#lx.\n", hr
);
495 hr
= CoRegisterClassObject(&CLSID_TestEngine
, (IUnknown
*)&test_engine_cf
,
496 CLSCTX_INPROC_SERVER
, REGCLS_MULTIPLEUSE
, ®id
);
497 ok(hr
== S_OK
, "got %#lx.\n", hr
);
499 hr
= CoCreateInstance(&CLSID_SpObjectToken
, NULL
, CLSCTX_INPROC_SERVER
,
500 &IID_ISpObjectToken
, (void **)&token
);
501 ok(hr
== S_OK
, "got %#lx.\n", hr
);
503 hr
= ISpObjectToken_SetId(token
, NULL
, test_token_id
, TRUE
);
504 ok(hr
== S_OK
|| broken(hr
== E_ACCESSDENIED
) /* w1064_adm */, "got %#lx.\n", hr
);
505 if (hr
== E_ACCESSDENIED
)
507 win_skip("token SetId access denied.\n");
511 ISpObjectToken_SetStringValue(token
, L
"CLSID", TESTENGINE_CLSID
);
512 hr
= ISpObjectToken_CreateKey(token
, L
"Attributes", &attrs_key
);
513 ok(hr
== S_OK
, "got %#lx.\n", hr
);
514 ISpDataKey_SetStringValue(attrs_key
, L
"Language", L
"409");
515 ISpDataKey_Release(attrs_key
);
517 hr
= ISpVoice_SetVoice(voice
, token
);
518 ok(hr
== S_OK
, "got %#lx.\n", hr
);
520 test_engine
.speak_called
= FALSE
;
521 hr
= ISpVoice_Speak(voice
, NULL
, SPF_PURGEBEFORESPEAK
, NULL
);
522 ok(hr
== S_OK
, "got %#lx.\n", hr
);
523 ok(!test_engine
.speak_called
, "ISpTTSEngine::Speak was called.\n");
525 stream_num
= 0xdeadbeef;
526 hr
= ISpVoice_Speak(voice
, NULL
, SPF_PURGEBEFORESPEAK
, &stream_num
);
527 ok(hr
== S_OK
, "got %#lx.\n", hr
);
528 ok(stream_num
== 0xdeadbeef, "got %lu.\n", stream_num
);
530 ISpVoice_SetRate(voice
, 0);
531 ISpVoice_SetVolume(voice
, 100);
533 reset_engine_params(&test_engine
);
534 stream_num
= 0xdeadbeef;
535 start
= GetTickCount();
536 hr
= ISpVoice_Speak(voice
, test_text
, SPF_DEFAULT
, &stream_num
);
537 duration
= GetTickCount() - start
;
538 ok(hr
== S_OK
, "got %#lx.\n", hr
);
539 ok(test_engine
.speak_called
, "ISpTTSEngine::Speak was not called.\n");
540 ok(test_engine
.flags
== SPF_DEFAULT
, "got %#lx.\n", test_engine
.flags
);
541 ok(test_engine
.frag_list
!= NULL
, "frag_list is NULL.\n");
542 ok(test_engine
.frag_list
->pNext
== NULL
, "frag_list->pNext != NULL.\n");
543 ok(test_engine
.frag_list
->ulTextLen
== wcslen(test_text
), "got %lu.\n", test_engine
.frag_list
->ulTextLen
);
544 ok(!wcsncmp(test_text
, test_engine
.frag_list
->pTextStart
, wcslen(test_text
)),
545 "got %s.\n", wine_dbgstr_w(test_engine
.frag_list
->pTextStart
));
546 ok(test_engine
.rate
== 0, "got %ld.\n", test_engine
.rate
);
547 ok(test_engine
.volume
== 100, "got %d.\n", test_engine
.volume
);
548 ok(stream_num
== 1, "got %lu.\n", stream_num
);
549 ok(duration
> 800 && duration
< 3000, "took %lu ms.\n", duration
);
551 start
= GetTickCount();
552 hr
= ISpVoice_WaitUntilDone(voice
, INFINITE
);
553 duration
= GetTickCount() - start
;
554 ok(hr
== S_OK
, "got %#lx.\n", hr
);
555 ok(duration
< 200, "took %lu ms.\n", duration
);
557 reset_engine_params(&test_engine
);
558 stream_num
= 0xdeadbeef;
559 start
= GetTickCount();
560 hr
= ISpVoice_Speak(voice
, test_text
, SPF_DEFAULT
| SPF_ASYNC
| SPF_NLP_SPEAK_PUNC
, &stream_num
);
561 duration
= GetTickCount() - start
;
562 ok(hr
== S_OK
, "got %#lx.\n", hr
);
563 todo_wine
ok(stream_num
== 1, "got %lu.\n", stream_num
);
564 ok(duration
< 500, "took %lu ms.\n", duration
);
566 hr
= ISpVoice_WaitUntilDone(voice
, 100);
567 ok(hr
== S_FALSE
, "got %#lx.\n", hr
);
569 hr
= ISpVoice_WaitUntilDone(voice
, INFINITE
);
570 duration
= GetTickCount() - start
;
571 ok(hr
== S_OK
, "got %#lx.\n", hr
);
572 ok(duration
> 800 && duration
< 3000, "took %lu ms.\n", duration
);
574 ok(test_engine
.speak_called
, "ISpTTSEngine::Speak was not called.\n");
575 ok(test_engine
.flags
== SPF_NLP_SPEAK_PUNC
, "got %#lx.\n", test_engine
.flags
);
576 ok(test_engine
.frag_list
!= NULL
, "frag_list is NULL.\n");
577 ok(test_engine
.frag_list
->pNext
== NULL
, "frag_list->pNext != NULL.\n");
578 ok(test_engine
.frag_list
->ulTextLen
== wcslen(test_text
), "got %lu.\n", test_engine
.frag_list
->ulTextLen
);
579 ok(!wcsncmp(test_text
, test_engine
.frag_list
->pTextStart
, wcslen(test_text
)),
580 "got %s.\n", wine_dbgstr_w(test_engine
.frag_list
->pTextStart
));
581 ok(test_engine
.rate
== 0, "got %ld.\n", test_engine
.rate
);
582 ok(test_engine
.volume
== 100, "got %d.\n", test_engine
.volume
);
584 reset_engine_params(&test_engine
);
585 hr
= ISpVoice_Speak(voice
, test_text
, SPF_DEFAULT
| SPF_ASYNC
, NULL
);
586 ok(hr
== S_OK
, "got %#lx.\n", hr
);
589 start
= GetTickCount();
590 hr
= ISpVoice_Speak(voice
, NULL
, SPF_PURGEBEFORESPEAK
, NULL
);
591 duration
= GetTickCount() - start
;
592 ok(hr
== S_OK
, "got %#lx.\n", hr
);
593 ok(duration
< 300, "took %lu ms.\n", duration
);
596 reset_engine_params(&test_engine
);
597 ISpVoice_Release(voice
);
598 ISpObjectToken_Release(token
);
599 ISpMMSysAudio_Release(audio_out
);