📄 vxml.cxx
字号:
void PVXMLPlayableCommand::OnStop()
{
if (pipeCmd != NULL) {
pipeCmd->WaitForTermination();
delete pipeCmd;
}
}
PFactory<PVXMLPlayable>::Worker<PVXMLPlayableCommand> vxmlPlayableCommandFactory("Command");
///////////////////////////////////////////////////////////////
BOOL PVXMLPlayableData::Open(PVXMLChannel & chan, const PString & /*_fn*/, PINDEX _delay, PINDEX _repeat, BOOL v)
{
return PVXMLPlayable::Open(chan, _delay, _repeat, v);
}
void PVXMLPlayableData::SetData(const PBYTEArray & _data)
{
data = _data;
}
void PVXMLPlayableData::Play(PVXMLChannel & outgoingChannel)
{
PMemoryFile * chan = new PMemoryFile(data);
PTRACE(3, "PVXML\tPlaying " << data.GetSize() << " bytes");
outgoingChannel.SetReadChannel(chan, TRUE);
}
BOOL PVXMLPlayableData::Rewind(PChannel * chan)
{
PMemoryFile * memfile = dynamic_cast<PMemoryFile *>(chan);
if (memfile == NULL)
return FALSE;
return memfile->SetPosition(0);
}
PFactory<PVXMLPlayable>::Worker<PVXMLPlayableData> vxmlPlayableDataFactory("PCM Data");
///////////////////////////////////////////////////////////////
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;
autoDeleteTextToSpeech = FALSE;
}
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;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -