1 /*
2 * Copyright (C) 2002-2003 Fhg Fokus (inband detector code)
3 * Copyright (C) 2005 Andriy I Pylypenko
4 * Copyright (C) 2007 iptego GmbH
5 *
6 * This file is part of SEMS, a free SIP media server.
7 *
8 * SEMS is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version. This program is released under
12 * the GPL with the additional exemption that compiling, linking,
13 * and/or using OpenSSL is allowed.
14 *
15 * For a license to use the SEMS software under conditions
16 * other than those described here, or to purchase support for this
17 * software, please contact iptel.org by e-mail at the following addresses:
18 * info@iptel.org
19 *
20 * SEMS is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 */
29 #include "AmDtmfDetector.h"
30 #include "AmSession.h"
31 #include "log.h"
32
33 #include <arpa/inet.h>
34 #include <netinet/in.h>
35 #include <math.h>
36 #include <sys/time.h>
37
38 // per RFC this is 5000ms, but in reality then
39 // one needs to wait 5 sec on the first keypress
40 // (e.g. due to a bug on recent snoms)
41 #define MAX_INFO_DTMF_LENGTH 1000
42
43 //
44 // AmDtmfEventQueue methods
45 //
AmDtmfEventQueue(AmDtmfDetector * handler)46 AmDtmfEventQueue::AmDtmfEventQueue(AmDtmfDetector *handler)
47 : AmEventQueue(handler), m_detector(handler)
48 {
49 }
50
processEvents()51 void AmDtmfEventQueue::processEvents()
52 {
53 AmDtmfDetector *local_handler = reinterpret_cast<AmDtmfDetector *>(handler);
54 local_handler->checkTimeout();
55 AmEventQueue::processEvents();
56 }
57
putDtmfAudio(const unsigned char * buf,int size,unsigned long long system_ts)58 void AmDtmfEventQueue::putDtmfAudio(const unsigned char *buf, int size, unsigned long long system_ts)
59 {
60 m_detector->putDtmfAudio(buf, size, system_ts);
61 }
62
63 //
64 // AmSipDtmfEvent methods
65 //
AmSipDtmfEvent(const string & request_body)66 AmSipDtmfEvent::AmSipDtmfEvent(const string& request_body)
67 : AmDtmfEvent(Dtmf::SOURCE_SIP)
68 {
69 parseRequestBody(request_body);
70 }
71
parseRequestBody(const string & request_body)72 void AmSipDtmfEvent::parseRequestBody(const string& request_body)
73 {
74 string::size_type start = 0;
75 string::size_type stop = 0;
76 while ((stop = request_body.find('\n', start)) != string::npos)
77 {
78 parseLine(request_body.substr(start, stop - start));
79 start = stop + 1;
80 }
81 if (start < request_body.length())
82 {
83 // last chunk was not ended with '\n'
84 parseLine(request_body.substr(start, string::npos));
85 }
86 }
87
parseLine(const string & line)88 void AmSipDtmfEvent::parseLine(const string& line)
89 {
90 static const string KeySignal("Signal=");
91 static const string KeyDuration("Duration=");
92
93 if (line.length() > KeySignal.length() &&
94 line.substr(0, KeySignal.length()) == KeySignal)
95 {
96 string event(line.substr(KeySignal.length(), string::npos));
97 switch (event.c_str()[0])
98 {
99 case '*':
100 m_event = 10;
101 break;
102 case '#':
103 m_event = 11;
104 break;
105 case 'A':
106 case 'a':
107 m_event = 12;
108 break;
109 case 'B':
110 case 'b':
111 m_event = 13;
112 break;
113 case 'C':
114 case 'c':
115 m_event = 14;
116 break;
117 case 'D':
118 case 'd':
119 m_event = 15;
120 break;
121 default:
122 m_event = atol(event.c_str());
123 }
124 }
125 else if (line.length() > KeyDuration.length() &&
126 line.substr(0, KeyDuration.length()) == KeyDuration)
127 {
128 m_duration_msec = atol(line.substr(KeyDuration.length(), string::npos).c_str());
129 if (m_duration_msec > MAX_INFO_DTMF_LENGTH)
130 m_duration_msec = MAX_INFO_DTMF_LENGTH;
131
132 }
133 }
134
135 //
136 // AmRtpDtmfEvent methods
137 //
AmRtpDtmfEvent(const dtmf_payload_t * payload,int sample_rate,unsigned int ts)138 AmRtpDtmfEvent::AmRtpDtmfEvent(const dtmf_payload_t *payload, int sample_rate, unsigned int ts)
139 : AmDtmfEvent(Dtmf::SOURCE_RTP)
140 {
141 m_duration_msec = ntohs(payload->duration) * 1000 / sample_rate;
142 m_e = payload->e;
143 m_volume = payload->volume;
144 m_event = payload->event;
145 m_ts = ts;
146 // RFC 2833:
147 // R: This field is reserved for future use. The sender MUST set it
148 // to zero, the receiver MUST ignore it.
149 // m_r = payload->r;
150 }
151
152 //
153 // AmSipDtmfDetector methods
154 //
AmSipDtmfDetector(AmKeyPressSink * keysink)155 AmSipDtmfDetector::AmSipDtmfDetector(AmKeyPressSink *keysink)
156 : m_keysink(keysink)
157 {
158 }
159
process(AmSipDtmfEvent * evt)160 void AmSipDtmfDetector::process(AmSipDtmfEvent *evt)
161 {
162 struct timeval start;
163 struct timeval stop;
164 gettimeofday(&start, NULL);
165 // stop = start + duration
166 memcpy(&stop, &start, sizeof(struct timeval));
167 stop.tv_usec += evt->duration() * 1000;
168 if (stop.tv_usec > 1000000)
169 {
170 ++stop.tv_sec;
171 stop.tv_usec -= 1000000;
172 }
173 m_keysink->registerKeyReleased(evt->event(), Dtmf::SOURCE_SIP, start, stop);
174 }
175
176 //
177 // AmDtmfDetector methods
178 //
AmDtmfDetector(AmDtmfSink * dtmf_sink)179 AmDtmfDetector::AmDtmfDetector(AmDtmfSink *dtmf_sink)
180 : m_dtmfSink(dtmf_sink), m_rtpDetector(this),
181 m_sipDetector(this),
182 m_inband_type(Dtmf::SEMSInternal), m_currentEvent(-1),
183 m_eventPending(false), m_current_eventid_i(false),
184 m_sipEventReceived(false),
185 m_inbandEventReceived(false),
186 m_rtpEventReceived(false)
187 {
188 //#ifndef USE_SPANDSP
189 // setInbandDetector(Dtmf::SEMSInternal, m_session->RTPStream()->getSampleRate());
190 //#else
191 // setInbandDetector(AmConfig::DefaultDTMFDetector, m_session->RTPStream()->getSampleRate());
192 //#endif
193 }
194
setInbandDetector(Dtmf::InbandDetectorType t,int sample_rate)195 void AmDtmfDetector::setInbandDetector(Dtmf::InbandDetectorType t, int sample_rate) {
196 #ifndef USE_SPANDSP
197 if (t == Dtmf::SpanDSP) {
198 ERROR("trying to use spandsp DTMF detector without support for it"
199 "recompile with -D USE_SPANDSP\n");
200 }
201 if (!m_inbandDetector.get())
202 m_inbandDetector.reset(new AmSemsInbandDtmfDetector(this, sample_rate));
203
204 return;
205 #else
206
207 if ((t != m_inband_type) || (!m_inbandDetector.get())) {
208 if (t == Dtmf::SEMSInternal) {
209 DBG("Setting internal DTMF detector\n");
210 m_inbandDetector.reset(new AmSemsInbandDtmfDetector(this, sample_rate));
211 } else { // if t == SpanDSP
212 DBG("Setting spandsp DTMF detector\n");
213 m_inbandDetector.reset(new AmSpanDSPInbandDtmfDetector(this, sample_rate));
214 }
215 m_inband_type = t;
216 }
217 #endif
218 }
219
220
process(AmEvent * evt)221 void AmDtmfDetector::process(AmEvent *evt)
222 {
223 AmDtmfEvent *event = dynamic_cast<AmDtmfEvent *>(evt);
224 if (NULL == event)
225 return;
226 switch (event->event_id)
227 {
228 case Dtmf::SOURCE_RTP:
229 m_rtpDetector.process(dynamic_cast<AmRtpDtmfEvent *>(event));
230 break;
231 // case AmDtmfEvent::INBAND:
232 // m_audioDetector.process(dynamic_cast<AmAudioDtmfEvent *>(event));
233 // break;
234 case Dtmf::SOURCE_SIP:
235 m_sipDetector.process(dynamic_cast<AmSipDtmfEvent *>(event));
236 break;
237 }
238 evt->processed = true;
239 }
240
flushKey(unsigned int event_id)241 void AmDtmfDetector::flushKey(unsigned int event_id) {
242 // flush the current key if it corresponds to the one with event_id
243 #ifdef EXCESSIVE_DTMF_DEBUGINFO
244 DBG("flushKey\n");
245 #endif
246 if (m_eventPending && m_current_eventid_i && event_id == m_current_eventid) {
247 #ifdef EXCESSIVE_DTMF_DEBUGINFO
248 DBG("flushKey - reportEvent()\n");
249 #endif
250 reportEvent();
251 }
252 }
253
registerKeyReleased(int event,Dtmf::EventSource source,const struct timeval & start,const struct timeval & stop,bool has_eventid,unsigned int event_id)254 void AmDtmfDetector::registerKeyReleased(int event, Dtmf::EventSource source,
255 const struct timeval& start,
256 const struct timeval& stop,
257 bool has_eventid, unsigned int event_id)
258 {
259 // Old event has not been sent yet
260 // push out it now
261 if ((m_eventPending && m_currentEvent != event) ||
262 (m_eventPending && has_eventid && m_current_eventid_i && (event_id != m_current_eventid))) {
263 #ifdef EXCESSIVE_DTMF_DEBUGINFO
264 DBG("event differs - reportEvent()\n");
265 #endif
266 reportEvent();
267 }
268
269 m_eventPending = true;
270 m_currentEvent = event;
271 if (has_eventid) {
272 m_current_eventid_i = true;
273 m_current_eventid = event_id;
274 }
275
276 if(timercmp(&start,&stop,<)){
277 memcpy(&m_startTime, &start, sizeof(struct timeval));
278 memcpy(&m_lastReportTime, &stop, sizeof(struct timeval));
279 }
280 else {
281 memcpy(&m_startTime, &stop, sizeof(struct timeval));
282 memcpy(&m_lastReportTime, &start, sizeof(struct timeval));
283 }
284 switch (source)
285 {
286 case Dtmf::SOURCE_SIP:
287 m_sipEventReceived = true;
288 break;
289 case Dtmf::SOURCE_RTP:
290 m_rtpEventReceived = true;
291 break;
292 case Dtmf::SOURCE_INBAND:
293 m_inbandEventReceived = true;
294 break;
295 default:
296 break;
297 }
298 }
299
registerKeyPressed(int event,Dtmf::EventSource type,bool has_eventid,unsigned int event_id)300 void AmDtmfDetector::registerKeyPressed(int event, Dtmf::EventSource type, bool has_eventid, unsigned int event_id)
301 {
302 #ifdef EXCESSIVE_DTMF_DEBUGINFO
303 DBG("registerKeyPressed(%d, .., %s, %u); m_eventPending=%s, m_currentEvent=%d, "
304 "m_current_eventid=%u,m_current_eventid_i=%s\n",
305 event, has_eventid?"true":"false", event_id, m_eventPending?"true":"false",
306 m_currentEvent, m_current_eventid, m_current_eventid_i?"true":"false");
307 #endif
308 struct timeval tm;
309 gettimeofday(&tm, NULL);
310
311 if (!m_eventPending)
312 {
313 m_eventPending = true;
314 m_currentEvent = event;
315 memcpy(&m_startTime, &tm, sizeof(struct timeval));
316 memcpy(&m_lastReportTime, &tm, sizeof(struct timeval));
317 }
318 else
319 {
320 // Old event has not been sent yet
321 // push out it now
322 if ((m_currentEvent != event) ||
323 (has_eventid && m_current_eventid_i && (event_id != m_current_eventid))) {
324 #ifdef EXCESSIVE_DTMF_DEBUGINFO
325 DBG("event differs - reportEvent() from key pressed\n");
326 #endif
327 reportEvent();
328 }
329
330 long delta_msec = (tm.tv_sec - m_lastReportTime.tv_sec) * 1000 +
331 (tm.tv_usec - m_lastReportTime.tv_usec) / 1000;
332 // SIP INFO can report stop time is in future so avoid changing
333 // m_lastReportTime during that period
334 if (delta_msec > 0)
335 memcpy(&m_lastReportTime, &tm, sizeof(struct timeval));
336
337
338 }
339
340 if (has_eventid) {
341 m_current_eventid_i = true;
342 m_current_eventid = event_id;
343 }
344 }
345
checkTimeout()346 void AmDtmfDetector::checkTimeout()
347 {
348 m_rtpDetector.checkTimeout();
349 if (m_eventPending)
350 {
351 if (m_sipEventReceived && m_rtpEventReceived && m_inbandEventReceived)
352 {
353 // all three methods triggered - do not wait until timeout
354 reportEvent();
355 }
356 else
357 {
358 // ... else wait until timeout
359 struct timeval tm;
360 gettimeofday(&tm, NULL);
361 long delta_msec = (tm.tv_sec - m_lastReportTime.tv_sec) * 1000 +
362 (tm.tv_usec - m_lastReportTime.tv_usec) / 1000;
363 if (delta_msec > WAIT_TIMEOUT)
364 reportEvent();
365 }
366 }
367 }
368
reportEvent()369 void AmDtmfDetector::reportEvent()
370 {
371 m_reportLock.lock();
372
373 if (m_eventPending) {
374 long duration = (m_lastReportTime.tv_sec - m_startTime.tv_sec) * 1000 +
375 (m_lastReportTime.tv_usec - m_startTime.tv_usec) / 1000;
376 m_dtmfSink->postDtmfEvent(new AmDtmfEvent(m_currentEvent, duration));
377 m_eventPending = false;
378 m_sipEventReceived = false;
379 m_rtpEventReceived = false;
380 m_inbandEventReceived = false;
381 m_current_eventid_i = false;
382 }
383
384 m_reportLock.unlock();
385 }
386
putDtmfAudio(const unsigned char * buf,int size,unsigned long long system_ts)387 void AmDtmfDetector::putDtmfAudio(const unsigned char *buf, int size, unsigned long long system_ts)
388 {
389 if (m_inbandDetector.get()) {
390 m_inbandDetector->streamPut(buf, size, system_ts);
391 } else {
392 DBG("warning: trying to put DTMF into non-initialized DTMF detector\n");
393 }
394 }
395
396 // AmRtpDtmfDetector methods
AmRtpDtmfDetector(AmKeyPressSink * keysink)397 AmRtpDtmfDetector::AmRtpDtmfDetector(AmKeyPressSink *keysink)
398 : m_keysink(keysink), m_eventPending(false), m_currentTS(0),
399 m_currentTS_i(false), m_packetCount(0), m_lastTS_i(false)
400 {
401 }
402
process(AmRtpDtmfEvent * evt)403 void AmRtpDtmfDetector::process(AmRtpDtmfEvent *evt)
404 {
405 if (evt && evt->volume() < 55) // From RFC 2833:
406 // The range of valid DTMF is from 0 to -36 dBm0 (must
407 // accept); lower than -55 dBm0 must be rejected (TR-TSY-000181,
408 // ITU-T Q.24A)
409 {
410 m_packetCount = 0; // reset idle packet counter
411
412 if (m_lastTS_i && m_lastTS == evt->ts()) {
413 // ignore events from past key press which was already reported
414 #ifdef EXCESSIVE_DTMF_DEBUGINFO
415 DBG("ignore RTP event ts ==%u\n", evt->ts());
416 #endif
417 return;
418 }
419
420 if (!m_eventPending)
421 {
422 #ifdef EXCESSIVE_DTMF_DEBUGINFO
423 DBG("new m_eventPending, event()==%d, ts=%u\n", evt->event(), evt->ts());
424 #endif
425 gettimeofday(&m_startTime, NULL);
426 m_eventPending = true;
427 m_currentEvent = evt->event();
428 m_currentTS = evt->ts();
429 m_currentTS_i = true;
430 }
431 else
432 {
433 #ifdef EXCESSIVE_DTMF_DEBUGINFO
434 DBG("RTP event, event()==%d, m_currentEvent == %d, m_currentTS_i=%s, "
435 "evt->ts=%u, m_currentTS=%u\n",
436 evt->event(), m_currentEvent, m_currentTS_i?"true":"false",
437 evt->ts(), m_currentTS);
438 #endif
439
440 if ((evt->event() != m_currentEvent) ||
441 (m_currentTS_i && (evt->ts() != m_currentTS)))
442 {
443 // Previous event does not end correctly so send out it now...
444 #ifdef EXCESSIVE_DTMF_DEBUGINFO
445 DBG("flushKey %u\n", m_currentTS);
446 #endif
447 m_keysink->flushKey(m_currentTS);
448 // ... and reinitialize to process current event
449 gettimeofday(&m_startTime, NULL);
450 m_eventPending = true;
451 m_currentEvent = evt->event();
452 m_currentTS = evt->ts();
453 m_currentTS_i = true;
454 }
455 }
456 #ifdef EXCESSIVE_DTMF_DEBUGINFO
457 DBG("registerKeyPressed %d, %u\n", m_currentEvent, m_currentTS);
458 #endif
459 m_keysink->registerKeyPressed(m_currentEvent, Dtmf::SOURCE_RTP, true, m_currentTS);
460 }
461 }
462
sendPending()463 void AmRtpDtmfDetector::sendPending()
464 {
465 if (m_eventPending)
466 {
467 struct timeval end_time;
468 gettimeofday(&end_time, NULL);
469 #ifdef EXCESSIVE_DTMF_DEBUGINFO
470 DBG("registerKeyReleased(%d, ... %u)\n", m_currentEvent, m_currentTS);
471 #endif
472 m_keysink->registerKeyReleased(m_currentEvent, Dtmf::SOURCE_RTP, m_startTime, end_time, true, m_currentTS);
473 m_eventPending = false;
474 m_currentTS_i = false;
475 m_lastTS = m_currentTS;
476 m_lastTS_i = true;
477 }
478 }
479
checkTimeout()480 void AmRtpDtmfDetector::checkTimeout()
481 {
482 if (m_eventPending && m_packetCount++ > MAX_PACKET_WAIT)
483 {
484 #ifdef EXCESSIVE_DTMF_DEBUGINFO
485 DBG("idle timeout ... sendPending()\n");
486 #endif
487 sendPending();
488 }
489 }
490
491 //
492 // AmInbandDtmfDetector methods
493
AmInbandDtmfDetector(AmKeyPressSink * keysink)494 AmInbandDtmfDetector::AmInbandDtmfDetector(AmKeyPressSink *keysink)
495 : m_keysink(keysink)
496 {
497 }
498
499 //
500 // -------------------------------------------------------------------------------------------
501 #define IVR_DTMF_ASTERISK 10
502 #define IVR_DTMF_HASH 11
503 #define IVR_DTMF_A 12
504 #define IVR_DTMF_B 13
505 #define IVR_DTMF_C 14
506 #define IVR_DTMF_D 15
507
508 /* the detector returns these values */
509
510 static int IVR_dtmf_matrix[4][4] =
511 {
512 { 1, 2, 3, IVR_DTMF_A},
513 { 4, 5, 6, IVR_DTMF_B},
514 { 7, 8, 9, IVR_DTMF_C},
515 {IVR_DTMF_ASTERISK, 0, IVR_DTMF_HASH, IVR_DTMF_D}
516 };
517
518
519 #define LOGRP 0
520 #define HIGRP 1
521
522 #define REL_DTMF_TRESH 4000 /* above this is dtmf */
523 #define REL_SILENCE_TRESH 200 /* below this is silence */
524 #define REL_AMP_BITS 9 /* bits per sample, reduced to avoid overflow */
525 #define PI 3.1415926
526 #define NELEMSOF(x) (sizeof(x)/sizeof(*x))
527
528 /** \brief DTMF tone filter type */
529 typedef struct {
530 int freq; /* frequency */
531 int grp; /* low/high group */
532 } dtmf_t;
533
534 static dtmf_t dtmf_tones[8] =
535 {
536 { 697, LOGRP},
537 { 770, LOGRP},
538 { 852, LOGRP},
539 { 941, LOGRP},
540 {1209, HIGRP},
541 {1336, HIGRP},
542 {1477, HIGRP},
543 {1633, HIGRP}
544 };
545
546 static char dtmf_matrix[4][4] =
547 {
548 {'1', '2', '3', 'A'},
549 {'4', '5', '6', 'B'},
550 {'7', '8', '9', 'C'},
551 {'*', '0', '#', 'D'}
552 };
553
AmSemsInbandDtmfDetector(AmKeyPressSink * keysink,int sample_rate)554 AmSemsInbandDtmfDetector::AmSemsInbandDtmfDetector(AmKeyPressSink *keysink, int sample_rate)
555 : AmInbandDtmfDetector(keysink),
556 SAMPLERATE(sample_rate),
557 m_last(' '),
558 m_idx(0),
559 m_count(0)
560 {
561 /* precalculate 2 * cos (2 PI k / N) */
562 for(unsigned i = 0; i < NELEMSOF(rel_cos2pik); i++) {
563 // FIXME: fixed samplerate. won't work for wideband
564 int k = (int)((double)dtmf_tones[i].freq * REL_DTMF_NPOINTS / SAMPLERATE + 0.5);
565 rel_cos2pik[i] = (int)(2 * 32768 * cos(2 * PI * k / REL_DTMF_NPOINTS));
566 }
567 }
~AmSemsInbandDtmfDetector()568 AmSemsInbandDtmfDetector::~AmSemsInbandDtmfDetector() {
569 }
570
571 /*
572 * Goertzel algorithm.
573 * See http://ptolemy.eecs.berkeley.edu/~pino/Ptolemy/papers/96/dtmf_ict/
574 * for more info.
575 */
576
isdn_audio_goertzel_relative()577 void AmSemsInbandDtmfDetector::isdn_audio_goertzel_relative()
578 {
579 int sk, sk1, sk2;
580
581 for (int k = 0; k < REL_NCOEFF; k++) {
582 // like m_buf, sk..sk2 are in (32-REL_AMP_BITS).REL_AMP_BITS fixed-point format
583 sk = sk1 = sk2 = 0;
584 for (int n = 0; n < REL_DTMF_NPOINTS; n++) {
585 sk = m_buf[n] + ((rel_cos2pik[k] * sk1) >> 15) - sk2;
586 sk2 = sk1;
587 sk1 = sk;
588 }
589 /* Avoid overflows */
590 sk >>= 1;
591 sk2 >>= 1;
592 /* compute |X(k)|**2 */
593 /* report overflows. This should not happen. */
594 /* Comment this out if desired */
595 /*if (sk < -32768 || sk > 32767)
596 DBG("isdn_audio: dtmf goertzel overflow, sk=%d\n", sk);
597 if (sk2 < -32768 || sk2 > 32767)
598 DBG("isdn_audio: dtmf goertzel overflow, sk2=%d\n", sk2);
599 */
600
601 // note that the result still is in (32-REL_AMP_BITS).REL_AMP_BITS format
602 m_result[k] =
603 ((sk * sk) >> REL_AMP_BITS) -
604 ((((rel_cos2pik[k] * sk) >> 15) * sk2) >> REL_AMP_BITS) +
605 ((sk2 * sk2) >> REL_AMP_BITS);
606 }
607 }
608
609
isdn_audio_eval_dtmf_relative()610 void AmSemsInbandDtmfDetector::isdn_audio_eval_dtmf_relative()
611 {
612 int silence;
613 int grp[2];
614 char what;
615 int thresh;
616
617 grp[LOGRP] = grp[HIGRP] = -1;
618 silence = 0;
619 thresh = 0;
620
621 for (int i = 0; i < REL_NCOEFF; i++)
622 {
623 if (m_result[i] > REL_DTMF_TRESH) {
624 if (m_result[i] > thresh)
625 thresh = m_result[i];
626 }
627 else if (m_result[i] < REL_SILENCE_TRESH)
628 silence++;
629 }
630 if (silence == REL_NCOEFF)
631 what = ' ';
632 else {
633 if (thresh > 0) {
634 thresh = thresh >> 4; /* touchtones must match within 12 dB */
635
636 for (int i = 0; i < REL_NCOEFF; i++) {
637 if (m_result[i] < thresh)
638 continue; /* ignore */
639
640 /* good level found. This is allowed only one time per group */
641 if (i < REL_NCOEFF / 2) {
642 /* lowgroup*/
643 if (grp[LOGRP] >= 0) {
644 // Bad. Another tone found. */
645 grp[LOGRP] = -1;
646 break;
647 }
648 else
649 grp[LOGRP] = i;
650 }
651 else { /* higroup */
652 if (grp[HIGRP] >= 0) { // Bad. Another tone found. */
653 grp[HIGRP] = -1;
654 break;
655 }
656 else
657 grp[HIGRP] = i - REL_NCOEFF/2;
658 }
659 }
660
661 if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
662 what = dtmf_matrix[grp[LOGRP]][grp[HIGRP]];
663 m_lastCode = IVR_dtmf_matrix[grp[LOGRP]][grp[HIGRP]];
664
665 if (what != m_last)
666 {
667 m_startTime.tv_sec = m_last_ts / SAMPLERATE;
668 m_startTime.tv_usec = ((m_last_ts * 10000) / (SAMPLERATE/100))
669 % 1000000;
670 }
671 } else
672 what = '.';
673 }
674 else
675 what = '.';
676 }
677 if (what != ' ' && what != '.')
678 {
679 if (++m_count >= DTMF_INTERVAL)
680 {
681 m_keysink->registerKeyPressed(m_lastCode, Dtmf::SOURCE_INBAND);
682 }
683 }
684 else
685 {
686 if (m_last != ' ' && m_last != '.' && m_count >= DTMF_INTERVAL)
687 {
688 struct timeval stop;
689 stop.tv_sec = m_last_ts / SAMPLERATE;
690 stop.tv_usec = ((m_last_ts * 10000) / (SAMPLERATE/100)) % 1000000;
691 m_keysink->registerKeyReleased(m_lastCode, Dtmf::SOURCE_INBAND, m_startTime, stop);
692 }
693 m_count = 0;
694 }
695 m_last = what;
696 }
697
isdn_audio_calc_dtmf(const signed short * buf,int len,unsigned int ts)698 void AmSemsInbandDtmfDetector::isdn_audio_calc_dtmf(const signed short* buf, int len, unsigned int ts)
699 {
700 int c;
701
702 if(m_idx == 0) m_last_ts = ts;
703
704 while (len) {
705 c = (len < ((int)NELEMSOF(m_buf) - m_idx)) ? len : (NELEMSOF(m_buf) - m_idx);
706
707 if (c <= 0) break;
708
709 for (int i = 0; i < c; i++) {
710 // m_buf is in (32-REL_AMP_BITS).REL_AMP_BITS fixed-point format, the samples
711 // itself are in the last REL_AMP_BITS bits, i.e. they go from -1.0 to +1.0
712 // (or more exactly from -1.0 to ~+0.996)
713 m_buf[m_idx++] = (*buf++) >> (15 - REL_AMP_BITS);
714 }
715 if (m_idx == NELEMSOF(m_buf)) {
716 isdn_audio_goertzel_relative();
717 isdn_audio_eval_dtmf_relative();
718 m_idx = 0;
719 m_last_ts = ts + c;
720 }
721 len -= c;
722 ts += c;
723 }
724 }
725
streamPut(const unsigned char * samples,unsigned int size,unsigned long long system_ts)726 int AmSemsInbandDtmfDetector::streamPut(const unsigned char* samples, unsigned int size, unsigned long long system_ts)
727 {
728 unsigned long long user_ts =
729 system_ts * ((unsigned long long)SAMPLERATE / 100)
730 / (WALLCLOCK_RATE / 100);
731
732 isdn_audio_calc_dtmf((const signed short *)samples, size / 2, (unsigned int)user_ts);
733 return size;
734 }
735
736 #ifdef USE_SPANDSP
737
AmSpanDSPInbandDtmfDetector(AmKeyPressSink * keysink,int sample_rate)738 AmSpanDSPInbandDtmfDetector::AmSpanDSPInbandDtmfDetector(AmKeyPressSink *keysink, int sample_rate)
739 : AmInbandDtmfDetector(keysink)
740 {
741 #ifdef HAVE_OLD_SPANDSP_CALLBACK
742 rx_state = (dtmf_rx_state_t*)malloc(sizeof(dtmf_rx_state_t));
743 if (NULL == rx_state) {
744 throw string("error allocating memory for DTMF detector\n");
745 }
746 #else
747 rx_state = NULL;
748 #endif
749 rx_state = dtmf_rx_init(rx_state, NULL /* dtmf_rx_callback */, (void*)this);
750
751 if (rx_state==NULL) {
752 throw string("error allocating memory for DTMF detector\n");
753 }
754 dtmf_rx_set_realtime_callback(rx_state, tone_report_func, (void*)this);
755 }
756
~AmSpanDSPInbandDtmfDetector()757 AmSpanDSPInbandDtmfDetector::~AmSpanDSPInbandDtmfDetector() {
758 // not in 0.0.4:
759 // dtmf_rx_release(rx_state);
760 #ifdef HAVE_OLD_SPANDSP_CALLBACK
761 free(rx_state);
762 #else
763 dtmf_rx_free(rx_state);
764 #endif
765 }
766
streamPut(const unsigned char * samples,unsigned int size,unsigned long long system_ts)767 int AmSpanDSPInbandDtmfDetector::streamPut(const unsigned char* samples, unsigned int size, unsigned long long system_ts) {
768 dtmf_rx(rx_state, (const int16_t*) samples, size/2);
769 return size;
770 }
771
772 #ifndef HAVE_OLD_SPANDSP_CALLBACK
tone_report_func(void * user_data,int code,int level,int delay)773 void AmSpanDSPInbandDtmfDetector::tone_report_func(void *user_data, int code, int level, int delay) {
774 AmSpanDSPInbandDtmfDetector* o = (AmSpanDSPInbandDtmfDetector*)user_data;
775 o->tone_report_f(code, level, delay);
776 }
777 #else
tone_report_func(void * user_data,int code)778 void AmSpanDSPInbandDtmfDetector::tone_report_func(void *user_data, int code) {
779 AmSpanDSPInbandDtmfDetector* o = (AmSpanDSPInbandDtmfDetector*)user_data;
780 o->tone_report_f(code, 0, 0);
781 }
782 #endif
783
tone_report_f(int code,int level,int delay)784 void AmSpanDSPInbandDtmfDetector::tone_report_f(int code, int level, int delay) {
785 // DBG("spandsp reports tone %c, %d, %d\n", code, level, delay);
786 if (code) { // key pressed
787 gettimeofday(&key_start, NULL);
788 m_lastCode = code;
789 // don't report key press - otherwise reported twice
790 // m_keysink->registerKeyPressed(char2int(code), Dtmf::SOURCE_INBAND);
791 } else { // released
792 struct timeval now;
793 gettimeofday(&now, NULL);
794 m_keysink->registerKeyReleased(char2int(m_lastCode), Dtmf::SOURCE_INBAND, key_start, now);
795 }
796 }
797
798 // uh, ugly
char2int(char code)799 int AmSpanDSPInbandDtmfDetector::char2int(char code) {
800 if (code>='0' && code<='9')
801 return code-'0';
802 if (code == '#')
803 return IVR_DTMF_HASH;
804 if (code == '*')
805 return IVR_DTMF_ASTERISK;
806
807 if (code >= 'A' && code <= 'D')
808 return code-'A';
809 return code;
810 }
811
812 // unused - we use realtime reporting functions instead
813 // void AmSpanDSPInbandDtmfDetector::dtmf_rx_callback(void* user_data, const char* digits, int len) {
814 // AmSpanDSPInbandDtmfDetector* o = (AmSpanDSPInbandDtmfDetector*)user_data;
815 // o->dtmf_rx_f(digits, len);
816 // }
817
818 // void AmSpanDSPInbandDtmfDetector::dtmf_rx_f(const char* digits, int len) {
819 // DBG("dtmf_rx_callback len=%d\n", len);
820
821 // for (int i=0;i<len;i++)
822 // DBG("char %c\n", digits[i]);
823 // }
824 #endif // USE_SPANDSP
825