4

Discovered key to the problem/crash, see the bottom of the post.

When creating instances of ISpVoice using CoCreateInstance, it seems like instances after the first one cannot speak as soon as the first one has spoken. That is, if pVoice speaks first, pVoice2 will not speak. If pVoice2 speaks first, pVoice will not speak. The order of creation/allocation does not seem to matter.

When I say "will not speak", I mean: calls to ISpVoice::Speak return immediately with the result S_OK; no voice was synthesized.

Correction: the above happens in the D version when the debugger is not attached. When the Visual Studio debugger is attached, an access violation occurs at vtjpnsapi50.dll!10004e65. Also, the access violation happens in the C++ version regardless of whether a debugger is attached or debug information is generated.

Inserting a call to sleep inbetween the calls to Speak does not change anything (except, of course, that it inserts a delay).

Reproduction in D (C++ equivalent is below):

import std.c.windows.com;
import core.sys.windows.windows;
import speech.windows.sapi;

import std.stdio;

int main()
{
    if (FAILED(CoInitialize(null)))
        return 1;

    scope(exit) CoUninitialize();

    ISpVoice pVoice;
    HRESULT hr = CoCreateInstance(&CLSID_SpVoice, null, CLSCTX_ALL, &IID_ISpVoice, cast(void**)&pVoice);
    assert(hr == S_OK);
    hr = pVoice.Speak("Hello world", 0, null); // This speaks fine
    assert(hr == S_OK);

    ISpVoice pVoice2;
    hr = CoCreateInstance(&CLSID_SpVoice, null, CLSCTX_ALL, &IID_ISpVoice, cast(void**)&pVoice2);
    assert(hr == S_OK);
    hr = pVoice2.Speak("hello again", 0, null); // This returns immediately
    assert(hr == S_OK); // Yet it still returns S_OK

    hr = pVoice.Speak("first voice again", 0, null); // This speaks fine too, immediately after "hello world" finishes
    assert(hr == S_OK);

    // The two objects are indeed at different memory addresses
    writefln("voice 1: %s, voice 2: %s", cast(void*)pVoice, cast(void*)pVoice2);

    pVoice.Release();
    pVoice = null;

    pVoice2.Release();
    pVoice2 = null;

    return 0;
}

This is the equivalent C++ program:

#include <sapi.h>
#include<Windows.h>

int main()
{
    if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
        return 1;

    ISpVoice* pVoice;
    HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void**)&pVoice);
    hr = pVoice->Speak(L"Hello world", 0, NULL); // This speaks fine

    ISpVoice* pVoice2;
    hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void**)&pVoice2);
    hr = pVoice2->Speak(L"hello again", 0, NULL); // This causes an access violation

    hr = pVoice->Speak(L"first voice again", 0, NULL);

    pVoice->Release();
    pVoice = NULL;

    pVoice2->Release();
    pVoice2 = NULL;

    CoUninitialize();

    return 0;
}

In the above example, both voices are allocated with the same parameters, and the first voice to speak works properly. In the D version when a debugger is not attached, the second call to Speak on pVoice also works.

If anyone has any idea what could cause this, or know about any open source software where multiple voice objects are used, please let me know, thanks!

edit This only happens with NeoSpeech's voices. It works fine with Microsoft's and eSpeak's voices. I'd still like to know if there's anything I could do to remedy the problem (NeoSpeech has some really, really good voices...).

jA_cOp
  • 3,275
  • 19
  • 15
  • Call WaitUntilDone() to be sure it is done speaking before you try to make it speak again. – Hans Passant Oct 04 '12 at 14:18
  • @HansPassant, it segfaults regardless of how long I wait. – jA_cOp Oct 04 '12 at 14:23
  • This is not the Microsoft version of SAPI, contact the vendor for support. – Hans Passant Oct 04 '12 at 14:25
  • @HansPassant, the C++ version uses `sapi.h` from the Windows SDK and exhibits the same problem. The D version simply uses a binding for `sapi.h` that I ported myself. This is definitely Microsoft's SAPI. If you are talking about the problematic voices, the NeoSpeech voices are added with the SAPI DDI just like every other SAPI voice, but yes, I suspect there might be a bug in their implementation, but I'd like to know whether I'm doing anything wrong in the application code. – jA_cOp Oct 05 '12 at 01:30

0 Answers0