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_fxo.h"
45 #include "lock.h"
46 #include "logger.h"
47
makeCall(std::string params)48 int BoardFXO::KhompPvtFXO::makeCall(std::string params)
49 {
50 DBG(FUNC,PVT_FMT(_target, "(FXO) c"));
51
52 int ret = ksSuccess;
53
54 /* we always have audio */
55 call()->_flags.set(Kflags::HAS_PRE_AUDIO);
56
57 if(callFXO()->_call_info_drop == 0 && !callFXO()->_call_info_report)
58 {
59 command(KHOMP_LOG, CM_DISABLE_CALL_ANSWER_INFO);
60 }
61
62 if (!callFXO()->_pre_digits.empty())
63 {
64 /* Seize the line at local PABX. */
65
66 callFXO()->_flags.set(Kflags::CALL_WAIT_SEIZE);
67
68 if (!command(KHOMP_LOG, CM_SEIZE, call()->_orig_addr.c_str()))
69 return ksFail;
70
71 int timeout = 150;
72
73 if(!loopWhileFlagTimed(Kflags::CALL_WAIT_SEIZE, timeout))
74 return ksFail;
75
76 if (callFXO()->_flags.check(Kflags::CALL_WAIT_SEIZE) || (timeout <= 0))
77 return ksFail;
78
79 /* Grab line from local PABX. */
80
81 callFXO()->_flags.set(Kflags::WAIT_SEND_DTMF);
82
83 if (!command(KHOMP_LOG, CM_DIAL_DTMF, callFXO()->_pre_digits.c_str()))
84 return ksFail;
85
86 if(!loopWhileFlagTimed(Kflags::WAIT_SEND_DTMF, timeout))
87 return ksFail;
88
89 if (callFXO()->_flags.check(Kflags::WAIT_SEND_DTMF) || (timeout <= 0))
90 return ksFail;
91
92 /* Seize line from public central (works because the *
93 * continuous cadence is always detected by the k3l api. */
94
95 callFXO()->_flags.set(Kflags::CALL_WAIT_SEIZE);
96
97 if (!command(KHOMP_LOG, CM_SEIZE, call()->_orig_addr.c_str()))
98 return ksFail;
99
100 if(!loopWhileFlagTimed(Kflags::CALL_WAIT_SEIZE, timeout))
101 return ksFail;
102
103 if (callFXO()->_flags.check(Kflags::CALL_WAIT_SEIZE) || (timeout <= 0))
104 return ksFail;
105
106 /* we want the audio as soon as dialing ends */
107 callFXO()->_flags.set(Kflags::EARLY_RINGBACK);
108
109 if (!command(KHOMP_LOG, CM_DIAL_DTMF, call()->_dest_addr.c_str()))
110 return ksFail;
111 }
112 else
113 {
114 /* we want the audio as soon as dialing ends */
115 callFXO()->_flags.set(Kflags::EARLY_RINGBACK);
116
117
118 if(!call()->_orig_addr.empty())
119 params += STG(FMT(" orig_addr=\"%s\"") % _call->_orig_addr);
120
121
122 ret = KhompPvt::makeCall(params);
123
124 if(ret != ksSuccess)
125 {
126 LOG(ERROR, PVT_FMT(target(), "Fail on make call"));
127 }
128
129 call()->_cleanup_upon_hangup = (ret == ksInvalidParams);
130 }
131
132 DBG(FUNC,PVT_FMT(_target, "(FXO) r"));
133 return ret;
134 }
135
doChannelAnswer(CommandRequest & cmd)136 bool BoardFXO::KhompPvtFXO::doChannelAnswer(CommandRequest &cmd)
137 {
138 DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
139
140 bool ret = true;
141
142 try
143 {
144 ScopedPvtLock lock(this);
145
146 // is this a collect call?
147 bool has_recv_collect_call = _call->_collect_call;
148
149 if(has_recv_collect_call)
150 DBG(FUNC, PVT_FMT(target(), "receive a collect call"));
151
152 if(call()->_flags.check(Kflags::DROP_COLLECT))
153 DBG(FUNC, PVT_FMT(target(), "flag DROP_COLLECT == true"));
154
155 // do we have to drop collect calls?
156 bool has_drop_collect_call = call()->_flags.check(Kflags::DROP_COLLECT);
157
158 // do we have to drop THIS call?
159 bool do_drop_call = has_drop_collect_call && has_recv_collect_call;
160
161 if(!do_drop_call)
162 {
163 command(KHOMP_LOG, CM_CONNECT);
164 }
165
166 if(has_drop_collect_call)
167 {
168 if(has_recv_collect_call)
169 {
170 usleep(75000);
171
172 DBG(FUNC, PVT_FMT(target(), "disconnecting collect call doChannelAnswer FXO"));
173 command(KHOMP_LOG,CM_DISCONNECT);
174
175 // thou shalt not talk anymore!
176 stopListen();
177 stopStream();
178 }
179 else
180 {
181 DBG(FUNC, PVT_FMT(target(), "dropping collect call at doChannelAnswer FXO"));
182 command(KHOMP_LOG, CM_DROP_COLLECT_CALL);
183 }
184 }
185
186 ret = KhompPvt::doChannelAnswer(cmd);
187
188 }
189 catch (ScopedLockFailed & err)
190 {
191 LOG(ERROR, PVT_FMT(_target,"(FXO) r (unable to lock %s!)") % err._msg.c_str() );
192 return false;
193 }
194
195 DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
196
197 return ret;
198 }
199
onNewCall(K3L_EVENT * e)200 bool BoardFXO::KhompPvtFXO::onNewCall(K3L_EVENT *e)
201 {
202 DBG(FUNC,PVT_FMT(_target,"(FXO) c"));
203
204 bool ret = true;
205
206 try
207 {
208 ScopedPvtLock lock(this);
209
210 /* we always have audio */
211 call()->_flags.set(Kflags::HAS_PRE_AUDIO);
212
213 ret = KhompPvt::onNewCall(e);
214
215 if(!ret)
216 return false;
217
218 startListen();
219 startStream();
220
221 }
222 catch(ScopedLockFailed & err)
223 {
224 LOG(ERROR, PVT_FMT(target(), "(FXO) r (unable to lock %s!)") % err._msg.c_str() );
225 return false;
226 }
227
228 DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
229
230 return ret;
231 }
232
onDisconnect(K3L_EVENT * e)233 bool BoardFXO::KhompPvtFXO::onDisconnect(K3L_EVENT *e)
234 {
235 DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
236
237 bool ret = true;
238
239 try
240 {
241 ScopedPvtLock lock(this);
242
243 command(KHOMP_LOG, CM_DISCONNECT);
244
245 ret = KhompPvt::onDisconnect(e);
246
247 }
248 catch (ScopedLockFailed & err)
249 {
250 LOG(ERROR, PVT_FMT(target(), "(FXO) r (unable to lock %s!)") % err._msg.c_str() );
251 return false;
252 }
253
254 DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
255
256 return ret;
257 }
258
onChannelRelease(K3L_EVENT * e)259 bool BoardFXO::KhompPvtFXO::onChannelRelease(K3L_EVENT *e)
260 {
261 DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
262
263 bool ret = true;
264
265 try
266 {
267 ScopedPvtLock lock(this);
268
269 if (call()->_flags.check(Kflags::FAX_SENDING))
270 {
271 DBG(FUNC, PVT_FMT(_target, "stopping fax tx"));
272 _fax->stopFaxTX();
273 }
274 else if (call()->_flags.check(Kflags::FAX_RECEIVING))
275 {
276 DBG(FUNC, PVT_FMT(_target, "stopping fax rx"));
277 _fax->stopFaxRX();
278 }
279
280 command(KHOMP_LOG, CM_ENABLE_CALL_ANSWER_INFO);
281
282 ret = KhompPvt::onChannelRelease(e);
283 }
284 catch(ScopedLockFailed & err)
285 {
286 LOG(ERROR, PVT_FMT(target(), "(FXO) r (unable to lock %s!)") % err._msg.c_str() );
287 return false;
288 }
289
290 DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
291 return ret;
292 }
293
onCallSuccess(K3L_EVENT * e)294 bool BoardFXO::KhompPvtFXO::onCallSuccess(K3L_EVENT *e)
295 {
296 DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
297
298 bool ret = true;
299
300 try
301 {
302 ScopedPvtLock lock(this);
303
304 ret = KhompPvt::onCallSuccess(e);
305
306 if (call()->_pre_answer)
307 {
308 dtmfSuppression(Opt::_options._out_of_band_dtmfs() && !call()->_flags.check(Kflags::FAX_DETECTED));
309
310 startListen();
311 startStream();
312 switch_channel_mark_pre_answered(getFSChannel());
313 }
314 }
315 catch (ScopedLockFailed & err)
316 {
317 LOG(ERROR, PVT_FMT(_target, "(FXO) r (unable to lock %s!)") % err._msg.c_str() );
318 return false;
319 }
320 catch (Board::KhompPvt::InvalidSwitchChannel & err)
321 {
322 LOG(ERROR, PVT_FMT(target(), "(FXO) r (%s)") % err._msg.c_str() );
323 return false;
324 }
325
326 DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
327
328 return ret;
329 }
330
onCallFail(K3L_EVENT * e)331 bool BoardFXO::KhompPvtFXO::onCallFail(K3L_EVENT *e)
332 {
333 bool ret = true;
334 try
335 {
336 ScopedPvtLock lock(this);
337
338 command(KHOMP_LOG, CM_DISCONNECT);
339
340 setHangupCause(causeFromCallFail(e->AddInfo), true);
341
342 ret = KhompPvt::onCallFail(e);
343
344 }
345 catch (ScopedLockFailed & err)
346 {
347 LOG(ERROR, PVT_FMT(target(), "unable to lock %s!") % err._msg.c_str() );
348 return false;
349 }
350
351 return ret;
352 }
353
onAudioStatus(K3L_EVENT * e)354 bool BoardFXO::KhompPvtFXO::onAudioStatus(K3L_EVENT *e)
355 {
356 DBG(STRM, PVT_FMT(_target, "(FXO) c"));
357
358 try
359 {
360 //ScopedPvtLock lock(this);
361
362 if(e->AddInfo == kmtFax)
363 {
364 DBG(STRM, PVT_FMT(_target, "Fax detected"));
365
366 /* hadn't we did this already? */
367 bool already_detected = call()->_flags.check(Kflags::FAX_DETECTED);
368
369 time_t time_was = call()->_call_statistics->_base_time;
370 time_t time_now = time(NULL);
371
372 bool detection_timeout = (time_now > (time_was + (time_t) (Opt::_options._fax_adjustment_timeout())));
373
374 BEGIN_CONTEXT
375 {
376 ScopedPvtLock lock(this);
377
378 /* already adjusted? do not adjust again. */
379 if (already_detected || detection_timeout)
380 break;
381
382 if (callFXO()->_call_info_drop != 0 || callFXO()->_call_info_report)
383 {
384 /* we did not detected fax yet, send answer info! */
385 setAnswerInfo(Board::KhompPvt::CI_FAX);
386
387 if (callFXO()->_call_info_drop & Board::KhompPvt::CI_FAX)
388 {
389 /* fastest way to force a disconnection */
390 command(KHOMP_LOG,CM_DISCONNECT);//,SCE_HIDE);
391 }
392 }
393
394 if (Opt::_options._auto_fax_adjustment())
395 {
396 DBG(FUNC, PVT_FMT(_target, "communication will be adjusted for fax!"));
397 _fax->adjustForFax();
398 }
399 }
400 END_CONTEXT
401
402 if (!already_detected)
403 {
404 ScopedPvtLock lock(this);
405
406 /* adjust the flag */
407 call()->_flags.set(Kflags::FAX_DETECTED);
408 }
409 }
410 }
411 catch (ScopedLockFailed & err)
412 {
413 LOG(ERROR, PVT_FMT(_target, "(FXO) r (unable to lock %s!)") % err._msg.c_str() );
414 return false;
415 }
416
417 bool ret = KhompPvt::onAudioStatus(e);
418
419 DBG(STRM, PVT_FMT(_target, "(FXO) r"));
420
421 return ret;
422 }
423
onSeizeSuccess(K3L_EVENT * e)424 bool BoardFXO::KhompPvtFXO::onSeizeSuccess(K3L_EVENT *e)
425 {
426 DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
427
428 try
429 {
430 ScopedPvtLock lock(this);
431
432 callFXO()->_flags.clear(Kflags::CALL_WAIT_SEIZE);
433
434 }
435 catch (ScopedLockFailed & err)
436 {
437 LOG(ERROR, PVT_FMT(_target, "(FXO) r (unable to lock %s!)") % err._msg.c_str() );
438 return false;
439 }
440
441 DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
442
443 return true;
444 }
445
onDtmfDetected(K3L_EVENT * e)446 bool BoardFXO::KhompPvtFXO::onDtmfDetected(K3L_EVENT *e)
447 {
448 DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
449
450 bool ret = true;
451
452 try
453 {
454 ScopedPvtLock lock(this);
455
456 if (callFXO()->_flags.check(Kflags::WAIT_SEND_DTMF) ||
457 callFXO()->_flags.check(Kflags::CALL_WAIT_SEIZE))
458 {
459 /* waiting digit or seize means DEADLOCK if we try to
460 * queue something below. */
461 DBG(FUNC, PVT_FMT(_target, "not queueing dtmf, waiting stuff!"));
462 return true;
463 }
464
465 ret = KhompPvt::onDtmfDetected(e);
466 }
467 catch (ScopedLockFailed & err)
468 {
469 LOG(ERROR, PVT_FMT(_target, "(FXO) r (unable to lock %s!)") % err._msg.c_str() );
470 return false;
471 }
472
473 DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
474
475 return ret;
476 }
477
onDtmfSendFinish(K3L_EVENT * e)478 bool BoardFXO::KhompPvtFXO::onDtmfSendFinish(K3L_EVENT *e)
479 {
480 DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
481
482 bool ret = true;
483
484 try
485 {
486 ScopedPvtLock lock(this);
487
488 ret = KhompPvt::onDtmfSendFinish(e);
489
490 if (callFXO()->_flags.check(Kflags::EARLY_RINGBACK))
491 {
492 callFXO()->_flags.clear(Kflags::EARLY_RINGBACK);
493
494 /* start grabbing */
495 startListen();
496
497 /* activate resources early... */
498 bool fax_detected = callFXO()->_flags.check(Kflags::FAX_DETECTED);
499
500 bool res_out_of_band_dtmf = Opt::_options._suppression_delay() && Opt::_options._out_of_band_dtmfs() && !fax_detected;
501 bool res_echo_cancellator = Opt::_options._echo_canceller() && !fax_detected;
502 bool res_auto_gain_cntrol = Opt::_options._auto_gain_control() && !fax_detected;
503
504 if (!call()->_flags.check(Kflags::KEEP_DTMF_SUPPRESSION))
505 dtmfSuppression(res_out_of_band_dtmf);
506
507 if (!call()->_flags.check(Kflags::KEEP_ECHO_CANCELLATION))
508 echoCancellation(res_echo_cancellator);
509
510 if (!call()->_flags.check(Kflags::KEEP_AUTO_GAIN_CONTROL))
511 autoGainControl(res_auto_gain_cntrol);
512
513 /* start sending audio if wanted so */
514 if (Opt::_options._fxo_send_pre_audio())
515 startStream();
516
517 //TODO: Verificar isso aqui
518 if (call()->_pre_answer)
519 {
520 /* tell the user we are answered! */
521 switch_channel_mark_answered(getFSChannel());
522 //pvt->signal_state(AST_CONTROL_ANSWER);
523 }
524 else
525 {
526 /* are we ringing, now? lets try this way! */
527 switch_channel_mark_ring_ready(getFSChannel());
528 //pvt->signal_state(AST_CONTROL_RINGING);
529 }
530 }
531 }
532 catch (ScopedLockFailed & err)
533 {
534 LOG(ERROR, PVT_FMT(_target, "(FXO) r (unable to lock %s!)") % err._msg.c_str() );
535 return false;
536 }
537 catch(Board::KhompPvt::InvalidSwitchChannel & err)
538 {
539 LOG(ERROR, PVT_FMT(_target, "(FXO) r (no valid channel: %s)") % err._msg.c_str());
540 return false;
541 }
542
543 DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
544
545 return ret;
546 }
547
onCallAnswerInfo(K3L_EVENT * e)548 bool BoardFXO::KhompPvtFXO::onCallAnswerInfo(K3L_EVENT *e)
549 {
550 DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
551 try
552 {
553 ScopedPvtLock lock(this);
554
555 int info_code = -1;
556
557 switch (e->AddInfo)
558 {
559 case kcsiCellPhoneMessageBox:
560 info_code = CI_MESSAGE_BOX;
561 break;
562 case kcsiHumanAnswer:
563 info_code = CI_HUMAN_ANSWER;
564 break;
565 case kcsiAnsweringMachine:
566 info_code = CI_ANSWERING_MACHINE;
567 break;
568 case kcsiCarrierMessage:
569 info_code = CI_CARRIER_MESSAGE;
570 break;
571 case kcsiUnknown:
572 info_code = CI_UNKNOWN;
573 break;
574 default:
575 DBG(FUNC, PVT_FMT(_target, "got an unknown call answer info '%d', ignoring...") % e->AddInfo);
576 break;
577 }
578
579 if (info_code != -1)
580 {
581 if (callFXO()->_call_info_report)
582 {
583 //TODO: HOW WE TREAT THAT
584 // make the channel export this
585 setAnswerInfo(info_code);
586 }
587
588 if (callFXO()->_call_info_drop & info_code)
589 {
590 command(KHOMP_LOG,CM_DISCONNECT);
591 }
592 }
593 }
594 catch (ScopedLockFailed & err)
595 {
596 LOG(ERROR, PVT_FMT(_target,"(FXO) r (unable to lock %s!)") % err._msg.c_str() );
597 return false;
598 }
599
600 DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
601 return true;
602 }
603
application(ApplicationType type,switch_core_session_t * session,const char * data)604 bool BoardFXO::KhompPvtFXO::application(ApplicationType type, switch_core_session_t * session, const char *data)
605 {
606 switch(type)
607 {
608 case FAX_ADJUST:
609 return _fax->adjustForFax();
610 case FAX_SEND:
611 return _fax->sendFax(session, data);
612 case FAX_RECEIVE:
613 return _fax->receiveFax(session, data);
614 case USER_TRANSFER:
615 return _transfer->userTransfer(session, data);
616 default:
617 return KhompPvt::application(type, session, data);
618 }
619
620 return true;
621 }
622
setupConnection()623 bool BoardFXO::KhompPvtFXO::setupConnection()
624 {
625 if(!call()->_flags.check(Kflags::IS_INCOMING) && !call()->_flags.check(Kflags::IS_OUTGOING))
626 {
627 DBG(FUNC,PVT_FMT(_target, "Channel already disconnected"));
628 return false;
629 }
630
631 callFXO()->_flags.clear(Kflags::CALL_WAIT_SEIZE);
632 callFXO()->_flags.clear(Kflags::WAIT_SEND_DTMF);
633
634 /* if received some disconnect from 'drop collect call'
635 feature of some pbx, then leave the call rock and rolling */
636 //Board::board(_target.device)->_timers.del(callFXO()->_idx_disconnect);
637
638 bool fax_detected = callFXO()->_flags.check(Kflags::FAX_DETECTED) || (callFXO()->_var_fax_adjust == T_TRUE);
639
640 bool res_out_of_band_dtmf = (call()->_var_dtmf_state == T_UNKNOWN || fax_detected ?
641 Opt::_options._suppression_delay() && Opt::_options._out_of_band_dtmfs() && !fax_detected : (call()->_var_dtmf_state == T_TRUE));
642
643 bool res_echo_cancellator = (call()->_var_echo_state == T_UNKNOWN || fax_detected ?
644 Opt::_options._echo_canceller() && !fax_detected : (call()->_var_echo_state == T_TRUE));
645
646 bool res_auto_gain_cntrol = (call()->_var_gain_state == T_UNKNOWN || fax_detected ?
647 Opt::_options._auto_gain_control() && !fax_detected : (call()->_var_gain_state == T_TRUE));
648
649 if (!call()->_flags.check(Kflags::REALLY_CONNECTED))
650 {
651 obtainRX(res_out_of_band_dtmf);
652
653 /* esvazia buffers de leitura/escrita */
654 cleanupBuffers();
655
656 if (!call()->_flags.check(Kflags::KEEP_DTMF_SUPPRESSION))
657 dtmfSuppression(res_out_of_band_dtmf);
658
659 if (!call()->_flags.check(Kflags::KEEP_ECHO_CANCELLATION))
660 echoCancellation(res_echo_cancellator);
661
662 if (!call()->_flags.check(Kflags::KEEP_AUTO_GAIN_CONTROL))
663 autoGainControl(res_auto_gain_cntrol);
664
665 startListen(false);
666
667 startStream();
668
669 DBG(FUNC, PVT_FMT(_target, "(FXO) Audio callbacks initialized successfully"));
670 }
671
672 return KhompPvt::setupConnection();
673 }
674
autoGainControl(bool enable)675 bool BoardFXO::KhompPvtFXO::autoGainControl(bool enable)
676 {
677 bool ret = KhompPvt::autoGainControl(enable);
678
679 /* enable this AGC also, can be very useful */
680 ret &= command(KHOMP_LOG, (enable ? CM_ENABLE_PLAYER_AGC : CM_DISABLE_PLAYER_AGC));
681 return ret;
682 }
683
setAnswerInfo(int answer_info)684 void BoardFXO::KhompPvtFXO::setAnswerInfo(int answer_info)
685 {
686 const char * value = answerInfoToString(answer_info);
687
688 if (value == NULL)
689 {
690 DBG(FUNC, PVT_FMT(_target,"signaled unknown call answer info '%d', using 'Unknown'...") % answer_info);
691 value = "Unknown";
692 }
693
694 DBG(FUNC,PVT_FMT(_target,"KCallAnswerInfo: %s") % value);
695
696 try
697 {
698 setFSChannelVar("KCallAnswerInfo", value);
699 }
700 catch(Board::KhompPvt::InvalidSwitchChannel & err)
701 {
702 LOG(ERROR,PVT_FMT(_target,"Cannot obtain the channel variable: %s") % err._msg.c_str());
703 }
704 }
705
indicateBusyUnlocked(int cause,bool sent_signaling)706 bool BoardFXO::KhompPvtFXO::indicateBusyUnlocked(int cause, bool sent_signaling)
707 {
708 DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
709
710 if(!KhompPvt::indicateBusyUnlocked(cause, sent_signaling))
711 {
712 DBG(FUNC, PVT_FMT(_target, "(FXO) r (false)"));
713 return false;
714 }
715
716 if(call()->_flags.check(Kflags::IS_INCOMING))
717 {
718 /* already connected or sent signaling... */
719 mixer(KHOMP_LOG, 1, kmsGenerator, kmtBusy);
720
721 if(!call()->_flags.check(Kflags::CONNECTED) && !sent_signaling)
722 {
723 /* we are talking about branches, not trunks */
724 command(KHOMP_LOG, CM_CONNECT);
725 callFXO()->_busy_disconnect = Board::board(_target.device)->_timers.add(Opt::_options._fxo_busy_disconnection(), &BoardFXO::KhompPvtFXO::busyDisconnect, this);
726 }
727 }
728 else if(call()->_flags.check(Kflags::IS_OUTGOING))
729 {
730 /* already connected or sent signaling... */
731 mixer(KHOMP_LOG, 1, kmsGenerator, kmtBusy);
732 }
733
734 DBG(FUNC,PVT_FMT(_target, "(FXO) r"));
735 return true;
736 }
737
busyDisconnect(Board::KhompPvt * pvt)738 void BoardFXO::KhompPvtFXO::busyDisconnect(Board::KhompPvt * pvt)
739 {
740 DBG(FUNC, PVT_FMT(pvt->target(), "Disconnecting FXO"));
741
742 try
743 {
744 ScopedPvtLock lock(pvt);
745 pvt->command(KHOMP_LOG, CM_DISCONNECT);
746 }
747 catch (...)
748 {
749 LOG(ERROR, PVT_FMT(pvt->target(), "unable to lock the pvt !"));
750 }
751 }
752
reportFailToReceive(int fail_code)753 void BoardFXO::KhompPvtFXO::reportFailToReceive(int fail_code)
754 {
755 KhompPvt::reportFailToReceive(fail_code);
756
757 command(KHOMP_LOG, CM_CONNECT);
758 command(KHOMP_LOG, CM_DISCONNECT);
759 }
760
validContexts(MatchExtension::ContextListType & contexts,std::string extra_context)761 bool BoardFXO::KhompPvtFXO::validContexts(
762 MatchExtension::ContextListType & contexts, std::string extra_context)
763 {
764 DBG(FUNC,PVT_FMT(_target,"(FXO) c"));
765
766 if(!_group_context.empty())
767 {
768 contexts.push_back(_group_context);
769 }
770
771 contexts.push_back(Opt::_options._context_fxo());
772 contexts.push_back(Opt::_options._context2_fxo());
773
774 for (MatchExtension::ContextListType::iterator i = contexts.begin(); i != contexts.end(); i++)
775 {
776 replaceTemplate((*i), "CC", _target.object);
777 }
778
779 bool ret = Board::KhompPvt::validContexts(contexts,extra_context);
780
781 DBG(FUNC,PVT_FMT(_target,"(FXO) r"));
782
783 return ret;
784 }
785
isOK()786 bool BoardFXO::KhompPvtFXO::isOK()
787 {
788 try
789 {
790 ScopedPvtLock lock(this);
791
792 K3L_CHANNEL_STATUS status;
793
794 if (k3lGetDeviceStatus (_target.device, _target.object + ksoChannel, &status, sizeof (status)) != ksSuccess)
795 return false;
796
797 return (status.AddInfo == kfcsEnabled);
798 }
799 catch (ScopedLockFailed & err)
800 {
801 LOG(ERROR, PVT_FMT(target(), "unable to lock %s!") % err._msg.c_str() );
802 }
803
804 return false;
805 }
806
sendDtmf(std::string digit)807 bool BoardFXO::KhompPvtFXO::sendDtmf(std::string digit)
808 {
809 if(_transfer->checkUserXferUnlocked(digit))
810 {
811 DBG(FUNC, PVT_FMT(target(), "started (or waiting for) an user xfer"));
812 return true;
813 }
814
815 bool ret = KhompPvt::sendDtmf(callFXO()->_digits_buffer);
816
817 callFXO()->_digits_buffer.clear();
818
819 return ret;
820 }
821
822