Posted By: medvidek (Blazni umiraji nadvakrat) on 'CZprogram'
Title:     Problem s MS SpeechAPI 4
Date:      Tue Aug  3 09:48:31 2004

Nevim, kolik lidi tady nekdy delalo s MS speechAPI, ale nepodarilo se mi na 
netu najit jedine forum nebo news grupu, ktera by se zabyvala SAPI a trochu 
to tam zilo, tak to zkusim dat sem. Dotaz je v anglictine, protoze jsem si ho 
pripravil pro ta neexistujici (schovana?) fora a nechce se mi to prepisovat. 
Predpokladam, ze to tu nikomu vadit nebude.

---------------

I am quite familiar with SAPI5 but I am new to SAPI4. I tried to create
a simple test application and it doesn't work as expected. I hope somebody
more experienced could help me to explain the behaviour and find the right
way of doing it.

All I want to do is to speak a sentence and wait until it is spoken. But
the wainting has to be non-blocking. In order to achieve this we create
a notification object to catch speech engine notification events. The
strange thing is that the methods of the notification object are called
only if we ask the engine periodically whether speking is in progress.
I have no idea why and what's wrong.

A simple windows console application that demonstrates the behaviour is
included. The interesting part is near to the end of the source and is
marked with a line of asterisks.

Could anybody help me?

Thanks a lot.

The code follows:
-----------------------------------------------------------------
// this code is a windows console application

#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <initguid.h>
#include <speech.h>

#ifdef _S_UNICODE
  #error we do not want unicode for now
#endif

HANDLE finishedEvent;

// Voice Message notifications
class CIVTxtNotifySink : public IVTxtNotifySink {
private:
  DWORD refCnt;

  public:
  CIVTxtNotifySink();
  ~CIVTxtNotifySink();

  // IUnkown members
  STDMETHODIMP QueryInterface (REFIID, LPVOID FAR *);
  STDMETHODIMP_(ULONG) AddRef(void);
  STDMETHODIMP_(ULONG) Release(void);

  // IVTxtNotifySink members
  STDMETHODIMP AttribChanged    (DWORD);
  STDMETHODIMP Visual           (WCHAR, char, DWORD, PTTSMOUTH);
  STDMETHODIMP Speak            (PSTR, PSTR, DWORD);
  STDMETHODIMP SpeakingStarted  (void);
  STDMETHODIMP SpeakingDone     (void);
};

CIVTxtNotifySink::CIVTxtNotifySink() {
  refCnt = 0;
}

CIVTxtNotifySink::~CIVTxtNotifySink (void) {
}

STDMETHODIMP CIVTxtNotifySink::QueryInterface (REFIID riid, LPVOID *ppv) {
  *ppv = NULL;

  // always return our IUnkown for IID_IUnknown
  if (IsEqualIID (riid, IID_IUnknown)
      || IsEqualIID(riid,IID_IVTxtNotifySink))
  {
    *ppv = (LPVOID) this;
    AddRef();
    return NOERROR;
  }

  // otherwise, cant find
  return E_NOINTERFACE;
}

STDMETHODIMP_ (ULONG) CIVTxtNotifySink::AddRef (void) {
  return ++refCnt;
}

STDMETHODIMP_(ULONG) CIVTxtNotifySink::Release (void) {
  if( --refCnt == 0 )
  {
    // reference count is 0, delete the object...
    delete this;
    return 0;
  }
  return refCnt;
}

STDMETHODIMP CIVTxtNotifySink::AttribChanged(DWORD dwAttribute) {
  std::cout << "NOTIFICATION: Attribute changed" << std::endl;
  return NOERROR;
}

STDMETHODIMP CIVTxtNotifySink::SpeakingStarted(void) {
  std::cout << "NOTIFICATION: Speaking started" << std::endl;
  return NOERROR;
}

STDMETHODIMP CIVTxtNotifySink::SpeakingDone(void) {
  std::cout << "NOTIFICATION: Speaking done" << std::endl;
  SetEvent (finishedEvent);
  return NOERROR;
}

STDMETHODIMP CIVTxtNotifySink::Visual(WCHAR cIPAPhoneme, char cEnginePhoneme,
                                      DWORD dwFlags, PTTSMOUTH pTTSMouth)
{
  std::cout << "NOTIFICATION: Visual" << std::endl;
  return NOERROR;
}

STDMETHODIMP CIVTxtNotifySink::Speak(PSTR pszMessage, PSTR pszApplication,
                                     DWORD dwTyep)
{
  std::cout << "NOTIFICATION: Speak (" << pszMessage << ")" << std::endl;
  return NOERROR;
}

int main(int argc,char *argv[]) {
  HRESULT hr;
  PIVOICETEXT voiceText = NULL;
  PIVTXTATTRIBUTES vTxtAttributes = NULL;
  CIVTxtNotifySink* notifySink = NULL;

  finishedEvent = CreateEvent (NULL, true, false, NULL);
  if (finishedEvent == INVALID_HANDLE_VALUE) {
    std::cout << "Cannot create event" << std::endl;
    return 1;
  }

  hr = CoInitialize(NULL);
  if (!SUCCEEDED(hr)) {
    std::cout << "ERROR: COM initialization failed" << std::endl;
    return 1;
  }

  // Create a voice text object...
  hr = CoCreateInstance (CLSID_VTxt, NULL, CLSCTX_LOCAL_SERVER,
                         IID_IVoiceText, (LPVOID *)&voiceText);
  if (hr != S_OK) {
    std::cout << "ERROR: Unable to create speak object." << std::endl;
    return 1;
  }

  hr = voiceText->QueryInterface (IID_IVTxtAttributes, 
(PVOID*)&vTxtAttributes);
  if (!SUCCEEDED(hr)) {
    std::cout << "ERROR: Cannot get IVTxtAttributes interface." << std::endl;
    return 1;
  }

  notifySink = new CIVTxtNotifySink();
  if (!notifySink) {
    std::cout << "ERROR: Unable to create notify sink." << std::endl;
    return 1;
  }

  // initialize speak object
  hr = voiceText->Register (NULL, "test", notifySink, IID_IVTxtNotifySink,
                            0, NULL);
  if (!SUCCEEDED(hr)) {
    std::cout << "ERROR: Unable to register speak object." << std::endl;
    return 1;
  }

  hr = voiceText->Speak ("This is a test.", 0, NULL);
  if (!SUCCEEDED(hr)) {
    std::cout << "ERROR: Speak failed." << std::endl;
    return 1;
  }

  // *******************************************************************
  // Wait until speaking is done.
  //
  // Simple WaitForSingleObject (finishedEvent, timeout); does not work.
  // This loop does work but only when we ask periodically the engine
  // whether speking is in progress. If we comment out the lines that do
  // the asking, it stops working
  DWORD result;
  for (int i = 0; i < 100; i++) {

    // if we comment out the following two lines, it doesn't work
    BOOL speaking;
    vTxtAttributes->IsSpeaking (&speaking);

    result = WaitForSingleObject (finishedEvent, 50);
    if (result == WAIT_OBJECT_0) {
      // Speaking done notification received
      break;
    }
  }
  if (result == WAIT_TIMEOUT) {
    std::cout << "ERROR: Timeout." << std::endl;
  }

  std::cout << "Destroying" << std::endl;

  delete notifySink;
  voiceText->Release();
  CoUninitialize();

  return 0;
}
 

                 medvidek

--
There are 4 boxes to use in the defense of liberty:
soap, ballot, jury, ammo.
Use in that order.

Search the boards