00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099 #include <qapplication.h>
00100 #include <qfile.h>
00101 #include <qdialog.h>
00102 #include <qcursor.h>
00103 #include <qdir.h>
00104 #include <qdom.h>
00105 #include <qimage.h>
00106 #include <pthread.h>
00107 #include <unistd.h>
00108 #include <math.h>
00109 #include <iostream>
00110 #include <cstdlib>
00111
00112 #include <mythtv/mythcontext.h>
00113
00114 using namespace std;
00115
00116 #include "config.h"
00117 #include "vxml.h"
00118 #include "tts.h"
00119
00120
00121 tts *speechEngine;
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 vxmlParser::vxmlParser()
00140 {
00141 Rtp = 0;
00142 callerName = "";
00143 killVxmlThread = false;
00144 killVxmlSession = false;
00145 killVxmlPage = false;
00146 waker = new QWaitCondition();
00147 pthread_create(&vxmlthread, NULL, vxmlThread, this);
00148 }
00149
00150 vxmlParser::~vxmlParser()
00151 {
00152 killVxmlThread = true;
00153 killVxmlSession = true;
00154 killVxmlPage = true;
00155 waker->wakeAll();
00156 pthread_join(vxmlthread, NULL);
00157 delete waker;
00158 }
00159
00160 void *vxmlParser::vxmlThread(void *p)
00161 {
00162 vxmlParser *me = (vxmlParser *)p;
00163 me->vxmlThreadWorker();
00164 return NULL;
00165 }
00166
00167
00168 void vxmlParser::vxmlThreadWorker()
00169 {
00170 speechEngine = new tts();
00171
00172 while (!killVxmlThread)
00173 {
00174 waker->wait();
00175 if (Rtp != 0)
00176 {
00177 cout << "Starting VXML Session; caller=" << callerName << endl;
00178 runVxmlSession();
00179 Rtp = 0;
00180 }
00181 }
00182
00183 Rtp = 0;
00184 delete speechEngine;
00185 }
00186
00187 void vxmlParser::beginVxmlSession(rtp *r, QString cName)
00188 {
00189 if ((!killVxmlThread) && (Rtp == 0))
00190 {
00191 killVxmlPage = false;
00192 killVxmlSession = false;
00193 callerName = cName;
00194 if (callerName.length() == 0)
00195 callerName = "Unknown";
00196 Rtp = r;
00197 waker->wakeAll();
00198 }
00199 else
00200 cerr << "VXML: Cannot process session; thread dead or busy\n";
00201 }
00202
00203 void vxmlParser::endVxmlSession()
00204 {
00205 killVxmlPage = true;
00206 killVxmlSession = true;
00207 while (Rtp != 0)
00208 usleep(100000);
00209 }
00210
00211 void vxmlParser::runVxmlSession()
00212 {
00213 QString ttsVoice = "voice_" + gContext->GetSetting("TTSVoice");
00214 speechEngine->setVoice(ttsVoice);
00215
00216 vxmlUrl = gContext->GetSetting("DefaultVxmlUrl");
00217 httpMethod = "get";
00218 postNamelist = "";
00219 lastUrl = vxmlUrl;
00220
00221 if (vxmlUrl == "")
00222 vxmlUrl = "Default";
00223
00224 while ((!killVxmlSession) && (vxmlUrl != ""))
00225 {
00226 loadVxmlPage(vxmlUrl, httpMethod, postNamelist, vxmlDoc);
00227 vxmlUrl = "";
00228 httpMethod = "";
00229 postNamelist = "";
00230
00231 Parse(vxmlDoc);
00232 killVxmlPage = false;
00233 }
00234 }
00235
00236
00237 bool vxmlParser::loadVxmlPage(QString strUrl, QString Method, QString Namelist, QDomDocument &script)
00238 {
00239 QString Content = "";
00240 QString httpRequest;
00241
00242 if (strUrl == "Default")
00243 {
00244 QString vmPrompt = gContext->GetSetting("DefaultVoicemailPrompt");
00245 Content = "<vxml version=\"1.0\">"
00246 "<form><record name=\"message\" beep=\"true\" maxtime=\"20s\" dtmfterm=\"true\">";
00247 if (vmPrompt.endsWith(".wav"))
00248 Content += " <prompt><audio src=\"" + vmPrompt + "\"/></prompt>";
00249 else
00250 Content += " <prompt>" + vmPrompt + "</prompt>";
00251 Content += " <filled><prompt>Thank you</prompt></filled>"
00252 " </record></form>"
00253 " <form><field name=\"choice\" type=\"digits?length=1\" modal=\"true\">"
00254 " <prompt>Press 1 to hear your message replayed</prompt>"
00255 " <prompt>Or press hash or hang up to leave the message</prompt>"
00256 " </field>"
00257 " <noinput>Goodbye</noinput>"
00258 " <filled>"
00259 " <if cond=\"choice == 1\"><prompt>You said <audio expr=\"message\"/></prompt><reprompt/>"
00260 " <else>Message delivered. Goodbye<disconnect></if>"
00261 " </filled></form></vxml>";
00262 script.setContent(Content);
00263 return true;
00264 }
00265
00266 QUrl Url(lastUrl, strUrl, TRUE);
00267 lastUrl = Url;
00268 lastUrl.setQuery("");
00269 QString Query = Url.query();
00270 if (Query != "")
00271 {
00272 Query.prepend('?');
00273
00274
00275
00276
00277
00278
00279
00280
00281 Query.replace('+', '&');
00282 }
00283 if (Method == "get")
00284 httpRequest = QString("GET %1%2 HTTP/1.0\r\n"
00285 "User-Agent: MythPhone/1.0\r\n"
00286 "\r\n").arg(Url.path()).arg(Query);
00287 else
00288 {
00289 Namelist.replace('+', '&');
00290 httpRequest = QString("POST %1%2 HTTP/1.0\r\n"
00291 "User-Agent: MythPhone/1.0\r\n"
00292 "Content-Type: application/x-www-form-urlencoded\r\n"
00293 "Content-Length: %3\r\n"
00294 "\r\n%4").arg(Url.path()).arg(Query).arg(Namelist.length()).arg(Namelist);
00295 }
00296 QSocketDevice *httpSock = new QSocketDevice(QSocketDevice::Stream);
00297 QHostAddress hostIp;
00298 int port = Url.port();
00299 if (port == -1)
00300 port = 80;
00301 if (hostIp.setAddress(Url.host()))
00302 hostIp.setAddress("127.0.0.1");
00303
00304
00305 if (httpSock->connect(hostIp, port))
00306 {
00307 int bytesAvail;
00308 if (httpSock->writeBlock(httpRequest, httpRequest.length()) != -1)
00309 {
00310 QString resp = "";
00311 while ((bytesAvail = httpSock->waitForMore(3000)) != -1)
00312 {
00313 char *httpResponse = new char[bytesAvail+1];
00314 int len = httpSock->readBlock(httpResponse, bytesAvail);
00315 if (len >= 0)
00316 {
00317 httpResponse[len] = 0;
00318 resp += QString(httpResponse);
00319
00320 QString firstLine = resp.section('\n', 0);
00321 if ((firstLine.contains("200 OK")) && !resp.contains("</vxml>"))
00322 {
00323 delete httpResponse;
00324 continue;
00325 }
00326
00327 Content = resp.section("\r\n\r\n", 1, 1);
00328 script.setContent(Content);
00329
00330 }
00331 delete httpResponse;
00332 break;
00333 }
00334 }
00335 else
00336 cerr << "Error sending VXML GET to socket\n";
00337 }
00338 else
00339 cout << "Could not connect to VXML host " << Url.host() << ":" << Url.port() << endl;
00340 httpSock->close();
00341 delete httpSock;
00342
00343 if (Content != "")
00344 return true;
00345
00346 Content = "<vxml version=\"1.0\">"
00347 " <prompt>There is a technical problem, please report this to the site owner</prompt>"
00348 " </vxml>";
00349 script.setContent(Content);
00350 return false;
00351
00352 }
00353
00354 void vxmlParser::Parse(QDomDocument &vxmlPage)
00355 {
00356 QDomElement rootElm = vxmlPage.documentElement();
00357
00358
00359 vxmlVarList = new vxmlVarContainer;
00360
00361 if (rootElm.tagName() != "vxml")
00362 {
00363 cerr << "Invalid VXML script\n";
00364 return;
00365 }
00366
00367 QDomNode n = rootElm.firstChild();
00368 while ((!n.isNull()) && (!killVxmlPage))
00369 {
00370 QDomElement e = n.toElement();
00371 if (!e.isNull())
00372 {
00373 if (e.tagName() == "form")
00374 {
00375 parseForm(e);
00376 }
00377 else if (e.tagName() == "prompt")
00378 {
00379 parsePrompt(e, false);
00380 }
00381 else if (e.tagName() == "submit")
00382 {
00383 vxmlUrl = e.attribute("next");
00384 postNamelist = e.attribute("namelist");
00385 httpMethod = e.attribute("method");
00386 killVxmlPage = true;
00387 }
00388 else
00389 cerr << "Unsupported VXML tag \"" << e.tagName() << "\"\n";
00390 }
00391 n = n.nextSibling();
00392 }
00393
00394
00395
00396 short *wav = 0;
00397 int samples;
00398 vxmlVariable *variable;
00399 for (variable=vxmlVarList->first(); variable; variable=vxmlVarList->next())
00400 {
00401 if (variable->isType("SHORTPTR"))
00402 {
00403 samples = variable->getSPLength();
00404 wav = variable->getSPValue();
00405 SaveWav(wav, samples);
00406 }
00407 }
00408
00409
00410
00411 delete vxmlVarList;
00412 }
00413
00414
00415
00416 void vxmlParser::parsePrompt(QDomElement &prompt, bool dtmfInterrupts)
00417 {
00418 QDomNode n = prompt.firstChild();
00419 while ((!n.isNull()) && (!killVxmlPage))
00420 {
00421 QDomElement e = n.toElement();
00422 QDomText t = n.toText();
00423 if (!e.isNull())
00424 {
00425 if (e.tagName() == "break")
00426 {
00427 QString strDuration = e.attribute("time");
00428 if (strDuration)
00429 {
00430 PlaySilence(parseDurationType(strDuration), dtmfInterrupts);
00431 }
00432 }
00433 else if (e.tagName() == "audio")
00434 {
00435 QString srcFile = e.attribute("src");
00436 if (srcFile)
00437 PlayWav(srcFile);
00438 QString expression = e.attribute("expr");
00439 if (expression)
00440 {
00441 int samples;
00442 short *wav = vxmlVarList->findShortPtrVariable(expression, samples);
00443 PlayWav(wav, samples);
00444 }
00445 }
00446 else
00447 cerr << "Unsupported prompt sub-element tag \"" << e.tagName() << "\"\n";
00448 }
00449 else if (!t.isNull())
00450 {
00451 PlayTTSPrompt(t.data(), dtmfInterrupts);
00452 }
00453 else
00454 cerr << "Unsupported child type for \"prompt\" tag\n";
00455 n = n.nextSibling();
00456 }
00457 }
00458
00459 int vxmlParser::parseDurationType(QString t)
00460 {
00461 int breaktime = 0;
00462 if (t.contains("ms", false))
00463 breaktime = 1;
00464 else if (t.contains("s", false))
00465 breaktime = 1000;
00466 return (breaktime * atoi((const char *)t));
00467 }
00468
00469 bool vxmlParser::parseField(QDomElement &field)
00470 {
00471 QString Name = field.attribute("name");
00472 QString Type = field.attribute("type");
00473 QString Modal = field.attribute("modal");
00474
00475 uint minDigits = 0;
00476 uint maxDigits = 0;
00477 parseFieldType(Type, maxDigits, minDigits);
00478
00479
00480 Rtp->getDtmf();
00481
00482 QDomNode n = field.firstChild();
00483 while ((!n.isNull()) && (!killVxmlPage))
00484 {
00485 QDomElement e = n.toElement();
00486 if (!e.isNull())
00487 {
00488 if (e.tagName() == "prompt")
00489 parsePrompt(e, Modal == "true");
00490 }
00491 n = n.nextSibling();
00492 }
00493
00494
00495
00496 QString inDigits = Rtp->getDtmf();
00497 if ((inDigits.length() > 0) && (inDigits.length() < maxDigits))
00498 {
00499 QString newDigits;
00500 do
00501 {
00502 PlaySilence(4000, true);
00503 newDigits = Rtp->getDtmf();
00504 inDigits += newDigits;
00505 } while ((inDigits.length() < maxDigits) && (newDigits.length() > 0));
00506 }
00507
00508
00509 if (inDigits.length() >= minDigits)
00510 {
00511 vxmlVariable *variable = new vxmlVariable(Name, inDigits);
00512 vxmlVarList->removeMatching(Name);
00513 vxmlVarList->append(variable);
00514 return true;
00515 }
00516 return false;
00517 }
00518
00519 void vxmlParser::parseFieldType(QString Type, uint &Max, uint &Min)
00520 {
00521 Max = Min = 0;
00522 if (Type.startsWith("digits?length="))
00523 {
00524 Type.remove(0,14);
00525 Max = Min = Type.toUInt();
00526 }
00527 else if (Type.startsWith("digits?"))
00528 {
00529 int startMin = Type.find("minlength");
00530 if (startMin >= 0)
00531 {
00532 startMin += 10;
00533 QString minString = Type.mid(startMin);
00534 Min = (uint)atoi(minString);
00535 }
00536
00537 int startMax = Type.find("maxlength");
00538 if (startMax >= 0)
00539 {
00540 startMax += 10;
00541 QString maxString = Type.mid(startMax);
00542 Max = (uint)atoi(maxString);
00543 }
00544 }
00545 }
00546
00547 void vxmlParser::parseRecord(QDomElement &record)
00548 {
00549 bool reprompt;
00550 QString Name = record.attribute("name");
00551 QString Type = record.attribute("type");
00552 QString dtmfTerm = record.attribute("dtmfterm");
00553 QString maxTimeStr = record.attribute("maxtime");
00554 QString beep = record.attribute("beep");
00555
00556 int maxTime = parseDurationType(maxTimeStr);
00557 if (maxTime == 0)
00558 return;
00559
00560 QDomNode n = record.firstChild();
00561 while ((!n.isNull()) && (!killVxmlPage))
00562 {
00563 QDomElement e = n.toElement();
00564 if (!e.isNull())
00565 {
00566 if (e.tagName() == "prompt")
00567 parsePrompt(e, false);
00568 else if (e.tagName() == "filled")
00569 {
00570 if (beep == "true")
00571 PlayBeep();
00572 short *recBuffer = new short [maxTime*8];
00573 int recSize = RecordAudio(recBuffer, maxTime*8, dtmfTerm == "true");
00574
00575
00576 vxmlVariable *variable = new vxmlVariable(Name, recBuffer, recSize);
00577 vxmlVarList->removeMatching(Name);
00578 vxmlVarList->append(variable);
00579
00580 parseFilled(e, reprompt);
00581 }
00582 }
00583 n = n.nextSibling();
00584 }
00585
00586 }
00587
00588 void vxmlParser::parseNoInput(QDomElement &noInput, bool &reprompt)
00589 {
00590 QDomNode n = noInput.firstChild();
00591 while ((!n.isNull()) && (!killVxmlPage))
00592 {
00593 QDomElement e = n.toElement();
00594 QDomText t = n.toText();
00595 if (!e.isNull())
00596 {
00597 if (e.tagName() == "submit")
00598 {
00599 vxmlUrl = e.attribute("next");
00600 postNamelist = e.attribute("namelist");
00601 httpMethod = e.attribute("method");
00602 killVxmlPage = true;
00603 }
00604 else if (e.tagName() == "disconnect")
00605 killVxmlPage = true;
00606 else if (e.tagName() == "clear")
00607 vxmlVarList->removeMatching(e.attribute("namelist"));
00608 else if (e.tagName() == "reprompt")
00609 reprompt = true;
00610 else
00611 cerr << "Unsupported prompt sub-element tag \"" << e.tagName() << "\"\n";
00612 }
00613 else if (!t.isNull())
00614 {
00615 PlayTTSPrompt(t.data(), false);
00616 }
00617 else
00618 cerr << "Unsupported child type for \"prompt\" tag\n";
00619 n = n.nextSibling();
00620 }
00621 }
00622
00623 void vxmlParser::parseFilled(QDomElement &filled, bool &reprompt)
00624 {
00625 QDomNode n = filled.firstChild();
00626 while ((!n.isNull()) && (!killVxmlPage))
00627 {
00628 QDomElement e = n.toElement();
00629 if (!e.isNull())
00630 {
00631 if (e.tagName() == "prompt")
00632 parsePrompt(e, false);
00633 else if (e.tagName() == "if")
00634 parseIfExpression(e, reprompt);
00635 else
00636 cerr << "Unsupported prompt sub-element tag \"" << e.tagName() << "\"\n";
00637 }
00638 else
00639 cerr << "Unsupported child type for \"prompt\" tag\n";
00640 n = n.nextSibling();
00641 }
00642 }
00643
00644 void vxmlParser::parseIfExpression(QDomElement &ifExp, bool &reprompt)
00645 {
00646 QString Cond = ifExp.attribute("cond");
00647 QDomElement e = ifExp;
00648
00649 while ((!e.isNull()) && (!killVxmlPage))
00650 {
00651 if (parseIfBlock(e, Cond, reprompt))
00652 break;
00653 else
00654 {
00655 QDomNode n = e.firstChild();
00656
00657
00658 while ((!n.isNull()) && (!killVxmlPage))
00659 {
00660 e = n.toElement();
00661 if (!e.isNull())
00662 {
00663 if (e.tagName() == "elseif")
00664 {
00665 Cond = e.attribute("cond");
00666 break;
00667 }
00668 else if (e.tagName() == "else")
00669 {
00670 Cond = "";
00671 break;
00672 }
00673 }
00674 n = n.nextSibling();
00675 }
00676 if ((n.isNull()) || (killVxmlPage))
00677 break;
00678 }
00679 }
00680 }
00681
00682
00683 bool vxmlParser::parseIfBlock(QDomElement &ifBlock, QString Cond, bool &reprompt)
00684 {
00685 if (evaluateExpression(Cond))
00686 {
00687 QDomNode n = ifBlock.firstChild();
00688 while ((!n.isNull()) && (!killVxmlPage))
00689 {
00690 QDomElement e = n.toElement();
00691 QDomText t = n.toText();
00692 if (!e.isNull())
00693 {
00694 if (e.tagName() == "submit")
00695 {
00696 vxmlUrl = e.attribute("next");
00697 postNamelist = e.attribute("namelist");
00698 httpMethod = e.attribute("method");
00699 killVxmlPage = true;
00700 }
00701 else if (e.tagName() == "prompt")
00702 parsePrompt(e, false);
00703 else if (e.tagName() == "disconnect")
00704 killVxmlPage = true;
00705 else if (e.tagName() == "clear")
00706 vxmlVarList->removeMatching(e.attribute("namelist"));
00707 else if (e.tagName() == "reprompt")
00708 reprompt = true;
00709 else if ((e.tagName() == "elseif") || (e.tagName() == "else"))
00710 break;
00711 else
00712 cerr << "Unsupported prompt sub-element tag \"" << e.tagName() << "\"\n";
00713 }
00714 else if (!t.isNull())
00715 {
00716 PlayTTSPrompt(t.data(), false);
00717 }
00718 n = n.nextSibling();
00719 }
00720 return true;
00721 }
00722 return false;
00723 }
00724
00725
00726 bool vxmlParser::evaluateExpression(QString Expression)
00727 {
00728
00729 if (Expression == "")
00730 {
00731 return true;
00732 }
00733
00734
00735
00736 int Equals = Expression.find("==");
00737 int NotEquals = Expression.find("!=");
00738 int Seperator;
00739
00740 if (Equals > 0)
00741 Seperator = Equals;
00742 else if (NotEquals > 0)
00743 Seperator = NotEquals;
00744 else
00745 {
00746 cerr << "Invalid IF expression in VXML page\n";
00747 return false;
00748 }
00749
00750 QString varName = Expression.left(Seperator).stripWhiteSpace();
00751 QString varValue = vxmlVarList->findStringVariable(varName);
00752 QString value = Expression.mid(Seperator+2, Expression.length()).stripWhiteSpace();
00753
00754 if (((Equals >= 0) && (varValue == value)) ||
00755 ((NotEquals >= 0) && (varValue != value)))
00756 {
00757 return true;
00758 }
00759 return false;
00760 }
00761
00762
00763 void vxmlParser::parseForm(QDomElement &formElm)
00764 {
00765 bool reprompt;
00766 int loopCnt=0;
00767 do
00768 {
00769 reprompt = false;
00770 loopCnt++;
00771 QDomNode n = formElm.firstChild();
00772 bool filled = false;
00773 while ((!n.isNull()) && (!killVxmlPage))
00774 {
00775 QDomElement e = n.toElement();
00776 if (!e.isNull())
00777 {
00778 if (e.tagName() == "record")
00779 parseRecord(e);
00780 else if (e.tagName() == "field")
00781 filled = parseField(e);
00782 else if ((e.tagName() == "filled") && (filled))
00783 parseFilled(e, reprompt);
00784 else if ((e.tagName() == "noinput") && (!filled) && ((e.attribute("count") == 0) || (atoi(e.attribute("count")) == loopCnt)))
00785 parseNoInput(e, reprompt);
00786 }
00787 n = n.nextSibling();
00788 }
00789 } while (reprompt);
00790 }
00791
00792
00793 void vxmlParser::PlayWav(short *buffer, int Samples)
00794 {
00795 Rtp->Transmit(buffer, Samples);
00796 waitUntilFinished(false);
00797 }
00798
00799
00800 void vxmlParser::PlayWav(QString wavFile)
00801 {
00802 wavfile wav;
00803 wav.load(wavFile);
00804
00805 Rtp->Transmit(wav.getData(), wav.samples());
00806 waitUntilFinished(false);
00807 }
00808
00809
00810 void vxmlParser::SaveWav(short *buffer, int Samples)
00811 {
00812 QString fileName = MythContext::GetConfDir() + "/MythPhone/Voicemail/" +
00813 QDateTime::currentDateTime().toString() + " " + callerName + ".wav";
00814
00815
00816
00817 QFile f(fileName);
00818 if (f.exists())
00819 f.remove();
00820
00821 wavfile vmail;
00822 vmail.load(buffer, Samples);
00823 vmail.saveToFile(fileName);
00824 }
00825
00826
00827
00828
00829 void vxmlParser::PlayBeep(int freqHz, int volume, int ms)
00830 {
00831 int Samples = ms * 8;
00832 short *beepBuffer = new short[Samples];
00833
00834 for (int c=0; c<Samples; c++)
00835 beepBuffer[c] = (short)(sin(c * 2 * M_PI * freqHz / 8000) * volume);
00836
00837 Rtp->Transmit(beepBuffer, Samples);
00838 waitUntilFinished(false);
00839 delete beepBuffer;
00840 }
00841
00842
00843
00844 void vxmlParser::PlayTTSPrompt(QString prompt, bool dtmfInterrupts)
00845 {
00846 wavfile Wave;
00847 speechEngine->toWavFile((const char *)prompt, Wave);
00848
00849
00850
00851
00852 if (Wave.getData())
00853 {
00854 Rtp->Transmit(Wave.getData(), Wave.samples());
00855 waitUntilFinished(dtmfInterrupts);
00856 }
00857 }
00858
00859 void vxmlParser::PlaySilence(int ms, bool dtmfInterrupts)
00860 {
00861 if (ms)
00862 {
00863 Rtp->Transmit(ms);
00864 waitUntilFinished(dtmfInterrupts);
00865 }
00866 }
00867
00868 int vxmlParser::RecordAudio(short *buffer, int Samples, bool dtmfInterrupts)
00869 {
00870 if (Samples)
00871 {
00872 Rtp->Record(buffer, Samples);
00873 waitUntilFinished(dtmfInterrupts);
00874 return Rtp->GetRecordSamples();
00875 }
00876 return 0;
00877 }
00878
00879 void vxmlParser::waitUntilFinished(bool dtmfInterrupts)
00880 {
00881
00882
00883
00884 while ((!killVxmlPage) && (!Rtp->Finished()) &&
00885 (!dtmfInterrupts || (!Rtp->checkDtmf())))
00886 usleep(100000);
00887 if (!Rtp->Finished())
00888 Rtp->StopTransmitRecord();
00889 }
00890
00891
00892
00894
00895
00896
00897
00898
00900
00901 vxmlVarContainer::vxmlVarContainer():QPtrList<vxmlVariable>()
00902 {
00903 }
00904
00905 vxmlVarContainer::~vxmlVarContainer()
00906 {
00907 vxmlVariable *p;
00908 while ((p = first()) != 0)
00909 {
00910 if (p->isType("SHORTPTR"))
00911 p->delSPValue();
00912 remove();
00913 delete p;
00914 }
00915 }
00916
00917 vxmlVariable *vxmlVarContainer::findFirstVariable(QString T)
00918 {
00919 vxmlVariable *it;
00920 for (it=first(); it; it=next())
00921 {
00922 if (it->isType(T))
00923 {
00924 return it;
00925 }
00926 }
00927 return 0;
00928 }
00929
00930 QString vxmlVarContainer::findStringVariable(QString N)
00931 {
00932 vxmlVariable *it;
00933 for (it=first(); it; it=next())
00934 {
00935 if (it->isType("STRING"))
00936 {
00937 if (it->getName() == N)
00938 return it->getSValue();
00939 }
00940 }
00941 return "";
00942 }
00943
00944 short *vxmlVarContainer::findShortPtrVariable(QString N, int &Samples)
00945 {
00946 vxmlVariable *it;
00947 for (it=first(); it; it=next())
00948 {
00949 if (it->isType("SHORTPTR"))
00950 {
00951 if (it->getName() == N)
00952 {
00953 Samples = it->getSPLength();
00954 return it->getSPValue();
00955 }
00956 }
00957 }
00958 return 0;
00959 }
00960
00961 void vxmlVarContainer::removeMatching(QString N)
00962 {
00963 vxmlVariable *it;
00964 for (it=first(); it; it=next())
00965 {
00966 if (it->getName() == N)
00967 {
00968 if (it->isType("SHORTPTR"))
00969 it->delSPValue();
00970 remove();
00971 delete it;
00972 }
00973 }
00974 }
00975
00976 vxmlVariable::vxmlVariable(QString N, QString V)
00977 {
00978 Name = N;
00979 sValue = V;
00980 Type = "STRING";
00981 spValue = 0;
00982 }
00983
00984 vxmlVariable::vxmlVariable(QString N, short *wav, int S)
00985 {
00986 Name = N;
00987 spValue = wav;
00988 spLength = S;
00989 Type = "SHORTPTR";
00990 }
00991
00992
00993
00994
00995
00996