PTLib Version 2.10.2
vxml.h
Go to the documentation of this file.
00001 /*
00002  * vxml.h
00003  *
00004  * VXML engine for pwlib library
00005  *
00006  * Copyright (C) 2002 Equivalence Pty. Ltd.
00007  *
00008  * The contents of this file are subject to the Mozilla Public License
00009  * Version 1.0 (the "License"); you may not use this file except in
00010  * compliance with the License. You may obtain a copy of the License at
00011  * http://www.mozilla.org/MPL/
00012  *
00013  * Software distributed under the License is distributed on an "AS IS"
00014  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
00015  * the License for the specific language governing rights and limitations
00016  * under the License.
00017  *
00018  * The Original Code is Portable Windows Library.
00019  *
00020  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
00021  *
00022  * Contributor(s): ______________________________________.
00023  *
00024  * $Revision: 25892 $
00025  * $Author: rjongbloed $
00026  * $Date: 2011-05-25 20:27:19 -0500 (Wed, 25 May 2011) $
00027  */
00028 
00029 #ifndef PTLIB_VXML_H
00030 #define PTLIB_VXML_H
00031 
00032 #ifdef P_USE_PRAGMA
00033 #pragma interface
00034 #endif
00035 
00036 
00037 #include <ptclib/pxml.h>
00038 
00039 #if P_VXML
00040 
00041 #include <ptlib/pfactory.h>
00042 #include <ptlib/pipechan.h>
00043 #include <ptclib/delaychan.h>
00044 #include <ptclib/pwavfile.h>
00045 #include <ptclib/ptts.h>
00046 #include <ptclib/url.h>
00047 
00048 #include <queue>
00049 
00050 
00051 class PVXMLSession;
00052 class PVXMLDialog;
00053 class PVXMLSession;
00054 
00055 // these are the same strings as the Opal equivalents, but as this is PWLib, we can't use Opal contants
00056 #define VXML_PCM16         "PCM-16"
00057 #define VXML_G7231         "G.723.1"
00058 #define VXML_G729          "G.729"
00059 
00060 
00062 
00063 class PVXMLGrammar : public PObject
00064 {
00065   PCLASSINFO(PVXMLGrammar, PObject);
00066   public:
00067     PVXMLGrammar(PXMLElement * field);
00068     virtual PBoolean OnUserInput(const char /*ch*/) { return true; }
00069     virtual void Stop() { }
00070 
00071     PString GetValue() const { return value; }
00072     PXMLElement * GetField() { return field; }
00073 
00074     enum GrammarState { 
00075       FILLED,       
00076       NOINPUT,      
00077       NOMATCH,      
00078       HELP };       
00079 
00080     GrammarState GetState() const { return state; }
00081 
00082   protected:
00083     PXMLElement * field;
00084     PString value;
00085     GrammarState state;
00086 };
00087 
00088 
00090 
00091 class PVXMLMenuGrammar : public PVXMLGrammar
00092 {
00093   PCLASSINFO(PVXMLMenuGrammar, PVXMLGrammar);
00094   public:
00095     PVXMLMenuGrammar(PXMLElement * field);
00096 };
00097 
00098 
00100 
00101 class PVXMLDigitsGrammar : public PVXMLGrammar
00102 {
00103   PCLASSINFO(PVXMLDigitsGrammar, PVXMLGrammar);
00104   public:
00105     PVXMLDigitsGrammar(PXMLElement * field, PINDEX minDigits, PINDEX maxDigits, PString terminators);
00106     PBoolean OnUserInput(const char ch);
00107     virtual void Stop();
00108 
00109   protected:
00110     PINDEX minDigits;
00111     PINDEX maxDigits;
00112     PString terminators;
00113 };
00114 
00115 
00117 
00118 class PVXMLCache : public PMutex
00119 {
00120   public:
00121     PVXMLCache(const PDirectory & directory);
00122 
00123     PFilePath CreateFilename(const PString & prefix, const PString & key, const PString & fileType);
00124 
00125     void Put(const PString & prefix,
00126              const PString & key, 
00127              const PString & fileType, 
00128              const PString & contentType,       
00129            const PFilePath & fn, 
00130                  PFilePath & dataFn);
00131 
00132     PBoolean Get(const PString & prefix,
00133              const PString & key, 
00134              const PString & fileType, 
00135                    PString & contentType,       
00136                  PFilePath & fn);
00137 
00138     PFilePath GetCacheDir() const
00139     { return directory; }
00140 
00141     PFilePath GetRandomFilename(const PString & prefix, const PString & fileType);
00142 
00143     static PVXMLCache & GetResourceCache();
00144 
00145   protected:
00146     PDirectory directory;
00147 };
00148 
00150 
00151 class PVXMLChannel;
00152 
00153 class PVXMLChannelInterface {
00154   public:
00155     virtual ~PVXMLChannelInterface() { }
00156     virtual void RecordEnd() = 0;
00157     virtual void OnEndRecording(const PString & channelName) = 0;
00158     virtual void Trigger() = 0;
00159 };
00160 
00162 
00163 class PVXMLSession : public PIndirectChannel, public PVXMLChannelInterface
00164 {
00165   PCLASSINFO(PVXMLSession, PIndirectChannel);
00166   public:
00167     PVXMLSession(PTextToSpeech * tts = NULL, PBoolean autoDelete = false);
00168     virtual ~PVXMLSession();
00169 
00170     // new functions
00171     PTextToSpeech * SetTextToSpeech(PTextToSpeech * tts, PBoolean autoDelete = false);
00172     PTextToSpeech * SetTextToSpeech(const PString & ttsName);
00173     PTextToSpeech * GetTextToSpeech() const { return textToSpeech; }
00174 
00175     virtual PBoolean Load(const PString & source);
00176     virtual PBoolean LoadFile(const PFilePath & file);
00177     virtual PBoolean LoadURL(const PURL & url);
00178     virtual PBoolean LoadVXML(const PString & xml);
00179     virtual PBoolean IsLoaded() const { return loaded; }
00180 
00181     virtual PBoolean Open(const PString & mediaFormat);
00182     virtual PBoolean Close();
00183 
00184     virtual PBoolean Execute();
00185 
00186     PVXMLChannel * GetAndLockVXMLChannel();
00187     void UnLockVXMLChannel() { sessionMutex.Signal(); }
00188     PMutex & GetSessionMutex() { return sessionMutex; }
00189 
00190     virtual PBoolean LoadGrammar(PVXMLGrammar * grammar);
00191 
00192     virtual PBoolean PlayText(const PString & text, PTextToSpeech::TextType type = PTextToSpeech::Default, PINDEX repeat = 1, PINDEX delay = 0);
00193     PBoolean ConvertTextToFilenameList(const PString & text, PTextToSpeech::TextType type, PStringArray & list, PBoolean useCacheing);
00194 
00195     virtual PBoolean PlayFile(const PString & fn, PINDEX repeat = 1, PINDEX delay = 0, PBoolean autoDelete = false);
00196     virtual PBoolean PlayData(const PBYTEArray & data, PINDEX repeat = 1, PINDEX delay = 0);
00197     virtual PBoolean PlayCommand(const PString & data, PINDEX repeat = 1, PINDEX delay = 0);
00198     virtual PBoolean PlayResource(const PURL & url, PINDEX repeat = 1, PINDEX delay = 0);
00199     virtual PBoolean PlayTone(const PString & toneSpec, PINDEX repeat = 1, PINDEX delay = 0);
00200 
00201     //virtual PBoolean PlayMedia(const PURL & url, PINDEX repeat = 1, PINDEX delay = 0);
00202     virtual PBoolean PlaySilence(PINDEX msecs = 0);
00203     virtual PBoolean PlaySilence(const PTimeInterval & timeout);
00204 
00205     virtual PBoolean PlayStop();
00206 
00207     virtual void SetPause(PBoolean pause);
00208     virtual void GetBeepData(PBYTEArray & data, unsigned ms);
00209 
00210     virtual PBoolean StartRecording(const PFilePath & fn, PBoolean recordDTMFTerm, const PTimeInterval & recordMaxTime, const PTimeInterval & recordFinalSilence);
00211     virtual PBoolean EndRecording();
00212     virtual PBoolean IsPlaying() const;
00213     virtual PBoolean IsRecording() const;
00214 
00215     virtual PBoolean OnUserInput(const PString & str);
00216 
00217     PString GetXMLError() const;
00218 
00219     virtual void OnEndDialog();
00220     virtual void OnEndSession()         { }
00221     virtual void OnTransfer(const PString & /*destination*/, bool /*bridged*/) { }
00222 
00223     const PStringToString & GetVariables() { return m_variables; }
00224     virtual PCaselessString GetVar(const PString & str) const;
00225     virtual void SetVar(const PString & ostr, const PString & val);
00226     virtual PString EvaluateExpr(const PString & oexpr);
00227 
00228     virtual PBoolean RetreiveResource(const PURL & url, PString & contentType, PFilePath & fn, PBoolean useCache = true);
00229 
00230     PDECLARE_NOTIFIER(PThread, PVXMLSession, VXMLExecute);
00231 
00232     void SetCallingToken( PString& token ) { callingCallToken = token; }
00233 
00234     PXMLElement * FindHandler(const PString & event);
00235 
00236     // overrides from VXMLChannelInterface
00237     virtual void OnEndRecording(const PString & channelName);
00238     virtual void RecordEnd();
00239     virtual void Trigger();
00240 
00241 
00242     virtual PBoolean TraverseAudio();
00243     virtual PBoolean TraverseBreak();
00244     virtual PBoolean TraverseValue();
00245     virtual PBoolean TraverseSayAs();
00246     virtual PBoolean TraverseGoto();
00247     virtual PBoolean TraverseGrammar();
00248     virtual PBoolean TraverseRecord();
00249     virtual PBoolean TraverseIf();
00250     virtual PBoolean TraverseExit();
00251     virtual PBoolean TraverseVar();
00252     virtual PBoolean TraverseSubmit();
00253     virtual PBoolean TraverseMenu();
00254     virtual PBoolean TraverseChoice();
00255     virtual PBoolean TraverseProperty();
00256     virtual PBoolean TraverseDisconnect();
00257     virtual PBoolean TraverseForm();
00258     virtual PBoolean TraversePrompt();
00259     virtual PBoolean TraverseField();
00260     virtual PBoolean TraversedField();
00261     virtual PBoolean TraversedTransfer();
00262 
00263   protected:
00264     void Initialise();
00265 
00266     virtual void ProcessUserInput();
00267     virtual void ProcessGrammar();
00268     virtual void ProcessNode();
00269     virtual bool NextNode();
00270 
00271     void SayAs(const PString & className, const PString & text);
00272     void SayAs(const PString & className, const PString & text, const PString & voice);
00273 
00274     static PTimeInterval StringToTime(const PString & str);
00275 
00276     PURL NormaliseResourceName(const PString & src);
00277 
00278     PXMLElement * FindForm(const PString & id);
00279 
00280     PSyncPoint waitForEvent;
00281 
00282     PMutex sessionMutex;
00283 
00284     PXML xmlFile;
00285 
00286     PVXMLGrammar * activeGrammar;
00287     PBoolean listening;                 // true if waiting for recognition events
00288     int timeout;                    // timeout in msecs for the current recognition
00289 
00290     PStringToString m_variables;
00291 
00292     PMutex userInputMutex;
00293     std::queue<char> userInputQueue;
00294 
00295     PBoolean recording;
00296     PFilePath recordFn;
00297     PBoolean recordDTMFTerm;
00298     PTimeInterval recordMaxTime;
00299     PTimeInterval recordFinalSilence;
00300     PSyncPoint    recordSync;
00301 
00302     PBoolean loaded;
00303     PURL rootURL;
00304     PBoolean emptyAction;
00305 
00306     PThread * vxmlThread;
00307     bool m_abortVXML;
00308 
00309     PString mediaFormat;
00310     PVXMLChannel * & vxmlChannel;
00311 
00312     PTextToSpeech * textToSpeech;
00313     PBoolean autoDeleteTextToSpeech;
00314 
00315     PXMLElement * currentForm;
00316     PXMLElement * currentField;
00317     PXMLObject  * currentNode;
00318     bool          m_speakNodeData;
00319 
00320   private:
00321     PString       callingCallToken;
00322     PSyncPoint    answerSync;
00323     PString       grammarResult;
00324     PString       eventName;
00325     PINDEX        defaultDTMF;
00326 };
00327 
00328 
00330 
00331 class PVXMLRecordable : public PObject
00332 {
00333   PCLASSINFO(PVXMLRecordable, PObject);
00334   public:
00335     PVXMLRecordable()
00336     { consecutiveSilence = 0; finalSilence = 3000; maxDuration = 30000; }
00337 
00338     virtual PBoolean Open(const PString & arg) = 0;
00339 
00340     virtual void Record(PVXMLChannel & incomingChannel) = 0;
00341 
00342     virtual void OnStart() { }
00343 
00344     virtual PBoolean OnFrame(PBoolean /*isSilence*/) { return false; }
00345 
00346     virtual void OnStop() { }
00347 
00348     void SetFinalSilence(unsigned v)
00349     { finalSilence = v; }
00350 
00351     unsigned GetFinalSilence()
00352     { return finalSilence; }
00353 
00354     void SetMaxDuration(unsigned v)
00355     { maxDuration = v; }
00356 
00357     unsigned GetMaxDuration()
00358     { return maxDuration; }
00359 
00360   protected:
00361     PTime silenceStart;
00362     PTime recordStart;
00363     unsigned finalSilence;
00364     unsigned maxDuration;
00365     unsigned consecutiveSilence;
00366 };
00367 
00369 
00370 class PVXMLPlayable : public PObject
00371 {
00372   PCLASSINFO(PVXMLPlayable, PObject);
00373   public:
00374     PVXMLPlayable()
00375     { repeat = 1; delay = 0; sampleFrequency = 8000; autoDelete = false; delayDone = false; }
00376 
00377     virtual PBoolean Open(PVXMLChannel & /*chan*/, PINDEX delay, PINDEX repeat, PBoolean autoDelete);
00378 
00379     virtual PBoolean Open(PVXMLChannel & chan, const PString & arg, PINDEX delay, PINDEX repeat, PBoolean v);
00380 
00381     virtual void Play(PVXMLChannel & outgoingChannel) = 0;
00382 
00383     virtual void OnRepeat(PVXMLChannel & /*outgoingChannel*/)
00384     { }
00385 
00386     virtual void OnStart() { }
00387 
00388     virtual void OnStop() { }
00389 
00390     virtual void SetRepeat(PINDEX v) 
00391     { repeat = v; }
00392 
00393     virtual PINDEX GetRepeat() const
00394     { return repeat; }
00395 
00396     virtual PINDEX GetDelay() const
00397     { return delay; }
00398 
00399     void SetFormat(const PString & fmt)
00400     { format = fmt; }
00401 
00402     void SetSampleFrequency(unsigned rate)
00403     { sampleFrequency = rate; }
00404 
00405     virtual PBoolean ReadFrame(PVXMLChannel & channel, void * buf, PINDEX len);
00406 
00407     virtual PBoolean Rewind(PChannel *) 
00408     { return false; }
00409 
00410     friend class PVXMLChannel;
00411 
00412   protected:
00413     PString arg;
00414     PINDEX repeat;
00415     PINDEX delay;
00416     PString format;
00417     unsigned sampleFrequency;
00418     PBoolean autoDelete;
00419     PBoolean delayDone; // very tacky flag used to indicate when the post-play delay has been done
00420 };
00421 
00423 
00424 class PVXMLPlayableStop : public PVXMLPlayable
00425 {
00426   PCLASSINFO(PVXMLPlayableStop, PVXMLPlayable);
00427   public:
00428     virtual void Play(PVXMLChannel & outgoingChannel);
00429     virtual PBoolean ReadFrame(PVXMLChannel & channel, void *, PINDEX);
00430 };
00431 
00433 
00434 class PVXMLPlayableURL : public PVXMLPlayable
00435 {
00436   PCLASSINFO(PVXMLPlayableURL, PVXMLPlayable);
00437   public:
00438     PBoolean Open(PVXMLChannel & chan, const PString & url, PINDEX delay, PINDEX repeat, PBoolean v);
00439     void Play(PVXMLChannel & outgoingChannel);
00440   protected:
00441     PURL url;
00442 };
00443 
00445 
00446 class PVXMLPlayableData : public PVXMLPlayable
00447 {
00448   PCLASSINFO(PVXMLPlayableData, PVXMLPlayable);
00449   public:
00450     PBoolean Open(PVXMLChannel & chan, const PString & fn, PINDEX delay, PINDEX repeat, PBoolean v);
00451     void SetData(const PBYTEArray & data);
00452     void Play(PVXMLChannel & outgoingChannel);
00453     PBoolean Rewind(PChannel * chan);
00454   protected:
00455     PBYTEArray data;
00456 };
00457 
00459 
00460 #include <ptclib/dtmf.h>
00461 
00462 class PVXMLPlayableTone : public PVXMLPlayableData
00463 {
00464   PCLASSINFO(PVXMLPlayableTone, PVXMLPlayableData);
00465   public:
00466     PBoolean Open(PVXMLChannel & chan, const PString & toneSpec, PINDEX delay, PINDEX repeat, PBoolean v);
00467   protected:
00468     PTones tones;
00469 };
00470 
00472 
00473 class PVXMLPlayableCommand : public PVXMLPlayable
00474 {
00475   PCLASSINFO(PVXMLPlayableCommand, PVXMLPlayable);
00476   public:
00477     PVXMLPlayableCommand();
00478     void Play(PVXMLChannel & outgoingChannel);
00479     void OnStop();
00480 
00481   protected:
00482     PPipeChannel * pipeCmd;
00483 };
00484 
00486 
00487 class PVXMLPlayableFilename : public PVXMLPlayable
00488 {
00489   PCLASSINFO(PVXMLPlayableFilename, PVXMLPlayable);
00490   public:
00491     PBoolean Open(PVXMLChannel & chan, const PString & fn, PINDEX delay, PINDEX repeat, PBoolean autoDelete);
00492     void Play(PVXMLChannel & outgoingChannel);
00493     void OnStop();
00494     virtual PBoolean Rewind(PChannel * chan);
00495   protected:
00496     PFilePath fn;
00497 };
00498 
00500 
00501 class PVXMLPlayableFilenameList : public PVXMLPlayable
00502 {
00503   PCLASSINFO(PVXMLPlayableFilenameList, PVXMLPlayable);
00504   public:
00505     PBoolean Open(PVXMLChannel & chan, const PStringArray & filenames, PINDEX delay, PINDEX repeat, PBoolean autoDelete);
00506     void Play(PVXMLChannel & outgoingChannel)
00507     { OnRepeat(outgoingChannel); }
00508     void OnRepeat(PVXMLChannel & outgoingChannel);
00509     void OnStop();
00510   protected:
00511     PINDEX currentIndex;
00512     PStringArray filenames;
00513 };
00514 
00516 
00517 class PVXMLRecordableFilename : public PVXMLRecordable
00518 {
00519   PCLASSINFO(PVXMLRecordableFilename, PVXMLRecordable);
00520   public:
00521     PBoolean Open(const PString & arg);
00522     void Record(PVXMLChannel & incomingChannel);
00523     PBoolean OnFrame(PBoolean isSilence);
00524 
00525   protected:
00526     PFilePath fn;
00527 };
00528 
00530 
00531 PQUEUE(PVXMLQueue, PVXMLPlayable);
00532 
00534 
00535 class PVXMLChannel : public PDelayChannel
00536 {
00537   PCLASSINFO(PVXMLChannel, PDelayChannel);
00538   public:
00539     PVXMLChannel(unsigned frameDelay, PINDEX frameSize);
00540     ~PVXMLChannel();
00541 
00542     virtual PBoolean Open(PVXMLChannelInterface * vxml);
00543 
00544     // overrides from PIndirectChannel
00545     virtual PBoolean IsOpen() const;
00546     virtual PBoolean Close();
00547     virtual PBoolean Read(void * buffer, PINDEX amount);
00548     virtual PBoolean Write(const void * buf, PINDEX len);
00549 
00550     // new functions
00551     virtual PWAVFile * CreateWAVFile(const PFilePath & fn, PBoolean recording = false);
00552 
00553     const PString & GetMediaFormat() const { return mediaFormat; }
00554     PBoolean IsMediaPCM() const { return mediaFormat == "PCM-16"; }
00555     virtual PString AdjustWavFilename(const PString & fn);
00556 
00557     // Incoming channel functions
00558     virtual PBoolean WriteFrame(const void * buf, PINDEX len) = 0;
00559     virtual PBoolean IsSilenceFrame(const void * buf, PINDEX len) const = 0;
00560 
00561     virtual PBoolean QueueRecordable(PVXMLRecordable * newItem);
00562 
00563     PBoolean StartRecording(const PFilePath & fn, unsigned finalSilence = 3000, unsigned maxDuration = 30000);
00564     PBoolean EndRecording();
00565     PBoolean IsRecording() const { return recording; }
00566 
00567     // Outgoing channel functions
00568     virtual PBoolean ReadFrame(void * buffer, PINDEX amount) = 0;
00569     virtual PINDEX CreateSilenceFrame(void * buffer, PINDEX amount) = 0;
00570     virtual void GetBeepData(PBYTEArray &, unsigned) { }
00571 
00572     virtual PBoolean QueueResource(const PURL & url, PINDEX repeat= 1, PINDEX delay = 0);
00573 
00574     virtual PBoolean QueuePlayable(const PString & type, const PString & str, PINDEX repeat = 1, PINDEX delay = 0, PBoolean autoDelete = false);
00575     virtual PBoolean QueuePlayable(PVXMLPlayable * newItem);
00576     virtual PBoolean QueueData(const PBYTEArray & data, PINDEX repeat = 1, PINDEX delay = 0);
00577 
00578     virtual PBoolean QueueFile(const PString & fn, PINDEX repeat = 1, PINDEX delay = 0, PBoolean autoDelete = false)
00579     { return QueuePlayable("File", fn, repeat, delay, autoDelete); }
00580 
00581     virtual PBoolean QueueCommand(const PString & cmd, PINDEX repeat = 1, PINDEX delay = 0)
00582     { return QueuePlayable("Command", cmd, repeat, delay, true); }
00583 
00584     virtual void FlushQueue();
00585     virtual PBoolean IsPlaying() const { return currentPlayItem != NULL || playQueue.GetSize() > 0; }
00586 
00587     void SetPause(PBoolean pause) { paused = pause; }
00588 
00589     void SetName(const PString & name) { channelName = name; }
00590 
00591     unsigned GetSampleFrequency() const { return sampleFrequency; }
00592 
00593     void SetSilence(unsigned msecs);
00594 
00595   protected:
00596     PVXMLChannelInterface * vxmlInterface;
00597 
00598     unsigned sampleFrequency;
00599     PString mediaFormat;
00600     PString wavFilePrefix;
00601 
00602     PMutex channelWriteMutex;
00603     PMutex channelReadMutex;
00604     PBoolean closed;
00605 
00606     // Incoming audio variables
00607     PBoolean recording;
00608     PVXMLRecordable * recordable;
00609     unsigned finalSilence;
00610     unsigned silenceRun;
00611 
00612     // Outgoing audio variables
00613     PMutex queueMutex;
00614     PVXMLQueue playQueue;
00615     PVXMLPlayable * currentPlayItem;
00616 
00617     PBoolean paused;
00618     PTimer   m_silenceTimer;
00619     int totalData;
00620 
00621     // "channelname" (which is the name of the <record> tag) so
00622     // results can be saved in vxml session variable
00623     PString channelName;
00624 };
00625 
00626 
00628 
00629 class PVXMLNodeHandler : public PObject
00630 {
00631     PCLASSINFO(PVXMLNodeHandler, PObject);
00632   public:
00633     virtual bool Start(PVXMLSession & /*session*/, const PXMLElement & /*node*/) const { return false; }
00634     virtual bool Finish(PVXMLSession & /*session*/, const PXMLElement & /*node*/) const { return false; }
00635 };
00636 
00637 
00638 typedef PFactory<PVXMLNodeHandler, PCaselessString> PVXMLNodeFactory;
00639 
00640 
00641 #endif // P_VXML
00642 
00643 #endif // PTLIB_VXML_H
00644 
00645 
00646 // End of file ////////////////////////////////////////////////////////////////
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines