1 /*******************************************************************************
2
3 KHOMP generic endpoint/channel library.
4 Copyright (C) 2007-2010 Khomp Ind. & Com.
5
6 The contents of this file are subject to the Mozilla Public License
7 Version 1.1 (the "License"); you may not use this file except in compliance
8 with the License. You may obtain a copy of the License at
9 http://www.mozilla.org/MPL/
10
11 Software distributed under the License is distributed on an "AS IS" basis,
12 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
13 the specific language governing rights and limitations under the License.
14
15 Alternatively, the contents of this file may be used under the terms of the
16 "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
17 case the provisions of "LGPL License" are applicable instead of those above.
18
19 If you wish to allow use of your version of this file only under the terms of
20 the LGPL License and not to allow others to use your version of this file
21 under the MPL, indicate your decision by deleting the provisions above and
22 replace them with the notice and other provisions required by the LGPL
23 License. If you do not delete the provisions above, a recipient may use your
24 version of this file under either the MPL or the LGPL License.
25
26 The LGPL header follows below:
27
28 This library is free software; you can redistribute it and/or
29 modify it under the terms of the GNU Lesser General Public
30 License as published by the Free Software Foundation; either
31 version 2.1 of the License, or (at your option) any later version.
32
33 This library is distributed in the hope that it will be useful,
34 but WITHOUT ANY WARRANTY; without even the implied warranty of
35 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36 Lesser General Public License for more details.
37
38 You should have received a copy of the GNU Lesser General Public License
39 along with this library; if not, write to the Free Software Foundation,
40 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
41
42 *******************************************************************************/
43
44 #include "khomp_pvt.h"
45 #include "lock.h"
46 #include "khomp_pvt_kxe1.h"
47 #include "khomp_pvt_gsm.h"
48 #include "khomp_pvt_fxo.h"
49 #include "khomp_pvt_passive.h"
50 #include "utils.h"
51
52 Board::VectorBoard Board::_boards;
53 char Board::_cng_buffer[Globals::cng_buffer_size];
54 Kommuter Board::kommuter;
55
56
KhompPvt(K3LAPIBase::GenericTarget & target)57 Board::KhompPvt::KhompPvt(K3LAPIBase::GenericTarget & target) :
58 _target(target),
59 _mutex(Globals::module_pool),
60 _session(NULL),
61 _caller_profile(NULL),
62 _reader_frames(&_read_codec),
63 _writer_frames(&_write_codec)
64 {
65 _read_codec.implementation = NULL;
66 _write_codec.implementation = NULL;
67
68 _pvt_statistics = new PvtStatistics(this);
69
70 _mohclass = Opt::_options._global_mohclass();
71 _language = Opt::_options._global_language();
72 _accountcode = Opt::_options._accountcode();
73 }
74
initializeK3L(void)75 bool Board::initializeK3L(void)
76 {
77 LOG(MESSAGE, "starting K3L API ...");
78
79 /* Start the API and connect to KServer */
80 k3lSetGlobalParam (klpResetFwOnStartup, 1);
81 k3lSetGlobalParam (klpDisableInternalVoIP, 1);
82
83 try
84 {
85 Globals::k3lapi.start();
86 }
87 catch (K3LAPI::start_failed & e)
88 {
89 LOG(ERROR,FMT("loading K3L API failed: %s") % e.what());
90 return false;
91 }
92
93 LOG(MESSAGE, "the K3L API have been started!");
94
95 return true;
96 }
97
finalizeK3L(void)98 bool Board::finalizeK3L(void)
99 {
100 /* Stop the API and disconnect to KServer */
101 try
102 {
103 Globals::k3lapi.stop();
104 }
105 catch(...)
106 {
107 LOG(ERROR, "K3L not stopped");
108 return false;
109 }
110 LOG(MESSAGE, "K3L stopped..");
111 return true;
112 }
113
initializeHandlers(void)114 bool Board::initializeHandlers(void)
115 {
116 Globals::global_timer = new Globals::GlobalTimer;
117 Globals::global_timer->start();
118
119 if (Globals::k3lapi.device_count() == 0)
120 return false;
121
122 for (VectorBoard::iterator it_dev = _boards.begin();
123 it_dev != _boards.end();
124 it_dev++)
125 {
126 Board * device = *it_dev;
127 device->_event_handler = new ChanEventHandler(device->id(), &eventThread);
128 device->_command_handler = new ChanCommandHandler(device->id(), &commandThread);
129
130 device->_timers.start();
131 }
132
133 k3lRegisterEventHandler( khompEventCallback );
134 k3lRegisterAudioListener( NULL, khompAudioListener );
135
136 LOG(MESSAGE, "K3l event and audio handlers registered.");
137
138 return true;
139 }
140
finalizeHandlers(void)141 bool Board::finalizeHandlers(void)
142 {
143 /* if timer still ticks, stop him */
144 if(Globals::global_timer != NULL)
145 {
146 Globals::global_timer->stop();
147 delete Globals::global_timer;
148 Globals::global_timer = NULL;
149 }
150
151 if (Globals::k3lapi.device_count() == 0)
152 return false;
153
154 k3lRegisterEventHandler( NULL );
155 k3lRegisterAudioListener( NULL, NULL );
156
157
158 for (VectorBoard::iterator it_dev = _boards.begin();
159 it_dev != _boards.end();
160 it_dev++)
161 {
162 Board * device = *it_dev;
163 // stop event handler for device
164 ChanEventHandler * evt_handler = device->_event_handler;
165 evt_handler->fifo()->_shutdown = true;
166 evt_handler->signal();
167 delete evt_handler;
168 device->_event_handler = NULL;
169 // stop command handler for device
170 ChanCommandHandler * cmd_handler = device->_command_handler;
171 cmd_handler->fifo()->_shutdown = true;
172 cmd_handler->signal();
173 delete cmd_handler;
174 device->_command_handler = NULL;
175 // stop timer
176 device->_timers.stop();
177 }
178
179 /* wait every thread to finalize */
180 sleep(1);
181
182 LOG(MESSAGE, "K3l event and audio handlers unregistered.");
183
184 return true;
185
186 }
187
initializeBoards(void)188 void Board::initializeBoards(void)
189 {
190
191 for (unsigned dev = 0; dev < Globals::k3lapi.device_count(); dev++)
192 {
193 LOG(MESSAGE,FMT("loading device %d..." ) % dev);
194
195 switch(Globals::k3lapi.device_type(dev))
196 {
197 case kdtE1:
198 case kdtE1Spx:
199 case kdtE1GW:
200 case kdtE1IP:
201 case kdtE1FXSSpx:
202 case kdtFXS:
203 case kdtFXSSpx:
204 _boards.push_back(new BoardE1(dev));
205 break;
206 case kdtGSM:
207 case kdtGSMSpx:
208 case kdtGSMUSB:
209 case kdtGSMUSBSpx:
210 _boards.push_back(new BoardGSM(dev));
211 break;
212 case kdtFXO:
213 case kdtFXOVoIP:
214 switch(Globals::k3lapi.device_config(dev).DeviceModel)
215 {
216 case kdmFXO80:
217 _boards.push_back(new BoardFXO(dev));
218 break;
219 default:
220 _boards.push_back(new BoardPassive(dev));
221 break;
222 }
223 break;
224 case kdtPR:
225 _boards.push_back(new BoardPassive(dev));
226 break;
227 default:
228 _boards.push_back(new Board(dev));
229 LOG(ERROR,FMT("device type %d unknown" ) % Globals::k3lapi.device_type(dev));
230 break;
231 }
232
233 _boards.back()->initializeChannels();
234 }
235 }
236
initializeChannels(void)237 void Board::initializeChannels(void)
238 {
239 LOG(MESSAGE, "loading channels ...");
240
241 for (unsigned obj = 0; obj < Globals::k3lapi.channel_count(_device_id); obj++)
242 {
243 K3LAPIBase::GenericTarget tgt(Globals::k3lapi, K3LAPIBase::GenericTarget::CHANNEL, _device_id, obj);
244
245 KhompPvt * pvt;
246
247 switch(Globals::k3lapi.channel_config(_device_id, obj).Signaling)
248 {
249 case ksigInactive:
250 default:
251 pvt = new Board::KhompPvt(tgt);
252 pvt->_call = new Board::KhompPvt::Call();
253 DBG(FUNC, FMT("signaling %d unknown") % Globals::k3lapi.channel_config(_device_id, obj).Signaling);
254 break;
255 }
256
257 _channels.push_back(pvt);
258
259 pvt->cleanup();
260 }
261 }
262
finalizeBoards(void)263 void Board::finalizeBoards(void)
264 {
265 LOG(MESSAGE, "finalizing boards ...");
266
267 for (VectorBoard::iterator it_dev = _boards.begin();
268 it_dev != _boards.end();
269 it_dev++)
270 {
271 Board * & device_ref = *it_dev;
272 Board * device_ptr = device_ref;
273
274 device_ptr->finalizeChannels();
275
276 device_ref = (Board *) NULL;
277
278 delete device_ptr;
279 }
280
281 }
282
finalizeChannels()283 void Board::finalizeChannels()
284 {
285 LOG(MESSAGE, "finalizing channels ...");
286 for (VectorChannel::iterator it_obj = _channels.begin();
287 it_obj != _channels.end();
288 it_obj++)
289 {
290 KhompPvt * & pvt_ref = *it_obj;
291 KhompPvt * pvt_ptr = pvt_ref;
292
293 if(!pvt_ptr)
294 continue;
295
296 try
297 {
298 ScopedPvtLock lock(pvt_ptr);
299
300 if(pvt_ptr->session())
301 {
302 //TODO: Tratamento para desconectar do canal do FreeSwitch.
303 pvt_ptr->cleanup();
304 }
305
306 delete pvt_ptr->_call;
307 pvt_ptr->_call = NULL;
308
309 pvt_ref = (KhompPvt *) NULL;
310 }
311 catch(...)
312 {
313 /* keep walking! */
314 }
315
316 delete pvt_ptr;
317 }
318 }
319
initializeCngBuffer(void)320 void Board::initializeCngBuffer(void)
321 {
322 bool turn = true;
323
324 for (unsigned int i = 0; i < Globals::cng_buffer_size; i++)
325 {
326 _cng_buffer[i] = (turn ? 0xD5 : 0xD4);
327 turn = !turn;
328 }
329 }
330
initialize(void)331 bool Board::initialize(void)
332 {
333 initializeCngBuffer();
334
335 try
336 {
337 initializeBoards();
338 }
339 catch(K3LAPITraits::invalid_device & err)
340 {
341 LOG(ERROR, FMT("Invalid device at initialize boards: %s") % err.what());
342 return false;
343 }
344 catch(K3LAPITraits::invalid_channel & err)
345 {
346 LOG(ERROR, FMT("Invalid channel at initialize boards: %s") % err.what());
347 return false;
348 }
349 catch(K3LAPITraits::invalid_link & err)
350 {
351 LOG(ERROR, FMT("Invalid link at initialize boards: %s") % err.what());
352 return false;
353 }
354
355 return true;
356 }
357
finalize(void)358 bool Board::finalize(void)
359 {
360 finalizeBoards();
361
362 return finalizeK3L();
363 }
364
khomp_add_event_board_data(const K3LAPIBase::GenericTarget target,switch_event_t * event)365 void Board::khomp_add_event_board_data(const K3LAPIBase::GenericTarget target, switch_event_t *event)
366 {
367
368 //if (!event) {
369 //TODO: RAISE!
370 //}
371
372 try
373 {
374 if (target.type == K3LAPIBase::GenericTarget::CHANNEL)
375 {
376 switch_core_session_t * s = get(target.device, target.object)->session();
377 switch_channel_event_set_data(Board::KhompPvt::getFSChannel(s), event);
378 }
379
380 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Khomp-DeviceId", "%u", target.device);
381 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Khomp-Object", "%u", target.object);
382 }
383 catch(K3LAPITraits::invalid_channel & err)
384 {
385 LOG(ERROR, PVT_FMT(target, "Invalid channel"));
386 }
387 catch(Board::KhompPvt::InvalidSwitchChannel & err)
388 {
389 LOG(ERROR, PVT_FMT(target, "No valid channel: %s") % err._msg.c_str());
390 }
391 }
392
getStatistics(Statistics::Type type)393 std::string Board::KhompPvt::getStatistics(Statistics::Type type)
394 {
395 switch(type)
396 {
397 case Statistics::DETAILED:
398 {
399 return _pvt_statistics->getDetailed();
400 }
401 case Statistics::ROW:
402 {
403 return _pvt_statistics->getRow();
404 }
405 default:
406 return "";
407 }
408 }
409
getStatisticsXML(Statistics::Type type)410 switch_xml_t Board::KhompPvt::getStatisticsXML(Statistics::Type type)
411 {
412 switch(type)
413 {
414 case Statistics::DETAILED:
415 {
416 return _pvt_statistics->getDetailedXML();
417 }
418 case Statistics::ROW:
419 {
420 return _pvt_statistics->getNode();
421 }
422 default:
423 return NULL;
424 }
425 }
426
getDetailedRates()427 std::string Board::KhompPvt::PvtStatistics::getDetailedRates()
428 {
429 /* skip inactive channels */
430 //if (_pvt->getSignaling() == ksigInactive) return "";
431
432 /* buffer our data to return at the end */
433 std::string strBuffer;
434
435 /* this values come from kserver */
436 unsigned int call_incoming = Globals::k3lapi.channel_stats(
437 _pvt->target().device, _pvt->target().object, kcsiInbound);
438 unsigned int call_outgoing = Globals::k3lapi.channel_stats(
439 _pvt->target().device, _pvt->target().object, kcsiOutbound);
440
441 float occupation_rate = 100.0;
442
443 if (_pvt->call()->statistics()->_total_idle_time > 0)
444 {
445 occupation_rate = 100 * (
446 _pvt->call()->statistics()->_total_time_incoming +
447 _pvt->call()->statistics()->_total_time_outgoing
448 ) / (
449 _pvt->call()->statistics()->_total_idle_time +
450 _pvt->call()->statistics()->_total_time_incoming +
451 _pvt->call()->statistics()->_total_time_outgoing);
452 }
453
454 strBuffer.append(STG(FMT("Occupation rate: \t\t%0.2f%%\n") % occupation_rate));
455
456 if (call_incoming > 0)
457 {
458 std::string str_calls_incoming_mean = timeToString ( (time_t) (_pvt->call()->statistics()->_total_time_incoming / call_incoming) );
459 strBuffer.append(STG(FMT("Mean duration time of incoming calls: %s\n") % str_calls_incoming_mean));
460 }
461
462 if (call_outgoing > 0)
463 {
464 std::string str_calls_outgoing_mean = timeToString ( (time_t) (_pvt->call()->statistics()->_total_time_outgoing / call_outgoing) );
465 strBuffer.append(STG(FMT("Mean duration time of outgoing calls: %s\n") % str_calls_outgoing_mean));
466 }
467
468 return strBuffer;
469 }
470
getDetailedRatesXML()471 switch_xml_t Board::KhompPvt::PvtStatistics::getDetailedRatesXML()
472 {
473 switch_xml_t xrates = switch_xml_new("rates");
474
475 /* this values come from kserver */
476 unsigned int call_incoming = Globals::k3lapi.channel_stats(
477 _pvt->target().device, _pvt->target().object, kcsiInbound);
478 unsigned int call_outgoing = Globals::k3lapi.channel_stats(
479 _pvt->target().device, _pvt->target().object, kcsiOutbound);
480
481 float occupation_rate = 100.0;
482
483 if (_pvt->call()->statistics()->_total_idle_time > 0)
484 {
485 occupation_rate = 100 * (
486 _pvt->call()->statistics()->_total_time_incoming +
487 _pvt->call()->statistics()->_total_time_outgoing
488 ) / (
489 _pvt->call()->statistics()->_total_idle_time +
490 _pvt->call()->statistics()->_total_time_incoming +
491 _pvt->call()->statistics()->_total_time_outgoing);
492 }
493
494 switch_xml_t xoccupation = switch_xml_add_child_d(xrates,"oucpation",0);
495 switch_xml_set_txt_d(xoccupation,STR(FMT("%d") % occupation_rate));
496
497 if (call_incoming > 0)
498 {
499 std::string str_calls_incoming_mean = timeToString ( (time_t) (_pvt->call()->statistics()->_total_time_incoming / call_incoming) );
500 switch_xml_t xmean_in = switch_xml_add_child_d(xrates,"incoming",0);
501 switch_xml_set_txt_d(xmean_in,str_calls_incoming_mean.c_str());
502 }
503
504 if (call_outgoing > 0)
505 {
506 std::string str_calls_outgoing_mean = timeToString ( (time_t) (_pvt->call()->statistics()->_total_time_outgoing / call_outgoing) );
507 switch_xml_t xmean_out = switch_xml_add_child_d(xrates,"outgoing",0);
508 switch_xml_set_txt_d(xmean_out,str_calls_outgoing_mean.c_str());
509 }
510
511 return xrates;
512 }
513
getDetailed()514 std::string Board::KhompPvt::PvtStatistics::getDetailed()
515 {
516 /* skip inactive channels */
517 //if (_pvt->getSignaling() == ksigInactive) return "";
518
519 /* buffer our data to return at the end */
520 std::string strBuffer;
521
522 strBuffer.append(_pvt->call()->statistics()->getDetailed());
523
524 /* this values come from kserver */
525 unsigned int call_incoming = Globals::k3lapi.channel_stats(
526 _pvt->target().device, _pvt->target().object, kcsiInbound);
527 unsigned int call_outgoing = Globals::k3lapi.channel_stats(
528 _pvt->target().device, _pvt->target().object, kcsiOutbound);
529 unsigned int call_fails = Globals::k3lapi.channel_stats(
530 _pvt->target().device, _pvt->target().object, kcsiOutFailed);
531
532 strBuffer.append(STG(FMT("Number of incoming calls: \t%d\n") % call_incoming));
533 strBuffer.append(STG(FMT("Number of outgoing calls: \t%d\n") % call_outgoing));
534 strBuffer.append(STG(FMT("Number of calls failed: \t%d\n") % call_fails));
535
536 strBuffer.append(getDetailedRates());
537
538 return strBuffer;
539 }
540
541
getDetailedXML()542 switch_xml_t Board::KhompPvt::PvtStatistics::getDetailedXML()
543 {
544 switch_xml_t xch = _pvt->call()->statistics()->getDetailedXML();
545
546 /* this values come from kserver */
547 unsigned int call_incoming = Globals::k3lapi.channel_stats(
548 _pvt->target().device, _pvt->target().object, kcsiInbound);
549 unsigned int call_outgoing = Globals::k3lapi.channel_stats(
550 _pvt->target().device, _pvt->target().object, kcsiOutbound);
551 unsigned int call_fails = Globals::k3lapi.channel_stats(
552 _pvt->target().device, _pvt->target().object, kcsiOutFailed);
553
554 /* total/call_incoming */
555 switch_xml_t xin_calls = switch_xml_add_child_d(xch,"calls_incoming",0);
556 switch_xml_set_txt_d(xin_calls,STR(FMT("%d") % call_incoming));
557
558 /* total/call_outgoing */
559 switch_xml_t xout_calls = switch_xml_add_child_d(xch,"calls_outgoing",0);
560 switch_xml_set_txt_d(xout_calls,STR(FMT("%d") % call_outgoing));
561
562 /* total/calls_failed */
563 switch_xml_t xfailed_calls = switch_xml_add_child_d(xch,"calls_failed",0);
564 switch_xml_set_txt_d(xfailed_calls,STR(FMT("%d") % call_fails));
565
566 return xch;
567 }
568
getRow()569 std::string Board::KhompPvt::PvtStatistics::getRow()
570 {
571 /* skip inactive channels */
572 //if (_pvt->getSignaling() == ksigInactive) return "";
573
574 time_t action_time;
575 time (&action_time);
576
577 action_time -= _pvt->call()->statistics()->_base_time;
578
579 uint32 calls_incoming = Globals::k3lapi.channel_stats(
580 _pvt->target().device, _pvt->target().object, kcsiInbound);
581 uint32 calls_outgoing = Globals::k3lapi.channel_stats(
582 _pvt->target().device, _pvt->target().object, kcsiOutbound);
583 uint32 call_fails = Globals::k3lapi.channel_stats(
584 _pvt->target().device, _pvt->target().object, kcsiOutFailed);
585
586 std::string string_time = " n/a ";
587 std::string call_type = " none ";
588
589 if (_pvt->call()->_flags.check(Kflags::IS_INCOMING))
590 call_type = "incoming";
591 else if (_pvt->call()->_flags.check(Kflags::IS_OUTGOING))
592 call_type = "outgoing";
593
594 if (_pvt->owner())
595 {
596 string_time = timeToString(action_time);
597 }
598
599 return STG(FMT("| %d,%02d | %8d | %8d | %8d | %7d | %10s | %8s | %8s |")
600 % _pvt->target().device
601 % _pvt->target().object
602 % calls_incoming
603 % calls_outgoing
604 % _pvt->call()->statistics()->_channel_fails
605 % call_fails
606 % _pvt->getStateString()
607 % call_type
608 % string_time);
609 }
610
getNode()611 switch_xml_t Board::KhompPvt::PvtStatistics::getNode()
612 {
613 time_t action_time;
614 time (&action_time);
615
616 action_time -= _pvt->call()->statistics()->_base_time;
617
618 uint32 calls_incoming = Globals::k3lapi.channel_stats(
619 _pvt->target().device, _pvt->target().object, kcsiInbound);
620 uint32 calls_outgoing = Globals::k3lapi.channel_stats(
621 _pvt->target().device, _pvt->target().object, kcsiOutbound);
622 uint32 call_fails = Globals::k3lapi.channel_stats(
623 _pvt->target().device, _pvt->target().object, kcsiOutFailed);
624
625 std::string string_time = " n/a ";
626 std::string call_type = " none ";
627
628 if (_pvt->call()->_flags.check(Kflags::IS_INCOMING))
629 call_type = "incoming";
630 else if (_pvt->call()->_flags.check(Kflags::IS_OUTGOING))
631 call_type = "outgoing";
632
633 if (_pvt->owner())
634 {
635 string_time = timeToString(action_time);
636 }
637
638 /* device/channel */
639 switch_xml_t xchn = switch_xml_new("channel");
640 switch_xml_set_attr_d(xchn,"id",STR(FMT("%d") % _pvt->target().object));
641
642 /* device/channel/details */
643 switch_xml_t xdetails = switch_xml_add_child_d(xchn,"details",0);
644
645 /* device/channel/details/calls_incomming */
646 switch_xml_t xin_calls = switch_xml_add_child_d(xdetails,"calls_incoming",0);
647 switch_xml_set_txt_d(xin_calls,STR(FMT("%d") % calls_incoming));
648
649 /* device/channel/details/calls_outgoing */
650 switch_xml_t xout_calls = switch_xml_add_child_d(xdetails,"calls_incoming",0);
651 switch_xml_set_txt_d(xout_calls,STR(FMT("%d") % calls_outgoing));
652
653 /* device/channel/details/channel_fails */
654 switch_xml_t xchn_fails = switch_xml_add_child_d(xdetails,"channel_fails",0);
655 switch_xml_set_txt_d(xchn_fails,STR(FMT("%d") % _pvt->call()->statistics()->_channel_fails));
656
657 /* device/channel/details/calls_fails */
658 switch_xml_t xcall_fails = switch_xml_add_child_d(xdetails,"calls_fails",0);
659 switch_xml_set_txt_d(xcall_fails,STR(FMT("%d") % call_fails));
660
661 /* device/channel/details/state */
662 switch_xml_t xstate = switch_xml_add_child_d(xdetails,"state",0);
663 switch_xml_set_txt_d(xstate,_pvt->getStateString().c_str());
664
665 /* device/channel/details/call_type */
666 switch_xml_t xcall_type = switch_xml_add_child_d(xdetails,"call_type",0);
667 switch_xml_set_txt_d(xcall_type,call_type.c_str());
668
669 /* device/channel/details/time */
670 switch_xml_t xtime = switch_xml_add_child_d(xdetails,"time",0);
671 switch_xml_set_txt_d(xtime,string_time.c_str());
672
673 return xchn;
674 }
675
justAlloc(bool is_answering,switch_memory_pool_t ** pool)676 switch_status_t Board::KhompPvt::justAlloc(bool is_answering, switch_memory_pool_t **pool)
677 {
678 DBG(FUNC, PVT_FMT(target(), "c"));
679
680 if(is_answering)
681 {
682 /* Create a new session on incoming call */
683 call()->_flags.set(Kflags::IS_INCOMING);
684 if(!session())
685 {
686 #if SWITCH_LESS_THAN(1,0,6)
687 session(switch_core_session_request(Globals::khomp_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL));
688 #else
689 session(switch_core_session_request(Globals::khomp_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL));
690 #endif
691 }
692 else
693 {
694 DBG(FUNC, PVT_FMT(target(), "Session already created"));
695 }
696 }
697 else
698 {
699 /* Create a new session on outgoing call */
700 call()->_flags.set(Kflags::IS_OUTGOING);
701 #if SWITCH_LESS_THAN(1,0,6)
702 session(switch_core_session_request(Globals::khomp_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, pool));
703 #else
704 session(switch_core_session_request(Globals::khomp_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, SOF_NONE, pool));
705 #endif
706 }
707
708 if(!session())
709 {
710 LOG(ERROR, PVT_FMT(target(), "r (Initilization Error, session not created!)"));
711 return SWITCH_STATUS_FALSE;
712 }
713
714 switch_core_session_add_stream(session(), NULL);
715
716 if (switch_core_codec_init(&_read_codec, "PCMA", NULL, NULL, 8000, Globals::switch_packet_duration, 1,
717 SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,
718 (pool ? *pool : NULL)) != SWITCH_STATUS_SUCCESS)
719 {
720 destroy();
721 LOG(ERROR, PVT_FMT(target(), "r (Error while init read codecs)"));
722 return SWITCH_STATUS_FALSE;
723 }
724
725 if (switch_core_codec_init(&_write_codec, "PCMA", NULL, NULL, 8000, Globals::switch_packet_duration, 1,
726 SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,
727 (pool ? *pool : NULL)) != SWITCH_STATUS_SUCCESS)
728 {
729 destroy();
730 LOG(ERROR, PVT_FMT(target(), "r (Error while init write codecs)"));
731 return SWITCH_STATUS_FALSE;
732 }
733
734 //TODO: Retirar daqui
735 // switch_mutex_init(&flag_mutex, SWITCH_MUTEX_NESTED,
736 // switch_core_session_get_pool(_session));
737
738 switch_core_session_set_private(_session, this);
739
740 if((switch_core_session_set_read_codec(_session, &_read_codec) !=
741 SWITCH_STATUS_SUCCESS) ||
742 (switch_core_session_set_write_codec(_session, &_write_codec) !=
743 SWITCH_STATUS_SUCCESS))
744 {
745 destroy();
746 LOG(ERROR, PVT_FMT(target(), "r (Error while set read codecs)"));
747 return SWITCH_STATUS_FALSE;
748 }
749
750 try
751 {
752 /* accounttcode for CDR identification */
753 setFSChannelVar(getFSChannel(),"accountcode",_accountcode.c_str());
754
755 /* language for IVR machine */
756 setFSChannelVar(getFSChannel(),"language",_language.c_str());
757 }
758 catch (Board::KhompPvt::InvalidSwitchChannel & err)
759 {
760 LOG(ERROR, PVT_FMT(target(), "(%s)") % err._msg.c_str() );
761 return SWITCH_STATUS_FALSE;
762 }
763
764 DBG(FUNC, PVT_FMT(target(), "r"));
765 return SWITCH_STATUS_SUCCESS;
766 }
767
justStart(switch_caller_profile_t * profile)768 switch_status_t Board::KhompPvt::justStart(switch_caller_profile_t *profile)
769 {
770 DBG(FUNC, PVT_FMT(target(), "c"));
771
772 try
773 {
774 switch_channel_t *channel = getFSChannel();
775
776 if(call()->_flags.check(Kflags::IS_INCOMING))
777 {
778 std::string exten("s");
779
780 owner(_session);
781
782 if(call()->_incoming_context.empty())
783 {
784 MatchExtension::ContextListType contexts;
785 std::string context("default");
786
787 if(!validContexts(contexts))
788 {
789 destroy();
790 owner(NULL);
791 LOG(ERROR, PVT_FMT(_target, "r (Invalid context)"));
792 return SWITCH_STATUS_FALSE;
793 }
794
795 switch(MatchExtension::findExtension(exten, context, contexts, _call->_dest_addr, _call->_orig_addr))
796 {
797 case MatchExtension::MATCH_NONE:
798 destroy();
799 owner(NULL);
800 LOG(ERROR, PVT_FMT(_target, "r (unable to find exten/context on incoming call %s/%s)")
801 % _call->_dest_addr % (contexts.size() >= 1 ? contexts[0] : "default"));
802 return SWITCH_STATUS_FALSE;
803 default:
804 DBG(FUNC, PVT_FMT(_target, "our: dialplan '%s', context '%s', exten '%s'") % Opt::_options._dialplan() % context % exten);
805 break;
806 }
807
808 call()->_incoming_context = context;
809 }
810 else
811 {
812 exten = call()->_dest_addr;
813 DBG(FUNC, PVT_FMT(target(), "already found our: dialplan '%s', context '%s', exten '%s'") % Opt::_options._dialplan() % call()->_incoming_context % exten);
814 }
815
816 _caller_profile = switch_caller_profile_new(switch_core_session_get_pool(_session),
817 "Khomp", //username
818 Opt::_options._dialplan().c_str(), //dialplan
819 NULL, //caller_id_name
820 _call->_orig_addr.c_str(), //caller_id_number
821 NULL, //network_addr
822 _call->_orig_addr.c_str(), //ani
823 NULL, //aniii
824 NULL, //rdnis
825 (char *) "mod_khomp", //source
826 call()->_incoming_context.c_str(), //context
827 exten.c_str()); //destination_number
828
829 if(!_caller_profile)
830 {
831 destroy();
832 owner(NULL);
833 LOG(ERROR, PVT_FMT(_target, "r (Cannot create caller profile)"));
834 return SWITCH_STATUS_FALSE;
835 }
836
837 std::string name = STG(FMT("Khomp/%d/%d/%s")
838 % target().device
839 % target().object
840 % _call->_dest_addr);
841
842 DBG(FUNC, PVT_FMT(target(), "Connect inbound channel %s") % name.c_str());
843
844 switch_channel_set_name(channel, name.c_str());
845 switch_channel_set_caller_profile(channel, _caller_profile);
846
847 switch_channel_set_state(channel, CS_INIT);
848
849 setSpecialVariables();
850
851 if (switch_core_session_thread_launch(_session) != SWITCH_STATUS_SUCCESS)
852 {
853 destroy();
854 owner(NULL);
855 LOG(ERROR, PVT_FMT(target(), "r (Error spawning thread)"));
856 return SWITCH_STATUS_FALSE;
857 }
858 }
859 else if(call()->_flags.check(Kflags::IS_OUTGOING))
860 {
861 if(_call->_orig_addr.empty())
862 _call->_orig_addr = profile->caller_id_number;
863
864 switch_channel_set_name(channel, STG(FMT("Khomp/%d/%d/%s")
865 % target().device
866 % target().object
867 % (!_call->_dest_addr.empty() ? _call->_dest_addr.c_str() : "")).c_str());
868 _caller_profile = switch_caller_profile_clone(_session, profile);
869 switch_channel_set_caller_profile(channel, _caller_profile);
870
871 switch_channel_set_state(channel, CS_INIT);
872 }
873 else
874 {
875 DBG(FUNC, PVT_FMT(target(), "r (Not INCOMING or OUTGOING)"));
876 return SWITCH_STATUS_FALSE;
877 }
878 }
879 catch(Board::KhompPvt::InvalidSwitchChannel & err)
880 {
881 destroy();
882 owner(NULL);
883 DBG(FUNC, PVT_FMT(target(), "r (%s)") % err._msg.c_str());
884 return SWITCH_STATUS_FALSE;
885 }
886
887 DBG(FUNC, PVT_FMT(target(), "r"));
888 return SWITCH_STATUS_SUCCESS;
889 }
890
makeCall(std::string params)891 int Board::KhompPvt::makeCall(std::string params)
892 {
893 DBG(FUNC, PVT_FMT(target(), "Dialing to %s from %s")
894 % _call->_dest_addr.c_str()
895 % _call->_orig_addr.c_str());
896
897 /* Lets make the call! */
898 std::string full_params;
899
900 if(!_call->_dest_addr.empty())
901 full_params += STG(FMT(" dest_addr=\"%s\"")
902 % _call->_dest_addr);
903
904 if(!params.empty())
905 full_params += STG(FMT(" %s")
906 % params);
907
908 DBG(FUNC, PVT_FMT(target(), "We are calling with params: %s.") % full_params.c_str());
909
910 int ret = commandState(KHOMP_LOG, CM_MAKE_CALL, (full_params != "" ? full_params.c_str() : NULL));
911
912 if(ret != ksSuccess)
913 {
914 destroy();
915 cleanup(CLN_FAIL);
916 }
917
918 return ret;
919 }
920
signalDTMF(char d)921 bool Board::KhompPvt::signalDTMF(char d)
922 {
923 DBG(FUNC, PVT_FMT(target(), "c (dtmf=%c)") % d);
924
925 try
926 {
927 switch_dtmf_t dtmf = { (char) d, switch_core_default_dtmf_duration(0) };
928 switch_channel_queue_dtmf(getFSChannel(), &dtmf);
929 }
930 catch (Board::KhompPvt::InvalidSwitchChannel & err)
931 {
932 LOG(ERROR, PVT_FMT(target(), "r (Received a DTMF, but %s)") % err._msg.c_str() );
933 return false;
934 }
935
936 DBG(FUNC, PVT_FMT(target(), "r"));
937
938 return true;
939 }
940
indicateBusyUnlocked(int cause,bool sent_signaling)941 bool Board::KhompPvt::indicateBusyUnlocked(int cause, bool sent_signaling)
942 {
943 DBG(FUNC, PVT_FMT(target(), "c"));
944
945 /* already playing! */
946 if (call()->_indication != INDICA_NONE)
947 {
948 if (call()->_indication == INDICA_RING)
949 {
950 DBG(FUNC, PVT_FMT(target(), "ringback being disabled"));
951
952 if(call()->_cadence == PLAY_RINGBACK)
953 stopCadence();
954
955 try
956 {
957 call()->_flags.clear(Kflags::GEN_PBX_RING);
958 call()->_flags.clear(Kflags::GEN_CO_RING);
959
960 Board::board(_target.device)->_timers.del(call()->_idx_pbx_ring);
961 Board::board(_target.device)->_timers.del(call()->_idx_co_ring);
962 }
963 catch (K3LAPITraits::invalid_device & err)
964 {
965 LOG(ERROR, PVT_FMT(_target, "Unable to get device: %d!") % err.device);
966 }
967
968 mixer(KHOMP_LOG, 1, kmsGenerator, kmtSilence);
969 call()->_indication = INDICA_NONE;
970 }
971 else
972 {
973 DBG(FUNC, PVT_FMT(target(), "r (already playing something: %d)")
974 % call()->_indication);
975 return false;
976 }
977 }
978
979 setHangupCause(cause, false);
980
981 call()->_indication = INDICA_BUSY;
982
983 DBG(FUNC, PVT_FMT(target(), "r"));
984
985 return true;
986 }
987
destroy(switch_core_session_t * s)988 void Board::KhompPvt::destroy(switch_core_session_t * s)
989 {
990 switch_core_session_t * tmp_session;
991
992 if(!s)
993 {
994 if(!_session)
995 return;
996
997 tmp_session = _session;
998 }
999 else
1000 {
1001 tmp_session = s;
1002
1003 }
1004
1005 switch_core_session_destroy(&tmp_session);
1006 }
1007
destroyAll()1008 void Board::KhompPvt::destroyAll()
1009 {
1010 if(_session)
1011 {
1012 switch_core_session_set_private(_session, NULL);
1013 _session = NULL;
1014 }
1015
1016 owner(NULL);
1017
1018 if(_caller_profile)
1019 {
1020 //DBG(FUNC, PVT_FMT(target(), "Profile != NULL"));
1021 //TODO: Destruir
1022 _caller_profile = NULL;
1023 }
1024
1025 if (switch_core_codec_ready(&_read_codec)) {
1026 //if(session())
1027 // switch_core_session_lock_codec_read(_session);
1028 switch_core_codec_destroy(&_read_codec);
1029 _read_codec.implementation = NULL;
1030 //if(session())
1031 // switch_core_session_unlock_codec_read(_session);
1032 }
1033
1034 if (switch_core_codec_ready(&_write_codec)) {
1035 //if(session())
1036 // switch_core_session_lock_codec_write(_session);
1037 switch_core_codec_destroy(&_write_codec);
1038 _write_codec.implementation = NULL;
1039 //if(session())
1040 // switch_core_session_unlock_codec_write(_session);
1041 }
1042
1043 }
1044
doHangup()1045 void Board::KhompPvt::doHangup()
1046 {
1047 try
1048 {
1049 switch_channel_t *channel = getFSChannel();
1050
1051 int cause_from_freeswitch = switch_channel_get_cause(channel);
1052 if(cause_from_freeswitch != SWITCH_CAUSE_NONE)
1053 {
1054 DBG(FUNC, PVT_FMT(_target, "cause already set to %s from freeswitch") % switch_channel_cause2str((switch_call_cause_t)cause_from_freeswitch));
1055 }
1056 else
1057 {
1058 DBG(FUNC, PVT_FMT(target(), "Hangup channel \"%s\"") % switch_channel_get_name(channel));
1059
1060 switch_channel_hangup(channel, (switch_call_cause_t)call()->_hangup_cause);
1061 }
1062 }
1063 catch(Board::KhompPvt::InvalidSwitchChannel & err)
1064 {
1065 //DBG(FUNC, PVT_FMT(target(), "Hangup channel already done"));
1066 }
1067 }
1068
cleanup(CleanupType type)1069 bool Board::KhompPvt::cleanup(CleanupType type)
1070 {
1071 // flags = 0;
1072
1073 _reader_frames.clear();
1074 _writer_frames.clear();
1075
1076 call()->_flags.clear(Kflags::CONNECTED);
1077
1078 //call()->_flags.clear(Kflags::BRIDGED);
1079
1080 call()->_flags.clear(Kflags::DROP_COLLECT);
1081
1082 call()->_flags.clear(Kflags::OUT_OF_BAND_DTMFS);
1083
1084 call()->_flags.clear(Kflags::WAIT_SEND_DTMF);
1085
1086 call()->_flags.clear(Kflags::GEN_PBX_RING);
1087 call()->_flags.clear(Kflags::GEN_CO_RING);
1088
1089 try
1090 {
1091 Board::board(_target.device)->_timers.del(call()->_idx_pbx_ring);
1092 Board::board(_target.device)->_timers.del(call()->_idx_co_ring);
1093 }
1094 catch (K3LAPITraits::invalid_device & err)
1095 {
1096 LOG(ERROR, PVT_FMT(_target, "Unable to get device: %d!") % err.device);
1097 }
1098
1099 call()->_idx_pbx_ring.reset();
1100 call()->_idx_co_ring.reset();
1101
1102 switch (type)
1103 {
1104 case CLN_HARD:
1105 case CLN_FAIL:
1106 call()->_flags.clear(Kflags::KEEP_DTMF_SUPPRESSION);
1107 call()->_flags.clear(Kflags::KEEP_ECHO_CANCELLATION);
1108 call()->_flags.clear(Kflags::KEEP_AUTO_GAIN_CONTROL);
1109
1110 stopStream();
1111 stopListen();
1112 doHangup();
1113 call()->_flags.clear(Kflags::IS_INCOMING);
1114 call()->_flags.clear(Kflags::IS_OUTGOING);
1115 call()->_flags.clear(Kflags::REALLY_CONNECTED);
1116 call()->_flags.clear(Kflags::HAS_PRE_AUDIO);
1117 call()->_flags.clear(Kflags::HAS_CALL_FAIL);
1118
1119 /* pára cadências e limpa estado das flags */
1120 stopCadence();
1121
1122 cleanupIndications(true);
1123
1124 if(call()->_input_volume >= -10 && call()->_input_volume <= 10)
1125 setVolume("input" , Opt::_options._input_volume());
1126
1127 if(call()->_output_volume >= -10 && call()->_output_volume <= 10)
1128 setVolume("output", Opt::_options._output_volume());
1129
1130 return _call->clear();
1131 case CLN_SOFT:
1132 if(call()->_cadence != PLAY_FASTBUSY)
1133 {
1134 /* pára cadências e limpa estado das flags */
1135 stopCadence();
1136 }
1137
1138 if (call()->_indication == INDICA_RING)
1139 {
1140 call()->_indication = INDICA_NONE;
1141
1142 mixer(KHOMP_LOG, 1, kmsGenerator, kmtSilence);
1143 }
1144 break;
1145 }
1146
1147 return true;
1148 }
1149
cleanupIndications(bool force)1150 void Board::KhompPvt::cleanupIndications(bool force)
1151 {
1152 if (call()->_indication != INDICA_NONE)
1153 {
1154 call()->_indication = INDICA_NONE;
1155 mixer(KHOMP_LOG, 1, kmsGenerator, kmtSilence);
1156 }
1157 }
1158
isFree(bool just_phy)1159 bool Board::KhompPvt::isFree(bool just_phy)
1160 {
1161 //DBG(FUNC, DP(this, "c"));
1162 try
1163 {
1164 bool is_physical_free = isPhysicalFree();
1165
1166 /* if we got here, is physically free */
1167 if (!is_physical_free || just_phy)
1168 return is_physical_free;
1169
1170 ScopedPvtLock lock(this);
1171
1172 if(session())
1173 return false;
1174
1175 bool free_state = !(_call->_flags.check(Kflags::IS_INCOMING) || _call->_flags.check(Kflags::IS_OUTGOING));
1176
1177 DBG(FUNC, PVT_FMT(target(), "[free = %s]") % (free_state ? "yes" : "no"));
1178 return free_state;
1179 }
1180 catch (ScopedLockFailed & err)
1181 {
1182 DBG(FUNC, PVT_FMT(target(), "unable to obtain lock: %s") % err._msg.c_str());
1183 }
1184
1185 return false;
1186 }
1187
queueFindFree(PriorityCallQueue & pqueue)1188 Board::KhompPvt * Board::queueFindFree(PriorityCallQueue &pqueue)
1189 {
1190 for (PriorityCallQueue::iterator i = pqueue.begin(); i != pqueue.end(); i++)
1191 {
1192 KhompPvt *pvt = (*i);
1193 if (pvt && pvt->isFree())
1194 {
1195 return pvt;
1196 }
1197 }
1198
1199 DBG(FUNC, D("found no free channel for fair allocation!"));
1200 return NULL;
1201 }
1202
queueAddChannel(PriorityCallQueue & pqueue,unsigned int board,unsigned int object)1203 void Board::queueAddChannel(PriorityCallQueue &pqueue, unsigned int board, unsigned int object)
1204 {
1205 try
1206 {
1207 KhompPvt * pvt = get(board, object);
1208 pqueue.insert(pvt);
1209 }
1210 catch(K3LAPITraits::invalid_channel & err)
1211 {
1212 //...
1213 }
1214 }
1215
findFree(unsigned int board,unsigned int object,bool fully_available)1216 Board::KhompPvt * Board::findFree(unsigned int board, unsigned int object, bool fully_available)
1217 {
1218 try
1219 {
1220 KhompPvt * pvt = get(board, object);
1221 return ((fully_available ? pvt->isFree() : pvt->isOK()) ? pvt : NULL);
1222 }
1223 catch(K3LAPITraits::invalid_channel & err)
1224 {
1225 }
1226 return NULL;
1227 }
1228
applyGlobalVolume(void)1229 void Board::applyGlobalVolume(void)
1230 {
1231 DBG(FUNC, "c");
1232
1233 for (unsigned int dev = 0; dev < Globals::k3lapi.device_count(); dev++)
1234 {
1235 for (unsigned int obj = 0; obj < Globals::k3lapi.channel_count(dev); obj++)
1236 {
1237 try
1238 {
1239 Board::get(dev,obj)->setVolume("input", Opt::_options._input_volume());
1240 Board::get(dev,obj)->setVolume("output",Opt::_options._output_volume());
1241 }
1242 catch(K3LAPITraits::invalid_channel & err)
1243 {
1244 DBG(FUNC, OBJ_FMT(dev, obj, "Channel not found"));
1245 }
1246 }
1247 }
1248
1249 DBG(FUNC, "r");
1250 }
1251
startCadence(CadencesType type)1252 bool Board::KhompPvt::startCadence(CadencesType type)
1253 {
1254 DBG(FUNC, PVT_FMT(target(), "c"));
1255
1256 std::string tone("");
1257
1258 /**/ if (type == PLAY_VM_TONE) tone = "vm-dialtone";
1259 else if (type == PLAY_PBX_TONE) tone = "pbx-dialtone";
1260 else if (type == PLAY_PUB_TONE) tone = "co-dialtone";
1261 else if (type == PLAY_RINGBACK) tone = "ringback";
1262 else if (type == PLAY_FASTBUSY) tone = "fast-busy";
1263
1264
1265 if (tone != "")
1266 {
1267 call()->_cadence = type;
1268
1269 CadencesMapType::iterator i = Opt::_cadences.find(tone);
1270 std::string cmd_params;
1271
1272 if (i != Opt::_cadences.end())
1273 {
1274 CadenceType cadence = (*i).second;
1275
1276 if (cadence.ring == 0 && cadence.ring_s == 0)
1277 {
1278 cmd_params = "cadence_times=\"continuous\" mixer_track=1";
1279 }
1280 else if (cadence.ring_ext == 0 && cadence.ring_ext_s == 0)
1281 {
1282 cmd_params = STG(FMT("cadence_times=\"%d,%d\" mixer_track=1")
1283 % cadence.ring % cadence.ring_s);
1284 }
1285 else
1286 {
1287 cmd_params = STG(FMT("cadence_times=\"%d,%d,%d,%d\" mixer_track=1")
1288 % cadence.ring % cadence.ring_s % cadence.ring_ext % cadence.ring_ext_s);
1289 }
1290
1291 command(KHOMP_LOG,CM_START_CADENCE,cmd_params.c_str());
1292 }
1293 else
1294 {
1295 LOG(ERROR, PVT_FMT(_target, "r (cadence '%s' not found)") % tone);
1296 return false;
1297 }
1298 }
1299 else
1300 {
1301 LOG(ERROR, PVT_FMT(_target, "r (unknown cadence requested )"));
1302 return false;
1303 }
1304
1305 DBG(FUNC, PVT_FMT(target(), "r"));
1306 return true;
1307 }
1308
1309 /* Helper functions - based on code from chan_khomp */
startStream(bool enable_mixer)1310 bool Board::KhompPvt::startStream(bool enable_mixer)
1311 {
1312 if (call()->_flags.check(Kflags::STREAM_UP))
1313 return true;
1314
1315 if(enable_mixer)
1316 {
1317 if(!mixer(KHOMP_LOG, 0, kmsPlay, _target.object))
1318 return false;
1319 }
1320
1321 if(!command(KHOMP_LOG, CM_START_STREAM_BUFFER))
1322 return false;
1323
1324 call()->_flags.set(Kflags::STREAM_UP);
1325
1326 return true;
1327 }
1328
stopStream(bool enable_mixer)1329 bool Board::KhompPvt::stopStream(bool enable_mixer)
1330 {
1331 if (!call()->_flags.check(Kflags::STREAM_UP))
1332 return true;
1333
1334 call()->_flags.clear(Kflags::STREAM_UP);
1335
1336 if(enable_mixer)
1337 {
1338 if(!mixer(KHOMP_LOG, 0, kmsGenerator, kmtSilence))
1339 return false;
1340 }
1341
1342 if(!command(KHOMP_LOG, CM_STOP_STREAM_BUFFER))
1343 return false;
1344
1345 return true;
1346 }
1347
startListen(bool conn_rx)1348 bool Board::KhompPvt::startListen(bool conn_rx)
1349 {
1350 if(call()->_flags.check(Kflags::LISTEN_UP))
1351 return true;
1352
1353 const size_t buffer_size = Globals::boards_packet_duration;
1354
1355 if(conn_rx)
1356 {
1357 if(!obtainRX(false)) //no delay, by default..
1358 return false;
1359 }
1360
1361 if(!command(KHOMP_LOG, CM_LISTEN, (const char *) &buffer_size))
1362 return false;
1363
1364 call()->_flags.set(Kflags::LISTEN_UP);
1365
1366 return true;
1367 }
1368
stopListen(void)1369 bool Board::KhompPvt::stopListen(void)
1370 {
1371 if(!call()->_flags.check(Kflags::LISTEN_UP))
1372 return true;
1373
1374 call()->_flags.clear(Kflags::LISTEN_UP);
1375
1376 if(!command(KHOMP_LOG, CM_STOP_LISTEN))
1377 {
1378 return false;
1379 }
1380
1381 return true;
1382 }
1383
obtainRX(bool with_delay)1384 bool Board::KhompPvt::obtainRX(bool with_delay)
1385 {
1386 try
1387 {
1388 Globals::k3lapi.mixerRecord(_target, 0, (with_delay ? kmsChannel : kmsNoDelayChannel), target().object);
1389 Globals::k3lapi.mixerRecord(_target, 1, kmsGenerator, kmtSilence);
1390 }
1391 catch(K3LAPI::failed_raw_command & e)
1392 {
1393 LOG(ERROR, PVT_FMT(target(), "ERROR sending mixer command!"));
1394 return false;
1395 }
1396
1397 return true;
1398 }
1399
obtainTX()1400 bool Board::KhompPvt::obtainTX()
1401 {
1402 /* estes buffers *NAO PODEM SER ESTATICOS*! */
1403 char cmd1[] = { 0x3f, 0x03, 0xff, 0x00, 0x00, 0xff };
1404 char cmd2[] = { 0x3f, 0x03, 0xff, 0x01, 0x09, 0x0f };
1405
1406 cmd1[2] = cmd1[5] = cmd2[2] = _target.object;
1407
1408 try
1409 {
1410 int dsp = Globals::k3lapi.get_dsp(_target, K3LAPI::DSP_AUDIO);
1411
1412 Globals::k3lapi.raw_command(_target.device, dsp, cmd1, sizeof(cmd1));
1413
1414 Globals::k3lapi.raw_command(_target.device, dsp, cmd2, sizeof(cmd2));
1415
1416 }
1417 catch(K3LAPI::failed_raw_command & e)
1418 {
1419 LOG(ERROR, PVT_FMT(target(), "ERROR sending mixer command!"));
1420 return false;
1421 }
1422
1423 return true;
1424 }
1425
sendDtmf(std::string digit)1426 bool Board::KhompPvt::sendDtmf(std::string digit)
1427 {
1428 if(!call()->_flags.check(Kflags::STREAM_UP))
1429 {
1430 DBG(FUNC, PVT_FMT(target(), "stream down, not sending dtmf"));
1431 return false;
1432 }
1433
1434 if(!call()->_flags.check(Kflags::OUT_OF_BAND_DTMFS))
1435 {
1436 DBG(FUNC, PVT_FMT(target(), "dtmf suppression disabled, not generating dtmf"));
1437 return false;
1438 }
1439
1440 if(digit.empty())
1441 {
1442 DBG(FUNC, PVT_FMT(target(), "not sending dtmf (there is nothing to send)"));
1443 return false;
1444 }
1445
1446 if(call()->_flags.check(Kflags::WAIT_SEND_DTMF))
1447 {
1448 DBG(FUNC, PVT_FMT(target(), "queueing dtmf (%s)") % digit);
1449 call()->_queued_digits_buffer += digit;
1450 return true;
1451 }
1452
1453 DBG(FUNC, PVT_FMT(target(), "sending dtmf (%s)") % digit);
1454
1455 call()->_flags.set(Kflags::WAIT_SEND_DTMF);
1456
1457 return command(KHOMP_LOG, CM_DIAL_DTMF, digit.c_str());
1458 }
1459
setVolume(const char * type,int volume)1460 bool Board::KhompPvt::setVolume(const char * type, int volume)
1461 {
1462 std::string arg = STG(FMT("volume=\"%d\" type=\"%s\"") % volume % type);
1463 DBG(FUNC, PVT_FMT(_target, "%s") % arg);
1464 return command(KHOMP_LOG,CM_SET_VOLUME,arg.c_str());
1465 }
1466
getStateString(void)1467 std::string Board::KhompPvt::getStateString(void)
1468 {
1469 try
1470 {
1471 switch_channel_t *c = getFSChannel();
1472 if(!c) return "unused";
1473
1474 switch_channel_state_t state = switch_channel_get_state(c);
1475
1476 /* shortcut */
1477 typedef std::string S;
1478
1479 switch (state)
1480 {
1481 case CS_NEW: return S("new");
1482 case CS_INIT: return S("init");
1483 case CS_ROUTING: return S("routing");
1484 case CS_SOFT_EXECUTE: return S("sf_exec");
1485 case CS_EXECUTE: return S("execute");
1486 case CS_EXCHANGE_MEDIA: return S("ex_media");
1487 case CS_PARK: return S("park");
1488 case CS_CONSUME_MEDIA: return S("cs_media");
1489 case CS_HIBERNATE: return S("hibernat");
1490 case CS_RESET: return S("reset");
1491 case CS_HANGUP: return S("hangup");
1492 case CS_REPORTING: return S("reportg");
1493 case CS_DESTROY: return S("destroy");
1494 case CS_NONE: return S("none");
1495 default:
1496 return STG(FMT("none (%d)") % state);
1497 }
1498 }
1499 catch(Board::KhompPvt::InvalidSwitchChannel & err)
1500 {
1501 return "unused";
1502 }
1503 }
1504
dtmfSuppression(bool enable)1505 bool Board::KhompPvt::dtmfSuppression(bool enable)
1506 {
1507 if (!command(KHOMP_LOG, (enable ? CM_ENABLE_DTMF_SUPPRESSION : CM_DISABLE_DTMF_SUPPRESSION)))
1508 return false;
1509
1510 if (enable) call()->_flags.set(Kflags::OUT_OF_BAND_DTMFS);
1511 else call()->_flags.clear(Kflags::OUT_OF_BAND_DTMFS);
1512
1513 DBG(FUNC, PVT_FMT(_target, "flag OUT_OF_BAND_DTMFS is : %s") %
1514 (call()->_flags.check(Kflags::OUT_OF_BAND_DTMFS) ? "true" : "false"));
1515
1516 return true;
1517 }
1518
echoCancellation(bool enable)1519 bool Board::KhompPvt::echoCancellation(bool enable)
1520 {
1521 const K3L_DEVICE_CONFIG & devCfg = Globals::k3lapi.device_config(_target);
1522
1523 /* echo canceller should not be used for non-echo cancellable channels */
1524 switch (devCfg.EchoConfig)
1525 {
1526 case keccFail:
1527 if (!enable)
1528 return true;
1529
1530 LOG(ERROR, PVT_FMT(_target, "unable to activate echo cancellation"));
1531 return false;
1532
1533 case keccNotPresent:
1534 DBG(FUNC, PVT_FMT(_target, "echo cancellation not present, not %s.") % (enable ? "enabling" : "disabling"));
1535 return true;
1536
1537 default:
1538 return command(KHOMP_LOG,(enable ? CM_ENABLE_ECHO_CANCELLER : CM_DISABLE_ECHO_CANCELLER));
1539 }
1540 }
1541
autoGainControl(bool enable)1542 bool Board::KhompPvt::autoGainControl(bool enable)
1543 {
1544 bool ret = command(KHOMP_LOG,(enable ? CM_ENABLE_AGC : CM_DISABLE_AGC));
1545 return ret;
1546 }
1547
pbxRingGen(Board::KhompPvt * pvt)1548 void Board::KhompPvt::pbxRingGen(Board::KhompPvt * pvt)
1549 {
1550 DBG(FUNC, PVT_FMT(pvt->target(), "Generating pbx ring"));
1551
1552 try
1553 {
1554 ScopedPvtLock lock(pvt);
1555
1556 if (!pvt->call()->_flags.check(Kflags::GEN_PBX_RING))
1557 return;
1558
1559 if (!pvt->obtainTX())
1560 return;
1561
1562 pvt->startCadence(PLAY_RINGBACK);
1563 }
1564 catch (...)
1565 {
1566 LOG(ERROR, PVT_FMT(pvt->target(), "unable to lock!"));
1567 }
1568 }
1569
coRingGen(Board::KhompPvt * pvt)1570 void Board::KhompPvt::coRingGen(Board::KhompPvt * pvt)
1571 {
1572 DBG(FUNC, PVT_FMT(pvt->target(), "Generating co ring"));
1573
1574 try
1575 {
1576 ScopedPvtLock lock(pvt);
1577
1578 if (!pvt->call()->_flags.check(Kflags::GEN_CO_RING))
1579 return;
1580
1581 pvt->startCadence(PLAY_RINGBACK);
1582 }
1583 catch (...)
1584 {
1585 LOG(ERROR, PVT_FMT(pvt->target(), "unable to lock the pvt !"));
1586 }
1587 }
1588
getActiveChannel(bool invalid_as_not_found)1589 int Board::KhompPvt::getActiveChannel(bool invalid_as_not_found)
1590 {
1591 // AT CONSTRUCTION
1592 return 0;
1593 }
1594
setCollectCall()1595 bool Board::KhompPvt::setCollectCall()
1596 {
1597 DBG(FUNC, PVT_FMT(target(), "c"));
1598 // NEEDS LOCK !?
1599
1600 std::vector< TriState > confvalues;
1601
1602 // temporary!
1603 const char * tmp_var = NULL;
1604
1605 // get option configuration value
1606 confvalues.push_back(Opt::_options._drop_collect_call() ? T_TRUE : T_FALSE);
1607 DBG(FUNC, PVT_FMT(_target, "option drop collect call is '%s'") % (Opt::_options._drop_collect_call() ? "yes" : "no"));
1608
1609 // get global filter configuration value
1610 tmp_var = getFSGlobalVar("KDropCollectCall");
1611 confvalues.push_back(getTriStateValue(tmp_var));
1612 DBG(FUNC, PVT_FMT(_target, "global KDropCollectCall was '%s'") % (tmp_var ? tmp_var : "(empty)"));
1613
1614 freeFSGlobalVar(&tmp_var);
1615
1616 try
1617 {
1618 // get local filter configuration value
1619 tmp_var = switch_channel_get_variable(getFSChannel(), "KDropCollectCall");
1620 confvalues.push_back(getTriStateValue(tmp_var));
1621 DBG(FUNC, PVT_FMT(_target, "local KDropCollectCall was '%s'") % (tmp_var ? tmp_var : "(empty)"));
1622 }
1623 catch(Board::KhompPvt::InvalidSwitchChannel & err)
1624 {
1625 LOG(ERROR, PVT_FMT(_target, "Cannot obtain the channel variable: %s") % err._msg.c_str());
1626 }
1627
1628 // store last state assigned
1629 bool last_state = false;
1630
1631 // validate the states
1632 std::vector< TriState >::const_iterator end = confvalues.end();
1633 for (std::vector< TriState >::const_iterator i = confvalues.begin(); i != end; ++i)
1634 {
1635 switch(*i)
1636 {
1637 case T_TRUE:
1638 last_state = true;
1639 break;
1640 case T_FALSE:
1641 last_state = false;
1642 break;
1643 case T_UNKNOWN:
1644 default:
1645 break;
1646 }
1647 }
1648
1649 if (last_state)
1650 call()->_flags.set(Kflags::DROP_COLLECT);
1651 else
1652 call()->_flags.clear(Kflags::DROP_COLLECT);
1653
1654 DBG(FUNC, PVT_FMT(_target, "drop collect call flag: %s.") % (last_state ? "set" : "unset"));
1655
1656 return last_state;
1657 }
1658
onChannelRelease(K3L_EVENT * e)1659 bool Board::KhompPvt::onChannelRelease(K3L_EVENT *e)
1660 {
1661 DBG(FUNC, PVT_FMT(target(), "c"));
1662
1663 try
1664 {
1665 ScopedPvtLock lock(this);
1666
1667 if (e->Code == EV_CHANNEL_FAIL)
1668 {
1669 call()->statistics()->incrementChannelFail();
1670 _has_fail = true;
1671 setHangupCause(SWITCH_CAUSE_NETWORK_OUT_OF_ORDER);
1672 cleanup(CLN_HARD);
1673 }
1674 else
1675 {
1676 if(call()->_flags.check(Kflags::REALLY_CONNECTED))
1677 {
1678 call()->statistics()->incrementHangup();
1679 }
1680
1681 setHangupCause(SWITCH_CAUSE_NORMAL_CLEARING);
1682 cleanup(CLN_HARD);
1683 }
1684 }
1685 catch (ScopedLockFailed & err)
1686 {
1687 LOG(ERROR, PVT_FMT(target(), "r (unable to lock %s!)") % err._msg.c_str() );
1688 return false;
1689 }
1690
1691 DBG(FUNC, PVT_FMT(target(), "r"));
1692 return true;
1693 }
1694
1695 //TODO: This method must return more information about the channel allocation
onNewCall(K3L_EVENT * e)1696 bool Board::KhompPvt::onNewCall(K3L_EVENT *e)
1697 {
1698 DBG(FUNC, PVT_FMT(target(), "c"));
1699
1700 std::string orig_addr, dest_addr;
1701
1702 Globals::k3lapi.get_param(e, "orig_addr", orig_addr);
1703 Globals::k3lapi.get_param(e, "dest_addr", dest_addr);
1704
1705 if(dest_addr.empty())
1706 {
1707 dest_addr="s";
1708 }
1709
1710 try
1711 {
1712 ScopedPvtLock lock(this);
1713
1714 _call->_orig_addr = orig_addr;
1715 _call->_dest_addr = dest_addr;
1716
1717 if (justAlloc(true) != SWITCH_STATUS_SUCCESS)
1718 {
1719 int fail_code = callFailFromCause(SWITCH_CAUSE_UNALLOCATED_NUMBER);
1720 setHangupCause(SWITCH_CAUSE_UNALLOCATED_NUMBER);
1721 cleanup(CLN_FAIL);
1722 reportFailToReceive(fail_code);
1723
1724 LOG(ERROR, PVT_FMT(target(), "r (Initilization Error on alloc!)"));
1725 return false;
1726 }
1727
1728 if (justStart() != SWITCH_STATUS_SUCCESS)
1729 {
1730 int fail_code = callFailFromCause(SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL);
1731 setHangupCause(SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL);
1732 cleanup(CLN_FAIL);
1733 reportFailToReceive(fail_code);
1734
1735 LOG(ERROR, PVT_FMT(target(), "r (Initilization Error on start!)"));
1736 return false;
1737 }
1738 }
1739 catch (ScopedLockFailed & err)
1740 {
1741 cleanup(CLN_FAIL);
1742 LOG(ERROR, PVT_FMT(target(), "r (unable to lock %s!)") % err._msg.c_str() );
1743 return false;
1744 }
1745 catch (Board::KhompPvt::InvalidSwitchChannel & err)
1746 {
1747 cleanup(CLN_FAIL);
1748 LOG(ERROR, PVT_FMT(target(), "r (%s)") % err._msg.c_str() );
1749 return false;
1750 }
1751
1752 DBG(FUNC, PVT_FMT(target(), "r"));
1753 return true;
1754 }
1755
onDisconnect(K3L_EVENT * e)1756 bool Board::KhompPvt::onDisconnect(K3L_EVENT *e)
1757 {
1758 DBG(FUNC, PVT_FMT(_target, "c"));
1759
1760 /*
1761 try
1762 {
1763 ScopedPvtLock lock(this);
1764
1765 }
1766 catch (ScopedLockFailed & err)
1767 {
1768 LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
1769 return false;
1770 }
1771 */
1772
1773 DBG(FUNC, PVT_FMT(_target, "r"));
1774 return true;
1775 }
1776
onAudioStatus(K3L_EVENT * e)1777 bool Board::KhompPvt::onAudioStatus(K3L_EVENT *e)
1778 {
1779 try
1780 {
1781 if(e->AddInfo != kmtSilence)
1782 {
1783 if(call()->_flags.check(Kflags::GEN_PBX_RING))
1784 {
1785 DBG(FUNC, PVT_FMT(_target, "PBX ringback being disabled..."));
1786 ScopedPvtLock lock(this);
1787
1788 call()->_flags.clear(Kflags::GEN_PBX_RING);
1789 Board::board(_target.device)->_timers.del(call()->_idx_pbx_ring);
1790
1791 if(call()->_cadence != PLAY_VM_TONE)
1792 {
1793 stopCadence();
1794 }
1795
1796 if (!call()->_flags.check(Kflags::CONNECTED))
1797 {
1798 obtainRX(Opt::_options._suppression_delay());
1799
1800 //Marcar para o Freeswitch que jah tem audio passando
1801 if (call()->_flags.check(Kflags::IS_OUTGOING))
1802 switch_channel_mark_pre_answered(getFSChannel());
1803
1804 }
1805 }
1806
1807 if (!call()->_is_progress_sent && call()->_flags.check(Kflags::HAS_CALL_FAIL))
1808 {
1809
1810 ScopedPvtLock lock(this);
1811
1812 DBG(FUNC, PVT_FMT(_target, "Audio status progress"));
1813
1814 call()->_is_progress_sent = true;
1815 //Sinaliza para o Freeswitch PROGRESS
1816
1817 DBG(FUNC, PVT_FMT(_target, "Pre answer"));
1818
1819 //pvt->signal_state(AST_CONTROL_PROGRESS);
1820 switch_channel_pre_answer(getFSChannel());
1821 }
1822 }
1823 }
1824 catch (ScopedLockFailed & err)
1825 {
1826 LOG(ERROR, PVT_FMT(_target, "unable to lock %s!") % err._msg.c_str() );
1827 return false;
1828
1829 }
1830 catch (Board::KhompPvt::InvalidSwitchChannel & err)
1831 {
1832 cleanup(CLN_FAIL);
1833 LOG(ERROR, PVT_FMT(target(), "r (%s)") % err._msg.c_str() );
1834 return false;
1835 }
1836 catch (K3LAPITraits::invalid_device & err)
1837 {
1838 LOG(ERROR, PVT_FMT(_target, "r (unable to get device: %d!)") % err.device);
1839 return false;
1840 }
1841
1842 return true;
1843 }
1844
onCollectCall(K3L_EVENT * e)1845 bool Board::KhompPvt::onCollectCall(K3L_EVENT *e)
1846 {
1847 try
1848 {
1849 ScopedPvtLock lock(this);
1850
1851 //TODO: AMI ?
1852 //K::internal::ami_event(pvt, EVENT_FLAG_CALL, "CollectCall",
1853 // STG(FMT("Channel: Khomp/B%dC%d\r\n") % pvt->boardid % pvt->objectid));
1854
1855 if (Opt::_options._drop_collect_call() || _call->_flags.check(Kflags::DROP_COLLECT))
1856 {
1857 /* disconnect! */
1858 //TODO: SCE_HIDE !?
1859 command(KHOMP_LOG,CM_DISCONNECT);
1860 // command(KHOMP_LOG,CM_DISCONNECT,SCE_HIDE);
1861
1862 }
1863 }
1864 catch (ScopedLockFailed & err)
1865 {
1866 LOG(ERROR, PVT_FMT(_target, "unable to lock %s!") % err._msg.c_str() );
1867 return false;
1868 }
1869
1870 return true;
1871 }
1872
onSeizureStart(K3L_EVENT * e)1873 bool Board::KhompPvt::onSeizureStart(K3L_EVENT *e)
1874 {
1875 /*
1876 try
1877 {
1878 ScopedPvtLock lock(this);
1879 }
1880 catch (ScopedLockFailed & err)
1881 {
1882 LOG(ERROR, PVT_FMT(_target, "unable to lock %s!") % err._msg.c_str() );
1883 return false;
1884 }
1885 */
1886 return true;
1887 }
1888
setupConnection()1889 bool Board::KhompPvt::setupConnection()
1890 {
1891 if(!call()->_flags.check(Kflags::IS_INCOMING) && !call()->_flags.check(Kflags::IS_OUTGOING))
1892 {
1893 DBG(FUNC, PVT_FMT(_target, "Channel already disconnected"));
1894 return false;
1895 }
1896
1897 if(call()->_cadence != PLAY_VM_TONE)
1898 {
1899 stopCadence();
1900 }
1901
1902 if (call()->_indication != INDICA_NONE)
1903 {
1904 call()->_indication = INDICA_NONE;
1905
1906 mixer(KHOMP_LOG, 1, kmsGenerator, kmtSilence);
1907 }
1908
1909 if(call()->_flags.check(Kflags::GEN_PBX_RING))
1910 {
1911 call()->_flags.clear(Kflags::GEN_PBX_RING);
1912 Board::board(_target.device)->_timers.del(call()->_idx_pbx_ring);
1913 }
1914
1915 if(call()->_flags.check(Kflags::GEN_CO_RING))
1916 {
1917 call()->_flags.clear(Kflags::GEN_CO_RING);
1918 Board::board(_target.device)->_timers.del(call()->_idx_co_ring);
1919 }
1920
1921 if (!call()->_flags.check(Kflags::CONNECTED))
1922 call()->_flags.set(Kflags::CONNECTED);
1923
1924 if (!call()->_flags.check(Kflags::REALLY_CONNECTED))
1925 call()->_flags.set(Kflags::REALLY_CONNECTED);
1926
1927 /* Sinalizar para o Freeswitch o atendimento */
1928
1929 DBG(FUNC, PVT_FMT(_target, "Call will be answered."));
1930
1931 if(call()->_flags.check(Kflags::IS_INCOMING))
1932 {
1933 switch_channel_answer(getFSChannel());
1934 }
1935 else if(call()->_flags.check(Kflags::IS_OUTGOING))
1936 {
1937 switch_channel_mark_answered(getFSChannel());
1938 }
1939
1940 call()->statistics()->incrementNewCall();
1941
1942 return true;
1943 }
1944
1945
onConnect(K3L_EVENT * e)1946 bool Board::KhompPvt::onConnect(K3L_EVENT *e)
1947 {
1948 DBG(FUNC, PVT_FMT(_target, "c"));
1949
1950 try
1951 {
1952 ScopedPvtLock lock(this);
1953
1954 return setupConnection();
1955 }
1956 catch (ScopedLockFailed & err)
1957 {
1958 LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
1959 return false;
1960 }
1961 catch (Board::KhompPvt::InvalidSwitchChannel & err)
1962 {
1963 LOG(ERROR, PVT_FMT(target(), "r (%s)") % err._msg.c_str() );
1964 return false;
1965 }
1966 catch (K3LAPITraits::invalid_device & err)
1967 {
1968 LOG(ERROR, PVT_FMT(_target, "r (unable to get device: %d!)") % err.device);
1969 return false;
1970 }
1971
1972 DBG(FUNC, PVT_FMT(_target, "r"));
1973
1974 return true;
1975 }
1976
onCallSuccess(K3L_EVENT * e)1977 bool Board::KhompPvt::onCallSuccess(K3L_EVENT *e)
1978 {
1979 DBG(FUNC, PVT_FMT(_target, "c"));
1980
1981 try
1982 {
1983 ScopedPvtLock lock(this);
1984
1985 switch_channel_mark_ring_ready(getFSChannel());
1986 }
1987 catch (ScopedLockFailed & err)
1988 {
1989 LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
1990 return false;
1991 }
1992 catch (Board::KhompPvt::InvalidSwitchChannel & err)
1993 {
1994 LOG(ERROR, PVT_FMT(target(), "r (%s)") % err._msg.c_str() );
1995 return false;
1996 }
1997
1998 DBG(FUNC, PVT_FMT(_target, "r"));
1999
2000 return true;
2001 }
2002
onCallFail(K3L_EVENT * e)2003 bool Board::KhompPvt::onCallFail(K3L_EVENT *e)
2004 {
2005 DBG(FUNC, PVT_FMT(_target, "c"));
2006 try
2007 {
2008 ScopedPvtLock lock(this);
2009
2010 call()->_flags.set(Kflags::HAS_CALL_FAIL);
2011
2012 //TODO: Notificar o Freeswitch: call fail
2013
2014 cleanup(CLN_SOFT);
2015 }
2016 catch (ScopedLockFailed & err)
2017 {
2018 LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
2019 return false;
2020 }
2021
2022 DBG(FUNC, PVT_FMT(_target, "r"));
2023
2024 return true;
2025 }
2026
onNoAnswer(K3L_EVENT * e)2027 bool Board::KhompPvt::onNoAnswer(K3L_EVENT *e)
2028 {
2029 /* TODO: Destroy sessions and channels */
2030 DBG(FUNC, PVT_FMT(_target, "No one answered the call."));
2031
2032 // TODO: Set channel variable if we get this event
2033 // TODO: Fire an event so ESL can get it?
2034 // Call Analyser has to be enabled on k3lconfig
2035 DBG(FUNC, PVT_FMT(_target, "Detected: \"%s\"") % Verbose::callStartInfo((KCallStartInfo)e->AddInfo).c_str());
2036
2037 // Fire a custom event about this
2038 /* MUST USE THE NEW EVENT SYSTEM
2039 switch_event_t * event;
2040 if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, KHOMP_EVENT_MAINT) == SWITCH_STATUS_SUCCESS)
2041 {
2042 Board::khomp_add_event_board_data(_target, event);
2043 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM,
2044 "EV_CALL_ANSWER_INFO",
2045 Verbose::callStartInfo((KCallStartInfo)e->AddInfo).c_str());
2046
2047 switch_event_fire(&event);
2048 }
2049 */
2050
2051 return true;
2052 }
2053
onDtmfDetected(K3L_EVENT * e)2054 bool Board::KhompPvt::onDtmfDetected(K3L_EVENT *e)
2055 {
2056 DBG(FUNC, PVT_FMT(_target, "c (dtmf=%c)") % (char) e->AddInfo);
2057
2058 try
2059 {
2060 ScopedPvtLock lock(this);
2061
2062 if (call()->_flags.check(Kflags::IS_INCOMING) || call()->_flags.check(Kflags::IS_OUTGOING)) /* is a valid call? */
2063 {
2064 char digit = (char) e->AddInfo;
2065
2066 //TODO: WTHeck ?
2067 //if (!call()->_flags.check(Kflags::OUT_OF_BAND_DTMFS) && !call()->_flags.check(Kflags::BRIDGED))
2068 if (!call()->_flags.check(Kflags::OUT_OF_BAND_DTMFS))
2069 {
2070 /* we do not queue dtmfs as we do not need to resend them */
2071 DBG(FUNC, PVT_FMT(_target, "r (not queueing dtmf, not needed.)"));
2072 return true;
2073 }
2074
2075 if (Opt::_options._ignore_letter_dtmfs())
2076 {
2077 switch (e->AddInfo)
2078 {
2079 case 'A': case 'a':
2080 case 'B': case 'b':
2081 case 'C': case 'c':
2082 case 'D': case 'd':
2083 DBG(FUNC, PVT_FMT(_target, "r (not queueing dtmf, letter digit ignored!)"));
2084 return true;
2085 default:
2086 break;
2087 }
2088 }
2089
2090 signalDTMF(e->AddInfo);
2091 }
2092 }
2093 catch (ScopedLockFailed & err)
2094 {
2095 LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
2096 return false;
2097 }
2098
2099 DBG(FUNC, PVT_FMT(_target, "r"));
2100 return true;
2101 }
2102
onDtmfSendFinish(K3L_EVENT * e)2103 bool Board::KhompPvt::onDtmfSendFinish(K3L_EVENT *e)
2104 {
2105 DBG(FUNC, PVT_FMT(_target, "c"));
2106
2107 try
2108 {
2109 ScopedPvtLock lock(this);
2110
2111 if (call()->_flags.check(Kflags::WAIT_SEND_DTMF))
2112 {
2113 if(!call()->_queued_digits_buffer.empty())
2114 {
2115 DBG(FUNC, PVT_FMT(target(), "sending dtmf (%s)")
2116 % call()->_queued_digits_buffer);
2117
2118 command(KHOMP_LOG, CM_DIAL_DTMF,
2119 call()->_queued_digits_buffer.c_str());
2120
2121 /* clear the buffer that has been send */
2122 call()->_queued_digits_buffer.clear();
2123 }
2124 else
2125 {
2126 DBG(FUNC, PVT_FMT(target(),
2127 "finished sending some digits, cleaning up!"));
2128 call()->_flags.clear(Kflags::WAIT_SEND_DTMF);
2129 }
2130 }
2131 }
2132 catch (ScopedLockFailed & err)
2133 {
2134 LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
2135 return false;
2136 }
2137
2138 DBG(FUNC, PVT_FMT(_target, "r"));
2139
2140 return true;
2141 }
2142
onEvUntreated(K3L_EVENT * e)2143 bool Board::KhompPvt::onEvUntreated(K3L_EVENT *e)
2144 {
2145 DBG(FUNC, PVT_FMT(_target, "New Event has just arrived with untreated code \"%d\" \"%s\"") % e->Code % Globals::verbose.event(_target.object, e));
2146
2147 return false;
2148 }
2149
eventHandler(K3L_EVENT * e)2150 bool Board::KhompPvt::eventHandler(K3L_EVENT *e)
2151 {
2152 DBG(STRM, D("c"));
2153
2154 bool ret = true;
2155
2156 switch(e->Code)
2157 {
2158 case EV_CHANNEL_FREE:
2159 case EV_CHANNEL_FAIL:
2160 ret = onChannelRelease(e);
2161 break;
2162
2163 case EV_NEW_CALL:
2164 ret = onNewCall(e);
2165 break;
2166
2167 case EV_CALL_SUCCESS:
2168 ret = onCallSuccess(e);
2169 break;
2170
2171 case EV_CALL_FAIL:
2172 ret = onCallFail(e);
2173 break;
2174
2175 case EV_CONNECT:
2176 ret = onConnect(e);
2177 break;
2178
2179 case EV_DISCONNECT:
2180 ret = onDisconnect(e);
2181 break;
2182
2183 case EV_AUDIO_STATUS:
2184 ret = onAudioStatus(e);
2185 break;
2186
2187 case EV_NO_ANSWER:
2188 ret = onNoAnswer(e);
2189 break;
2190
2191 case EV_DTMF_DETECTED:
2192 ret = onDtmfDetected(e);
2193 break;
2194
2195 case EV_DTMF_SEND_FINISH:
2196 ret = onDtmfSendFinish(e);
2197 break;
2198
2199 case EV_COLLECT_CALL:
2200 ret = onCollectCall(e);
2201 break;
2202
2203 case EV_SEIZURE_START:
2204 ret = onSeizureStart(e);
2205 break;
2206
2207 case EV_CADENCE_RECOGNIZED:
2208 break;
2209
2210 default:
2211 ret = onEvUntreated(e);
2212 break;
2213 }
2214
2215 DBG(STRM, D("r"));
2216
2217 return ret;
2218 }
2219
indicateProgress()2220 bool Board::KhompPvt::indicateProgress()
2221 {
2222 DBG(FUNC, PVT_FMT(_target, "c"));
2223
2224 int ret = false;
2225
2226 try
2227 {
2228 ScopedPvtLock lock(this);
2229
2230 if (!call()->_flags.check(Kflags::CONNECTED))
2231 {
2232 bool has_audio = sendPreAudio(RingbackDefs::RB_SEND_NOTHING);
2233
2234 if (has_audio)
2235 {
2236 /* start grabbing audio */
2237 startListen();
2238 /* start stream if it is not already */
2239 startStream();
2240
2241 ret = true;
2242 }
2243 }
2244 }
2245 catch (ScopedLockFailed & err)
2246 {
2247 LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
2248 return false;
2249 }
2250
2251 DBG(FUNC, PVT_FMT(_target, "r"));
2252
2253 return ret;
2254 }
2255
indicateRinging()2256 bool Board::KhompPvt::indicateRinging()
2257 {
2258 DBG(FUNC, PVT_FMT(_target, "c"));
2259
2260 bool ret = false;
2261 try
2262 {
2263 ScopedPvtLock lock(this);
2264
2265 /* already playing! */
2266 if (call()->_indication != INDICA_NONE)
2267 {
2268 DBG(FUNC, PVT_FMT(_target, "r (already playing something: %d)")
2269 % call()->_indication);
2270 return false;
2271 }
2272
2273 // any collect calls ?
2274 setCollectCall();
2275
2276 call()->_indication = INDICA_RING;
2277
2278 bool send_ringback = true;
2279
2280 if (!call()->_flags.check(Kflags::CONNECTED))
2281 {
2282 int ringback_value = RingbackDefs::RB_SEND_DEFAULT;
2283
2284 bool do_drop_call = Opt::_options._drop_collect_call()
2285 || call()->_flags.check(Kflags::DROP_COLLECT);
2286
2287 if (do_drop_call && call()->_collect_call)
2288 {
2289 ringback_value = kq931cCallRejected;
2290 DBG(FUNC, PVT_FMT(_target, "ringback value adjusted to refuse collect call: %d") % ringback_value);
2291 }
2292
2293 // send ringback too?
2294 send_ringback = sendPreAudio(ringback_value);
2295
2296 if (!send_ringback)
2297 {
2298 // warn the developer which may be debugging some "i do not have ringback!" issue.
2299 DBG(FUNC, PVT_FMT(_target, " not sending pre connection audio"));
2300 }
2301
2302 }
2303
2304 if (send_ringback)
2305 {
2306 call()->_flags.set(Kflags::GEN_CO_RING);
2307 call()->_idx_co_ring = Board::board(_target.device)->_timers.add(Opt::_options._ringback_co_delay(), &Board::KhompPvt::coRingGen,this);
2308
2309 /* start grabbing audio */
2310 startListen();
2311
2312 /* start stream if it is not already */
2313 startStream();
2314
2315 ret = true;
2316 }
2317
2318 }
2319 catch (ScopedLockFailed & err)
2320 {
2321 LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
2322 return false;
2323 }
2324 catch (K3LAPITraits::invalid_device & err)
2325 {
2326 LOG(ERROR, PVT_FMT(_target, "r (unable to get device: %d!)") % err.device);
2327 return false;
2328 }
2329
2330
2331 DBG(FUNC, PVT_FMT(_target, "r"));
2332 return ret;
2333 }
2334
doChannelAnswer(CommandRequest & cmd)2335 bool Board::KhompPvt::doChannelAnswer(CommandRequest &cmd)
2336 {
2337 DBG(FUNC, PVT_FMT(_target, "c"));
2338
2339 try
2340 {
2341 ScopedPvtLock lock(this);
2342
2343 call()->_flags.set(Kflags::CONNECTED);
2344
2345 }
2346 catch (ScopedLockFailed & err)
2347 {
2348 LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
2349 return false;
2350 }
2351
2352 DBG(FUNC, PVT_FMT(_target, "r"));
2353 return true;
2354 }
2355
doChannelHangup(CommandRequest & cmd)2356 bool Board::KhompPvt::doChannelHangup(CommandRequest &cmd)
2357 {
2358 DBG(FUNC, PVT_FMT(_target, "c"));
2359
2360 bool answered = true;
2361 bool disconnected = false;
2362
2363 try
2364 {
2365 ScopedPvtLock lock(this);
2366
2367 if (call()->_flags.check(Kflags::IS_INCOMING))
2368 {
2369 DBG(FUNC, PVT_FMT(_target, "disconnecting incoming channel"));
2370
2371 //disconnected = command(KHOMP_LOG, CM_DISCONNECT);
2372 }
2373 else if (call()->_flags.check(Kflags::IS_OUTGOING))
2374 {
2375 if(call()->_cleanup_upon_hangup)
2376 {
2377 DBG(FUNC, PVT_FMT(_target, "disconnecting not allocated outgoing channel..."));
2378
2379 disconnected = command(KHOMP_LOG, CM_DISCONNECT);
2380 cleanup(KhompPvt::CLN_HARD);
2381 answered = false;
2382
2383 }
2384 else
2385 {
2386 DBG(FUNC, PVT_FMT(_target, "disconnecting outgoing channel..."));
2387
2388 disconnected = command(KHOMP_LOG, CM_DISCONNECT);
2389 }
2390 }
2391 else
2392 {
2393 DBG(FUNC, PVT_FMT(_target, "already disconnected"));
2394 return true;
2395 }
2396
2397 if(answered)
2398 {
2399 indicateBusyUnlocked(SWITCH_CAUSE_USER_BUSY, disconnected);
2400 }
2401
2402 if (call()->_flags.check(Kflags::IS_INCOMING))
2403 {
2404 DBG(FUNC, PVT_FMT(_target, "disconnecting incoming channel..."));
2405 disconnected = command(KHOMP_LOG, CM_DISCONNECT);
2406 }
2407
2408 stopStream();
2409
2410 stopListen();
2411
2412 }
2413 catch (ScopedLockFailed & err)
2414 {
2415 LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
2416 return false;
2417 }
2418
2419
2420 DBG(FUNC, PVT_FMT(_target, "r"));
2421 return true;
2422 }
2423
commandHandler(CommandRequest & cmd)2424 bool Board::KhompPvt::commandHandler(CommandRequest &cmd)
2425 {
2426 DBG(STRM, PVT_FMT(target(), "c"));
2427
2428 bool ret = true;
2429
2430 switch(cmd.type())
2431 {
2432 case CommandRequest::COMMAND:
2433 switch(cmd.code())
2434 {
2435 case CommandRequest::CMD_CALL:
2436 break;
2437 case CommandRequest::CMD_ANSWER:
2438 ret = doChannelAnswer(cmd);
2439 break;
2440 case CommandRequest::CMD_HANGUP:
2441 ret = doChannelHangup(cmd);
2442 break;
2443 default:
2444 ret = false;
2445 }
2446 break;
2447
2448 case CommandRequest::ACTION:
2449 break;
2450
2451 default:
2452 ret = false;
2453 }
2454
2455 DBG(STRM, PVT_FMT(target(), "r"));
2456 return ret;
2457 }
2458
eventThread(void * void_evt)2459 int Board::eventThread(void *void_evt)
2460 {
2461 EventRequest evt(false);
2462 EventFifo * fifo = static_cast < ChanEventHandler * >(void_evt)->fifo();
2463 int devid = fifo->_device;
2464
2465 for(;;)
2466 {
2467 DBG(THRD, D("(d=%d) c") % devid);
2468 while(1)
2469 {
2470 try
2471 {
2472 evt = fifo->_buffer.consumer_start();
2473 break;
2474 }
2475 catch(...) //BufferEmpty & e
2476 {
2477 DBG(THRD, D("(d=%d) buffer empty") % devid);
2478
2479 fifo->_cond.wait();
2480
2481 if (fifo->_shutdown)
2482 return 0;
2483
2484 DBG(THRD, D("(d=%d) waked up!") % devid);
2485 }
2486 }
2487
2488 /*while (!fifo->_buffer.consume(evt))
2489 {
2490 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(d=%d) buffer empty\n", fifo->_device);
2491
2492 fifo->_cond.wait();
2493
2494 if (fifo->_shutdown)
2495 return 0;
2496
2497 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(d=%d) waked up!\n", fifo->_device);
2498 }*/
2499
2500 DBG(THRD, D("(d=%d) processing buffer...") % devid);
2501
2502 try
2503 {
2504 if(!board(devid)->eventHandler(evt.obj(), evt.event()))
2505 {
2506 LOG(ERROR, D("(d=%d) Error on event (%d) \"%s\"")
2507 % devid
2508 % evt.event()->Code
2509 % Globals::verbose.event(evt.obj(), evt.event()));
2510 }
2511 }
2512 catch (K3LAPITraits::invalid_device & invalid)
2513 {
2514 LOG(ERROR, D("invalid device on event '%s'")
2515 % Verbose::eventName(evt.event()->Code).c_str());
2516 }
2517
2518 fifo->_buffer.consumer_commit();
2519
2520 }
2521
2522 return 0;
2523 }
2524
commandThread(void * void_evt)2525 int Board::commandThread(void *void_evt)
2526 {
2527 CommandFifo * fifo = static_cast < ChanCommandHandler * >(void_evt)->fifo();
2528 int devid = fifo->_device;
2529
2530 for(;;)
2531 {
2532 CommandRequest cmd;
2533
2534 DBG(THRD, D("(d=%d) Command c") % devid);
2535
2536 while (!fifo->_buffer.consume(cmd))
2537 {
2538 DBG(THRD, D("(d=%d) Command buffer empty") % devid);
2539 fifo->_cond.wait();
2540
2541 if (fifo->_shutdown)
2542 return 0;
2543
2544 DBG(THRD, D("(d=%d) Command waked up!") % devid);
2545 }
2546
2547 DBG(THRD, D("(d=%d) Command processing buffer...") % devid);
2548
2549
2550 try
2551 {
2552 if(!get(devid, cmd.obj())->commandHandler(cmd))
2553 {
2554 LOG(ERROR, D("(d=%d) Error on command(%d)") % devid % cmd.code());
2555 }
2556 }
2557 catch (K3LAPITraits::invalid_channel & invalid)
2558 {
2559 LOG(ERROR, OBJ_FMT(devid,cmd.obj(), "invalid device on command '%d'") % cmd.code());
2560 }
2561
2562 }
2563
2564
2565 return 0;
2566 }
2567
2568 /* This is the callback function for API events. It selects the event *
2569 * on a switch and forwards to the real implementation. */
khompEventCallback(int32 obj,K3L_EVENT * e)2570 extern "C" int32 Kstdcall khompEventCallback(int32 obj, K3L_EVENT * e)
2571 {
2572 //if (K::Logger::Logg.classe(C_EVENT).enabled())
2573 // std::string msg = Globals::verbose.event (obj, e) + ".";
2574 LOGC(EVENT, FMT("%s.") % Globals::verbose.event(obj, e));
2575
2576 switch(e->Code)
2577 {
2578 case EV_WATCHDOG_COUNT:
2579 Board::kommuter.initialize(e);
2580 break;
2581 case EV_HARDWARE_FAIL:
2582 case EV_DISK_IS_FULL:
2583 case EV_CLIENT_RECONNECT:
2584 case EV_CLIENT_BUFFERED_AUDIOLISTENER_OVERFLOW:
2585 LOG(ERROR, D("Audio client buffered overflow"));
2586 break;
2587 case EV_CLIENT_AUDIOLISTENER_TIMEOUT:
2588 LOG(ERROR, "Timeout on audio listener, registering audio listener again");
2589 k3lRegisterAudioListener( NULL, khompAudioListener );
2590 break;
2591 default:
2592 try
2593 {
2594 EventRequest e_req(obj, e);
2595 Board::board(e->DeviceId)->chanEventHandler()->write(e_req);
2596 }
2597 catch (K3LAPITraits::invalid_device & err)
2598 {
2599 LOG(ERROR, D("Unable to get device: %d!") % err.device);
2600 return ksFail;
2601 }
2602 break;
2603 }
2604
2605 return ksSuccess;
2606 }
2607
2608