VXIrec.cpp
上传用户:xqtpzdz
上传日期:2022-05-21
资源大小:1764k
文件大小:30k
源码类别:

xml/soap/webservice

开发平台:

Visual C++

  1. /****************License************************************************
  2.  * Vocalocity OpenVXI
  3.  * Copyright (C) 2004-2005 by Vocalocity, Inc. All Rights Reserved.
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  *  
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17.  * Vocalocity, the Vocalocity logo, and VocalOS are trademarks or 
  18.  * registered trademarks of Vocalocity, Inc. 
  19.  * OpenVXI is a trademark of Scansoft, Inc. and used under license 
  20.  * by Vocalocity.
  21.  ***********************************************************************/
  22. #define VXIREC_EXPORTS
  23. #include "VXIrecAPI.h"
  24. #include "VXIrec_utils.h"
  25. #include "LogBlock.hpp"
  26. #include <cstdio>
  27. #include <cstring>
  28. #include <sstream>
  29. // ------*---------*---------*---------*---------*---------*---------*---------
  30. static void ResultContentDestroy(VXIbyte **content, void *userData)
  31. {
  32.   if (content && *content)
  33.     delete [] *content;
  34.   *content = NULL;
  35. }
  36. class VXIVectorHolder {
  37. public:
  38.   VXIVectorHolder() : _vector(NULL)  { _vector = VXIVectorCreate(); }
  39.   VXIVectorHolder(VXIVector * m) : _vector(m) { }
  40.   ~VXIVectorHolder()        { if (_vector != NULL) VXIVectorDestroy(&_vector);}
  41.   VXIVectorHolder & operator=(const VXIVectorHolder & x)
  42.   { if (this != &x) {
  43.       if (_vector != NULL) VXIVectorDestroy(&_vector);
  44.       _vector = VXIVectorClone(x._vector); }
  45.     return *this; }
  46.   // GetValue returns the internal vector.  The standard vector manipulation
  47.   // functions may then be used.
  48.   VXIVector * GetValue() const       { return _vector; }
  49.   // These functions allow the holder to take ownership of an existing vector
  50.   // or to release the internal one.
  51.   VXIVector * Release()  
  52.   { VXIVector * m = _vector; _vector = NULL; return m; }
  53.   void Acquire(VXIVector * m)
  54.   { if (_vector != NULL) VXIVectorDestroy(&_vector); else _vector = m; }
  55. private:
  56.   VXIVectorHolder(const VXIVectorHolder &);   // intentionally not defined.
  57.   VXIVector * _vector;
  58. };
  59. // ------*---------*---------*---------*---------*---------*---------*---------
  60. // Global for the base diagnostic tag ID, see osbrec_utils.h for tags
  61. //
  62. static VXIunsigned gblDiagLogBase = 0;
  63. // VXIrec implementation of the VXIrec interface
  64. //
  65. extern "C" {
  66.   struct VXIrecImpl {
  67.     // Base interface, must be first
  68.     VXIrecInterface intf;
  69.     // Class for managing grammars
  70.     VXIrecData *recData;
  71.   };
  72. }
  73. // A few conversion functions...
  74. static inline VXIrecGrammar * ToVXIrecGrammar(VXIrecGrammar * i)
  75. { return reinterpret_cast<VXIrecGrammar *>(i); }
  76. static inline VXIrecGrammar * FromVXIrecGrammar(VXIrecGrammar * i)
  77. { return reinterpret_cast<VXIrecGrammar *>(i); }
  78. static inline VXIrecData * GetRecData(VXIrecInterface * i)
  79. {
  80.   if (i == NULL) return NULL;
  81.   return reinterpret_cast<VXIrecImpl *>(i)->recData;
  82. }
  83. /*******************************************************
  84.  * Method routines for VXIrecInterface structure
  85.  *******************************************************/ 
  86. // Get the VXIrec interface version supported
  87. //
  88. static VXIint32 VXIrecGetVersion(void)
  89. {
  90.   return VXI_CURRENT_VERSION;
  91. }
  92. // Get the implementation name
  93. //
  94. static const VXIchar* VXIrecGetImplementationName(void)
  95. {
  96.   static const VXIchar IMPLEMENTATION_NAME[] = COMPANY_DOMAIN L".VXIrec";
  97.   return IMPLEMENTATION_NAME;
  98. }
  99. static VXIrecResult VXIrecBeginSession(VXIrecInterface * pThis, VXIMap *)
  100. {
  101.   const wchar_t* fnname = L"VXIrecBeginSession";
  102.   VXIrecData* tp = GetRecData(pThis);
  103.   
  104.   if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT;
  105.   LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE);
  106.   
  107.   return VXIrec_RESULT_SUCCESS;
  108. }
  109. static VXIrecResult VXIrecEndSession(VXIrecInterface *pThis, VXIMap *)
  110. {
  111.   const wchar_t* fnname = L"VXIrecEndSession";
  112.   VXIrecData* tp = GetRecData(pThis);
  113.   if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT;
  114.   LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE);
  115.   tp->Clear();
  116.   return VXIrec_RESULT_SUCCESS;
  117. }
  118. static VXIrecResult VXIrecLoadGrammarFromString(VXIrecInterface *pThis,
  119.                                                 const VXIMap *prop,
  120.                                                 const VXIchar *type,
  121.                                                 const VXIchar *str,
  122.                                                 VXIrecGrammar **gram)
  123. {
  124.   const wchar_t* fnname = L"VXIrecLoadGrammarFromString";
  125.   VXIrecData* tp = GetRecData(pThis);
  126.   if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT;
  127.   LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE);
  128.   // Check the arguments
  129.   if (str == NULL) {
  130.     logger = VXIrec_RESULT_INVALID_ARGUMENT;
  131.     return VXIrec_RESULT_INVALID_ARGUMENT;
  132.   }
  133.   if (type == NULL) {
  134.     logger = VXIrec_RESULT_UNSUPPORTED;
  135.     return VXIrec_RESULT_UNSUPPORTED;
  136.   }
  137.   
  138.   VXIrecGrammar * gp = NULL;
  139.   vxistring srgsGram, mtype(type);
  140.   
  141.   logger.logDiag(DIAG_TAG_GRAMMARS, L"%s%s", L"TYPE: ", mtype.c_str());
  142.   tp->ShowPropertyValue(prop);
  143.   
  144.   if( mtype == L"application/x-jsgf" || mtype == REC_MIME_CHOICE || mtype == REC_MIME_CHOICE_DTMF)
  145.   {
  146.     // first crack the srgs grammar
  147.     JSGFInfo info;
  148.     tp->ConvertJSGFType(str, info);
  149.     // then try to convert to SRGS format 
  150.     if( !tp->JSGFToSRGS(info.contentStr, srgsGram, prop) ) return  VXIrec_RESULT_FAILURE;
  151.     mtype = VXI_MIME_SRGS; // reset mime type
  152.     logger.logDiag(DIAG_TAG_GRAMMARS, L"%s%s", L"Converted GRAMMAR: ", srgsGram.c_str());   
  153.   }
  154.   else if( mtype == VXI_MIME_SRGS ) {
  155.     // processing below  
  156.     srgsGram = str;
  157.   }
  158.   else {
  159.     // Handle your own type here, return unsupported for now
  160.     logger = VXIrec_RESULT_UNSUPPORTED;
  161.     return VXIrec_RESULT_UNSUPPORTED;
  162.   }
  163.   
  164.   // Parsing SRGS grammar.
  165.   // NOTES: The parsing is very simple, therefore it may not work
  166.   // for complex grammar.  As you know, this is a simulator!!!
  167.   
  168.   VXIrecGrammar * gramPtr = tp->ParseSRGSGrammar(srgsGram, prop);
  169.   if( gramPtr == NULL ) return VXIrec_RESULT_FAILURE;
  170.   tp->AddGrammar(gramPtr);
  171.   *gram = ToVXIrecGrammar(gramPtr);
  172.   return VXIrec_RESULT_SUCCESS;
  173. }
  174. static VXIrecResult VXIrecLoadGrammarFromURI(struct VXIrecInterface *pThis,
  175.                                              const VXIMap *properties,
  176.                                              const VXIchar *type, 
  177.                                              const VXIchar *uri,
  178.                                              const VXIMap *uriArgs,
  179.                                              VXIrecGrammar **gram)
  180. {
  181.   VXIrecData* tp = GetRecData(pThis);
  182.   if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT;
  183.   const wchar_t* fnname = L"VXIrecLoadGrammarFromURI";
  184.   LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE);
  185.   tp->ShowPropertyValue(properties);
  186.   if (wcsncmp(uri, L"builtin", 7) == 0 ){
  187.     logger.logDiag(DIAG_TAG_GRAMMARS, L"%s", L"built-in not supported");
  188.     return VXIrec_RESULT_UNSUPPORTED;
  189.   }
  190.   VXIbyte *buffer = NULL;
  191.   VXIulong read = 0;
  192.   if (!tp->FetchContent(uri, uriArgs, &buffer, read))
  193.     return VXIrec_RESULT_FAILURE;
  194.   // NOTE:  this code assumes the retieved buffer is
  195.   // composed of single byte chars.  in the real world,
  196.   // that can't be assumed.
  197.   buffer[read] = 0;
  198.   VXIchar *charbuff = new VXIchar[read+1];
  199.   mbstowcs(charbuff, (char*)buffer, read+1);
  200.   VXIrecResult rc = VXIrecLoadGrammarFromString(pThis, properties,
  201.     type, charbuff, gram);
  202.   delete[] buffer;
  203.   delete[] charbuff;
  204.   return rc;
  205. }
  206. static VXIrecResult VXIrecLoadGrammarOption(VXIrecInterface * pThis,
  207.                                       const VXIMap    * properties,
  208.                                       const VXIVector * gramChoice,
  209.                                       const VXIVector * gramValue,
  210.                                       const VXIVector * gramAcceptance,
  211.                                       const VXIbool     isDTMF,
  212.                                       VXIrecGrammar  ** gram)
  213. {
  214.   const wchar_t* fnname = L"VXIrecLoadGrammarOption";
  215.   // Check the arguments
  216.   VXIrecData* tp = GetRecData(pThis);
  217.   if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT;
  218.   LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE);
  219.     
  220.   if (gram == NULL) {
  221.     logger = VXIrec_RESULT_INVALID_ARGUMENT;
  222.     return VXIrec_RESULT_INVALID_ARGUMENT;
  223.   }
  224.   tp->ShowPropertyValue(properties);
  225.   
  226.   VXIrecGrammar * gp = NULL;
  227.   
  228.   vxistring srgsGram;
  229.   if( !tp->OptionToSRGS(properties, gramChoice, gramValue, 
  230.                        gramAcceptance, isDTMF, srgsGram) )
  231.     return VXIrec_RESULT_FAILURE;
  232.   // Parsing SRGS grammar.
  233.   // NOTES: The parsing is very simple, therefore it may not work
  234.   // for complex grammar.  As you know, this is a simulator!!!
  235.   
  236.   VXIrecGrammar * gramPtr = tp->ParseSRGSGrammar(srgsGram, properties, isDTMF);
  237.   if( gramPtr == NULL ) return VXIrec_RESULT_FAILURE;
  238.   tp->AddGrammar(gramPtr);
  239.   *gram = ToVXIrecGrammar(gramPtr);
  240.   return VXIrec_RESULT_SUCCESS;
  241. }
  242. static VXIrecResult VXIrecFreeGrammar(VXIrecInterface *pThis,
  243.                                       VXIrecGrammar **gram)
  244. {
  245.   const wchar_t* fnname = L"VXIrecFreeGrammar";
  246.   // Check the arguments
  247.   VXIrecData* tp = GetRecData(pThis);
  248.   if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT;
  249.   LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE);
  250.   // If the grammar pointer is null, there is nothing to free.
  251.   if (gram == NULL || *gram == NULL) VXIrec_RESULT_SUCCESS;
  252.   tp->FreeGrammar(FromVXIrecGrammar(*gram));
  253.   *gram = NULL;
  254.   return VXIrec_RESULT_SUCCESS;
  255. }
  256. static VXIrecResult VXIrecActivateGrammar(VXIrecInterface *pThis,
  257.                                           const VXIMap *properties,
  258.                                           VXIrecGrammar *gram)
  259. {
  260.   const wchar_t* fnname = L"VXIrecActivateGrammar";
  261.   VXIrecData* tp = GetRecData(pThis);
  262.   if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT;
  263.   LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE);
  264.   if (gram == NULL) {
  265.     logger = VXIrec_RESULT_INVALID_ARGUMENT;
  266.     return VXIrec_RESULT_INVALID_ARGUMENT;
  267.   }
  268.   tp->ActivateGrammar(FromVXIrecGrammar(gram));
  269.   return VXIrec_RESULT_SUCCESS;
  270. }
  271. static VXIrecResult VXIrecDeactivateGrammar(VXIrecInterface *pThis,
  272.                                             VXIrecGrammar *gram)
  273. {
  274.   const wchar_t* fnname = L"VXIrecDeactivateGrammar";
  275.   VXIrecData* tp = GetRecData(pThis);
  276.   if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT;
  277.   LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE);
  278.   if (gram == NULL) 
  279.   {
  280.     logger = VXIrec_RESULT_INVALID_ARGUMENT;
  281.     return VXIrec_RESULT_INVALID_ARGUMENT;
  282.   }
  283.   tp->DeactivateGrammar(FromVXIrecGrammar(gram));
  284.   return VXIrec_RESULT_SUCCESS;
  285. }
  286. /*******************************************************
  287.  * Recognize related
  288.  *******************************************************/ 
  289. static void RecognitionResultDestroy(VXIrecRecognitionResult **Result)
  290. {
  291.   if (Result == NULL || *Result == NULL) return;
  292.   VXIrecRecognitionResult * result = *Result;
  293.   if (result->utterance != NULL)
  294.     VXIContentDestroy(&result->utterance);
  295.   if (result->xmlresult != NULL)
  296.     VXIContentDestroy(&result->xmlresult);
  297.   if (result->markname != NULL)
  298.     VXIStringDestroy(&result->markname);
  299.   delete result;
  300.   *Result = NULL;
  301. }
  302. static void TransferResultDestroy(VXIrecTransferResult **Result)
  303. {
  304.   if (Result == NULL || *Result == NULL) return;
  305.   VXIrecTransferResult * result = *Result;
  306.   if (result->utterance != NULL)
  307.     VXIContentDestroy(&result->utterance);
  308.   if (result->xmlresult != NULL)
  309.     VXIContentDestroy(&result->xmlresult);
  310.   if (result->markname != NULL)
  311.     VXIStringDestroy(&result->markname);
  312.   delete result;
  313.   *Result = NULL;
  314. }
  315. static const unsigned int NLSML_NOINPUT_SIZE = 109;
  316. static const VXIchar NLSML_NOINPUT[NLSML_NOINPUT_SIZE] =
  317.   L"<?xml version='1.0'?>"
  318.   L"<result>"
  319.     L"<interpretation>"
  320.       L"<instance/>"
  321.       L"<input><noinput/></input>"
  322.     L"</interpretation>"
  323.   L"</result>";
  324. static const unsigned int NLSML_NOMATCH_SIZE = 109;
  325. static const VXIchar NLSML_NOMATCH[NLSML_NOMATCH_SIZE] =
  326.   L"<?xml version='1.0'?>"
  327.   L"<result>"
  328.     L"<interpretation>"
  329.       L"<instance/>"
  330.       L"<input><nomatch/></input>"
  331.     L"</interpretation>"
  332.   L"</result>";
  333. void DestroyNLSMLBuffer(VXIbyte ** buffer, void * ok)
  334. {
  335.   // Return immediate if we know the buffer is static memory, 
  336.   // i.e: noinput, nomatch as defined above
  337.   if (ok == NULL || buffer == NULL) return;
  338.   // otherwise reclaim the memory
  339.   delete[] (*buffer);
  340.   *buffer = NULL;
  341. }
  342. static VXIrecResult VXIrecRecognize(VXIrecInterface *pThis,
  343.                                     const VXIMap *properties,
  344.                                     VXIrecRecognitionResult **recogResult)
  345. {
  346.   const wchar_t* fnname = L"VXIrecRecognize";
  347.   VXIrecData* tp = GetRecData(pThis);
  348.   if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT;
  349.   LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE);
  350.   VXIchar* input = NULL;
  351.   VXIMap*  res  = NULL;
  352.   VXIchar* str  = NULL;
  353.   VXIchar console[512];
  354.   bool recordUtterance = false;
  355.   bool haveUtterance = true;
  356.     
  357.   if (properties != NULL) {
  358.     const VXIValue * ru = VXIMapGetProperty(properties, REC_RECORDUTTERANCE);
  359.     if (ru)
  360.       recordUtterance = wcscmp(VXIStringCStr((const VXIString*)ru), L"true") == 0;
  361.     const VXIValue * val = VXIMapGetProperty(properties, L"SpeechInput");
  362.     if( val ) {
  363.        logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%s", L"SpeechInput: ",
  364.                       VXIStringCStr((const VXIString*)val));
  365.     }
  366.     if (val == NULL || VXIValueGetType(val) != VALUE_STRING) {
  367.       val = VXIMapGetProperty(properties, L"DTMFInput");
  368.       if( val ) {
  369.         logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%s", L"DTMFInput: ",
  370.                        VXIStringCStr((const VXIString*)val));      
  371.       }
  372.     }
  373.     VXIString* vect = (VXIString*) val;
  374.     if (vect != NULL) input = (VXIchar*) VXIStringCStr(vect);
  375.     if (input && wcscmp(input, L"-") == 0) {
  376.       unsigned int i;
  377.       VXIchar* cp = console;
  378.       char lbuf[512];
  379.       printf("Console: ");
  380.       fgets(lbuf, 511, stdin);
  381.       // copy to VXIchar
  382.       for(i = 0; i < strlen(lbuf); ++i) {
  383.         if (lbuf[i] == 'r' || lbuf[i] == 'n') continue;
  384.         *cp++ = lbuf[i] & 0x7f;
  385.       }
  386.       *cp++ = 0;
  387.       input = console;
  388.       logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%s", L"Input: ", 
  389.                      (input ? input : L"NULL"));
  390.     }
  391.   }
  392.   // Create a new results structure.
  393.   const unsigned int CHARSIZE = sizeof(VXIchar) / sizeof(VXIbyte);
  394.   VXIContent * xmlresult = NULL;
  395.   // Looking for matched phrase, if not act appropriately
  396.   vxistring nlsmlresult;
  397.   bool found = tp->ConstructNLSMLForInput(input, nlsmlresult);  
  398.   if( !found ) {
  399.     if( !input || input[0] == L'' ) {
  400.       // No input case
  401.       haveUtterance = false;
  402.       logger.logDiag(DIAG_TAG_RECOGNITION, L"%s", L"-- NO_INPUT RESULT --");
  403.       xmlresult = VXIContentCreate(VXIREC_MIMETYPE_XMLRESULT,
  404.                                    (VXIbyte *) NLSML_NOINPUT,
  405.                                    NLSML_NOINPUT_SIZE * CHARSIZE,
  406.                                    DestroyNLSMLBuffer, NULL);    
  407.     } else {
  408.       // No match case
  409.       logger.logDiag(DIAG_TAG_RECOGNITION, L"%s", L"-- NO_MATCH RESULT --");
  410.       xmlresult = VXIContentCreate(VXIREC_MIMETYPE_XMLRESULT,
  411.                                    (VXIbyte *) NLSML_NOMATCH,
  412.                                    NLSML_NOMATCH_SIZE * CHARSIZE,
  413.                                    DestroyNLSMLBuffer, NULL);      
  414.     }
  415.   }
  416.   else {
  417.     // Found matched grammar  
  418.     logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%s", L"NLSML_RESULT: ", 
  419.                    nlsmlresult.c_str());
  420.     
  421.     unsigned int BUFFERSIZE = (nlsmlresult.length() + 1) * CHARSIZE;
  422.     VXIbyte * buffer = new VXIbyte[BUFFERSIZE];
  423.     if (buffer == NULL) return VXIrec_RESULT_OUT_OF_MEMORY;
  424.     memcpy(buffer, nlsmlresult.c_str(), BUFFERSIZE);
  425.     xmlresult = VXIContentCreate(VXIREC_MIMETYPE_XMLRESULT,
  426.                                  buffer, BUFFERSIZE,
  427.                                  DestroyNLSMLBuffer, buffer);
  428.     if (xmlresult == NULL) {
  429.       delete [] buffer;
  430.       return VXIrec_RESULT_OUT_OF_MEMORY;
  431.     }
  432.   }
  433.   VXIrecRecognitionResult * result = new VXIrecRecognitionResult();
  434.   if (result == NULL) {
  435.     VXIContentDestroy(&xmlresult);
  436.     return VXIrec_RESULT_OUT_OF_MEMORY;
  437.   }
  438.   result->Destroy = RecognitionResultDestroy;
  439.   result->markname = NULL;
  440.   result->marktime = 0;
  441.   result->xmlresult = xmlresult;
  442.   if (!haveUtterance ||!recordUtterance) {
  443.     result->utterance = NULL;
  444.     result->utteranceDuration = 0;
  445.   }
  446.   else {
  447.     result->utteranceDuration = 5000; // 5sec
  448.     unsigned int waveformSizeBytes = (result->utteranceDuration / 1000 ) * 8000 * sizeof(unsigned char);
  449.     unsigned char * c_waveform = new unsigned char[waveformSizeBytes];
  450.     if (c_waveform == NULL) {
  451.       result->utterance = NULL;
  452.       result->utteranceDuration = 0;
  453.     }
  454.     else {
  455.       for (unsigned int i = 0; i < waveformSizeBytes; ++i)
  456.         c_waveform[i] = i & 0x00ff;
  457.       result->utterance = VXIContentCreate(VXIREC_MIMETYPE_ULAW,
  458.                                            c_waveform, waveformSizeBytes,
  459.                                            ResultContentDestroy, NULL);  
  460.     }
  461.   }
  462.   *recogResult = result;
  463.   return VXIrec_RESULT_SUCCESS;
  464. }
  465. static VXIrecResult VXIrecGetMatchedGrammar(VXIrecInterface *pThis,
  466.                                             const VXIchar *grammarID,
  467.                                             const VXIrecGrammar **gram)
  468. {
  469.   const wchar_t* fnname = L"VXIrecGetMatchedGrammar";
  470.   VXIrecData* tp = GetRecData(pThis);
  471.   if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT;
  472.   LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE);
  473.   if (grammarID == NULL || gram == NULL)
  474.     return VXIrec_RESULT_INVALID_ARGUMENT;
  475.   VXIrecGrammar * mgram = NULL;
  476.   SWIswscanf(grammarID, L"%p", &mgram);
  477.   *gram = mgram;
  478.   logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%p", L"Got Matched grammar: ", mgram); 
  479.   return VXIrec_RESULT_SUCCESS;
  480. }
  481. static void RecordResultDestroy(VXIrecRecordResult **Result)
  482. {
  483.   if (Result == NULL || *Result == NULL) return;
  484.   VXIrecRecordResult * result = *Result;
  485.   if (result->waveform != NULL)
  486.     VXIContentDestroy(&result->waveform);
  487.   if (result->xmlresult != NULL)
  488.     VXIContentDestroy(&result->xmlresult);
  489.   delete result;
  490.   *Result = NULL;
  491. }
  492. static VXIrecResult VXIrecRecord(VXIrecInterface *pThis,
  493.                                  const VXIMap *props,
  494.                                  VXIrecRecordResult **recordResult)
  495. {
  496.   const wchar_t* fnname = L"VXIrecRecord";
  497.   VXIrecData* tp = GetRecData(pThis);
  498.   if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT;
  499.   LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE);
  500.   if (recordResult == NULL) {
  501.     logger = VXIrec_RESULT_INVALID_ARGUMENT;
  502.     return VXIrec_RESULT_INVALID_ARGUMENT;
  503.   }
  504.   // (1) Create record structure
  505.   VXIrecRecordResult *result = new VXIrecRecordResult();
  506.   if (result == NULL) {
  507.     logger = VXIrec_RESULT_OUT_OF_MEMORY;
  508.     return VXIrec_RESULT_OUT_OF_MEMORY;
  509.   }
  510.   result->Destroy = RecordResultDestroy;
  511.   result->waveform = NULL;
  512.   result->xmlresult = NULL;
  513.   result->duration = 0;
  514.   result->termchar = 0;
  515.   result->maxtime = FALSE;
  516.   result->markname = NULL;
  517.   result->marktime = 0;
  518.   *recordResult = result;
  519.   VXIlong duration = -1;
  520.   VXIlong maxtime = 0;
  521.   VXIlong finalsilence = 0;
  522.   // (2) Get maxtime
  523.   const VXIValue* val = VXIMapGetProperty(props, REC_MAX_RECORDING_TIME);
  524.   if (val != NULL && VXIValueGetType(val) == VALUE_INTEGER )
  525.     maxtime = VXIIntegerValue(reinterpret_cast<const VXIInteger *>(val));
  526.   else
  527.     maxtime = 1000 * 20; // in milliseconds (default to 20 secs)
  528.   // (2.1) adjust duration for simulator
  529.   if( duration < 0 ) duration = maxtime;
  530.   (*recordResult)->duration = duration;
  531.   if( duration == maxtime ) (*recordResult)->maxtime = TRUE;
  532.   // TODO: this should use the media type.  For now just construct
  533.   // raw ulaw audio with silence
  534.   unsigned int waveformSizeBytes = (duration / 1000 ) * 8000 * sizeof(unsigned char);
  535.   unsigned char * c_waveform = new unsigned char[waveformSizeBytes];
  536.   if (c_waveform == NULL) {
  537.     (*recordResult)->Destroy(recordResult);    
  538.     tp->LogError(400, L"%s%s", L"Error", L"out of memory");
  539.     return VXIrec_RESULT_OUT_OF_MEMORY;
  540.   }
  541.   for (unsigned int i = 0; i < waveformSizeBytes; ++i)
  542.     c_waveform[i] = i & 0x00ff;
  543.   (*recordResult)->waveform = VXIContentCreate(VXIREC_MIMETYPE_ULAW,
  544.                                             c_waveform, waveformSizeBytes,
  545.                                             ResultContentDestroy, NULL);  
  546.   if( (*recordResult)->waveform == NULL ) {
  547.     (*recordResult)->Destroy(recordResult);    
  548.     tp->LogError(400, L"%s%s", L"Error", L"out of memory");
  549.     return VXIrec_RESULT_OUT_OF_MEMORY;    
  550.   }
  551.   return VXIrec_RESULT_SUCCESS;
  552. }
  553. static VXIbool VXIrecSupportsHotwordTransfer(
  554.   struct VXIrecInterface * pThis,
  555.   const VXIMap  * properties,
  556.   const VXIchar * transferDest)
  557. {
  558.   VXIbool result = FALSE;
  559.   // this is really just to demonstrate how the platform could
  560.   // support hotword for some type of transfers, but not others.
  561.   // this could just as easily been based on other properties of
  562.   // the transfer. i.e., destination type, required line type, etc...
  563.   const VXIValue* dval = VXIMapGetProperty(properties, TEL_TRANSFER_TYPE);
  564.   if( dval && VXIValueGetType(dval) == VALUE_STRING ){
  565.     const wchar_t* hid = VXIStringCStr(reinterpret_cast<const VXIString *>(dval));
  566. if (wcscmp(hid, L"consultation") == 0)
  567.       return FALSE;
  568.   }
  569.   dval = VXIMapGetProperty(properties, L"SupportsHotwordTransfer");
  570.   if( dval && VXIValueGetType(dval) == VALUE_STRING ){
  571.     const wchar_t* hid = VXIStringCStr(reinterpret_cast<const VXIString *>(dval));
  572. result = (wcscmp(hid, L"true") == 0) ? TRUE : FALSE;
  573.   }
  574.   return result;
  575. }
  576. static VXIrecResult VXIrecHotwordTransfer
  577. (
  578.   struct VXIrecInterface * pThis,
  579.   struct VXItelInterface * tel,
  580.   const VXIMap *properties,
  581.   const VXIchar* transferDest,
  582.   VXIrecTransferResult  ** transferResult
  583. )
  584. {
  585.   const wchar_t* fnname = L"VXIrecHotwordTransfer";
  586.   VXIrecData* tp = GetRecData(pThis);
  587.   if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT;
  588.   LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE);
  589.   
  590.   VXIrecResult res = VXIrec_RESULT_SUCCESS;
  591.   // this is probably not how it would be done in real life...but for this
  592.   // sample app it will suffice:
  593.   // Do the transfer
  594.   int activeGrammars = tp->GetActiveCount();
  595.   VXIMap *xferResp = NULL;
  596.   VXItelResult xferResult = tel->TransferBridge(tel, properties, transferDest, &xferResp);
  597.   if (xferResult != VXItel_RESULT_SUCCESS) {
  598.     res = VXIrec_RESULT_FAILURE;
  599.   }
  600.   else if (activeGrammars == 0) {
  601.     *transferResult = new VXIrecTransferResult();
  602.     (*transferResult)->Destroy = TransferResultDestroy;
  603.     (*transferResult)->utterance = NULL;
  604.     (*transferResult)->markname = NULL;
  605.     (*transferResult)->marktime = 0;
  606.     (*transferResult)->xmlresult = NULL;
  607.     const VXIValue * v = VXIMapGetProperty(xferResp, TEL_TRANSFER_DURATION);
  608.     if (v != NULL && VXIValueGetType(v) == VALUE_INTEGER)
  609.       (*transferResult)->duration = VXIIntegerValue(reinterpret_cast<const VXIInteger*>(v));
  610.     v = VXIMapGetProperty(xferResp, TEL_TRANSFER_STATUS);
  611.     if (v != NULL && VXIValueGetType(v) == VALUE_INTEGER) {
  612.       long temp = VXIIntegerValue(reinterpret_cast<const VXIInteger *>(v));
  613.       (*transferResult)->status = VXItelTransferStatus(temp);
  614.     }
  615. VXIMapDestroy(&xferResp);
  616.   }
  617.   else {
  618.     // get input from the user.
  619.     VXIrecRecognitionResult *recResult = NULL;
  620.     VXIrecResult localRes = pThis->Recognize(pThis, properties, &recResult);
  621. if (localRes == VXIrec_RESULT_SUCCESS){
  622.       *transferResult = new VXIrecTransferResult();
  623.   if ((*transferResult) == NULL) {
  624.         recResult->Destroy(&recResult);
  625.         VXIMapDestroy(&xferResp);
  626.         return VXIrec_RESULT_OUT_OF_MEMORY;
  627.   }
  628.       // setup the transfer result by first copying the 
  629.   // RecResult.
  630.       (*transferResult)->Destroy = TransferResultDestroy;
  631.       (*transferResult)->utterance = recResult->utterance;
  632.       (*transferResult)->markname = recResult->markname;
  633.   (*transferResult)->marktime = recResult->marktime;
  634.       (*transferResult)->xmlresult = recResult->xmlresult;
  635.   (*transferResult)->duration = 0;
  636.   (*transferResult)->status = VXItel_TRANSFER_FAR_END_DISCONNECT;
  637.       // we no long need the rec result (but we don't want the VXIContent
  638.   // fields destroyed).
  639.   recResult->utterance = NULL;
  640.   recResult->xmlresult = NULL;
  641.   recResult->Destroy(&recResult);
  642.       // translate the status and duration to the transfer result fields.
  643.   // since this code is simply so that Hotword transfers work, any
  644.   // valid recognition (ignoring noinput and nomatch) will set the
  645.   // transfer to "near_end_disconnect".  Otherwise, we pretend that
  646.   // the other end terminated the transfer.
  647.   if((*transferResult)->xmlresult){
  648.     // we're going to ignore noinput and nomatch results.
  649.         const VXIchar * contentType;
  650.         const VXIbyte * content;
  651.         VXIulong contentSize = 0; 
  652.         VXIContentValue((*transferResult)->xmlresult, &contentType, &content, &contentSize);
  653.     // we're going to ignore noinput and nomatch results.
  654.         if (   !wcsstr((VXIchar*)content, L"<noinput/>")
  655. && !wcsstr((VXIchar*)content, L"<nomatch/>")){
  656.           (*transferResult)->status = VXItel_TRANSFER_NEAR_END_DISCONNECT;
  657.         }
  658.       }
  659.   const VXIValue * v = VXIMapGetProperty(xferResp, TEL_TRANSFER_DURATION);
  660.   if (v != NULL && VXIValueGetType(v) == VALUE_INTEGER)
  661.     (*transferResult)->duration = VXIIntegerValue(reinterpret_cast<const VXIInteger*>(v));
  662.   VXIMapDestroy(&xferResp);
  663. }
  664.   }
  665.   return res; 
  666. }
  667. /*******************************************************
  668.  * Init and factory routines
  669.  *******************************************************/ 
  670. static inline VXIrecImpl * ToVXIrecImpl(VXIrecInterface * i)
  671. { return reinterpret_cast<VXIrecImpl *>(i); }
  672. // Global init - Don't need to do much here
  673. //
  674. VXIREC_API VXIrecResult VXIrecInit(VXIlogInterface *log,
  675.    VXIunsigned      diagLogBase,
  676.    VXIMap           *args)
  677. {
  678.   if (!log) return VXIrec_RESULT_INVALID_ARGUMENT;
  679.   gblDiagLogBase = diagLogBase;
  680.   const wchar_t* fnname = L"VXIrecInit";
  681.   LogBlock logger(log, gblDiagLogBase, fnname, VXIREC_MODULE);
  682.   logger = VXIrecData::Initialize(log, diagLogBase);
  683.   return VXIrec_RESULT_SUCCESS;
  684. }
  685. // Global shutdown
  686. //
  687. VXIREC_API VXIrecResult VXIrecShutDown(VXIlogInterface *log)
  688. {
  689.   if (!log) return VXIrec_RESULT_INVALID_ARGUMENT;
  690.   const wchar_t* fnname = L"VXIrecShutDown";
  691.   LogBlock logger(log, gblDiagLogBase, fnname, VXIREC_MODULE);
  692.   logger = VXIrecData::ShutDown();
  693.   return VXIrec_RESULT_SUCCESS;
  694. }
  695. // Create an VXIrecInterface object and return.
  696. //
  697. VXIREC_API VXIrecResult VXIrecCreateResource(VXIlogInterface   *log,
  698.      VXIinetInterface  *inet,
  699.       VXIcacheInterface *cache,
  700.       VXIpromptInterface *prompt,
  701.       VXItelInterface *tel,
  702.      VXIrecInterface  **rec)
  703. {
  704.   if (!log) return VXIrec_RESULT_INVALID_ARGUMENT;
  705.   const wchar_t* fnname = L"VXIrecCreateResource";
  706.   LogBlock logger(log, gblDiagLogBase, fnname, VXIREC_MODULE);
  707.   VXIrecImpl* pp = new VXIrecImpl();
  708.   if (pp == NULL) {
  709.     logger = VXIrec_RESULT_OUT_OF_MEMORY;
  710.     return VXIrec_RESULT_OUT_OF_MEMORY;
  711.   }
  712.   VXIrecData* tp = new VXIrecData(log, inet);
  713.   if (tp == NULL) {
  714.     logger = VXIrec_RESULT_OUT_OF_MEMORY;
  715.     return VXIrec_RESULT_OUT_OF_MEMORY;
  716.   }
  717.   
  718.   pp->recData = tp;
  719.   pp->intf.GetVersion = VXIrecGetVersion;
  720.   pp->intf.GetImplementationName = VXIrecGetImplementationName;
  721.   pp->intf.BeginSession = VXIrecBeginSession;
  722.   pp->intf.EndSession = VXIrecEndSession;
  723.   pp->intf.LoadGrammarURI = VXIrecLoadGrammarFromURI;  
  724.   pp->intf.LoadGrammarString = VXIrecLoadGrammarFromString;
  725.   pp->intf.LoadGrammarOption = VXIrecLoadGrammarOption;
  726.   pp->intf.ActivateGrammar = VXIrecActivateGrammar;
  727.   pp->intf.DeactivateGrammar = VXIrecDeactivateGrammar;
  728.   pp->intf.FreeGrammar = VXIrecFreeGrammar;
  729.   pp->intf.Recognize = VXIrecRecognize;
  730.   pp->intf.Record = VXIrecRecord;
  731.   pp->intf.HotwordTransfer = VXIrecHotwordTransfer;
  732.   pp->intf.SupportsHotwordTransfer = VXIrecSupportsHotwordTransfer;
  733.   pp->intf.GetMatchedGrammar = VXIrecGetMatchedGrammar;
  734.   *rec = &pp->intf;
  735.   return VXIrec_RESULT_SUCCESS;
  736. }
  737. // Free VXIrec structure allocated in VXIrecCreateResource.
  738. //
  739. VXIREC_API VXIrecResult VXIrecDestroyResource(VXIrecInterface **rec)
  740. {
  741.   if (rec == NULL || *rec == NULL) return VXIrec_RESULT_INVALID_ARGUMENT;
  742.   VXIrecImpl* recImpl = reinterpret_cast<VXIrecImpl*>(*rec);
  743.   VXIrecData * tp = recImpl->recData;
  744.   if ( tp ) {
  745.     const wchar_t* fnname = L"VXIrecDestroyResource";
  746.     LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE);
  747.     delete tp;
  748.   }
  749.   
  750.   delete recImpl;
  751.   *rec = NULL;
  752.   return VXIrec_RESULT_SUCCESS;
  753. }