1 /*
2 * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3 * Copyright (C) 2005-2016, Anthony Minessale II <anthm@freeswitch.org>
4 *
5 * Version: MPL 1.1
6 *
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
11 *
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
16 *
17 * The Original Code is FreeSWITCH mod_spandsp.
18 *
19 * The Initial Developer of the Original Code is
20 * Massimo Cetra <devel@navynet.it>
21 *
22 * Portions created by the Initial Developer are Copyright (C)
23 * the Initial Developer. All Rights Reserved.
24 *
25 * Contributor(s):
26 *
27 * Brian West <brian@freeswitch.org>
28 * Anthony Minessale II <anthm@freeswitch.org>
29 * Steve Underwood <steveu@coppice.org>
30 * Antonio Gallo <agx@linux.it>
31 * Christopher M. Rienzo <chris@rienzo.com>
32 * mod_spandsp_dsp.c -- dsp applications provided by SpanDSP
33 *
34 */
35
36 #include "mod_spandsp.h"
37
38 #define TDD_LEAD 10
39
40 typedef struct {
41 switch_core_session_t *session;
42 v18_state_t *tdd_state;
43 int head_lead;
44 int tail_lead;
45 } switch_tdd_t;
46
tdd_encode_callback(switch_media_bug_t * bug,void * user_data,switch_abc_type_t type)47 static switch_bool_t tdd_encode_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
48 {
49 switch_tdd_t *pvt = (switch_tdd_t *) user_data;
50 switch_frame_t *frame = NULL;
51 switch_bool_t r = SWITCH_TRUE;
52
53 switch (type) {
54 case SWITCH_ABC_TYPE_INIT: {
55 break;
56 }
57 case SWITCH_ABC_TYPE_CLOSE:
58 if (pvt->tdd_state) {
59 v18_free(pvt->tdd_state);
60 }
61 break;
62 case SWITCH_ABC_TYPE_WRITE_REPLACE:
63 if ((frame = switch_core_media_bug_get_write_replace_frame(bug))) {
64 int len;
65
66 if (pvt->tail_lead) {
67 if (!--pvt->tail_lead) {
68 r = SWITCH_FALSE;
69 }
70 memset(frame->data, 0, frame->datalen);
71
72 } else if (pvt->head_lead) {
73 pvt->head_lead--;
74 memset(frame->data, 0, frame->datalen);
75 } else {
76 len = v18_tx(pvt->tdd_state, frame->data, frame->samples);
77
78 if (!len) {
79 pvt->tail_lead = TDD_LEAD;
80 }
81 }
82
83 switch_core_media_bug_set_write_replace_frame(bug, frame);
84 }
85 break;
86 case SWITCH_ABC_TYPE_WRITE:
87 default:
88 break;
89 }
90
91 return r;
92 }
93
spandsp_stop_tdd_encode_session(switch_core_session_t * session)94 switch_status_t spandsp_stop_tdd_encode_session(switch_core_session_t *session)
95 {
96 switch_media_bug_t *bug;
97 switch_channel_t *channel = switch_core_session_get_channel(session);
98
99 if ((bug = switch_channel_get_private(channel, "tdd_encode"))) {
100 switch_channel_set_private(channel, "tdd_encode", NULL);
101 switch_core_media_bug_remove(session, &bug);
102 return SWITCH_STATUS_SUCCESS;
103 }
104 return SWITCH_STATUS_FALSE;
105 }
106
put_text_msg(void * user_data,const uint8_t * msg,int len)107 static void put_text_msg(void *user_data, const uint8_t *msg, int len)
108 {
109 switch_tdd_t *pvt = (switch_tdd_t *) user_data;
110 switch_event_t *event, *clone;
111 switch_channel_t *channel = switch_core_session_get_channel(pvt->session);
112 switch_core_session_t *other_session;
113
114
115 switch_channel_add_variable_var_check(channel, "tdd_messages", (char *)msg, SWITCH_FALSE, SWITCH_STACK_PUSH);
116
117
118 if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_TDD_RECV_MESSAGE) == SWITCH_STATUS_SUCCESS) {
119
120 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", "mod_spandsp");
121 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", "tdd");
122 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "subject", "TDD MESSAGE");
123 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "TDD-Data", (char *)msg);
124 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(pvt->session));
125 switch_event_add_body(event, "%s\n\n", (char *)msg);
126
127 if (switch_core_session_get_partner(pvt->session, &other_session) == SWITCH_STATUS_SUCCESS) {
128
129 if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
130 switch_core_session_receive_event(other_session, &clone);
131 }
132
133 if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
134 switch_core_session_queue_event(other_session, &clone);
135 }
136
137 switch_core_session_rwunlock(other_session);
138
139 } else if (switch_channel_test_flag(channel, CF_QUEUE_TEXT_EVENTS)) {
140
141 if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
142 switch_core_session_queue_event(pvt->session, &clone);
143 }
144 }
145
146 switch_event_fire(&event);
147
148
149 }
150
151 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "%s got TDD Message [%s]\n", switch_channel_get_name(channel), (char *)msg);
152
153 }
154
get_v18_mode(switch_core_session_t * session)155 static int get_v18_mode(switch_core_session_t *session)
156 {
157 switch_channel_t *channel = switch_core_session_get_channel(session);
158 const char *var;
159 int r = V18_MODE_5BIT_4545;
160
161 if ((var = switch_channel_get_variable(channel, "v18_mode"))) {
162 if (!strcasecmp(var, "5BIT_45") || !strcasecmp(var, "baudot")) {
163 r = V18_MODE_5BIT_4545;
164 } else if (!strcasecmp(var, "5BIT_50")) {
165 r = V18_MODE_5BIT_50;
166 } else if (!strcasecmp(var, "DTMF")) {
167 r = V18_MODE_DTMF;
168 } else if (!strcasecmp(var, "EDT")) {
169 r = V18_MODE_EDT;
170 } else if (!strcasecmp(var, "BELL103") || !strcasecmp(var, "ascii")) {
171 r = V18_MODE_BELL103;
172 } else if (!strcasecmp(var, "V23VIDEOTEX")) {
173 r = V18_MODE_V23VIDEOTEX;
174 } else if (!strcasecmp(var, "V21TEXTPHONE")) {
175 r = V18_MODE_V21TEXTPHONE;
176 } else if (!strcasecmp(var, "V18TEXTPHONE")) {
177 r = V18_MODE_V18TEXTPHONE;
178 }
179 }
180
181 return r;
182 }
183
184
spandsp_tdd_send_session(switch_core_session_t * session,const char * text)185 switch_status_t spandsp_tdd_send_session(switch_core_session_t *session, const char *text)
186 {
187 v18_state_t *tdd_state;
188 switch_frame_t *read_frame, write_frame = { 0 };
189 uint8_t write_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
190 switch_codec_implementation_t read_impl = { 0 };
191 switch_codec_t write_codec = { 0 };
192 switch_channel_t *channel = switch_core_session_get_channel(session);
193 switch_status_t status;
194
195 switch_core_session_get_read_impl(session, &read_impl);
196
197 if (switch_core_codec_init(&write_codec,
198 "L16",
199 NULL,
200 NULL,
201 read_impl.actual_samples_per_second,
202 read_impl.microseconds_per_packet / 1000,
203 read_impl.number_of_channels,
204 SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,
205 switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) {
206 write_frame.data = write_buf;
207 write_frame.buflen = sizeof(write_buf);
208 write_frame.datalen = read_impl.decoded_bytes_per_packet;
209 write_frame.samples = write_frame.datalen / 2;
210 write_frame.codec = &write_codec;
211 switch_core_session_set_read_codec(session, &write_codec);
212 } else {
213 return SWITCH_STATUS_FALSE;
214 }
215
216 tdd_state = v18_init(NULL, TRUE, get_v18_mode(session), V18_AUTOMODING_GLOBAL, put_text_msg, NULL);
217
218
219 v18_put(tdd_state, text, -1);
220
221 while(switch_channel_ready(channel)) {
222 status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
223
224 if (!SWITCH_READ_ACCEPTABLE(status)) {
225 break;
226 }
227
228
229 if (!v18_tx(tdd_state, (void *)write_buf, write_frame.samples)) {
230 break;
231 }
232
233 if (switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
234 break;
235 }
236
237 }
238
239 switch_core_codec_destroy(&write_codec);
240 switch_core_session_set_read_codec(session, NULL);
241
242 v18_free(tdd_state);
243
244 return SWITCH_STATUS_SUCCESS;
245 }
246
247
spandsp_tdd_encode_session(switch_core_session_t * session,const char * text)248 switch_status_t spandsp_tdd_encode_session(switch_core_session_t *session, const char *text)
249 {
250 switch_channel_t *channel = switch_core_session_get_channel(session);
251 switch_media_bug_t *bug;
252 switch_status_t status;
253 switch_tdd_t *pvt;
254 //switch_codec_implementation_t read_impl = { 0 };
255
256 //switch_core_session_get_read_impl(session, &read_impl);
257
258 if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt)))) {
259 return SWITCH_STATUS_MEMERR;
260 }
261
262 pvt->session = session;
263 pvt->tdd_state = v18_init(NULL, TRUE, get_v18_mode(session), V18_AUTOMODING_GLOBAL, put_text_msg, NULL);
264 pvt->head_lead = TDD_LEAD;
265
266 v18_put(pvt->tdd_state, text, -1);
267
268 if ((status = switch_core_media_bug_add(session, "spandsp_tdd_encode", NULL,
269 tdd_encode_callback, pvt, 0, SMBF_WRITE_REPLACE | SMBF_NO_PAUSE, &bug)) != SWITCH_STATUS_SUCCESS) {
270 v18_free(pvt->tdd_state);
271 return status;
272 }
273
274 switch_channel_set_private(channel, "tdd_encode", bug);
275
276 return SWITCH_STATUS_SUCCESS;
277 }
278
279
280
281 ///XXX
tdd_decode_callback(switch_media_bug_t * bug,void * user_data,switch_abc_type_t type)282 static switch_bool_t tdd_decode_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
283 {
284 switch_tdd_t *pvt = (switch_tdd_t *) user_data;
285 switch_frame_t *frame = NULL;
286 switch_bool_t r = SWITCH_TRUE;
287
288 switch (type) {
289 case SWITCH_ABC_TYPE_INIT: {
290 break;
291 }
292 case SWITCH_ABC_TYPE_CLOSE:
293 if (pvt->tdd_state) {
294 v18_free(pvt->tdd_state);
295 }
296 break;
297 case SWITCH_ABC_TYPE_READ_REPLACE:
298 if ((frame = switch_core_media_bug_get_read_replace_frame(bug))) {
299
300 v18_rx(pvt->tdd_state, frame->data, frame->samples);
301
302 switch_core_media_bug_set_read_replace_frame(bug, frame);
303 }
304 break;
305 case SWITCH_ABC_TYPE_WRITE:
306 default:
307 break;
308 }
309
310 return r;
311 }
312
spandsp_stop_tdd_decode_session(switch_core_session_t * session)313 switch_status_t spandsp_stop_tdd_decode_session(switch_core_session_t *session)
314 {
315 switch_media_bug_t *bug;
316 switch_channel_t *channel = switch_core_session_get_channel(session);
317
318 if ((bug = switch_channel_get_private(channel, "tdd_decode"))) {
319 switch_channel_set_private(channel, "tdd_decode", NULL);
320 switch_core_media_bug_remove(session, &bug);
321 return SWITCH_STATUS_SUCCESS;
322 }
323 return SWITCH_STATUS_FALSE;
324 }
325
spandsp_tdd_decode_session(switch_core_session_t * session)326 switch_status_t spandsp_tdd_decode_session(switch_core_session_t *session)
327 {
328 switch_channel_t *channel = switch_core_session_get_channel(session);
329 switch_media_bug_t *bug;
330 switch_status_t status;
331 switch_tdd_t *pvt;
332 //switch_codec_implementation_t read_impl = { 0 };
333
334 //switch_core_session_get_read_impl(session, &read_impl);
335
336 if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt)))) {
337 return SWITCH_STATUS_MEMERR;
338 }
339
340 pvt->session = session;
341 pvt->tdd_state = v18_init(NULL, FALSE, get_v18_mode(session), V18_AUTOMODING_GLOBAL, put_text_msg, pvt);
342
343 if ((status = switch_core_media_bug_add(session, "spandsp_tdd_decode", NULL,
344 tdd_decode_callback, pvt, 0, SMBF_READ_REPLACE | SMBF_NO_PAUSE, &bug)) != SWITCH_STATUS_SUCCESS) {
345 v18_free(pvt->tdd_state);
346 return status;
347 }
348
349 switch_channel_set_private(channel, "tdd_decode", bug);
350
351 return SWITCH_STATUS_SUCCESS;
352 }
353
354 ///XXX
355
356 typedef struct {
357 switch_core_session_t *session;
358 dtmf_rx_state_t *dtmf_detect;
359 int verbose;
360 char last_digit;
361 uint32_t samples;
362 uint32_t last_digit_end;
363 uint32_t digit_begin;
364 uint32_t min_dup_digit_spacing;
365 int twist;
366 int reverse_twist;
367 int filter_dialtone;
368 int threshold;
369 switch_audio_resampler_t *resampler;
370 } switch_inband_dtmf_t;
371
spandsp_dtmf_rx_realtime_callback(void * user_data,int code,int level,int duration)372 static void spandsp_dtmf_rx_realtime_callback(void *user_data, int code, int level, int duration)
373 {
374 switch_inband_dtmf_t *pvt = (switch_inband_dtmf_t *)user_data;
375 char digit = (char)code;
376 pvt->samples += duration;
377 if (digit) {
378 /* prevent duplicate DTMF */
379 if (digit != pvt->last_digit || (pvt->samples - pvt->last_digit_end) > pvt->min_dup_digit_spacing) {
380 switch_dtmf_t dtmf = {0};
381 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "DTMF BEGIN DETECTED: [%c]\n", digit);
382 pvt->last_digit = digit;
383 dtmf.digit = digit;
384 dtmf.duration = switch_core_default_dtmf_duration(0);
385 dtmf.source = SWITCH_DTMF_INBAND_AUDIO;
386 switch_channel_queue_dtmf(switch_core_session_get_channel(pvt->session), &dtmf);
387 pvt->digit_begin = pvt->samples;
388 } else {
389 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "DUP DTMF DETECTED: [%c]\n", digit);
390 pvt->last_digit_end = pvt->samples;
391 }
392 } else {
393 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "DTMF END DETECTED: [%c], duration = %u ms\n", pvt->last_digit, (pvt->samples - pvt->digit_begin) / 8);
394 pvt->last_digit_end = pvt->samples;
395 }
396 }
397
inband_dtmf_callback(switch_media_bug_t * bug,void * user_data,switch_abc_type_t type)398 static switch_bool_t inband_dtmf_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
399 {
400 switch_inband_dtmf_t *pvt = (switch_inband_dtmf_t *) user_data;
401 switch_frame_t *frame = NULL;
402 switch_core_session_t *session = switch_core_media_bug_get_session(bug);
403 switch_codec_implementation_t read_impl = { 0 };
404
405
406 switch (type) {
407 case SWITCH_ABC_TYPE_INIT: {
408 pvt->dtmf_detect = dtmf_rx_init(NULL, NULL, NULL);
409 span_log_set_message_handler(dtmf_rx_get_logging_state(pvt->dtmf_detect), mod_spandsp_log_message, pvt->session);
410 if (pvt->verbose) {
411 span_log_set_level(dtmf_rx_get_logging_state(pvt->dtmf_detect), SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
412 }
413 dtmf_rx_parms(pvt->dtmf_detect, pvt->filter_dialtone, (float)pvt->twist, (float)pvt->reverse_twist, (float)pvt->threshold);
414 dtmf_rx_set_realtime_callback(pvt->dtmf_detect, spandsp_dtmf_rx_realtime_callback, pvt);
415 break;
416 }
417 case SWITCH_ABC_TYPE_CLOSE:
418 if (pvt->dtmf_detect) {
419 dtmf_rx_free(pvt->dtmf_detect);
420 }
421
422 if (pvt->resampler) {
423 switch_resample_destroy(&pvt->resampler);
424 }
425
426 break;
427 case SWITCH_ABC_TYPE_READ_REPLACE:
428 if ((frame = switch_core_media_bug_get_read_replace_frame(bug))) {
429 int16_t data[SWITCH_RECOMMENDED_BUFFER_SIZE];
430 int datalen = frame->datalen;
431 int16_t *dp = frame->data;
432 int samples = frame->samples;
433
434 switch_core_session_get_read_impl(session, &read_impl);
435
436 if (read_impl.number_of_channels != 1 || read_impl.actual_samples_per_second != 8000) {
437 memcpy(data, frame->data, frame->datalen);
438 dp = data;
439 }
440
441 if (read_impl.number_of_channels != 1) {
442 uint32_t rlen = frame->datalen / 2 / read_impl.number_of_channels;
443
444 switch_mux_channels((int16_t *) dp, rlen, read_impl.number_of_channels, 1);
445 datalen = rlen * 2 * 1;
446 samples = datalen / 2;
447 }
448
449 if (read_impl.actual_samples_per_second != 8000) {
450 if (!pvt->resampler) {
451 if (switch_resample_create(&pvt->resampler,
452 read_impl.actual_samples_per_second,
453 8000,
454 8 * (read_impl.microseconds_per_packet / 1000) * 2,
455 SWITCH_RESAMPLE_QUALITY,
456 1) != SWITCH_STATUS_SUCCESS) {
457 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to allocate resampler\n");
458 return SWITCH_FALSE;
459 }
460 }
461
462
463
464 switch_resample_process(pvt->resampler, dp, (int) datalen / 2 / 1);
465 memcpy(dp, pvt->resampler->to, pvt->resampler->to_len * 2 * 1);
466 samples = pvt->resampler->to_len;
467 }
468
469 dtmf_rx(pvt->dtmf_detect, dp, samples);
470 switch_core_media_bug_set_read_replace_frame(bug, frame);
471 }
472 break;
473 case SWITCH_ABC_TYPE_WRITE:
474 default:
475 break;
476 }
477
478 return SWITCH_TRUE;
479 }
480
spandsp_stop_inband_dtmf_session(switch_core_session_t * session)481 switch_status_t spandsp_stop_inband_dtmf_session(switch_core_session_t *session)
482 {
483 switch_media_bug_t *bug;
484 switch_channel_t *channel = switch_core_session_get_channel(session);
485
486 if ((bug = switch_channel_get_private(channel, "dtmf"))) {
487 switch_channel_set_private(channel, "dtmf", NULL);
488 switch_core_media_bug_remove(session, &bug);
489 return SWITCH_STATUS_SUCCESS;
490 }
491 return SWITCH_STATUS_FALSE;
492 }
493
spandsp_inband_dtmf_session(switch_core_session_t * session)494 switch_status_t spandsp_inband_dtmf_session(switch_core_session_t *session)
495 {
496 switch_channel_t *channel = switch_core_session_get_channel(session);
497 switch_media_bug_t *bug;
498 switch_status_t status;
499 switch_inband_dtmf_t *pvt;
500 switch_codec_implementation_t read_impl = { 0 };
501 const char *value;
502
503 switch_core_session_get_read_impl(session, &read_impl);
504
505 if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt)))) {
506 return SWITCH_STATUS_MEMERR;
507 }
508
509 pvt->session = session;
510
511 /* get detector params */
512 pvt->min_dup_digit_spacing = 0;
513 value = switch_channel_get_variable(channel, "min_dup_digit_spacing_ms");
514 if (!zstr(value) && switch_is_number(value)) {
515 int val = atoi(value) * 8; /* convert from ms to samples */
516 if (val < 0) {
517 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "min_dup_digit_spacing_ms must be >= 0\n");
518 } else {
519 pvt->min_dup_digit_spacing = val;
520 }
521 }
522
523 pvt->threshold = -100;
524 value = switch_channel_get_variable(channel, "spandsp_dtmf_rx_threshold");
525 if (!zstr(value) && switch_is_number(value)) {
526 int val = atoi(value);
527 if (val < -99) {
528 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "spandsp_dtmf_rx_threshold must be >= -99 dBm0\n");
529 } else {
530 pvt->threshold = val;
531 }
532 }
533
534 pvt->twist = -1;
535 value = switch_channel_get_variable(channel, "spandsp_dtmf_rx_twist");
536 if (!zstr(value) && switch_is_number(value)) {
537 int val = atoi(value);
538 if (val < 0) {
539 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "spandsp_dtmf_rx_twist must be >= 0 dB\n");
540 } else {
541 pvt->twist = val;
542 }
543 }
544
545 pvt->reverse_twist = -1;
546 value = switch_channel_get_variable(channel, "spandsp_dtmf_rx_reverse_twist");
547 if (!zstr(value) && switch_is_number(value)) {
548 int val = atoi(value);
549 if (val < 0) {
550 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "spandsp_dtmf_rx_reverse_twist must be >= 0 dB\n");
551 } else {
552 pvt->reverse_twist = val;
553 }
554 }
555
556 pvt->filter_dialtone = -1;
557 value = switch_channel_get_variable(channel, "spandsp_dtmf_rx_filter_dialtone");
558 if (switch_true(value)) {
559 pvt->filter_dialtone = 1;
560 } else if (switch_false(value)) {
561 pvt->filter_dialtone = 0;
562 }
563
564 if ((value = switch_channel_get_variable(channel, "dtmf_verbose"))) {
565 pvt->verbose = switch_true(value);
566 }
567
568 if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
569 return SWITCH_STATUS_FALSE;
570 }
571
572 if ((status = switch_core_media_bug_add(session, "spandsp_dtmf_detect", NULL,
573 inband_dtmf_callback, pvt, 0, SMBF_READ_REPLACE | SMBF_NO_PAUSE | SMBF_ONE_ONLY, &bug)) != SWITCH_STATUS_SUCCESS) {
574 return status;
575 }
576
577 switch_channel_set_private(channel, "dtmf", bug);
578
579 return SWITCH_STATUS_SUCCESS;
580 }
581
582
583
584 /* private channel data */
585 #define TONE_PRIVATE "mod_tone_detect_bug"
586
587
588
589 /**
590 * Tone detector
591 *
592 * Performs detection for the tones described by the descriptor.
593 */
594 struct tone_detector {
595 /** The tones to look for */
596 tone_descriptor_t *descriptor;
597
598 /** The detector */
599 super_tone_rx_state_t *spandsp_detector;
600
601 /** The detected tone */
602 int detected_tone;
603
604 /** The debug level */
605 int debug;
606
607 /** The session that owns this detector */
608 switch_core_session_t *session;
609 };
610 typedef struct tone_detector tone_detector_t;
611
612 static switch_status_t tone_detector_create(switch_core_session_t *session, tone_detector_t **detector, tone_descriptor_t *descriptor);
613 static switch_bool_t tone_detector_process_buffer(tone_detector_t *detector, void *data, unsigned int len, const char **key);
614 static void tone_detector_destroy(tone_detector_t *detector);
615
616 static switch_bool_t callprogress_detector_process_buffer(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type);
617
618 /**
619 * Allocate the tone descriptor
620 *
621 * @param descriptor the descriptor to create
622 * @param name the descriptor name
623 * @param memory_pool the pool to use
624 * @return SWITCH_STATUS_SUCCESS if successful
625 */
tone_descriptor_create(tone_descriptor_t ** descriptor,const char * name,switch_memory_pool_t * memory_pool)626 switch_status_t tone_descriptor_create(tone_descriptor_t **descriptor, const char *name, switch_memory_pool_t *memory_pool)
627 {
628 tone_descriptor_t *ldescriptor = NULL;
629 ldescriptor = switch_core_alloc(memory_pool, sizeof(tone_descriptor_t));
630 if (!ldescriptor) {
631 return SWITCH_STATUS_FALSE;
632 }
633 memset(ldescriptor, 0, sizeof(tone_descriptor_t));
634 ldescriptor->name = switch_core_strdup(memory_pool, name);
635 ldescriptor->spandsp_tone_descriptor = super_tone_rx_make_descriptor(NULL);
636 *descriptor = ldescriptor;
637 return SWITCH_STATUS_SUCCESS;
638 }
639
640 /**
641 * Destroy the tone descriptor
642 *
643 * @param descriptor the descriptor to create
644 * @return void
645 */
tone_descriptor_destroy(tone_descriptor_t * descriptor)646 void tone_descriptor_destroy(tone_descriptor_t *descriptor)
647 {
648 if (descriptor->spandsp_tone_descriptor) {
649 super_tone_rx_free_descriptor(descriptor->spandsp_tone_descriptor);
650 descriptor->spandsp_tone_descriptor = NULL;
651 }
652 }
653
654 /**
655 * Add a tone to the tone descriptor
656 *
657 * @param descriptor the tone descriptor
658 * @param key the tone key - this will be returned by the detector upon match
659 * @return the tone ID
660 */
tone_descriptor_add_tone(tone_descriptor_t * descriptor,const char * key)661 int tone_descriptor_add_tone(tone_descriptor_t *descriptor, const char *key)
662 {
663 int id = super_tone_rx_add_tone(descriptor->spandsp_tone_descriptor);
664 if (id >= MAX_TONES) {
665 return -1;
666 }
667 switch_set_string(descriptor->tone_keys[id], key);
668
669 if (id > descriptor->idx) {
670 descriptor->idx = id;
671 }
672
673 return id;
674 }
675
676 /**
677 * Add a tone element to the tone descriptor
678 *
679 * @param descriptor the tone descriptor
680 * @param tone_id the tone ID
681 * @param freq1 the first frequency (0 if none)
682 * @param freq2 the second frequency (0 if none)
683 * @param min the minimum tone duration in ms
684 * @param max the maximum tone duration in ms
685 * @return SWITCH_STATUS_SUCCESS if successful
686 */
tone_descriptor_add_tone_element(tone_descriptor_t * descriptor,int tone_id,int freq1,int freq2,int min,int max)687 switch_status_t tone_descriptor_add_tone_element(tone_descriptor_t *descriptor, int tone_id, int freq1, int freq2, int min, int max)
688 {
689 if (super_tone_rx_add_element(descriptor->spandsp_tone_descriptor, tone_id, freq1, freq2, min, max) == 0) {
690 return SWITCH_STATUS_SUCCESS;
691 }
692 return SWITCH_STATUS_FALSE;
693 }
694
695 /**
696 * Process tone report callback from spandsp
697 *
698 * @param user_data the tone_detector
699 * @param code the detected tone
700 * @param level unused
701 * @param delay unused
702 */
tone_report_callback(void * user_data,int code,int level,int delay)703 static void tone_report_callback(void *user_data, int code, int level, int delay)
704 {
705 tone_detector_t *detector = (tone_detector_t *)user_data;
706 if (detector->debug > 0) {
707 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(detector->session), SWITCH_LOG_DEBUG, "Tone report: code = %d, level = %d, delay = %d\n", code, level, delay);
708 }
709 detector->detected_tone = code;
710 }
711
712 /**
713 * Process tone segment report from spandsp (for debugging)
714 *
715 * @param user_data the tone_detector
716 * @param f1 the first frequency of the segment
717 * @param f2 the second frequency of the segment
718 * @param duration the duration of the segment
719 */
tone_segment_callback(void * user_data,int f1,int f2,int duration)720 static void tone_segment_callback(void *user_data, int f1, int f2, int duration)
721 {
722 tone_detector_t *detector = (tone_detector_t *)user_data;
723 if (detector->debug > 1) {
724 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(detector->session), SWITCH_LOG_DEBUG, "Tone segment: f1 = %d, f2 = %d, duration = %d\n", f1, f2, duration);
725 }
726 }
727
728 /**
729 * Duplicate the tone descriptor
730 *
731 * @param descriptor the descriptor to use
732 * @param memory_pool the pool to use
733 * @return pointer to a copy of descriptor
734 */
tone_descriptor_dup(tone_descriptor_t * descriptor,switch_memory_pool_t * pool)735 static tone_descriptor_t *tone_descriptor_dup(tone_descriptor_t *descriptor, switch_memory_pool_t *pool)
736 {
737 tone_descriptor_t *desc = NULL;
738 int t = 0, s = 0, tone_count = 0;
739
740 if (descriptor && pool) {
741 if (tone_descriptor_create(&desc, descriptor->name, pool) != SWITCH_STATUS_SUCCESS) {
742 return NULL;
743 }
744
745 tone_count = descriptor->idx + 1;
746
747 for (t = 0; t < tone_count; t++) {
748 int tone_id = tone_descriptor_add_tone(desc, descriptor->tone_keys[t]);
749 if (-1 != tone_id) {
750 int step = descriptor->spandsp_tone_descriptor->tone_segs[tone_id];
751 for (s = 0; s < step; s++) {
752 super_tone_rx_segment_t segment = descriptor->spandsp_tone_descriptor->tone_list[tone_id][s];
753 int f1 = (segment.f1 == -1 ? 0 : descriptor->spandsp_tone_descriptor->pitches[segment.f1][0]);
754 int f2 = (segment.f2 == -1 ? 0 : descriptor->spandsp_tone_descriptor->pitches[segment.f2][0]);
755 int min = segment.min_duration / 8;
756 int max = (segment.max_duration == 0x7FFFFFFF ? 0 : segment.max_duration / 8);
757 tone_descriptor_add_tone_element(desc, tone_id, f1, f2, min, max);
758 }
759 } else {
760 tone_descriptor_destroy(desc);
761 desc = NULL;
762 break;
763 }
764 }
765 }
766
767 return desc;
768 }
769
770 /**
771 * Allocate the tone detector
772 *
773 * @param session the session that owns the detector
774 * @param detector the detector to create
775 * @param descriptor the descriptor to use
776 * @param memory_pool the pool to use
777 * @return SWITCH_STATUS_SUCCESS if successful
778 */
tone_detector_create(switch_core_session_t * session,tone_detector_t ** detector,tone_descriptor_t * descriptor)779 static switch_status_t tone_detector_create(switch_core_session_t *session, tone_detector_t **detector, tone_descriptor_t *descriptor)
780 {
781 tone_detector_t *ldetector = switch_core_session_alloc(session, sizeof(tone_detector_t));
782
783 ldetector->descriptor = tone_descriptor_dup(descriptor, switch_core_session_get_pool(session));
784 ldetector->debug = spandsp_globals.tonedebug;
785 ldetector->session = session;
786 *detector = ldetector;
787 return SWITCH_STATUS_SUCCESS;
788 }
789
790 /**
791 * Initialize detector. Call when media bug starts detection
792 *
793 * @param detector the detector to initialize
794 */
tone_detector_init(tone_detector_t * detector)795 static void tone_detector_init(tone_detector_t *detector)
796 {
797 detector->spandsp_detector = super_tone_rx_init(NULL, detector->descriptor->spandsp_tone_descriptor, tone_report_callback, detector);
798 super_tone_rx_segment_callback(detector->spandsp_detector, tone_segment_callback);
799 }
800
801 /**
802 * Process the buffer looking for tones
803 *
804 * @param data the data to process
805 * @param len the amount of data to process
806 * @param key the found tone key
807 * @return SWITCH_TRUE if a tone was found
808 */
tone_detector_process_buffer(tone_detector_t * detector,void * data,unsigned int len,const char ** key)809 static switch_bool_t tone_detector_process_buffer(tone_detector_t *detector, void *data, unsigned int len, const char **key)
810 {
811 detector->detected_tone = -1;
812 super_tone_rx(detector->spandsp_detector, data, len);
813
814 if (detector->detected_tone > -1 && detector->detected_tone <= detector->descriptor->idx && detector->detected_tone < MAX_TONES) {
815 *key = detector->descriptor->tone_keys[detector->detected_tone];
816 return SWITCH_TRUE;
817 }
818 return SWITCH_FALSE;
819 }
820
821 /**
822 * Destroy the tone detector
823 * @param detector the detector to destroy
824 */
tone_detector_destroy(tone_detector_t * detector)825 static void tone_detector_destroy(tone_detector_t *detector)
826 {
827 if (detector) {
828 if (detector->spandsp_detector) {
829 super_tone_rx_release(detector->spandsp_detector);
830 super_tone_rx_free(detector->spandsp_detector);
831 detector->spandsp_detector = NULL;
832 }
833 if (detector->descriptor) {
834 tone_descriptor_destroy(detector->descriptor);
835 detector->descriptor = NULL;
836 }
837 }
838 }
839
840 /**
841 * Start call progress detection
842 *
843 * @param session the session to detect
844 * @param name of the descriptor to use
845 * @return SWITCH_STATUS_SUCCESS if successful
846 */
callprogress_detector_start(switch_core_session_t * session,const char * name)847 switch_status_t callprogress_detector_start(switch_core_session_t *session, const char *name)
848 {
849 switch_channel_t *channel = switch_core_session_get_channel(session);
850 tone_detector_t *detector = NULL;
851 tone_descriptor_t *descriptor = NULL;
852 switch_media_bug_t *bug = NULL;
853
854 /* are we already running? */
855 bug = switch_channel_get_private(channel, TONE_PRIVATE);
856 if (bug) {
857 return SWITCH_STATUS_FALSE;
858 }
859
860 switch_mutex_lock(spandsp_globals.mutex);
861 /* find the tone descriptor with the matching name and create the detector */
862 descriptor = switch_core_hash_find(spandsp_globals.tones, name);
863
864 if (!descriptor) {
865 switch_mutex_unlock(spandsp_globals.mutex);
866 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "no tone descriptor defined with name '%s'. Update configuration. \n", name);
867 return SWITCH_STATUS_FALSE;
868 }
869
870 tone_detector_create(session, &detector, descriptor);
871 switch_mutex_unlock(spandsp_globals.mutex);
872
873 /* start listening for tones */
874 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Starting tone detection for '%s'\n", name);
875 switch_core_media_bug_add(session, "spandsp_tone_detect", NULL,
876 callprogress_detector_process_buffer, detector, 0 /* stop time */, SMBF_READ_REPLACE, &bug);
877 if (!bug) {
878 return SWITCH_STATUS_FALSE;
879 }
880 switch_channel_set_private(channel, TONE_PRIVATE, bug);
881
882 return SWITCH_STATUS_SUCCESS;
883 }
884
885 /**
886 * Process a buffer of audio data for call progress tones
887 *
888 * @param bug the session's media bug
889 * @param user_data the detector
890 * @param type the type of data available from the bug
891 * @return SWITCH_TRUE
892 */
callprogress_detector_process_buffer(switch_media_bug_t * bug,void * user_data,switch_abc_type_t type)893 static switch_bool_t callprogress_detector_process_buffer(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
894 {
895 tone_detector_t *detector = (tone_detector_t *)user_data;
896 switch_core_session_t *session = detector->session;
897
898 switch(type) {
899 case SWITCH_ABC_TYPE_INIT:
900 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "initializing tone detector\n");
901 tone_detector_init(detector);
902 break;
903 case SWITCH_ABC_TYPE_READ_REPLACE:
904 {
905 switch_frame_t *frame;
906 const char *detected_tone = NULL;
907 if (!detector->spandsp_detector) {
908 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "detector is destroyed\n");
909 return SWITCH_FALSE;
910 }
911 if (!(frame = switch_core_media_bug_get_read_replace_frame(bug))) {
912 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "error reading frame\n");
913 return SWITCH_FALSE;
914 }
915 tone_detector_process_buffer(detector, frame->data, frame->samples, &detected_tone);
916 if (detected_tone) {
917 switch_event_t *event = NULL;
918 switch_channel_t *channel = switch_core_session_get_channel(session);
919 const char *execute_on_tone_var = switch_core_session_sprintf(session, "execute_on_spandsp_tone_detect_%s", detected_tone);
920 const char *api_on_tone_var = switch_core_session_sprintf(session, "api_on_spandsp_tone_detect_%s", detected_tone);
921 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "DETECTED TONE: %s\n", detected_tone);
922 switch_channel_execute_on(channel, execute_on_tone_var);
923 switch_channel_api_on(channel, api_on_tone_var);
924 if (switch_event_create(&event, SWITCH_EVENT_DETECTED_TONE) == SWITCH_STATUS_SUCCESS) {
925 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Detected-Tone", detected_tone);
926 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(session));
927 switch_channel_event_set_data(channel, event);
928 switch_event_fire(&event);
929 }
930 if (switch_true(switch_channel_get_variable(channel, "spandsp_tone_detect_stop_on_tone"))) {
931 /* all done */
932 return SWITCH_FALSE;
933 }
934 }
935 break;
936 }
937 case SWITCH_ABC_TYPE_CLOSE:
938 if (detector->spandsp_detector) {
939 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "destroying tone detector\n");
940 tone_detector_destroy(detector);
941 }
942 break;
943 default:
944 break;
945 }
946 return SWITCH_TRUE;
947 }
948
949 /**
950 * Stop call progress detection
951 * @param session the session to stop
952 * @return SWITCH_STATUS_SUCCESS if successful
953 */
callprogress_detector_stop(switch_core_session_t * session)954 switch_status_t callprogress_detector_stop(switch_core_session_t *session)
955 {
956 switch_channel_t *channel = switch_core_session_get_channel(session);
957 switch_media_bug_t *bug = switch_channel_get_private(channel, TONE_PRIVATE);
958 if (bug) {
959 switch_core_media_bug_remove(session, &bug);
960 switch_channel_set_private(channel, TONE_PRIVATE, NULL);
961 }
962 return SWITCH_STATUS_SUCCESS;
963 }
964
965 /**
966 * Called when FreeSWITCH loads the module
967 */
mod_spandsp_dsp_load(switch_loadable_module_interface_t ** module_interface,switch_memory_pool_t * pool)968 switch_status_t mod_spandsp_dsp_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool)
969 {
970 /* indicate that the module should continue to be loaded */
971 return SWITCH_STATUS_SUCCESS;
972 }
973
974 /**
975 * Called when FreeSWITCH stops the module
976 */
mod_spandsp_dsp_shutdown(void)977 void mod_spandsp_dsp_shutdown(void)
978 {
979 return;
980 }
981
982
983 /* For Emacs:
984 * Local Variables:
985 * mode:c
986 * indent-tabs-mode:t
987 * tab-width:4
988 * c-basic-offset:4
989 * End:
990 * For VIM:
991 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
992 */
993