00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <bogotel/Portability.h>
00011 #include <bogotel/VoiceDev.h>
00012 #include <bogotel/BgtErrors.h>
00013 #include <bogotel/SignalDev.h>
00014 #include <bogotel/util.h>
00015 #include <bogotel/Timer.h>
00016 #include <bogotel/playop.h>
00017 #include <bogotel/dialop.h>
00018 #include <bogotel/getdigop.h>
00019
00020 namespace bogotel {
00021
00022 MAP_INT2STR CVoiceDev::s_mapHandle2Filename;
00023 std::string CVoiceDev::s_strWavFilenameBase;
00024 CProperties CVoiceDev::s_propWav2Dtmfs;
00025 const int CVoiceDev::invalidHandle = -1;
00026
00027 CVoiceDev::CVoiceDev(CBgtRt *pBgtRt) :
00028 CDevBase(pBgtRt),
00029 m_lSCbusTimeslot(-1),
00030 m_lHandle(invalidHandle),
00031 m_pSignalDev(NULL),
00032 m_lTermMsk(0),
00033 m_pIoOp(NULL),
00034 m_pInternalIoOp(NULL),
00035 m_speakerState(speakerState::SILENT),
00036 m_uiStateId(0)
00037 {
00038 }
00039
00040 int CVoiceDev::init(std::string strName, long lHandle, long lTimeslot)
00041 {
00042 int rc;
00043 if ((rc = CDevBase::init()) != resultSUCCESS) {
00044 return rc;
00045 }
00046
00047 m_strName = strName;
00048 m_lHandle = lHandle;
00049 m_lSCbusTimeslot = lTimeslot;
00050 return resultSUCCESS;
00051 }
00052
00053 int CVoiceDev::listen(CSignalDev *pSD)
00054 {
00055 if (m_pSignalDev != NULL) {
00056 return resultPOINTER;
00057 }
00058 m_pSignalDev = pSD;
00059
00060 return resultSUCCESS;
00061 }
00062
00063
00064 int CVoiceDev::play(DX_IOTT *pIott, const DV_TPT *pTpt, const DX_XPB *pXpb, unsigned short usMode)
00065 {
00066 char method[] = "CVoiceDev::play";
00067
00068 if (usMode != EV_ASYNC) {
00069 return resultFUNC_BAD_PARAMETER;
00070 }
00071
00072 try {
00073 registerIoOp(new CPlayOp(this, pIott, pTpt));
00074 } catch (...) {
00075 log(3, "%s(): CVoiceDev::registerIoOp threw an exception", method);
00076 return resultFAIL;
00077 }
00078
00079 return resultSUCCESS;
00080 }
00081
00082
00083 int CVoiceDev::dial(const char *szDialStr, const DX_CAP *pCAP, unsigned short usMode)
00084 {
00085 char method[] = "CVoiceDev::dial";
00086
00087 if (usMode != EV_ASYNC) {
00088 return resultFUNC_BAD_PARAMETER;
00089 }
00090 try {
00091 registerIoOp(new CDialOp(this, szDialStr, targetType::remote));
00092 } catch (std::invalid_argument& x) {
00093 log(3, "%s(): new CDialOp threw an invalid_argument exception. %s", method,
00094 x.what());
00095 return resultFAIL;
00096 } catch (...) {
00097 log(3, "%s(): CVoiceDev::registerIoOp threw an exception", method);
00098 return resultFAIL;
00099 }
00100
00101 return resultSUCCESS;
00102 }
00103
00104
00105
00106 int CVoiceDev::getDigit(const DV_TPT *pTpt, DV_DIGIT *pDigit, unsigned short usMode)
00107 {
00108 char method[] = "CVoiceDev::getDigit";
00109
00110
00111 if (usMode != EV_ASYNC) {
00112 return resultFUNC_BAD_PARAMETER;
00113 }
00114
00115 CGetDigOp *pOp;
00116 try {
00117 pOp = new CGetDigOp(this, pTpt, pDigit);
00118 } catch (std::invalid_argument& x) {
00119 log(3, "%s(): new CGetDigOp threw an invalid_argument exception. %s", method,
00120 x.what());
00121 return resultFAIL;
00122 } catch (...) {
00123 log(3, "%s(): new CGetDigOp threw an exception", method);
00124 return resultFAIL;
00125 }
00126
00127 try {
00128 registerIoOp(pOp);
00129 } catch (std::invalid_argument& x) {
00130 log(3, "%s(): CVoiceDev::registerIoOp threw an invalid_argument exception. %s", method,
00131 x.what());
00132 return resultFAIL;
00133 } catch (...) {
00134 log(3, "%s(): CVoiceDev::registerIoOp threw an exception", method);
00135 return resultFAIL;
00136 }
00137
00138 return resultSUCCESS;
00139 }
00140
00141
00142 void CVoiceDev::terminateIoOp(long lTermMsk, bool bInternalIoOp)
00143 {
00144 char method[] = "CVoiceDev::terminateIoOp";
00145
00146 boost::recursive_mutex::scoped_lock lock(m_mtxIoOps);
00147
00148 log(9, "%s: Entered.", method);
00149 if (bInternalIoOp) {
00150 if (m_pInternalIoOp) {
00151 std::string strOpName = m_pInternalIoOp->toString();
00152 m_pTimer->requestTargetDeletion(m_pInternalIoOp);
00153 m_pInternalIoOp = NULL;
00154 log(7, "%s: internal IO op terminated. Op: %s", method,
00155 strOpName.c_str());
00156 }
00157 } else {
00158 if (m_pIoOp) {
00159 std::string strOpName = m_pIoOp->toString();
00160 sendEvent(m_pIoOp->terminationEvent(), lTermMsk);
00161
00162 m_pTimer->requestTargetDeletion(m_pIoOp);
00163 m_pIoOp = NULL;
00164 log(7, "%s: IO op terminated. Op: %s", method,
00165 strOpName.c_str());
00166 }
00167 }
00168 log(9, "%s: Completed.", method);
00169 }
00170
00171
00172
00173 void CVoiceDev::registerIoOp(CIOOp *pIoOp, bool bInternalIoOp)
00174 {
00175 char method[] = "CVoiceDev::registerIoOp";
00176 log(9, "%s: Entered. Is internal OP? %s", method, bInternalIoOp? "TRUE" : "FALSE");
00177
00178 boost::recursive_mutex::scoped_lock lock(m_mtxIoOps);
00179
00180 terminateIoOp(TM_USRSTOP, bInternalIoOp);
00181 m_pTimer->registerTarget(pIoOp);
00182
00183 if (bInternalIoOp) {
00184 m_pInternalIoOp = pIoOp;
00185 } else {
00186 m_pIoOp = pIoOp;
00187 }
00188
00189 pIoOp->start();
00190 }
00191
00192 int CVoiceDev::stop(unsigned short usMode)
00193 {
00194 int rc = resultSUCCESS;
00195
00196 terminateIoOp(TM_USRSTOP);
00197
00198 log(9, "CVoiceDev::stop() completed.");
00199
00200 return rc;
00201 }
00202
00203 int CVoiceDev::clearDigitBuffer()
00204 {
00205 while (! m_queueDigitValue.empty()) {
00206 m_queueDigitValue.pop();
00207 m_queueDigitType.pop();
00208 }
00209 eraseDigitHistory();
00210
00211 log(9, "CVoiceDev::clearDigitBuffer() completed.");
00212
00213 return resultSUCCESS;
00214 }
00215
00216 int CVoiceDev::receiveMsg(CMsg *pMsg)
00217 {
00218 long hSignal = m_pSignalDev->getHandle();
00219 char method[] = "CVoiceDev::receiveMsg";
00220
00221 char szType[30];
00222 pMsg->getMsgTypeString(szType, sizeof(szType));
00223 log(7, "%s(): %s type", method, szType);
00224
00225 switch(pMsg->m_type) {
00226 case MT_PLAY_WAV:
00227 updateSpeakerState(speakerState::WAV, pMsg->getParam(PT_WAV_FILENAME).c_str());
00228 break;
00229
00230 case MT_PLAY_WAV_FINISHED:
00231
00232 terminateIoOp(TM_USRSTOP, true);
00233 updateSpeakerState(speakerState::SILENT);
00234 break;
00235
00236 case MT_PLAY_DTMF:
00237 updateSpeakerState(speakerState::DTMF, pMsg->getParam(PT_DTMF).c_str()[0]);
00238 break;
00239
00240 case MT_PLAY_DTMF_FINISHED:
00241 updateSpeakerState(speakerState::SILENT);
00242 break;
00243
00244 default:
00245 log(3, "%s: Unknown message type: %i",method , pMsg->m_type);
00246 break;
00247 }
00248
00249 log(9, "%s completed.", method);
00250 return resultSUCCESS;
00251 }
00252
00253 void CVoiceDev::updateSpeakerState(speakerState state, std::string strFilename)
00254 {
00255 m_strCurrPlaybackFilename = strFilename;
00256
00257 if (! attemptRecognition(strFilename)) {
00258
00259 updateSpeakerState(state);
00260 }
00261 }
00262
00263 void CVoiceDev::updateSpeakerState(speakerState state, char chDtmf)
00264 {
00265 if (chDtmf == '\0') {
00266 log(3, "Null as new dtmf char");
00267 return;
00268 }
00269
00270 if (m_queueDigitValue.size() < DG_MAXDIGS) {
00271 m_queueDigitValue.push(chDtmf);
00272 m_queueDigitType.push(D_DTMF);
00273 }
00274 updateSpeakerState(state);
00275 }
00276
00277 void CVoiceDev::updateSpeakerState(speakerState state)
00278 {
00279 char method[] = "CVoiceDev::updateSpeakerState";
00280 log(9, "%s entered.", method);
00281
00282 m_speakerState = state;
00283 m_uiStateId++;
00284 switch (state) {
00285 case speakerState::WAV:
00286 log(5, "Now hearing WAV file \"%s\"", m_strCurrPlaybackFilename);
00287 break;
00288 case speakerState::DTMF:
00289 log(5, "Now hearing DTMF \"%c\"", m_queueDigitValue.back());
00290 break;
00291 case speakerState::SILENT:
00292 m_strCurrPlaybackFilename = "";
00293 log(5, "Now hearing nothing.");
00294 break;
00295 }
00296
00297 CSubject::notify();
00298
00299 log(9, "%s completed.", method);
00300 }
00301
00302
00303
00304
00305 bool CVoiceDev::attemptRecognition(std::string& strFilename)
00306 {
00307 char method[] = "CVoiceDev::attemptRecognition";
00308
00309 std::string strDtmfs = s_propWav2Dtmfs.getProperty(strFilename);
00310 if (strDtmfs != "") {
00311
00312 strDtmfs.append(g_util->m_propIni.getProperty("DtmfDelimiterChar", "d"));
00313
00314 log(5, "Wav \"%s\" recognized as DTMFs \"%s\"", strFilename.c_str(),
00315 strDtmfs.c_str());
00316
00317 try {
00318
00319
00320
00321 if (m_pInternalIoOp != NULL) {
00322 log(3, "%s(): m_pInternalIoOp not NULL.", method);
00323 }
00324
00325 CIOOp *pIoOp = new CDialOp(this, strDtmfs.c_str(), targetType::local);
00326 registerIoOp(pIoOp, true);
00327 return true;
00328 } catch (...) {
00329 log(3, "%s(): CVoiceDev::registerIoOp threw an exception", method);
00330 return false;
00331 }
00332 }
00333 return false;
00334 }
00335
00336 int CVoiceDev::sendMsg(CMsg *pMsg, int iTargetType)
00337 {
00338 char szType[30];
00339 pMsg->getMsgTypeString(szType, sizeof(szType));
00340 log(7, "CVoiceDev::sendMsg(): %s type", szType);
00341 switch (iTargetType) {
00342 case targetType::remote:
00343 return m_pTransport->sendMsg(pMsg);
00344 case targetType::local:
00345 return receiveMsg(pMsg);
00346 default:
00347 log(3, "CVoiceDev::sendMsg(): Invalid target type");
00348 return resultFUNC_BAD_PARAMETER;
00349 }
00350 }
00351
00352 void CVoiceDev::sendPlayMsg(std::string strFilename)
00353 {
00354 stripBaseFromWavFilename(strFilename);
00355
00356 m_pMsg->init(MT_PLAY_WAV, MC_VOICE, m_lHandle);
00357 m_pMsg->addParam(PT_WAV_FILENAME, strFilename);
00358 if (sendMsg(m_pMsg) != resultSUCCESS) {
00359 log(3, "CVoiceDev::sendPlayMsg(): sendMsg() failed");
00360 }
00361 }
00362
00363 void CVoiceDev::sendPlayFinishedMsg()
00364 {
00365 m_pMsg->init(MT_PLAY_WAV_FINISHED, MC_VOICE, m_lHandle);
00366 if (sendMsg(m_pMsg) != resultSUCCESS) {
00367 log(3, "CVoiceDev::sendPlayFinishedMsg(): sendMsg() failed");
00368 }
00369 }
00370
00371 void CVoiceDev::sendDtmfMsg(char chDtmf, int iTargetType)
00372 {
00373 char method[] = "CVoiceDev::sendDtmfMsg";
00374
00375 log(9, "%s: dtmf=%c", method, chDtmf);
00376 m_pMsg->init(MT_PLAY_DTMF, MC_VOICE, m_lHandle);
00377 std::string strDtmf;
00378 strDtmf.push_back(chDtmf);
00379 m_pMsg->addParam(PT_DTMF, strDtmf);
00380 if (sendMsg(m_pMsg, iTargetType) != resultSUCCESS) {
00381 log(3, "CVoiceDev::sendDTMFMsg(): sendMsg() failed");
00382 }
00383 }
00384
00385 void CVoiceDev::sendDtmfFinishedMsg(int iTargetType)
00386 {
00387 m_pMsg->init(MT_PLAY_DTMF_FINISHED, MC_VOICE, m_lHandle);
00388 if (sendMsg(m_pMsg, iTargetType) != resultSUCCESS) {
00389 log(3, "CVoiceDev::sendDTMFFinishedMsg(): sendMsg() failed");
00390 }
00391 }
00392
00393 void CVoiceDev::stripBaseFromWavFilename(std::string& strFilename)
00394 {
00395 if (strFilename.find(s_strWavFilenameBase) == 0) {
00396 strFilename.erase(0, s_strWavFilenameBase.length());
00397 }
00398 }
00399
00400 int CVoiceDev::sendEvent(long lType, long lTermMask)
00401 {
00402
00403
00404
00405 m_lTermMsk = lTermMask;
00406
00407 CEvt *pEvt = new CEvt();
00408
00409 pEvt->m_pUsrAttr = NULL;
00410 pEvt->m_lLen = 0;
00411 pEvt->m_lType = lType;
00412 pEvt->m_lVoiceDevHandle = m_lHandle;
00413 pEvt->m_lSignalDevHandle = m_pSignalDev->getHandle();
00414 pEvt->m_ulFlags = 0;
00415 pEvt->m_lCrn = INVALID_CRN;
00416 pEvt->m_iSysType = CEvt::SysType::DEVICE;
00417
00418 int rc;
00419 if ((rc = m_pBgtRt->addEvent(pEvt)) != resultSUCCESS) {
00420 log(3, "CVoiceDev::sendEvent(): CBgtRt::addEvent failed. rc is %d", rc);
00421 return rc;
00422 }
00423 log(7, "CVoiceDev::sendEvent(): %s type", pEvt->toString().c_str());
00424 return rc;
00425 }
00426
00427 void CVoiceDev::log(int iLevel, char *szFmt, ...)
00428 {
00429 va_list vl;
00430 char szTemp[2000];
00431
00432 va_start(vl, szFmt);
00433 _vsnprintf(szTemp, sizeof(szTemp), szFmt, vl);
00434 va_end(vl);
00435
00436 g_util->log(iLevel, m_pSignalDev->getHandle(), szTemp);
00437 }
00438
00439 long CVoiceDev::getSignalHandle()
00440 {
00441 return m_pSignalDev->getHandle();
00442 }
00443
00444 void CVoiceDev::eraseFromDigitHistory(unsigned short iToChop)
00445 {
00446 char method[] = "CVoiceDev::eraseFromDigitHistory";
00447
00448 DEQUE_CHAR::iterator iterTillToChop = m_dequeDigitHistory.begin();
00449 for (int i = 0; i < iToChop; i++) {
00450 if (iterTillToChop == m_dequeDigitHistory.end()) {
00451 log(3, "%s: request to remove more digits than in history. Length of history: %d."
00452 " Number to remove: %d", method, m_dequeDigitHistory.size(),
00453 iToChop);
00454 break;
00455 }
00456 iterTillToChop++;
00457 }
00458 m_dequeDigitHistory.erase(m_dequeDigitHistory.begin(), iterTillToChop);
00459 }
00460
00461 void CVoiceDev::eraseFromDigitHistory(DEQUE_CHAR::iterator iterTillToChop)
00462 {
00463 m_dequeDigitHistory.erase(m_dequeDigitHistory.begin(), iterTillToChop);
00464 }
00465
00466 void CVoiceDev::eraseDigitHistory()
00467 {
00468 m_dequeDigitHistory.erase(m_dequeDigitHistory.begin(), m_dequeDigitHistory.end());
00469 }
00470
00471 void CVoiceDev::getDigits(DV_DIGIT *pDigit, int iNumToGet)
00472 {
00473 char method[] = "CVoiceDev::getDigits";
00474
00475 log(9, "%s: Entered.", method);
00476
00477
00478 if (iNumToGet > DG_MAXDIGS) {
00479 log(5, "%s: request to get more digits than DG_MAXDIGS. Number requested: %d.",
00480 method, iNumToGet);
00481 iNumToGet = DG_MAXDIGS;
00482 }
00483 if (iNumToGet > static_cast<int>(m_queueDigitValue.size())) {
00484 log(5, "%s: request to get more digits than in buffer. Number requested: %d."
00485 " Number in buffer: %d", method, iNumToGet, m_dequeDigitHistory.size());
00486 iNumToGet = m_queueDigitValue.size();
00487 }
00488
00489 for (int i = 0; i < iNumToGet; i++) {
00490 pDigit->dg_value[i] = m_queueDigitValue.front();
00491 m_queueDigitValue.pop();
00492 pDigit->dg_type[i] = m_queueDigitType.front();
00493 m_queueDigitType.pop();
00494 }
00495 pDigit->dg_value[iNumToGet] = '\0';
00496 pDigit->dg_type[iNumToGet] = (char)DG_END;
00497 }
00498
00499 const std::string& CVoiceDev::getEventName(long lType)
00500 {
00501 switch(lType) {
00502 case TDX_PLAY: return eventNames[0];
00503 case TDX_GETDIG: return eventNames[1];
00504 case TDX_ERROR: return eventNames[2];
00505 case TDX_DIAL: return eventNames[3];
00506 default: return eventNames[4];
00507 }
00508 }
00509
00510 const std::string CVoiceDev::eventNames[5] = {
00511 "TDX_PLAY",
00512 "TDX_GETDIG",
00513 "TDX_ERROR",
00514 "TDX_DIAL",
00515 "Unknown"
00516 };
00517
00518 }
00519