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