From: Anshuman S. R. <ar...@3c...> - 2012-06-07 12:06:59
|
/****************License************************************************ * Vocalocity OpenVXI * Copyright (C) 2004-2005 by Vocalocity, Inc. All Rights Reserved. * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Vocalocity, the Vocalocity logo, and VocalOS are trademarks or * registered trademarks of Vocalocity, Inc. * OpenVXI is a trademark of Scansoft, Inc. and used under license * by Vocalocity. ***********************************************************************/ #define VXIREC_EXPORTS #include "VXIrecAPI.h" #include "VXIrec_utils.h" #include "LogBlock.hpp" #include <cstdio> #include <cstring> #include <sstream> // ------*---------*---------*---------*---------*---------*---------*--------- static void ResultContentDestroy(VXIbyte **content, void *userData) { if (content && *content) delete [] *content; *content = NULL; } class VXIVectorHolder { public: VXIVectorHolder() : _vector(NULL) { _vector = VXIVectorCreate(); } VXIVectorHolder(VXIVector * m) : _vector(m) { } ~VXIVectorHolder() { if (_vector != NULL) VXIVectorDestroy(&_vector);} VXIVectorHolder & operator=(const VXIVectorHolder & x) { if (this != &x) { if (_vector != NULL) VXIVectorDestroy(&_vector); _vector = VXIVectorClone(x._vector); } return *this; } // GetValue returns the internal vector. The standard vector manipulation // functions may then be used. VXIVector * GetValue() const { return _vector; } // These functions allow the holder to take ownership of an existing vector // or to release the internal one. VXIVector * Release() { VXIVector * m = _vector; _vector = NULL; return m; } void Acquire(VXIVector * m) { if (_vector != NULL) VXIVectorDestroy(&_vector); else _vector = m; } private: VXIVectorHolder(const VXIVectorHolder &); // intentionally not defined. VXIVector * _vector; }; // ------*---------*---------*---------*---------*---------*---------*--------- // Global for the base diagnostic tag ID, see osbrec_utils.h for tags // static VXIunsigned gblDiagLogBase = 0; // VXIrec implementation of the VXIrec interface // extern "C" { //Anshuman: created a replica of structure in pjsip_vxi branch //for debugging purposes only. Not intended for actual use. struct VXIrecImpl { // Base interface, must be first VXIrecInterface intf; // Class for managing grammars VXIrecData *recData; // call id int call_id; //memory pool for this prompt resource void *pool; //lock for synchronizing various operations void *obj_lock; //semaphore for input event void *input_lock; //store for input events VXIMap *pProperty; VXIrecResult result; }; } static struct VXIrecImpl *recImplTable[100]; // A few conversion functions... static inline VXIrecGrammar * ToVXIrecGrammar(VXIrecGrammar * i) { return reinterpret_cast<VXIrecGrammar *>(i); } static inline VXIrecGrammar * FromVXIrecGrammar(VXIrecGrammar * i) { return reinterpret_cast<VXIrecGrammar *>(i); } static inline VXIrecData * GetRecData(VXIrecInterface * i) { if (i == NULL) return NULL; return reinterpret_cast<VXIrecImpl *>(i)->recData; } /******************************************************* * Method routines for VXIrecInterface structure *******************************************************/ // Get the VXIrec interface version supported // static VXIint32 VXIrecGetVersion(void) { return VXI_CURRENT_VERSION; } // Get the implementation name // static const VXIchar* VXIrecGetImplementationName(void) { static const VXIchar IMPLEMENTATION_NAME[] = COMPANY_DOMAIN L".VXIrec"; return IMPLEMENTATION_NAME; } static VXIrecResult VXIrecBeginSession(VXIrecInterface * pThis, VXIMap *m) { const wchar_t* fnname = L"VXIrecBeginSession"; VXIrecData* tp = GetRecData(pThis); if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT; LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE); printf("VXIrecBeginSession\n"); return VXIrec_RESULT_SUCCESS; } static VXIrecResult VXIrecEndSession(VXIrecInterface *pThis, VXIMap *) { const wchar_t* fnname = L"VXIrecEndSession"; VXIrecData* tp = GetRecData(pThis); if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT; LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE); printf("VXIrecEndSession\n"); tp->Clear(); return VXIrec_RESULT_SUCCESS; } static VXIrecResult VXIrecLoadGrammarFromString(VXIrecInterface *pThis, const VXIMap *prop, const VXIchar *type, const VXIchar *str, VXIrecGrammar **gram) { const wchar_t* fnname = L"VXIrecLoadGrammarFromString"; VXIrecData* tp = GetRecData(pThis); if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT; LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE); printf("VXIrecLoadGrammarFromString: \ntype: %S,\nstr: %S\n", type, str); // Check the arguments if (str == NULL) { logger = VXIrec_RESULT_INVALID_ARGUMENT; return VXIrec_RESULT_INVALID_ARGUMENT; } if (type == NULL) { logger = VXIrec_RESULT_UNSUPPORTED; return VXIrec_RESULT_UNSUPPORTED; } VXIrecGrammar * gp = NULL; vxistring srgsGram, mtype(type); logger.logDiag(DIAG_TAG_GRAMMARS, L"%s%s", L"TYPE: ", mtype.c_str()); tp->ShowPropertyValue(prop); if( mtype == L"application/x-jsgf" || mtype == REC_MIME_CHOICE || mtype == REC_MIME_CHOICE_DTMF) { // first crack the srgs grammar JSGFInfo info; tp->ConvertJSGFType(str, info); // then try to convert to SRGS format if( !tp->JSGFToSRGS(info.contentStr, srgsGram, prop) ) return VXIrec_RESULT_FAILURE; mtype = VXI_MIME_SRGS; // reset mime type logger.logDiag(DIAG_TAG_GRAMMARS, L"%s%s", L"Converted GRAMMAR: ", srgsGram.c_str()); } else if( mtype == VXI_MIME_SRGS ) { // processing below srgsGram = str; printf("VXIrecLoadGrammarFromString: VXI_MIME_SRGS grammar\n"); } else { // Handle your own type here, return unsupported for now logger = VXIrec_RESULT_UNSUPPORTED; return VXIrec_RESULT_UNSUPPORTED; } // Parsing SRGS grammar. // NOTES: The parsing is very simple, therefore it may not work // for complex grammar. As you know, this is a simulator!!! VXIrecGrammar * gramPtr = tp->ParseSRGSGrammar(srgsGram, prop); if( gramPtr == NULL ) return VXIrec_RESULT_FAILURE; tp->AddGrammar(gramPtr); *gram = ToVXIrecGrammar(gramPtr); printf("VXIrecLoadGrammarFromString returning success\n"); return VXIrec_RESULT_SUCCESS; } static VXIrecResult VXIrecLoadGrammarFromURI(struct VXIrecInterface *pThis, const VXIMap *properties, const VXIchar *type, const VXIchar *uri, const VXIMap *uriArgs, VXIrecGrammar **gram) { VXIrecData* tp = GetRecData(pThis); if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT; const wchar_t* fnname = L"VXIrecLoadGrammarFromURI"; LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE); printf("VXIrecLoadGrammarFromURI\n"); tp->ShowPropertyValue(properties); if (wcsncmp(uri, L"builtin", 7) == 0 ){ logger.logDiag(DIAG_TAG_GRAMMARS, L"%s", L"built-in not supported"); return VXIrec_RESULT_UNSUPPORTED; } VXIbyte *buffer = NULL; VXIulong read = 0; if (!tp->FetchContent(uri, uriArgs, &buffer, read)) return VXIrec_RESULT_FAILURE; // NOTE: this code assumes the retieved buffer is // composed of single byte chars. in the real world, // that can't be assumed. buffer[read] = 0; VXIchar *charbuff = new VXIchar[read+1]; mbstowcs(charbuff, (char*)buffer, read+1); VXIrecResult rc = VXIrecLoadGrammarFromString(pThis, properties, type, charbuff, gram); printf("VXIrecLoadGrammarFromURI: result rc: %d\n", rc); delete[] buffer; delete[] charbuff; return rc; } static VXIrecResult VXIrecLoadGrammarOption(VXIrecInterface * pThis, const VXIMap * properties, const VXIVector * gramChoice, const VXIVector * gramValue, const VXIVector * gramAcceptance, const VXIbool isDTMF, VXIrecGrammar ** gram) { const wchar_t* fnname = L"VXIrecLoadGrammarOption"; // Check the arguments VXIrecData* tp = GetRecData(pThis); if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT; LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE); printf("VXIrecLoadGrammarOption\n"); if (gram == NULL) { logger = VXIrec_RESULT_INVALID_ARGUMENT; return VXIrec_RESULT_INVALID_ARGUMENT; } tp->ShowPropertyValue(properties); VXIrecGrammar * gp = NULL; vxistring srgsGram; if( !tp->OptionToSRGS(properties, gramChoice, gramValue, gramAcceptance, isDTMF, srgsGram) ) return VXIrec_RESULT_FAILURE; // Parsing SRGS grammar. // NOTES: The parsing is very simple, therefore it may not work // for complex grammar. As you know, this is a simulator!!! VXIrecGrammar * gramPtr = tp->ParseSRGSGrammar(srgsGram, properties, isDTMF); if( gramPtr == NULL ) return VXIrec_RESULT_FAILURE; tp->AddGrammar(gramPtr); *gram = ToVXIrecGrammar(gramPtr); printf("VXIrecLoadGrammarOption returning success\n"); return VXIrec_RESULT_SUCCESS; } static VXIrecResult VXIrecFreeGrammar(VXIrecInterface *pThis, VXIrecGrammar **gram) { const wchar_t* fnname = L"VXIrecFreeGrammar"; // Check the arguments VXIrecData* tp = GetRecData(pThis); if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT; LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE); printf("VXIrecFreeGrammar\n"); // If the grammar pointer is null, there is nothing to free. if (gram == NULL || *gram == NULL) VXIrec_RESULT_SUCCESS; tp->FreeGrammar(FromVXIrecGrammar(*gram)); *gram = NULL; printf("VXIrecFreeGrammar returning success\n"); return VXIrec_RESULT_SUCCESS; } static VXIrecResult VXIrecActivateGrammar(VXIrecInterface *pThis, const VXIMap *properties, VXIrecGrammar *gram) { const wchar_t* fnname = L"VXIrecActivateGrammar"; VXIrecData* tp = GetRecData(pThis); if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT; LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE); printf("VXIrecActivateGrammar\n"); if (gram == NULL) { logger = VXIrec_RESULT_INVALID_ARGUMENT; return VXIrec_RESULT_INVALID_ARGUMENT; } tp->ActivateGrammar(FromVXIrecGrammar(gram)); printf("VXIrecActivateGrammar returning success\n"); return VXIrec_RESULT_SUCCESS; } static VXIrecResult VXIrecDeactivateGrammar(VXIrecInterface *pThis, VXIrecGrammar *gram) { const wchar_t* fnname = L"VXIrecDeactivateGrammar"; VXIrecData* tp = GetRecData(pThis); if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT; LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE); printf("VXIrecDeactivateGrammar\n"); if (gram == NULL) { logger = VXIrec_RESULT_INVALID_ARGUMENT; return VXIrec_RESULT_INVALID_ARGUMENT; } tp->DeactivateGrammar(FromVXIrecGrammar(gram)); printf("VXIrecDeactivateGrammar returning success\n"); return VXIrec_RESULT_SUCCESS; } /******************************************************* * Recognize related *******************************************************/ static void RecognitionResultDestroy(VXIrecRecognitionResult **Result) { if (Result == NULL || *Result == NULL) return; VXIrecRecognitionResult * result = *Result; if (result->utterance != NULL) VXIContentDestroy(&result->utterance); if (result->xmlresult != NULL) VXIContentDestroy(&result->xmlresult); if (result->markname != NULL) VXIStringDestroy(&result->markname); delete result; *Result = NULL; } static void TransferResultDestroy(VXIrecTransferResult **Result) { if (Result == NULL || *Result == NULL) return; VXIrecTransferResult * result = *Result; if (result->utterance != NULL) VXIContentDestroy(&result->utterance); if (result->xmlresult != NULL) VXIContentDestroy(&result->xmlresult); if (result->markname != NULL) VXIStringDestroy(&result->markname); delete result; *Result = NULL; } static const unsigned int NLSML_NOINPUT_SIZE = 109; static const VXIchar NLSML_NOINPUT[NLSML_NOINPUT_SIZE] = L"<?xml version='1.0'?>" L"<result>" L"<interpretation>" L"<instance/>" L"<input><noinput/></input>" L"</interpretation>" L"</result>\0"; static const unsigned int NLSML_NOMATCH_SIZE = 109; static const VXIchar NLSML_NOMATCH[NLSML_NOMATCH_SIZE] = L"<?xml version='1.0'?>" L"<result>" L"<interpretation>" L"<instance/>" L"<input><nomatch/></input>" L"</interpretation>" L"</result>\0"; void DestroyNLSMLBuffer(VXIbyte ** buffer, void * ok) { // Return immediate if we know the buffer is static memory, // i.e: noinput, nomatch as defined above if (ok == NULL || buffer == NULL) return; // otherwise reclaim the memory delete[] (*buffer); *buffer = NULL; } static VXIrecResult VXIrecRecognize(VXIrecInterface *pThis, const VXIMap *properties, VXIrecRecognitionResult **recogResult) { const wchar_t* fnname = L"VXIrecRecognize"; VXIrecData* tp = GetRecData(pThis); if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT; LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE); printf("VXIrecRecognize\n"); VXIchar* input = L"111#"; VXIMap* res = NULL; VXIchar* str = NULL; VXIchar console[512]; bool recordUtterance = false; bool haveUtterance = true; VXIint32 dtmf_timeout = -1; VXIint32 dtmf_interdigit_timeout = -1; VXIint32 dtmf_timeout_terminator = -1; VXIchar* dtmf_terminator_char = NULL; if (properties != NULL) { const VXIValue *rec_dtmf_timeout = VXIMapGetProperty(properties, REC_DTMF_TIMEOUT); if (VXIValueGetType(rec_dtmf_timeout) == VALUE_INTEGER) dtmf_timeout = VXIIntegerValue((VXIInteger*)rec_dtmf_timeout); const VXIValue *rec_dtmf_interdigit_timeout = VXIMapGetProperty(properties, REC_DTMF_TIMEOUT_INTERDIGIT); if (VXIValueGetType(rec_dtmf_interdigit_timeout) == VALUE_INTEGER) dtmf_interdigit_timeout = VXIIntegerValue((VXIInteger*)rec_dtmf_interdigit_timeout); const VXIValue *rec_dtmf_timeout_terminator = VXIMapGetProperty(properties, REC_DTMF_TIMEOUT_TERMINATOR); if (VXIValueGetType(rec_dtmf_timeout_terminator) == VALUE_INTEGER) dtmf_timeout_terminator = VXIIntegerValue((VXIInteger*)rec_dtmf_timeout_terminator); const VXIValue *rec_dtmf_terminator_char = VXIMapGetProperty(properties, REC_DTMF_TERMINATOR_CHAR); if (VXIValueGetType(rec_dtmf_terminator_char) == VALUE_STRING) dtmf_terminator_char = (VXIchar*)VXIStringCStr((const VXIString*)rec_dtmf_terminator_char); const VXIValue * ru = VXIMapGetProperty(properties, REC_RECORDUTTERANCE); if (ru) recordUtterance = wcscmp(VXIStringCStr((const VXIString*)ru), L"true") == 0; const VXIValue * val = VXIMapGetProperty(properties, L"SpeechInput"); if (val) { logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%s", L"SpeechInput: ", VXIStringCStr((const VXIString*)val)); } if (val == NULL || VXIValueGetType(val) != VALUE_STRING) { val = VXIMapGetProperty(properties, L"DTMFInput"); if (val) { logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%s", L"DTMFInput: ", VXIStringCStr((const VXIString*)val)); } } VXIString* vect = (VXIString*) val; if (vect != NULL) input = (VXIchar*) VXIStringCStr(vect); if (input && wcscmp(input, L"-") == 0) { unsigned int i; VXIchar* cp = console; char lbuf[512]; printf("Console: "); fgets(lbuf, 511, stdin); // copy to VXIchar for(i = 0; i < strlen(lbuf); ++i) { if (lbuf[i] == '\r' || lbuf[i] == '\n') continue; *cp++ = lbuf[i] & 0x7f; } *cp++ = 0; input = console; logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%s", L"Input: ", (input ? input : L"NULL")); } } // Create a new results structure. const unsigned int CHARSIZE = sizeof(VXIchar) / sizeof(VXIbyte); VXIContent * xmlresult = NULL; // Looking for matched phrase, if not act appropriately vxistring nlsmlresult; bool terminate = input ? (wcscmp(input, dtmf_terminator_char) == 0) : false; bool recogComplete = false; bool found = false; for (int i = 0; i < wcslen(input); i++) { logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%s", L"Input: ", &input[i]); if (terminate) break; found = tp->ConstructNLSMLForInput(&input[i], nlsmlresult, recogComplete); if (recogComplete) { if (!found) { if (!input || input[0] == L'\0') { // No input case haveUtterance = false; logger.logDiag(DIAG_TAG_RECOGNITION, L"%s", L"-- NO_INPUT RESULT --"); xmlresult = VXIContentCreate(VXIREC_MIMETYPE_XMLRESULT, (VXIbyte *) NLSML_NOINPUT, NLSML_NOINPUT_SIZE * CHARSIZE, DestroyNLSMLBuffer, NULL); } else { // No match case logger.logDiag(DIAG_TAG_RECOGNITION, L"%s", L"-- NO_MATCH RESULT --"); xmlresult = VXIContentCreate(VXIREC_MIMETYPE_XMLRESULT, (VXIbyte *) NLSML_NOMATCH, NLSML_NOMATCH_SIZE * CHARSIZE, DestroyNLSMLBuffer, NULL); } } else { // Found matched grammar logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%s", L"NLSML_RESULT: ", nlsmlresult.c_str()); unsigned int BUFFERSIZE = (nlsmlresult.length() + 1) * CHARSIZE; VXIbyte * buffer = new VXIbyte[BUFFERSIZE]; if (buffer == NULL) return VXIrec_RESULT_OUT_OF_MEMORY; memcpy(buffer, nlsmlresult.c_str(), BUFFERSIZE); xmlresult = VXIContentCreate(VXIREC_MIMETYPE_XMLRESULT, buffer, BUFFERSIZE, DestroyNLSMLBuffer, buffer); if (xmlresult == NULL) { delete [] buffer; return VXIrec_RESULT_OUT_OF_MEMORY; } } } } if (!xmlresult) { //xmlresult null means matching failed but result wasn't generated logger.logDiag(DIAG_TAG_RECOGNITION, L"%s", L"-- NO_MATCH RESULT --"); xmlresult = VXIContentCreate(VXIREC_MIMETYPE_XMLRESULT, (VXIbyte *) NLSML_NOMATCH, NLSML_NOMATCH_SIZE * CHARSIZE, DestroyNLSMLBuffer, NULL); } VXIrecRecognitionResult * result = new VXIrecRecognitionResult(); if (result == NULL) { VXIContentDestroy(&xmlresult); return VXIrec_RESULT_OUT_OF_MEMORY; } result->Destroy = RecognitionResultDestroy; result->markname = NULL; result->marktime = 0; result->xmlresult = xmlresult; if (!haveUtterance ||!recordUtterance) { result->utterance = NULL; result->utteranceDuration = 0; } else { result->utteranceDuration = 5000; // 5sec unsigned int waveformSizeBytes = (result->utteranceDuration / 1000 ) * 8000 * sizeof(unsigned char); unsigned char * c_waveform = new unsigned char[waveformSizeBytes]; if (c_waveform == NULL) { result->utterance = NULL; result->utteranceDuration = 0; } else { for (unsigned int i = 0; i < waveformSizeBytes; ++i) c_waveform[i] = i & 0x00ff; result->utterance = VXIContentCreate(VXIREC_MIMETYPE_ULAW, c_waveform, waveformSizeBytes, ResultContentDestroy, NULL); } } *recogResult = result; printf("VXIrecRecognize returning success\n"); return VXIrec_RESULT_SUCCESS; } static VXIrecResult VXIrecGetMatchedGrammar(VXIrecInterface *pThis, const VXIchar *grammarID, const VXIrecGrammar **gram) { const wchar_t* fnname = L"VXIrecGetMatchedGrammar"; VXIrecData* tp = GetRecData(pThis); if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT; LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE); printf("VXIrecGetMatchedGrammar\n"); if (grammarID == NULL || gram == NULL) return VXIrec_RESULT_INVALID_ARGUMENT; VXIrecGrammar * mgram = NULL; SWIswscanf(grammarID, L"%p", &mgram); *gram = mgram; logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%p", L"Got Matched grammar: ", mgram); printf("VXIrecGetMatchedGrammar returning success\n"); return VXIrec_RESULT_SUCCESS; } static void RecordResultDestroy(VXIrecRecordResult **Result) { if (Result == NULL || *Result == NULL) return; VXIrecRecordResult * result = *Result; if (result->waveform != NULL) VXIContentDestroy(&result->waveform); if (result->xmlresult != NULL) VXIContentDestroy(&result->xmlresult); delete result; *Result = NULL; } static VXIrecResult VXIrecRecord(VXIrecInterface *pThis, const VXIMap *props, VXIrecRecordResult **recordResult) { const wchar_t* fnname = L"VXIrecRecord"; VXIrecData* tp = GetRecData(pThis); if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT; LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE); if (recordResult == NULL) { logger = VXIrec_RESULT_INVALID_ARGUMENT; return VXIrec_RESULT_INVALID_ARGUMENT; } // (1) Create record structure VXIrecRecordResult *result = new VXIrecRecordResult(); if (result == NULL) { logger = VXIrec_RESULT_OUT_OF_MEMORY; return VXIrec_RESULT_OUT_OF_MEMORY; } result->Destroy = RecordResultDestroy; result->waveform = NULL; result->xmlresult = NULL; result->duration = 0; result->termchar = 0; result->maxtime = FALSE; result->markname = NULL; result->marktime = 0; *recordResult = result; VXIlong duration = -1; VXIlong maxtime = 0; VXIlong finalsilence = 0; // (2) Get maxtime const VXIValue* val = VXIMapGetProperty(props, REC_MAX_RECORDING_TIME); if (val != NULL && VXIValueGetType(val) == VALUE_INTEGER ) maxtime = VXIIntegerValue(reinterpret_cast<const VXIInteger *>(val)); else maxtime = 1000 * 20; // in milliseconds (default to 20 secs) // (2.1) adjust duration for simulator if( duration < 0 ) duration = maxtime; (*recordResult)->duration = duration; if( duration == maxtime ) (*recordResult)->maxtime = TRUE; // (2.2) Get MIME type VXIchar *mimeType = VXI_MIME_WAV; val = VXIMapGetProperty(props, REC_RECORD_MIME_TYPE); if (val != NULL && VXIValueGetType(val) == VALUE_STRING) mimeType = (VXIchar*)VXIStringCStr((const VXIString*)val); // TODO: this should use the media type. For now just construct // raw ulaw audio with silence unsigned int waveformSizeBytes = (duration / 1000 ) * 8000 * sizeof(unsigned char); unsigned char * c_waveform = new unsigned char[waveformSizeBytes]; if (c_waveform == NULL) { (*recordResult)->Destroy(recordResult); tp->LogError(400, L"%s%s", L"Error", L"out of memory"); return VXIrec_RESULT_OUT_OF_MEMORY; } for (unsigned int i = 0; i < waveformSizeBytes; ++i) c_waveform[i] = i & 0x00ff; (*recordResult)->waveform = VXIContentCreate(VXIREC_MIMETYPE_ULAW, c_waveform, waveformSizeBytes, ResultContentDestroy, NULL); if((*recordResult)->waveform == NULL ) { (*recordResult)->Destroy(recordResult); tp->LogError(400, L"%s%s", L"Error", L"out of memory"); return VXIrec_RESULT_OUT_OF_MEMORY; } printf("VXIrecRecord returning success\n"); return VXIrec_RESULT_SUCCESS; } static VXIbool VXIrecSupportsHotwordTransfer( struct VXIrecInterface * pThis, const VXIMap * properties, const VXIchar * transferDest) { VXIbool result = FALSE; printf("VXIrecSupportsHotwordTransfer\n"); // this is really just to demonstrate how the platform could // support hotword for some type of transfers, but not others. // this could just as easily been based on other properties of // the transfer. i.e., destination type, required line type, etc... const VXIValue* dval = VXIMapGetProperty(properties, TEL_TRANSFER_TYPE); if( dval && VXIValueGetType(dval) == VALUE_STRING ){ const wchar_t* hid = VXIStringCStr(reinterpret_cast<const VXIString *>(dval)); if (wcscmp(hid, L"consultation") == 0) return FALSE; } dval = VXIMapGetProperty(properties, L"SupportsHotwordTransfer"); if( dval && VXIValueGetType(dval) == VALUE_STRING ){ const wchar_t* hid = VXIStringCStr(reinterpret_cast<const VXIString *>(dval)); result = (wcscmp(hid, L"true") == 0) ? TRUE : FALSE; } return result; } static VXIrecResult VXIrecHotwordTransfer ( struct VXIrecInterface * pThis, struct VXItelInterface * tel, const VXIMap *properties, const VXIchar* transferDest, VXIrecTransferResult ** transferResult ) { const wchar_t* fnname = L"VXIrecHotwordTransfer"; VXIrecData* tp = GetRecData(pThis); if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT; LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE); VXIrecResult res = VXIrec_RESULT_SUCCESS; printf("VXIrecHotwordTransfer\n"); // this is probably not how it would be done in real life...but for this // sample app it will suffice: // Do the transfer int activeGrammars = tp->GetActiveCount(); VXIMap *xferResp = NULL; VXItelResult xferResult = tel->TransferBridge(tel, properties, transferDest, &xferResp); if (xferResult != VXItel_RESULT_SUCCESS) { res = VXIrec_RESULT_FAILURE; } else if (activeGrammars == 0) { *transferResult = new VXIrecTransferResult(); (*transferResult)->Destroy = TransferResultDestroy; (*transferResult)->utterance = NULL; (*transferResult)->markname = NULL; (*transferResult)->marktime = 0; (*transferResult)->xmlresult = NULL; const VXIValue * v = VXIMapGetProperty(xferResp, TEL_TRANSFER_DURATION); if (v != NULL && VXIValueGetType(v) == VALUE_INTEGER) (*transferResult)->duration = VXIIntegerValue(reinterpret_cast<const VXIInteger*>(v)); v = VXIMapGetProperty(xferResp, TEL_TRANSFER_STATUS); if (v != NULL && VXIValueGetType(v) == VALUE_INTEGER) { long temp = VXIIntegerValue(reinterpret_cast<const VXIInteger *>(v)); (*transferResult)->status = VXItelTransferStatus(temp); } VXIMapDestroy(&xferResp); } else { // get input from the user. VXIrecRecognitionResult *recResult = NULL; VXIrecResult localRes = pThis->Recognize(pThis, properties, &recResult); if (localRes == VXIrec_RESULT_SUCCESS){ *transferResult = new VXIrecTransferResult(); if ((*transferResult) == NULL) { recResult->Destroy(&recResult); VXIMapDestroy(&xferResp); return VXIrec_RESULT_OUT_OF_MEMORY; } // setup the transfer result by first copying the // RecResult. (*transferResult)->Destroy = TransferResultDestroy; (*transferResult)->utterance = recResult->utterance; (*transferResult)->markname = recResult->markname; (*transferResult)->marktime = recResult->marktime; (*transferResult)->xmlresult = recResult->xmlresult; (*transferResult)->duration = 0; (*transferResult)->status = VXItel_TRANSFER_FAR_END_DISCONNECT; // we no long need the rec result (but we don't want the VXIContent // fields destroyed). recResult->utterance = NULL; recResult->xmlresult = NULL; recResult->Destroy(&recResult); // translate the status and duration to the transfer result fields. // since this code is simply so that Hotword transfers work, any // valid recognition (ignoring noinput and nomatch) will set the // transfer to "near_end_disconnect". Otherwise, we pretend that // the other end terminated the transfer. if((*transferResult)->xmlresult){ // we're going to ignore noinput and nomatch results. const VXIchar * contentType; const VXIbyte * content; VXIulong contentSize = 0; VXIContentValue((*transferResult)->xmlresult, &contentType, &content, &contentSize); // we're going to ignore noinput and nomatch results. if ( !wcsstr((VXIchar*)content, L"<noinput/>") && !wcsstr((VXIchar*)content, L"<nomatch/>")){ (*transferResult)->status = VXItel_TRANSFER_NEAR_END_DISCONNECT; } } const VXIValue * v = VXIMapGetProperty(xferResp, TEL_TRANSFER_DURATION); if (v != NULL && VXIValueGetType(v) == VALUE_INTEGER) (*transferResult)->duration = VXIIntegerValue(reinterpret_cast<const VXIInteger*>(v)); VXIMapDestroy(&xferResp); } } printf("VXIrecHotwordTransfer return res: %d\n", res); return res; } /******************************************************* * Init and factory routines *******************************************************/ static inline VXIrecImpl * ToVXIrecImpl(VXIrecInterface * i) { return reinterpret_cast<VXIrecImpl *>(i); } // Global init - Don't need to do much here // VXIREC_API VXIrecResult VXIrecInit(VXIlogInterface *log, VXIunsigned diagLogBase, VXIMap *args) { if (!log) return VXIrec_RESULT_INVALID_ARGUMENT; gblDiagLogBase = diagLogBase; const wchar_t* fnname = L"VXIrecInit"; LogBlock logger(log, gblDiagLogBase, fnname, VXIREC_MODULE); printf("VXIrecInit\n"); memset(recImplTable, 0, sizeof(recImplTable)); for (int i = 0; i < (sizeof(recImplTable)/sizeof(recImplTable[0])); i++) { recImplTable[i] = NULL; } logger = VXIrecData::Initialize(log, diagLogBase); return VXIrec_RESULT_SUCCESS; } // Global shutdown // VXIREC_API VXIrecResult VXIrecShutDown(VXIlogInterface *log) { if (!log) return VXIrec_RESULT_INVALID_ARGUMENT; const wchar_t* fnname = L"VXIrecShutDown"; LogBlock logger(log, gblDiagLogBase, fnname, VXIREC_MODULE); printf("VXIrecShutDown\n"); logger = VXIrecData::ShutDown(); return VXIrec_RESULT_SUCCESS; } // Create an VXIrecInterface object and return. // VXIREC_API VXIrecResult VXIrecCreateResource(VXIlogInterface *log, VXIinetInterface *inet, VXIcacheInterface *cache, VXIpromptInterface *prompt, VXItelInterface *tel, VXIrecInterface **rec) { if (!log) return VXIrec_RESULT_INVALID_ARGUMENT; const wchar_t* fnname = L"VXIrecCreateResource"; LogBlock logger(log, gblDiagLogBase, fnname, VXIREC_MODULE); printf("VXIrecCreateResource\n"); VXIrecImpl* pp = new VXIrecImpl(); if (pp == NULL) { logger = VXIrec_RESULT_OUT_OF_MEMORY; return VXIrec_RESULT_OUT_OF_MEMORY; } VXIrecData* tp = new VXIrecData(log, inet); if (tp == NULL) { logger = VXIrec_RESULT_OUT_OF_MEMORY; return VXIrec_RESULT_OUT_OF_MEMORY; } pp->recData = tp; pp->intf.GetVersion = VXIrecGetVersion; pp->intf.GetImplementationName = VXIrecGetImplementationName; pp->intf.BeginSession = VXIrecBeginSession; pp->intf.EndSession = VXIrecEndSession; pp->intf.LoadGrammarURI = VXIrecLoadGrammarFromURI; pp->intf.LoadGrammarString = VXIrecLoadGrammarFromString; pp->intf.LoadGrammarOption = VXIrecLoadGrammarOption; pp->intf.ActivateGrammar = VXIrecActivateGrammar; pp->intf.DeactivateGrammar = VXIrecDeactivateGrammar; pp->intf.FreeGrammar = VXIrecFreeGrammar; pp->intf.Recognize = VXIrecRecognize; pp->intf.Record = VXIrecRecord; pp->intf.HotwordTransfer = VXIrecHotwordTransfer; pp->intf.SupportsHotwordTransfer = VXIrecSupportsHotwordTransfer; pp->intf.GetMatchedGrammar = VXIrecGetMatchedGrammar; *rec = &pp->intf; printf("VXIrecCreateResource returning success\n"); return VXIrec_RESULT_SUCCESS; } // Free VXIrec structure allocated in VXIrecCreateResource. // VXIREC_API VXIrecResult VXIrecDestroyResource(VXIrecInterface **rec) { if (rec == NULL || *rec == NULL) return VXIrec_RESULT_INVALID_ARGUMENT; VXIrecImpl* recImpl = reinterpret_cast<VXIrecImpl*>(*rec); printf("VXIrecDestroyResource\n"); VXIrecData * tp = recImpl->recData; if ( tp ) { const wchar_t* fnname = L"VXIrecDestroyResource"; LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE); delete tp; } delete recImpl; *rec = NULL; return VXIrec_RESULT_SUCCESS; } |