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