📄 promptmanager.cpp
字号:
/****************License************************************************ * * Copyright 2000-2003. ScanSoft, Inc. * * Use of this software is subject to notices and obligations set forth * in the SpeechWorks Public License - Software Version 1.2 which is * included with this software. * * ScanSoft is a registered trademark of ScanSoft, Inc., and OpenSpeech, * SpeechWorks and the SpeechWorks logo are registered trademarks or * trademarks of SpeechWorks International, Inc. in the United States * and other countries. * ***********************************************************************/ #include "PromptManager.hpp" #include "SimpleLogger.hpp" // for SimpleLogger #include "VXIprompt.h" // for VXIpromptInterface #include "VXML.h" // for node names #include "DocumentModel.hpp" // for VXMLNode, VXMLElement #include "CommonExceptions.hpp" // for InterpreterEvent, OutOfMemory #include "PropertyList.hpp" // for PropertyList #include <sstream> #include <iostream> static VXIchar SPACE = ' '; //############################################################################# bool static ConvertValueToString(const VXIValue * value, vxistring & source) { if (value == NULL) return false; switch (VXIValueGetType(value)) { case VALUE_BOOLEAN: { std::basic_stringstream<VXIchar> attrStream; if(VXIBooleanValue(reinterpret_cast<const VXIBoolean *>(value)) == TRUE) attrStream << L"true"; else attrStream << L"false"; source = attrStream.str(); return true; } case VALUE_INTEGER: { std::basic_stringstream<VXIchar> attrStream; attrStream << VXIIntegerValue(reinterpret_cast<const VXIInteger *>(value)); source = attrStream.str(); return true; } case VALUE_FLOAT: { std::basic_stringstream<VXIchar> attrStream; attrStream << VXIFloatValue(reinterpret_cast<const VXIFloat *>(value)); source = attrStream.str(); return true; } case VALUE_STRING: source = VXIStringCStr(reinterpret_cast<const VXIString *>(value)); return true; default: return false; } } inline void AddSSMLAttribute(const VXMLElement & elem, VXMLAttributeType attr, const VXIchar * const defaultVal, const VXIchar * const name, vxistring & sofar) { // Get attribute or use the default value. vxistring attrString; if (!elem.GetAttribute(attr, attrString) || attrString.empty()) { if (defaultVal == NULL) return; attrString = defaultVal; } sofar += SPACE; sofar += name; sofar += L"=\""; // We need to escape three characters: (",<,&) -> (", <, &) vxistring::size_type pos = 0; while ((pos = attrString.find_first_of(L"\"<&", pos)) != vxistring::npos) { switch (attrString[pos]) { case '\"': attrString.replace(pos, 1, L"""); ++pos; break; case '<': attrString.replace(pos, 1, L"<"); ++pos; break; case '&': attrString.replace(pos, 1, L"&"); ++pos; break; } }; sofar += attrString; sofar += L"\""; } inline void AppendTextSegment(vxistring & sofar, const vxistring & addition) { if (addition.empty()) return; vxistring::size_type pos = sofar.length(); sofar += addition; // We need to escape two characters: (<,&) -> (<, &) // NOTE: It starts from the old length and operates only on the addition. while ((pos = sofar.find_first_of(L"<&", pos)) != vxistring::npos) { switch (sofar[pos]) { case '<': sofar.replace(pos, 1, L"<"); ++pos; break; case '&': sofar.replace(pos, 1, L"&"); ++pos; break; } } } //############################################################################# //////// // About prompts: // // Prompts may be defined in two places within VXML documents. // 1) form items - menu, field, initial, record, transfer, subdialog, object // 2) executable content - block, catch, filled // // The <enumerate> element only is valid with parent menu or fields having one // or more option elements. Otherwise an error.semantic results. // // From the VXML working drafts, barge-in may be controlled on a prompt by // prompt basis. There are several unresolved issues with this request. // Instead this implements a different tactic. void PromptManager::ThrowEventIfError(VXIpromptResult rc) { switch( rc ) { case VXIprompt_RESULT_SUCCESS: break; case VXIprompt_RESULT_TTS_BAD_LANGUAGE: throw VXIException::InterpreterEvent(EV_UNSUPPORT_LANGUAGE); case VXIprompt_RESULT_FETCH_TIMEOUT: case VXIprompt_RESULT_FETCH_ERROR: case VXIprompt_RESULT_NON_FATAL_ERROR: throw VXIException::InterpreterEvent(EV_ERROR_BADFETCH); case VXIprompt_RESULT_HW_BAD_TYPE: throw VXIException::InterpreterEvent(EV_UNSUPPORT_FORMAT); case VXIprompt_RESULT_TTS_ACCESS_ERROR: case VXIprompt_RESULT_NO_RESOURCE: throw VXIException::InterpreterEvent(EV_ERROR_NORESOURCE); case VXIprompt_RESULT_NO_AUTHORIZATION: throw VXIException::InterpreterEvent(EV_ERROR_NOAUTHORIZ); case VXIprompt_RESULT_BAD_SAYAS_CLASS: case VXIprompt_RESULT_TTS_BAD_DOCUMENT: case VXIprompt_RESULT_TTS_SYNTAX_ERROR: case VXIprompt_RESULT_TTS_ERROR: default: throw VXIException::InterpreterEvent(EV_ERROR_SEMANTIC); } } void PromptManager::WaitAndCheckError() { VXIpromptResult rc; prompt->Wait(prompt, &rc); ThrowEventIfError(rc); } bool PromptManager::ConnectResources(SimpleLogger * l, VXIpromptInterface * p) { if (l == NULL || p == NULL) return false; log = l; prompt = p; enabledSegmentInQueue = false; playedBargeinDisabledPrompt = false; timeout = -1; return true; } void PromptManager::PlayFiller(const vxistring & src, const VXIMapHolder & properties) { log->LogDiagnostic(2, L"PromptManager::PlayFiller()"); if (src.empty()) return; const VXIMap * propMap = properties.GetValue(); // Get fetchaudiominimum value VXIint minPlayMsec = 0; const VXIValue * val = (VXIMapGetProperty(propMap, L"fetchaudiominimum")); if( val && VXIValueGetType(val) == VALUE_STRING ) { const VXIchar* fmin = VXIStringCStr(reinterpret_cast<const VXIString*>(val)); if( fmin ) PropertyList::ConvertTimeToMilliseconds(*log, fmin, minPlayMsec); } prompt->PlayFiller(prompt, NULL, src.c_str(), NULL, propMap, minPlayMsec); } void PromptManager::Play(bool *playedBDPrompt) { log->LogDiagnostic(2, L"PromptManager::Play()"); *playedBDPrompt = playedBargeinDisabledPrompt; //VXIpromptResult temp; //prompt->Wait(prompt, &temp); WaitAndCheckError(); prompt->Play(prompt); enabledSegmentInQueue = false; playedBargeinDisabledPrompt = false; timeout = -1; } void PromptManager::PlayAll() { log->LogDiagnostic(2, L"PromptManager::PlayAll()"); prompt->Play(prompt); //VXIpromptResult temp; //prompt->Wait(prompt, &temp); WaitAndCheckError(); enabledSegmentInQueue = false; playedBargeinDisabledPrompt = false; timeout = -1; } int PromptManager::GetMillisecondTimeout() const { return timeout; } void PromptManager::Queue(const VXMLElement & elem, const VXMLElement & ref, const PropertyList & propertyList, PromptTranslator & translator) { log->LogDiagnostic(2, L"PromptManager::Queue()"); // (1) Find <field> or <menu> associated with this prompt, if any. This is // used by the <enumerate> element. VXMLElement item = ref; while (item != 0) { VXMLElementType type = item.GetName(); if (type == NODE_FIELD || type == NODE_MENU) break; item = item.GetParent(); } // (2) Get properties. VXIMapHolder properties; if (properties.GetValue() == NULL) throw VXIException::OutOfMemory(); // (2.1) Flatten the property list. propertyList.GetProperties(properties); // (2.2) Add the URI information. propertyList.GetFetchobjBase(properties); // (3) Handle <prompt> elements // (3.1) Update timeout if specified. vxistring timeoutString; if (elem.GetAttribute(ATTRIBUTE_TIMEOUT, timeoutString) == true) PropertyList::ConvertTimeToMilliseconds(*log, timeoutString, timeout); // (3.2) Get bargein setting. PromptManager::BargeIn bargein = PromptManager::ENABLED; const VXIchar * j = propertyList.GetProperty(PROP_BARGEIN); if (j != NULL && vxistring(L"false") == j) bargein = PromptManager::DISABLED; vxistring bargeinAttr; if (elem.GetAttribute(ATTRIBUTE_BARGEIN, bargeinAttr) == true) { bargein = PromptManager::ENABLED; if (bargeinAttr == L"false") bargein = PromptManager::DISABLED; // override default bargein attribute VXIMapSetProperty(properties.GetValue(), PROP_BARGEIN, (VXIValue*)VXIStringCreate(bargeinAttr.c_str())); } vxistring bargeinType; if (elem.GetAttribute(ATTRIBUTE_BARGEINTYPE, bargeinType) == true) { // override default bargeintype attribute VXIMapSetProperty(properties.GetValue(), PROP_BARGEINTYPE, (VXIValue*)VXIStringCreate(bargeinType.c_str())); } // (4) Build prompt, recursively handling the contents. vxistring content; for (VXMLNodeIterator it(elem); it; ++it) ProcessSegments(*it, item, propertyList, translator, bargein, properties, content); if (content.empty()) return; // (5) Add a new segment. AddSegment(SEGMENT_SSML, content, properties, bargein); } void PromptManager::Queue(const vxistring & uri) { if (uri.empty()) return; AddSegment(PromptManager::SEGMENT_AUDIO, uri, VXIMapHolder(), PromptManager::UNSPECIFIED); } bool PromptManager::AddSegment(PromptManager::SegmentType type, const vxistring & data, const VXIMapHolder & properties, PromptManager::BargeIn bargein, bool throwExceptions) { const VXIMap * propMap = properties.GetValue(); VXIpromptResult result; // Handle the easy case. switch (type) { case PromptManager::SEGMENT_AUDIO: result = prompt->Queue(prompt, NULL, data.c_str(), NULL, propMap); break; case PromptManager::SEGMENT_SSML: result = prompt->Queue(prompt, VXI_MIME_SSML, NULL, data.c_str(), propMap); break; } if (throwExceptions) { ThrowEventIfError(result); } switch (bargein) { case PromptManager::DISABLED: if (!enabledSegmentInQueue) { prompt->Play(prompt); playedBargeinDisabledPrompt = true; } break; case PromptManager::ENABLED: enabledSegmentInQueue = true; break; case PromptManager::UNSPECIFIED: break; } return result == VXIprompt_RESULT_SUCCESS; } void PromptManager::ProcessSegments(const VXMLNode & node, const VXMLElement & item, const PropertyList & propertyList, PromptTranslator & translator, PromptManager::BargeIn bargein, VXIMapHolder & props, vxistring & sofar) { // (1) Handle bare content. switch (node.GetType()) { case VXMLNode::Type_VXMLContent: { const VXMLContent & content = reinterpret_cast<const VXMLContent &>(node); sofar += content.GetValue(); return; } case VXMLNode::Type_VXMLElement: break; default: // This should never happen. log->LogError(999, SimpleLogger::MESSAGE, L"unexpected type in PromptManager::ProcessSegments"); throw VXIException::Fatal(); } // (2) Retrieve fetch properties (if we haven't already) const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(node); vxistring attr; switch (elem.GetName()) { // (3) audio
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -