Обнаружен ключ к проблеме / вылету, смотрите внизу поста.
При создании экземпляров ISpVoice
с помощью CoCreateInstance
Кажется, что случаи, когда первый человек не может говорить, как только первый из них говорит. То есть если pVoice
говорит первым, pVoice2
не буду говорить. Если pVoice2
говорит первым, pVoice
не буду говорить. Порядок создания / размещения не имеет значения.
Когда я говорю «не буду говорить», я имею в виду: призывы к ISpVoice::Speak
немедленно вернуться с результатом S_OK
; голос не был синтезирован.
Исправление: вышеописанное происходит в версии D, когда отладчик не подключен. Когда отладчик Visual Studio подключен, нарушение прав доступа происходит в vtjpnsapi50.dll!10004e65
, Кроме того, нарушение прав доступа происходит в версии C ++ независимо от того, подключен ли отладчик или генерируется отладочная информация.
Вставка звонка в sleep
Между вызовами Speak ничего не меняется (за исключением, конечно, того, что он вставляет задержку).
Воспроизведение в D (эквивалент C ++ ниже):
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;
}
Это эквивалентная программа на C ++:
#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;
}
В приведенном выше примере оба голоса распределены с одинаковыми параметрами, и первый голос, который говорит, работает правильно. В версии D, когда отладчик не подключен, второй вызов Speak
на pVoice
тоже работает.
Если кто-нибудь знает, что может вызвать это, или знает о каком-либо программном обеспечении с открытым исходным кодом, где используются несколько голосовых объектов, пожалуйста, дайте мне знать, спасибо!
редактировать
Это происходит только с голосами NeoSpeech. Он прекрасно работает с голосами Microsoft и eSpeak. Я все еще хотел бы знать, могу ли я что-нибудь сделать, чтобы решить проблему (у NeoSpeech есть действительно очень хорошие голоса …).
Задача ещё не решена.
Других решений пока нет …