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: 22848 $
00025  * $Author: rjongbloed $
00026  * $Date: 2009-06-12 01:26:03 -0500 (Fri, 12 Jun 2009) $
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/pipechan.h>
00042 #include <ptclib/delaychan.h>
00043 #include <ptclib/pwavfile.h>
00044 #include <ptclib/ptts.h>
00045 #include <ptclib/url.h>
00046 
00047 #include <queue>
00048 
00049 
00050 class PVXMLSession;
00051 class PVXMLDialog;
00052 class PVXMLSession;
00053 
00054 // these are the same strings as the Opal equivalents, but as this is PWLib, we can't use Opal contants
00055 #define VXML_PCM16         "PCM-16"
00056 #define VXML_G7231         "G.723.1"
00057 #define VXML_G729          "G.729"
00058 
00059 #define PVXML_HAS_FACTORY   1
00060 
00061 class PVXMLGrammar : public PObject
00062 {
00063   PCLASSINFO(PVXMLGrammar, PObject);
00064   public:
00065     PVXMLGrammar(PXMLElement * field);
00066     virtual PBoolean OnUserInput(const char /*ch*/) { return PTrue; }
00067     virtual void Stop() { }
00068 
00069     PString GetValue() const { return value; }
00070     PXMLElement * GetField() { return field; }
00071 
00072     enum GrammarState { 
00073       FILLED,       
00074       NOINPUT,      
00075       NOMATCH,      
00076       HELP };       
00077 
00078     GrammarState GetState() const { return state; }
00079 
00080   protected:
00081     PXMLElement * field;
00082     PString value;
00083     GrammarState state;
00084 };
00085 
00086 
00088 
00089 class PVXMLMenuGrammar : public PVXMLGrammar
00090 {
00091   PCLASSINFO(PVXMLMenuGrammar, PVXMLGrammar);
00092   public:
00093     PVXMLMenuGrammar(PXMLElement * field);
00094 };
00095 
00096 
00098 
00099 class PVXMLDigitsGrammar : public PVXMLGrammar
00100 {
00101   PCLASSINFO(PVXMLDigitsGrammar, PVXMLGrammar);
00102   public:
00103     PVXMLDigitsGrammar(PXMLElement * field, PINDEX minDigits, PINDEX maxDigits, PString terminators);
00104     PBoolean OnUserInput(const char ch);
00105     virtual void Stop();
00106 
00107   protected:
00108     PINDEX minDigits;
00109     PINDEX maxDigits;
00110     PString terminators;
00111 };
00112 
00113 
00115 
00116 class PVXMLCache : public PMutex
00117 {
00118   public:
00119     PVXMLCache(const PDirectory & directory);
00120 
00121     PFilePath CreateFilename(const PString & prefix, const PString & key, const PString & fileType);
00122 
00123     void Put(const PString & prefix,
00124              const PString & key, 
00125              const PString & fileType, 
00126              const PString & contentType,       
00127            const PFilePath & fn, 
00128                  PFilePath & dataFn);
00129 
00130     PBoolean Get(const PString & prefix,
00131              const PString & key, 
00132              const PString & fileType, 
00133                    PString & contentType,       
00134                  PFilePath & fn);
00135 
00136     PFilePath GetCacheDir() const
00137     { return directory; }
00138 
00139     PFilePath GetRandomFilename(const PString & prefix, const PString & fileType);
00140 
00141     static PVXMLCache & GetResourceCache();
00142 
00143   protected:
00144     PDirectory directory;
00145 };
00146 
00148 
00149 class PVXMLChannel;
00150 
00151 class PVXMLChannelInterface {
00152   public:
00153     virtual ~PVXMLChannelInterface() { }
00154     virtual PWAVFile * CreateWAVFile(const PFilePath & fn, PFile::OpenMode mode, int opts, unsigned fmt) = 0;
00155     virtual void RecordEnd() = 0;
00156     virtual void OnEndRecording(const PString & channelName) = 0;
00157     virtual void Trigger() = 0;
00158 };
00159 
00161 
00162 class PVXMLSession : public PIndirectChannel, public PVXMLChannelInterface
00163 {
00164   PCLASSINFO(PVXMLSession, PIndirectChannel);
00165   public:
00166     PVXMLSession(PTextToSpeech * tts = NULL, PBoolean autoDelete = PFalse);
00167     virtual ~PVXMLSession();
00168 
00169     // new functions
00170     PTextToSpeech * SetTextToSpeech(PTextToSpeech * tts, PBoolean autoDelete = false);
00171     PTextToSpeech * SetTextToSpeech(const PString & ttsName);
00172     PTextToSpeech * GetTextToSpeech() { return textToSpeech; }
00173 
00174     virtual PBoolean Load(const PString & source);
00175     virtual PBoolean LoadFile(const PFilePath & file);
00176     virtual PBoolean LoadURL(const PURL & url);
00177     virtual PBoolean LoadVXML(const PString & xml);
00178     virtual PBoolean IsLoaded() const { return loaded; }
00179 
00180     virtual PBoolean Open(const PString & mediaFormat);
00181     virtual PBoolean Close();
00182 
00183     PBoolean Execute();
00184 
00185     PVXMLChannel * GetAndLockVXMLChannel() 
00186     { 
00187       sessionMutex.Wait(); 
00188       if (vxmlChannel != NULL) 
00189         return vxmlChannel; 
00190       sessionMutex.Signal();
00191       return NULL;
00192     }
00193     void UnLockVXMLChannel() { sessionMutex.Signal(); }
00194     PMutex & GetSessionMutex() { return sessionMutex; }
00195 
00196     PBoolean LoadGrammar(PVXMLGrammar * grammar);
00197 
00198     virtual PBoolean PlayText(const PString & text, PTextToSpeech::TextType type = PTextToSpeech::Default, PINDEX repeat = 1, PINDEX delay = 0);
00199     PBoolean ConvertTextToFilenameList(const PString & text, PTextToSpeech::TextType type, PStringArray & list, PBoolean useCacheing);
00200 
00201     virtual PBoolean PlayFile(const PString & fn, PINDEX repeat = 1, PINDEX delay = 0, PBoolean autoDelete = PFalse);
00202     virtual PBoolean PlayData(const PBYTEArray & data, PINDEX repeat = 1, PINDEX delay = 0);
00203     virtual PBoolean PlayCommand(const PString & data, PINDEX repeat = 1, PINDEX delay = 0);
00204     virtual PBoolean PlayResource(const PURL & url, PINDEX repeat = 1, PINDEX delay = 0);
00205     virtual PBoolean PlayTone(const PString & toneSpec, PINDEX repeat = 1, PINDEX delay = 0);
00206 
00207     //virtual PBoolean PlayMedia(const PURL & url, PINDEX repeat = 1, PINDEX delay = 0);
00208     virtual PBoolean PlaySilence(PINDEX msecs = 0);
00209     virtual PBoolean PlaySilence(const PTimeInterval & timeout);
00210 
00211     virtual PBoolean PlayStop();
00212 
00213     virtual void SetPause(PBoolean pause);
00214     virtual void GetBeepData(PBYTEArray & data, unsigned ms);
00215 
00216     virtual PBoolean StartRecording(const PFilePath & fn, PBoolean recordDTMFTerm, const PTimeInterval & recordMaxTime, const PTimeInterval & recordFinalSilence);
00217     virtual PBoolean EndRecording();
00218     virtual PBoolean IsPlaying() const;
00219     virtual PBoolean IsRecording() const;
00220 
00221     virtual PBoolean OnUserInput(const PString & str);
00222 
00223     PString GetXMLError() const;
00224 
00225     virtual void OnEndSession()         { }
00226 
00227     virtual PString GetVar(const PString & str) const;
00228     virtual void SetVar(const PString & ostr, const PString & val);
00229     virtual PString EvaluateExpr(const PString & oexpr);
00230 
00231     virtual PBoolean RetreiveResource(const PURL & url, PString & contentType, PFilePath & fn, PBoolean useCache = PTrue);
00232 
00233     PDECLARE_NOTIFIER(PThread, PVXMLSession, VXMLExecute);
00234 
00235     void SetCallingToken( PString& token ) { callingCallToken = token; }
00236 
00237     PXMLElement * FindHandler(const PString & event);
00238 
00239     // overrides from VXMLChannelInterface
00240     PWAVFile * CreateWAVFile(const PFilePath & fn, PFile::OpenMode mode, int opts, unsigned fmt);
00241     void OnEndRecording(const PString & channelName);
00242     void RecordEnd();
00243     void Trigger();
00244 
00245     PStringToString & GetSessionVars() { return sessionVars; }
00246 
00247   protected:
00248     void Initialise();
00249 
00250     void AllowClearCall();
00251     void ProcessUserInput();
00252     void ProcessNode();
00253     void ProcessGrammar();
00254 
00255     PBoolean TraverseAudio();
00256     PBoolean TraverseGoto();
00257     PBoolean TraverseGrammar();
00258     PBoolean TraverseRecord();
00259 
00260     PBoolean TraverseIf();
00261     PBoolean TraverseExit();
00262     PBoolean TraverseVar();
00263     PBoolean TraverseSubmit();
00264     PBoolean TraverseMenu();
00265     PBoolean TraverseChoice(const PString & grammarResult);
00266     PBoolean TraverseProperty();
00267 
00268     void SayAs(const PString & className, const PString & text);
00269     void SayAs(const PString & className, const PString & text, const PString & voice);
00270 
00271     static PTimeInterval StringToTime(const PString & str);
00272 
00273     PURL NormaliseResourceName(const PString & src);
00274 
00275     PXMLElement * FindForm(const PString & id);
00276 
00277     PSyncPoint waitForEvent;
00278 
00279     PMutex sessionMutex;
00280 
00281     PXML xmlFile;
00282 
00283     PVXMLGrammar * activeGrammar;
00284     PBoolean listening;                 // PTrue if waiting for recognition events
00285     int timeout;                    // timeout in msecs for the current recognition
00286 
00287     PStringToString sessionVars;
00288     PStringToString documentVars;
00289 
00290     PMutex userInputMutex;
00291     std::queue<char> userInputQueue;
00292 
00293     PBoolean recording;
00294     PFilePath recordFn;
00295     PBoolean recordDTMFTerm;
00296     PTimeInterval recordMaxTime;
00297     PTimeInterval recordFinalSilence;
00298     PSyncPoint    recordSync;
00299 
00300     PBoolean loaded;
00301     PURL rootURL;
00302     PBoolean emptyAction;
00303 
00304     PThread * vxmlThread;
00305     PBoolean threadRunning;
00306     PBoolean forceEnd;
00307 
00308     PString mediaFormat;
00309     PVXMLChannel * & vxmlChannel;
00310 
00311     PTextToSpeech * textToSpeech;
00312     PBoolean autoDeleteTextToSpeech;
00313 
00314     PXMLElement * currentForm;
00315     PXMLElement * currentField;
00316     PXMLObject  * currentNode;
00317 
00318   private:
00319     void      ExecuteDialog();
00320 
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 PFalse; }
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 = PFalse; delayDone = PFalse; }
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 PFalse; }
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 = PFalse);
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 = PFalse);
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 = PFalse)
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, PTrue); }
00583 
00584     virtual void FlushQueue();
00585     virtual PBoolean IsPlaying() const   { return (playQueue.GetSize() > 0) || playing ; }
00586 
00587     void SetPause(PBoolean pause) { paused = pause; }
00588 
00589     void SetName(const PString & name) { channelName = name; }
00590 
00591     unsigned GetSampleFrequency() const
00592     { return sampleFrequency; }
00593 
00594           void SetSilentCount(int v) { silentCount = v; }
00595 
00596   protected:
00597     PVXMLChannelInterface * vxmlInterface;
00598 
00599     unsigned sampleFrequency;
00600     PString mediaFormat;
00601     PString wavFilePrefix;
00602 
00603     PMutex channelWriteMutex;
00604     PMutex channelReadMutex;
00605     PBoolean closed;
00606 
00607     // Incoming audio variables
00608     PBoolean recording;
00609     PVXMLRecordable * recordable;
00610     unsigned finalSilence;
00611     unsigned silenceRun;
00612 
00613     // Outgoing audio variables
00614     PBoolean playing;
00615     PMutex queueMutex;
00616     PVXMLQueue playQueue;
00617     PVXMLPlayable * currentPlayItem;
00618 
00619     PBoolean paused;
00620     int silentCount;
00621     int totalData;
00622     PTimer delayTimer;
00623 
00624     // "channelname" (which is the name of the <record> tag) so
00625     // results can be saved in vxml session variable
00626     PString channelName;
00627 };
00628 
00629 
00631 
00632 
00633 #endif // P_VXML
00634 
00635 #endif // PTLIB_VXML_H
00636 
00637 
00638 // End of file ////////////////////////////////////////////////////////////////

Generated on Thu May 27 01:36:48 2010 for PTLib by  doxygen 1.4.7