📄 vxml.cxx
字号:
///////////////////////////////////////////////////////////////BOOL PVXMLPlayableURL::Open(PVXMLChannel & chan, const PString & _url, PINDEX _delay, PINDEX _repeat, BOOL autoDelete){ url = arg = _url; return PVXMLPlayable::Open(chan, _delay, _repeat, autoDelete); }void PVXMLPlayableURL::Play(PVXMLChannel & outgoingChannel){ // open the resource PHTTPClient * client = new PHTTPClient; PMIMEInfo outMIME, replyMIME; int code = client->GetDocument(url, outMIME, replyMIME, FALSE); if ((code != 200) || (replyMIME(PHTTP::TransferEncodingTag) *= PHTTP::ChunkedTag)) delete client; else { outgoingChannel.SetReadChannel(client, TRUE); }}PFactory<PVXMLPlayable>::Worker<PVXMLPlayableURL> vxmlPlayableURLFactory("URL");///////////////////////////////////////////////////////////////BOOL PVXMLRecordableFilename::Open(const PString & _arg){ fn = _arg; consecutiveSilence = 0; return TRUE;}void PVXMLRecordableFilename::Record(PVXMLChannel & outgoingChannel){ PChannel * chan = NULL; // check the file extension and open a .wav or a raw (.sw or .g723) file if ((fn.Right(4)).ToLower() == ".wav") chan = outgoingChannel.CreateWAVFile(fn, TRUE); else { PFile * fileChan = new PFile(fn); if (fileChan->Open(PFile::WriteOnly)) chan = fileChan; else { delete fileChan; } } if (chan == NULL) PTRACE(3, "PVXML\tCannot open file \"" << fn << "\""); else { PTRACE(3, "PVXML\tRecording to file \"" << fn << "\""); outgoingChannel.SetWriteChannel(chan, TRUE); } recordStart = PTime(); silenceStart = PTime(); consecutiveSilence = 0;}BOOL PVXMLRecordableFilename::OnFrame(BOOL isSilence){ if (!isSilence) { silenceStart = PTime(); consecutiveSilence = 0; } else { consecutiveSilence++; if ( ((consecutiveSilence % 20) == 0) && ( ((finalSilence > 0) && ((PTime() - silenceStart).GetMilliSeconds() >= finalSilence)) || ((maxDuration > 0) && ((PTime() - recordStart).GetMilliSeconds() >= maxDuration)) ) ) return TRUE; } return FALSE;}///////////////////////////////////////////////////////////////PVXMLCache::PVXMLCache(const PDirectory & _directory) : directory(_directory){ if (!directory.Exists()) directory.Create();}static PString MD5AsHex(const PString & str){ PMessageDigest::Result digest; PMessageDigest5::Encode(str, digest); PString hexStr; const BYTE * data = digest.GetPointer(); for (PINDEX i = 0; i < digest.GetSize(); ++i) hexStr.sprintf("%02x", (unsigned)data[i]); return hexStr;}PFilePath PVXMLCache::CreateFilename(const PString & prefix, const PString & key, const PString & fileType){ PString md5 = MD5AsHex(key); PString md5_2 = MD5AsHex(key); return directory + ((prefix + "_") + md5 + fileType);}BOOL PVXMLCache::Get(const PString & prefix, const PString & key, const PString & fileType, PString & contentType, PFilePath & dataFn){ PWaitAndSignal m(*this); dataFn = CreateFilename(prefix, key, "." + fileType); PFilePath typeFn = CreateFilename(prefix, key, "_type.txt"); if (!PFile::Exists(dataFn) || !PFile::Exists(typeFn)) { PTRACE(4, "Key \"" << key << "\" not found in cache"); return FALSE; } PTextFile typeFile(typeFn, PFile::ReadOnly); if (!typeFile.IsOpen()) { PTRACE(4, "Cannot find type for cached key " << key << " in cache"); PFile::Remove(dataFn); return FALSE; } typeFile.ReadLine(contentType); contentType.Trim(); if (contentType.IsEmpty()) contentType = GetContentType(dataFn); return TRUE;}void PVXMLCache::Put(const PString & prefix, const PString & key, const PString & fileType, const PString & contentType, const PFilePath & fn, PFilePath & dataFn){ PWaitAndSignal m(*this); // create the filename for the cache files dataFn = CreateFilename(prefix, key, "." + fileType); PFilePath typeFn = CreateFilename(prefix, key, "_type.txt"); // write the content type file PTextFile typeFile(typeFn, PFile::WriteOnly); if (contentType.IsEmpty()) typeFile.WriteLine(GetContentType(fn)); else typeFile.WriteLine(contentType); // rename the file to the correct name PFile::Rename(fn, dataFn.GetFileName(), TRUE);}PVXMLCache & PVXMLCache::GetResourceCache(){ static PVXMLCache cache(PDirectory() + "cache"); return cache;}PFilePath PVXMLCache::GetRandomFilename(const PString & prefix, const PString & fileType){ PFilePath fn; // create a random temporary filename PRandom r; for (;;) { fn = directory + psprintf("%s_%i.%s", (const char *)prefix, r.Generate() % 1000000, (const char *)fileType); if (!PFile::Exists(fn)) break; } return fn;}//////////////////////////////////////////////////////////PVXMLSession::PVXMLSession(PTextToSpeech * _tts, BOOL autoDelete){ vxmlThread = NULL; vxmlChannel = NULL; finishWhenEmpty = TRUE; textToSpeech = NULL; SetTextToSpeech(_tts, autoDelete); Initialise();}void PVXMLSession::Initialise(){ recording = FALSE; allowFinish = FALSE; listening = FALSE; activeGrammar = NULL; listening = FALSE; forceEnd = FALSE; currentForm = NULL; currentNode = NULL;}PVXMLSession::~PVXMLSession(){ Close(); if ((textToSpeech != NULL) && autoDeleteTextToSpeech) delete textToSpeech;}PTextToSpeech * PVXMLSession::SetTextToSpeech(PTextToSpeech * _tts, BOOL autoDelete){ PWaitAndSignal m(sessionMutex); if (autoDeleteTextToSpeech && (textToSpeech != NULL)) delete textToSpeech; autoDeleteTextToSpeech = autoDelete; textToSpeech = _tts; return textToSpeech;}PTextToSpeech * PVXMLSession::SetTextToSpeech(const PString & ttsName){ PWaitAndSignal m(sessionMutex); if (autoDeleteTextToSpeech && (textToSpeech != NULL)) delete textToSpeech; autoDeleteTextToSpeech = TRUE; textToSpeech = PFactory<PTextToSpeech>::CreateInstance(ttsName); return textToSpeech;}BOOL PVXMLSession::Load(const PString & source){ // Lets try and guess what was passed, if file exists then is file PFilePath file = source; if (PFile::Exists(file)) return LoadFile(file); // see if looks like URL PINDEX pos = source.Find(':'); if (pos != P_MAX_INDEX) { PString scheme = source.Left(pos); if ((scheme *= "http") || (scheme *= "https") || (scheme *= "file")) return LoadURL(source); } // See if is actual VXML if (PCaselessString(source).Find("<vxml") != P_MAX_INDEX) return LoadVXML(source); return FALSE;}BOOL PVXMLSession::LoadFile(const PFilePath & filename){ // create a file URL from the filename return LoadURL(filename);}BOOL PVXMLSession::LoadURL(const PURL & url){ // retreive the document (may be a HTTP get) PFilePath fn; PString contentType; if (!RetreiveResource(url, contentType, fn, FALSE)) { PTRACE(1, "PVXML\tCannot load document " << url); return FALSE; } PTextFile file(fn, PFile::ReadOnly); if (!file.IsOpen()) { PTRACE(1, "PVXML\tCannot read data from " << fn); return FALSE; } off_t len = file.GetLength(); PString text; file.Read(text.GetPointer(len+1), len); len = file.GetLastReadCount(); text.SetSize(len+1); text[(PINDEX)len] = '\0'; if (!LoadVXML(text)) { PTRACE(1, "PVXML\tCannot load VXML in " << url); return FALSE; } rootURL = url; return TRUE;}BOOL PVXMLSession::LoadVXML(const PString & xmlText){ PWaitAndSignal m(sessionMutex); allowFinish = loaded = FALSE; rootURL = PString::Empty(); // parse the XML xmlFile.RemoveAll(); if (!xmlFile.Load(xmlText)) { PTRACE(1, "PVXML\tCannot parse root document: " << GetXMLError()); return FALSE; } PXMLElement * root = xmlFile.GetRootElement(); if (root == NULL) return FALSE; // reset interpeter state Initialise(); // find the first form if ((currentForm = FindForm(PString::Empty())) == NULL) return FALSE; // start processing with this <form> element currentNode = currentForm; loaded = TRUE; return TRUE;}PURL PVXMLSession::NormaliseResourceName(const PString & src){ // if resource name has a scheme, then use as is PINDEX pos = src.Find(':'); if ((pos != P_MAX_INDEX) && (pos < 5)) return src; if (rootURL.IsEmpty()) return "file:" + src; // else use scheme and path from root document PURL url = rootURL; PStringArray path = url.GetPath(); PString pathStr; if (path.GetSize() > 0) { pathStr += path[0]; PINDEX i; for (i = 1; i < path.GetSize()-1; i++) pathStr += "/" + path[i]; pathStr += "/" + src; url.SetPathStr(pathStr); } return url;}BOOL PVXMLSession::RetreiveResource(const PURL & url, PString & contentType, PFilePath & dataFn, BOOL useCache){ BOOL stat = FALSE; // files on the local file system get loaded locally if (url.GetScheme() *= "file") { dataFn = url.AsFilePath(); if (contentType.IsEmpty()) contentType = GetContentType(dataFn); stat = TRUE; } // do a HTTP get when appropriate else if ((url.GetScheme() *= "http") || (url.GetScheme() *= "https")) { PFilePath fn; PString fileType = url.AsFilePath().GetType(); BOOL inCache = FALSE; if (useCache) inCache = PVXMLCache::GetResourceCache().Get("url", url.AsString(), fileType, contentType, dataFn); if (!inCache) { // get a random filename fn = PVXMLCache::GetResourceCache().GetRandomFilename("url", fileType); // get the resource header information PHTTPClient client; PMIMEInfo outMIME, replyMIME; if (!client.GetDocument(url, outMIME, replyMIME)) { PTRACE(2, "PVXML\tCannot load resource " << url); stat =FALSE; } else { // Get the body of the response in a PBYTEArray (might be binary data) PBYTEArray incomingData; client.ReadContentBody(replyMIME, incomingData); contentType = replyMIME(PHTTPClient::ContentTypeTag); // write the data in the file PFile cacheFile(fn, PFile::WriteOnly); cacheFile.Write(incomingData.GetPointer(), incomingData.GetSize() ); // if we have a cache and we are using it, then save the data if (useCache) PVXMLCache::GetResourceCache().Put("url", url.AsString(), fileType, contentType, fn, dataFn); // data is loaded stat = TRUE; } } } // files on the local file system get loaded locally else if (url.GetScheme() *= "file") { dataFn = url.AsFilePath(); stat = TRUE; } // unknown schemes give an error else stat = FALSE; return stat;}PXMLElement * PVXMLSession::FindForm(const PString & id){ // NOTE: should have some flag to know if it is loaded PXMLElement * root = xmlFile.GetRootElement(); if (root == NULL) return NULL; // Only handle search of top level nodes for <form> element PINDEX i; for (i = 0; i < root->GetSize(); i++) { PXMLObject * xmlObject = root->GetElement(i); if (xmlObject->IsElement()) { PXMLElement * xmlElement = (PXMLElement*)xmlObject; if ( (xmlElement->GetName() *= "form") && (id.IsEmpty() || (xmlElement->GetAttribute("id") *= id)) ) return xmlElement; } } return NULL;}BOOL PVXMLSession::Open(BOOL isPCM){ if (isPCM) return Open(VXML_PCM16); else return Open(VXML_G7231);}BOOL PVXMLSession::Open(const PString & _mediaFormat){ mediaFormat = _mediaFormat; PVXMLChannel * chan = PFactory<PVXMLChannel>::CreateInstance(mediaFormat); if (chan == NULL) { PTRACE(1, "VXML\tCannot create VXML channel with format " << mediaFormat); return FALSE; } // set the underlying channel if (!PIndirectChannel::Open(chan, chan)) return FALSE; // start the VXML session in another thread
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -