linux版本中间件

Session.cpp 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. #include "..\AsrService\Session.h"
  2. #include "..\AsrService\Session.h"
  3. #include "..\AsrService\Session.h"
  4. #include "..\AsrService\Session.h"
  5. #include "Session.h"
  6. #include <boost/filesystem.hpp>
  7. #include "FsProxy.h"
  8. #include "ChanTrunk.h"
  9. #include "ChanExten.h"
  10. #include "JsonStringMaker.h"
  11. #include "Util.h"
  12. #include "SqlWrite.h"
  13. #include "Config.h"
  14. Session::Session(CFsProxy* pParent, string Id) : m_pParent(pParent), m_Id(Id), m_IsAnswer(false), m_IsSaveDb(true), m_AtionId(0)
  15. {
  16. }
  17. Session::~Session()
  18. {
  19. }
  20. bool Session::isContainChanId(const std::string & chanId)
  21. {
  22. std::unique_lock<std::mutex> lock(m_ChanLock);
  23. for (auto pChan : m_ListChan)
  24. {
  25. if (pChan->chanId() == chanId)
  26. return true;
  27. }
  28. return false;
  29. }
  30. void Session::prepare(PCHAN_EVENT_NOTIFY pNotify)
  31. {
  32. if (m_Id != pNotify->ChanId) // 触发会话的通道不是会话主通道,则查找并添加主通道
  33. {
  34. VirtualChan* pChan = m_pParent->getBusyChan(m_Id);
  35. if (pChan != nullptr)
  36. __addChan(pChan);
  37. }
  38. }
  39. void Session::onChanEvent(PCHAN_EVENT_NOTIFY pNotify)
  40. {
  41. if (pNotify == nullptr) return;
  42. VirtualChan* pChan = __getChan(pNotify->ChanId);
  43. if (pChan == nullptr)
  44. {
  45. pChan = __findChan(pNotify);
  46. if (pChan != nullptr)
  47. __addChan(pChan);
  48. else
  49. {
  50. Format fmt("{Fs.Session}: 处理通道事件时查找对应通道失败, Caller = %s, Callee = %s");
  51. fmt % pNotify->Caller % pNotify->Callee;
  52. LOG_WARN_S(fmt.str());
  53. return;
  54. }
  55. }
  56. __notifyDbSaveChanEvent(pChan, pNotify); // 通话记录保存
  57. pChan->onChanEvent(pNotify);
  58. __notifyIncomingChanEvent(pChan, pNotify); // 来电弹屏
  59. __onRecord(pChan, pNotify); // 执行录音
  60. // 过滤无效状态
  61. if (pChan->state() == CHAN_LOGIC_STATE_FREE && pNotify->EventId == CHANNEL_EVENT_CREATE)
  62. return;
  63. __notifySessionChanEvent(pChan, pNotify);
  64. __onPlayAgentNo(pChan, pNotify); // 判断是否报工号
  65. try
  66. {
  67. if (pChan->isFree())
  68. __onChanFree(pChan, pNotify);
  69. }
  70. catch (const std::exception& e)
  71. {
  72. LOG_WARN(("{Fs.Session.onChanEvent}: 通道空闲处理函数执行发生异常[%s], Caller = %s, Callee = %s"),e.what(), pNotify->Caller.c_str(), pNotify->Callee.c_str());
  73. }
  74. }
  75. void Session::onChanDtmf(PDTMF_NOTIFY pNotify)
  76. {
  77. }
  78. void Session::onChanHold(PHOLD_NOTIFY pNotify)
  79. {
  80. VirtualChan* pChan = __getChan(pNotify->ChanId);
  81. if (pChan != nullptr)
  82. {
  83. pChan->onChanHold(pNotify->EvtType);
  84. }
  85. }
  86. VirtualChan * Session::getAssoChan(VirtualChan * pChan)
  87. {
  88. std::unique_lock<std::mutex> lock(m_ChanLock);
  89. auto it = m_ListChan.begin();
  90. while (it != m_ListChan.end())
  91. {
  92. if (*it != pChan)
  93. return *it;
  94. ++it;
  95. }
  96. return nullptr;
  97. }
  98. VirtualChan * Session::getAssoFinalChan()
  99. {
  100. std::unique_lock<std::mutex> lock(m_ChanLock);
  101. return m_ListChan.back();
  102. }
  103. VirtualChan * Session::getAssoFinalChan(VirtualChan * pChan)
  104. {
  105. std::unique_lock<std::mutex> lock(m_ChanLock);
  106. auto pFinalChan = m_ListChan.back();
  107. if (pFinalChan == pChan)return nullptr; // 是同一条,返回空
  108. return m_ListChan.back();
  109. }
  110. VirtualChan * Session::__getFirstChan()
  111. {
  112. std::unique_lock<std::mutex> lock(m_ChanLock);
  113. if(m_ListChan.empty())
  114. return nullptr;
  115. return m_ListChan.front();
  116. }
  117. VirtualChan * Session::__getChan(string ChanId)
  118. {
  119. std::unique_lock<std::mutex> lock(m_ChanLock);
  120. auto it = m_ListChan.begin();
  121. while (it != m_ListChan.end())
  122. {
  123. if ((*it)->chanId() == ChanId)
  124. return *it;
  125. ++it;
  126. }
  127. return nullptr;
  128. }
  129. VirtualChan * Session::__findChan(PCHAN_EVENT_NOTIFY pNotify)
  130. {
  131. VirtualChan* pChan = nullptr;
  132. if (pNotify->EventId == CHANNEL_EVENT_CREATE)
  133. {
  134. stringstream str;
  135. uint32_t ExtenNo = 0;
  136. if (pNotify->Direction == CALL_DIRECTION_INBOUND)
  137. str << pNotify->Caller; //ExtenNo = stoul(pNotify->Caller); // 呼入FS
  138. else
  139. str << pNotify->Callee; //ExtenNo = stoul(pNotify->Callee); // FS呼出
  140. str >> ExtenNo;
  141. pChan = m_pParent->getExten(ExtenNo);
  142. if (pChan == nullptr) // 分机通道中无,则说明是中继通道
  143. {
  144. pChan = m_pParent->getFreeTrunk();
  145. if (pChan == nullptr)
  146. {
  147. Format fmt("{Fs.Session}: 处理通道事件时获取空闲中继通道失败, Caller = %s, Callee = %s");
  148. fmt % pNotify->Caller % pNotify->Callee;
  149. LOG_WARN_S(fmt.str());
  150. m_pParent->onChanPoor(this, pNotify);
  151. }
  152. }
  153. }
  154. else
  155. {
  156. pChan = m_pParent->getBusyChan(pNotify->ChanId);
  157. }
  158. return pChan;
  159. }
  160. void Session::__addChan(VirtualChan * pChan)
  161. {
  162. std::unique_lock<std::mutex> lock(m_ChanLock);
  163. m_ListChan.emplace_back(pChan);
  164. }
  165. /*****************************************************************
  166. **【函数名称】 __delChan
  167. **【函数功能】 删除指定通道
  168. **【参数】
  169. **【返回值】
  170. *****************************************************************/
  171. void Session::__delChan(VirtualChan * pChan)
  172. {
  173. std::unique_lock<std::mutex> lock(m_ChanLock);
  174. m_ListChan.remove(pChan);
  175. }
  176. /*****************************************************************
  177. **【函数名称】 __clearChan
  178. **【函数功能】 清空通道
  179. **【参数】
  180. **【返回值】
  181. *****************************************************************/
  182. void Session::__clearChan(void)
  183. {
  184. std::unique_lock<std::mutex> lock(m_ChanLock);
  185. m_ListChan.clear();
  186. }
  187. void Session::__notifySessionChanEvent(VirtualChan * pChanHost, PCHAN_EVENT_NOTIFY pNotify)
  188. {
  189. std::unique_lock<std::mutex> lock(m_ChanLock);
  190. auto it = m_ListChan.begin();
  191. while (it != m_ListChan.end())
  192. {
  193. if ((*it) != pChanHost)
  194. {
  195. (*it)->onSessionChanEvent(pChanHost, pNotify);
  196. }
  197. ++it;
  198. }
  199. }
  200. /*
  201. ** 分机来电事件
  202. */
  203. void Session::__notifyIncomingChanEvent(VirtualChan * pChanHost, PCHAN_EVENT_NOTIFY pNotify)
  204. {
  205. if (pNotify->Caller == pNotify->Callee && pNotify->Called.empty()) // 自震分机不弹屏/班长坐席操作不弹屏
  206. return;
  207. // 会话有两条通道,且当前通道为分机,当前时间为创建对话,发送来电事件给当前分机
  208. if (m_ListChan.size()==2 && pChanHost->type() == DEV_RES_TYPE_EXT && pNotify->EventId == CHANNEL_EVENT_CREATE)
  209. {
  210. std::string CallID = pNotify->CcId.empty()==true ? pNotify->CallId : pNotify->CcId;
  211. std::string ExtenNo = std::to_string(pChanHost->no());
  212. std::string Number = pNotify->Caller; // 主叫号码
  213. std::string callee = pNotify->Callee; // 被叫号码
  214. std::string TrunkNumber;
  215. int inComingType = 0;
  216. inComingType = 1;
  217. auto pFirstChan = __getFirstChan();
  218. if (pFirstChan != nullptr && pFirstChan->type() == DEV_RES_TYPE_TRUNK)
  219. TrunkNumber = pFirstChan->calleeNum();
  220. std::string data = m_pParent->creatJsonIncoming(CallID, Number, callee, TrunkNumber,inComingType);
  221. m_pParent->send2Agent(ExtenNo,data); // 发送来电事件到坐席
  222. }
  223. if (m_ListChan.size() == 1 && pNotify->EventId == CHANNEL_EVENT_CREATE)
  224. {
  225. if (pChanHost->type() == DEV_RES_TYPE_EXT) // 分机外呼弹屏
  226. {
  227. std::string CallID = pNotify->CcId.empty() == true ? pNotify->CallId : pNotify->CcId;
  228. std::string ExtenNo = std::to_string(pChanHost->no());
  229. std::string Number = pChanHost->callerNum(); //pNotify->Caller; // 主叫号码 , 代接,强插时主叫问题
  230. std::string callee = pNotify->Callee; // 被叫号码
  231. if (Number == callee && !pNotify->Called.empty())
  232. {
  233. callee = pNotify->Called;
  234. }
  235. std::string TrunkNumber;
  236. int inComingType = 0;
  237. if (pNotify->CallType == 0) // 分机外呼
  238. {
  239. inComingType = 2;
  240. if (pNotify->Caller != pNotify->Callee && pNotify->Direction == CALL_DIRECTION_OUTBOUND) // 该条件下会议 收到来电弹屏
  241. inComingType = 1;
  242. }
  243. else // 自动外呼
  244. {
  245. inComingType = 3;
  246. }
  247. std::string data = m_pParent->creatJsonIncoming(CallID, Number, callee, TrunkNumber, inComingType);
  248. m_pParent->send2Agent(ExtenNo, data); // 发送来电事件到坐席
  249. }
  250. }
  251. //if (m_ListChan.size() == 2 && pNotify->EventId == CHANNEL_EVENT_CREATE)
  252. //{
  253. // std::string CallID = pNotify->CcId.empty() == true ? pNotify->CallId : pNotify->CcId;
  254. // std::string ExtenNo = std::to_string(pChanHost->no());
  255. // std::string Number = pNotify->Caller; // 主叫号码
  256. // std::string callee = pNotify->Callee; // 被叫号码
  257. // std::string TrunkNumber; // 中继号码
  258. // int inComingType = 0;
  259. // auto pFirstChan = __getFirstChan();
  260. // if (pFirstChan != nullptr && pFirstChan->type() == DEV_RES_TYPE_TRUNK)
  261. // {
  262. // TrunkNumber = pFirstChan->calleeNum();
  263. // inComingType = 2; // 来电
  264. // }
  265. // else if(pFirstChan != nullptr && pFirstChan->type() == DEV_RES_TYPE_EXT)
  266. // {
  267. // inComingType = 1; // 分机外呼
  268. // if(pNotify->CallType == 2) // 自动外呼
  269. // inComingType = 3; // 分机外呼
  270. // }
  271. // std::string data = m_pParent->creatJsonIncoming(CallID, Number, callee, TrunkNumber, inComingType);
  272. // m_pParent->send2Agent(ExtenNo, data); // 发送来电事件到坐席
  273. //}
  274. }
  275. void Session::__notifyDbSaveChanEvent(VirtualChan * pChanHost, PCHAN_EVENT_NOTIFY pNotify)
  276. {
  277. if (pNotify == nullptr || pChanHost == nullptr) return;
  278. // 自动外呼不用该方法保存数据库
  279. if (pNotify->CallType != 0)
  280. {
  281. __saveAutoCallDB(pChanHost,pNotify);
  282. return;
  283. }
  284. if (pChanHost->isInMeeting()&& pNotify->EventId == CHANNEL_EVENT_HANGUP_COMPLETE) // 会议,
  285. {
  286. Format fmt("update conference set end_time = '%s' where uuid = '%s'");
  287. fmt %Util::CurTime() % pChanHost->sessionId();
  288. SqlWrite::GetInstance()->addSql(fmt.str());
  289. }
  290. if (!pChanHost->opNumber().empty()) // 强插等操作会有操作码
  291. {
  292. return;
  293. }
  294. if (pNotify->EventId == CHANNEL_EVENT_CREATE && pChanHost->type() == DEV_RES_TYPE_EXT && pChanHost == __getFirstChan()) // 分机为主叫时数据库新添加一条记录
  295. {
  296. std::string curTime = Util::CurTime();
  297. std::string callid = pNotify->CcId.empty() == true ? pNotify->CallId : pNotify->CcId;
  298. std::string agent = m_pParent->getAgentByExten(pNotify->Caller);
  299. Format fmt("insert into cdr(uuid,caller_agent,caller,call_type,create_time,action_id) values('%s','%s','%s',%d,'%s',%d)"); // 分机呼叫 call_type=1
  300. fmt %callid %agent % pNotify->Caller % 1 % curTime % 1;
  301. SqlWrite::GetInstance()->addSql(fmt.str());
  302. }
  303. else if (pNotify->EventId == CHANNEL_EVENT_CREATE && pChanHost != __getFirstChan()) // b腿创建
  304. {
  305. m_AtionId++;
  306. m_RingTime.clear();
  307. m_AnswerTime.clear();
  308. m_IsSaveDb = true;
  309. if (m_AtionId >1 )
  310. {
  311. auto pChan = __getFirstChan();
  312. if (pChan != nullptr)
  313. {
  314. int call_type = 0;
  315. if (pChan->type() == DEV_RES_TYPE_EXT)
  316. {
  317. call_type = 1;
  318. }
  319. std::string curTime = Util::CurTime();
  320. std::string callid = pNotify->CcId.empty() == true ? pNotify->CallId : pNotify->CcId;
  321. std::string agent = m_pParent->getAgentByExten(pNotify->Caller);
  322. Format fmt("insert into cdr(uuid,caller_agent,caller,call_type,create_time,action_id) values('%s','%s','%s',%d,'%s',%d)"); // 分机呼叫 call_type=1
  323. fmt %callid %agent % pNotify->Caller % call_type % curTime % m_AtionId;
  324. SqlWrite::GetInstance()->addSql(fmt.str());
  325. }
  326. }
  327. }
  328. else if ((pNotify->EventId == CHANNEL_EVENT_PROGRESS || pNotify->EventId == CHANNEL_EVENT_PROGRESS_MEDIA) && pChanHost != __getFirstChan()) // 呼出振铃
  329. {
  330. if (m_RingTime.empty())
  331. m_RingTime = Util::CurTime();
  332. }
  333. else if (pNotify->EventId == CHANNEL_EVENT_ANSWER && pChanHost != __getFirstChan())
  334. {
  335. m_AnswerTime = Util::CurTime();
  336. m_IsAnswer = true;
  337. }
  338. if (pNotify->EventId == CHANNEL_EVENT_HANGUP_COMPLETE && m_IsSaveDb ) // 收到挂机事件,且第一次更新数据库(update)
  339. {
  340. std::string curTime = Util::CurTime();
  341. std::string agent;
  342. std::string callee; // 被叫
  343. std::string group; // 坐席组
  344. if (pChanHost->type() == DEV_RES_TYPE_TRUNK && pChanHost == __getFirstChan()) // 中继呼入且先挂机
  345. {
  346. auto pAssoChan = getAssoChan(pChanHost); // 根据对端线路获取被叫
  347. if (pAssoChan != nullptr)
  348. {
  349. callee = pAssoChan->calleeNum();
  350. }
  351. }
  352. else
  353. {
  354. if (pChanHost->isInMeeting()) // 会议时
  355. callee = pNotify->Caller;
  356. else
  357. callee = pNotify->Callee;
  358. }
  359. agent = m_pParent->getAgentByExten(callee,group);
  360. auto fun = [](std::string time)->std::string { if (time.empty()) return "null"; else return "'" + time + "'"; }; // 匿名函数用于转化时间
  361. m_RingTime = fun(m_RingTime);
  362. m_AnswerTime = fun(m_AnswerTime);
  363. if (m_AtionId == 0)
  364. m_AtionId = 1;
  365. // 增加被叫坐席组
  366. Format fmt("update cdr set group_no = '%s',callee_agent = '%s',callee = '%s', ring_time = %s,answer_time = %s,is_answer = %d,end_time = '%s',record_path = '%s', hangup_cause = '%s' where uuid = '%s' and action_id = %d");
  367. fmt %group %agent %callee % m_RingTime %m_AnswerTime %m_IsAnswer %curTime %m_RecordFile %pNotify->HangupCause %pChanHost->sessionId() % m_AtionId;
  368. SqlWrite::GetInstance()->addSql(fmt.str());
  369. // 清空
  370. m_RingTime.clear();
  371. m_AnswerTime.clear();
  372. m_IsAnswer = false;
  373. m_IsSaveDb = false;
  374. }
  375. if (pNotify->EventId == CHANNEL_EVENT_HANGUP_COMPLETE && pChanHost->type() == DEV_RES_TYPE_TRUNK)
  376. {
  377. std::string curTime = Util::CurTime();
  378. Format fmt("update cdr set hangup_time = '%s' where uuid = '%s'");
  379. fmt %curTime %pChanHost->sessionId();
  380. SqlWrite::GetInstance()->addSql(fmt.str());
  381. }
  382. }
  383. void Session::__saveAutoCallDB(VirtualChan * pChanHost, PCHAN_EVENT_NOTIFY pNotify)
  384. {
  385. if (pNotify->EventId == CHANNEL_EVENT_CREATE && pChanHost == __getFirstChan()) // 分机为主叫时数据库新添加一条记录
  386. {
  387. std::string curTime = Util::CurTime();
  388. std::string callid = pNotify->CcId.empty() == true ? pNotify->CallId : pNotify->CcId;
  389. std::string sql;
  390. if (pNotify->CallType == VOICE_CALL)
  391. {
  392. Format fmt("insert into auto_cdr(uuid,caller,create_time,task_id) values('%s','%s','%s',%ld)"); // 语音呼叫 call_type=1
  393. fmt %callid % pNotify->Caller % curTime %pNotify->TaskId;
  394. sql = fmt.str();
  395. }
  396. else
  397. {
  398. std::string agent = m_pParent->getAgentByExten(pNotify->Caller);
  399. Format fmt("insert into auto_cdr(uuid,agent,caller,create_time,task_id) values('%s','%s','%s','%s',%ld)"); // 分机呼叫 call_type=2
  400. fmt %callid %agent %pNotify->Callee %curTime %pNotify->TaskId;
  401. //Format fmt("insert into auto_cdr(uuid,caller,create_time,task_id) values('%s','%s','%s',%ld)"); // 分机呼叫 call_type=2
  402. //fmt %callid % pNotify->Callee % curTime %pNotify->TaskId;
  403. sql = fmt.str();
  404. }
  405. SqlWrite::GetInstance()->addSql(sql);
  406. }
  407. else if ((pNotify->EventId == CHANNEL_EVENT_PROGRESS || pNotify->EventId == CHANNEL_EVENT_PROGRESS_MEDIA) && (pChanHost != __getFirstChan() || pNotify->CallType == VOICE_CALL)) // 呼出振铃
  408. {
  409. if (m_RingTime.empty())
  410. m_RingTime = Util::CurTime();
  411. }
  412. else if (pNotify->EventId == CHANNEL_EVENT_ANSWER && (pChanHost != __getFirstChan() || pNotify->CallType == VOICE_CALL))
  413. {
  414. m_AnswerTime = Util::CurTime();
  415. }
  416. else if (pNotify->EventId == CHANNEL_EVENT_HANGUP_COMPLETE && m_IsSaveDb) // 收到挂机事件,且第一次更新数据库(update)
  417. {
  418. std::string curTime = Util::CurTime();
  419. auto fun = [](std::string time)->std::string { if (time.empty()) return "null"; else return "'" + time + "'"; }; // 匿名函数用于转化时间
  420. m_RingTime = fun(m_RingTime);
  421. m_AnswerTime = fun(m_AnswerTime);
  422. Format fmt("update auto_cdr set callee = '%s', ring_time = %s,answer_time = %s,end_time = '%s',record_path = '%s', hangup_cause = '%s' where uuid = '%s'");
  423. if (pNotify->CallType == VOICE_CALL) // 语音外呼被叫 接通挂机时取 caller
  424. fmt %pNotify->Caller % m_RingTime %m_AnswerTime %curTime %m_RecordFile %pNotify->HangupCause %pChanHost->sessionId();
  425. else
  426. fmt %pNotify->Callee % m_RingTime %m_AnswerTime %curTime %m_RecordFile %pNotify->HangupCause %pChanHost->sessionId();
  427. SqlWrite::GetInstance()->addSql(fmt.str());
  428. // 清空
  429. m_RingTime.clear();
  430. m_AnswerTime.clear();
  431. m_IsSaveDb = false;
  432. }
  433. }
  434. void Session::__onChanFree(VirtualChan * pChan, PCHAN_EVENT_NOTIFY pNotify)
  435. {
  436. //if (m_Id == pNotify->ChanId) // 若会话主通道空闲则清空会话
  437. // __clearChan();
  438. //else
  439. // __delChan(pChan);
  440. __delChan(pChan); // 防止重复收到挂机事件覆盖之前的有效数据
  441. if (pChan->isVoid()) // 若通道已被丢弃,则删除
  442. m_pParent->delChan(pChan);
  443. }
  444. void Session::__onPlayAgentNo(VirtualChan * pChan, PCHAN_EVENT_NOTIFY pNotify)
  445. {
  446. if (pChan == nullptr)
  447. {
  448. LOG_ERROR_S("通道pChan已被释放!!!");
  449. return;
  450. }
  451. if(pNotify == nullptr)
  452. {
  453. LOG_ERROR_S("通道事件pNotify已被释放!!!");
  454. return;
  455. }
  456. // 事件为接听,通道为分机,线路数为2, 对端为外线,进行播报工号
  457. if (pNotify->EventId != CHANNEL_EVENT_ANSWER || pChan->isInMeeting() || m_ListChan.size() != 2)
  458. {
  459. //LOG_DEBUG("调用播报工号 %d %d %d ", pNotify->EventId, pChan->isInMeeting(), m_ListChan.size());
  460. return;
  461. }
  462. VirtualChan* pFirstChan = __getFirstChan();
  463. if (pFirstChan != nullptr && pFirstChan->type() == DEV_RES_TYPE_TRUNK && pChan->type() == DEV_RES_TYPE_EXT)
  464. {
  465. m_pParent->playAgentNo(pChan);
  466. }
  467. }
  468. void Session::__onRecord(VirtualChan * pChan, PCHAN_EVENT_NOTIFY pNotify)
  469. {
  470. /*
  471. if (pChan == __getFirstChan() && pNotify->EventId == CHANNEL_EVENT_ANSWER)
  472. {
  473. std::string Number;
  474. Number = pNotify->Caller;
  475. // 判断是否需要录音
  476. std::string sql = boost::str(Format("select id from record where caller = '%s'") % Number);
  477. JdbcHelper::GetInstance()->jdbc_executeQuery(sql, [=](sql::PreparedStatement* stmt) {
  478. }, [=](sql::ResultSet* result) {
  479. if (!result->next()) // 数据库查不到记录,进行录音
  480. {
  481. LOG_DEBUG("操作标识:%ld", pNotify->ChanOpInstance);
  482. //if (pNotify->ChanOpInstance == 0) // 会议不进行再次录音
  483. if(CConfig::GetInstance()->isAutoRecord())
  484. COperationReactor::GetInstance()->procOperation(-1, LINE_OP_RECORD, pChan->no(), nullptr); // 执行录音
  485. }
  486. }, NULL);
  487. }
  488. */
  489. // 保持状态过滤
  490. auto Status = (HELD_STATE_FILTER_MASK & pChan->state());
  491. // 通话
  492. if (Status == TRUNK_STATE_TALKING || Status == INNER_STATE_TALKING)
  493. {
  494. for (auto pTempChan : m_ListChan)
  495. {
  496. if (pTempChan == NULL || pTempChan == pChan)
  497. continue;
  498. auto nTempStatus = (HELD_STATE_FILTER_MASK & pTempChan->state());
  499. if (nTempStatus == TRUNK_STATE_TALKING || nTempStatus == INNER_STATE_TALKING)
  500. {
  501. __onLineTalking(pChan);
  502. __onLineTalking(pTempChan);
  503. break;
  504. }
  505. }
  506. }
  507. }
  508. void Session::__createFileName(VirtualChan * pChan)
  509. {
  510. if (m_RecordFile.empty() || m_RecordFile == "")
  511. {
  512. std::string strCurTime = Util::CurTime();
  513. strCurTime = std::regex_replace(strCurTime, std::regex("-|:"), "");
  514. auto index = strCurTime.find(" ");
  515. std::string data = strCurTime.substr(0, index);
  516. std::string time = strCurTime.substr(index+1);
  517. std::string strTempCallID = regex_replace(m_Id, std::regex("-"), "");
  518. strTempCallID = time + "_" + strTempCallID;
  519. m_RecordFile = CConfig::GetInstance()->recordPath() + "/" + data + "/";
  520. // 判断文件夹是否存在
  521. boost::filesystem::path p(m_RecordFile);
  522. if (!boost::filesystem::exists(p))
  523. {
  524. boost::filesystem::create_directories(p);
  525. }
  526. std::stringstream ss;
  527. ss << m_RecordFile << pChan->no() << "/" << strTempCallID << ".wav";
  528. m_RecordFile = ss.str();
  529. }
  530. }
  531. void Session::__onLineTalking(VirtualChan * pChan)
  532. {
  533. // 如果是监听 不再产生录音文件文件路径
  534. //if (pChan->currOp() == PDU_CMD_AGENT_MONI_LISTEN) return;
  535. // 对该线路进行录音处理
  536. if (pChan == NULL) return;
  537. if (pChan->type() != DEV_RES_TYPE_EXT) return;
  538. if (pChan->recordFile() != "") return ;
  539. if (m_RecordFile.empty() || m_RecordFile == "")
  540. {
  541. __createFileName(pChan);
  542. LineOpParam LineOpInfo;
  543. memset(&LineOpInfo, 0, sizeof(LineOpInfo));
  544. LineOpInfo.szParam3 = m_RecordFile;
  545. //COperationReactor::GetInstance()->procOperation(-1, LINE_OP_RECORD, pChan->no(), &LineOpInfo); // 执行录音
  546. pChan->setRecordFile(m_RecordFile);
  547. for (auto pTempChan : m_ListChan)
  548. {
  549. if (pTempChan != NULL && pTempChan->type() != pChan->type() && pTempChan->recordFile() == "")
  550. pTempChan->setRecordFile(m_RecordFile);
  551. }
  552. }
  553. else
  554. {
  555. pChan->setRecordFile(m_RecordFile);
  556. }
  557. }