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; }
// 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; }
/** * 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; }
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 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); VXIchar* input = NULL; VXIMap* res = NULL; VXIchar* str = NULL; VXIchar console[512]; bool recordUtterance = false; bool haveUtterance = true; // DEBUG if (voiceglue_loglevel() >= LOG_DEBUG) { std::ostringstream logstring; logstring << "VXIrecRecognize called with properties " << VXIValue_to_Std_String ((const VXIValue *) properties); voiceglue_log ((char) LOG_DEBUG, logstring); }; if (properties != NULL) { const VXIValue * ru = VXIMapGetProperty(properties, REC_RECORDUTTERANCE); if (ru) recordUtterance = wcscmp(VXIStringCStr((const VXIString*)ru), L"true") == 0; /* Ignore force-feed input option 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); */ /* Ignore console input option 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")); } */ } // Get NLSML recognition result from perl in nlsmlresult vxistring nlsmlresult; VXIrecResult rec_res; rec_res = voiceglue_recognize (properties, nlsmlresult); if (rec_res != VXIrec_RESULT_SUCCESS) { return (rec_res); }; // Create a new results structure. const unsigned int CHARSIZE = sizeof(VXIchar) / sizeof(VXIbyte); VXIContent * xmlresult = NULL; 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; } 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; return VXIrec_RESULT_SUCCESS; }
/** * Bridging Transfer. * */ static VXItelResult OSBtelTransferBridge(VXItelInterface * vxip, const VXIMap * prop, const VXIchar * transferDestination, const VXIMap * data, VXIMap **resp) { OSBtelImpl *impl = ToOSBtelImpl(vxip); Diag(impl, DIAG_TAG_SIGNALING, NULL, L"TransferBridge: %s", transferDestination); *resp = VXIMapCreate(); VXIchar* dest = 0; VXIchar* xaudio = 0; if (prop != NULL) { VXIString* vect =(VXIString*)VXIMapGetProperty(prop, L"Destination"); if (vect != NULL) dest = (VXIchar*) VXIStringCStr(vect); vect =(VXIString*)VXIMapGetProperty(prop, TEL_TRANSFER_AUDIO); if (vect != NULL) xaudio = (VXIchar*) VXIStringCStr(vect); } *resp = VXIMapCreate(); if (impl->callId && transferDestination) { vxistring dest = transferDestination; if (! dest.empty()) { char* str = 0; int len = dest.length() + 1; if (len > 0) { str = new char [len + 1]; wcstombs(str, transferDestination, len); str[len] = 0; } if (str) { UtlString from(str); HttpMessage::unescape( from ); if (impl->live == 1) { impl->pCallMgr->connect((char*)impl->callId, from.data()); impl->transferred = 0; int state = 0; int status = VXItel_TRANSFER_UNKNOWN; int duration = 0; OsTime startTime; OsTime endTime; OsDateTimeBase::getCurTime(startTime); VXItelResult ret; do { ret = setTransferState(impl, prop, transferDestination, resp, &state, &status); } while (state != PtEvent::CONNECTION_DISCONNECTED && state != PtEvent::CONNECTION_FAILED && ret != VXItel_RESULT_TIMEOUT); OsDateTimeBase::getCurTime(endTime); duration = (endTime.cvtToMsecs() - startTime.cvtToMsecs())/1000; VXIMapSetProperty(*resp, TEL_TRANSFER_STATUS, (VXIValue *) VXIIntegerCreate(status)); VXIMapSetProperty(*resp, TEL_TRANSFER_DURATION, (VXIValue *)VXIIntegerCreate(duration)); } else { Diag(impl, DIAG_TAG_SIGNALING, NULL, L"Exiting called, live=%d, cancel TransferBridge: %s", impl->live, transferDestination); } } } } return VXItel_RESULT_SUCCESS; }
/** * Blind Transfer. */ static VXItelResult OSBtelTransferBlind(VXItelInterface * vxip, const VXIMap * prop, const VXIchar * transferDestination, const VXIMap * data, VXIMap ** resp) { OSBtelImpl *impl = ToOSBtelImpl(vxip); Diag(impl, DIAG_TAG_SIGNALING, NULL, L"TransferBlind: %s", transferDestination); VXIchar* best = (VXIchar *) calloc(128, sizeof(VXIchar)); if (prop != NULL) { VXIString* vect =(VXIString*)VXIMapGetProperty(prop, L"Destination"); if (vect != NULL) best = (VXIchar*) VXIStringCStr(vect); } *resp = VXIMapCreate(); if (impl->callId && transferDestination) { vxistring dest = transferDestination; if (! dest.empty()) { char* str = 0; int len = dest.length() + 1; if (len > 0) { str = new char [len + 1]; wcstombs(str, transferDestination, len); str[len] = 0; } if (str) { UtlString from(str); HttpMessage::unescape( from ); OsSysLog::add(FAC_MEDIASERVER_VXI, PRI_DEBUG, "OSBtelTransferBlind from = '%s'", from.data()); if (impl->live == 1) { if (PT_SUCCESS == impl->pCallMgr->transfer_blind((char*)impl->callId, from.data(), // to url 0, // target call id 0, // target connect addr false // no remote hold first ) ) { impl->transferred = 0; int state = 0; int status = VXItel_TRANSFER_UNKNOWN; int duration = 0; OsTime startTime; OsTime endTime; OsDateTimeBase::getCurTime(startTime); setTransferState(impl, prop, transferDestination, resp, &state, &status); OsDateTimeBase::getCurTime(endTime); duration = (endTime.cvtToMsecs() - startTime.cvtToMsecs())/1000; VXIMapSetProperty(*resp, TEL_TRANSFER_STATUS, (VXIValue *) VXIIntegerCreate(status)); VXIMapSetProperty(*resp, TEL_TRANSFER_DURATION, (VXIValue *)VXIIntegerCreate(duration)); } } else { Diag(impl, DIAG_TAG_SIGNALING, NULL, L"Exiting called, live=%d, cancel TransferBlind: %s", impl->live, transferDestination); } } } } return VXItel_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; }
// 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; }