FreeSWITCH API Documentation  1.7.0
switch_ivr_async.c
Go to the documentation of this file.
1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2015, 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 Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Anthony Minessale II <anthm@freeswitch.org>
27  * Michael Jerris <mike@jerris.com>
28  * Bret McDanel <bret AT 0xdecafbad dot com>
29  * Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC)
30  * Christopher M. Rienzo <chris@rienzo.com>
31  *
32  * switch_ivr_async.c -- IVR Library (async operations)
33  *
34  */
35 
36 #include <switch.h>
38 #include <speex/speex_preprocess.h>
39 #include <speex/speex_echo.h>
40 
42  char *digits;
43  int32_t key;
44  uint8_t rmatch;
47  void *user_data;
49 };
51 
52 typedef struct {
55  char *name;
56  char *terminators;
58 
62  char *name;
63  uint32_t digit_timeout_ms;
64  uint32_t input_timeout_ms;
71  uint32_t cur_digit_len;
72  uint32_t max_digit_len;
79  void *user_data;
82  uint8_t pinging;
83 };
84 
85 
87 {
88  return dmachine->last_return;
89 }
90 
92 {
93  switch_assert(dmachine);
94  return dmachine->target;
95 }
96 
98 {
99  switch_assert(dmachine);
100  dmachine->target = target;
101 }
102 
103 
105 {
106 
107  switch_assert(dmachine);
108  dmachine->match_callback = match_callback;
109 
110 }
111 
113 {
114 
115  switch_assert(dmachine);
116  dmachine->nonmatch_callback = nonmatch_callback;
117 
118 }
119 
121 {
122  return (const char *) dmachine->name;
123 }
124 
126  const char *name,
128  uint32_t digit_timeout_ms,
129  uint32_t input_timeout_ms,
130  switch_ivr_dmachine_callback_t match_callback,
131  switch_ivr_dmachine_callback_t nonmatch_callback,
132  void *user_data)
133 {
134  switch_byte_t my_pool = 0;
135  switch_ivr_dmachine_t *dmachine;
136 
137  if (!pool) {
139  my_pool = 1;
140  }
141 
142  dmachine = switch_core_alloc(pool, sizeof(*dmachine));
143  dmachine->pool = pool;
144  dmachine->my_pool = my_pool;
145  dmachine->digit_timeout_ms = digit_timeout_ms;
146  dmachine->input_timeout_ms = input_timeout_ms;
147  dmachine->match.dmachine = dmachine;
148  dmachine->name = switch_core_strdup(dmachine->pool, name);
149  switch_mutex_init(&dmachine->mutex, SWITCH_MUTEX_NESTED, dmachine->pool);
150 
152 
153  if (match_callback) {
154  dmachine->match_callback = match_callback;
155  }
156 
157  if (nonmatch_callback) {
158  dmachine->nonmatch_callback = nonmatch_callback;
159  }
160 
161  dmachine->user_data = user_data;
162 
163  *dmachine_p = dmachine;
164 
165  return SWITCH_STATUS_SUCCESS;
166 }
167 
168 
170 {
171  dmachine->digit_timeout_ms = digit_timeout_ms;
172 }
173 
175 {
176  dmachine->input_timeout_ms = input_timeout_ms;
177 }
178 
180 {
182 
183  if (!(dmachine && *dmachine)) return;
184 
185  pool = (*dmachine)->pool;
186 
187  switch_core_hash_destroy(&(*dmachine)->binding_hash);
188 
189  if ((*dmachine)->my_pool) {
191  }
192 }
193 
195 {
196  if (!dmachine->realm) {
197  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No realm selected.\n");
198  return SWITCH_STATUS_FALSE;
199  }
200 
201 
202  dmachine->realm->terminators = switch_core_strdup(dmachine->pool, terminators);
203  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Digit parser %s: Setting terminators for realm '%s' to '%s'\n",
204  dmachine->name, dmachine->realm->name, terminators);
205 
206  return SWITCH_STATUS_SUCCESS;
207 }
208 
210 {
211  dm_binding_head_t *headp = switch_core_hash_find(dmachine->binding_hash, realm);
212 
213  if (headp) {
214  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Digit parser %s: Setting realm to '%s'\n", dmachine->name, realm);
215  dmachine->realm = headp;
216  return SWITCH_STATUS_SUCCESS;
217  }
218 
219  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Digit parser %s: Error Setting realm to '%s'\n", dmachine->name, realm);
220 
221  return SWITCH_STATUS_FALSE;
222 }
223 
225 {
226  dm_binding_head_t *headp;
227 
228  if (zstr(realm)) {
229  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Digit parser %s: Error unknown realm: '%s'\n", dmachine->name, realm);
230  return SWITCH_STATUS_FALSE;
231  }
232 
233  headp = switch_core_hash_find(dmachine->binding_hash, realm);
234 
235  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Digit parser %s: Clearing realm '%s'\n", dmachine->name, realm);
236 
237  if (headp == dmachine->realm) {
239  "Digit parser %s: '%s' was the active realm, no realm currently selected.\n", dmachine->name, realm);
240  dmachine->realm = NULL;
241  }
242 
243  /* pool alloc'd just ditch it and it will give back the memory when we destroy ourselves */
244  switch_core_hash_delete(dmachine->binding_hash, realm);
245  return SWITCH_STATUS_SUCCESS;
246 }
247 
249  const char *realm,
250  const char *digits,
251  int32_t key,
253  void *user_data)
254 {
255  switch_ivr_dmachine_binding_t *binding = NULL, *ptr;
256  switch_size_t len;
257  dm_binding_head_t *headp;
258  const char *msg = "";
259 
260  if (strlen(digits) > DMACHINE_MAX_DIGIT_LEN -1) {
261  return SWITCH_STATUS_FALSE;
262  }
263 
264  if (zstr(realm)) {
265  realm = "default";
266  }
267 
268  if (!(headp = switch_core_hash_find(dmachine->binding_hash, realm))) {
269  headp = switch_core_alloc(dmachine->pool, sizeof(*headp));
270  headp->name = switch_core_strdup(dmachine->pool, realm);
271  switch_core_hash_insert(dmachine->binding_hash, realm, headp);
272  }
273 
274  for(ptr = headp->binding_list; ptr; ptr = ptr->next) {
275  if ((ptr->is_regex && !strcmp(ptr->digits, digits+1)) || !strcmp(ptr->digits, digits)) {
276  msg = "Reuse Existing ";
277  binding = ptr;
278  binding->callback = callback;
279  binding->user_data = user_data;
280  goto done;
281  }
282  }
283 
284 
285  binding = switch_core_alloc(dmachine->pool, sizeof(*binding));
286 
287  if (*digits == '~') {
288  binding->is_regex = 1;
289  digits++;
290  }
291 
292  binding->key = key;
293  binding->digits = switch_core_strdup(dmachine->pool, digits);
294  binding->callback = callback;
295  binding->user_data = user_data;
296 
297  if (headp->tail) {
298  headp->tail->next = binding;
299  } else {
300  headp->binding_list = binding;
301  }
302 
303  headp->tail = binding;
304 
305  len = strlen(digits);
306 
307  if (dmachine->realm != headp) {
308  switch_ivr_dmachine_set_realm(dmachine, realm);
309  }
310 
311  if (binding->is_regex && dmachine->max_digit_len != DMACHINE_MAX_DIGIT_LEN -1) {
312  dmachine->max_digit_len = DMACHINE_MAX_DIGIT_LEN -1;
313  } else if (len > dmachine->max_digit_len) {
314  dmachine->max_digit_len = (uint32_t) len;
315  }
316 
317  done:
318 
319  if (binding->is_regex) {
320  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%sDigit parser %s: binding %s/%s/%d callback: %p data: %p\n",
321  msg, dmachine->name, digits, realm, key, (void *)(intptr_t) callback, user_data);
322  } else {
323  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%sDigit parser %s: binding %s/%s/%d callback: %p data: %p\n",
324  msg, dmachine->name, digits, realm, key, (void *)(intptr_t) callback, user_data);
325  }
326 
327  return SWITCH_STATUS_SUCCESS;
328 }
329 
330 typedef enum {
336 } dm_match_t;
337 
338 
340 {
341  dm_match_t best = DM_MATCH_NONE;
342  switch_ivr_dmachine_binding_t *bp, *exact_bp = NULL, *partial_bp = NULL, *both_bp = NULL, *r_bp = NULL;
343  int pmatches = 0, ematches = 0, rmatches = 0;
344 
345  if (!dmachine->cur_digit_len || !dmachine->realm) goto end;
346 
347  for(bp = dmachine->realm->binding_list; bp; bp = bp->next) {
348  if (bp->is_regex) {
349  switch_status_t r_status = switch_regex_match(dmachine->digits, bp->digits);
350 
351  if (r_status == SWITCH_STATUS_SUCCESS) {
352  bp->rmatch++;
353  } else {
354  bp->rmatch = 0;
355  }
356 
357  rmatches++;
358  pmatches++;
359 
360  } else {
361  if (!strncmp(dmachine->digits, bp->digits, strlen(dmachine->digits))) {
362  pmatches++;
363  ematches = 1;
364  }
365  }
366  }
367 
368  if (!zstr(dmachine->realm->terminators)) {
369  char *p = dmachine->realm->terminators;
370  char *q;
371 
372  while(p && *p) {
373  if ((q=strrchr(dmachine->digits, *p))) {
374  *q = '\0';
375  is_timeout = 1;
376  break;
377  }
378  p++;
379  }
380  }
381 
382  for(bp = dmachine->realm->binding_list; bp; bp = bp->next) {
383  if (bp->is_regex) {
384  if (bp->rmatch) {
385  if (is_timeout || (bp == dmachine->realm->binding_list && !bp->next)) {
386  best = DM_MATCH_EXACT;
387  exact_bp = bp;
388  break;
389  }
390  best = DM_MATCH_PARTIAL;
391  }
392  } else {
393  int pmatch = !strncmp(dmachine->digits, bp->digits, strlen(dmachine->digits));
394 
395  if (!exact_bp && pmatch && (((pmatches == 1 || ematches == 1) && !rmatches) || is_timeout) && !strcmp(bp->digits, dmachine->digits)) {
396  best = DM_MATCH_EXACT;
397  exact_bp = bp;
398  if (dmachine->cur_digit_len == dmachine->max_digit_len) break;
399  }
400 
401  if (!(both_bp && partial_bp) && strlen(bp->digits) != strlen(dmachine->digits) && pmatch) {
402 
403  if (exact_bp) {
404  best = DM_MATCH_BOTH;
405  both_bp = bp;
406  } else {
407  best = DM_MATCH_PARTIAL;
408  partial_bp = bp;
409  }
410  }
411 
412  if (both_bp && exact_bp && partial_bp) break;
413  }
414  }
415 
416  if (!pmatches) {
417  best = DM_MATCH_NEVER;
418  }
419 
420 
421  end:
422 
423  if (is_timeout) {
424  if (both_bp) {
425  r_bp = exact_bp ? exact_bp : both_bp;
426  }
427  }
428 
429  if (best == DM_MATCH_EXACT && exact_bp) {
430  r_bp = exact_bp;
431  }
432 
433 
434  if (r_bp) {
435  dmachine->last_matching_binding = r_bp;
436  switch_set_string(dmachine->last_matching_digits, dmachine->digits);
437  best = DM_MATCH_EXACT;
438  }
439 
440  return best;
441 
442 }
443 
445 {
447  uint32_t timeout = dmachine->cur_digit_len ? dmachine->digit_timeout_ms : dmachine->input_timeout_ms;
448 
449  if (!dmachine->last_digit_time) dmachine->last_digit_time = now;
450 
451  if (timeout) {
452  if ((uint32_t)((now - dmachine->last_digit_time) / 1000) > timeout) {
453  return SWITCH_TRUE;
454  }
455  }
456 
457  return SWITCH_FALSE;
458 }
459 
461 {
462  if (dmachine->is_match) {
463  dmachine->is_match = 0;
464  return &dmachine->match;
465  }
466 
467  return NULL;
468 }
469 
471 {
472 
473  return dmachine->last_failed_digits;
474 }
475 
477 {
478  switch_bool_t is_timeout = switch_ivr_dmachine_check_timeout(dmachine);
479  dm_match_t is_match = switch_ivr_dmachine_check_match(dmachine, is_timeout);
480  switch_status_t r, s;
481  int clear = 0;
482 
483  if (is_match == DM_MATCH_NEVER) {
484  is_timeout++;
485  }
486 
487  if (switch_mutex_trylock(dmachine->mutex) != SWITCH_STATUS_SUCCESS) {
488  return SWITCH_STATUS_SUCCESS;
489  }
490 
491  if (dmachine->pinging) {
492  return SWITCH_STATUS_BREAK;
493  }
494 
495  dmachine->pinging = 1;
496 
497  if (zstr(dmachine->digits) && !is_timeout) {
499  } else if (dmachine->cur_digit_len > dmachine->max_digit_len) {
501  } else if (is_match == DM_MATCH_EXACT || (is_match == DM_MATCH_BOTH && is_timeout)) {
503 
504  dmachine->match.match_digits = dmachine->last_matching_digits;
505  dmachine->match.match_key = dmachine->last_matching_binding->key;
506  dmachine->match.user_data = dmachine->last_matching_binding->user_data;
507 
508  if (match_p) {
509  *match_p = &dmachine->match;
510  }
511 
512  dmachine->is_match = 1;
513 
514  dmachine->match.type = DM_MATCH_POSITIVE;
515 
516  if (dmachine->last_matching_binding->callback) {
517  s = dmachine->last_matching_binding->callback(&dmachine->match);
518 
519  switch(s) {
522  break;
524  break;
525  default:
527  break;
528  }
529  }
530 
531  if (dmachine->match_callback) {
532  dmachine->match.user_data = dmachine->user_data;
533  s = dmachine->match_callback(&dmachine->match);
534 
535  switch(s) {
538  break;
540  break;
541  default:
543  break;
544  }
545 
546  }
547 
548  clear++;
549  } else if (is_timeout) {
551  } else if (is_match == DM_MATCH_NONE && dmachine->cur_digit_len == dmachine->max_digit_len) {
553  } else {
555  }
556 
558  switch_set_string(dmachine->last_failed_digits, dmachine->digits);
559  dmachine->match.match_digits = dmachine->last_failed_digits;
560 
561  dmachine->match.type = DM_MATCH_NEGATIVE;
562 
563  if (dmachine->nonmatch_callback) {
564  dmachine->match.user_data = dmachine->user_data;
565  s = dmachine->nonmatch_callback(&dmachine->match);
566 
567  switch(s) {
570  break;
572  break;
573  default:
575  break;
576  }
577 
578  }
579 
580  clear++;
581  }
582 
583  if (clear) {
584  switch_ivr_dmachine_clear(dmachine);
585  }
586 
587  dmachine->last_return = r;
588 
589  dmachine->pinging = 0;
590 
591  switch_mutex_unlock(dmachine->mutex);
592 
593  return r;
594 }
595 
597 {
598  const char *p;
600 
601  if (!zstr(digits)) {
602  status = SWITCH_STATUS_SUCCESS;
603  }
604 
605  for (p = digits; p && *p; p++) {
606  switch_mutex_lock(dmachine->mutex);
607  if (dmachine->cur_digit_len < dmachine->max_digit_len) {
608  switch_status_t istatus;
609  char *e = dmachine->digits + strlen(dmachine->digits);
610 
611  *e++ = *p;
612  *e = '\0';
613  dmachine->cur_digit_len++;
614  switch_mutex_unlock(dmachine->mutex);
615  dmachine->last_digit_time = switch_time_now();
616  if (status == SWITCH_STATUS_SUCCESS && (istatus = switch_ivr_dmachine_ping(dmachine, match)) != SWITCH_STATUS_SUCCESS) {
617  status = istatus;
618  }
619  } else {
620  switch_mutex_unlock(dmachine->mutex);
621  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "dmachine overflow error!\n");
622  status = SWITCH_STATUS_FALSE;
623  }
624  }
625 
626  return status;
627 }
628 
630 {
631  return !!dmachine->cur_digit_len;
632 }
633 
635 {
636 
637  memset(dmachine->digits, 0, sizeof(dmachine->digits));
638  dmachine->cur_digit_len = 0;
639  dmachine->last_digit_time = 0;
640  return SWITCH_STATUS_SUCCESS;
641 }
642 
643 
644 
646 {
647  switch_status_t status;
648  switch_frame_t *read_frame;
650 
652  return SWITCH_STATUS_FALSE;
653  }
654 
656 
657  if (switch_true(switch_channel_get_variable(channel, "echo_decode_video"))) {
659  }
660 
661  if (switch_true(switch_channel_get_variable(channel, "echo_decode_audio"))) {
663  }
664 
666 
667  while (switch_channel_ready(channel)) {
668  status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
669  if (!SWITCH_READ_ACCEPTABLE(status)) {
670  break;
671  }
672 
674 
675  if (args && (args->input_callback || args->buf || args->buflen)) {
676  switch_dtmf_t dtmf = {0};
677 
678  /*
679  dtmf handler function you can hook up to be executed when a digit is dialed during playback
680  if you return anything but SWITCH_STATUS_SUCCESS the playback will stop.
681  */
682  if (switch_channel_has_dtmf(channel)) {
683  if (!args->input_callback && !args->buf) {
684  status = SWITCH_STATUS_BREAK;
685  break;
686  }
687  switch_channel_dequeue_dtmf(channel, &dtmf);
688  if (args->input_callback) {
689  status = args->input_callback(session, (void *) &dtmf, SWITCH_INPUT_TYPE_DTMF, args->buf, args->buflen);
690  } else {
691  *((char *) args->buf) = dtmf.digit;
692  status = SWITCH_STATUS_BREAK;
693  }
694  }
695 
696  if (args->input_callback) {
697  switch_event_t *event = NULL;
698 
700  status = args->input_callback(session, event, SWITCH_INPUT_TYPE_EVENT, args->buf, args->buflen);
701  switch_event_destroy(&event);
702  }
703  }
704 
705  if (status != SWITCH_STATUS_SUCCESS) {
706  break;
707  }
708  }
709 
710  switch_core_session_write_frame(session, read_frame, SWITCH_IO_FLAG_NONE, 0);
711 
712  if (switch_channel_test_flag(channel, CF_BREAK)) {
714  break;
715  }
716  }
717 
720 
721  return SWITCH_STATUS_SUCCESS;
722 }
723 
724 typedef struct {
726  int mux;
727  int loop;
728  char *file;
730 
732 {
733  displace_helper_t *dh = (displace_helper_t *) user_data;
734 
735  switch (type) {
737  break;
739  if (dh) {
741  switch_channel_t *channel;
742 
744 
745  if (session && (channel = switch_core_session_get_channel(session))) {
746  switch_channel_set_private(channel, dh->file, NULL);
747  }
748  }
749  break;
751  {
753  if (dh && !dh->mux) {
754  memset(rframe->data, 255, rframe->datalen);
755  }
757  }
758  break;
760  if (dh) {
761  switch_frame_t *rframe = NULL;
762  switch_size_t len;
763  switch_status_t st;
764 
766  len = rframe->samples;
767 
768  if (dh->mux) {
770  int16_t *fp = rframe->data;
771  uint32_t x;
772 
773  st = switch_core_file_read(&dh->fh, buf, &len);
774 
775  for (x = 0; x < (uint32_t) len * dh->fh.channels; x++) {
776  int32_t mixed = fp[x] + buf[x];
778  fp[x] = (int16_t) mixed;
779  }
780  } else {
781  st = switch_core_file_read(&dh->fh, rframe->data, &len);
782  if (len < rframe->samples) {
783  memset((char *)rframe->data + (len * 2 * dh->fh.channels), 0, (rframe->samples - len) * 2 * dh->fh.channels);
784  }
785  }
786 
787  rframe->datalen = rframe->samples * 2 * dh->fh.channels;
788 
789  if (st != SWITCH_STATUS_SUCCESS || len == 0) {
790  if (dh->loop) {
791  uint32_t pos = 0;
792  switch_core_file_seek(&dh->fh, &pos, 0, SEEK_SET);
793  } else {
795  switch_channel_t *channel;
796 
797  if (session && (channel = switch_core_session_get_channel(session))) {
798  switch_channel_set_private(channel, dh->file, NULL);
799  }
800  return SWITCH_FALSE;
801  }
802  }
803 
805  }
806  break;
808  default:
809  break;
810  }
811 
812  return SWITCH_TRUE;
813 }
814 
816 {
817  displace_helper_t *dh = (displace_helper_t *) user_data;
818 
819  switch (type) {
821  break;
823  if (dh) {
825  switch_channel_t *channel;
826 
828 
829  if (session && (channel = switch_core_session_get_channel(session))) {
830  switch_channel_set_private(channel, dh->file, NULL);
831  }
832  }
833  break;
835  {
837  if (dh && !dh->mux) {
838  memset(rframe->data, 255, rframe->datalen);
839  }
841  }
842  break;
844  if (dh) {
845  switch_frame_t *rframe = NULL;
846  switch_size_t len;
847  switch_status_t st;
849  len = rframe->samples;
850 
851  if (dh->mux) {
853  int16_t *fp = rframe->data;
854  uint32_t x;
855 
856  st = switch_core_file_read(&dh->fh, buf, &len);
857 
858  for (x = 0; x < (uint32_t) len * dh->fh.channels; x++) {
859  int32_t mixed = fp[x] + buf[x];
861  fp[x] = (int16_t) mixed;
862  }
863 
864  } else {
865  st = switch_core_file_read(&dh->fh, rframe->data, &len);
866  rframe->samples = (uint32_t) len;
867  }
868 
869  rframe->datalen = rframe->samples * 2 * dh->fh.channels;
870 
871 
872  if (st != SWITCH_STATUS_SUCCESS || len == 0) {
873  if (dh->loop) {
874  uint32_t pos = 0;
875  switch_core_file_seek(&dh->fh, &pos, 0, SEEK_SET);
876  } else {
878  switch_channel_t *channel;
879 
880  if (session && (channel = switch_core_session_get_channel(session))) {
881  switch_channel_set_private(channel, dh->file, NULL);
882  }
883  return SWITCH_FALSE;
884  }
885  }
886 
888  }
889  break;
891  default:
892  break;
893  }
894 
895  return SWITCH_TRUE;
896 }
897 
899 {
900  switch_media_bug_t *bug;
902 
903  if ((bug = switch_channel_get_private(channel, file))) {
904  switch_channel_set_private(channel, file, NULL);
905  switch_core_media_bug_remove(session, &bug);
906  return SWITCH_STATUS_SUCCESS;
907  }
908 
909  return SWITCH_STATUS_FALSE;
910 }
911 
912 SWITCH_DECLARE(switch_status_t) switch_ivr_displace_session(switch_core_session_t *session, const char *file, uint32_t limit, const char *flags)
913 {
915  switch_media_bug_t *bug;
916  switch_status_t status;
917  time_t to = 0;
918  char *ext;
919  const char *prefix;
920  displace_helper_t *dh;
921  const char *p;
922  switch_bool_t hangup_on_error = SWITCH_FALSE;
923  switch_codec_implementation_t read_impl = { 0 };
924  switch_core_session_get_read_impl(session, &read_impl);
925 
926  if ((p = switch_channel_get_variable(channel, "DISPLACE_HANGUP_ON_ERROR"))) {
927  hangup_on_error = switch_true(p);
928  }
929 
930  if (zstr(file)) {
931  return SWITCH_STATUS_FALSE;
932  }
933 
934  if ((status = switch_channel_pre_answer(channel)) != SWITCH_STATUS_SUCCESS) {
935  return SWITCH_STATUS_FALSE;
936  }
937 
938  if (!switch_channel_media_up(channel) || !switch_core_session_get_read_codec(session)) {
939  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can not displace session. Media not enabled on channel\n");
940  return SWITCH_STATUS_FALSE;
941  }
942 
943  if ((bug = switch_channel_get_private(channel, file))) {
944  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Only 1 of the same file per channel please!\n");
945  return SWITCH_STATUS_FALSE;
946  }
947 
948  if (!(dh = switch_core_session_alloc(session, sizeof(*dh)))) {
949  return SWITCH_STATUS_MEMERR;
950  }
951 
952  if (!(prefix = switch_channel_get_variable(channel, "sound_prefix"))) {
953  prefix = SWITCH_GLOBAL_dirs.base_dir;
954  }
955 
956  if (!strstr(file, SWITCH_URL_SEPARATOR)) {
957  if (!switch_is_file_path(file)) {
958  char *tfile = NULL;
959  char *e;
960 
961  if (*file == '[') {
962  tfile = switch_core_session_strdup(session, file);
963  if ((e = switch_find_end_paren(tfile, '[', ']'))) {
964  *e = '\0';
965  file = e + 1;
966  } else {
967  tfile = NULL;
968  }
969  }
970 
971  file = switch_core_session_sprintf(session, "%s%s%s%s%s", switch_str_nil(tfile), tfile ? "]" : "", prefix, SWITCH_PATH_SEPARATOR, file);
972  }
973  if ((ext = strrchr(file, '.'))) {
974  ext++;
975  } else {
976  ext = read_impl.iananame;
977  file = switch_core_session_sprintf(session, "%s.%s", file, ext);
978  }
979  }
980 
981  dh->fh.channels = read_impl.number_of_channels;
982  dh->fh.samplerate = read_impl.actual_samples_per_second;
983  dh->file = switch_core_session_strdup(session, file);
984 
985  if (switch_core_file_open(&dh->fh,
986  file,
987  read_impl.number_of_channels,
989  if (hangup_on_error) {
992  }
993  return SWITCH_STATUS_GENERR;
994  }
995 
996  if (limit) {
997  to = switch_epoch_time_now(NULL) + limit;
998  }
999 
1000  if (flags && strchr(flags, 'm')) {
1001  dh->mux++;
1002  }
1003 
1004  if (flags && strchr(flags, 'l')) {
1005  dh->loop++;
1006  }
1007 
1008  if (flags && strchr(flags, 'r')) {
1009  status = switch_core_media_bug_add(session, "displace", file,
1011  } else {
1012  status = switch_core_media_bug_add(session, "displace", file,
1014  }
1015 
1016  if (status != SWITCH_STATUS_SUCCESS) {
1017  switch_core_file_close(&dh->fh);
1018  return status;
1019  }
1020 
1021  switch_channel_set_private(channel, file, bug);
1022 
1023  return SWITCH_STATUS_SUCCESS;
1024 }
1025 
1026 
1028  char *file;
1032  int native;
1033  uint32_t packet_len;
1034  int min_sec;
1040  int rready;
1041  int wready;
1051  uint32_t writes;
1052  uint32_t vwrites;
1053  const char *completion_cause;
1054 };
1055 
1056 /**
1057  * Set the recording completion cause. The cause can only be set once, to minimize the logic in the record_callback.
1058  * [The completion_cause strings are essentially those of an MRCP Recorder resource.]
1059  */
1060 static void set_completion_cause(struct record_helper *rh, const char *completion_cause)
1061 {
1062  if (!rh->completion_cause) {
1063  rh->completion_cause = completion_cause;
1064  }
1065 }
1066 
1067 static switch_bool_t is_silence_frame(switch_frame_t *frame, int silence_threshold, switch_codec_implementation_t *codec_impl)
1068 {
1069  int16_t *fdata = (int16_t *) frame->data;
1070  uint32_t samples = frame->datalen / sizeof(*fdata);
1071  switch_bool_t is_silence = SWITCH_TRUE;
1072  uint32_t channel_num = 0;
1073 
1074  int divisor = 0;
1075  if (!(divisor = codec_impl->samples_per_second / 8000)) {
1076  divisor = 1;
1077  }
1078 
1079  /* is silence only if every channel is silent */
1080  for (channel_num = 0; channel_num < codec_impl->number_of_channels && is_silence; channel_num++) {
1081  uint32_t count = 0, j = channel_num;
1082  double energy = 0;
1083  for (count = 0; count < samples; count++) {
1084  energy += abs(fdata[j]);
1085  j += codec_impl->number_of_channels;
1086  }
1087  is_silence &= (uint32_t) ((energy / (samples / divisor)) < silence_threshold);
1088  }
1089 
1090  return is_silence;
1091 }
1092 
1094 {
1095  switch_event_t *event;
1096 
1097  if (rh->fh) {
1098  switch_channel_set_variable_printf(channel, "record_samples", "%d", rh->fh->samples_out);
1099  if (read_impl->actual_samples_per_second) {
1100  switch_channel_set_variable_printf(channel, "record_seconds", "%d", rh->fh->samples_out / read_impl->actual_samples_per_second);
1101  switch_channel_set_variable_printf(channel, "record_ms", "%d", rh->fh->samples_out / (read_impl->actual_samples_per_second / 1000));
1102  }
1103  }
1104 
1105  if (!zstr(rh->completion_cause)) {
1106  switch_channel_set_variable_printf(channel, "record_completion_cause", "%s", rh->completion_cause);
1107  }
1108 
1110  switch_channel_event_set_data(channel, event);
1111  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-File-Path", rh->file);
1112  if (!zstr(rh->completion_cause)) {
1113  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-Completion-Cause", rh->completion_cause);
1114  }
1115  switch_event_fire(&event);
1116  }
1117 }
1118 
1120 {
1121  switch_media_bug_t *bug = (switch_media_bug_t *) obj;
1124  struct record_helper *rh;
1125  switch_size_t bsize = SWITCH_RECOMMENDED_BUFFER_SIZE, samples = 0, inuse = 0;
1126  unsigned char *data;
1127  int channels = 1;
1129 
1131  return NULL;
1132  }
1133 
1135  switch_buffer_create_dynamic(&rh->thread_buffer, 1024 * 512, 1024 * 64, 0);
1136  rh->thread_ready = 1;
1137 
1140 
1141  while(switch_test_flag(rh->fh, SWITCH_FILE_OPEN)) {
1143  switch_core_session_get_read_impl(session, &read_impl);
1145  bsize = read_impl.decoded_bytes_per_packet;
1146  }
1147  }
1148 
1150  inuse = switch_buffer_inuse(rh->thread_buffer);
1151 
1152  if (rh->thread_ready && switch_channel_up_nosig(channel) && inuse < bsize) {
1154  switch_yield(20000);
1155  continue;
1156  } else if ((!rh->thread_ready || switch_channel_down_nosig(channel)) && !inuse) {
1158  break;
1159  }
1160 
1161  samples = switch_buffer_read(rh->thread_buffer, data, bsize) / 2 / channels;
1163 
1164  if (switch_core_file_write(rh->fh, data, &samples) != SWITCH_STATUS_SUCCESS) {
1165  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error writing %s\n", rh->file);
1166  /* File write failed */
1167  set_completion_cause(rh, "uri-failure");
1168  if (rh->hangup_on_error) {
1171  }
1172  }
1173  }
1174 
1176 
1177  return NULL;
1178 }
1179 
1181 {
1184  struct record_helper *rh = (struct record_helper *) user_data;
1185  switch_event_t *event;
1186  switch_frame_t *nframe;
1187  switch_size_t len = 0;
1188  int mask = switch_core_media_bug_test_flag(bug, SMBF_MASK);
1189  unsigned char null_data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
1190 
1191  switch (type) {
1192  case SWITCH_ABC_TYPE_INIT:
1193  {
1194  const char *var = switch_channel_get_variable(channel, "RECORD_USE_THREAD");
1195 
1196  if (!rh->native && rh->fh && (zstr(var) || switch_true(var))) {
1197  switch_threadattr_t *thd_attr = NULL;
1199  int sanity = 200;
1200 
1201 
1204  switch_threadattr_create(&thd_attr, pool);
1206  switch_thread_create(&rh->thread, thd_attr, recording_thread, bug, pool);
1207 
1208  while(--sanity > 0 && !rh->thread_ready) {
1209  switch_yield(10000);
1210  }
1211  }
1212 
1214  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-File-Path", rh->file);
1215  switch_channel_event_set_data(channel, event);
1216  switch_event_fire(&event);
1217  }
1218 
1222  rh->completion_cause = NULL;
1223 
1225  }
1226  break;
1228  {
1230  switch_time_t diff;
1231 
1232  rh->rready = 1;
1233 
1235  len = nframe->datalen;
1236 
1237  if (!rh->wready) {
1238  unsigned char fill_data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
1239  switch_size_t fill_len = len;
1240 
1241  switch_core_gen_encoded_silence(fill_data, &rh->read_impl, len);
1242  switch_core_file_write(&rh->out_fh, fill_data, &fill_len);
1243  }
1244 
1245 
1246  if (rh->last_read_time && rh->last_read_time < now) {
1247  diff = (now - rh->last_read_time) / rh->read_impl.microseconds_per_packet;
1248 
1249  if (diff > 3) {
1250  unsigned char fill_data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
1251  switch_core_gen_encoded_silence(fill_data, &rh->read_impl, len);
1252 
1253  while(diff > 1) {
1254  switch_size_t fill_len = len;
1255  switch_core_file_write(&rh->in_fh, fill_data, &fill_len);
1256  diff--;
1257  }
1258  }
1259  }
1260 
1261  switch_core_file_write(&rh->in_fh, mask ? null_data : nframe->data, &len);
1262  rh->last_read_time = now;
1263  rh->writes++;
1264  }
1265  break;
1267  {
1269  switch_time_t diff;
1270  rh->wready = 1;
1271 
1273  len = nframe->datalen;
1274 
1275  if (!rh->rready) {
1276  unsigned char fill_data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
1277  switch_size_t fill_len = len;
1278  switch_core_gen_encoded_silence(fill_data, &rh->read_impl, len);
1279  switch_core_file_write(&rh->in_fh, fill_data, &fill_len);
1280  }
1281 
1282 
1283 
1284 
1285  if (rh->last_write_time && rh->last_write_time < now) {
1286  diff = (now - rh->last_write_time) / rh->read_impl.microseconds_per_packet;
1287 
1288  if (diff > 3) {
1289  unsigned char fill_data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
1290  switch_core_gen_encoded_silence(fill_data, &rh->read_impl, len);
1291 
1292  while(diff > 1) {
1293  switch_size_t fill_len = len;
1294  switch_core_file_write(&rh->out_fh, fill_data, &fill_len);
1295  diff--;
1296  }
1297  }
1298  }
1299 
1300  switch_core_file_write(&rh->out_fh, mask ? null_data : nframe->data, &len);
1301  rh->last_write_time = now;
1302  rh->writes++;
1303  }
1304  break;
1305  case SWITCH_ABC_TYPE_CLOSE:
1306  {
1307  const char *var;
1308 
1310  switch_core_session_get_read_impl(session, &read_impl);
1311 
1312  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Stop recording file %s\n", rh->file);
1313  switch_channel_set_private(channel, rh->file, NULL);
1314 
1315  if (rh->native) {
1318  } else if (rh->fh) {
1319  switch_size_t len;
1320  uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE];
1321  switch_frame_t frame = { 0 };
1322 
1323  if (rh->thread_ready) {
1324  switch_status_t st;
1325 
1326  rh->thread_ready = 0;
1327  switch_thread_join(&st, rh->thread);
1328  }
1329 
1330  if (rh->thread_buffer) {
1332  }
1333 
1334 
1335  frame.data = data;
1337 
1339  len = (switch_size_t) frame.datalen / 2;
1340 
1341  if (len && switch_core_file_write(rh->fh, mask ? null_data : data, &len) != SWITCH_STATUS_SUCCESS) {
1342  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error writing %s\n", rh->file);
1343  /* File write failed */
1344  set_completion_cause(rh, "uri-failure");
1345  if (rh->hangup_on_error) {
1348  }
1349  send_record_stop_event(channel, &read_impl, rh);
1350  return SWITCH_FALSE;
1351  }
1352  }
1353 
1354 
1355  //if (switch_core_file_has_video(rh->fh, SWITCH_TRUE)) {
1356  //switch_core_media_set_video_file(session, NULL, SWITCH_RW_READ);
1357  //switch_channel_clear_flag_recursive(session->channel, CF_VIDEO_DECODED_READ);
1358  //}
1359 
1361 
1362  if (!rh->writes && !rh->vwrites) {
1363  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Discarding empty file %s\n", rh->file);
1364  switch_channel_set_variable(channel, "RECORD_DISCARDED", "true");
1366  set_completion_cause(rh, "empty-file");
1367  } else if (rh->fh->samples_out < rh->fh->samplerate * rh->min_sec) {
1368  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Discarding short file %s\n", rh->file);
1369  switch_channel_set_variable(channel, "RECORD_DISCARDED", "true");
1371  set_completion_cause(rh, "input-too-short");
1372  } else {
1373 
1374  if (switch_channel_down_nosig(channel)) {
1375  /* We got hung up */
1376  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Channel is hung up\n");
1377  if (rh->speech_detected) {
1378  /* Treat it as equivalent with final-silence */
1379  set_completion_cause(rh, "success-silence");
1380  } else {
1381  /* Treat it as equivalent with inital-silence timeout */
1382  set_completion_cause(rh, "no-input-timeout");
1383  }
1384  } else {
1385  /* Set the completion_cause to maxtime reached, unless it's already set */
1386  set_completion_cause(rh, "success-maxtime");
1387  }
1388  }
1389  }
1390 
1391  send_record_stop_event(channel, &read_impl, rh);
1392 
1394 
1396  char *cmd = switch_core_session_strdup(session, var);
1397  char *data, *expanded = NULL;
1398  switch_stream_handle_t stream = { 0 };
1399 
1400  SWITCH_STANDARD_STREAM(stream);
1401 
1402  if ((data = strchr(cmd, ':'))) {
1403  *data++ = '\0';
1404  expanded = switch_channel_expand_variables(channel, data);
1405  }
1406 
1407  switch_api_execute(cmd, expanded, session, &stream);
1408 
1409  if (expanded && expanded != data) {
1410  free(expanded);
1411  }
1412 
1413  switch_safe_free(stream.data);
1414 
1415  }
1416 
1417 
1418  }
1419 
1420  break;
1422 
1423  if (rh->fh) {
1424  switch_size_t len;
1425  uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE];
1426  switch_frame_t frame = { 0 };
1427  switch_status_t status;
1428  int i = 0;
1429 
1430  frame.data = data;
1432 
1433  for (;;) {
1434  status = switch_core_media_bug_read(bug, &frame, i++ == 0 ? SWITCH_FALSE : SWITCH_TRUE);
1435 
1436  if (status != SWITCH_STATUS_SUCCESS || !frame.datalen) {
1437  break;
1438  } else {
1439  len = (switch_size_t) frame.datalen / 2 / frame.channels;
1440 
1441  if (rh->thread_buffer) {
1443  switch_buffer_write(rh->thread_buffer, mask ? null_data : data, frame.datalen);
1445  } else if (switch_core_file_write(rh->fh, mask ? null_data : data, &len) != SWITCH_STATUS_SUCCESS) {
1446  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error writing %s\n", rh->file);
1447  /* File write failed */
1448  set_completion_cause(rh, "uri-failure");
1449  if (rh->hangup_on_error) {
1451  switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
1452  }
1453  return SWITCH_FALSE;
1454  }
1455 
1456  rh->writes++;
1457 
1458  /* check for silence timeout */
1459  if (rh->silence_threshold) {
1461  switch_core_session_get_read_impl(session, &read_impl);
1462  if (is_silence_frame(&frame, rh->silence_threshold, &read_impl)) {
1463  if (!rh->silence_time) {
1464  /* start of silence */
1465  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Start of silence detected\n");
1467  } else {
1468  /* continuing silence */
1469  int duration_ms = (int)((switch_micro_time_now() - rh->silence_time) / 1000);
1470  if (rh->silence_timeout_ms > 0 && duration_ms >= rh->silence_timeout_ms) {
1471  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Recording file %s timeout: %i >= %i\n", rh->file, duration_ms, rh->silence_timeout_ms);
1473  if (rh->speech_detected) {
1474  /* Reached final silence timeout */
1475  set_completion_cause(rh, "success-silence");
1476  } else {
1477  /* Reached initial silence timeout */
1478  set_completion_cause(rh, "no-input-timeout");
1479  /* Discard the silent file? */
1480  }
1481  }
1482  }
1483  } else { /* not silence */
1484  if (rh->silence_time) {
1485  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Start of speech detected\n");
1487  /* end of silence */
1488  rh->silence_time = 0;
1489  /* switch from initial timeout to final timeout */
1491  }
1492  }
1493  } else {
1494  /* no silence detection */
1495  if (!rh->speech_detected) {
1496  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No silence detection configured; assuming start of speech\n");
1498  }
1499  }
1500  }
1501  }
1502  }
1503  break;
1506  if (rh->fh) {
1507  if (!bug->video_ping_frame) break;
1508 
1510  rh->hangup_on_error) {
1511  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error writing video to %s\n", rh->file);
1514  return SWITCH_FALSE;
1515  }
1516  rh->vwrites++;
1517  }
1518  break;
1519 
1520  case SWITCH_ABC_TYPE_WRITE:
1521  default:
1522  break;
1523  }
1524 
1525  return SWITCH_TRUE;
1526 }
1527 
1529 {
1530  switch_media_bug_t *bug;
1532 
1533  if ((bug = switch_channel_get_private(channel, file))) {
1534  if (on) {
1536  } else {
1538  }
1539  return SWITCH_STATUS_SUCCESS;
1540  }
1541  return SWITCH_STATUS_FALSE;
1542 }
1543 
1545 {
1546  switch_media_bug_t *bug;
1548 
1549  if (!strcasecmp(file, "all")) {
1551  } else if ((bug = switch_channel_get_private(channel, file))) {
1552  switch_core_media_bug_remove(session, &bug);
1553  return SWITCH_STATUS_SUCCESS;
1554  }
1555  return SWITCH_STATUS_FALSE;
1556 }
1557 
1558 static void* switch_ivr_record_user_data_dup(switch_core_session_t *session, void *user_data)
1559 {
1560  struct record_helper *rh = (struct record_helper *) user_data, *dup = NULL;
1561 
1562  dup = switch_core_session_alloc(session, sizeof(*dup));
1563  memcpy(dup, rh, sizeof(*rh));
1564  dup->file = switch_core_session_strdup(session, rh->file);
1565  dup->fh = switch_core_session_alloc(session, sizeof(switch_file_handle_t));
1566  memcpy(dup->fh, rh->fh, sizeof(switch_file_handle_t));
1567 
1568  return dup;
1569 }
1570 
1572 {
1573  const char *var = NULL;
1574  switch_channel_t *orig_channel = switch_core_session_get_channel(orig_session);
1575  switch_channel_t *new_channel = switch_core_session_get_channel(new_session);
1576 
1579  }
1581 
1583 }
1584 
1593  uint32_t flags;
1596  int errs;
1600 };
1601 
1602 
1604 {
1605  switch_media_bug_t *bug = (switch_media_bug_t *) user_data;
1606 
1607  if (frame->img) {
1610  }
1611 
1614  }
1615  }
1616 
1617  return SWITCH_STATUS_SUCCESS;
1618 }
1619 
1621 {
1622  struct eavesdrop_pvt *ep = (struct eavesdrop_pvt *) user_data;
1624  switch_frame_t frame = { 0 };
1627  int show_spy = 0;
1628 
1629  frame.data = data;
1631 
1633 
1634  if (show_spy) {
1635  if (!ep->set_decoded_read) {
1636  ep->set_decoded_read = 1;
1639  }
1640  } else {
1641  if (ep->set_decoded_read) {
1642  ep->set_decoded_read = 0;
1645  }
1646  }
1647 
1648  switch (type) {
1649  case SWITCH_ABC_TYPE_INIT:
1650 
1656  }
1657  break;
1658  case SWITCH_ABC_TYPE_CLOSE:
1659  if (ep->set_decoded_read) {
1661  }
1662 
1667  }
1668 
1670 
1671  break;
1672  case SWITCH_ABC_TYPE_WRITE:
1673  break;
1675  if (ep->buffer) {
1678  switch_buffer_zwrite(ep->buffer, frame.data, frame.datalen);
1680  }
1681  } else {
1682  return SWITCH_FALSE;
1683  }
1684  break;
1685  case SWITCH_ABC_TYPE_READ:
1686  break;
1687 
1689  {
1690 
1691  if (switch_test_flag(ep, ED_MUX_READ)) {
1693 
1694  if (switch_buffer_inuse(ep->r_buffer) >= rframe->datalen) {
1695  uint32_t bytes;
1696  int channels = rframe->channels ? rframe->channels : 1;
1697 
1699  bytes = (uint32_t) switch_buffer_read(ep->r_buffer, ep->data, rframe->datalen);
1700 
1701  rframe->datalen = switch_merge_sln(rframe->data, rframe->samples, (int16_t *) ep->data, bytes / 2, channels) * 2 * channels;
1702  rframe->samples = rframe->datalen / 2;
1703 
1704  ep->demux_frame.data = ep->data;
1705  ep->demux_frame.datalen = bytes;
1706  ep->demux_frame.samples = bytes / 2;
1707  ep->demux_frame.channels = rframe->channels;
1708 
1712  }
1713  }
1714 
1715  }
1716  break;
1717 
1719  {
1720  if (switch_test_flag(ep, ED_MUX_WRITE)) {
1722 
1723  if (switch_buffer_inuse(ep->w_buffer) >= rframe->datalen) {
1724  uint32_t bytes;
1725  int channels = rframe->channels ? rframe->channels : 1;
1726 
1728  bytes = (uint32_t) switch_buffer_read(ep->w_buffer, data, rframe->datalen);
1729 
1730  rframe->datalen = switch_merge_sln(rframe->data, rframe->samples, (int16_t *) data, bytes / 2, channels) * 2 * channels;
1731  rframe->samples = rframe->datalen / 2;
1732 
1735  }
1736  }
1737  }
1738  break;
1739 
1742  {
1743 
1744  if (!bug->video_ping_frame || !bug->video_ping_frame->img) {
1745  break;
1746  }
1747 
1751  ep->errs++;
1752 
1753  if (ep->errs > 10) {
1757  return SWITCH_FALSE;
1758  }
1759  } else {
1760  ep->errs = 0;
1761  }
1763  }
1764  }
1765  break;
1766  default:
1767  break;
1768  }
1769 
1770  return SWITCH_TRUE;
1771 }
1772 
1774 {
1775  switch_media_bug_t *bug;
1777 
1778  if (switch_core_media_bug_pop(session, "eavesdrop", &bug) == SWITCH_STATUS_SUCCESS) {
1780 
1781  if (ep && ep->eavesdropper && ep->eavesdropper != session) {
1783  *sessionp = ep->eavesdropper;
1785  status = SWITCH_STATUS_SUCCESS;
1786  }
1787  }
1788 
1789 
1790  return status;
1791 }
1792 
1795  char *var;
1796  char *val;
1797 };
1798 
1799 static void exec_cb(switch_media_bug_t *bug, void *user_data)
1800 {
1801  struct exec_cb_data *data = (struct exec_cb_data *) user_data;
1803 
1804  if (ep && ep->eavesdropper && ep->eavesdropper != data->caller) {
1807 
1808  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s telling %s to exec %s:%s\n",
1810 
1812  }
1813 }
1814 
1815 static void display_exec_cb(switch_media_bug_t *bug, void *user_data)
1816 {
1817  struct exec_cb_data *data = (struct exec_cb_data *) user_data;
1819 
1820  if (ep && ep->eavesdropper && ep->eavesdropper != data->caller) {
1821  switch_core_session_message_t msg = { 0 };
1822 
1823  msg.from = __FILE__;
1825  msg.string_array_arg[0] = data->var;
1826  msg.string_array_arg[1] = data->val;
1827 
1829  }
1830 }
1831 
1833 {
1834  struct exec_cb_data *data = NULL;
1835 
1836  data = switch_core_session_alloc(session, sizeof(*data));
1837  data->var = switch_core_session_strdup(session, app);
1838  data->val = switch_core_session_strdup(session, arg);
1839  data->caller = session;
1840 
1841  return switch_core_media_bug_exec_all(session, "eavesdrop", exec_cb, data);
1842 }
1843 
1844 
1846 {
1847  struct exec_cb_data *data = NULL;
1850 
1851  data = switch_core_session_alloc(session, sizeof(*data));
1852  data->var = switch_core_session_strdup(session, name);
1853  data->val = switch_core_session_strdup(session, number);
1854  data->caller = session;
1855 
1856  if (!switch_channel_test_app_flag_key("EAVESDROP", channel, 1)) {
1857  switch_channel_set_app_flag_key("EAVESDROP", channel, 1);
1858  status = switch_core_media_bug_exec_all(session, "eavesdrop", display_exec_cb, data);
1859  switch_channel_clear_app_flag_key("EAVESDROP", channel, 1);
1860  }
1861 
1862  return status;
1863 }
1864 
1865 
1867  const char *uuid, const char *require_group, switch_eavesdrop_flag_t flags)
1868 {
1869  switch_core_session_t *tsession;
1872  int codec_initialized = 0;
1873  const char *name, *num;
1874 
1875  if ((tsession = switch_core_session_locate(uuid))) {
1876  struct eavesdrop_pvt *ep = NULL;
1877  switch_media_bug_t *bug = NULL;
1878  switch_channel_t *tchannel = switch_core_session_get_channel(tsession);
1879  switch_frame_t *read_frame, write_frame = { 0 };
1880  switch_codec_t codec = { 0 };
1881  int16_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE / 2];
1882  uint32_t tlen;
1883  const char *macro_name = "eavesdrop_announce";
1884  const char *id_name = NULL;
1886  switch_core_session_message_t msg = { 0 };
1887  char cid_buf[1024] = "";
1888  switch_caller_profile_t *cp = NULL;
1889  uint32_t sanity = 600;
1890  switch_media_bug_flag_t read_flags = 0, write_flags = 0;
1891  const char *vval;
1892  int buf_size = 0;
1893 
1894  if (!switch_channel_media_up(channel)) {
1895  goto end;
1896  }
1897 
1898  while(switch_channel_state_change_pending(tchannel) || !switch_channel_media_up(tchannel)) {
1899  switch_yield(10000);
1900  if (!--sanity) break;
1901  }
1902 
1903  if (!switch_channel_media_up(tchannel)) {
1904  goto end;
1905  }
1906 
1907  switch_core_session_get_read_impl(tsession, &tread_impl);
1909 
1910  if ((id_name = switch_channel_get_variable(tchannel, "eavesdrop_announce_id"))) {
1911  const char *tmp = switch_channel_get_variable(tchannel, "eavesdrop_announce_macro");
1912  if (tmp) {
1913  macro_name = tmp;
1914  }
1915 
1916  switch_ivr_phrase_macro(session, macro_name, id_name, NULL, NULL);
1917  }
1918 
1919 
1920  if (!zstr(require_group)) {
1921  int argc, i;
1922  int ok = 0;
1923  char *argv[10] = { 0 };
1924  char *data;
1925 
1926  const char *group_name = switch_channel_get_variable(tchannel, "eavesdrop_group");
1927  /* If we don't have a group, then return */
1928  if (!group_name) {
1929  status = SWITCH_STATUS_BREAK;
1930  goto end;
1931  }
1932  /* Separate the group */
1933  data = strdup(group_name);
1934  if ((argc = switch_separate_string(data, ',', argv, (sizeof(argv) / sizeof(argv[0]))))) {
1935  for (i = 0; i < argc; i++) {
1936  /* If one of the group matches, then ok */
1937  if (argv[i] && !strcmp(argv[i], require_group)) {
1938  ok = 1;
1939  }
1940  }
1941  }
1942  switch_safe_free(data);
1943  /* If we didn't find any match, then end */
1944  if (!ok) {
1945  status = SWITCH_STATUS_BREAK;
1946  goto end;
1947  }
1948  }
1949 
1950 
1951  ep = switch_core_session_alloc(session, sizeof(*ep));
1952 
1953  tlen = tread_impl.decoded_bytes_per_packet;
1954 
1955 
1957  goto end;
1958  }
1959 
1960 
1961  if (switch_core_codec_init(&codec,
1962  "L16",
1963  NULL,
1964  NULL,
1965  tread_impl.actual_samples_per_second,
1966  tread_impl.microseconds_per_packet / 1000,
1967  tread_impl.number_of_channels,
1970  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
1971  switch_core_session_rwunlock(tsession);
1972  goto end;
1973  }
1974 
1976 
1977  ep->read_impl = read_impl;
1978  ep->tread_impl = tread_impl;
1979 
1980  codec_initialized = 1;
1981 
1982  switch_core_session_set_read_codec(session, &codec);
1983  write_frame.codec = &codec;
1984  write_frame.data = buf;
1985  write_frame.buflen = sizeof(buf);
1986  write_frame.rate = codec.implementation->actual_samples_per_second;
1987 
1988  /* Make sure that at least one leg is bridged, default to both */
1989  if (! (flags & (ED_BRIDGE_READ | ED_BRIDGE_WRITE))) {
1990  flags |= ED_BRIDGE_READ | ED_BRIDGE_WRITE;
1991  }
1992 
1993  buf_size = codec.implementation->decoded_bytes_per_packet * 10;
1994 
1995  ep->eavesdropper = session;
1996  ep->flags = flags;
1998  switch_buffer_create_dynamic(&ep->buffer, buf_size, buf_size, buf_size);
2000 
2002  switch_buffer_create_dynamic(&ep->w_buffer, buf_size, buf_size, buf_size);
2004 
2006  switch_buffer_create_dynamic(&ep->r_buffer, buf_size, buf_size, buf_size);
2008 
2009  if (flags & ED_BRIDGE_READ) {
2010  read_flags = SMBF_READ_STREAM | SMBF_READ_REPLACE;
2011  }
2012 
2013  if (flags & ED_BRIDGE_WRITE) {
2014  write_flags = SMBF_WRITE_STREAM | SMBF_WRITE_REPLACE;
2015  }
2016 
2017  if (switch_channel_test_flag(session->channel, CF_VIDEO) && switch_channel_test_flag(tsession->channel, CF_VIDEO)) {
2018  if ((vval = switch_channel_get_variable(session->channel, "eavesdrop_show_listener_video"))) {
2019  if (switch_true(vval) || !strcasecmp(vval, "aleg") || !strcasecmp(vval, "bleg") || !strcasecmp(vval, "both")) {
2020  read_flags |= SMBF_SPY_VIDEO_STREAM;
2021  }
2022  if (switch_true(vval) || !strcasecmp(vval, "bleg") || !strcasecmp(vval, "both")) {
2023  read_flags |= SMBF_SPY_VIDEO_STREAM_BLEG;
2024  }
2025  }
2026 
2027  if ((vval = switch_channel_get_variable(session->channel, "eavesdrop_concat_video")) && switch_true(vval)) {
2028  read_flags |= SMBF_READ_VIDEO_STREAM;
2029  read_flags |= SMBF_WRITE_VIDEO_STREAM;
2030  } else {
2031  read_flags |= SMBF_READ_VIDEO_PING;
2032  }
2033  } else {
2034  read_flags &= ~SMBF_READ_VIDEO_PING;
2035  read_flags &= ~SMBF_READ_VIDEO_STREAM;
2036  read_flags &= ~SMBF_WRITE_VIDEO_STREAM;
2037  read_flags &= ~SMBF_SPY_VIDEO_STREAM;
2038  read_flags &= ~SMBF_SPY_VIDEO_STREAM_BLEG;
2039  }
2040 
2041 
2042  if (switch_core_media_bug_add(tsession, "eavesdrop", uuid,
2043  eavesdrop_callback, ep, 0,
2044  read_flags | write_flags | SMBF_READ_PING | SMBF_THREAD_LOCK | SMBF_NO_PAUSE,
2045  &bug) != SWITCH_STATUS_SUCCESS) {
2046  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot attach bug\n");
2047  goto end;
2048  }
2049 
2050  if ((vval = switch_channel_get_variable(session->channel, "eavesdrop_video_spy_fmt"))) {
2052  }
2053 
2054  msg.from = __FILE__;
2055 
2056  /* Tell the channel we are going to be in a bridge */
2058  switch_core_session_receive_message(session, &msg);
2059  cp = switch_channel_get_caller_profile(tchannel);
2060 
2061  name = cp->caller_id_name;
2062  num = cp->caller_id_number;
2063 
2064  if (flags & ED_COPY_DISPLAY) {
2066  name = cp->callee_id_name;
2067  num = cp->callee_id_number;
2068  } else {
2069  name = cp->caller_id_name;
2070  num = cp->caller_id_number;
2071  }
2072  }
2073 
2074  sanity = 300;
2075  while(switch_channel_up(channel) && !switch_channel_media_ack(channel) && --sanity) {
2076  switch_yield(10000);
2077  }
2078 
2079 
2080  switch_snprintf(cid_buf, sizeof(cid_buf), "%s|%s", name, num);
2081  msg.string_arg = cid_buf;
2083  switch_core_session_receive_message(session, &msg);
2084 
2085  if (switch_channel_test_flag(tchannel, CF_VIDEO)) {
2086 
2088 
2089  switch_core_session_receive_message(tsession, &msg);
2090  }
2091 
2092  while (switch_channel_up_nosig(tchannel) && switch_channel_ready(channel)) {
2093  uint32_t len = sizeof(buf);
2094  switch_event_t *event = NULL;
2095  char *fcommand = NULL;
2096  char db[2] = "";
2097  int vid_bug = 0, vid_dual = 0;
2098 
2099  status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
2100 
2101  if (!SWITCH_READ_ACCEPTABLE(status)) {
2102  goto end_loop;
2103  }
2104 
2106  char *command = switch_event_get_header(event, "eavesdrop-command");
2107  if (command) {
2108  fcommand = switch_core_session_strdup(session, command);
2109  }
2110  switch_event_destroy(&event);
2111  }
2112 
2113  if ((flags & ED_DTMF) && switch_channel_has_dtmf(channel)) {
2114  switch_dtmf_t dtmf = { 0 };
2115  switch_channel_dequeue_dtmf(channel, &dtmf);
2116  db[0] = dtmf.digit;
2117  fcommand = db;
2118  }
2119 
2122  vid_dual = 1;
2123  }
2124 
2125  if (vid_dual || switch_core_media_bug_test_flag(bug, SMBF_READ_VIDEO_PING)) {
2126  vid_bug = 1;
2127  }
2128 
2129  if (fcommand) {
2130  char *d;
2131  for (d = fcommand; *d; d++) {
2132  int z = 1;
2133 
2134  switch (*d) {
2135  case '1':
2138  if (vid_bug) {
2142  }
2143  break;
2144  case '2':
2147  if (vid_bug) {
2151  }
2152  break;
2153  case '3':
2156  if (vid_bug) {
2160  }
2161  break;
2162 
2163  case '4':
2165  break;
2166  case '5':
2168  break;
2169  case '6':
2171  break;
2172  case '0':
2175  if (vid_bug) {
2179  }
2180  break;
2181  case '*':
2182  goto end_loop;
2183  default:
2184  z = 0;
2185  break;
2186 
2187  }
2188 
2189  if (z) {
2190  if (ep->r_buffer) {
2194  }
2195 
2196  if (ep->w_buffer) {
2200  }
2201  }
2202  }
2203  }
2204 
2205  if (!switch_test_flag(read_frame, SFF_CNG)) {
2207  switch_buffer_zwrite(ep->r_buffer, read_frame->data, read_frame->datalen);
2209 
2211  switch_buffer_zwrite(ep->w_buffer, read_frame->data, read_frame->datalen);
2213  }
2214 
2215  if (len > tlen) {
2216  len = tlen;
2217  }
2218 
2219  if (switch_buffer_inuse(ep->buffer) >= len) {
2221  while (switch_buffer_inuse(ep->buffer) >= len) {
2222  int tchanged = 0, changed = 0;
2223 
2224  write_frame.datalen = (uint32_t) switch_buffer_read(ep->buffer, buf, len);
2225  write_frame.samples = write_frame.datalen / 2;
2226 
2227 
2228  switch_core_session_get_read_impl(tsession, &tread_impl);
2230 
2231  if (tread_impl.number_of_channels != ep->tread_impl.number_of_channels ||
2233  tchanged = 1;
2234  }
2235 
2238  changed = 1;
2239  }
2240 
2241  if (changed || tchanged) {
2242 
2243  if (changed) {
2245  "SPYING CHANNEL CODEC CHANGE FROM %dhz@%dc to %dhz@%dc\n",
2250  }
2251 
2252  if (tchanged) {
2254  "SPYED CHANNEL CODEC CHANGE FROM %dhz@%dc to %dhz@%dc\n",
2257  tread_impl.actual_samples_per_second,
2258  tread_impl.number_of_channels);
2259 
2260  tlen = tread_impl.decoded_bytes_per_packet;
2261 
2262  if (len > tlen) {
2263  len = tlen;
2264  }
2265 
2266  switch_core_codec_destroy(&codec);
2267 
2268  if (switch_core_codec_init(&codec,
2269  "L16",
2270  NULL,
2271  NULL,
2272  tread_impl.actual_samples_per_second,
2273  tread_impl.microseconds_per_packet / 1000,
2274  tread_impl.number_of_channels,
2277  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
2278  switch_core_session_rwunlock(tsession);
2279  goto end;
2280  }
2281  }
2282 
2283  ep->read_impl = read_impl;
2284  ep->tread_impl = tread_impl;
2285  }
2286 
2287 
2289  uint32_t rlen = write_frame.datalen / 2 / ep->tread_impl.number_of_channels;
2290 
2291  switch_mux_channels((int16_t *) write_frame.data, rlen, ep->tread_impl.number_of_channels, ep->read_impl.number_of_channels);
2292  write_frame.datalen = rlen * 2 * ep->read_impl.number_of_channels;
2293  write_frame.samples = write_frame.datalen / 2;
2294  }
2295 
2296  if ((status = switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0)) != SWITCH_STATUS_SUCCESS) {
2297  break;
2298  }
2299  }
2301  }
2302 
2303  }
2304 
2305  end_loop:
2306 
2307  /* Tell the channel we are no longer going to be in a bridge */
2309  switch_core_session_receive_message(session, &msg);
2310 
2311 
2312 
2313  end:
2314 
2315  if (codec_initialized)
2316  switch_core_codec_destroy(&codec);
2317 
2318  if (bug) {
2319  switch_core_media_bug_remove(tsession, &bug);
2320  }
2321 
2322  if (ep) {
2323  if (ep->buffer) {
2325  }
2326 
2327  if (ep->r_buffer) {
2329  }
2330 
2331  if (ep->w_buffer) {
2333  }
2334  }
2335 
2336  switch_core_session_rwunlock(tsession);
2337  status = SWITCH_STATUS_SUCCESS;
2338 
2340  }
2341 
2342  return status;
2343 }
2344 
2346 {
2348  const char *p;
2349  const char *vval;
2350  switch_media_bug_t *bug;
2351  switch_status_t status;
2352  time_t to = 0;
2354  uint8_t channels;
2356  struct record_helper *rh = NULL;
2359  char *file_path = NULL;
2360  char *ext;
2361  char *in_file = NULL, *out_file = NULL;
2362 
2363  if ((p = switch_channel_get_variable(channel, "RECORD_HANGUP_ON_ERROR"))) {
2364  hangup_on_error = switch_true(p);
2365  }
2366 
2367  if ((status = switch_channel_pre_answer(channel)) != SWITCH_STATUS_SUCCESS) {
2368  return SWITCH_STATUS_FALSE;
2369  }
2370 
2371  if (!switch_channel_media_up(channel) || !switch_core_session_get_read_codec(session)) {
2372  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can not record session. Media not enabled on channel\n");
2373  return SWITCH_STATUS_FALSE;
2374  }
2375 
2376  switch_core_session_get_read_impl(session, &read_impl);
2377  channels = read_impl.number_of_channels;
2378 
2379  if ((bug = switch_channel_get_private(channel, file))) {
2380  if (switch_true(switch_channel_get_variable(channel, "RECORD_TOGGLE_ON_REPEAT"))) {
2381  return switch_ivr_stop_record_session(session, file);
2382  }
2383 
2384  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Already recording [%s]\n", file);
2385  return SWITCH_STATUS_SUCCESS;
2386  }
2387 
2388 
2389  if ((p = switch_channel_get_variable(channel, "RECORD_CHECK_BRIDGE")) && switch_true(p)) {
2390  switch_core_session_t *other_session;
2391  int exist = 0;
2393 
2394  if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
2395  switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
2396  if ((bug = switch_channel_get_private(other_channel, file))) {
2397  if (switch_true(switch_channel_get_variable(other_channel, "RECORD_TOGGLE_ON_REPEAT"))) {
2398  rstatus = switch_ivr_stop_record_session(other_session, file);
2399  } else {
2400  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(other_session), SWITCH_LOG_WARNING, "Already recording [%s]\n", file);
2401  }
2402  exist = 1;
2403  }
2404  switch_core_session_rwunlock(other_session);
2405  }
2406 
2407  if (exist) {
2408  return rstatus;
2409  }
2410  }
2411 
2412  if (!fh) {
2413  if (!(fh = switch_core_session_alloc(session, sizeof(*fh)))) {
2414  return SWITCH_STATUS_MEMERR;
2415  }
2416  }
2417 
2418  if ((p = switch_channel_get_variable(channel, "RECORD_WRITE_ONLY")) && switch_true(p)) {
2419  flags &= ~SMBF_READ_STREAM;
2420  flags |= SMBF_WRITE_STREAM;
2421  }
2422 
2423  if ((p = switch_channel_get_variable(channel, "RECORD_READ_ONLY")) && switch_true(p)) {
2424  flags &= ~SMBF_WRITE_STREAM;
2425  flags |= SMBF_READ_STREAM;
2426  }
2427 
2428  if (channels == 1) { /* if leg is already stereo this feature is not available */
2429  if ((p = switch_channel_get_variable(channel, "RECORD_STEREO")) && switch_true(p)) {
2430  flags |= SMBF_STEREO;
2431  flags &= ~SMBF_STEREO_SWAP;
2432  channels = 2;
2433  }
2434 
2435  if ((p = switch_channel_get_variable(channel, "RECORD_STEREO_SWAP")) && switch_true(p)) {
2436  flags |= SMBF_STEREO;
2437  flags |= SMBF_STEREO_SWAP;
2438  channels = 2;
2439  }
2440  }
2441 
2442  if ((p = switch_channel_get_variable(channel, "RECORD_ANSWER_REQ")) && switch_true(p)) {
2443  flags |= SMBF_ANSWER_REQ;
2444  }
2445 
2446  if ((p = switch_channel_get_variable(channel, "RECORD_BRIDGE_REQ")) && switch_true(p)) {
2447  flags |= SMBF_BRIDGE_REQ;
2448  }
2449 
2450  if ((p = switch_channel_get_variable(channel, "RECORD_APPEND")) && switch_true(p)) {
2451  file_flags |= SWITCH_FILE_WRITE_APPEND;
2452  }
2453 
2454 
2455  fh->samplerate = 0;
2456  if ((vval = switch_channel_get_variable(channel, "record_sample_rate"))) {
2457  int tmp = 0;
2458 
2459  tmp = atoi(vval);
2460 
2461  if (switch_is_valid_rate(tmp)) {
2462  fh->samplerate = tmp;
2463  }
2464  }
2465 
2466  if (!fh->samplerate) {
2467  fh->samplerate = read_impl.actual_samples_per_second;
2468  }
2469 
2470  fh->channels = channels;
2471 
2472  if ((vval = switch_channel_get_variable(channel, "enable_file_write_buffering"))) {
2473  int tmp = atoi(vval);
2474 
2475  if (tmp > 0) {
2476  fh->pre_buffer_datalen = tmp;
2477  } else if (switch_true(vval)) {
2478  fh->pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN;
2479  }
2480 
2481  } else {
2482  fh->pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN;
2483  }
2484 
2485 
2486  if (!switch_is_file_path(file)) {
2487  char *tfile = NULL;
2488  char *e;
2489  const char *prefix;
2490 
2491  prefix = switch_channel_get_variable(channel, "sound_prefix");
2492 
2493  if (!prefix) {
2494  prefix = SWITCH_GLOBAL_dirs.base_dir;
2495  }
2496 
2497  if (*file == '[') {
2498  tfile = switch_core_session_strdup(session, file);
2499  if ((e = switch_find_end_paren(tfile, '[', ']'))) {
2500  *e = '\0';
2501  file = e + 1;
2502  } else {
2503  tfile = NULL;
2504  }
2505  } else {
2506  file_path = switch_core_session_sprintf(session, "%s%s%s", prefix, SWITCH_PATH_SEPARATOR, file);
2507  }
2508 
2509  file = switch_core_session_sprintf(session, "%s%s%s%s%s", switch_str_nil(tfile), tfile ? "]" : "", prefix, SWITCH_PATH_SEPARATOR, file);
2510  } else {
2511  file_path = switch_core_session_strdup(session, file);
2512  }
2513 
2514  if (file_path && !strstr(file_path, SWITCH_URL_SEPARATOR)) {
2515  char *p;
2516  char *path = switch_core_session_strdup(session, file_path);
2517 
2518  if ((p = strrchr(path, *SWITCH_PATH_SEPARATOR))) {
2519  *p = '\0';
2520 
2521  if (*path == '{') {
2522  path = switch_find_end_paren(path, '{', '}') + 1;
2523  }
2524 
2526  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error creating %s\n", path);
2527  return SWITCH_STATUS_GENERR;
2528  }
2529 
2530  } else {
2531  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error finding the folder path section in '%s'\n", path);
2532  path = NULL;
2533  }
2534  }
2535 
2536  rh = switch_core_session_alloc(session, sizeof(*rh));
2537 
2538  if ((ext = strrchr(file, '.'))) {
2539  ext++;
2540 
2541  if (switch_channel_test_flag(channel, CF_VIDEO)) {
2542  file_flags |= SWITCH_FILE_FLAG_VIDEO;
2543  }
2544 
2545  if (switch_core_file_open(fh, file, channels, read_impl.actual_samples_per_second, file_flags, NULL) != SWITCH_STATUS_SUCCESS) {
2546  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error opening %s\n", file);
2547  if (hangup_on_error) {
2550  }
2551  return SWITCH_STATUS_GENERR;
2552  }
2553 
2555  //switch_core_media_set_video_file(session, fh, SWITCH_RW_READ);
2556  //switch_channel_set_flag_recursive(session->channel, CF_VIDEO_DECODED_READ);
2557 
2558  if ((vval = switch_channel_get_variable(channel, "record_concat_video")) && switch_true(vval)) {
2559  flags |= SMBF_READ_VIDEO_STREAM;
2560  flags |= SMBF_WRITE_VIDEO_STREAM;
2561  } else {
2562  flags |= SMBF_READ_VIDEO_PING;
2563  }
2564  } else {
2565  flags &= ~SMBF_READ_VIDEO_PING;
2566  flags &= ~SMBF_READ_VIDEO_STREAM;
2567  flags &= ~SMBF_WRITE_VIDEO_STREAM;
2568  }
2569 
2570  } else {
2571  int tflags = 0;
2572 
2573  ext = read_impl.iananame;
2574 
2575  in_file = switch_core_session_sprintf(session, "%s-in.%s", file, ext);
2576  out_file = switch_core_session_sprintf(session, "%s-out.%s", file, ext);
2577  rh->in_fh.pre_buffer_datalen = rh->out_fh.pre_buffer_datalen = fh->pre_buffer_datalen;
2578  channels = 1;
2581 
2582  if (switch_core_file_open(&rh->in_fh, in_file, channels, read_impl.actual_samples_per_second, file_flags, NULL) != SWITCH_STATUS_SUCCESS) {
2583  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error opening %s\n", in_file);
2584  if (hangup_on_error) {
2587  }
2588  return SWITCH_STATUS_GENERR;
2589  }
2590 
2591  if (switch_core_file_open(&rh->out_fh, out_file, channels, read_impl.actual_samples_per_second, file_flags, NULL) != SWITCH_STATUS_SUCCESS) {
2592  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error opening %s\n", out_file);
2594  if (hangup_on_error) {
2597  }
2598  return SWITCH_STATUS_GENERR;
2599  }
2600 
2601  rh->native = 1;
2602  fh = NULL;
2603 
2604  if ((flags & SMBF_WRITE_STREAM)) {
2605  tflags |= SMBF_TAP_NATIVE_WRITE;
2606  }
2607 
2608  if ((flags & SMBF_READ_STREAM)) {
2609  tflags |= SMBF_TAP_NATIVE_READ;
2610  }
2611 
2612  flags = tflags;
2613  }
2614 
2615 
2616 
2617  if ((p = switch_channel_get_variable(channel, "RECORD_TITLE"))) {
2618  vval = (const char *) switch_core_session_strdup(session, p);
2620  switch_channel_set_variable(channel, "RECORD_TITLE", NULL);
2621  }
2622 
2623  if ((p = switch_channel_get_variable(channel, "RECORD_COPYRIGHT"))) {
2624  vval = (const char *) switch_core_session_strdup(session, p);
2626  switch_channel_set_variable(channel, "RECORD_COPYRIGHT", NULL);
2627  }
2628 
2629  if ((p = switch_channel_get_variable(channel, "RECORD_SOFTWARE"))) {
2630  vval = (const char *) switch_core_session_strdup(session, p);
2632  switch_channel_set_variable(channel, "RECORD_SOFTWARE", NULL);
2633  }
2634 
2635  if ((p = switch_channel_get_variable(channel, "RECORD_ARTIST"))) {
2636  vval = (const char *) switch_core_session_strdup(session, p);
2638  switch_channel_set_variable(channel, "RECORD_ARTIST", NULL);
2639  }
2640 
2641  if ((p = switch_channel_get_variable(channel, "RECORD_COMMENT"))) {
2642  vval = (const char *) switch_core_session_strdup(session, p);
2644  switch_channel_set_variable(channel, "RECORD_COMMENT", NULL);
2645  }
2646 
2647  if ((p = switch_channel_get_variable(channel, "RECORD_DATE"))) {
2648  vval = (const char *) switch_core_session_strdup(session, p);
2650  switch_channel_set_variable(channel, "RECORD_DATE", NULL);
2651  }
2652 
2653  if (limit) {
2654  to = switch_epoch_time_now(NULL) + limit;
2655  }
2656 
2657  rh->fh = fh;
2658  rh->file = switch_core_session_strdup(session, file);
2659  rh->packet_len = read_impl.decoded_bytes_per_packet;
2660 
2661  if (file_flags & SWITCH_FILE_WRITE_APPEND) {
2662  rh->min_sec = 3;
2663  }
2664 
2665  if ((p = switch_channel_get_variable(channel, "RECORD_MIN_SEC"))) {
2666  int tmp = atoi(p);
2667  if (tmp >= 0) {
2668  rh->min_sec = tmp;
2669  }
2670  }
2671 
2672  if ((p = switch_channel_get_variable(channel, "RECORD_INITIAL_TIMEOUT_MS"))) {
2673  int tmp = atoi(p);
2674  if (tmp >= 0) {
2675  rh->initial_timeout_ms = tmp;
2676  rh->silence_threshold = 200;
2677  }
2678  }
2679 
2680  if ((p = switch_channel_get_variable(channel, "RECORD_FINAL_TIMEOUT_MS"))) {
2681  int tmp = atoi(p);
2682  if (tmp >= 0) {
2683  rh->final_timeout_ms = tmp;
2684  rh->silence_threshold = 200;
2685  }
2686  }
2687 
2688  if ((p = switch_channel_get_variable(channel, "RECORD_SILENCE_THRESHOLD"))) {
2689  int tmp = atoi(p);
2690  if (tmp >= 0) {
2691  rh->silence_threshold = tmp;
2692  }
2693  }
2694 
2696 
2697  if ((status = switch_core_media_bug_add(session, "session_record", file,
2698  record_callback, rh, to, flags, &bug)) != SWITCH_STATUS_SUCCESS) {
2699  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error adding media bug for file %s\n", file);
2700  if (rh->native) {
2703  } else {
2705  }
2706  return status;
2707  }
2708 
2709  if ((p = switch_channel_get_variable(channel, "RECORD_PRE_BUFFER_FRAMES"))) {
2710  int tmp = atoi(p);
2711 
2712  if (tmp > 0) {
2714  }
2715  } else {
2717  }
2718 
2719  switch_channel_set_private(channel, file, bug);
2720 
2721  if (switch_channel_test_flag(channel, CF_VIDEO)) {
2722  switch_core_session_message_t msg = { 0 };
2723 
2724  msg.from = __FILE__;
2726 
2727  switch_core_session_receive_message(session, &msg);
2728  }
2729 
2730  return SWITCH_STATUS_SUCCESS;
2731 }
2732 
2733 
2734 typedef struct {
2735  SpeexPreprocessState *read_st;
2736  SpeexPreprocessState *write_st;
2737  SpeexEchoState *read_ec;
2738  SpeexEchoState *write_ec;
2739  switch_byte_t read_data[2048];
2740  switch_byte_t write_data[2048];
2741  switch_byte_t read_out[2048];
2742  switch_byte_t write_out[2048];
2745  int done;
2746 } pp_cb_t;
2747 
2749 {
2752  pp_cb_t *cb = (pp_cb_t *) user_data;
2753  switch_codec_implementation_t read_impl = { 0 };
2754  switch_frame_t *frame = NULL;
2755 
2756  switch_core_session_get_read_impl(session, &read_impl);
2757 
2758  switch (type) {
2759  case SWITCH_ABC_TYPE_INIT:
2760  {
2763  }
2764  break;
2765  case SWITCH_ABC_TYPE_CLOSE:
2766  {
2767  if (cb->read_st) {
2768  speex_preprocess_state_destroy(cb->read_st);
2769  }
2770 
2771  if (cb->write_st) {
2772  speex_preprocess_state_destroy(cb->write_st);
2773  }
2774 
2775  if (cb->read_ec) {
2776  speex_echo_state_destroy(cb->read_ec);
2777  }
2778 
2779  if (cb->write_ec) {
2780  speex_echo_state_destroy(cb->write_ec);
2781  }
2782 
2783  switch_channel_set_private(channel, "_preprocess", NULL);
2784  }
2785  break;
2787  {
2788  if (cb->done)
2789  return SWITCH_FALSE;
2791 
2792  if (cb->read_st) {
2793 
2794  if (cb->read_ec) {
2795  speex_echo_cancellation(cb->read_ec, (int16_t *) frame->data, (int16_t *) cb->write_data, (int16_t *) cb->read_out);
2796  memcpy(frame->data, cb->read_out, frame->datalen);
2797  }
2798 
2799  speex_preprocess_run(cb->read_st, frame->data);
2800  }
2801 
2802  if (cb->write_ec) {
2803  memcpy(cb->read_data, frame->data, frame->datalen);
2804  }
2805  }
2806  break;
2808  {
2809  if (cb->done)
2810  return SWITCH_FALSE;
2812 
2813  if (cb->write_st) {
2814 
2815  if (cb->write_ec) {
2816  speex_echo_cancellation(cb->write_ec, (int16_t *) frame->data, (int16_t *) cb->read_data, (int16_t *) cb->write_out);
2817  memcpy(frame->data, cb->write_out, frame->datalen);
2818  }
2819 
2820  speex_preprocess_run(cb->write_st, frame->data);
2821  }
2822 
2823  if (cb->read_ec) {
2824  memcpy(cb->write_data, frame->data, frame->datalen);
2825  }
2826  }
2827  break;
2828  default:
2829  break;
2830  }
2831 
2832  return SWITCH_TRUE;
2833 }
2834 
2836 {
2838  switch_media_bug_t *bug;
2839  switch_status_t status;
2840  time_t to = 0;
2842  switch_codec_implementation_t read_impl = { 0 };
2843  pp_cb_t *cb;
2844  int update = 0;
2845  int argc;
2846  char *mydata = NULL, *argv[5];
2847  int i = 0;
2848 
2849  switch_core_session_get_read_impl(session, &read_impl);
2850 
2851  if ((cb = switch_channel_get_private(channel, "_preprocess"))) {
2852  update = 1;
2853  } else {
2854  cb = switch_core_session_alloc(session, sizeof(*cb));
2855  }
2856 
2857 
2858  if (update) {
2859  if (!strcasecmp(cmds, "stop")) {
2860  cb->done = 1;
2861  return SWITCH_STATUS_SUCCESS;
2862  }
2863  }
2864 
2865  mydata = strdup(cmds);
2866  argc = switch_separate_string(mydata, ',', argv, (sizeof(argv) / sizeof(argv[0])));
2867 
2868  for (i = 0; i < argc; i++) {
2869  char *var = argv[i];
2870  char *val = NULL;
2871  char rw;
2872  int tr;
2873  int err = 1;
2874  SpeexPreprocessState *st = NULL;
2875  SpeexEchoState *ec = NULL;
2876  switch_mutex_t *mutex = NULL;
2877  int r = 0;
2878 
2879  if (var) {
2880  if ((val = strchr(var, '='))) {
2881  *val++ = '\0';
2882 
2883  rw = *var++;
2884  while (*var == '.' || *var == '_') {
2885  var++;
2886  }
2887 
2888  if (rw == 'r') {
2889  if (!cb->read_st) {
2890  cb->read_st = speex_preprocess_state_init(read_impl.samples_per_packet, read_impl.samples_per_second);
2891  flags |= SMBF_READ_REPLACE;
2892  }
2893  st = cb->read_st;
2894  ec = cb->read_ec;
2895  mutex = cb->read_mutex;
2896  } else if (rw == 'w') {
2897  if (!cb->write_st) {
2898  cb->write_st = speex_preprocess_state_init(read_impl.samples_per_packet, read_impl.samples_per_second);
2899  flags |= SMBF_WRITE_REPLACE;
2900  }
2901  st = cb->write_st;
2902  ec = cb->write_ec;
2903  mutex = cb->write_mutex;
2904  }
2905 
2906  if (mutex)
2907  switch_mutex_lock(mutex);
2908 
2909  if (st) {
2910  err = 0;
2911  tr = switch_true(val);
2912  if (!strcasecmp(var, "agc")) {
2913  int l = read_impl.samples_per_second;
2914  int tmp = atoi(val);
2915 
2916  if (!tr) {
2917  l = tmp;
2918  }
2919 
2920  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setting AGC on %c to %d\n", rw, tr);
2921  speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC, &tr);
2922  speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &l);
2923 
2924  } else if (!strcasecmp(var, "noise_suppress")) {
2925  int db = atoi(val);
2926  if (db < 0) {
2927  r = speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &db);
2928  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setting NOISE_SUPPRESS on %c to %d [%d]\n", rw, db,
2929  r);
2930  } else {
2931  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Syntax error noise_suppress should be in -db\n");
2932  }
2933  } else if (!strcasecmp(var, "echo_cancel")) {
2934  int tail = 1024;
2935  int tmp = atoi(val);
2936 
2937  if (!tr && tmp > 0) {
2938  tail = tmp;
2939  } else if (!tr) {
2940  if (ec) {
2941  if (rw == 'r') {
2942  speex_echo_state_destroy(cb->read_ec);
2943  cb->read_ec = NULL;
2944  } else {
2945  speex_echo_state_destroy(cb->write_ec);
2946  cb->write_ec = NULL;
2947  }
2948  }
2949 
2950  ec = NULL;
2951  }
2952 
2953  if (!ec) {
2954  if (rw == 'r') {
2955  ec = cb->read_ec = speex_echo_state_init(read_impl.samples_per_packet, tail);
2956  speex_echo_ctl(ec, SPEEX_ECHO_SET_SAMPLING_RATE, &read_impl.samples_per_second);
2957  flags |= SMBF_WRITE_REPLACE;
2958  } else {
2959  ec = cb->write_ec = speex_echo_state_init(read_impl.samples_per_packet, tail);
2960  speex_echo_ctl(ec, SPEEX_ECHO_SET_SAMPLING_RATE, &read_impl.samples_per_second);
2961  flags |= SMBF_READ_REPLACE;
2962  }
2963  speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_ECHO_STATE, ec);
2964  }
2965 
2966 
2967  } else if (!strcasecmp(var, "echo_suppress")) {
2968  int db = atoi(val);
2969  if (db < 0) {
2970  speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS, &db);
2971  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setting ECHO_SUPPRESS on %c to %d [%d]\n", rw, db,
2972  r);
2973  } else {
2974  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Syntax error echo_suppress should be in -db\n");
2975  }
2976  } else {
2977  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Warning unknown parameter [%s] \n", var);
2978  }
2979  }
2980  }
2981 
2982  if (mutex)
2983  switch_mutex_unlock(mutex);
2984 
2985  if (err) {
2986  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Syntax error parsing preprocessor commands\n");
2987  }
2988 
2989  } else {
2990  break;
2991  }
2992  }
2993 
2994 
2995  switch_safe_free(mydata);
2996 
2997  if (update) {
2998  return SWITCH_STATUS_SUCCESS;
2999  }
3000 
3001 
3002  if ((status = switch_core_media_bug_add(session, "preprocess", NULL,
3003  preprocess_callback, cb, to, flags, &bug)) != SWITCH_STATUS_SUCCESS) {
3004  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error adding media bug.\n");
3005  if (cb->read_st) {
3006  speex_preprocess_state_destroy(cb->read_st);
3007  }
3008 
3009  if (cb->write_st) {
3010  speex_preprocess_state_destroy(cb->write_st);
3011  }
3012 
3013  if (cb->read_ec) {
3014  speex_echo_state_destroy(cb->read_ec);
3015  }
3016 
3017  if (cb->write_ec) {
3018  speex_echo_state_destroy(cb->write_ec);
3019  }
3020 
3021  return status;
3022  }
3023 
3024  switch_channel_set_private(channel, "_preprocess", cb);
3025 
3026  return SWITCH_STATUS_SUCCESS;
3027 }
3028 
3029 
3030 typedef struct {
3032  int mute;
3038 
3040 {
3041  switch_session_audio_t *pvt = (switch_session_audio_t *) user_data;
3042  switch_frame_t *frame = NULL;
3043  int level = 0, mute = 0;
3045  switch_codec_implementation_t read_impl = { 0 };
3046 
3047  switch_core_session_get_read_impl(session, &read_impl);
3048 
3049 
3051  if (!(pvt->read_level || pvt->write_level || pvt->read_mute || pvt->write_mute)) {
3053  return SWITCH_FALSE;
3054  }
3055  }
3056 
3057  if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
3058  level = pvt->read_level;
3059  mute = pvt->read_mute;
3061  } else if (type == SWITCH_ABC_TYPE_WRITE_REPLACE) {
3062  level = pvt->write_level;
3063  mute = pvt->write_mute;
3065  }
3066 
3067  if (frame) {
3068  if (mute) {
3069  if (mute > 1) {
3070  switch_generate_sln_silence(frame->data, frame->datalen / 2, read_impl.number_of_channels, mute);
3071  } else {
3072  memset(frame->data, 0, frame->datalen);
3073  }
3074  } else if (level) {
3075  switch_change_sln_volume(frame->data, frame->datalen / 2, level);
3076  }
3077 
3078  if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
3080  } else if (type == SWITCH_ABC_TYPE_WRITE_REPLACE) {
3082  }
3083  }
3084 
3085  return SWITCH_TRUE;
3086 }
3087 
3089 {
3090  switch_media_bug_t *bug;
3092 
3093  if ((bug = switch_channel_get_private(channel, "__audio"))) {
3094  switch_channel_set_private(channel, "__audio", NULL);
3095  switch_core_media_bug_remove(session, &bug);
3096  return SWITCH_STATUS_SUCCESS;
3097  }
3098  return SWITCH_STATUS_FALSE;
3099 }
3100 
3101 SWITCH_DECLARE(switch_status_t) switch_ivr_session_audio(switch_core_session_t *session, const char *cmd, const char *direction, int level)
3102 {
3104  switch_media_bug_t *bug;
3105  switch_status_t status;
3107  switch_codec_implementation_t read_impl = { 0 };
3108  int existing = 0, c_read = 0, c_write = 0, flags = SMBF_NO_PAUSE;
3109 
3111  return SWITCH_STATUS_FALSE;
3112  }
3113 
3114  switch_core_session_get_read_impl(session, &read_impl);
3115 
3116 
3117  if ((bug = switch_channel_get_private(channel, "__audio"))) {
3119  existing = 1;
3120  } else {
3121  if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt)))) {
3122  return SWITCH_STATUS_MEMERR;
3123  }
3124 
3125  pvt->session = session;
3126  }
3127 
3128 
3129  if (!strcasecmp(direction, "write")) {
3130  flags = SMBF_WRITE_REPLACE;
3131  c_write = 1;
3132  } else if (!strcasecmp(direction, "read")) {
3133  flags = SMBF_READ_REPLACE;
3134  c_read = 1;
3135  } else if (!strcasecmp(direction, "both")) {
3137  c_read = c_write = 1;
3138  }
3139 
3140 
3141  if (!strcasecmp(cmd, "mute")) {
3142  if (c_read) {
3143  pvt->read_mute = level;
3144  pvt->read_level = 0;
3145  }
3146  if (c_write) {
3147  pvt->write_mute = level;
3148  pvt->write_level = 0;
3149  }
3150  } else if (!strcasecmp(cmd, "level")) {
3151  if (level < 5 && level > -5) {
3152  if (c_read) {
3153  pvt->read_level = level;
3154  }
3155  if (c_write) {
3156  pvt->write_level = level;
3157  }
3158  }
3159  }
3160 
3161  if (existing) {
3162  switch_core_media_bug_set_flag(bug, flags);
3163  } else {
3164  if ((status = switch_core_media_bug_add(session, "audio", cmd,
3165  session_audio_callback, pvt, 0, flags, &bug)) != SWITCH_STATUS_SUCCESS) {
3166  return status;
3167  }
3168 
3169  switch_channel_set_private(channel, "__audio", bug);
3170  }
3171 
3172 
3173  return SWITCH_STATUS_SUCCESS;
3174 }
3175 
3176 
3177 typedef struct {
3181 
3183 {
3184  switch_inband_dtmf_t *pvt = (switch_inband_dtmf_t *) user_data;
3185  switch_frame_t *frame = NULL;
3187  teletone_hit_type_t hit;
3188 
3189  switch (type) {
3190  case SWITCH_ABC_TYPE_INIT:
3191  break;
3192  case SWITCH_ABC_TYPE_CLOSE:
3193  break;
3195  if ((frame = switch_core_media_bug_get_read_replace_frame(bug))) {
3196  if ((hit = teletone_dtmf_detect(&pvt->dtmf_detect, frame->data, frame->samples)) == TT_HIT_END) {
3197  switch_dtmf_t dtmf = {0};
3198 
3199  teletone_dtmf_get(&pvt->dtmf_detect, &dtmf.digit, &dtmf.duration);
3201  dtmf.digit, dtmf.duration);
3203  switch_channel_queue_dtmf(channel, &dtmf);
3204  }
3206  }
3207  break;
3208  case SWITCH_ABC_TYPE_WRITE:
3209  default:
3210  break;
3211  }
3212 
3213  return SWITCH_TRUE;
3214 }
3215 
3217 {
3218  switch_media_bug_t *bug;
3220 
3221  if ((bug = switch_channel_get_private(channel, "dtmf"))) {
3222  switch_channel_set_private(channel, "dtmf", NULL);
3223  switch_core_media_bug_remove(session, &bug);
3224  return SWITCH_STATUS_SUCCESS;
3225  }
3226  return SWITCH_STATUS_FALSE;
3227 }
3228 
3230 {
3232  switch_media_bug_t *bug;
3233  switch_status_t status;
3234  switch_inband_dtmf_t *pvt;
3235  switch_codec_implementation_t read_impl = { 0 };
3236 
3237  switch_core_session_get_read_impl(session, &read_impl);
3238 
3239  if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt)))) {
3240  return SWITCH_STATUS_MEMERR;
3241  }
3242 
3244 
3245  pvt->session = session;
3246 
3247 
3249  return SWITCH_STATUS_FALSE;
3250  }
3251 
3252  if ((status = switch_core_media_bug_add(session, "inband_dtmf", NULL,
3254  return status;
3255  }
3256 
3257  switch_channel_set_private(channel, "dtmf", bug);
3258 
3259  return SWITCH_STATUS_SUCCESS;
3260 }
3261 
3262 typedef struct {
3268  int read;
3269  int ready;
3270  int skip;
3272 
3274 {
3275  switch_buffer_t *audio_buffer = ts->user_data;
3276  int wrote;
3277 
3278  if (!audio_buffer) {
3279  return -1;
3280  }
3281 
3282  wrote = teletone_mux_tones(ts, map);
3283  switch_buffer_write(audio_buffer, ts->buffer, wrote * 2);
3284 
3285  return 0;
3286 }
3287 
3289 {
3291  switch_media_bug_t *bug = switch_channel_get_private(channel, "dtmf_generate");
3293 
3294  if (bug) {
3296 
3297  if (pvt) {
3298  switch_mutex_lock(pvt->mutex);
3299 
3300  if (pvt->ready) {
3301  switch_dtmf_t *dt = NULL;
3302  switch_zmalloc(dt, sizeof(*dt));
3303  *dt = *dtmf;
3304  if (!switch_buffer_inuse(pvt->audio_buffer)) {
3305  pvt->skip = 10;
3306  }
3308  switch_event_t *event;
3309 
3311  switch_channel_event_set_data(channel, event);
3312  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "DTMF-Digit", "%c", dtmf->digit);
3313  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "DTMF-Duration", "%u", dtmf->duration);
3314  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "DTMF-Source", "APP");
3315  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "DTMF-Conversion", "native:inband");
3317  switch_core_session_queue_event(session, &event);
3318  } else {
3319  switch_event_fire(&event);
3320  }
3321  }
3322 
3323  dt = NULL;
3324  /*
3325  SWITCH_STATUS_FALSE indicates pretend there never was a DTMF
3326  since we will be generating it inband now.
3327  */
3328  status = SWITCH_STATUS_FALSE;
3329  } else {
3330  free(dt);
3331  }
3332  }
3333  switch_mutex_unlock(pvt->mutex);
3334  }
3335  }
3336 
3337  return status;
3338 }
3339 
3340 
3342 {
3344  switch_frame_t *frame;
3345  switch_codec_implementation_t read_impl = { 0 };
3346  switch_core_session_get_read_impl(pvt->session, &read_impl);
3347 
3348  switch (type) {
3349  case SWITCH_ABC_TYPE_INIT:
3350  {
3352  switch_buffer_create_dynamic(&pvt->audio_buffer, 512, 1024, 0);
3354  pvt->ts.rate = read_impl.actual_samples_per_second;
3355  pvt->ts.channels = 1;
3357  if (pvt->read) {
3358  switch_core_event_hook_add_recv_dtmf(pvt->session, generate_on_dtmf);
3359  } else {
3360  switch_core_event_hook_add_send_dtmf(pvt->session, generate_on_dtmf);
3361  }
3362  switch_mutex_lock(pvt->mutex);
3363  pvt->ready = 1;
3364  switch_mutex_unlock(pvt->mutex);
3365  }
3366  break;
3367  case SWITCH_ABC_TYPE_CLOSE:
3368  {
3369  switch_mutex_lock(pvt->mutex);
3370  pvt->ready = 0;
3371  switch_core_event_hook_remove_recv_dtmf(pvt->session, generate_on_dtmf);
3374  switch_mutex_unlock(pvt->mutex);
3375  }
3376  break;
3379  {
3380  switch_size_t bytes;
3381  void *pop;
3382 
3383  if (pvt->skip) {
3384  pvt->skip--;
3385  return SWITCH_TRUE;
3386  }
3387 
3388 
3389  switch_mutex_lock(pvt->mutex);
3390 
3391  if (!pvt->ready) {
3392  switch_mutex_unlock(pvt->mutex);
3393  return SWITCH_FALSE;
3394  }
3395 
3396  if (pvt->read) {
3398  } else {
3400  }
3401 
3402  if (!switch_buffer_inuse(pvt->audio_buffer)) {
3404  switch_dtmf_t *dtmf = (switch_dtmf_t *) pop;
3405 
3406 
3407  if (dtmf->source != SWITCH_DTMF_INBAND_AUDIO) {
3408  char buf[2] = "";
3409  int duration = dtmf->duration;
3410 
3411  buf[0] = dtmf->digit;
3412  if (duration > (int)switch_core_max_dtmf_duration(0)) {
3413  duration = switch_core_default_dtmf_duration(0);
3415  SWITCH_LOG_WARNING, "%s Truncating DTMF duration %d ms to %d ms\n",
3417  }
3418 
3419 
3420  pvt->ts.duration = duration;
3421  teletone_run(&pvt->ts, buf);
3422  }
3423  free(pop);
3424  }
3425  }
3426 
3427  if (switch_buffer_inuse(pvt->audio_buffer) && (bytes = switch_buffer_read(pvt->audio_buffer, frame->data, frame->datalen))) {
3428  if (bytes < frame->datalen) {
3429  switch_byte_t *dp = frame->data;
3430  memset(dp + bytes, 0, frame->datalen - bytes);
3431  }
3432  }
3433 
3434  if (pvt->read) {
3436  } else {
3438  }
3439 
3440  switch_mutex_unlock(pvt->mutex);
3441  }
3442  break;
3443  default:
3444  break;
3445  }
3446 
3447  return SWITCH_TRUE;
3448 }
3449 
3451 {
3453  switch_media_bug_t *bug = switch_channel_get_private(channel, "dtmf_generate");
3454 
3455  if (bug) {
3456  switch_channel_set_private(channel, "dtmf_generate", NULL);
3457  switch_core_media_bug_remove(session, &bug);
3458  return SWITCH_STATUS_SUCCESS;
3459  }
3460 
3461  return SWITCH_STATUS_FALSE;
3462 
3463 }
3464 
3466 {
3468  switch_media_bug_t *bug;
3469  switch_status_t status;
3471 
3472  if ((status = switch_channel_pre_answer(channel)) != SWITCH_STATUS_SUCCESS) {
3473  return SWITCH_STATUS_FALSE;
3474  }
3475 
3476  if (!switch_channel_media_up(channel) || !switch_core_session_get_read_codec(session)) {
3477  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can not install inband dtmf generate. Media not enabled on channel\n");
3478  return status;
3479  }
3480 
3481  if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt)))) {
3482  return SWITCH_STATUS_MEMERR;
3483  }
3484 
3485  pvt->session = session;
3486  pvt->read = !!read_stream;
3487 
3488  if ((status = switch_core_media_bug_add(session, "inband_dtmf_generate", NULL,
3491  return status;
3492  }
3493 
3494  switch_channel_set_private(channel, "dtmf_generate", bug);
3495 
3496  return SWITCH_STATUS_SUCCESS;
3497 }
3498 
3499 #define MAX_TONES 16
3500 typedef struct {
3502  char *app;
3503  char *data;
3504  char *key;
3506  int up;
3508  int hits;
3509  int sleep;
3510  int expires;
3513  int once;
3517 
3518 typedef struct {
3520  int index;
3526 
3527 
3529 {
3530  char *total_time = switch_mprintf("%d", (int)(switch_micro_time_now() - cont->list[index].start_time) / 1000);
3531 
3532  switch_channel_set_variable_name_printf(switch_core_session_get_channel(cont->session), total_time, "tone_detect_%s_total_time",
3533  cont->list[index].key);
3534  switch_safe_free(total_time);
3535 }
3536 
3538 {
3540  switch_tone_container_t *cont = switch_channel_get_private(channel, "_tone_detect_");
3541  int i;
3542 
3543  if (!cont || !cont->detect_fax || dtmf->digit != 'f') {
3544  return SWITCH_STATUS_SUCCESS;
3545  }
3546 
3547  i = cont->detect_fax;
3548 
3549  tone_detect_set_total_time(cont, i);
3550  if (cont->list[i].callback) {
3551  cont->list[i].callback(cont->session, cont->list[i].app, cont->list[i].data);
3552  } else {
3555 
3556  if (cont->list[i].app) {
3558  }
3559  }
3560 
3561  return SWITCH_STATUS_SUCCESS;
3562 
3563 }
3564 
3566 {
3567  switch_tone_container_t *cont = (switch_tone_container_t *) user_data;
3568  switch_frame_t *frame = NULL;
3569  int i = 0;
3570  switch_bool_t rval = SWITCH_TRUE;
3571 
3572  switch (type) {
3573  case SWITCH_ABC_TYPE_INIT:
3574  if (cont) {
3575  cont->bug_running = 1;
3576  }
3577  break;
3578  case SWITCH_ABC_TYPE_CLOSE:
3579  break;
3582  {
3583 
3584  if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
3586  } else {
3588  }
3589 
3590  for (i = 0; i < cont->index; i++) {
3591  int skip = 0;
3592 
3593  if (cont->list[i].sleep) {
3594  cont->list[i].sleep--;
3595  if (cont->list[i].sleep) {
3596  skip = 1;
3597  }
3598  }
3599 
3600  if (cont->list[i].expires) {
3601  cont->list[i].expires--;
3602  if (!cont->list[i].expires) {
3603  cont->list[i].hits = 0;
3604  cont->list[i].sleep = 0;
3605  cont->list[i].expires = 0;
3606  }
3607  }
3608 
3609  if (!cont->list[i].up)
3610  skip = 1;
3611 
3612  if (skip)
3613  continue;
3614 
3615  if (teletone_multi_tone_detect(&cont->list[i].mt, frame->data, frame->samples)) {
3616  switch_event_t *event;
3617  cont->list[i].hits++;
3618 
3620  cont->list[i].key, cont->list[i].hits, cont->list[i].total_hits);
3621  cont->list[i].sleep = cont->list[i].default_sleep;
3622  cont->list[i].expires = cont->list[i].default_expires;
3623 
3624  if (cont->list[i].hits >= cont->list[i].total_hits) {
3626  cont->list[i].key);
3627  tone_detect_set_total_time(cont, i);
3628  cont->list[i].up = 0;
3629 
3630  if (cont->list[i].callback) {
3631  if ((rval = cont->list[i].callback(cont->session, cont->list[i].app, cont->list[i].data)) == SWITCH_TRUE) {
3633  cont->list[i].key);
3634  cont->list[i].up = 1;
3635  cont->list[i].hits = 0;
3636  cont->list[i].sleep = 0;
3637  cont->list[i].expires = 0;
3638  }
3639  } else {
3641  if (cont->list[i].app) {
3643  }
3644  }
3645 
3646  if (cont->list[i].once) {
3647  rval = SWITCH_FALSE;
3648  }
3649 
3651  switch_event_t *dup;
3652  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Detected-Tone", cont->list[i].key);
3653 
3654  if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {
3655  switch_event_fire(&dup);
3656  }
3657 
3660  "Event queue failed!\n");
3661  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
3662  switch_event_fire(&event);
3663  }
3664  }
3665  }
3666  }
3667  }
3668  }
3669  break;
3670  case SWITCH_ABC_TYPE_WRITE:
3671  default:
3672  break;
3673  }
3674 
3675  if (rval == SWITCH_FALSE) {
3676  cont->bug_running = 0;
3677  }
3678 
3679  return rval;
3680 }
3681 
3683 {
3685  switch_tone_container_t *cont = switch_channel_get_private(channel, "_tone_detect_");
3686  int i = 0;
3687 
3688  if (cont) {
3689  switch_channel_set_private(channel, "_tone_detect_", NULL);
3690  for (i = 0; i < cont->index; i++) {
3691  cont->list[i].up = 0;
3692  }
3693  switch_core_media_bug_remove(session, &cont->bug);
3694  if (cont->detect_fax) {
3695  cont->detect_fax = 0;
3696  }
3697  return SWITCH_STATUS_SUCCESS;
3698  }
3699  return SWITCH_STATUS_FALSE;
3700 }
3701 
3703  const char *key, const char *tone_spec,
3704  const char *flags, time_t timeout,
3705  int hits, const char *app, const char *data, switch_tone_detect_callback_t callback)
3706 {
3708  switch_status_t status;
3709  switch_tone_container_t *cont = switch_channel_get_private(channel, "_tone_detect_");
3710  char *p, *next;
3711  int i = 0, ok = 0, detect_fax = 0;
3712  switch_media_bug_flag_t bflags = 0;
3713  const char *var;
3714  switch_codec_implementation_t read_impl = { 0 };
3715  switch_core_session_get_read_impl(session, &read_impl);
3716 
3717 
3718  if (zstr(key)) {
3719  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No Key Specified!\n");
3720  return SWITCH_STATUS_FALSE;
3721  }
3722 
3723  if (cont) {
3724  if (cont->index >= MAX_TONES) {
3725  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Max Tones Reached!\n");
3726  return SWITCH_STATUS_FALSE;
3727  }
3728 
3729  for (i = 0; i < cont->index; i++) {
3730  if (!zstr(cont->list[i].key) && !strcasecmp(key, cont->list[i].key)) {
3731  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Re-enabling %s\n", key);
3732  cont->list[i].up = 1;
3733  cont->list[i].hits = 0;
3734  cont->list[i].sleep = 0;
3735  cont->list[i].expires = 0;
3736  return SWITCH_STATUS_SUCCESS;
3737  }
3738  }
3739  }
3740 
3741  if (zstr(tone_spec)) {
3742  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No Spec Specified!\n");
3743  return SWITCH_STATUS_FALSE;
3744  }
3745 
3746  if (!cont && !(cont = switch_core_session_alloc(session, sizeof(*cont)))) {
3747  return SWITCH_STATUS_MEMERR;
3748  }
3749 
3750  if ((var = switch_channel_get_variable(channel, "tone_detect_hits"))) {
3751  int tmp = atoi(var);
3752  if (tmp > 0) {
3753  hits = tmp;
3754  }
3755  }
3756 
3757  if (!hits) hits = 1;
3758 
3759  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Adding tone spec %s index %d hits %d\n", tone_spec, cont->index, hits);
3760 
3761  i = 0;
3762  p = (char *) tone_spec;
3763 
3764  do {
3765  teletone_process_t this;
3766  next = strchr(p, ',');
3767  while (*p == ' ')
3768  p++;
3769  if ((this = (teletone_process_t) atof(p))) {
3770  ok++;
3771  cont->list[cont->index].map.freqs[i++] = this;
3772  }
3773  if (!strncasecmp(p, "1100", 4)) {
3774  detect_fax = cont->index;
3775  }
3776 
3777  if (next) {
3778  p = next + 1;
3779  }
3780  } while (next);
3781  cont->list[cont->index].map.freqs[i++] = 0;
3782 
3783  if (!ok) {
3784  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid tone spec!\n");
3785  return SWITCH_STATUS_FALSE;
3786  }
3787 
3788  cont->detect_fax = detect_fax;
3789 
3790  cont->list[cont->index].key = switch_core_session_strdup(session, key);
3791 
3792  if (app) {
3793  cont->list[cont->index].app = switch_core_session_strdup(session, app);
3794  }
3795 
3796  if (data) {
3797  cont->list[cont->index].data = switch_core_session_strdup(session, data);
3798  }
3799 
3800  cont->list[cont->index].callback = callback;
3801 
3802  if (!hits)
3803  hits = 1;
3804 
3805  cont->list[cont->index].hits = 0;
3806  cont->list[cont->index].total_hits = hits;
3807  cont->list[cont->index].start_time = switch_micro_time_now();
3808 
3809  cont->list[cont->index].up = 1;
3810  memset(&cont->list[cont->index].mt, 0, sizeof(cont->list[cont->index].mt));
3811  cont->list[cont->index].mt.sample_rate = read_impl.actual_samples_per_second;
3812  teletone_multi_tone_init(&cont->list[cont->index].mt, &cont->list[cont->index].map);
3813  cont->session = session;
3814 
3816  return SWITCH_STATUS_FALSE;
3817  }
3818 
3819  cont->list[cont->index].default_sleep = 25;
3820  cont->list[cont->index].default_expires = 250;
3821 
3822  if ((var = switch_channel_get_variable(channel, "tone_detect_sleep"))) {
3823  int tmp = atoi(var);
3824  if (tmp > 0) {
3825  cont->list[cont->index].default_sleep = tmp;
3826  }
3827  }
3828 
3829  if ((var = switch_channel_get_variable(channel, "tone_detect_expires"))) {
3830  int tmp = atoi(var);
3831  if (tmp > 0) {
3832  cont->list[cont->index].default_expires = tmp;
3833  }
3834  }
3835 
3836 
3837  if (zstr(flags)) {
3838  bflags = SMBF_READ_REPLACE;
3839  } else {
3840  if (strchr(flags, 'o')) {
3841  cont->list[cont->index].once = 1;
3842  }
3843 
3844  if (strchr(flags, 'r')) {
3845  bflags |= SMBF_READ_REPLACE;
3846  } else if (strchr(flags, 'w')) {
3847  bflags |= SMBF_WRITE_REPLACE;
3848  }
3849  }
3850 
3851  bflags |= SMBF_NO_PAUSE;
3852 
3853  if (cont->bug_running) {
3854  status = SWITCH_STATUS_SUCCESS;
3855  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s bug already running\n", switch_channel_get_name(channel));
3856  } else {
3857  cont->bug_running = 1;
3858  if (cont->detect_fax) {
3859  switch_core_event_hook_add_send_dtmf(session, tone_on_dtmf);
3860  switch_core_event_hook_add_recv_dtmf(session, tone_on_dtmf);
3861  }
3862 
3863  if ((status = switch_core_media_bug_add(session, "tone_detect", key,
3864  tone_detect_callback, cont, timeout, bflags, &cont->bug)) != SWITCH_STATUS_SUCCESS) {
3865  cont->bug_running = 0;
3866  return status;
3867  }
3868  switch_channel_set_private(channel, "_tone_detect_", cont);
3869  }
3870 
3871  cont->index++;
3872 
3873  return SWITCH_STATUS_SUCCESS;
3874 }
3875 
3876 
3877 typedef struct {
3878  const char *app;
3879  uint32_t flags;
3881 } dtmf_meta_app_t;
3882 
3883 typedef struct {
3885  time_t last_digit;
3887  char meta;
3888  int up;
3890 
3891 typedef struct {
3894 
3895 #define SWITCH_META_VAR_KEY "__dtmf_meta"
3896 #define SWITCH_BLOCK_DTMF_KEY "__dtmf_block"
3897 
3898 typedef struct {
3900  const char *app;
3901  int flags;
3902 } bch_t;
3903 
3905 {
3906  bch_t *bch = (bch_t *) obj;
3907 
3908  if (!bch->session) {
3909  return NULL;
3910  }
3911 
3915 
3916  return NULL;
3917 
3918 }
3919 SWITCH_DECLARE(void) switch_ivr_broadcast_in_thread(switch_core_session_t *session, const char *app, int flags)
3920 {
3922  switch_threadattr_t *thd_attr = NULL;
3924  bch_t *bch;
3925 
3926  switch_assert(session);
3927 
3928  pool = switch_core_session_get_pool(session);
3929 
3930  bch = switch_core_session_alloc(session, sizeof(*bch));
3931  bch->session = session;
3932  bch->app = app;
3933  bch->flags = flags;
3934 
3935 
3936  switch_threadattr_create(&thd_attr, pool);
3937  switch_threadattr_detach_set(thd_attr, 1);
3939  switch_thread_create(&thread, thd_attr, bcast_thread, bch, pool);
3940 }
3941 
3943 {
3946  time_t now = switch_epoch_time_now(NULL);
3947  char digit[2] = "";
3948  int dval;
3949 
3950  if (!md || switch_channel_test_flag(channel, CF_INNER_BRIDGE)) {
3951  return SWITCH_STATUS_SUCCESS;
3952  }
3953 
3954  if (direction == SWITCH_DTMF_RECV && !md->sr[SWITCH_DTMF_RECV].up) {
3955  return SWITCH_STATUS_SUCCESS;
3956  }
3957 
3958  if (direction == SWITCH_DTMF_SEND && !md->sr[SWITCH_DTMF_SEND].up) {
3959  return SWITCH_STATUS_SUCCESS;
3960  }
3961 
3962  if (md->sr[direction].meta_on && now - md->sr[direction].last_digit > 5) {
3963  md->sr[direction].meta_on = SWITCH_FALSE;
3964  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s Meta digit timeout parsing %c\n", switch_channel_get_name(channel),
3965  dtmf->digit);
3966  return SWITCH_STATUS_SUCCESS;
3967  }
3968 
3969  md->sr[direction].last_digit = now;
3970 
3971  if (dtmf->digit == md->sr[direction].meta) {
3972  if (md->sr[direction].meta_on) {
3973  md->sr[direction].meta_on = SWITCH_FALSE;
3974  return SWITCH_STATUS_SUCCESS;
3975  } else {
3976  md->sr[direction].meta_on = SWITCH_TRUE;
3977  return SWITCH_STATUS_FALSE;
3978  }
3979  }
3980 
3981  if (md->sr[direction].meta_on) {
3982  if (is_dtmf(dtmf->digit)) {
3983  int ok = 0;
3984  *digit = dtmf->digit;
3985  dval = switch_dtmftoi(digit);
3986 
3987  if (direction == SWITCH_DTMF_RECV && (md->sr[direction].map[dval].bind_flags & SBF_DIAL_ALEG)) {
3988  ok = 1;
3989  } else if (direction == SWITCH_DTMF_SEND && (md->sr[direction].map[dval].bind_flags & SBF_DIAL_BLEG)) {
3990  ok = 1;
3991  }
3992 
3993  if (ok && md->sr[direction].map[dval].app) {
3994  uint32_t flags = md->sr[direction].map[dval].flags;
3995 
3996  if ((md->sr[direction].map[dval].bind_flags & SBF_EXEC_OPPOSITE)) {
3997  if (direction == SWITCH_DTMF_SEND) {
3998  flags |= SMF_ECHO_ALEG;
3999  } else {
4000  flags |= SMF_ECHO_BLEG;
4001  }
4002  } else if ((md->sr[direction].map[dval].bind_flags & SBF_EXEC_SAME)) {
4003  if (direction == SWITCH_DTMF_SEND) {
4004  flags |= SMF_ECHO_BLEG;
4005  } else {
4006  flags |= SMF_ECHO_ALEG;
4007  }
4008  } else if ((md->sr[direction].map[dval].bind_flags & SBF_EXEC_ALEG)) {
4009  flags |= SMF_ECHO_ALEG;
4010  } else if ((md->sr[direction].map[dval].bind_flags & SBF_EXEC_BLEG)) {
4011  flags |= SMF_ECHO_BLEG;
4012  } else {
4013  flags |= SMF_ECHO_ALEG;
4014  }
4015 
4016  if ((md->sr[direction].map[dval].bind_flags & SBF_EXEC_INLINE)) {
4017  flags |= SMF_EXEC_INLINE;
4018  }
4019 
4020  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Processing meta digit '%c' [%s]\n",
4021  switch_channel_get_name(channel), dtmf->digit, md->sr[direction].map[dval].app);
4022 
4023  if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
4024  switch_ivr_broadcast_in_thread(session, md->sr[direction].map[dval].app, flags | SMF_REBRIDGE);
4025  } else {
4026  switch_ivr_broadcast(switch_core_session_get_uuid(session), md->sr[direction].map[dval].app, flags);
4027  }
4028 
4029  if ((md->sr[direction].map[dval].bind_flags & SBF_ONCE)) {
4030  memset(&md->sr[direction].map[dval], 0, sizeof(md->sr[direction].map[dval]));
4031  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Unbinding meta digit '%c'\n",
4032  switch_channel_get_name(channel), dtmf->digit);
4033  }
4034 
4035  } else {
4036  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Ignoring meta digit '%c' not mapped\n",
4037  switch_channel_get_name(channel), dtmf->digit);
4038 
4039  }
4040  }
4041  md->sr[direction].meta_on = SWITCH_FALSE;
4042  return SWITCH_STATUS_FALSE;
4043  }
4044 
4045  return SWITCH_STATUS_SUCCESS;
4046 }
4047 
4049 {
4051 
4052  if (key) {
4054 
4055  if (!md || key > 9) {
4056  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid key %u\n", key);
4057  return SWITCH_STATUS_FALSE;
4058  }
4059 
4060  memset(&md->sr[SWITCH_DTMF_RECV].map[key], 0, sizeof(md->sr[SWITCH_DTMF_RECV].map[key]));
4061  memset(&md->sr[SWITCH_DTMF_SEND].map[key], 0, sizeof(md->sr[SWITCH_DTMF_SEND].map[key]));
4062  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "UnBound A-Leg: %d\n", key);
4063 
4064  } else {
4065  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "UnBound A-Leg: ALL\n");
4067  }
4068 
4069  return SWITCH_STATUS_SUCCESS;
4070 }
4071 
4073 {
4075  uint8_t enabled = (uint8_t)(intptr_t)switch_channel_get_private(channel, SWITCH_BLOCK_DTMF_KEY);
4076 
4077  if (!enabled || switch_channel_test_flag(channel, CF_INNER_BRIDGE)) {
4078  return SWITCH_STATUS_SUCCESS;
4079  }
4080 
4081  return SWITCH_STATUS_FALSE;
4082 }
4083 
4085 {
4087  uint8_t enabled = (uint8_t)(intptr_t)switch_channel_get_private(channel, SWITCH_BLOCK_DTMF_KEY);
4088 
4089  if (enabled) {
4091  }
4092 
4093  return SWITCH_STATUS_SUCCESS;
4094 }
4095 
4097 {
4099  uint8_t enabled = (uint8_t)(intptr_t)switch_channel_get_private(channel, SWITCH_BLOCK_DTMF_KEY);
4100 
4101  if (!enabled) {
4102  switch_channel_set_private(channel, SWITCH_BLOCK_DTMF_KEY, (void *)(intptr_t)1);
4103  switch_core_event_hook_add_send_dtmf(session, block_on_dtmf);
4104  switch_core_event_hook_add_recv_dtmf(session, block_on_dtmf);
4105  }
4106 
4107  return SWITCH_STATUS_SUCCESS;
4108 }
4109 
4111  switch_bind_flag_t bind_flags, const char *app)
4112 {
4115  const char *meta_var = switch_channel_get_variable(channel, "bind_meta_key");
4116  char meta = '*';
4117  char str[2] = "";
4118 
4119  if (meta_var) {
4120  char t_meta = *meta_var;
4121  if (is_dtmf(t_meta)) {
4122  meta = t_meta;
4123  } else {
4124  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Invalid META KEY %c\n", t_meta);
4125  }
4126  }
4127 
4128  if (meta != '*' && meta != '#') {
4129  str[0] = meta;
4130 
4131  if (switch_dtmftoi(str) == (char)key) {
4132  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid key %u, same as META CHAR\n", key);
4133  return SWITCH_STATUS_FALSE;
4134  }
4135  }
4136 
4137 
4138  if (key > 13) {
4139  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid key %u\n", key);
4140  return SWITCH_STATUS_FALSE;
4141  }
4142 
4143  if (!md) {
4144  md = switch_core_session_alloc(session, sizeof(*md));
4146  switch_core_event_hook_add_send_dtmf(session, meta_on_dtmf);
4147  switch_core_event_hook_add_recv_dtmf(session, meta_on_dtmf);
4148  }
4149 
4150  if (!zstr(app)) {
4151  if ((bind_flags & SBF_DIAL_ALEG)) {
4152  md->sr[SWITCH_DTMF_RECV].meta = meta;
4153  md->sr[SWITCH_DTMF_RECV].up = 1;
4154  md->sr[SWITCH_DTMF_RECV].map[key].app = switch_core_session_strdup(session, app);
4155  md->sr[SWITCH_DTMF_RECV].map[key].flags |= SMF_HOLD_BLEG;
4156  md->sr[SWITCH_DTMF_RECV].map[key].bind_flags = bind_flags;
4157 
4158  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Bound A-Leg: %c%c %s\n", meta, switch_itodtmf((char)key), app);
4159  }
4160  if ((bind_flags & SBF_DIAL_BLEG)) {
4161  md->sr[SWITCH_DTMF_SEND].meta = meta;
4162  md->sr[SWITCH_DTMF_SEND].up = 1;
4163  md->sr[SWITCH_DTMF_SEND].map[key].app = switch_core_session_strdup(session, app);
4164  md->sr[SWITCH_DTMF_SEND].map[key].flags |= SMF_HOLD_BLEG;
4165  md->sr[SWITCH_DTMF_SEND].map[key].bind_flags = bind_flags;
4166  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Bound B-Leg: %c%c %s\n", meta, switch_itodtmf((char)key), app);
4167  }
4168 
4169  } else {
4170  if ((bind_flags & SBF_DIAL_ALEG)) {
4171  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "UnBound A-Leg: %c%c\n", meta, switch_itodtmf((char)key));
4172  md->sr[SWITCH_DTMF_SEND].map[key].app = NULL;
4173  } else {
4174  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "UnBound: B-Leg %c%d\n", meta, key);
4175  md->sr[SWITCH_DTMF_SEND].map[key].app = NULL;
4176  }
4177  }
4178 
4179  return SWITCH_STATUS_SUCCESS;
4180 }
4181 
4182 #define PLAY_AND_DETECT_DONE 1
4183 #define PLAY_AND_DETECT_DONE_RECOGNIZING 2
4184 typedef struct {
4185  int done;
4186  char *result;
4188 
4189 static switch_status_t play_and_detect_input_callback(switch_core_session_t *session, void *input, switch_input_type_t input_type, void *data, unsigned int len)
4190 {
4192  if (!state->done) {
4194  if (input_type == SWITCH_INPUT_TYPE_EVENT) {
4195  switch_event_t *event;
4196  event = (switch_event_t *)input;
4197  if (event->event_id == SWITCH_EVENT_DETECTED_SPEECH) {
4198  const char *speech_type = switch_event_get_header(event, "Speech-Type");
4199  if (!zstr(speech_type)) {
4200  if (!strcasecmp(speech_type, "detected-speech")) {
4201  const char *result;
4202  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "(%s) DETECTED SPEECH\n", switch_channel_get_name(channel));
4203  result = switch_event_get_body(event);
4204  if (!zstr(result)) {
4205  state->result = switch_core_session_strdup(session, result);
4206  } else {
4207  state->result = "";
4208  }
4210  return SWITCH_STATUS_BREAK;
4211  } else if (!strcasecmp(speech_type, "begin-speaking")) {
4212  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "(%s) START OF SPEECH\n", switch_channel_get_name(channel));
4213  return SWITCH_STATUS_BREAK;
4214  } else if (!strcasecmp("closed", speech_type)) {
4216  state->result = "";
4217  return SWITCH_STATUS_BREAK;
4218  }
4219  }
4220  }
4221  } else if (input_type == SWITCH_INPUT_TYPE_DTMF) {
4222  switch_dtmf_t *dtmf = (switch_dtmf_t *) input;
4223  const char *terminators = switch_channel_get_variable(channel, SWITCH_PLAYBACK_TERMINATORS_VARIABLE);
4224  if (terminators) {
4225  if (!strcasecmp(terminators, "any")) {
4226  terminators = "1234567890*#";
4227  } else if (!strcasecmp(terminators, "none")) {
4228  terminators = NULL;
4229  }
4230  }
4231  if (terminators && strchr(terminators, dtmf->digit)) {
4232  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "(%s) ACCEPT TERMINATOR %c\n", switch_channel_get_name(channel), dtmf->digit);
4234  state->result = switch_core_session_sprintf(session, "DIGIT: %c", dtmf->digit);
4235  state->done = PLAY_AND_DETECT_DONE;
4236  return SWITCH_STATUS_BREAK;
4237  } else {
4238  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "(%s) IGNORE NON-TERMINATOR DIGIT %c\n", switch_channel_get_name(channel), dtmf->digit);
4239  }
4240  }
4241  }
4242  return SWITCH_STATUS_SUCCESS;
4243 }
4244 
4246  const char *file,
4247  const char *mod_name,
4248  const char *grammar,
4249  char **result,
4250  uint32_t input_timeout,
4251  switch_input_args_t *args)
4252 {
4254  int recognizing = 0;
4255  switch_input_args_t myargs = { 0 };
4258 
4260 
4261  if (result == NULL) {
4262  goto done;
4263  }
4264 
4265  if (!input_timeout) input_timeout = 5000;
4266 
4267  if (!args) {
4268  args = &myargs;
4269  }
4270 
4271  /* start speech detection */
4272  if ((status = switch_ivr_detect_speech(session, mod_name, grammar, "", NULL, NULL)) != SWITCH_STATUS_SUCCESS) {
4273  /* map SWITCH_STATUS_FALSE to SWITCH_STATUS_GENERR to indicate grammar load failed
4274  SWITCH_STATUS_NOT_INITALIZED will be passed back to indicate ASR resource problem */
4275  if (status == SWITCH_STATUS_FALSE) {
4276  status = SWITCH_STATUS_GENERR;
4277  }
4278  goto done;
4279  }
4280  recognizing = 1;
4281 
4282  /* play the prompt, looking for detection result */
4283  args->input_callback = play_and_detect_input_callback;
4284  args->buf = &state;
4285  args->buflen = sizeof(state);
4286  status = switch_ivr_play_file(session, NULL, file, args);
4287 
4288  if (args->dmachine && switch_ivr_dmachine_last_ping(args->dmachine) != SWITCH_STATUS_SUCCESS) {
4289  state.done |= PLAY_AND_DETECT_DONE;
4290  goto done;
4291  }
4292 
4293  if (status != SWITCH_STATUS_BREAK && status != SWITCH_STATUS_SUCCESS) {
4294  status = SWITCH_STATUS_FALSE;
4295  goto done;
4296  }
4297 
4298  /* wait for result if not done */
4299  if (!state.done) {
4301  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "(%s) WAITING FOR RESULT\n", switch_channel_get_name(channel));
4302  while (!state.done && switch_channel_ready(channel)) {
4303  status = switch_ivr_sleep(session, input_timeout, SWITCH_FALSE, args);
4304 
4305  if (args->dmachine && switch_ivr_dmachine_last_ping(args->dmachine) != SWITCH_STATUS_SUCCESS) {
4306  state.done |= PLAY_AND_DETECT_DONE;
4307  goto done;
4308  }
4309 
4310  if (status != SWITCH_STATUS_BREAK && status != SWITCH_STATUS_SUCCESS) {
4311  status = SWITCH_STATUS_FALSE;
4312  goto done;
4313  }
4314  }
4315  }
4316 
4317 
4318 
4319 done:
4320  if (recognizing && !(state.done & PLAY_AND_DETECT_DONE_RECOGNIZING)) {
4322  }
4323  if (recognizing && switch_true(switch_channel_get_variable(channel, "play_and_detect_speech_close_asr"))) {
4325  }
4326 
4327  if (state.done) {
4328  status = SWITCH_STATUS_SUCCESS;
4329  }
4330  *result = state.result;
4331 
4333 
4334  return status;
4335 }
4336 
4345  int ready;
4346 };
4347 
4349 {
4350  struct speech_thread_handle *sth = (struct speech_thread_handle *) obj;
4353  switch_status_t status;
4354  switch_event_t *event;
4355 
4356  switch_thread_cond_create(&sth->cond, sth->pool);
4358 
4360  sth->ready = 0;
4361  return NULL;
4362  }
4363 
4364  switch_mutex_lock(sth->mutex);
4365 
4366  sth->ready = 1;
4367 
4369  char *xmlstr = NULL;
4370  switch_event_t *headers = NULL;
4371 
4372  switch_thread_cond_wait(sth->cond, sth->mutex);
4373 
4375  break;
4376  }
4377 
4379 
4380  status = switch_core_asr_get_results(sth->ah, &xmlstr, &flags);
4381 
4382  if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
4383  goto done;
4384  } else if (status == SWITCH_STATUS_SUCCESS) {
4385  /* Try to fetch extra information for this result, the return value doesn't really matter here - it's just optional data. */
4386  switch_core_asr_get_result_headers(sth->ah, &headers, &flags);
4387  }
4388 
4389  if (status == SWITCH_STATUS_SUCCESS && switch_true(switch_channel_get_variable(channel, "asr_intercept_dtmf"))) {
4390  const char *p;
4391 
4392  if ((p = switch_stristr("<input>", xmlstr))) {
4393  p += 7;
4394  }
4395 
4396  while (p && *p) {
4397  char c;
4398 
4399  if (*p == '<') {
4400  break;
4401  }
4402 
4403  if (!strncasecmp(p, "pound", 5)) {
4404  c = '#';
4405  p += 5;
4406  } else if (!strncasecmp(p, "hash", 4)) {
4407  c = '#';
4408  p += 4;
4409  } else if (!strncasecmp(p, "star", 4)) {
4410  c = '*';
4411  p += 4;
4412  } else if (!strncasecmp(p, "asterisk", 8)) {
4413  c = '*';
4414  p += 8;
4415  } else {
4416  c = *p;
4417  p++;
4418  }
4419 
4420  if (is_dtmf(c)) {
4421  switch_dtmf_t dtmf = {0};
4422  dtmf.digit = c;
4425  switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Queue speech detected dtmf %c\n", c);
4426  switch_channel_queue_dtmf(channel, &dtmf);
4427  }
4428 
4429  }
4431  }
4432 
4434  if (status == SWITCH_STATUS_SUCCESS) {
4435  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "detected-speech");
4436 
4437  if (headers) {
4438  switch_event_merge(event, headers);
4439  }
4440 
4441  switch_event_add_body(event, "%s", xmlstr);
4442  } else {
4443  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "begin-speaking");
4444  }
4445 
4447  switch_event_t *dup;
4448 
4449  if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {
4450  switch_channel_event_set_data(channel, dup);
4451  switch_event_fire(&dup);
4452  }
4453 
4454  }
4455 
4457  switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Event queue failed!\n");
4458  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
4459  switch_event_fire(&event);
4460  }
4461  }
4462 
4463  switch_safe_free(xmlstr);
4464 
4465  if (headers) {
4466  switch_event_destroy(&headers);
4467  }
4468  }
4469  }
4470  done:
4471 
4473  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "closed");
4475  switch_event_t *dup;
4476 
4477  if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {
4478  switch_channel_event_set_data(channel, dup);
4479  switch_event_fire(&dup);
4480  }
4481 
4482  }
4483 
4485  switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Event queue failed!\n");
4486  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
4487  switch_event_fire(&event);
4488  }
4489  }
4490 
4491  switch_mutex_unlock(sth->mutex);
4493 
4494  return NULL;
4495 }
4496 
4498 {
4499  struct speech_thread_handle *sth = (struct speech_thread_handle *) user_data;
4500  uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE];
4501  switch_frame_t frame = { 0 };
4503 
4504  frame.data = data;
4506 
4507  switch (type) {
4508  case SWITCH_ABC_TYPE_INIT:
4509  {
4510  switch_threadattr_t *thd_attr = NULL;
4511 
4512  switch_threadattr_create(&thd_attr, sth->pool);
4514  switch_thread_create(&sth->thread, thd_attr, speech_thread, sth, sth->pool);
4515  }
4516  break;
4517  case SWITCH_ABC_TYPE_CLOSE:
4518  {
4519  switch_status_t st;
4520 
4521  switch_core_asr_close(sth->ah, &flags);
4522  if (sth->mutex && sth->cond && sth->ready) {
4525  switch_mutex_unlock(sth->mutex);
4526  }
4527  }
4528 
4529  switch_thread_join(&st, sth->thread);
4530 
4531  }
4532  break;
4533  case SWITCH_ABC_TYPE_READ:
4534  if (sth->ah) {
4536  if (switch_core_asr_feed(sth->ah, frame.data, frame.datalen, &flags) != SWITCH_STATUS_SUCCESS) {
4538  return SWITCH_FALSE;
4539  }
4541  if (sth->mutex && sth->cond && sth->ready) {
4542  switch_mutex_lock(sth->mutex);
4544  switch_mutex_unlock(sth->mutex);
4545  }
4546  }
4547  }
4548  }
4549  break;
4550  case SWITCH_ABC_TYPE_WRITE:
4551  default:
4552  break;
4553  }
4554 
4555  return SWITCH_TRUE;
4556 }
4557 
4559 {
4564 
4565  if (sth) {
4566  if (switch_core_asr_feed_dtmf(sth->ah, dtmf, &flags) != SWITCH_STATUS_SUCCESS) {
4567  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error Feeding DTMF\n");
4568  }
4569  }
4570 
4571  return status;
4572 }
4573 
4575 {
4577  struct speech_thread_handle *sth;
4578 
4579  switch_assert(channel != NULL);
4580  if ((sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY))) {
4582  switch_core_event_hook_remove_recv_dtmf(session, speech_on_dtmf);
4583  switch_core_media_bug_remove(session, &sth->bug);
4584  return SWITCH_STATUS_SUCCESS;
4585  }
4586 
4587  return SWITCH_STATUS_FALSE;
4588 }
4589 
4591 {
4594 
4595  if (sth) {
4596  switch_core_asr_pause(sth->ah);
4597  return SWITCH_STATUS_SUCCESS;
4598  }
4599  return SWITCH_STATUS_FALSE;
4600 }
4601 
4603 {
4606 
4607  if (sth) {
4608  switch_core_asr_resume(sth->ah);
4609  return SWITCH_STATUS_SUCCESS;
4610  }
4611  return SWITCH_STATUS_FALSE;
4612 }
4613 
4615 {
4618  switch_status_t status;
4619 
4620  if (sth) {
4621  if ((status = switch_core_asr_load_grammar(sth->ah, grammar, name)) != SWITCH_STATUS_SUCCESS) {
4622  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Error loading Grammar\n");
4624  }
4625  return status;
4626  }
4627  return SWITCH_STATUS_FALSE;
4628 }
4629 
4631 {
4634 
4635  if (sth && sth->ah && name && val) {
4636  switch_core_asr_text_param(sth->ah, (char *) name, val);
4637  status = SWITCH_STATUS_SUCCESS;
4638  }
4639 
4640  return status;
4641 }
4642 
4644 {
4647 
4648  if (sth) {
4650  return SWITCH_STATUS_SUCCESS;
4651  }
4652  return SWITCH_STATUS_FALSE;
4653 }
4654 
4656 {
4659  switch_status_t status;
4660 
4661  if (sth) {
4662  if ((status = switch_core_asr_unload_grammar(sth->ah, name)) != SWITCH_STATUS_SUCCESS) {
4663  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Error unloading Grammar\n");
4665  }
4666  return status;
4667  }
4668  return SWITCH_STATUS_FALSE;
4669 }
4670 
4672 {
4675  switch_status_t status;
4676 
4677  if (sth) {
4678  if ((status = switch_core_asr_enable_grammar(sth->ah, name)) != SWITCH_STATUS_SUCCESS) {
4679  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Error enabling Grammar\n");
4681  }
4682  return status;
4683  }
4684  return SWITCH_STATUS_FALSE;
4685 }
4686 
4688 {
4691  switch_status_t status;
4692 
4693  if (sth) {
4694  if ((status = switch_core_asr_disable_grammar(sth->ah, name)) != SWITCH_STATUS_SUCCESS) {
4695  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Error disabling Grammar\n");
4697  }
4698  return status;
4699  }
4700  return SWITCH_STATUS_FALSE;
4701 }
4702 
4704 {
4707  switch_status_t status;
4708 
4709  if (sth) {
4711  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Error disabling all Grammars\n");
4713  }
4714  return status;
4715  }
4716  return SWITCH_STATUS_FALSE;
4717 }
4718 
4720  const char *dest, switch_asr_handle_t *ah)
4721 {
4723  switch_status_t status;
4726  switch_codec_implementation_t read_impl = { 0 };
4727  const char *p;
4728  char key[512] = "";
4729 
4730  if (sth) {
4731  /* Already initialized */
4732  return SWITCH_STATUS_SUCCESS;
4733  }
4734 
4735  if (!ah) {
4736  if (!(ah = switch_core_session_alloc(session, sizeof(*ah)))) {
4737  return SWITCH_STATUS_MEMERR;
4738  }
4739  }
4740 
4741  switch_core_session_get_read_impl(session, &read_impl);
4742 
4743  if ((status = switch_core_asr_open(ah,
4744  mod_name,
4745  "L16",
4746  read_impl.actual_samples_per_second, dest, &flags,
4748  return status;
4749  }
4750 
4751  sth = switch_core_session_alloc(session, sizeof(*sth));
4752  sth->pool = switch_core_session_get_pool(session);
4753  sth->session = session;
4754  sth->ah = ah;
4755 
4756  if ((p = switch_channel_get_variable(channel, "fire_asr_events")) && switch_true(p)) {
4758  }
4759 
4760  switch_snprintf(key, sizeof(key), "%s/%s/%s/%s", mod_name, NULL, NULL, dest);
4761 
4762  if ((status = switch_core_media_bug_add(session, "detect_speech", key,
4764  switch_core_asr_close(ah, &flags);
4765  return status;
4766  }
4767 
4768  if ((status = switch_core_event_hook_add_recv_dtmf(session, speech_on_dtmf)) != SWITCH_STATUS_SUCCESS) {
4770  return status;
4771  }
4772 
4774 
4775  return SWITCH_STATUS_SUCCESS;
4776 }
4777 
4779  const char *mod_name,
4780  const char *grammar, const char *name, const char *dest, switch_asr_handle_t *ah)
4781 {
4783  switch_status_t status;
4785  const char *p;
4786 
4787  if (!sth) {
4788  /* No speech thread handle available yet, init speech detection first. */
4789  if ((status = switch_ivr_detect_speech_init(session, mod_name, dest, ah)) != SWITCH_STATUS_SUCCESS) {
4791  }
4792 
4793  /* Fetch the new speech thread handle */
4794  if (!(sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY))) {
4796  }
4797  }
4798 
4799  if (switch_core_asr_load_grammar(sth->ah, grammar, name) != SWITCH_STATUS_SUCCESS) {
4800  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Error loading Grammar\n");
4802  return SWITCH_STATUS_FALSE;
4803  }
4804 
4805  if ((p = switch_channel_get_variable(channel, "fire_asr_events")) && switch_true(p)) {
4807  }
4808 
4809  return SWITCH_STATUS_SUCCESS;
4810 }
4811 
4816 };
4817 
4818 SWITCH_STANDARD_SCHED_FUNC(sch_hangup_callback)
4819 {
4820  struct hangup_helper *helper;
4821  switch_core_session_t *session, *other_session;
4822  const char *other_uuid;
4823 
4824  switch_assert(task);
4825 
4826  helper = (struct hangup_helper *) task->cmd_arg;
4827 
4828  if ((session = switch_core_session_locate(helper->uuid_str))) {
4830 
4831  if (helper->bleg) {
4832  if ((other_uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(other_uuid))) {
4833  switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
4834  switch_channel_hangup(other_channel, helper->cause);
4835  switch_core_session_rwunlock(other_session);
4836  } else {
4837  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "No channel to hangup\n");
4838  }
4839  } else {
4840  switch_channel_hangup(channel, helper->cause);
4841  }
4842 
4844  }
4845 }
4846 
4848 {
4849  struct hangup_helper *helper;
4850  size_t len = sizeof(*helper);
4851 
4852  switch_zmalloc(helper, len);
4853 
4854  switch_copy_string(helper->uuid_str, uuid, sizeof(helper->uuid_str));
4855  helper->cause = cause;
4856  helper->bleg = bleg;
4857 
4858  return switch_scheduler_add_task(runtime, sch_hangup_callback, (char *) __SWITCH_FUNC__, uuid, 0, helper, SSHF_FREE_ARG);
4859 }
4860 
4863  char *extension;
4864  char *dialplan;
4865  char *context;
4866 };
4867 
4868 SWITCH_STANDARD_SCHED_FUNC(sch_transfer_callback)
4869 {
4870  struct transfer_helper *helper;
4871  switch_core_session_t *session;
4872 
4873  switch_assert(task);
4874 
4875  helper = (struct transfer_helper *) task->cmd_arg;
4876 
4877  if ((session = switch_core_session_locate(helper->uuid_str))) {
4878  switch_ivr_session_transfer(session, helper->extension, helper->dialplan, helper->context);
4880  }
4881 
4882 }
4883 
4884 SWITCH_DECLARE(uint32_t) switch_ivr_schedule_transfer(time_t runtime, const char *uuid, char *extension, char *dialplan, char *context)
4885 {
4886  struct transfer_helper *helper;
4887  size_t len = sizeof(*helper);
4888  char *cur = NULL;
4889 
4890  if (extension) {
4891  len += strlen(extension) + 1;
4892  }
4893 
4894  if (dialplan) {
4895  len += strlen(dialplan) + 1;
4896  }
4897 
4898  if (context) {
4899  len += strlen(context) + 1;
4900  }
4901 
4902  switch_zmalloc(cur, len);
4903  helper = (struct transfer_helper *) cur;
4904 
4905  switch_copy_string(helper->uuid_str, uuid, sizeof(helper->uuid_str));
4906 
4907  cur += sizeof(*helper);
4908 
4909  if (extension) {
4910  switch_copy_string(cur, extension, strlen(extension) + 1);
4911  helper->extension = cur;
4912  cur += strlen(helper->extension) + 1;
4913  }
4914 
4915  if (dialplan) {
4916  switch_copy_string(cur, dialplan, strlen(dialplan) + 1);
4917  helper->dialplan = cur;
4918  cur += strlen(helper->dialplan) + 1;
4919  }
4920 
4921  if (context) {
4922  switch_copy_string(cur, context, strlen(context) + 1);
4923  helper->context = cur;
4924  }
4925 
4926  return switch_scheduler_add_task(runtime, sch_transfer_callback, (char *) __SWITCH_FUNC__, uuid, 0, helper, SSHF_FREE_ARG);
4927 }
4928 
4931  char *path;
4933 };
4934 
4935 SWITCH_STANDARD_SCHED_FUNC(sch_broadcast_callback)
4936 {
4937  struct broadcast_helper *helper;
4938  switch_assert(task);
4939 
4940  helper = (struct broadcast_helper *) task->cmd_arg;
4941  switch_ivr_broadcast(helper->uuid_str, helper->path, helper->flags);
4942 }
4943 
4944 SWITCH_DECLARE(uint32_t) switch_ivr_schedule_broadcast(time_t runtime, const char *uuid, const char *path, switch_media_flag_t flags)
4945 {
4946  struct broadcast_helper *helper;
4947  size_t len = sizeof(*helper) + strlen(path) + 1;
4948  char *cur = NULL;
4949 
4950  switch_zmalloc(cur, len);
4951  helper = (struct broadcast_helper *) cur;
4952 
4953  cur += sizeof(*helper);
4954  switch_copy_string(helper->uuid_str, uuid, sizeof(helper->uuid_str));
4955  helper->flags = flags;
4956 
4957  switch_copy_string(cur, path, len - sizeof(helper));
4958  helper->path = cur;
4959 
4960  return switch_scheduler_add_task(runtime, sch_broadcast_callback, (char *) __SWITCH_FUNC__, uuid, 0, helper, SSHF_FREE_ARG);
4961 }
4962 
4964 {
4965  switch_channel_t *channel;
4966  switch_core_session_t *session, *master;
4967  switch_event_t *event;
4968  switch_core_session_t *other_session = NULL;
4969  const char *other_uuid = NULL;
4970  char *app = "playback";
4971  char *cause = NULL;
4972  char *mypath;
4973  char *p;
4974  int app_flags = 0, nomedia = 0;
4975 
4976  switch_assert(path);
4977 
4978  if (!(master = session = switch_core_session_locate(uuid))) {
4979  return SWITCH_STATUS_FALSE;
4980  }
4981 
4982  channel = switch_core_session_get_channel(session);
4983 
4984  mypath = strdup(path);
4985  assert(mypath);
4986 
4987  if ((p = strchr(mypath, ':')) && *(p + 1) == ':') {
4988  app = mypath;
4989  *p++ = '\0';
4990  *p++ = '\0';
4991  path = p;
4992  }
4993 
4994  if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
4995  nomedia = 1;
4997  }
4998 
4999  if ((cause = strchr(app, '!'))) {
5000  *cause++ = '\0';
5001  if (!cause) {
5002  cause = "normal_clearing";
5003  }
5004  }
5005 
5006  if ((flags & SMF_ECHO_BLEG) && (other_uuid = switch_channel_get_partner_uuid(channel))
5007  && (other_session = switch_core_session_locate(other_uuid))) {
5008  if ((flags & SMF_EXEC_INLINE)) {
5009  switch_core_session_execute_application_get_flags(other_session, app, path, &app_flags);
5010  nomedia = 0;
5011  } else {
5012  switch_core_session_get_app_flags(app, &app_flags);
5014  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
5015  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-name", app);
5016  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-arg", path);
5017  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, (flags & SMF_PRIORITY) ? "event-lock-pri" : "event-lock", "true");
5018 
5019  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "lead-frames", "%d", 5);
5020 
5021  if ((flags & SMF_LOOP)) {
5022  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "loops", "%d", -1);
5023  }
5024 
5025  if ((flags & SMF_HOLD_BLEG)) {
5026  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "hold-bleg", "true");
5027  }
5028 
5029  switch_core_session_queue_private_event(other_session, &event, (flags & SMF_PRIORITY));
5030  }
5031  }
5032 
5033  switch_core_session_rwunlock(other_session);
5034  master = other_session;
5035  other_session = NULL;
5036  }
5037 
5038  if ((app_flags & SAF_MEDIA_TAP)) {
5039  nomedia = 0;
5040  }
5041 
5042  if ((flags & SMF_ECHO_ALEG)) {
5043  if ((flags & SMF_EXEC_INLINE)) {
5044  nomedia = 0;
5045  switch_core_session_execute_application(session, app, path);
5046  } else {
5048  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
5049  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-name", app);
5050  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-arg", path);
5051  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, (flags & SMF_PRIORITY) ? "event-lock-pri" : "event-lock", "true");
5052  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "lead-frames", "%d", 5);
5053 
5054  if ((flags & SMF_LOOP)) {
5055  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "loops", "%d", -1);
5056  }
5057  if ((flags & SMF_HOLD_BLEG)) {
5058  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "hold-bleg", "true");
5059  }
5060 
5061  switch_core_session_queue_private_event(session, &event, (flags & SMF_PRIORITY));
5062 
5063  if (nomedia)
5065  }
5066  }
5067  master = session;
5068  }
5069 
5070  if (cause) {
5072  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
5073  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-name", "hangup");
5074  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-arg", cause);
5075  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, (flags & SMF_PRIORITY) ? "event-lock-pri" : "event-lock", "true");
5076  switch_core_session_queue_private_event(session, &event, (flags & SMF_PRIORITY));
5077  }
5078  }
5079 
5081  switch_safe_free(mypath);
5082 
5083  return SWITCH_STATUS_SUCCESS;
5084 }
5085 
5086 
5087 typedef struct oht_s {
5090  uint8_t alpha;
5091 } overly_helper_t;
5092 
5094 {
5095  overly_helper_t *oht = (overly_helper_t *) user_data;
5098 
5099  switch (type) {
5100  case SWITCH_ABC_TYPE_INIT:
5101  {
5102  }
5103  break;
5104  case SWITCH_ABC_TYPE_CLOSE:
5105  {
5106  switch_img_free(&oht->img);
5107  }
5108  break;
5112  int x = 0, y = 0;
5113  switch_image_t *oimg = NULL;
5114 
5115  if (frame->img && oht->img) {
5116  switch_img_copy(oht->img, &oimg);
5117  switch_img_fit(&oimg, frame->img->d_w, frame->img->d_h, SWITCH_FIT_SIZE);
5118  switch_img_find_position(oht->pos, frame->img->d_w, frame->img->d_h, oimg->d_w, oimg->d_h, &x, &y);
5119  switch_img_overlay(frame->img, oimg, x, y, oht->alpha);
5120  //switch_img_patch(frame->img, oimg, x, y);
5121  switch_img_free(&oimg);
5122  }
5123  }
5124  break;
5125  default:
5126  break;
5127  }
5128 
5129  return SWITCH_TRUE;
5130 }
5131 
5132 
5134 {
5136  switch_media_bug_t *bug = switch_channel_get_private(channel, "_video_write_overlay_bug_");
5137 
5138  if (bug) {
5139  switch_channel_set_private(channel, "_video_write_overlay_bug_", NULL);
5140  switch_core_media_bug_remove(session, &bug);
5141  return SWITCH_STATUS_SUCCESS;
5142  }
5143 
5144  return SWITCH_STATUS_FALSE;
5145 }
5146 
5148  switch_img_position_t pos, uint8_t alpha)
5149 {
5151  switch_status_t status;
5153  switch_media_bug_t *bug;
5154  overly_helper_t *oht;
5155  switch_image_t *img;
5156 
5157  bflags |= SMBF_NO_PAUSE;
5158 
5159  if (switch_channel_get_private(channel, "_video_write_overlay_bug_")) {
5160  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Only one of this type of bug per channel\n");
5161  return SWITCH_STATUS_FALSE;
5162  }
5163 
5164  if (!(img = switch_img_read_png(img_path, SWITCH_IMG_FMT_ARGB))) {
5165  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening file: %s\n", img_path);
5166  return SWITCH_STATUS_FALSE;
5167  }
5168 
5169  oht = switch_core_session_alloc(session, sizeof(*oht));
5170  oht->img = img;
5171  oht->pos = pos;
5172  oht->alpha = alpha;
5173 
5174  if ((status = switch_core_media_bug_add(session, "video_write_overlay", NULL,
5175  video_write_overlay_callback, oht, 0, bflags, &bug)) != SWITCH_STATUS_SUCCESS) {
5176 
5177  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating bug, file: %s\n", img_path);
5178  switch_img_free(&oht->img);
5179  return status;
5180  }
5181 
5182  switch_channel_set_private(channel, "_video_write_overlay_bug_", bug);
5183 
5184  return SWITCH_STATUS_SUCCESS;
5185 }
5186 
5187 /* For Emacs:
5188  * Local Variables:
5189  * mode:c
5190  * indent-tabs-mode:t
5191  * tab-width:4
5192  * c-basic-offset:4
5193  * End:
5194  * For VIM:
5195  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
5196  */
struct apr_queue_t switch_queue_t
Definition: switch_apr.h:590
switch_status_t switch_channel_set_variable_printf(switch_channel_t *channel, const char *varname, const char *fmt,...)
void switch_ivr_dmachine_set_nonmatch_callback(switch_ivr_dmachine_t *dmachine, switch_ivr_dmachine_callback_t nonmatch_callback)
#define __SWITCH_FUNC__
struct switch_ivr_dmachine_binding * next
uint32_t switch_bind_flag_t
Definition: switch_types.h:308
switch_frame_t * switch_core_media_bug_get_video_ping_frame(switch_media_bug_t *bug)
switch_time_t switch_micro_time_now(void)
Get the current epoch time in microseconds.
Definition: switch_time.c:310
#define switch_event_fire(event)
Fire an event filling in most of the arguements with obvious values.
Definition: switch_event.h:412
#define switch_channel_hangup(channel, hangup_cause)
Hangup a channel flagging it's state machine to end.
switch_status_t switch_ivr_dmachine_set_terminators(switch_ivr_dmachine_t *dmachine, const char *terminators)
switch_status_t switch_channel_execute_on(switch_channel_t *channel, const char *variable_prefix)
switch_event_types_t event_id
Definition: switch_event.h:82
#define switch_core_new_memory_pool(p)
Create a new sub memory pool from the core's master pool.
Definition: switch_core.h:631
void switch_channel_set_flag_recursive(switch_channel_t *channel, switch_channel_flag_t flag)
teletone_multi_tone_t mt
switch_status_t switch_core_asr_start_input_timers(switch_asr_handle_t *ah)
Start input timers on an asr handle.
char * switch_core_session_sprintf(_In_ switch_core_session_t *session, _In_z_ _Printf_format_string_ const char *fmt,...)
printf-style style printing routine. The data is output to a string allocated from the session ...
switch_status_t switch_thread_cond_create(switch_thread_cond_t **cond, switch_memory_pool_t *pool)
Definition: switch_apr.c:350
switch_mutex_t * read_mutex
#define SWITCH_CHANNEL_SESSION_LOG(x)
Image Descriptor.
Definition: switch_image.h:88
Call Specific Data.
Definition: switch_caller.h:73
switch_ivr_dmachine_callback_t nonmatch_callback
#define switch_set_flag(obj, flag)
Set a flag on an arbitrary object.
Definition: switch_utils.h:631
#define SWITCH_THREAD_FUNC
switch_abc_type_t
Definition: switch_types.h:484
switch_size_t switch_buffer_zwrite(_In_ switch_buffer_t *buffer, _In_bytecount_(datalen) const void *data, _In_ switch_size_t datalen)
switch_asr_handle_t * ah
SpeexEchoState * write_ec
switch_core_session_message_types_t message_id
Definition: switch_core.h:181
#define SWITCH_CHANNEL_LOG
void switch_core_session_reset(_In_ switch_core_session_t *session, switch_bool_t flush_dtmf, switch_bool_t reset_read_codec)
Reset the buffers and resampler on a session.
switch_size_t switch_buffer_read(_In_ switch_buffer_t *buffer, _In_ void *data, _In_ switch_size_t datalen)
Read data from a switch_buffer_t up to the ammount of datalen if it is available. Remove read data fr...
switch_status_t switch_core_asr_disable_all_grammars(switch_asr_handle_t *ah)
Disable all grammars from an asr handle.
char last_failed_digits[DMACHINE_MAX_DIGIT_LEN]
switch_time_t last_read_time
switch_status_t switch_channel_set_variable_name_printf(switch_channel_t *channel, const char *val, const char *fmt,...)
switch_status_t switch_mutex_trylock(switch_mutex_t *lock)
Definition: switch_apr.c:295
switch_status_t switch_core_hash_destroy(_Inout_ switch_hash_t **hash)
Destroy an existing hash table.
switch_status_t switch_ivr_dmachine_feed(switch_ivr_dmachine_t *dmachine, const char *digits, switch_ivr_dmachine_match_t **match)
switch_status_t switch_channel_queue_dtmf(_In_ switch_channel_t *channel, _In_ const switch_dtmf_t *dtmf)
Queue DTMF on a given channel.
char * switch_find_end_paren(const char *s, char open, char close)
Definition: switch_utils.c:661
void * switch_core_hash_find(_In_ switch_hash_t *hash, _In_z_ const char *key)
Retrieve data from a given hash.
switch_status_t switch_core_asr_get_result_headers(switch_asr_handle_t *ah, switch_event_t **headers, switch_asr_flag_t *flags)
Get result headers from an asr handle.
#define MAX_TONES
switch_status_t switch_ivr_eavesdrop_exec_all(switch_core_session_t *session, const char *app, const char *arg)
switch_core_session_t * session
teletone_tone_map_t map
void switch_img_free(switch_image_t **img)
Close an image descriptor.
switch_media_flag_t flags
A container for a single multi-tone detection TELETONE_MAX_TONES dictates the maximum simultaneous to...
void * switch_core_media_bug_get_user_data(_In_ switch_media_bug_t *bug)
Obtain private data from a media bug.
const char * switch_channel_get_partner_uuid(switch_channel_t *channel)
uint32_t switch_ivr_schedule_hangup(time_t runtime, const char *uuid, switch_call_cause_t cause, switch_bool_t bleg)
Hangup an existing session in the future.
switch_hash_t * binding_hash
#define switch_core_hash_init(_hash)
Definition: switch_core.h:1390
switch_status_t switch_ivr_dmachine_create(switch_ivr_dmachine_t **dmachine_p, const char *name, switch_memory_pool_t *pool, uint32_t digit_timeout_ms, uint32_t input_timeout_ms, switch_ivr_dmachine_callback_t match_callback, switch_ivr_dmachine_callback_t nonmatch_callback, void *user_data)
switch_status_t switch_channel_set_private(switch_channel_t *channel, const char *key, const void *private_info)
Set private data on channel.
static switch_bool_t session_audio_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
switch_status_t switch_core_session_set_video_read_callback(switch_core_session_t *session, switch_core_video_thread_callback_func_t func, void *user_data)
#define switch_core_file_open(_fh, _file_path, _channels, _rate, _flags, _pool)
Open a media file using file format modules.
Definition: switch_core.h:1865
static switch_status_t play_and_detect_input_callback(switch_core_session_t *session, void *input, switch_input_type_t input_type, void *data, unsigned int len)
switch_ivr_dmachine_match_t * switch_ivr_dmachine_get_match(switch_ivr_dmachine_t *dmachine)
An abstraction to store a tone mapping.
Definition: libteletone.h:93
switch_status_t switch_buffer_create_dynamic(_Out_ switch_buffer_t **buffer, _In_ switch_size_t blocksize, _In_ switch_size_t start_len, _In_ switch_size_t max_len)
Allocate a new dynamic switch_buffer.
static void set_completion_cause(struct record_helper *rh, const char *completion_cause)
SpeexPreprocessState * write_st
switch_status_t switch_ivr_stop_record_session(switch_core_session_t *session, const char *file)
Stop Recording a session.
switch_status_t switch_ivr_sleep(switch_core_session_t *session, uint32_t ms, switch_bool_t sync, switch_input_args_t *args)
Wait for time to pass for a specified number of milliseconds.
Definition: switch_ivr.c:127
switch_frame_t * switch_core_media_bug_get_native_read_frame(switch_media_bug_t *bug)
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH+1]
static switch_bool_t switch_ivr_dmachine_check_timeout(switch_ivr_dmachine_t *dmachine)
void switch_core_media_bug_set_write_replace_frame(_In_ switch_media_bug_t *bug, _In_ switch_frame_t *frame)
Set a return replace frame.
SWITCH_STANDARD_SCHED_FUNC(sch_hangup_callback)
struct oht_s overly_helper_t
#define switch_channel_up(_channel)
teletone_hit_type_t
#define SWITCH_RECORD_POST_PROCESS_EXEC_APP_VARIABLE
Definition: switch_types.h:145
#define SWITCH_RECOMMENDED_BUFFER_SIZE
Definition: switch_types.h:557
switch_time_t silence_time
void switch_channel_event_set_data(_In_ switch_channel_t *channel, _In_ switch_event_t *event)
Add information about a given channel to an event object.
switch_bool_t
Definition: switch_types.h:405
uint8_t alpha
switch_ivr_dmachine_t * dmachine
switch_status_t switch_ivr_stop_session_audio(switch_core_session_t *session)
switch_status_t switch_core_asr_open(switch_asr_handle_t *ah, const char *module_name, const char *codec, int rate, const char *dest, switch_asr_flag_t *flags, switch_memory_pool_t *pool)
Open an asr handle.
static switch_status_t block_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction)
#define switch_core_strdup(_pool, _todup)
Copy a string using memory allocation from a given pool.
Definition: switch_core.h:729
switch_status_t switch_core_session_set_read_codec(_In_ switch_core_session_t *session, switch_codec_t *codec)
Assign the read codec to a given session.
#define SWITCH_URL_SEPARATOR
Definition: switch_types.h:124
switch_core_session_t * session
switch_status_t switch_core_asr_get_results(switch_asr_handle_t *ah, char **xmlstr, switch_asr_flag_t *flags)
Get results from an asr handle.
static void *SWITCH_THREAD_FUNC bcast_thread(switch_thread_t *thread, void *obj)
#define SWITCH_BLOCK_DTMF_KEY
switch_status_t switch_core_file_set_string(_In_ switch_file_handle_t *fh, switch_audio_col_t col, const char *string)
Set metadata to the desired string.
switch_status_t switch_api_execute(const char *cmd, const char *arg, switch_core_session_t *session, switch_stream_handle_t *stream)
Execute a registered API command.
switch_status_t switch_ivr_broadcast(const char *uuid, const char *path, switch_media_flag_t flags)
Signal the session to broadcast audio.
teletone_generation_session_t ts
switch_status_t switch_threadattr_stacksize_set(switch_threadattr_t *attr, switch_size_t stacksize)
Definition: switch_apr.c:660
void switch_core_session_raw_read(switch_core_session_t *session)
switch_ivr_dmachine_binding_t * last_matching_binding
switch_status_t switch_core_asr_feed_dtmf(switch_asr_handle_t *ah, const switch_dtmf_t *dtmf, switch_asr_flag_t *flags)
Feed DTMF to an asr handle.
switch_buffer_t * r_buffer
#define switch_core_destroy_memory_pool(p)
Returns a subpool back to the main pool.
Definition: switch_core.h:640
switch_memory_pool_t * pool
void switch_ivr_dmachine_set_target(switch_ivr_dmachine_t *dmachine, switch_digit_action_target_t target)
switch_status_t switch_event_add_header(switch_event_t *event, switch_stack_t stack, const char *header_name, const char *fmt,...) PRINTF_FUNCTION(4
Add a header to an event.
Representation of an event.
Definition: switch_event.h:80
dm_binding_head_t * realm
static switch_status_t speech_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction)
A container for a DTMF detection state.
switch_status_t switch_core_media_bug_set_pre_buffer_framecount(switch_media_bug_t *bug, uint32_t framecount)
switch_status_t switch_core_file_close(_In_ switch_file_handle_t *fh)
Close an open file handle.
#define switch_channel_ready(_channel)
switch_status_t switch_event_add_body(switch_event_t *event, const char *fmt,...) PRINTF_FUNCTION(2
Add a body to an event.
double teletone_process_t
Definition: libteletone.h:84
#define arg_recursion_check_stop(_args)
static switch_bool_t tone_detect_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
void switch_media_bug_set_spy_fmt(switch_media_bug_t *bug, switch_vid_spy_fmt_t spy_fmt)
switch_status_t switch_core_session_read_lock(_In_ switch_core_session_t *session)
Acquire a read lock on the session.
switch_status_t switch_queue_trypop(switch_queue_t *queue, void **data)
Definition: switch_apr.c:1140
#define SWITCH_PLAYBACK_TERMINATOR_USED
Definition: switch_types.h:185
switch_digit_action_target_t
Definition: switch_types.h:273
void switch_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t channels, uint32_t divisor)
Generate static noise.
int teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *map)
Execute a single tone generation instruction.
switch_status_t switch_core_file_seek(_In_ switch_file_handle_t *fh, unsigned int *cur_pos, int64_t samples, int whence)
Seek a position in a file.
switch_media_bug_t * bug
switch_core_session_t * switch_core_media_bug_get_session(_In_ switch_media_bug_t *bug)
Obtain the session from a media bug.
static switch_bool_t is_silence_frame(switch_frame_t *frame, int silence_threshold, switch_codec_implementation_t *codec_impl)
int teletone_destroy_session(teletone_generation_session_t *ts)
Free the buffer allocated by a tone generation session.
const char * app
static switch_bool_t read_displace_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
switch_status_t switch_core_asr_feed(switch_asr_handle_t *ah, void *data, unsigned int len, switch_asr_flag_t *flags)
Feed audio data to an asr handle.
switch_core_session_t * caller
#define PLAY_AND_DETECT_DONE_RECOGNIZING
uint32_t switch_core_media_bug_set_flag(_In_ switch_media_bug_t *bug, _In_ uint32_t flag)
switch_status_t switch_ivr_play_file(switch_core_session_t *session, switch_file_handle_t *fh, const char *file, switch_input_args_t *args)
play a file from the disk to the session
switch_mutex_t * w_mutex
switch_bool_t bleg
static switch_bool_t inband_dtmf_generate_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
switch_status_t switch_core_codec_destroy(switch_codec_t *codec)
Destroy an initalized codec handle.
switch_status_t switch_thread_cond_wait(switch_thread_cond_t *cond, switch_mutex_t *mutex)
Definition: switch_apr.c:355
const char * string_array_arg[MESSAGE_STRING_ARG_MAX]
Definition: switch_core.h:209
switch_time_t last_write_time
#define switch_core_session_get_name(_s)
Definition: switch_core.h:271
static void tone_detect_set_total_time(switch_tone_container_t *cont, int index)
switch_status_t switch_core_file_read(_In_ switch_file_handle_t *fh, void *data, switch_size_t *len)
Read media from a file handle.
static void *SWITCH_THREAD_FUNC recording_thread(switch_thread_t *thread, void *obj)
#define PLAY_AND_DETECT_DONE
void switch_core_media_bug_set_read_replace_frame(_In_ switch_media_bug_t *bug, _In_ switch_frame_t *frame)
Set a return replace frame.
uint32_t duration
Definition: switch_types.h:288
#define SWITCH_IMG_FMT_ARGB
Definition: switch_vpx.h:72
switch_ivr_dmachine_binding_t * binding_list
switch_status_t switch_event_dup(switch_event_t **event, switch_event_t *todup)
Duplicate an event.
switch_status_t switch_ivr_parse_all_events(switch_core_session_t *session)
Parse all commands from an event.
Definition: switch_ivr.c:867
void switch_ivr_dmachine_set_match_callback(switch_ivr_dmachine_t *dmachine, switch_ivr_dmachine_callback_t match_callback)
pack cur
switch_status_t switch_ivr_media(const char *uuid, switch_media_flag_t flags)
Signal a session to request direct media access to it's remote end.
Definition: switch_ivr.c:1674
switch_status_t switch_core_session_execute_application_async(switch_core_session_t *session, const char *app, const char *arg)
static switch_thread_t * thread
Definition: switch_log.c:279
switch_status_t switch_ivr_eavesdrop_pop_eavesdropper(switch_core_session_t *session, switch_core_session_t **sessionp)
int switch_snprintf(_Out_z_cap_(len) char *buf, _In_ switch_size_t len, _In_z_ _Printf_format_string_ const char *format,...)
switch_mutex_t * buffer_mutex
const char * switch_ivr_dmachine_get_failed_digits(switch_ivr_dmachine_t *dmachine)
switch_size_t switch_buffer_write(_In_ switch_buffer_t *buffer, _In_bytecount_(datalen) const void *data, _In_ switch_size_t datalen)
Write data into a switch_buffer_t up to the length of datalen.
switch_status_t switch_core_media_bug_add(_In_ switch_core_session_t *session, _In_ const char *function, _In_ const char *target, _In_ switch_media_bug_callback_t callback, _In_opt_ void *user_data, _In_ time_t stop_time, _In_ switch_media_bug_flag_t flags, _Out_ switch_media_bug_t **new_bug)
Add a media bug to the session.
struct switch_runtime runtime
Definition: switch_core.c:64
static int switch_true(const char *expr)
Evaluate the truthfullness of a string expression.
Definition: switch_utils.h:450
uint32_t switch_channel_test_flag(switch_channel_t *channel, switch_channel_flag_t flag)
Test for presence of given flag on a given channel.
switch_status_t switch_ivr_dmachine_clear(switch_ivr_dmachine_t *dmachine)
switch_core_session_t * eavesdropper
uint32_t switch_scheduler_add_task(time_t task_runtime, switch_scheduler_func_t func, const char *desc, const char *group, uint32_t cmd_id, void *cmd_arg, switch_scheduler_flag_t flags)
Schedule a task in the future.
static dm_match_t switch_ivr_dmachine_check_match(switch_ivr_dmachine_t *dmachine, switch_bool_t is_timeout)
static switch_bool_t eavesdrop_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
switch_input_type_t
struct apr_thread_cond_t switch_thread_cond_t
Definition: switch_apr.h:463
switch_status_t switch_core_session_read_frame(_In_ switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
Read a frame from a session.
void switch_img_find_position(switch_img_position_t pos, int sw, int sh, int iw, int ih, int *xP, int *yP)
switch_status_t switch_ivr_stop_inband_dtmf_session(switch_core_session_t *session)
Stop looking for DTMF inband.
switch_status_t switch_core_asr_load_grammar(switch_asr_handle_t *ah, const char *grammar, const char *name)
Load a grammar to an asr handle.
switch_codec_t * codec
Definition: switch_frame.h:45
A message object designed to allow unlike technologies to exchange data.
Definition: switch_core.h:177
switch_status_t switch_ivr_unblock_dtmf_session(switch_core_session_t *session)
uint8_t switch_byte_t
Definition: switch_types.h:246
switch_image_t * img
switch_status_t switch_core_asr_pause(switch_asr_handle_t *ah)
Pause detection on an asr handle.
#define zstr(x)
Definition: switch_utils.h:281
switch_codec_t * switch_core_session_get_read_codec(_In_ switch_core_session_t *session)
Retrieve the read codec from a given session.
switch_status_t switch_file_remove(const char *path, switch_memory_pool_t *pool)
Definition: switch_apr.c:429
switch_buffer_t * thread_buffer
uint32_t switch_core_max_dtmf_duration(uint32_t duration)
Definition: switch_core.c:1664
switch_status_t switch_ivr_dmachine_last_ping(switch_ivr_dmachine_t *dmachine)
switch_status_t switch_ivr_session_transfer(_In_ switch_core_session_t *session, const char *extension, const char *dialplan, const char *context)
Transfer an existing session to another location.
#define SWITCH_SPEECH_KEY
Definition: switch_types.h:226
unsigned int d_w
Definition: switch_image.h:99
#define is_dtmf(key)
determine if a character is a valid DTMF key
Definition: switch_utils.h:614
switch_core_session_t * session
void switch_change_sln_volume(int16_t *data, uint32_t samples, int32_t vol)
Change the volume of a signed linear audio frame.
switch_status_t switch_core_session_write_frame(_In_ switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
Write a frame to a session.
switch_status_t switch_mutex_unlock(switch_mutex_t *lock)
Definition: switch_apr.c:290
void teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map)
Initilize a multi-frequency tone detector.
int teletone_run(teletone_generation_session_t *ts, const char *cmd)
Execute a tone generation script and call callbacks after each instruction.
switch_status_t switch_thread_join(switch_status_t *retval, switch_thread_t *thd)
Definition: switch_apr.c:1255
switch_status_t switch_core_session_get_read_impl(switch_core_session_t *session, switch_codec_implementation_t *impp)
#define switch_core_session_execute_application(_a, _b, _c)
Execute an application on a session.
Definition: switch_core.h:1103
_Ret_ switch_channel_t * switch_core_session_get_channel(_In_ switch_core_session_t *session)
Retrieve a pointer to the channel object associated with a given session.
static switch_status_t tone_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction)
void switch_channel_clear_app_flag_key(const char *app, switch_channel_t *channel, uint32_t flags)
void switch_ivr_broadcast_in_thread(switch_core_session_t *session, const char *app, int flags)
#define switch_clear_flag(obj, flag)
Clear a flag on an arbitrary object while locked.
Definition: switch_utils.h:655
switch_codec_implementation_t read_impl
int teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_handler handler, void *user_data)
Initilize a tone generation session.
char digits[DMACHINE_MAX_DIGIT_LEN]
#define SWITCH_MUTEX_NESTED
Definition: switch_apr.h:318
switch_frame_t * switch_core_media_bug_get_read_replace_frame(_In_ switch_media_bug_t *bug)
Obtain a replace frame from a media bug.
switch_bool_t switch_ivr_dmachine_is_parsing(switch_ivr_dmachine_t *dmachine)
switch_status_t switch_core_media_bug_pop(switch_core_session_t *orig_session, const char *function, switch_media_bug_t **pop)
switch_status_t switch_core_session_get_app_flags(const char *app, int32_t *flags)
switch_core_session_t * session
uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE]
#define SWITCH_PATH_SEPARATOR
Definition: switch_types.h:122
switch_status_t switch_threadattr_detach_set(switch_threadattr_t *attr, int32_t on)
Definition: switch_apr.c:655
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH+1]
switch_digit_action_target_t target
int64_t switch_time_t
Definition: switch_apr.h:188
const switch_codec_implementation_t * implementation
uint32_t buflen
Definition: switch_frame.h:59
if((uint32_t)(unpack->cur-unpack->buf) > unpack->buflen)
switch_status_t switch_core_media_bug_transfer_callback(switch_core_session_t *orig_session, switch_core_session_t *new_session, switch_media_bug_callback_t callback, void *(*user_data_dup_func)(switch_core_session_t *, void *))
switch_status_t switch_core_session_execute_application_get_flags(_In_ switch_core_session_t *session, _In_ const char *app, _In_opt_z_ const char *arg, _Out_opt_ int32_t *flags)
Execute an application on a session.
switch_byte_t switch_byte_t * buf
static void exec_cb(switch_media_bug_t *bug, void *user_data)
switch_status_t switch_ivr_play_and_detect_speech(switch_core_session_t *session, const char *file, const char *mod_name, const char *grammar, char **result, uint32_t input_timeout, switch_input_args_t *args)
play a file to the session while doing speech recognition.
#define switch_yield(ms)
Wait a desired number of microseconds and yield the CPU.
Definition: switch_utils.h:908
unsigned int switch_separate_string(_In_ char *buf, char delim, _Post_count_(return) char **array, unsigned int arraylen)
Separate a string into an array based on a character delimiter.
switch_channel_t * channel
switch_status_t switch_core_asr_close(switch_asr_handle_t *ah, switch_asr_flag_t *flags)
Close an asr handle.
switch_core_session_t * session
uint32_t datalen
Definition: switch_frame.h:57
switch_ivr_dmachine_binding_t * tail
switch_codec_implementation_t tread_impl
teletone_process_t freqs[TELETONE_MAX_TONES]
Definition: libteletone.h:95
switch_file_handle_t fh
void switch_event_merge(switch_event_t *event, switch_event_t *tomerge)
switch_status_t switch_mutex_lock(switch_mutex_t *lock)
Definition: switch_apr.c:285
const char * callee_id_number
Definition: switch_caller.h:89
void switch_buffer_lock(_In_ switch_buffer_t *buffer)
switch_codec_implementation_t read_impl
const char * completion_cause
char * switch_event_get_body(switch_event_t *event)
Retrieve the body value from an event.
Definition: switch_event.c:838
switch_status_t switch_ivr_stop_detect_speech(switch_core_session_t *session)
Stop background Speech detection on a session.
switch_thread_cond_t * cond
switch_frame_t * switch_core_media_bug_get_write_replace_frame(_In_ switch_media_bug_t *bug)
Obtain a replace frame from a media bug.
#define switch_core_alloc(_pool, _mem)
Allocate memory directly from a memory pool.
Definition: switch_core.h:682
static switch_bool_t speech_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
switch_img_position_t
switch_status_t switch_core_media_bug_push_spy_frame(switch_media_bug_t *bug, switch_frame_t *frame, switch_rw_t rw)
uint32_t rate
Definition: switch_frame.h:63
switch_status_t switch_ivr_pause_detect_speech(switch_core_session_t *session)
Pause background Speech detection on a session.
switch_ivr_dmachine_match_t match
switch_memory_pool_t * pool
#define switch_channel_get_variable(_c, _v)
switch_call_cause_t cause
#define SWITCH_THREAD_STACKSIZE
Definition: switch_types.h:551
switch_status_t switch_channel_dequeue_dtmf(_In_ switch_channel_t *channel, _In_ switch_dtmf_t *dtmf)
Retrieve DTMF digits from a given channel.
switch_status_t switch_core_media_bug_remove_callback(switch_core_session_t *session, switch_media_bug_callback_t callback)
Remove media bug callback.
switch_status_t switch_event_add_header_string(switch_event_t *event, switch_stack_t stack, const char *header_name, const char *data)
Add a string header to an event.
switch_file_handle_t in_fh
#define switch_zmalloc(ptr, len)
switch_thread_t * thread
void switch_img_copy(switch_image_t *img, switch_image_t **new_img)
Copy image to a new image.
switch_ivr_dmachine_callback_t match_callback
const char * caller_id_name
Definition: switch_caller.h:79
#define switch_safe_free(it)
Free a pointer and set it to NULL unless it already is NULL.
Definition: switch_utils.h:789
teletone_hit_type_t teletone_dtmf_detect(teletone_dtmf_detect_state_t *dtmf_detect_state, int16_t sample_buffer[], int samples)
Check a sample buffer for the presence of DTMF digits.
switch_status_t switch_img_fit(switch_image_t **srcP, int width, int height, switch_img_fit_t fit)
switch_status_t switch_ivr_preprocess_session(switch_core_session_t *session, const char *cmds)
switch_status_t switch_ivr_inband_dtmf_session(switch_core_session_t *session)
Start looking for DTMF inband.
static void display_exec_cb(switch_media_bug_t *bug, void *user_data)
switch_status_t switch_mutex_init(switch_mutex_t **lock, unsigned int flags, switch_memory_pool_t *pool)
Definition: switch_apr.c:270
switch_status_t switch_ivr_dmachine_bind(switch_ivr_dmachine_t *dmachine, const char *realm, const char *digits, int32_t key, switch_ivr_dmachine_callback_t callback, void *user_data)
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH+1]
switch_status_t switch_channel_transfer_variable_prefix(switch_channel_t *orig_channel, switch_channel_t *new_channel, const char *prefix)
switch_image_t * switch_img_read_png(const char *file_name, switch_img_fmt_t img_fmt)
uint32_t switch_core_media_bug_clear_flag(_In_ switch_media_bug_t *bug, _In_ uint32_t flag)
switch_status_t switch_ivr_video_write_overlay_session(switch_core_session_t *session, const char *img_path, switch_img_position_t pos, uint8_t alpha)
void switch_buffer_zero(_In_ switch_buffer_t *buffer)
Remove all data from the buffer.
static switch_status_t generate_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction)
static switch_bool_t preprocess_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
#define switch_channel_down_nosig(_channel)
switch_byte_t write_out[2048]
switch_img_position_t pos
switch_buffer_t * w_buffer
An abstraction of a data frame.
Definition: switch_frame.h:43
switch_status_t switch_core_asr_disable_grammar(switch_asr_handle_t *ah, const char *name)
Disable a grammar from an asr handle.
uintptr_t switch_size_t
switch_status_t switch_ivr_session_audio(switch_core_session_t *session, const char *cmd, const char *direction, int level)
#define arg_recursion_check_start(_args)
switch_status_t switch_ivr_stop_tone_detect_session(switch_core_session_t *session)
Stop looking for TONES.
switch_frame_t * video_ping_frame
switch_status_t switch_ivr_stop_displace_session(switch_core_session_t *session, const char *file)
Stop displacing a session.
switch_ivr_dmachine_callback_t callback
switch_status_t switch_core_media_bug_read(_In_ switch_media_bug_t *bug, _In_ switch_frame_t *frame, switch_bool_t fill)
Read a frame from the bug.
uint32_t switch_asr_flag_t
switch_status_t switch_core_media_bug_remove(_In_ switch_core_session_t *session, _Inout_ switch_media_bug_t **bug)
Remove a media bug from the session.
switch_status_t switch_ivr_detect_speech_load_grammar(switch_core_session_t *session, const char *grammar, const char *name)
Load a grammar on a background speech detection handle.
switch_vid_spy_fmt_t switch_media_bug_parse_spy_fmt(const char *name)
#define switch_core_codec_init(_codec, _codec_name, _modname, _fmtp, _rate, _ms, _channels, _flags, _codec_settings, _pool)
Initialize a codec handle.
Definition: switch_core.h:1602
switch_byte_t is_match
switch_status_t switch_ivr_eavesdrop_session(switch_core_session_t *session, const char *uuid, const char *require_group, switch_eavesdrop_flag_t flags)
Eavesdrop on a another session.
#define switch_core_session_get_partner(_session, _partner)
Definition: switch_core.h:1002
uint32_t switch_eavesdrop_flag_t
Definition: switch_types.h:345
dm_match_t
switch_status_t switch_ivr_detect_speech_disable_grammar(switch_core_session_t *session, const char *name)
Disable a grammar on a background speech detection handle.
#define SWITCH_STANDARD_STREAM(s)
char * switch_copy_string(_Out_z_cap_(dst_size) char *dst, _In_z_ const char *src, _In_ switch_size_t dst_size)
switch_status_t switch_ivr_detect_speech(switch_core_session_t *session, const char *mod_name, const char *grammar, const char *name, const char *dest, switch_asr_handle_t *ah)
Engage background Speech detection on a session.
switch_status_t switch_core_session_queue_event(_In_ switch_core_session_t *session, _Inout_ switch_event_t **event)
Queue an event on a given session.
#define SWITCH_BRIDGE_VARIABLE
Definition: switch_types.h:199
switch_call_cause_t
switch_dtmf_direction_t
Definition: switch_types.h:310
switch_byte_t read_data[2048]
switch_status_t switch_ivr_detect_speech_unload_grammar(switch_core_session_t *session, const char *name)
Unload a grammar on a background speech detection handle.
switch_status_t switch_ivr_stop_inband_dtmf_generate_session(switch_core_session_t *session)
Stop generating DTMF inband.
void * switch_core_hash_delete(_In_ switch_hash_t *hash, _In_z_ const char *key)
Delete data from a hash based on desired key.
void switch_buffer_add_mutex(_In_ switch_buffer_t *buffer, _In_ switch_mutex_t *mutex)
static switch_status_t video_eavesdrop_callback(switch_core_session_t *session, switch_frame_t *frame, void *user_data)
switch_byte_t write_data[2048]
switch_status_t switch_ivr_resume_detect_speech(switch_core_session_t *session)
Resume background Speech detection on a session.
#define switch_core_session_receive_message(_session, _message)
Definition: switch_core.h:1217
void switch_core_session_rwunlock(_In_ switch_core_session_t *session)
Unlock a read or write lock on as given session.
switch_directories SWITCH_GLOBAL_dirs
Definition: switch_core.c:60
char * switch_core_session_get_uuid(_In_ switch_core_session_t *session)
Retrieve the unique identifier from a session.
void switch_core_session_video_reset(switch_core_session_t *session)
switch_mutex_t * mutex
void switch_channel_set_app_flag_key(const char *app, switch_channel_t *channel, uint32_t flags)
#define switch_str_nil(s)
Make a null string a blank string instead.
Definition: switch_utils.h:903
static char switch_itodtmf(char i)
Definition: switch_utils.h:389
int teletone_dtmf_get(teletone_dtmf_detect_state_t *dtmf_detect_state, char *buf, unsigned int *dur)
retrieve any collected digits into a string buffer
void switch_mux_channels(int16_t *data, switch_size_t samples, uint32_t orig_channels, uint32_t channels)
static switch_bool_t video_write_overlay_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
switch_status_t switch_thread_cond_signal(switch_thread_cond_t *cond)
Definition: switch_apr.c:371
static switch_bool_t inband_dtmf_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
switch_status_t switch_ivr_tone_detect_session(switch_core_session_t *session, const char *key, const char *tone_spec, const char *flags, time_t timeout, int hits, const char *app, const char *data, switch_tone_detect_callback_t callback)
Start looking for TONES.
void switch_ivr_dmachine_set_digit_timeout_ms(switch_ivr_dmachine_t *dmachine, uint32_t digit_timeout_ms)
#define SWITCH_DEFAULT_DIR_PERMS
Definition: switch_types.h:118
switch_status_t switch_core_session_write_video_frame(_In_ switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
Write a video frame to a session.
uint32_t switch_core_default_dtmf_duration(uint32_t duration)
Definition: switch_core.c:1681
switch_digit_action_target_t switch_ivr_dmachine_get_target(switch_ivr_dmachine_t *dmachine)
teletone_dtmf_detect_state_t dtmf_detect
#define switch_channel_expand_variables(_channel, _in)
static void *SWITCH_THREAD_FUNC speech_thread(switch_thread_t *thread, void *obj)
switch_status_t switch_core_session_request_video_refresh(switch_core_session_t *session)
switch_status_t switch_ivr_dmachine_clear_realm(switch_ivr_dmachine_t *dmachine, const char *realm)
switch_status_t switch_core_asr_check_results(switch_asr_handle_t *ah, switch_asr_flag_t *flags)
Check an asr handle for results.
static const char * ep
Definition: switch_json.c:36
switch_bool_t speech_detected
struct apr_thread_mutex_t switch_mutex_t
Definition: switch_apr.h:314
switch_status_t switch_ivr_stop_video_write_overlay_session(switch_core_session_t *session)
switch_image_t * img
Definition: switch_frame.h:77
switch_status_t
Common return values.
switch_status_t switch_core_file_write(_In_ switch_file_handle_t *fh, void *data, switch_size_t *len)
Write media to a file handle.
void * switch_channel_get_private(switch_channel_t *channel, const char *key)
Retrieve private from a given channel.
switch_status_t switch_core_session_queue_private_event(_In_ switch_core_session_t *session, _Inout_ switch_event_t **event, switch_bool_t priority)
Queue a private event on a given session.
switch_time_t last_digit_time
switch_status_t switch_core_session_dequeue_event(_In_ switch_core_session_t *session, _Out_ switch_event_t **event, switch_bool_t force)
DE-Queue an event on a given session.
switch_byte_t read_out[2048]
switch_status_t switch_ivr_dmachine_set_realm(switch_ivr_dmachine_t *dmachine, const char *realm)
int teletone_multi_tone_detect(teletone_multi_tone_t *mt, int16_t sample_buffer[], int samples)
Check a sample buffer for the presence of the mulit-frequency tone described by mt.
switch_status_t switch_dir_make_recursive(const char *path, switch_fileperms_t perm, switch_memory_pool_t *pool)
Definition: switch_apr.c:528
void switch_ivr_dmachine_set_input_timeout_ms(switch_ivr_dmachine_t *dmachine, uint32_t input_timeout_ms)
switch_status_t switch_ivr_detect_speech_disable_all_grammars(switch_core_session_t *session)
Disable all grammars on a background speech detection handle.
switch_size_t switch_channel_has_dtmf(_In_ switch_channel_t *channel)
Test for presence of DTMF on a given channel.
switch_status_t switch_ivr_record_session(switch_core_session_t *session, char *file, uint32_t limit, switch_file_handle_t *fh)
Record a session to disk.
#define switch_core_hash_insert(_h, _k, _d)
Definition: switch_core.h:1410
void switch_buffer_unlock(_In_ switch_buffer_t *buffer)
struct apr_thread_t switch_thread_t
Definition: switch_apr.h:941
#define switch_core_session_locate(uuid_str)
Locate a session based on it's uuid.
Definition: switch_core.h:916
int switch_channel_state_change_pending(switch_channel_t *channel)
switch_bind_flag_t bind_flags
Main Library Header.
uint32_t switch_merge_sln(int16_t *data, uint32_t samples, int16_t *other_data, uint32_t other_samples, int channels)
#define switch_event_create(event, id)
Create a new event assuming it will not be custom event and therefore hiding the unused parameters...
Definition: switch_event.h:383
static switch_bool_t switch_is_file_path(const char *file)
static void send_record_stop_event(switch_channel_t *channel, switch_codec_implementation_t *read_impl, struct record_helper *rh)
switch_memory_pool_t * pool
switch_status_t switch_ivr_set_param_detect_speech(switch_core_session_t *session, const char *name, const char *val)
switch_status_t switch_ivr_eavesdrop_update_display(switch_core_session_t *session, const char *name, const char *number)
char last_matching_digits[DMACHINE_MAX_DIGIT_LEN]
switch_status_t switch_core_asr_resume(switch_asr_handle_t *ah)
Resume detection on an asr handle.
#define SWITCH_DECLARE(type)
uint32_t samples
Definition: switch_frame.h:61
switch_core_session_t * session
#define switch_event_get_header(_e, _h)
Definition: switch_event.h:172
switch_status_t switch_ivr_displace_session(switch_core_session_t *session, const char *file, uint32_t limit, const char *flags)
displace the media for a session with the audio from a file
#define switch_channel_set_flag(_c, _f)
SpeexPreprocessState * read_st
An abstraction to store a tone generation session.
switch_byte_t my_pool
uint32_t channels
Definition: switch_frame.h:65
switch_bool_t switch_core_file_has_video(switch_file_handle_t *fh, switch_bool_t CHECK_OPEN)
switch_mutex_t * r_mutex
#define SWITCH_CHANNEL_EXECUTE_ON_TONE_DETECT_VARIABLE
Definition: switch_types.h:152
#define switch_set_string(_dst, _src)
Definition: switch_utils.h:665
switch_status_t switch_queue_trypush(switch_queue_t *queue, void *data)
Definition: switch_apr.c:1155
void switch_core_media_bug_set_read_demux_frame(_In_ switch_media_bug_t *bug, _In_ switch_frame_t *frame)
switch_thread_t * thread
switch_status_t(* switch_ivr_dmachine_callback_t)(switch_ivr_dmachine_match_t *match)
switch_status_t switch_ivr_dmachine_ping(switch_ivr_dmachine_t *dmachine, switch_ivr_dmachine_match_t **match_p)
#define switch_channel_media_ack(_channel)
static const char * skip(const char *in)
Definition: switch_json.c:270
static int teletone_dtmf_generate_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
switch_status_t switch_ivr_bind_dtmf_meta_session(switch_core_session_t *session, uint32_t key, switch_bind_flag_t bind_flags, const char *app)
switch_status_t switch_ivr_block_dtmf_session(switch_core_session_t *session)
time_t switch_epoch_time_now(time_t *t)
Get the current epoch time.
Definition: switch_time.c:321
switch_status_t switch_ivr_detect_speech_enable_grammar(switch_core_session_t *session, const char *name)
Enable a grammar on a background speech detection handle.
const char * caller_id_number
Definition: switch_caller.h:81
switch_mutex_t * write_mutex
switch_frame_t demux_frame
switch_status_t switch_ivr_unbind_dtmf_meta_session(switch_core_session_t *session, uint32_t key)
#define SWITCH_PLAYBACK_TERMINATORS_VARIABLE
Definition: switch_types.h:184
#define switch_core_session_alloc(_session, _memory)
Allocate memory from a session's pool.
Definition: switch_core.h:694
static void * switch_ivr_record_user_data_dup(switch_core_session_t *session, void *user_data)
switch_bool_t hangup_on_error
switch_buffer_t * buffer
static int switch_dtmftoi(char *s)
Definition: switch_utils.h:402
struct apr_pool_t switch_memory_pool_t
uint32_t switch_ivr_schedule_broadcast(time_t runtime, const char *uuid, const char *path, switch_media_flag_t flags)
Signal the session to broadcast audio in the future.
uint32_t switch_media_flag_t
Definition: switch_types.h:477
switch_status_t switch_core_asr_enable_grammar(switch_asr_handle_t *ah, const char *name)
Enable a grammar from an asr handle.
#define SWITCH_META_VAR_KEY
const char * switch_ivr_dmachine_get_name(switch_ivr_dmachine_t *dmachine)
#define switch_test_flag(obj, flag)
Test for the existance of a flag on an arbitary object.
Definition: switch_utils.h:624
switch_dtmf_source_t source
Definition: switch_types.h:290
void switch_channel_clear_flag_recursive(switch_channel_t *channel, switch_channel_flag_t flag)
void switch_log_printf(_In_ switch_text_channel_t channel, _In_z_ const char *file, _In_z_ const char *func, _In_ int line, _In_opt_z_ const char *userdata, _In_ switch_log_level_t level, _In_z_ _Printf_format_string_ const char *fmt,...) PRINTF_FUNCTION(7
Write log data to the logging engine.
const char * switch_stristr(const char *instr, const char *str)
void switch_core_gen_encoded_silence(unsigned char *data, const switch_codec_implementation_t *read_impl, switch_size_t len)
switch_status_t switch_ivr_detect_speech_init(switch_core_session_t *session, const char *mod_name, const char *dest, switch_asr_handle_t *ah)
Initialize background Speech detection on a session, so that parameters can be set, and grammars loaded. After calling this function, it is possible to call switch_ivr_set_param_detect_speech() to set recognition parameters. Calling switch_ivr_detect_speech_load_grammar() starts the speech recognition.
switch_status_t switch_threadattr_create(switch_threadattr_t **new_attr, switch_memory_pool_t *pool)
Definition: switch_apr.c:642
switch_status_t switch_thread_create(switch_thread_t **new_thread, switch_threadattr_t *attr, switch_thread_start_t func, void *data, switch_memory_pool_t *cont)
Definition: switch_apr.c:675
switch_status_t switch_ivr_inband_dtmf_generate_session(switch_core_session_t *session, switch_bool_t read_stream)
Start generating DTMF inband.
A table of settings and callbacks that define a paticular implementation of a codec.
#define switch_is_valid_rate(_tmp)
Definition: switch_utils.h:344
dtmf_meta_settings_t sr[3]
switch_status_t switch_ivr_transfer_recordings(switch_core_session_t *orig_session, switch_core_session_t *new_session)
void switch_img_overlay(switch_image_t *IMG, switch_image_t *img, int x, int y, uint8_t percent)
put a small img over a big IMG at position x,y, with alpha transparency
#define switch_normalize_to_16bit(n)
Definition: switch_utils.h:261
#define switch_ivr_phrase_macro(session, macro_name, data, lang, args)
Definition: switch_ivr.h:903
switch_status_t switch_core_file_write_video(_In_ switch_file_handle_t *fh, switch_frame_t *frame)
Write media to a file handle.
uint32_t switch_media_bug_flag_t
switch_frame_t * switch_core_media_bug_get_native_write_frame(switch_media_bug_t *bug)
uint32_t switch_core_media_bug_test_flag(_In_ switch_media_bug_t *bug, _In_ uint32_t flag)
Test for the existance of a flag on an media bug.
switch_file_handle_t out_fh
#define switch_channel_up_nosig(_channel)
switch_status_t switch_queue_create(switch_queue_t **queue, unsigned int queue_capacity, switch_memory_pool_t *pool)
Definition: switch_apr.c:1109
#define switch_core_session_strdup(_session, _todup)
Copy a string using memory allocation from a session's pool.
Definition: switch_core.h:717
void switch_event_destroy(switch_event_t **event)
Destroy an event.
switch_status_t switch_ivr_session_echo(switch_core_session_t *session, switch_input_args_t *args)
NEEDDESC -
switch_file_handle_t * fh
unsigned int d_h
Definition: switch_image.h:100
switch_status_t switch_core_media_bug_exec_all(switch_core_session_t *orig_session, const char *function, switch_media_bug_exec_cb_t cb, void *user_data)
static switch_bool_t write_displace_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
void switch_channel_clear_flag(switch_channel_t *channel, switch_channel_flag_t flag)
Clear given flag(s) from a channel.
#define SWITCH_RECORD_POST_PROCESS_EXEC_API_VARIABLE
Definition: switch_types.h:146
int switch_channel_test_app_flag_key(const char *app, switch_channel_t *channel, uint32_t flags)
void switch_ivr_dmachine_destroy(switch_ivr_dmachine_t **dmachine)
#define switch_assert(expr)
switch_tone_detect_callback_t callback
switch_status_t switch_core_asr_unload_grammar(switch_asr_handle_t *ah, const char *name)
Unload a grammar from an asr handle.
dtmf_meta_app_t map[14]
switch_mutex_t * mutex
#define switch_channel_set_variable(_channel, _var, _val)
switch_time_t switch_time_now(void)
Definition: switch_apr.c:302
#define switch_channel_pre_answer(channel)
Indicate progress on a channel to attempt early media.
switch_caller_profile_t * switch_channel_get_caller_profile(switch_channel_t *channel)
Retrieve the given channel's caller profile.
switch_mutex_t * mutex
void switch_core_asr_text_param(switch_asr_handle_t *ah, char *param, const char *val)
Set a text parameter on an asr handle.
switch_size_t switch_buffer_inuse(_In_ switch_buffer_t *buffer)
Get the in use amount of a switch_buffer_t.
switch_status_t switch_channel_api_on(switch_channel_t *channel, const char *variable_prefix)
void switch_buffer_destroy(switch_buffer_t **buffer)
Destroy the buffer.
char * switch_channel_get_name(switch_channel_t *channel)
Retrieve the name of a given channel.
SWITCH_BEGIN_EXTERN_C char * switch_mprintf(const char *zFormat,...)
#define SWITCH_READ_ACCEPTABLE(status)
Definition: switch_utils.h:995
switch_tone_detect_t list[MAX_TONES+1]
static switch_status_t meta_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction)
memset(buf, 0, buflen)
#define switch_channel_media_up(_channel)
#define SWITCH_CHANNEL_CHANNEL_LOG(x)
const char * callee_id_name
Definition: switch_caller.h:87
switch_mutex_t * mutex
void teletone_dtmf_detect_init(teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate)
Initilize a DTMF detection state object.
switch_memory_pool_t * switch_core_session_get_pool(_In_ switch_core_session_t *session)
Retrieve the memory pool from a session.
#define SWITCH_CHANNEL_API_ON_TONE_DETECT_VARIABLE
Definition: switch_types.h:164
#define DMACHINE_MAX_DIGIT_LEN
SpeexEchoState * read_ec
switch_status_t last_return
#define SWITCH_UUID_FORMATTED_LENGTH
Definition: switch_apr.h:545
switch_status_t switch_ivr_detect_speech_start_input_timers(switch_core_session_t *session)
Start input timers on a background speech detection handle.
uint32_t switch_ivr_schedule_transfer(time_t runtime, const char *uuid, char *extension, char *dialplan, char *context)
Transfer an existing session to another location in the future.
switch_status_t switch_regex_match(const char *target, const char *expression)
Function to evaluate an expression against a string.
Definition: switch_regex.c:295
switch_bool_t(* switch_tone_detect_callback_t)(switch_core_session_t *, const char *, const char *)
#define SWITCH_DEFAULT_FILE_BUFFER_LEN
Definition: switch_types.h:229
switch_status_t switch_ivr_record_session_mask(switch_core_session_t *session, const char *file, switch_bool_t on)
static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
switch_media_bug_t * bug