static VXIbool VXIrecSupportsHotwordTransfer( struct VXIrecInterface * pThis, const VXIMap * properties, const VXIchar * transferDest) { VXIbool result = FALSE; // 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; }
/** * Sample object setting the defaults document for subsequent calls * * @param properties [IN] See description in VXIobjectExecute() * or VXIobjectValidate() * @param parameters [IN] See description in VXIobjectExecute() * or VXIobjectValidate() * @param execute [IN] Specifies whether the object should be * executed (true) or simply validated (false) * @param result [OUT] See description in VXIobjectExecute() * or VXIobjectValidate() * * @result VXIobj_RESULT_SUCCESS on success */ static VXIobjResult ProcessComSpeechworksSetDefaultsObject (struct VXIobjectInterface *pThis, const VXIMap *properties, const VXIMap *parameters, VXIbool execute, VXIValue **result) { static const wchar_t func[] = L"ProcessComSpeechworksSetDefaults"; GET_VXIOBJECT (pThis, sbObject, log, rc); if((execute) && (result == NULL)) return VXIobj_RESULT_INVALID_ARGUMENT; if((! properties) || (! parameters)) return VXIobj_RESULT_INVALID_ARGUMENT; if(execute) { const VXIchar *defaults = NULL; const VXIValue *val = VXIMapGetProperty(parameters, L"defaults"); if (! val) { Error(log, 202, L"%s%s", L"parameter", L"defaults"); return VXIobj_RESULT_INVALID_PROP_VALUE; } else if (VXIValueGetType(val) != VALUE_STRING) { Error(log, 203, L"%s%s%s%d", L"parameter", L"defaults", L"type", VXIValueGetType(val)); return VXIobj_RESULT_INVALID_PROP_VALUE; } defaults = VXIStringCStr(reinterpret_cast<const VXIString *>(val)); if (! defaults[0]) { Error(log, 204, L"%s%s%s%s", L"parameter", L"defaults", L"value", defaults); return VXIobj_RESULT_INVALID_PROP_VALUE; } // Hack to set the defaults document VXIobjectAPI *objectAPI = (VXIobjectAPI *) pThis; if ( ! objectAPI ) { rc = VXIobj_RESULT_INVALID_ARGUMENT; return rc; } VXIplatform *plat = objectAPI->resources->platform; VXIMap *vxiProperties = VXIMapCreate(); VXIString * valstr = VXIStringCreate(defaults); VXIMapSetProperty(vxiProperties, VXI_PLATFORM_DEFAULTS, (VXIValue *) valstr); plat->VXIinterpreter->SetProperties(plat->VXIinterpreter, vxiProperties); // Create the result object VXIMap *resultObj = VXIMapCreate(); if(resultObj == NULL) { Error(log, 100, NULL); return VXIobj_RESULT_OUT_OF_MEMORY; } *result = reinterpret_cast<VXIValue *>(resultObj); // Set the result object's status field to 'success' VXIMapSetProperty(resultObj, L"status", reinterpret_cast<VXIValue *>(VXIStringCreate(L"success"))); } return VXIobj_RESULT_SUCCESS; }
// Begin a session // static VXItelResult OSBtelBeginSession(VXItelInterface * pThis, VXIMap *sessionArgs) { OSBtelImpl *impl = ToOSBtelImpl(pThis); impl->live = -1; // not quite live yet, other threads shouldn't its access resources Diag(impl, DIAG_TAG_SIGNALING, NULL, L"tel BeginSession"); const VXIchar *callId = NULL; const VXIValue *val; val = VXIMapGetProperty(sessionArgs, L"callid"); impl->pExitGuard = new OsBSem(OsBSem::Q_PRIORITY, OsBSem::FULL); impl->transferred = 0; impl->callId = NULL; if ((val) && (VXIValueGetType(val) == VALUE_STRING)) { callId = VXIStringCStr((const VXIString *) val); int len = strlen((char*)callId) + 1; VXIchar *vxiCallid = (VXIchar *) calloc(len, sizeof(VXIchar)); if (vxiCallid) { strncpy((char*)vxiCallid, (char*)callId, len); impl->callId = vxiCallid; } else return VXItel_RESULT_OUT_OF_MEMORY; } else return VXItel_RESULT_INVALID_ARGUMENT; impl->live = 1; // live return VXItel_RESULT_SUCCESS; }
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; // 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); } } return res; }
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"; std::ostringstream srgs_version; vxistring srgs_wide_version; VXIunsigned num_choices; VXIvalueType value_type; const VXIValue *utterance_value; // Check the arguments VXIrecData* tp = GetRecData(pThis); if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT; LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE); if (gram == NULL) { logger = VXIrec_RESULT_INVALID_ARGUMENT; return VXIrec_RESULT_INVALID_ARGUMENT; } // DEBUG if (voiceglue_loglevel() >= LOG_DEBUG) { std::ostringstream logstring; logstring << "VXIrecLoadGrammarOption called with type " << (isDTMF ? "DTMF" : "speech") << ", choices " << VXIValue_to_Std_String ((VXIValue *) gramChoice) << ", values " << VXIValue_to_Std_String ((VXIValue *) gramValue) << ", properties " << VXIValue_to_Std_String ((const VXIValue *) properties); voiceglue_log ((char) LOG_DEBUG, logstring); }; tp->ShowPropertyValue(properties); // Convert to SRGS grammar num_choices = VXIVectorLength (gramChoice); srgs_version << "<rule id=\"choice\">\n <one-of>\n"; for (VXIunsigned choice_num = 0; choice_num < num_choices; ++choice_num) { srgs_version << " <item> "; utterance_value = VXIVectorGetElement (gramChoice, choice_num); value_type = VXIValueGetType (utterance_value); if (value_type == VALUE_INTEGER) { srgs_version << VXIIntegerValue ((const VXIInteger*) utterance_value); } else if (value_type == VALUE_LONG) { srgs_version << VXILongValue ((const VXILong*) utterance_value); } else if (value_type == VALUE_ULONG) { srgs_version << VXIULongValue ((const VXIULong*) utterance_value); } else if (isDTMF) { srgs_version << VXIchar_to_Std_String ( VXIStringCStr ((VXIString *) utterance_value)); } else { srgs_version << (choice_num + 1); }; srgs_version << " <tag>" << VXIchar_to_Std_String ( VXIStringCStr ( (VXIString *) VXIVectorGetElement (gramValue, choice_num))) << "</tag> </item>\n"; }; srgs_version << " </one-of>\n</rule>\n"; srgs_wide_version = Std_String_to_vxistring (srgs_version.str()); return VXIrecLoadGrammarFromString (pThis, properties, L"text/x-grammar-choice-dtmf", (const VXIchar *) srgs_wide_version.c_str(), gram); 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); return VXIrec_RESULT_SUCCESS; }
/** * Validate an object, performing validity checks without execution * * @param properties [IN] Map containing properties and attributes for * the <object> as specified in the VoiceXML * specification except that "expr" and "cond" are * always omitted (are handled by the interpreter). * @param parameters [IN] Map containing parameters for the <object> as * specified by the VoiceXML <param> tag. The keys * of the map correspond to the parameter name ("name" * attribute) while the value of each key corresponds * to a VXIValue based type. See Execute( ) above * for details. * * @return VXIobj_RESULT_SUCCESS on success, * VXIobj_RESULT_NON_FATAL_ERROR on error, * VXIobj_RESULT_UNSUPPORTED for unsupported object types * (this will cause interpreter to throw the correct event) */ static VXIobjResult VXIobjectValidate(struct VXIobjectInterface *pThis, const VXIMap *properties, const VXIMap *parameters) { static const wchar_t func[] = L"VXIobjectValidate"; GET_VXIOBJECT (pThis, sbObject, log, rc); Diag (log, LOG_API, func, L"entering: 0x%p, 0x%p, 0x%p", pThis, properties, parameters); if(properties == NULL) { Error (log, 201, NULL); return VXIobj_RESULT_INVALID_ARGUMENT; } // Get the name of the object to execute const VXIValue *val = VXIMapGetProperty(properties, OBJECT_CLASS_ID); if(val == NULL) { Error(log, 202, L"%s%s", L"parameter", OBJECT_CLASS_ID); return VXIobj_RESULT_INVALID_PROP_VALUE; } else if (VXIValueGetType(val) != VALUE_STRING) { Error(log, 203, L"%s%s%s%d", L"parameter", OBJECT_CLASS_ID, L"type", VXIValueGetType(val)); return VXIobj_RESULT_INVALID_PROP_VALUE; } const VXIchar *classID = VXIStringCStr((VXIString *)val); // Handle the object if (::wcscmp(classID, L"com.vocalocity.diag") == 0) { // // Sample diagnostic logging object // rc = ProcessComSpeechworksDiagObject(pThis, properties, parameters, false, NULL); if(rc != VXIobj_RESULT_SUCCESS) rc = VXIobj_RESULT_NON_FATAL_ERROR; } else if (::wcscmp(classID, L"com.vocalocity.echo") == 0) { // // Sample object echoing back all attributes and parameters // rc = ProcessComSpeechworksEchoObject(pThis, properties, parameters, false, NULL); if(rc != VXIobj_RESULT_SUCCESS) rc = VXIobj_RESULT_NON_FATAL_ERROR; } else if (::wcscmp(classID, L"com.vocalocity.saveRecording") == 0) { // // Sample object that saves a recording to a file // rc = ProcessComSpeechworksSaveRecordingObject(pThis, properties, parameters, false, NULL); if(rc != VXIobj_RESULT_SUCCESS) rc = VXIobj_RESULT_NON_FATAL_ERROR; } else if (::wcscmp(classID, L"com.vocalocity.setDefaults") == 0) { // // Sample object that sets the defaults document for subsequent // calls. This is really a hack and not recommended. This was // done more for fun than any value. // rc = ProcessComSpeechworksSetDefaultsObject(pThis, properties, parameters, false, NULL); if(rc != VXIobj_RESULT_SUCCESS) rc = VXIobj_RESULT_NON_FATAL_ERROR; } else { // // Unsupported object // rc = VXIobj_RESULT_UNSUPPORTED; } Diag (log, LOG_API, func, L"exiting: returned %d", rc); return rc; }
/** * Sample object to save a recording to a file * * @param properties [IN] See description in VXIobjectExecute() * or VXIobjectValidate() * @param parameters [IN] See description in VXIobjectExecute() * or VXIobjectValidate() * @param execute [IN] Specifies whether the object should be * executed (true) or simply validated (false) * @param result [OUT] See description in VXIobjectExecute() * or VXIobjectValidate() * * @result VXIobj_RESULT_SUCCESS on success */ static VXIobjResult ProcessComSpeechworksSaveRecordingObject (struct VXIobjectInterface *pThis, const VXIMap *properties, const VXIMap *parameters, VXIbool execute, VXIValue **result) { static const wchar_t func[] = L"ProcessComSpeechworksSaveRecordingObject"; GET_VXIOBJECT (pThis, sbObject, log, rc); if((execute) && (result == NULL)) return VXIobj_RESULT_INVALID_ARGUMENT; if((! properties) || (! parameters)) return VXIobj_RESULT_INVALID_ARGUMENT; // Get the recording, MIME type, size, and destination path const VXIbyte *recording = NULL; const VXIchar *type = NULL, *dest = NULL; VXIulong size = 0; const VXIValue *val = VXIMapGetProperty(parameters, L"recording"); if (! val) { Error(log, 202, L"%s%s", L"parameter", L"recording"); return VXIobj_RESULT_INVALID_PROP_VALUE; } else if (VXIValueGetType(val) != VALUE_CONTENT) { Error(log, 203, L"%s%s%s%d", L"parameter", L"recording", L"type", VXIValueGetType(val)); return VXIobj_RESULT_INVALID_PROP_VALUE; } if (VXIContentValue(reinterpret_cast<const VXIContent *>(val), &type, &recording, &size) != VXIvalue_RESULT_SUCCESS) { Error(log, 204, L"%s%s", L"parameter", L"recording"); return VXIobj_RESULT_INVALID_PROP_VALUE; } else if (size < 1) { Error(log, 204, L"%s%s%s%d", L"parameter", L"recording.size", L"value", L"size"); return VXIobj_RESULT_INVALID_PROP_VALUE; } val = VXIMapGetProperty(parameters, L"dest"); if (! val) { Error(log, 202, L"%s%s", L"parameter", L"dest"); return VXIobj_RESULT_INVALID_PROP_VALUE; } else if (VXIValueGetType(val) != VALUE_STRING) { Error(log, 203, L"%s%s%s%d", L"parameter", L"dest", L"type", VXIValueGetType(val)); return VXIobj_RESULT_INVALID_PROP_VALUE; } dest = VXIStringCStr(reinterpret_cast<const VXIString *>(val)); if (! dest[0]) { Error(log, 204, L"%s%s%s%s", L"parameter", L"dest", L"value", dest); return VXIobj_RESULT_INVALID_PROP_VALUE; } if(execute) { // Convert the destination to narrow characters, use an upside // down question mark for unsupported Unicode characters size_t len = wcslen(dest); char *ndest = new char [len + 1]; if (! ndest) { Error(log, 100, NULL); return VXIobj_RESULT_OUT_OF_MEMORY; } for (size_t i = 0; i <= len; i++) ndest[i] = (dest[i] & 0xff00 ? '\277' : static_cast<char>(dest[i])); // Open the destination and save the file size_t totWritten = 0; #ifdef VXIOBJECT_PERMIT_FILE_WRITES FILE *fp = fopen(ndest, "wb"); delete [] ndest; if (fp) { do { size_t w = fwrite(&recording[totWritten], 1, ((size_t) size) - totWritten, fp); totWritten += w; } while ((totWritten < (size_t) size) && (! ferror(fp))); fclose(fp); } else { Error(log, 205, L"%s%s%s%d", L"file", dest, L"errno", errno); } #else Error(log, 206, L"%s%s", L"file", dest); #endif // Create the result object VXIMap *resultObj = VXIMapCreate(); if(resultObj == NULL) { Error(log, 100, NULL); return VXIobj_RESULT_OUT_OF_MEMORY; } *result = reinterpret_cast<VXIValue *>(resultObj); // Set the result object's status field to 'success' or 'failure' if (totWritten == (size_t) size) VXIMapSetProperty(resultObj, L"status", reinterpret_cast<VXIValue *>(VXIStringCreate(L"success"))); else VXIMapSetProperty(resultObj, L"status", reinterpret_cast<VXIValue *>(VXIStringCreate(L"failure"))); } return VXIobj_RESULT_SUCCESS; }
/** * Sample diagnostic logging object * * @param properties [IN] See description in VXIobjectExecute() * or VXIobjectValidate() * @param parameters [IN] See description in VXIobjectExecute() * or VXIobjectValidate() * @param execute [IN] Specifies whether the object should be * executed (true) or simply validated (false) * @param result [OUT] See description in VXIobjectExecute() * or VXIobjectValidate() * * @result VXIobj_RESULT_SUCCESS on success */ static VXIobjResult ProcessComSpeechworksDiagObject (struct VXIobjectInterface *pThis, const VXIMap *properties, const VXIMap *parameters, VXIbool execute, VXIValue **result) { static const wchar_t func[] = L"ProcessComSpeechworksDiagObject"; GET_VXIOBJECT (pThis, sbObject, log, rc); if((execute) && (result == NULL)) return VXIobj_RESULT_INVALID_ARGUMENT; if((! properties) || (! parameters)) return VXIobj_RESULT_INVALID_ARGUMENT; // Get the tag ID const VXIValue *val = VXIMapGetProperty(parameters, L"tag"); if(val == NULL) { Error(log, 202, L"%s%s", L"parameter", L"tag"); return VXIobj_RESULT_INVALID_PROP_VALUE; } VXIint tag; switch (VXIValueGetType(val)) { case VALUE_INTEGER: tag = VXIIntegerValue((VXIInteger *)val); break; case VALUE_STRING: { wchar_t *ptr; tag = ::wcstol(VXIStringCStr((VXIString *)val), &ptr, 10); } break; default: Error(log, 203, L"%s%s%s%d", L"parameter", L"tag", L"type", VXIValueGetType(val)); return VXIobj_RESULT_INVALID_PROP_VALUE; } // Get the message string val = VXIMapGetProperty(parameters, L"message"); if(val == NULL) { Error(log, 202, L"%s%s", L"parameter", L"message"); return VXIobj_RESULT_INVALID_PROP_VALUE; } // Check whether the message was sent in "data" or "ref" format. // If it is "ref", we need to retrieve it in the embedded map. const VXIchar *messageStr = NULL; switch (VXIValueGetType(val)) { case VALUE_MAP: { const VXIValue *val2 = VXIMapGetProperty((const VXIMap *)val, OBJECT_VALUE); if (VXIValueGetType(val2) == VALUE_STRING) messageStr = VXIStringCStr((VXIString *)val2); } break; case VALUE_STRING: messageStr = VXIStringCStr((VXIString *)val); break; default: Error(log, 203, L"%s%s%s%d", L"parameter", L"message", L"type", VXIValueGetType(val)); return VXIobj_RESULT_INVALID_PROP_VALUE; } if ((! messageStr) || (! messageStr[0])) { Error(log, 204, L"%s%s", L"parameter", L"message"); return VXIobj_RESULT_INVALID_PROP_VALUE; } if(execute) { // Print a diagnostic message using the retrieved arguments. // To see this message, you must enable client.log.diagTag.xxx // in your VXIclient configuration file, where 'xxx' is the // value of client.object.diagLogBase defined in the same file. VXIlogResult rc = Diag (log, tag, NULL, messageStr); // Create the result object VXIMap *resultObj = VXIMapCreate(); if(resultObj == NULL) { Error(log, 100, NULL); return VXIobj_RESULT_OUT_OF_MEMORY; } *result = reinterpret_cast<VXIValue *>(resultObj); // Set the result object's status field to 'success' or 'failure' if(rc == VXIlog_RESULT_SUCCESS) VXIMapSetProperty(resultObj, L"status", reinterpret_cast<VXIValue *>(VXIStringCreate(L"success"))); else VXIMapSetProperty(resultObj, L"status", reinterpret_cast<VXIValue *>(VXIStringCreate(L"failure"))); } return VXIobj_RESULT_SUCCESS; }
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; }
// Open the entry VXIcacheResult SBcacheEntryDetails::Open(VXIlogInterface *log, const SBcacheString &moduleName, const SBcacheKey &key, const SBcachePath &path, VXIcacheOpenMode mode, VXIint32 flags, VXIulong maxSizeBytes, const VXIMap *properties, VXIMap *streamInfo, VXIcacheStream **stream) { VXIcacheResult rc = VXIcache_RESULT_SUCCESS; FILE *filePtr = NULL; // Lock and copy input data switch ( mode ) { case CACHE_MODE_WRITE: if ( _rwMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) { Error (log, 110, L"%s%s", L"mutex", L"cache entry rw mutex, writer"); rc = VXIcache_RESULT_SYSTEM_ERROR; } else { // If the open fails due to directory not existing, call // path.CreateDirectories( ) to create the dir tree then open // again if ( ! _invalidated ) { filePtr = fopen (path.c_str( ), "wb"); int retries = 10; // work around possible race condition w/ rmdir while ((retries-- > 0) && ( ! filePtr ) && ( path.CreateDirectories( ) == VXIcache_RESULT_SUCCESS )) filePtr = fopen (path.c_str( ), "wb"); } if ( ! filePtr ) { if ( _invalidated ) { // Invalidated or another thread attempted an open for write // and failed, we only got here due to a race condition // where we were waiting on the mutex to start our write // before the failure/invalidation happened by the previous // writer rc = VXIcache_RESULT_FAILURE; } else { // File open error LogIOError (log, 213, path); rc = VXIcache_RESULT_IO_ERROR; } _fileExists = false; _rwMutex.Unlock( ); } else { _fileExists = true; _creationCost = CACHE_CREATION_COST_DEFAULT; _flags = flags; _sizeBytes = 0; // Only set the path and key if they differ if (path != _path || key != _key) { _path = path; _key = key; } // Load properties if ( properties ) { const VXIValue *value = VXIMapGetProperty (properties, CACHE_CREATION_COST); if ( value ) { if ( VXIValueGetType(value) == VALUE_INTEGER ) _creationCost = (VXIcacheCreationCost) VXIIntegerValue ((const VXIInteger *) value); else Error (log, 301, L"%s%d", L"VXIValueType", VXIValueGetType(value)); } } } } break; case CACHE_MODE_READ: if ( _rwMutex.StartRead( ) != VXItrd_RESULT_SUCCESS ) { Error (log, 110, L"%s%s", L"mutex", L"cache entry rw mutex, reader"); rc = VXIcache_RESULT_SYSTEM_ERROR; } else { if (( _fileExists ) && ( ! _invalidated )) { filePtr = fopen (_path.c_str( ), "rb"); if ( ! filePtr ) { _fileExists = false; LogIOError (log, 214, _path); _rwMutex.EndRead( ); rc = VXIcache_RESULT_IO_ERROR; } } else { // Invalidated or another thread attempted an open for write // and failed, we only got here due to a race condition where // we were waiting on the mutex to start our read before the // failure/invalidation happened by the writer _rwMutex.EndRead( ); rc = VXIcache_RESULT_FAILURE; } } break; default: Error (log, 215, L"%s%d", L"mode", mode); rc = VXIcache_RESULT_UNSUPPORTED; } if ( rc == VXIcache_RESULT_SUCCESS ) { // Update the accessed time _lastAccessed = time(0); if (mode == CACHE_MODE_WRITE) _lastModified = _lastAccessed; // Return stream information if ( streamInfo ) { if (( VXIMapSetProperty (streamInfo, CACHE_INFO_LAST_MODIFIED, (VXIValue *) VXIIntegerCreate(_lastModified)) != VXIvalue_RESULT_SUCCESS ) || ( VXIMapSetProperty (streamInfo, CACHE_INFO_SIZE_BYTES, (VXIValue *) VXIIntegerCreate (_sizeBytes)) != VXIvalue_RESULT_SUCCESS )) { Error (log, 100, NULL); rc = VXIcache_RESULT_OUT_OF_MEMORY; } } } // Return the stream if ( rc == VXIcache_RESULT_SUCCESS ) { SBcacheEntry entry(this); *stream = new SBcacheStream (log, GetDiagBase( ), moduleName, key, entry, mode, ((flags & CACHE_FLAG_NONBLOCKING_IO) == 0), maxSizeBytes, filePtr); if ( ! *stream ) { Error (log, 100, NULL); fclose (filePtr); Close (log, mode, 0, true); rc = VXIcache_RESULT_OUT_OF_MEMORY; } } Diag (log, SBCACHE_ENTRY_TAGID, L"Open", L"%s, %S, 0x%x, 0x%x: rc = %d", key.c_str( ), path.c_str( ), mode, flags, rc); return rc; }
VXIinetResult SBinetFileStream::Open(VXIint32 flags, const VXIMap *properties, VXIMap *streamInfo) { VXIinetResult returnValue = VXIinet_RESULT_SUCCESS; /* Get the flag to determine whether to open local files. Also check the validator to see if it contains INET_INFO_VALIDATOR and if it does contain the modified time. */ SBinetValidator validator(GetLog(), GetDiagBase()); const VXIValue *validatorVal = NULL; if (properties) { const VXIValue *val = VXIMapGetProperty(properties, INET_OPEN_LOCAL_FILE); if (val != NULL) { if (VXIValueGetType(val) == VALUE_INTEGER) { if (VXIIntegerValue((const VXIInteger *) val) == FALSE) returnValue = VXIinet_RESULT_LOCAL_FILE; } else { Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetFileStream::Open", L"Passed invalid type for INET_OPEN_LOCAL_FILE property"); } } // SBinetValidator::Create() logs errors for us validatorVal = VXIMapGetProperty(properties, INET_OPEN_IF_MODIFIED); if((validatorVal != NULL) && (validator.Create(validatorVal) != VXIinet_RESULT_SUCCESS)) validatorVal = NULL; } Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetFileStream::Open", _url->getAbsolute( )); // Stat the file to make sure it exists and to get the length and // last modified time VXIStatStruct statInfo; if (VXIStat(SBinetNString(_url->getPath()).c_str(), &statInfo) != 0) { Error(222, L"%s%s", L"File", _url->getPath()); return(VXIinet_RESULT_NOT_FOUND); } _content_length = statInfo.st_size; // If there is a conditional open using a validator, see if the // validator is still valid (no need to re-read and re-process) if (validatorVal) { if (! validator.isModified(statInfo.st_mtime, statInfo.st_size)) { Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetFileStream::Open", L"Validator OK, returning NOT_MODIFIED"); returnValue = VXIinet_RESULT_NOT_MODIFIED; } else { Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetFileStream::Open", L"Validator modified, must re-fetch"); } } if (returnValue != VXIinet_RESULT_LOCAL_FILE) { // Use fopen for now. Note: Open support reads for now _pFile = ::fopen( SBinetNString(_url->getPath()).c_str(), "rb" ); if(!_pFile){ Error(223, L"%s%s", L"File", _url->getPath()); return(VXIinet_RESULT_NOT_FOUND); } _ReadSoFar = 0; } if (streamInfo != NULL) { // Set FILE data source information VXIMapSetProperty(streamInfo, INET_INFO_DATA_SOURCE, (VXIValue*) VXIIntegerCreate(INET_DATA_SOURCE_FILE)); // Use extension mapping algorithm to determine MIME content type VXIString *guessContent = _url->getContentTypeFromUrl(); if (guessContent == NULL) { guessContent = VXIStringCreate(_channel->getDefaultMimeType()); // This error message is useful, but unfortunately it gets printed // for all the grammar files etc. whose extensions are unknown... //Error (303, L"%s%s", L"URL", _url->getPath()); } VXIMapSetProperty(streamInfo, INET_INFO_MIME_TYPE, (VXIValue*) guessContent); // Set the absolute path, any file:// prefix and host name is // already stripped prior to this method being invoked VXIMapSetProperty(streamInfo, INET_INFO_ABSOLUTE_NAME, (VXIValue*)VXIStringCreate( _url->getPath() )); // Set the validator property VXIValue *newValidator = NULL; if (returnValue == VXIinet_RESULT_NOT_MODIFIED) { newValidator = VXIValueClone(validatorVal); } else { SBinetValidator validator(GetLog(), GetDiagBase()); if (validator.Create(_url->getPath(), statInfo.st_size, statInfo.st_mtime) == VXIinet_RESULT_SUCCESS) { newValidator = (VXIValue *) validator.serialize(); } } if (newValidator) VXIMapSetProperty(streamInfo, INET_INFO_VALIDATOR, newValidator); else { Error(103, NULL); returnValue = VXIinet_RESULT_OUT_OF_MEMORY; } // Set the size VXIMapSetProperty(streamInfo, INET_INFO_SIZE_BYTES, (VXIValue*)VXIIntegerCreate( _content_length)); } if (!validatorVal && (returnValue == VXIinet_RESULT_NOT_MODIFIED)) return VXIinet_RESULT_SUCCESS; return returnValue; }
// 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; }