static void ShowPropertyValues(const VXIchar *key, const VXIValue *value, VXIunsigned PROP_TAG, VXIlogInterface *log) { VXIchar subtag[512] = L"Property"; if( value == 0 ) return; VXIvalueType type = VXIValueGetType(value); { switch( type ) { case VALUE_INTEGER: wcscpy(subtag, L"Property:INT"); Diag(log, PROP_TAG, subtag, L"%s=%d", key, VXIIntegerValue((const VXIInteger*)value)); break; case VALUE_FLOAT: wcscpy(subtag, L"Property:FLT"); Diag(log, PROP_TAG, subtag, L"%s=%f", key, VXIFloatValue((const VXIFloat*)value)); break; case VALUE_BOOLEAN: wcscpy(subtag, L"Property:BOOL"); Diag(log, PROP_TAG, subtag, L"%s=%d", key, VXIBooleanValue((const VXIBoolean*)value)); break; case VALUE_STRING: wcscpy(subtag, L"Property:STR"); Diag(log, PROP_TAG, subtag, L"%s=%s", key, VXIStringCStr((const VXIString*)value)); break; case VALUE_PTR: wcscpy(subtag, L"Property:PTR"); Diag(log, PROP_TAG, subtag, L"%s(ptr)=0x%p", key, VXIPtrValue((const VXIPtr*)value)); break; case VALUE_CONTENT: wcscpy(subtag, L"Property:CNT"); Diag(log, PROP_TAG, subtag, L"%s(content)=0x%p", key, value); break; case VALUE_MAP: { VXIchar endtag[512]; const VXIchar *mykey = key ? key : L"NULL"; wcscpy(subtag, L"Property:MAP:BEG"); wcscpy(endtag, L"Property:MAP:END"); Diag(log, PROP_TAG, subtag, L"%s", mykey); const VXIchar *key = NULL; const VXIValue *gvalue = NULL; VXIMapIterator *it = VXIMapGetFirstProperty((const VXIMap*)value, &key, &gvalue); int ret = 0; while( ret == 0 && key && gvalue ) { ShowPropertyValues(key, gvalue, PROP_TAG, log); ret = VXIMapGetNextProperty(it, &key, &gvalue); } VXIMapIteratorDestroy(&it); Diag(log, PROP_TAG, endtag, L"%s", mykey); } break; case VALUE_VECTOR: { VXIunsigned vlen = VXIVectorLength((const VXIVector*)value); for(VXIunsigned i = 0; i < vlen; ++i) { const VXIValue *gvalue = VXIVectorGetElement((const VXIVector*)value, i); ShowPropertyValues(L"Vector", gvalue, PROP_TAG, log); } } break; default: Diag(log, PROP_TAG, subtag, L"%s=%s", key, L"UNKOWN"); } } return; }
// This function is responsible for calling the VXIrec level Recognize function // and then mapping the grammar back to the corresponding VXML node. // int GrammarManager::Recognize(const VXIMapHolder & properties, RecognitionAnswer & recAnswer, VXMLElement & recNode) { recNode = VXMLElement(); VXIrecRecognitionResult * answer = NULL; // (1) Do VXIrec level Recognitize and process return value. // (1.1) Recognize. VXIrecResult err = vxirec->Recognize(vxirec, properties.GetValue(), &answer); if (err == VXIrec_RESULT_OUT_OF_MEMORY) { log.LogDiagnostic(0,L"GrammarManager::InternalRecognize - Out of memory."); return GrammarManager::OutOfMemory; } if (err == VXIrec_RESULT_DISCONNECT) { // Here is the case that the call is being disconnected before the // recognition even starts return GrammarManager::Disconnect; } // (1.2) Anything other than success indicates that recognition failed // (badly). The normal error conditions are returned through the recogntion // result structure. if (err != VXIrec_RESULT_SUCCESS) { log.StartDiagnostic(0) << L"GrammarManager::InternalRecognize - " L"VXIrecInterface::Recognize returned " << int (err); log.EndDiagnostic(); log.LogError(420, SimpleLogger::MESSAGE, L"function did not return the expected VXIrecSUCCESS result"); return GrammarManager::InternalError; } // (1.3) The answer structure must be defined. if (answer == NULL) { // Here is the case that the call is being disconnected before the recording even starts return GrammarManager::Disconnect; } // (1.4) Attach the answer structure returned by VXIrec and the waveform to // the recAnswer class. recAnswer.Bind(answer); recAnswer.waveform = answer->waveform; // (2) Process all non-Successful results. // (2.1) First the status code. switch (answer->status) { case REC_STATUS_SUCCESS: // Recognition returned a hypothesis case REC_STATUS_DTMFSUCCESS: // Recognition returned a hypothesis break; case REC_STATUS_FAILURE: // Speech detected, no likely hypothesis return GrammarManager::Failure; case REC_STATUS_TIMEOUT: // No speech was detected return GrammarManager::Timeout; case REC_STATUS_DISCONNECT: // Caller has disconnected; no hypothesis return GrammarManager::Disconnect; case REC_STATUS_ERROR: // An error aborted recognition return GrammarManager::Error; default: log.StartDiagnostic(0) << L"GrammarManager::InternalRecognize - " L"VXIrecInterface::Recognize returned status " << int(answer->status); log.EndDiagnostic(); log.LogError(420, SimpleLogger::MESSAGE, L"function returned an invalid VXIrecStatus code"); return GrammarManager::InternalError; } // (2.2) Recognition success. Verify that the input mode was set correctly. switch (answer->mode) { case REC_INPUT_MODE_DTMF: case REC_INPUT_MODE_SPEECH: break; default: log.StartDiagnostic(0) << L"GrammarManager::InternalRecognize - " L"VXIrecInterface::Recognize returned mode " << int(answer->mode); log.EndDiagnostic(); log.LogError(420, SimpleLogger::MESSAGE, L"function returned an invalid VXIrecInputMode value"); return GrammarManager::InternalError; } // (3) Walk through results array and sanity check the results. // (3.1) How many answers are there? if (answer->results == NULL) { log.LogError(420, SimpleLogger::MESSAGE, L"function returned a null results vector"); return GrammarManager::InternalError; } unsigned int NUM_ANSWERS = VXIVectorLength(answer->results); if (NUM_ANSWERS == 0) { log.LogError(420, SimpleLogger::MESSAGE, L"function returned an empty results vector"); return GrammarManager::InternalError; } const VXIMap * bestAnswer = NULL; for (unsigned int i = 0; i < NUM_ANSWERS; ++i) { // (3.2) Find each element in the result vector. const VXIValue * temp = VXIVectorGetElement(answer->results, i); if (temp == NULL) { log.LogError(400, SimpleLogger::MESSAGE, L"VXIVectorGetElement failed to return answer."); return GrammarManager::InternalError; } if (VXIValueGetType(temp) != VALUE_MAP) { log.LogError(420, SimpleLogger::MESSAGE, L"function returned an invalid results vector"); return GrammarManager::InternalError; } const VXIMap * nthAnswer = reinterpret_cast<const VXIMap*>(temp); if (i == 0) bestAnswer = nthAnswer; // (3.3) Validate types of member keys. temp = VXIMapGetProperty(nthAnswer, REC_KEYS); if (temp == NULL || VXIValueGetType(temp) != VALUE_VECTOR) { log.LogError(420, SimpleLogger::MESSAGE, L"REC_KEYS must be defined with type vector"); return GrammarManager::InternalError; } const VXIVector * keys = reinterpret_cast<const VXIVector *>(temp); temp = VXIMapGetProperty(nthAnswer, REC_VALUES); if (temp == NULL || VXIValueGetType(temp) != VALUE_VECTOR) { log.LogError(420, SimpleLogger::MESSAGE, L"REC_VALUES must be defined with type vector"); return GrammarManager::InternalError; } const VXIVector * values = reinterpret_cast<const VXIVector *>(temp); temp = VXIMapGetProperty(nthAnswer, REC_CONF); if (temp == NULL || VXIValueGetType(temp) != VALUE_VECTOR) { log.LogError(420, SimpleLogger::MESSAGE, L"REC_CONF must be defined with type vector"); return GrammarManager::InternalError; } const VXIVector * scores = reinterpret_cast<const VXIVector *>(temp); temp = VXIMapGetProperty(nthAnswer, REC_RAW); if (temp == NULL || VXIValueGetType(temp) != VALUE_VECTOR) { log.LogError(420, SimpleLogger::MESSAGE, L"REC_RAW must be defined with type vector"); return GrammarManager::InternalError; } const VXIVector * utts = reinterpret_cast<const VXIVector *>(temp); // (3.4) Validate vector lengths. const VXIunsigned length = VXIVectorLength(keys); if (length < 1) { log.LogError(420, SimpleLogger::MESSAGE, L"result vector must have length of at least one"); throw VXIException::Fatal(); } if (length != VXIVectorLength(values) || length != VXIVectorLength(scores) || length != VXIVectorLength(utts)) { log.LogError(420, SimpleLogger::MESSAGE, L"result vector length must all match"); return GrammarManager::InternalError; } temp = VXIVectorGetElement(keys, 0); if (temp == NULL || VXIValueGetType(temp) != VALUE_STRING) { log.LogError(420, SimpleLogger::MESSAGE, L"first REC_KEYS must be defined with type string"); return GrammarManager::InternalError; } // (3.5) Copy into results class. recAnswer.keys.push_back(keys); recAnswer.values.push_back(values); recAnswer.scores.push_back(scores); recAnswer.utts.push_back(utts); } recAnswer.numAnswers = NUM_ANSWERS; // (4) Find the VXML element associated with the matched grammar. // (4.1) Find the grammar corresponding to the best answer. const VXIValue * temp = VXIMapGetProperty(bestAnswer, REC_GRAMMAR); if (temp == NULL || VXIValueGetType(temp) != VALUE_PTR) { log.LogError(420, SimpleLogger::MESSAGE, L"unable to obtain grammar key from 'results' #0"); return GrammarManager::InternalError; } const VXIPtr * tempptr = reinterpret_cast<const VXIPtr *>(temp); const VXIrecGrammar * bestGrammar = reinterpret_cast<const VXIrecGrammar*>(VXIPtrValue(tempptr)); // (4.2) Map the VXIrecGrammar pointer back to the source VXMLElement. for (GRAMMARS::iterator j = grammars.begin(); j != grammars.end(); ++j) { if ((answer->mode == REC_INPUT_MODE_DTMF && REC_STATUS_DTMFSUCCESS != answer->status) && (*j)->GetRecGrammar() != bestGrammar) continue; if (!(*j)->IsEnabled()) { if (j == grammars.end()) { log.LogError(420, SimpleLogger::MESSAGE, L"function returned an inactive grammar"); return GrammarManager::InternalError; } continue; } (*j)->GetElement(recNode); if (answer->mode == REC_INPUT_MODE_DTMF) return GrammarManager::SuccessDTMF; return GrammarManager::Success; } log.LogError(420, SimpleLogger::MESSAGE, L"function returned a non-existent grammar"); return GrammarManager::InternalError; }