RTS API Documentation  1.10.11
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  char *repl;
45  char *substituted;
46  int32_t key;
47  uint8_t rmatch;
51  void *user_data;
53 };
55 
56 typedef struct {
59  char *name;
60  char *terminators;
62 
66  char *name;
67  uint32_t digit_timeout_ms;
68  uint32_t input_timeout_ms;
73  char last_matching_digits[DMACHINE_MAX_DIGIT_LEN];
74  char last_failed_digits[DMACHINE_MAX_DIGIT_LEN];
75  uint32_t cur_digit_len;
76  uint32_t max_digit_len;
83  void *user_data;
86  uint8_t pinging;
87 };
88 
89 static const char *get_recording_var(switch_channel_t *channel, switch_event_t *vars, const char *name);
90 static int recording_var_true(switch_channel_t *channel, switch_event_t *vars, const char *name);
92 
94 {
95  return dmachine->last_return;
96 }
97 
99 {
100  switch_assert(dmachine);
101  return dmachine->target;
102 }
103 
105 {
106  switch_assert(dmachine);
107  dmachine->target = target;
108 }
109 
110 
112 {
113 
114  switch_assert(dmachine);
115  dmachine->match_callback = match_callback;
116 
117 }
118 
120 {
121 
122  switch_assert(dmachine);
123  dmachine->nonmatch_callback = nonmatch_callback;
124 
125 }
126 
128 {
129  return (const char *) dmachine->name;
130 }
131 
133  const char *name,
135  uint32_t digit_timeout_ms,
136  uint32_t input_timeout_ms,
137  switch_ivr_dmachine_callback_t match_callback,
138  switch_ivr_dmachine_callback_t nonmatch_callback,
139  void *user_data)
140 {
141  switch_byte_t my_pool = 0;
142  switch_ivr_dmachine_t *dmachine;
143 
144  if (!pool) {
146  my_pool = 1;
147  }
148 
149  dmachine = switch_core_alloc(pool, sizeof(*dmachine));
150  dmachine->pool = pool;
151  dmachine->my_pool = my_pool;
152  dmachine->digit_timeout_ms = digit_timeout_ms;
153  dmachine->input_timeout_ms = input_timeout_ms;
154  dmachine->match.dmachine = dmachine;
155  dmachine->name = switch_core_strdup(dmachine->pool, name);
156  switch_mutex_init(&dmachine->mutex, SWITCH_MUTEX_NESTED, dmachine->pool);
157 
159 
160  if (match_callback) {
161  dmachine->match_callback = match_callback;
162  }
163 
164  if (nonmatch_callback) {
165  dmachine->nonmatch_callback = nonmatch_callback;
166  }
167 
168  dmachine->user_data = user_data;
169 
170  *dmachine_p = dmachine;
171 
172  return SWITCH_STATUS_SUCCESS;
173 }
174 
175 
177 {
178  dmachine->digit_timeout_ms = digit_timeout_ms;
179 }
180 
182 {
183  dmachine->input_timeout_ms = input_timeout_ms;
184 }
185 
187 {
189 
190  if (!(dmachine && *dmachine)) return;
191 
192  pool = (*dmachine)->pool;
193 
194  switch_core_hash_destroy(&(*dmachine)->binding_hash);
195 
196  if ((*dmachine)->my_pool) {
198  }
199 }
200 
202 {
203  if (!dmachine->realm) {
204  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No realm selected.\n");
205  return SWITCH_STATUS_FALSE;
206  }
207 
208 
209  dmachine->realm->terminators = switch_core_strdup(dmachine->pool, terminators);
210  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Digit parser %s: Setting terminators for realm '%s' to '%s'\n",
211  dmachine->name, dmachine->realm->name, terminators);
212 
213  return SWITCH_STATUS_SUCCESS;
214 }
215 
217 {
218  dm_binding_head_t *headp = switch_core_hash_find(dmachine->binding_hash, realm);
219 
220  if (headp) {
221  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Digit parser %s: Setting realm to '%s'\n", dmachine->name, realm);
222  dmachine->realm = headp;
223  return SWITCH_STATUS_SUCCESS;
224  }
225 
226  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Digit parser %s: Error Setting realm to '%s'\n", dmachine->name, realm);
227 
228  return SWITCH_STATUS_FALSE;
229 }
230 
232 {
233  dm_binding_head_t *headp;
234 
235  if (zstr(realm)) {
236  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Digit parser %s: Error unknown realm: '%s'\n", dmachine->name, realm);
237  return SWITCH_STATUS_FALSE;
238  }
239 
240  headp = switch_core_hash_find(dmachine->binding_hash, realm);
241 
242  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Digit parser %s: Clearing realm '%s'\n", dmachine->name, realm);
243 
244  if (headp == dmachine->realm) {
246  "Digit parser %s: '%s' was the active realm, no realm currently selected.\n", dmachine->name, realm);
247  dmachine->realm = NULL;
248  }
249 
250  /* pool alloc'd just ditch it and it will give back the memory when we destroy ourselves */
251  switch_core_hash_delete(dmachine->binding_hash, realm);
252  return SWITCH_STATUS_SUCCESS;
253 }
254 
256  const char *realm,
257  const char *digits,
259  int32_t key,
261  void *user_data)
262 {
263  switch_ivr_dmachine_binding_t *binding = NULL, *ptr;
264  switch_size_t len;
265  dm_binding_head_t *headp;
266  const char *msg = "";
267  char *repl = NULL;
268  char *digits_;
269 
270  if (strlen(digits) > DMACHINE_MAX_DIGIT_LEN -1) {
271  return SWITCH_STATUS_FALSE;
272  }
273 
274  if (zstr(realm)) {
275  realm = "default";
276  }
277 
278  if (!(headp = switch_core_hash_find(dmachine->binding_hash, realm))) {
279  headp = switch_core_alloc(dmachine->pool, sizeof(*headp));
280  headp->name = switch_core_strdup(dmachine->pool, realm);
281  switch_core_hash_insert(dmachine->binding_hash, realm, headp);
282  }
283 
284  for(ptr = headp->binding_list; ptr; ptr = ptr->next) {
285  if ((ptr->is_regex && !strcmp(ptr->digits, digits+1)) || !strcmp(ptr->digits, digits)) {
286  msg = "Reuse Existing ";
287  binding = ptr;
288  binding->callback = callback;
289  binding->user_data = user_data;
290  goto done;
291  }
292  }
293 
294 
295  binding = switch_core_alloc(dmachine->pool, sizeof(*binding));
296 
297  digits_ = switch_core_strdup(dmachine->pool, digits);
298 
299  if (*digits_ == '=') {
300  binding->first_match = 1;
301  digits_++;
302  }
303 
304  if (*digits_ == '~') {
305  binding->is_regex = 1;
306  digits_++;
307  if ((repl = strchr(digits_, '~')) && *(repl+1) == '~') {
308  *repl++ = '\0';
309  *repl++ = '\0';
310  }
311  }
312 
313  binding->key = key;
314  binding->digits = digits_;
315  binding->is_priority = is_priority;
316  binding->callback = callback;
317  binding->user_data = user_data;
318  binding->repl = repl;
319 
320  if (headp->tail) {
321  headp->tail->next = binding;
322  } else {
323  headp->binding_list = binding;
324  }
325 
326  headp->tail = binding;
327 
328  len = strlen(digits);
329 
330  if (dmachine->realm != headp) {
331  switch_ivr_dmachine_set_realm(dmachine, realm);
332  }
333 
334  if (binding->is_regex && dmachine->max_digit_len != DMACHINE_MAX_DIGIT_LEN -1) {
335  dmachine->max_digit_len = DMACHINE_MAX_DIGIT_LEN -1;
336  } else if (len > dmachine->max_digit_len) {
337  dmachine->max_digit_len = (uint32_t) len;
338  }
339 
340  done:
341 
342  if (binding->is_regex) {
343  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%sDigit parser %s: binding %s/%s/%d callback: %p data: %p\n",
344  msg, dmachine->name, digits, realm, key, (void *)(intptr_t) callback, user_data);
345  } else {
346  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%sDigit parser %s: binding %s/%s/%d callback: %p data: %p\n",
347  msg, dmachine->name, digits, realm, key, (void *)(intptr_t) callback, user_data);
348  }
349 
350  return SWITCH_STATUS_SUCCESS;
351 }
352 
353 typedef enum {
359 } dm_match_t;
360 
361 
363 {
364  dm_match_t best = DM_MATCH_NONE;
365  switch_ivr_dmachine_binding_t *bp, *exact_bp = NULL, *partial_bp = NULL, *both_bp = NULL, *r_bp = NULL;
366  int pmatches = 0, ematches = 0, rmatches = 0;
367 
368  if (!dmachine->cur_digit_len || !dmachine->realm) goto end;
369 
370  for(bp = dmachine->realm->binding_list; bp; bp = bp->next) {
371  if (bp->is_regex) {
372  if (bp->repl) {
373  int ovector[30] = { 0 };
374  int proceed = 0;
375  switch_regex_t *re = NULL;
376 
377 
378  proceed = switch_regex_perform(dmachine->digits, bp->digits, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
379 
380  if (proceed) {
381  char *substituted = NULL;
382  switch_size_t len;
383 
384  len = (strlen(dmachine->digits) + strlen(bp->digits) + 10) * proceed;
385  substituted = malloc(len);
386  switch_assert(substituted);
387  memset(substituted, 0, len);
388  switch_perform_substitution(re, proceed, bp->repl, dmachine->digits, substituted, len, ovector);
389 
390  if (!bp->substituted || strcmp(substituted, bp->substituted)) {
391  bp->substituted = switch_core_strdup(dmachine->pool, substituted);
392  }
393  free(substituted);
395  bp->rmatch = 1;
396  } else {
397  bp->substituted = NULL;
398  bp->rmatch = 0;
399  }
400  } else {
401  switch_status_t r_status = switch_regex_match(dmachine->digits, bp->digits);
402  bp->rmatch = r_status == SWITCH_STATUS_SUCCESS;
403  }
404 
405  rmatches++;
406  pmatches++;
407 
408  if (bp->rmatch && bp->first_match) break;
409 
410  } else {
411  if (!strncmp(dmachine->digits, bp->digits, strlen(dmachine->digits))) {
412  pmatches++;
413  if (dmachine->cur_digit_len == strlen(bp->digits)) {
414  ematches++;
415  }
416  }
417  }
418  }
419 
420  if (!zstr(dmachine->realm->terminators)) {
421  char *p = dmachine->realm->terminators;
422  char *q;
423 
424  while(p && *p) {
425  if ((q=strrchr(dmachine->digits, *p))) {
426  *q = '\0';
427  is_timeout = 1;
428  break;
429  }
430  p++;
431  }
432  }
433 
434  for(bp = dmachine->realm->binding_list; bp; bp = bp->next) {
435  if (bp->is_regex) {
436  if (bp->rmatch) {
437  if (bp->first_match || (bp->is_priority && ! ematches) || is_timeout || (bp == dmachine->realm->binding_list && !bp->next)) {
438  best = DM_MATCH_EXACT;
439  exact_bp = bp;
440  break;
441  }
442  best = DM_MATCH_PARTIAL;
443  }
444  } else {
445  int pmatch = !strncmp(dmachine->digits, bp->digits, strlen(dmachine->digits));
446 
447  if (!exact_bp && pmatch && (bp->first_match || !rmatches || bp->is_priority || is_timeout) && !strcmp(bp->digits, dmachine->digits)) {
448  best = DM_MATCH_EXACT;
449  exact_bp = bp;
450  if (bp->first_match || bp->is_priority || dmachine->cur_digit_len == dmachine->max_digit_len) break;
451  }
452 
453  if (!(both_bp && partial_bp) && strlen(bp->digits) != strlen(dmachine->digits) && pmatch) {
454 
455  if (exact_bp) {
456  best = DM_MATCH_BOTH;
457  both_bp = bp;
458  } else {
459  best = DM_MATCH_PARTIAL;
460  partial_bp = bp;
461  }
462  }
463 
464  if (both_bp && exact_bp && partial_bp) break;
465  }
466  }
467 
468  if (!pmatches) {
469  best = DM_MATCH_NEVER;
470  }
471 
472 
473  end:
474 
475  if (is_timeout) {
476  if (both_bp) {
477  r_bp = exact_bp;
478  }
479  }
480 
481  if (best == DM_MATCH_EXACT && exact_bp) {
482  r_bp = exact_bp;
483  }
484 
485 
486  if (r_bp) {
487  dmachine->last_matching_binding = r_bp;
488 
489  if (r_bp->substituted) {
490  switch_set_string(dmachine->last_matching_digits, r_bp->substituted);
491  } else {
492  switch_set_string(dmachine->last_matching_digits, dmachine->digits);
493  }
494  best = DM_MATCH_EXACT;
495  }
496 
497  return best;
498 
499 }
500 
502 {
504  uint32_t timeout = dmachine->cur_digit_len ? dmachine->digit_timeout_ms : dmachine->input_timeout_ms;
505 
506  if (!dmachine->last_digit_time) dmachine->last_digit_time = now;
507 
508  if (timeout) {
509  if ((uint32_t)((now - dmachine->last_digit_time) / 1000) > timeout) {
510  return SWITCH_TRUE;
511  }
512  }
513 
514  return SWITCH_FALSE;
515 }
516 
518 {
519  if (dmachine->is_match) {
520  dmachine->is_match = 0;
521  return &dmachine->match;
522  }
523 
524  return NULL;
525 }
526 
528 {
529 
530  return dmachine->last_failed_digits;
531 }
532 
534 {
535  switch_bool_t is_timeout = switch_ivr_dmachine_check_timeout(dmachine);
536  dm_match_t is_match = switch_ivr_dmachine_check_match(dmachine, is_timeout);
537  switch_status_t r, s;
538  int clear = 0;
539 
540  if (is_match == DM_MATCH_NEVER) {
541  is_timeout++;
542  }
543 
545  return SWITCH_STATUS_SUCCESS;
546  }
547 
548  if (dmachine->pinging) {
549  switch_mutex_unlock(dmachine->mutex);
550  return SWITCH_STATUS_BREAK;
551  }
552 
553  dmachine->pinging = 1;
554 
555  if (zstr(dmachine->digits) && !is_timeout) {
557  } else if (dmachine->cur_digit_len > dmachine->max_digit_len) {
559  } else if (is_match == DM_MATCH_EXACT || (is_match == DM_MATCH_BOTH && is_timeout)) {
561 
562  dmachine->match.match_digits = dmachine->last_matching_digits;
563  dmachine->match.match_key = dmachine->last_matching_binding->key;
564  dmachine->match.user_data = dmachine->last_matching_binding->user_data;
565 
566  if (match_p) {
567  *match_p = &dmachine->match;
568  }
569 
570  dmachine->is_match = 1;
571 
572  dmachine->match.type = DM_MATCH_POSITIVE;
573 
574  if (dmachine->last_matching_binding->callback) {
575  s = dmachine->last_matching_binding->callback(&dmachine->match);
576 
577  switch(s) {
580  break;
582  break;
583  default:
585  break;
586  }
587  }
588 
589  if (dmachine->match_callback) {
590  dmachine->match.user_data = dmachine->user_data;
591  s = dmachine->match_callback(&dmachine->match);
592 
593  switch(s) {
596  break;
598  break;
599  default:
601  break;
602  }
603 
604  }
605 
606  clear++;
607  } else if (is_timeout) {
609  } else if (is_match == DM_MATCH_NONE && dmachine->cur_digit_len == dmachine->max_digit_len) {
611  } else {
613  }
614 
616  switch_set_string(dmachine->last_failed_digits, dmachine->digits);
617  dmachine->match.match_digits = dmachine->last_failed_digits;
618 
619  dmachine->match.type = DM_MATCH_NEGATIVE;
620 
621  if (dmachine->nonmatch_callback) {
622  dmachine->match.user_data = dmachine->user_data;
623  s = dmachine->nonmatch_callback(&dmachine->match);
624 
625  switch(s) {
628  break;
630  break;
631  default:
633  break;
634  }
635 
636  }
637 
638  clear++;
639  }
640 
641  if (clear) {
642  switch_ivr_dmachine_clear(dmachine);
643  }
644 
645  dmachine->last_return = r;
646 
647  dmachine->pinging = 0;
648 
649  switch_mutex_unlock(dmachine->mutex);
650 
651  return r;
652 }
653 
655 {
656  const char *p;
658 
659  if (!zstr(digits)) {
660  status = SWITCH_STATUS_SUCCESS;
661  }
662 
663  for (p = digits; p && *p; p++) {
664  switch_mutex_lock(dmachine->mutex);
665  if (dmachine->cur_digit_len < dmachine->max_digit_len) {
666  switch_status_t istatus;
667  char *e = dmachine->digits + strlen(dmachine->digits);
668 
669  *e++ = *p;
670  *e = '\0';
671  dmachine->cur_digit_len++;
672  switch_mutex_unlock(dmachine->mutex);
673  dmachine->last_digit_time = switch_time_now();
674  if (status == SWITCH_STATUS_SUCCESS && (istatus = switch_ivr_dmachine_ping(dmachine, match)) != SWITCH_STATUS_SUCCESS) {
675  status = istatus;
676  }
677  } else {
678  switch_mutex_unlock(dmachine->mutex);
679  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "dmachine overflow error!\n");
680  status = SWITCH_STATUS_FALSE;
681  }
682  }
683 
684  return status;
685 }
686 
688 {
689  return !!dmachine->cur_digit_len;
690 }
691 
693 {
694 
695  memset(dmachine->digits, 0, sizeof(dmachine->digits));
696  dmachine->cur_digit_len = 0;
697  dmachine->last_digit_time = 0;
698  return SWITCH_STATUS_SUCCESS;
699 }
700 
701 
702 
704 {
705  switch_status_t status;
706  switch_frame_t *read_frame;
708 
710  return SWITCH_STATUS_FALSE;
711  }
712 
714 
715  if (switch_channel_var_true(channel, "echo_decode_video")) {
717  }
718 
719  if (switch_channel_var_true(channel, "echo_decode_audio")) {
721  }
722 
725 
726  while (switch_channel_ready(channel)) {
727  status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
728  if (!SWITCH_READ_ACCEPTABLE(status)) {
729  break;
730  }
731 
733 
734  if (args && (args->input_callback || args->buf || args->buflen)) {
735  switch_dtmf_t dtmf = {0};
736 
737  /*
738  dtmf handler function you can hook up to be executed when a digit is dialed during playback
739  if you return anything but SWITCH_STATUS_SUCCESS the playback will stop.
740  */
741  if (switch_channel_has_dtmf(channel)) {
742  if (!args->input_callback && !args->buf) {
743  break;
744  }
745  switch_channel_dequeue_dtmf(channel, &dtmf);
746  if (args->input_callback) {
747  status = args->input_callback(session, (void *) &dtmf, SWITCH_INPUT_TYPE_DTMF, args->buf, args->buflen);
748  } else {
749  *((char *) args->buf) = dtmf.digit;
750  status = SWITCH_STATUS_BREAK;
751  }
752  }
753 
754  if (args->input_callback) {
755  switch_event_t *event = NULL;
756 
758  status = args->input_callback(session, event, SWITCH_INPUT_TYPE_EVENT, args->buf, args->buflen);
759  switch_event_destroy(&event);
760  }
761  }
762 
763  if (status != SWITCH_STATUS_SUCCESS) {
764  break;
765  }
766  }
767 
768  switch_core_session_write_frame(session, read_frame, SWITCH_IO_FLAG_NONE, 0);
769 
770  if (switch_channel_test_flag(channel, CF_BREAK)) {
772  break;
773  }
774  }
775 
776  if (switch_channel_var_true(channel, "echo_decode_video")) {
778  }
779 
783 
784  return SWITCH_STATUS_SUCCESS;
785 }
786 
787 typedef struct {
789  int mux;
790  int loop;
791  char *file;
792  switch_buffer_t *wbuffer; // only in r&w mode
795 
797 {
798  displace_helper_t *dh = (displace_helper_t *) user_data;
799 
800  switch (type) {
802  break;
804  if (dh) {
806  switch_channel_t *channel;
807 
809 
810  if (session && (channel = switch_core_session_get_channel(session))) {
811  switch_channel_set_private(channel, dh->file, NULL);
812  }
813  }
814  break;
816  {
818  if (dh && !dh->mux) {
819  memset(rframe->data, 255, rframe->datalen);
820  }
822  }
823  break;
825  if (dh) {
826  switch_frame_t *rframe = NULL;
827  switch_size_t len;
828  switch_status_t st;
829 
831  len = rframe->samples;
832 
833  if (dh->mux) {
835  int16_t *fp = rframe->data;
836  uint32_t x;
837 
838  st = switch_core_file_read(&dh->fh, buf, &len);
839 
840  for (x = 0; x < (uint32_t) len * dh->fh.channels; x++) {
841  int32_t mixed = fp[x] + buf[x];
843  fp[x] = (int16_t) mixed;
844  }
845  } else {
846  st = switch_core_file_read(&dh->fh, rframe->data, &len);
847  if (len < rframe->samples) {
848  memset((char *)rframe->data + (len * 2 * dh->fh.channels), 0, (rframe->samples - len) * 2 * dh->fh.channels);
849  }
850  }
851 
852  rframe->datalen = rframe->samples * 2 * dh->fh.channels;
853 
854  if (st != SWITCH_STATUS_SUCCESS || len == 0) {
855  if (dh->loop) {
856  uint32_t pos = 0;
857  switch_core_file_seek(&dh->fh, &pos, 0, SEEK_SET);
858  } else {
860  switch_channel_t *channel;
861 
862  if (session && (channel = switch_core_session_get_channel(session))) {
863  switch_channel_set_private(channel, dh->file, NULL);
864  }
865  return SWITCH_FALSE;
866  }
867  }
868 
870  }
871  break;
873  default:
874  break;
875  }
876 
877  return SWITCH_TRUE;
878 }
879 
881 {
882  displace_helper_t *dh = (displace_helper_t *) user_data;
883 
884  switch (type) {
886  break;
888  if (dh) {
890  switch_channel_t *channel;
891 
892  if (dh->wbuffer) switch_buffer_destroy(&dh->wbuffer);
893  if (dh->mutex) switch_mutex_destroy(dh->mutex);
894 
896 
897  if (session && (channel = switch_core_session_get_channel(session))) {
898  switch_channel_set_private(channel, dh->file, NULL);
899  }
900  }
901  break;
903  {
905 
906  if (dh) {
907  if (dh->wbuffer) {
909  if (switch_buffer_inuse(dh->wbuffer) >= rframe->datalen) {
910  switch_buffer_read(dh->wbuffer, rframe->data, rframe->datalen);
911  } else {
913  SWITCH_LOG_WARNING, "not enough data %" SWITCH_SIZE_T_FMT "\n",
915  memset(rframe->data, 255, rframe->datalen);
916  }
918  } else if (!dh->mux) {
919  memset(rframe->data, 255, rframe->datalen);
920  }
921  }
922 
924  }
925  break;
927  if (dh) {
928  switch_frame_t *rframe = NULL;
929  switch_size_t len;
930  switch_status_t st;
932  len = rframe->samples;
933 
934  if (dh->mux) {
936  int16_t *fp = rframe->data;
937  uint32_t x;
938 
939  st = switch_core_file_read(&dh->fh, buf, &len);
940 
941  for (x = 0; x < (uint32_t) len * dh->fh.channels; x++) {
942  int32_t mixed = fp[x] + buf[x];
944  fp[x] = (int16_t) mixed;
945  }
946 
947  } else {
948  st = switch_core_file_read(&dh->fh, rframe->data, &len);
949  rframe->samples = (uint32_t) len;
950 
951  if (dh->wbuffer) {
953  switch_buffer_write(dh->wbuffer, rframe->data, len * 2 * dh->fh.channels);
955  }
956  }
957 
958  rframe->datalen = rframe->samples * 2 * dh->fh.channels;
959 
960 
961  if (st != SWITCH_STATUS_SUCCESS || len == 0) {
962  if (dh->loop) {
963  uint32_t pos = 0;
964  switch_core_file_seek(&dh->fh, &pos, 0, SEEK_SET);
965  } else {
967  switch_channel_t *channel;
968 
969  if (session && (channel = switch_core_session_get_channel(session))) {
970  switch_channel_set_private(channel, dh->file, NULL);
971  }
972  return SWITCH_FALSE;
973  }
974  }
975 
977  }
978  break;
980  default:
981  break;
982  }
983 
984  return SWITCH_TRUE;
985 }
986 
988 {
989  switch_media_bug_t *bug;
991 
992  if ((bug = switch_channel_get_private(channel, file))) {
993  switch_channel_set_private(channel, file, NULL);
994  switch_core_media_bug_remove(session, &bug);
995  return SWITCH_STATUS_SUCCESS;
996  }
997 
998  return SWITCH_STATUS_FALSE;
999 }
1000 
1001 SWITCH_DECLARE(switch_status_t) switch_ivr_displace_session(switch_core_session_t *session, const char *file, uint32_t limit, const char *flags)
1002 {
1004  switch_media_bug_t *bug;
1005  switch_status_t status;
1006  time_t to = 0;
1007  char *ext;
1008  const char *prefix;
1009  displace_helper_t *dh;
1010  const char *p;
1011  switch_bool_t hangup_on_error = SWITCH_FALSE;
1012  switch_media_bug_flag_enum_t bug_flags = 0;
1013  switch_codec_implementation_t read_impl = { 0 };
1014  switch_core_session_get_read_impl(session, &read_impl);
1015 
1016  if ((p = switch_channel_get_variable(channel, "DISPLACE_HANGUP_ON_ERROR"))) {
1017  hangup_on_error = switch_true(p);
1018  }
1019 
1020  if (zstr(file)) {
1021  return SWITCH_STATUS_FALSE;
1022  }
1023 
1025  return SWITCH_STATUS_FALSE;
1026  }
1027 
1028  if (!switch_channel_media_up(channel) || !switch_core_session_get_read_codec(session)) {
1029  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can not displace session. Media not enabled on channel\n");
1030  return SWITCH_STATUS_FALSE;
1031  }
1032 
1033  if ((bug = switch_channel_get_private(channel, file))) {
1034  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Only 1 of the same file per channel please!\n");
1035  return SWITCH_STATUS_FALSE;
1036  }
1037 
1038  if (!(dh = switch_core_session_alloc(session, sizeof(*dh)))) {
1039  return SWITCH_STATUS_MEMERR;
1040  }
1041 
1042  if (!(prefix = switch_channel_get_variable(channel, "sound_prefix"))) {
1043  prefix = SWITCH_GLOBAL_dirs.base_dir;
1044  }
1045 
1046  if (!strstr(file, SWITCH_URL_SEPARATOR)) {
1047  if (!switch_is_file_path(file)) {
1048  char *tfile = NULL;
1049  char *e;
1050 
1051  if (*file == '[') {
1052  tfile = switch_core_session_strdup(session, file);
1053  if ((e = switch_find_end_paren(tfile, '[', ']'))) {
1054  *e = '\0';
1055  file = e + 1;
1056  } else {
1057  tfile = NULL;
1058  }
1059  }
1060 
1061  file = switch_core_session_sprintf(session, "%s%s%s%s%s", switch_str_nil(tfile), tfile ? "]" : "", prefix, SWITCH_PATH_SEPARATOR, file);
1062  }
1063  if ((ext = strrchr(file, '.'))) {
1064  ext++;
1065  } else {
1066  ext = read_impl.iananame;
1067  file = switch_core_session_sprintf(session, "%s.%s", file, ext);
1068  }
1069  }
1070 
1071  dh->fh.channels = read_impl.number_of_channels;
1072  dh->fh.samplerate = read_impl.actual_samples_per_second;
1073  dh->file = switch_core_session_strdup(session, file);
1074 
1075  if (switch_core_file_open(&dh->fh,
1076  file,
1077  read_impl.number_of_channels,
1079  if (hangup_on_error) {
1082  }
1083  return SWITCH_STATUS_GENERR;
1084  }
1085 
1086  if (limit) {
1087  to = switch_epoch_time_now(NULL) + limit;
1088  }
1089 
1090  if (flags && strchr(flags, 'm')) {
1091  dh->mux++;
1092  }
1093 
1094  if (flags && strchr(flags, 'l')) {
1095  dh->loop++;
1096  }
1097 
1098  if (flags && strchr(flags, 'f')) {
1099  bug_flags |= SMBF_FIRST;
1100  }
1101 
1102  if (flags && strchr(flags, 'r')) {
1103  if (strchr(flags, 'w')) { // r&w mode, both sides can hear the same file
1104  int len = dh->fh.samplerate / 10 * 2 * dh->fh.channels; // init with 100ms
1105 
1107  switch_buffer_create_dynamic(&dh->wbuffer, len, len, 0);
1108  }
1109 
1110  status = switch_core_media_bug_add(session, "displace", file,
1112  } else {
1113  status = switch_core_media_bug_add(session, "displace", file,
1115  }
1116 
1117  if (status != SWITCH_STATUS_SUCCESS) {
1118  switch_core_file_close(&dh->fh);
1119  return status;
1120  }
1121 
1122  switch_channel_set_private(channel, file, bug);
1123 
1124  return SWITCH_STATUS_SUCCESS;
1125 }
1126 
1127 
1134  char *file;
1138  int native;
1139  uint32_t packet_len;
1140  int min_sec;
1146  int rready;
1147  int wready;
1158  uint32_t writes;
1159  uint32_t vwrites;
1160  const char *completion_cause;
1165 };
1166 
1168 
1169 /**
1170  * Set the recording completion cause. The cause can only be set once, to minimize the logic in the record_callback.
1171  * [The completion_cause strings are essentially those of an MRCP Recorder resource.]
1172  */
1173 static void set_completion_cause(struct record_helper *rh, const char *completion_cause)
1174 {
1175  if (!rh->completion_cause) {
1176  rh->completion_cause = completion_cause;
1177  }
1178 }
1179 
1180 static switch_bool_t is_silence_frame(switch_frame_t *frame, int silence_threshold, switch_codec_implementation_t *codec_impl)
1181 {
1182  int16_t *fdata = (int16_t *) frame->data;
1183  uint32_t samples = frame->datalen / sizeof(*fdata);
1184  switch_bool_t is_silence = SWITCH_TRUE;
1185  uint32_t channel_num = 0;
1186 
1187  int divisor = 0;
1188  if (!(divisor = codec_impl->samples_per_second / 8000)) {
1189  divisor = 1;
1190  }
1191 
1192  /* is silence only if every channel is silent */
1193  for (channel_num = 0; channel_num < codec_impl->number_of_channels && is_silence; channel_num++) {
1194  uint32_t count = 0, j = channel_num;
1195  double energy = 0;
1196  for (count = 0; count < samples; count++) {
1197  energy += abs(fdata[j]);
1198  j += codec_impl->number_of_channels;
1199  }
1200  is_silence &= (uint32_t) ((energy / (samples / divisor)) < silence_threshold);
1201  }
1202 
1203  return is_silence;
1204 }
1205 
1207 {
1209  if (rh->variables) {
1210  for (hi = rh->variables->headers; hi; hi = hi->next) {
1211  char buf[1024];
1212  char *vvar = NULL, *vval = NULL;
1213 
1214  vvar = (char *) hi->name;
1215  vval = (char *) hi->value;
1216 
1217  switch_assert(vvar && vval);
1218  switch_snprintf(buf, sizeof(buf), "Recording-Variable-%s", vvar);
1220  }
1221  }
1222 }
1223 
1225 {
1226  switch_event_t *event;
1227 
1228  if (rh->fh) {
1229  switch_channel_set_variable_printf(channel, "record_samples", "%d", rh->fh->samples_out);
1230  if (read_impl->actual_samples_per_second) {
1231  switch_channel_set_variable_printf(channel, "record_seconds", "%d", rh->fh->samples_out / read_impl->actual_samples_per_second);
1232  switch_channel_set_variable_printf(channel, "record_ms", "%d", rh->fh->samples_out / (read_impl->actual_samples_per_second / 1000));
1233  }
1234  }
1235 
1236  if (!zstr(rh->completion_cause)) {
1237  switch_channel_set_variable_printf(channel, "record_completion_cause", "%s", rh->completion_cause);
1238  }
1239 
1241  switch_channel_event_set_data(channel, event);
1242  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-File-Path", rh->file);
1243  merge_recording_variables(rh, event);
1244  if (!zstr(rh->completion_cause)) {
1245  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-Completion-Cause", rh->completion_cause);
1246  }
1247  switch_event_fire(&event);
1248  }
1249 
1250  if (rh->start_event_sent) {
1251  if (rh->variables) {
1252  const char *exec_app = NULL;
1253  exec_app = switch_event_get_header(rh->variables, "execute_on_record_stop");
1254  if (exec_app) {
1255  switch_channel_execute_on_value(channel, exec_app);
1256  }
1257  }
1258  switch_channel_execute_on(channel, "execute_on_record_stop");
1259  switch_channel_api_on(channel, "api_on_record_stop");
1260  }
1261 
1262  rh->start_event_sent = 0;
1263 }
1264 
1266 {
1267  switch_media_bug_t *bug = (switch_media_bug_t *) obj;
1270  struct record_helper *rh;
1271  switch_size_t bsize = SWITCH_RECOMMENDED_BUFFER_SIZE, samples = 0, inuse = 0;
1272  unsigned char *data;
1273  int channels = 1;
1275 
1277  return NULL;
1278  }
1279 
1282  rh->thread_ready = 1;
1283 
1286 
1288 
1289  while(switch_test_flag(rh->fh, SWITCH_FILE_OPEN)) {
1290  if (rh->thread_needs_transfer) {
1291  assert(session != rh->recording_session);
1292 
1294  /* Wait until recording is reverted to the original session */
1296  continue;
1297  }
1298 
1300  session = rh->recording_session;
1301  channel = switch_core_session_get_channel(session);
1302  bug = rh->bug;
1304 
1305  /* Tell record_callback that we transferred */
1306  rh->thread_needs_transfer = 0;
1307 
1308  /* Erasing the obj variable for safety because we transferred (we are under another bug) */
1309  obj = NULL;
1310  }
1311 
1313  switch_core_session_get_read_impl(session, &read_impl);
1315  bsize = read_impl.decoded_bytes_per_packet;
1316  }
1317  }
1318 
1320  inuse = switch_buffer_inuse(rh->thread_buffer);
1321 
1322  if ((!rh->thread_ready || switch_channel_down_nosig(channel)) && !inuse) {
1324  break;
1325  }
1326 
1327  if (!inuse) {
1329  if (rh->thread_ready) {
1331  }
1332  continue;
1333  }
1334 
1335  samples = switch_buffer_read(rh->thread_buffer, data, bsize) / 2 / channels;
1337 
1338  if (switch_core_file_write(rh->fh, data, &samples) != SWITCH_STATUS_SUCCESS) {
1339  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error writing %s\n", rh->file);
1340  /* File write failed */
1341  set_completion_cause(rh, "uri-failure");
1342  if (rh->hangup_on_error) {
1345  }
1346  }
1347  }
1348 
1350 
1352 
1353  return NULL;
1354 }
1355 
1357 {
1359  const char *var = NULL;
1360  const char *post_process_exec = NULL;
1362  switch_channel_execute_on_value(channel, post_process_exec);
1363  }
1365 
1367  char *cmd = switch_core_session_strdup(session, var);
1368  char *data, *expanded = NULL;
1369  switch_stream_handle_t stream = { 0 };
1370 
1371  SWITCH_STANDARD_STREAM(stream);
1372 
1373  if ((data = strchr(cmd, ':'))) {
1374  *data++ = '\0';
1375  expanded = switch_channel_expand_variables(channel, data);
1376  }
1377 
1378  switch_api_execute(cmd, expanded, session, &stream);
1379 
1380  if (expanded && expanded != data) {
1381  free(expanded);
1382  }
1383 
1384  switch_safe_free(stream.data);
1385 
1386  }
1387 
1388 }
1389 
1391 {
1394  struct record_helper *rh = (struct record_helper *) user_data;
1395  switch_event_t *event;
1396  switch_frame_t *nframe;
1397  switch_size_t len = 0;
1398  int mask = switch_core_media_bug_test_flag(bug, SMBF_MASK);
1399  unsigned char null_data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
1400 
1401  /* Check if the recording was transferred (see recording_follow_transfer) */
1402  if (rh->recording_session != session) {
1403  return SWITCH_FALSE;
1404  }
1405 
1406  switch (type) {
1407  case SWITCH_ABC_TYPE_INIT:
1408  {
1409  const char *var = get_recording_var(channel, rh->variables, "RECORD_USE_THREAD");
1410 
1412 
1413  /* Check if recording is transferred from another session */
1415 
1416  /* If there is a thread, we need to re-initiate it */
1417  if (rh->thread_ready) {
1418  switch_media_bug_t *oldbug = rh->bug;
1419  int sanity = 200;
1420 
1421  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Re-initiating recording thread for file %s\n", rh->file);
1422 
1423  rh->bug = bug;
1424  rh->thread_needs_transfer = 1;
1425 
1429 
1430  while (--sanity > 0 && rh->thread_needs_transfer) {
1431  switch_yield(10000);
1432  }
1433 
1434  /* Check if the thread reacted on the transfer */
1435  if (rh->thread_needs_transfer) {
1436  /* Thread did not react, assuming it is cond_wait'ing */
1437  rh->bug = oldbug;
1439  rh->thread_needs_transfer = 0;
1440 
1441  return SWITCH_FALSE;
1442  }
1443  }
1444 
1445  if (rh->fh) {
1446  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Record session sample rate: %d -> %d\n", rh->fh->native_rate, rh->fh->samplerate);
1450  }
1451  }
1452 
1453  rh->transfer_from_session = NULL;
1454  rh->transfer_complete = 1;
1455 
1456  break;
1457  }
1458 
1459  /* Required for potential record_transfer */
1460  rh->bug = bug;
1461 
1462  if (!rh->native && rh->fh && (zstr(var) || switch_true(var))) {
1463  switch_threadattr_t *thd_attr = NULL;
1464  int sanity = 200;
1465 
1469  switch_threadattr_create(&thd_attr, rh->helper_pool);
1472  switch_thread_create(&rh->thread, thd_attr, recording_thread, bug, rh->helper_pool);
1473 
1474  while(--sanity > 0 && !rh->thread_ready) {
1475  switch_yield(10000);
1476  }
1477  }
1478 
1479  if(rh->start_event_sent == 0) {
1480  rh->start_event_sent = 1;
1482  switch_channel_event_set_data(channel, event);
1483  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-File-Path", rh->file);
1484  merge_recording_variables(rh, event);
1485  switch_event_fire(&event);
1486  }
1487  if (rh->variables) {
1488  const char *exec_app = NULL;
1489  exec_app = switch_event_get_header(rh->variables, "execute_on_record_start");
1490  if (exec_app) {
1491  switch_channel_execute_on_value(channel, exec_app);
1492  }
1493  }
1494  switch_channel_execute_on(channel, "execute_on_record_start");
1495  switch_channel_api_on(channel, "api_on_record_start");
1496  }
1497 
1501  rh->completion_cause = NULL;
1502 
1503  if (rh->fh) {
1504  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Record session sample rate: %d -> %d\n", rh->fh->native_rate, rh->fh->samplerate);
1510  }
1511  }
1512  }
1513  break;
1515  {
1517  switch_time_t diff;
1518 
1519  rh->rready = 1;
1520 
1522  len = nframe->datalen;
1523 
1524  if (!rh->wready) {
1525  unsigned char fill_data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
1526  switch_size_t fill_len = len;
1527 
1528  switch_core_gen_encoded_silence(fill_data, &rh->read_impl, len);
1529  switch_core_file_write(&rh->out_fh, fill_data, &fill_len);
1530  }
1531 
1532 
1533  if (rh->last_read_time && rh->last_read_time < now) {
1534  diff = (now - rh->last_read_time) / rh->read_impl.microseconds_per_packet;
1535 
1536  if (diff > 3) {
1537  unsigned char fill_data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
1538  switch_core_gen_encoded_silence(fill_data, &rh->read_impl, len);
1539 
1540  while(diff > 1) {
1541  switch_size_t fill_len = len;
1542  switch_core_file_write(&rh->in_fh, fill_data, &fill_len);
1543  diff--;
1544  }
1545  }
1546  }
1547 
1548  switch_core_file_write(&rh->in_fh, mask ? null_data : nframe->data, &len);
1549  rh->last_read_time = now;
1550  rh->writes++;
1551  }
1552  break;
1554  {
1556  switch_time_t diff;
1557  rh->wready = 1;
1558 
1560  len = nframe->datalen;
1561 
1562  if (!rh->rready) {
1563  unsigned char fill_data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
1564  switch_size_t fill_len = len;
1565  switch_core_gen_encoded_silence(fill_data, &rh->read_impl, len);
1566  switch_core_file_write(&rh->in_fh, fill_data, &fill_len);
1567  }
1568 
1569 
1570 
1571 
1572  if (rh->last_write_time && rh->last_write_time < now) {
1573  diff = (now - rh->last_write_time) / rh->read_impl.microseconds_per_packet;
1574 
1575  if (diff > 3) {
1576  unsigned char fill_data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
1577  switch_core_gen_encoded_silence(fill_data, &rh->read_impl, len);
1578 
1579  while(diff > 1) {
1580  switch_size_t fill_len = len;
1581  switch_core_file_write(&rh->out_fh, fill_data, &fill_len);
1582  diff--;
1583  }
1584  }
1585  }
1586 
1587  switch_core_file_write(&rh->out_fh, mask ? null_data : nframe->data, &len);
1588  rh->last_write_time = now;
1589  rh->writes++;
1590  }
1591  break;
1592  case SWITCH_ABC_TYPE_CLOSE:
1593  {
1595  switch_core_session_get_read_impl(session, &read_impl);
1596 
1597  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Stop recording file %s\n", rh->file);
1598  switch_channel_set_private(channel, rh->file, NULL);
1599 
1600  if (rh->native) {
1603  } else if (rh->fh) {
1604  switch_size_t len;
1605  uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE];
1606  switch_frame_t frame = { 0 };
1607  const char *file_trimmed_ms = NULL;
1608  const char *file_size = NULL;
1609  const char *file_trimmed = NULL;
1610 
1611  if (rh->thread_ready) {
1612  switch_status_t st;
1613 
1614  rh->thread_ready = 0;
1615 
1619 
1620  switch_thread_join(&st, rh->thread);
1621  }
1622 
1623  if (rh->thread_buffer) {
1625  }
1626 
1627  frame.data = data;
1629 
1631  len = (switch_size_t) frame.datalen / 2;
1632 
1633  if (len && switch_core_file_write(rh->fh, mask ? null_data : data, &len) != SWITCH_STATUS_SUCCESS) {
1634  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error writing %s\n", rh->file);
1635  /* File write failed */
1636  set_completion_cause(rh, "uri-failure");
1637  if (rh->hangup_on_error) {
1640  }
1641  send_record_stop_event(channel, &read_impl, rh);
1642  record_helper_destroy(&rh, session);
1643 
1644  return SWITCH_FALSE;
1645  }
1646  }
1647 
1648 
1649  //if (switch_core_file_has_video(rh->fh, SWITCH_TRUE)) {
1650  //switch_core_media_set_video_file(session, NULL, SWITCH_RW_READ);
1651  //switch_channel_clear_flag_recursive(session->channel, CF_VIDEO_DECODED_READ);
1652  //}
1653 
1654 
1659  if (file_trimmed_ms) switch_channel_set_variable(channel, "record_trimmed_ms", file_trimmed_ms);
1660  if (file_size) switch_channel_set_variable(channel, "record_file_size", file_size);
1661  if (file_trimmed) switch_channel_set_variable(channel, "record_trimmed", file_trimmed);
1663 
1664  if (!rh->writes && !rh->vwrites && !switch_test_flag(rh->fh, SWITCH_FILE_WRITE_APPEND)) {
1665  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Discarding empty file %s\n", rh->file);
1666  switch_channel_set_variable(channel, "RECORD_DISCARDED", "true");
1668  set_completion_cause(rh, "empty-file");
1669  } else if ((rh->fh->samples_out < rh->fh->samplerate * rh->min_sec) && !switch_test_flag(rh->fh, SWITCH_FILE_WRITE_APPEND)) {
1670  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Discarding short file %s\n", rh->file);
1671  switch_channel_set_variable(channel, "RECORD_DISCARDED", "true");
1673  set_completion_cause(rh, "input-too-short");
1674  } else {
1675 
1676  if (switch_channel_down_nosig(channel)) {
1677  /* We got hung up */
1678  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Channel is hung up\n");
1679  if (rh->speech_detected) {
1680  /* Treat it as equivalent with final-silence */
1681  set_completion_cause(rh, "success-silence");
1682  } else {
1683  /* Treat it as equivalent with inital-silence timeout */
1684  set_completion_cause(rh, "no-input-timeout");
1685  }
1686  } else {
1687  /* Set the completion_cause to maxtime reached, unless it's already set */
1688  set_completion_cause(rh, "success-maxtime");
1689  }
1690  }
1691  }
1692 
1693  send_record_stop_event(channel, &read_impl, rh);
1694  record_helper_post_process(rh, session);
1695  record_helper_destroy(&rh, session);
1696  }
1697 
1698  break;
1700 
1701  if (rh->fh) {
1702  switch_size_t len;
1703  uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE];
1704  switch_frame_t frame = { 0 };
1705  switch_status_t status;
1706  int i = 0;
1707 
1708  frame.data = data;
1710 
1711  for (;;) {
1712  status = switch_core_media_bug_read(bug, &frame, i++ == 0 ? SWITCH_FALSE : SWITCH_TRUE);
1713 
1714  if (status != SWITCH_STATUS_SUCCESS || !frame.datalen) {
1715  break;
1716  } else {
1717  len = (switch_size_t) frame.datalen / 2 / frame.channels;
1718 
1719  if (rh->thread_buffer) {
1721  switch_buffer_write(rh->thread_buffer, mask ? null_data : data, frame.datalen);
1726  }
1727  } else if (switch_core_file_write(rh->fh, mask ? null_data : data, &len) != SWITCH_STATUS_SUCCESS) {
1728  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error writing %s\n", rh->file);
1729  /* File write failed */
1730  set_completion_cause(rh, "uri-failure");
1731  if (rh->hangup_on_error) {
1733  switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
1734  }
1735  return SWITCH_FALSE;
1736  }
1737 
1738  rh->writes++;
1739 
1740  /* check for silence timeout */
1741  if (rh->silence_threshold) {
1743  switch_core_session_get_read_impl(session, &read_impl);
1744  if (is_silence_frame(&frame, rh->silence_threshold, &read_impl)) {
1745  if (!rh->silence_time) {
1746  /* start of silence */
1747  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Start of silence detected\n");
1749  } else {
1750  /* continuing silence */
1751  int duration_ms = (int)((switch_micro_time_now() - rh->silence_time) / 1000);
1752  if (rh->silence_timeout_ms > 0 && duration_ms >= rh->silence_timeout_ms) {
1753  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);
1755  if (rh->speech_detected) {
1756  /* Reached final silence timeout */
1757  set_completion_cause(rh, "success-silence");
1758  } else {
1759  /* Reached initial silence timeout */
1760  set_completion_cause(rh, "no-input-timeout");
1761  /* Discard the silent file? */
1762  }
1763  }
1764  }
1765  } else { /* not silence */
1766  if (rh->silence_time) {
1767  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Start of speech detected\n");
1769  /* end of silence */
1770  rh->silence_time = 0;
1771  /* switch from initial timeout to final timeout */
1773  }
1774  }
1775  } else {
1776  /* no silence detection */
1777  if (!rh->speech_detected) {
1778  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No silence detection configured; assuming start of speech\n");
1780  }
1781  }
1782  }
1783  }
1784  }
1785  break;
1788  if (rh->fh && switch_test_flag(rh->fh, SWITCH_FILE_OPEN)) {
1789  if (!bug->video_ping_frame) break;
1790 
1792  rh->hangup_on_error) {
1793  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error writing video to %s\n", rh->file);
1796  return SWITCH_FALSE;
1797  }
1798  rh->vwrites++;
1799  }
1800  break;
1801 
1802  case SWITCH_ABC_TYPE_WRITE:
1803  default:
1804  break;
1805  }
1806 
1807  return SWITCH_TRUE;
1808 }
1809 
1810 
1812 {
1813 
1814  switch (type) {
1816  {
1817  const char *text = switch_core_media_bug_get_text(bug);
1818 
1819 
1820  if (!zstr(text)) {
1821  switch_event_t *event = NULL;
1823  //switch_channel_t *channel = switch_core_session_get_channel(session);
1824 
1826  switch_event_add_body(event, text, SWITCH_VA_NONE);
1827 
1828  if (switch_true(switch_core_get_variable("fire_text_events"))) {
1829  switch_event_t *clone = NULL;
1830 
1831  switch_event_dup(&clone, event);
1832  switch_event_fire(&clone);
1833  }
1834 
1835  switch_core_session_queue_event(session, &event);
1836  }
1837  }
1838  }
1839  break;
1840  default:
1841  break;
1842  }
1843 
1844  return SWITCH_TRUE;
1845 }
1846 
1848 {
1851 
1852  bug = (switch_media_bug_t *) switch_channel_get_private(channel, "capture_text");
1853 
1854  if (on) {
1855 
1856  if (bug) {
1857  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "text bug already attached\n");
1858  return SWITCH_STATUS_FALSE;
1859  }
1860 
1861 
1862  if (switch_core_media_bug_add(session, "capture_text", switch_core_session_get_uuid(session),
1863  text_callback, NULL, 0,
1865  &bug) != SWITCH_STATUS_SUCCESS) {
1866  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot attach bug\n");
1867  return SWITCH_STATUS_FALSE;
1868  }
1869 
1870  switch_channel_set_private(channel, "capture_text", bug);
1871  return SWITCH_STATUS_SUCCESS;
1872 
1873  } else {
1874 
1875  if (bug) {
1876  switch_channel_set_private(channel, "capture_text", NULL);
1877  switch_core_media_bug_remove(session, &bug);
1878  return SWITCH_STATUS_SUCCESS;
1879  } else {
1880  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "text bug not attached\n");
1881  return SWITCH_STATUS_FALSE;
1882  }
1883 
1884  }
1885 }
1886 
1887 
1889 {
1892 
1893  if ((bug = switch_channel_get_private(channel, file))) {
1894  if (on) {
1896  } else {
1898  }
1899  return SWITCH_STATUS_SUCCESS;
1900  }
1901  return SWITCH_STATUS_FALSE;
1902 }
1903 
1905 {
1908 
1909  if ((bug = switch_channel_get_private(channel, file))) {
1910  if (on) {
1912  } else {
1914  }
1915  return SWITCH_STATUS_SUCCESS;
1916  }
1917  return SWITCH_STATUS_FALSE;
1918 }
1919 
1921 {
1924 
1925  if (!strcasecmp(file, "all")) {
1927  } else if ((bug = switch_channel_get_private(channel, file))) {
1928  switch_core_media_bug_remove(session, &bug);
1929  return SWITCH_STATUS_SUCCESS;
1930  }
1931  return SWITCH_STATUS_FALSE;
1932 }
1933 
1935 {
1936  struct record_helper *rh = (struct record_helper *) user_data;
1937 
1938  if (!rh->transfer_complete && session == rh->transfer_from_session) {
1939  /* Transfer failed and now we are called to put the original session back */
1941  rh->transfer_from_session = NULL;
1942  } else {
1944  rh->recording_session = session;
1945  rh->transfer_complete = 0;
1946  }
1947 
1948  return rh;
1949 }
1950 
1952 {
1953  const char *var = NULL;
1954  switch_channel_t *orig_channel = switch_core_session_get_channel(orig_session);
1955  switch_channel_t *new_channel = switch_core_session_get_channel(new_session);
1956 
1959  }
1961 
1963 }
1964 
1973  uint32_t flags;
1976  int errs;
1980 };
1981 
1982 
1984 {
1985  switch_media_bug_t *bug = (switch_media_bug_t *) user_data;
1986 
1987  if (frame->img) {
1990  }
1991 
1994  }
1995  }
1996 
1997  return SWITCH_STATUS_SUCCESS;
1998 }
1999 
2001 {
2002  struct eavesdrop_pvt *ep = (struct eavesdrop_pvt *) user_data;
2004  switch_frame_t frame = { 0 };
2007  int show_spy = 0;
2008  switch_frame_t *nframe = NULL;
2009 
2010  frame.data = data;
2012 
2014 
2015  if (show_spy) {
2016  if (!ep->set_decoded_read) {
2017  ep->set_decoded_read = 1;
2020  }
2021  } else {
2022  if (ep->set_decoded_read) {
2023  ep->set_decoded_read = 0;
2026  }
2027  }
2028 
2029  switch (type) {
2030  case SWITCH_ABC_TYPE_INIT:
2031 
2037  }
2038  break;
2039  case SWITCH_ABC_TYPE_CLOSE:
2040  if (ep->set_decoded_read) {
2042  }
2043 
2048  }
2049 
2051 
2052  break;
2055  break;
2058  break;
2059  case SWITCH_ABC_TYPE_WRITE:
2060  break;
2062  if (ep->buffer) {
2065  switch_buffer_zwrite(ep->buffer, frame.data, frame.datalen);
2067  }
2068  }
2069  break;
2070  case SWITCH_ABC_TYPE_READ:
2071  break;
2072 
2074  {
2075 
2076  if (switch_test_flag(ep, ED_MUX_READ)) {
2078 
2079  if (switch_buffer_inuse(ep->r_buffer) >= rframe->datalen) {
2080  uint32_t bytes;
2081  int channels = rframe->channels ? rframe->channels : 1;
2082 
2084  bytes = (uint32_t) switch_buffer_read(ep->r_buffer, ep->data, rframe->datalen);
2085 
2086  rframe->datalen = switch_merge_sln(rframe->data, rframe->samples, (int16_t *) ep->data, bytes / 2, channels) * 2 * channels;
2087  rframe->samples = rframe->datalen / 2;
2088 
2089  ep->demux_frame.data = ep->data;
2090  ep->demux_frame.datalen = bytes;
2091  ep->demux_frame.samples = bytes / 2;
2092  ep->demux_frame.channels = rframe->channels;
2093 
2097  }
2098  }
2099 
2100  }
2101  break;
2102 
2104  {
2105  if (switch_test_flag(ep, ED_MUX_WRITE)) {
2107 
2108  if (switch_buffer_inuse(ep->w_buffer) >= rframe->datalen) {
2109  uint32_t bytes;
2110  int channels = rframe->channels ? rframe->channels : 1;
2111 
2113  bytes = (uint32_t) switch_buffer_read(ep->w_buffer, data, rframe->datalen);
2114 
2115  rframe->datalen = switch_merge_sln(rframe->data, rframe->samples, (int16_t *) data, bytes / 2, channels) * 2 * channels;
2116  rframe->samples = rframe->datalen / 2;
2117 
2120  }
2121  }
2122  }
2123  break;
2124 
2127  {
2128 
2129  if (!bug->video_ping_frame || !bug->video_ping_frame->img) {
2130  break;
2131  }
2132 
2136  ep->errs++;
2137 
2138  if (ep->errs > 10) {
2142  return SWITCH_FALSE;
2143  }
2144  } else {
2145  ep->errs = 0;
2146  }
2148  }
2149  }
2150  break;
2151  default:
2152  break;
2153  }
2154 
2155  if (nframe) {
2156  switch_frame_t frame = *nframe;
2157  uint8_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE] = "";
2158 
2159  frame.data = buf;
2160  frame.codec = nframe->codec;
2161 
2162  memcpy(frame.data, nframe->data, nframe->datalen);
2163 
2165  return SWITCH_FALSE;
2166  }
2167  }
2168 
2169  return SWITCH_TRUE;
2170 }
2171 
2173 {
2174  switch_media_bug_t *bug;
2176 
2177  if (switch_core_media_bug_pop(session, "eavesdrop", &bug) == SWITCH_STATUS_SUCCESS) {
2179 
2180  if (ep && ep->eavesdropper && ep->eavesdropper != session) {
2182  *sessionp = ep->eavesdropper;
2184  status = SWITCH_STATUS_SUCCESS;
2185  }
2186  }
2187  }
2188 
2189 
2190  return status;
2191 }
2192 
2195  char *var;
2196  char *val;
2197 };
2198 
2199 static void exec_cb(switch_media_bug_t *bug, void *user_data)
2200 {
2201  struct exec_cb_data *data = (struct exec_cb_data *) user_data;
2203 
2204  if (ep && ep->eavesdropper && ep->eavesdropper != data->caller) {
2207 
2208  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s telling %s to exec %s:%s\n",
2210 
2212  }
2213 }
2214 
2216 {
2217  struct exec_cb_data *data = (struct exec_cb_data *) user_data;
2219 
2220  if (ep && ep->eavesdropper && ep->eavesdropper != data->caller) {
2221  switch_core_session_message_t msg = { 0 };
2222 
2223  msg.from = __FILE__;
2225  msg.string_array_arg[0] = data->var;
2226  msg.string_array_arg[1] = data->val;
2227 
2229  }
2230 }
2231 
2233 {
2234  struct exec_cb_data *data = NULL;
2235 
2236  data = switch_core_session_alloc(session, sizeof(*data));
2237  data->var = switch_core_session_strdup(session, app);
2238  data->val = switch_core_session_strdup(session, arg);
2239  data->caller = session;
2240 
2241  return switch_core_media_bug_exec_all(session, "eavesdrop", exec_cb, data);
2242 }
2243 
2244 
2246 {
2247  struct exec_cb_data *data = NULL;
2250 
2251  data = switch_core_session_alloc(session, sizeof(*data));
2252  data->var = switch_core_session_strdup(session, name);
2253  data->val = switch_core_session_strdup(session, number);
2254  data->caller = session;
2255 
2256  if (!switch_channel_test_app_flag_key("EAVESDROP", channel, 1)) {
2257  switch_channel_set_app_flag_key("EAVESDROP", channel, 1);
2258  status = switch_core_media_bug_exec_all(session, "eavesdrop", display_exec_cb, data);
2259  switch_channel_clear_app_flag_key("EAVESDROP", channel, 1);
2260  }
2261 
2262  return status;
2263 }
2264 
2265 /*Greatest Common Divisor*/
2266 static uint32_t switch_gcd(uint32_t x, uint32_t y)
2267 {
2268  if (y == 0) {
2269  return x;
2270  }
2271 
2272  return switch_gcd(y, x % y);
2273 }
2274 
2275 /*Least Common Multiple*/
2276 static uint32_t switch_lcm(uint32_t x, uint32_t y)
2277 {
2278  uint32_t gcd = switch_gcd(x, y);
2279 
2280  if (gcd) return (x * y) / gcd;
2281 
2282  return 0;
2283 }
2284 
2286  const char *uuid, const char *require_group, switch_eavesdrop_flag_t flags)
2287 {
2288  switch_core_session_t *tsession;
2291  int codec_initialized = 0;
2292  const char *name, *num;
2293 
2294  if ((tsession = switch_core_session_locate(uuid))) {
2295  struct eavesdrop_pvt *ep = NULL;
2296  switch_media_bug_t *bug = NULL;
2297  switch_channel_t *tchannel = switch_core_session_get_channel(tsession);
2298  switch_frame_t *read_frame, write_frame = { 0 };
2299  switch_codec_t codec = { 0 };
2300  int16_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE / 2];
2301  uint32_t tlen;
2302  const char *macro_name = "eavesdrop_announce";
2303  const char *id_name = NULL;
2305  switch_core_session_message_t msg = { 0 };
2306  char cid_buf[1024] = "";
2307  switch_caller_profile_t *cp = NULL;
2308  uint32_t sanity = 600;
2309  switch_media_bug_flag_t read_flags = 0, write_flags = 0, stereo_flag = 0;
2310  const char *vval;
2311  int buf_size = 0;
2312  int channels;
2313  int lcm, buff_min_len, buffered = 1;
2314 
2315  if (!switch_channel_media_up(channel)) {
2316  goto end;
2317  }
2318 
2319  if (tsession == session) {
2320  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Eavesdrop target invalid.\n");
2321  goto end;
2322  }
2323 
2324  while(switch_channel_state_change_pending(tchannel) || !switch_channel_media_up(tchannel)) {
2325  switch_yield(10000);
2326  if (!--sanity) break;
2327  }
2328 
2329  if (!switch_channel_media_up(tchannel)) {
2330  goto end;
2331  }
2332 
2333  if ((flags & ED_TAP_READ) || (flags & ED_TAP_WRITE)) {
2334  switch_core_session_get_real_read_impl(tsession, &tread_impl);
2336 
2337  if (strcasecmp(tread_impl.iananame, read_impl.iananame)) {
2338  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codecs do not match which is required for this mode\n");
2339  goto end;
2340  }
2341  }
2342 
2343  switch_core_session_get_read_impl(tsession, &tread_impl);
2345 
2346  if ((id_name = switch_channel_get_variable(tchannel, "eavesdrop_announce_id"))) {
2347  const char *tmp = switch_channel_get_variable(tchannel, "eavesdrop_announce_macro");
2348  if (tmp) {
2349  macro_name = tmp;
2350  }
2351 
2352  switch_ivr_phrase_macro(session, macro_name, id_name, NULL, NULL);
2353  }
2354 
2355 
2356  if (!zstr(require_group)) {
2357  int argc, i;
2358  int ok = 0;
2359  char *argv[10] = { 0 };
2360  char *data;
2361 
2362  const char *group_name = switch_channel_get_variable(tchannel, "eavesdrop_group");
2363  /* If we don't have a group, then return */
2364  if (!group_name) {
2366  }
2367  /* Separate the group */
2368  data = strdup(group_name);
2369  if ((argc = switch_separate_string(data, ',', argv, (sizeof(argv) / sizeof(argv[0]))))) {
2370  for (i = 0; i < argc; i++) {
2371  /* If one of the group matches, then ok */
2372  if (argv[i] && !strcmp(argv[i], require_group)) {
2373  ok = 1;
2374  }
2375  }
2376  }
2377  switch_safe_free(data);
2378  /* If we didn't find any match, then end */
2379  if (!ok) {
2381  }
2382  }
2383 
2384 
2385  ep = switch_core_session_alloc(session, sizeof(*ep));
2386 
2387 
2389  goto end;
2390  }
2391 
2393  if (switch_core_codec_init(&codec,
2394  "L16",
2395  NULL,
2396  NULL,
2402  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
2403  goto end;
2404  }
2405  } else {
2406  if (switch_core_codec_init(&codec,
2407  "L16",
2408  NULL,
2409  NULL,
2410  tread_impl.actual_samples_per_second,
2411  tread_impl.microseconds_per_packet / 1000,
2412  tread_impl.number_of_channels,
2415  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
2416  goto end;
2417  }
2418  buffered = 0;
2419  }
2420 
2421  ep->read_impl = read_impl;
2422  ep->tread_impl = tread_impl;
2423 
2424  codec_initialized = 1;
2425 
2426  switch_core_session_set_read_codec(session, &codec);
2427  write_frame.codec = &codec;
2428  write_frame.data = buf;
2429  write_frame.buflen = sizeof(buf);
2430  write_frame.rate = codec.implementation->actual_samples_per_second;
2431 
2432  /* Make sure that at least one leg is bridged, default to both */
2433  if (! (flags & (ED_BRIDGE_READ | ED_BRIDGE_WRITE))) {
2434  flags |= ED_BRIDGE_READ | ED_BRIDGE_WRITE;
2435  }
2436 
2437  buf_size = codec.implementation->decoded_bytes_per_packet * 10;
2438 
2439  ep->eavesdropper = session;
2440  ep->flags = flags;
2441 
2442  if (!(flags & ED_TAP_READ) && !(flags & ED_TAP_WRITE)) {
2444  switch_buffer_create_dynamic(&ep->buffer, buf_size, buf_size, buf_size);
2446 
2448  switch_buffer_create_dynamic(&ep->w_buffer, buf_size, buf_size, buf_size);
2450 
2452  switch_buffer_create_dynamic(&ep->r_buffer, buf_size, buf_size, buf_size);
2454  }
2455 
2456  if (flags & ED_BRIDGE_READ) {
2457  read_flags = SMBF_READ_STREAM | SMBF_READ_REPLACE;
2458  }
2459 
2460  if (flags & ED_BRIDGE_WRITE) {
2461  write_flags = SMBF_WRITE_STREAM | SMBF_WRITE_REPLACE;
2462  }
2463 
2464  if (flags & ED_TAP_READ) {
2465  read_flags = SMBF_TAP_NATIVE_READ;
2466  write_flags = 0;
2467  }
2468 
2469  if (flags & ED_TAP_WRITE) {
2470  write_flags = SMBF_TAP_NATIVE_WRITE;
2471  read_flags = 0;
2472  }
2473 
2474  if (flags & ED_STEREO) {
2475  stereo_flag = SMBF_STEREO;
2476  }
2477 
2479  if ((vval = switch_channel_get_variable(session->channel, "eavesdrop_show_listener_video"))) {
2480  if (switch_true(vval) || !strcasecmp(vval, "aleg") || !strcasecmp(vval, "bleg") || !strcasecmp(vval, "both")) {
2481  read_flags |= SMBF_SPY_VIDEO_STREAM;
2482  }
2483  if (switch_true(vval) || !strcasecmp(vval, "bleg") || !strcasecmp(vval, "both")) {
2484  read_flags |= SMBF_SPY_VIDEO_STREAM_BLEG;
2485  }
2486  }
2487 
2488  if ((vval = switch_channel_get_variable(session->channel, "eavesdrop_concat_video")) && switch_true(vval)) {
2489  read_flags |= SMBF_READ_VIDEO_STREAM;
2490  read_flags |= SMBF_WRITE_VIDEO_STREAM;
2491  } else {
2492  read_flags |= SMBF_READ_VIDEO_PING;
2493  }
2494  } else {
2495  read_flags &= ~SMBF_READ_VIDEO_PING;
2496  read_flags &= ~SMBF_READ_VIDEO_STREAM;
2497  read_flags &= ~SMBF_WRITE_VIDEO_STREAM;
2498  read_flags &= ~SMBF_SPY_VIDEO_STREAM;
2499  read_flags &= ~SMBF_SPY_VIDEO_STREAM_BLEG;
2500  }
2501 
2502 
2503  if (switch_core_media_bug_add(tsession, "eavesdrop", uuid,
2504  eavesdrop_callback, ep, 0,
2505  read_flags | write_flags | SMBF_READ_PING | SMBF_THREAD_LOCK | SMBF_NO_PAUSE | stereo_flag,
2506  &bug) != SWITCH_STATUS_SUCCESS) {
2507  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot attach bug\n");
2508  goto end;
2509  }
2510 
2511  if ((vval = switch_channel_get_variable(session->channel, "eavesdrop_video_spy_fmt"))) {
2513  }
2514 
2515  msg.from = __FILE__;
2516 
2517  /* Tell the channel we are going to be in a bridge */
2519  switch_core_session_receive_message(session, &msg);
2520  cp = switch_channel_get_caller_profile(tchannel);
2521 
2522  name = cp->caller_id_name;
2523  num = cp->caller_id_number;
2524 
2525  if ((flags & ED_TAP_READ) || (flags & ED_TAP_WRITE)) {
2526  flags &= ~ED_DTMF;
2527  flags &= ~ED_BRIDGE_READ;
2528  flags &= ~ED_BRIDGE_WRITE;
2529  }
2530 
2531  if (flags & ED_COPY_DISPLAY) {
2533  name = cp->callee_id_name;
2534  num = cp->callee_id_number;
2535  } else {
2536  name = cp->caller_id_name;
2537  num = cp->caller_id_number;
2538  }
2539  }
2540 
2541  sanity = 300;
2542  while(switch_channel_up(channel) && !switch_channel_media_ack(channel) && --sanity) {
2543  switch_yield(10000);
2544  }
2545 
2546 
2547  switch_snprintf(cid_buf, sizeof(cid_buf), "%s|%s", name, num);
2548  msg.string_arg = cid_buf;
2550  switch_core_session_receive_message(session, &msg);
2551 
2552  if (switch_channel_test_flag(tchannel, CF_VIDEO)) {
2553 
2555 
2556  switch_core_session_receive_message(tsession, &msg);
2557  }
2558 
2560 
2561  while (switch_channel_up_nosig(tchannel) && switch_channel_ready(channel)) {
2562  uint32_t len = sizeof(buf);
2563  switch_event_t *event = NULL;
2564  char *fcommand = NULL;
2565  char db[2] = "";
2566  int vid_bug = 0, vid_dual = 0;
2567 
2568  status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
2569 
2570  if (!SWITCH_READ_ACCEPTABLE(status)) {
2571  goto end_loop;
2572  }
2573 
2575  char *command = switch_event_get_header(event, "eavesdrop-command");
2576  if (command) {
2577  fcommand = switch_core_session_strdup(session, command);
2578  }
2579  switch_event_destroy(&event);
2580  }
2581 
2582  if ((flags & ED_DTMF) && switch_channel_has_dtmf(channel)) {
2583  switch_dtmf_t dtmf = { 0 };
2584  switch_channel_dequeue_dtmf(channel, &dtmf);
2585  db[0] = dtmf.digit;
2586  fcommand = db;
2587  }
2588 
2591  vid_dual = 1;
2592  }
2593 
2594  if (vid_dual || switch_core_media_bug_test_flag(bug, SMBF_READ_VIDEO_PING)) {
2595  vid_bug = 1;
2596  }
2597 
2598  if (fcommand) {
2599  char *d;
2600  for (d = fcommand; *d; d++) {
2601  int z = 1;
2602 
2603  switch (*d) {
2604  case '1':
2607  if (vid_bug) {
2611  }
2612  break;
2613  case '2':
2616  if (vid_bug) {
2620  }
2621  break;
2622  case '3':
2625  if (vid_bug) {
2629  }
2630  break;
2631 
2632  case '4':
2634  break;
2635  case '5':
2637  break;
2638  case '6':
2640  break;
2641  case '0':
2644  if (vid_bug) {
2648  }
2649  break;
2650  case '*':
2651  goto end_loop;
2652  default:
2653  z = 0;
2654  break;
2655 
2656  }
2657 
2658  if (z) {
2659  if (ep->r_buffer) {
2663  }
2664 
2665  if (ep->w_buffer) {
2669  }
2670  }
2671  }
2672  }
2673 
2674  if (ep->r_buffer && ep->w_buffer && !switch_test_flag(read_frame, SFF_CNG)) {
2676  switch_buffer_zwrite(ep->r_buffer, read_frame->data, read_frame->datalen);
2678 
2680  switch_buffer_zwrite(ep->w_buffer, read_frame->data, read_frame->datalen);
2682  }
2683 
2684  channels = switch_core_media_bug_test_flag(bug, SMBF_STEREO) ? 2 : tread_impl.number_of_channels;
2685 
2686  if (channels == 0) {
2687  channels = 1;
2688  }
2689 
2690  tlen = ep->read_impl.decoded_bytes_per_packet * channels;
2691 
2692  if (len > tlen) {
2693  len = tlen;
2694  }
2695 
2696  if (buffered) {
2697  buff_min_len = lcm * 2;
2698  if (switch_buffer_inuse(ep->buffer) < buff_min_len) {
2699  continue;
2700  }
2701  } else {
2702  buff_min_len = len;
2703  }
2704 
2705  if (ep->buffer) {
2707  while (switch_buffer_inuse(ep->buffer) >= buff_min_len) {
2708  int tchanged = 0, changed = 0;
2709 
2710  write_frame.datalen = (uint32_t) switch_buffer_read(ep->buffer, buf, len);
2711  write_frame.samples = write_frame.datalen / 2 / channels;
2712  write_frame.channels = channels;
2713 
2714  switch_core_session_get_read_impl(tsession, &tread_impl);
2716 
2717  if (tread_impl.number_of_channels != ep->tread_impl.number_of_channels ||
2719  tchanged = 1;
2720  }
2721 
2724  changed = 1;
2725  }
2726 
2727  if (changed || tchanged) {
2728 
2729  if (changed) {
2731  "SPYING CHANNEL CODEC CHANGE FROM %dhz@%dc to %dhz@%dc\n",
2736 
2737  tlen = read_impl.decoded_bytes_per_packet * channels;
2738 
2739  if (len > tlen) {
2740  len = tlen;
2741  }
2742 
2743  }
2744 
2745  if (tchanged) {
2747  "SPYED CHANNEL CODEC CHANGE FROM %dhz@%dc to %dhz@%dc\n",
2750  tread_impl.actual_samples_per_second,
2751  tread_impl.number_of_channels);
2752  }
2753 
2754 
2755  switch_core_codec_destroy(&codec);
2756 
2758  if (switch_core_codec_init(&codec,
2759  "L16",
2760  NULL,
2761  NULL,
2767  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
2769  goto end;
2770  }
2771  buffered = 1;
2773  } else {
2774  if (switch_core_codec_init(&codec,
2775  "L16",
2776  NULL,
2777  NULL,
2778  tread_impl.actual_samples_per_second,
2779  tread_impl.microseconds_per_packet / 1000,
2780  tread_impl.number_of_channels,
2783  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
2785  goto end;
2786  }
2787  if (buffered == 1) {
2788  buffered = 0;
2789  }
2790  }
2791 
2792  ep->read_impl = read_impl;
2793  ep->tread_impl = tread_impl;
2794  }
2795 
2796 
2798  uint32_t rlen = write_frame.datalen / 2 / ep->tread_impl.number_of_channels;
2799 
2800  switch_mux_channels((int16_t *) write_frame.data, rlen, ep->tread_impl.number_of_channels, ep->read_impl.number_of_channels);
2801  write_frame.datalen = rlen * 2 * ep->read_impl.number_of_channels;
2802  write_frame.samples = write_frame.datalen / 2;
2803  }
2804 
2805  if ((status = switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0)) != SWITCH_STATUS_SUCCESS) {
2806  break;
2807  }
2808 
2811 
2813  /* push just the number of samples worth of a packet. */
2814  break;
2815  }
2816  }
2818  }
2819  }
2820 
2821  end_loop:
2822 
2823  /* Tell the channel we are no longer going to be in a bridge */
2825  switch_core_session_receive_message(session, &msg);
2826 
2827  status = SWITCH_STATUS_SUCCESS;
2828  end:
2829 
2830  if (codec_initialized)
2831  switch_core_codec_destroy(&codec);
2832 
2833  if (bug) {
2834  switch_core_media_bug_remove(tsession, &bug);
2835  }
2836 
2837  if (ep) {
2838  if (ep->buffer) {
2840  }
2841 
2842  if (ep->r_buffer) {
2844  }
2845 
2846  if (ep->w_buffer) {
2848  }
2849  }
2850 
2851  switch_core_session_rwunlock(tsession);
2852 
2854  }
2855 
2856  return status;
2857 }
2858 
2860 {
2861  switch_status_t status;
2863  struct record_helper *newrh;
2864 
2865  assert(rh);
2866  assert(session);
2867 
2868  if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
2869  return status;
2870  }
2871 
2872  if (!(newrh = switch_core_alloc(pool, sizeof(*newrh)))) {
2874  return SWITCH_STATUS_MEMERR;
2875  }
2876 
2877  newrh->helper_pool = pool;
2878  newrh->recording_session = session;
2879 
2880  *rh = newrh;
2881 
2882  return SWITCH_STATUS_SUCCESS;
2883 }
2884 
2886 {
2888 
2889  assert(rh);
2890  assert(*rh);
2891  assert(session);
2892 
2893  if ((*rh)->recording_session != session) {
2894  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Destroying a record helper of another session!\n");
2895  }
2896 
2897  if ((*rh)->native) {
2898  switch_core_file_close(&(*rh)->in_fh);
2899  switch_core_file_close(&(*rh)->out_fh);
2900  } else if((*rh)->fh) {
2901  switch_core_file_close((*rh)->fh);
2902  }
2903 
2904  switch_event_safe_destroy((*rh)->variables);
2905 
2906  pool = (*rh)->helper_pool;
2908  *rh = NULL;
2909 
2910  return SWITCH_STATUS_SUCCESS;
2911 }
2912 
2913 static const char *get_recording_var(switch_channel_t *channel, switch_event_t *vars, const char *name)
2914 {
2915  const char *val = NULL;
2916  if (!vars || !(val = switch_event_get_header(vars, name))) {
2917  val = switch_channel_get_variable(channel, name);
2918  }
2919  return val;
2920 }
2921 
2922 static int recording_var_true(switch_channel_t *channel, switch_event_t *vars, const char *name)
2923 {
2924  return switch_true(get_recording_var(channel, vars, name));
2925 }
2926 
2928 {
2930  const char *p;
2931  const char *vval;
2933  switch_status_t status;
2934  time_t to = 0;
2936  uint8_t channels;
2938  struct record_helper *rh = NULL;
2941  char *file_path = NULL;
2942  char *ext;
2943  char *in_file = NULL, *out_file = NULL;
2945 
2946  if ((p = get_recording_var(channel, vars, "RECORD_HANGUP_ON_ERROR"))) {
2947  hangup_on_error = switch_true(p);
2948  }
2949 
2951  return SWITCH_STATUS_FALSE;
2952  }
2953 
2954  if (!switch_channel_media_up(channel) || !switch_core_session_get_read_codec(session)) {
2955  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can not record session. Media not enabled on channel\n");
2956  return SWITCH_STATUS_FALSE;
2957  }
2958 
2959  switch_core_session_get_read_impl(session, &read_impl);
2960  channels = read_impl.number_of_channels;
2961 
2962  if ((bug = switch_channel_get_private(channel, file))) {
2963  if (recording_var_true(channel, vars, "RECORD_TOGGLE_ON_REPEAT")) {
2964  return switch_ivr_stop_record_session(session, file);
2965  }
2966 
2967  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Already recording [%s]\n", file);
2968  return SWITCH_STATUS_SUCCESS;
2969  }
2970 
2971 
2972  if (recording_var_true(channel, vars, "RECORD_CHECK_BRIDGE")) {
2973  switch_core_session_t *other_session;
2974  int exist = 0;
2976 
2977  if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
2978  switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
2979  if ((bug = switch_channel_get_private(other_channel, file))) {
2980  if (switch_true(switch_channel_get_variable(other_channel, "RECORD_TOGGLE_ON_REPEAT"))) {
2981  rstatus = switch_ivr_stop_record_session(other_session, file);
2982  } else {
2983  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(other_session), SWITCH_LOG_WARNING, "Already recording [%s]\n", file);
2984  }
2985  exist = 1;
2986  }
2987  switch_core_session_rwunlock(other_session);
2988  }
2989 
2990  if (exist) {
2991  return rstatus;
2992  }
2993  }
2994 
2995  if ((status = record_helper_create(&rh, session)) != SWITCH_STATUS_SUCCESS) {
2996  return status;
2997  }
2998 
2999  if (fh) {
3000  switch_file_handle_t *newfh;
3001 
3002  if ((status = switch_core_file_handle_dup(fh, &newfh, rh->helper_pool)) != SWITCH_STATUS_SUCCESS) {
3003  switch_goto_status(status, err);
3004  }
3005 
3006  fh = newfh;
3007  } else {
3008  if (!(fh = switch_core_alloc(rh->helper_pool, sizeof(*fh)))) {
3010  }
3011  }
3012 
3013  if (recording_var_true(channel, vars, "RECORD_WRITE_ONLY")) {
3014  flags &= ~SMBF_READ_STREAM;
3015  flags |= SMBF_WRITE_STREAM;
3016  }
3017 
3018  if (recording_var_true(channel, vars, "RECORD_READ_ONLY")) {
3019  flags &= ~SMBF_WRITE_STREAM;
3020  flags |= SMBF_READ_STREAM;
3021  }
3022 
3023  if (channels == 1) { /* if leg is already stereo this feature is not available */
3024  if (recording_var_true(channel, vars, "RECORD_STEREO")) {
3025  flags |= SMBF_STEREO;
3026  flags &= ~SMBF_STEREO_SWAP;
3027  channels = 2;
3028  }
3029 
3030  if (recording_var_true(channel, vars, "RECORD_STEREO_SWAP")) {
3031  flags |= SMBF_STEREO;
3032  flags |= SMBF_STEREO_SWAP;
3033  channels = 2;
3034  }
3035  }
3036 
3037  if (recording_var_true(channel, vars, "RECORD_ANSWER_REQ")) {
3038  flags |= SMBF_ANSWER_REQ;
3039  }
3040 
3041  if (recording_var_true(channel, vars, "RECORD_BRIDGE_REQ")) {
3042  flags |= SMBF_BRIDGE_REQ;
3043  }
3044 
3045  if (recording_var_true(channel, vars, "RECORD_APPEND")) {
3046  file_flags |= SWITCH_FILE_WRITE_APPEND;
3047  }
3048 
3049  fh->samplerate = 0;
3050  if ((vval = get_recording_var(channel, vars, "record_sample_rate"))) {
3051  int tmp = 0;
3052 
3053  tmp = atoi(vval);
3054 
3055  if (switch_is_valid_rate(tmp)) {
3056  fh->samplerate = tmp;
3057  }
3058  }
3059 
3060  if (!fh->samplerate) {
3061  fh->samplerate = read_impl.actual_samples_per_second;
3062  }
3063 
3064  fh->channels = channels;
3065 
3066  if ((vval = get_recording_var(channel, vars, "enable_file_write_buffering"))) {
3067  int tmp = atoi(vval);
3068 
3069  if (tmp > 0) {
3070  fh->pre_buffer_datalen = tmp;
3071  } else if (switch_true(vval)) {
3073  }
3074 
3075  } else {
3077  }
3078 
3079  if (!switch_is_file_path(file)) {
3080  char *tfile = NULL;
3081  char *e;
3082  const char *prefix;
3083 
3084  prefix = get_recording_var(channel, vars, "sound_prefix");
3085 
3086  if (!prefix) {
3087  prefix = SWITCH_GLOBAL_dirs.base_dir;
3088  }
3089 
3090  if (*file == '[') {
3091  tfile = switch_core_strdup(rh->helper_pool, file);
3092  if ((e = switch_find_end_paren(tfile, '[', ']'))) {
3093  *e = '\0';
3094  file = e + 1;
3095  } else {
3096  tfile = NULL;
3097  }
3098  } else {
3099  file_path = switch_core_sprintf(rh->helper_pool, "%s%s%s", prefix, SWITCH_PATH_SEPARATOR, file);
3100  }
3101 
3102  file = switch_core_sprintf(rh->helper_pool, "%s%s%s%s%s", switch_str_nil(tfile), tfile ? "]" : "", prefix, SWITCH_PATH_SEPARATOR, file);
3103  } else {
3104  file_path = switch_core_strdup(rh->helper_pool, file);
3105  }
3106 
3107  if (file_path && !strstr(file_path, SWITCH_URL_SEPARATOR)) {
3108  char *p;
3109  char *path = switch_core_strdup(rh->helper_pool, file_path);
3110 
3111  if ((p = strrchr(path, *SWITCH_PATH_SEPARATOR))) {
3112  *p = '\0';
3113 
3114  if (*path == '{') {
3115  path = switch_find_end_paren(path, '{', '}') + 1;
3116  }
3117  if ((vval = get_recording_var(channel, vars, "RECORD_DIR_PERMS"))) {
3118  fileperms = strtol(vval, 0, 16);
3119  }
3120 
3121 
3123  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error creating %s\n", path);
3124  set_completion_cause(rh, "uri-failure");
3126  }
3127 
3128  } else {
3129  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error finding the folder path section in '%s'\n", path);
3130  path = NULL;
3131  }
3132  }
3133 
3134  if ((ext = strrchr(file, '.'))) {
3135  ext++;
3136 
3137  if (switch_channel_test_flag(channel, CF_VIDEO)) {
3138  file_flags |= SWITCH_FILE_FLAG_VIDEO;
3139  }
3140 
3141  if (switch_core_file_open(fh, file, channels, read_impl.actual_samples_per_second, file_flags, NULL) != SWITCH_STATUS_SUCCESS) {
3142  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error opening %s\n", file);
3143  if (hangup_on_error) {
3146  }
3147  set_completion_cause(rh, "uri-failure");
3149  }
3150 
3151  if (fh->params) {
3152  if ((p = switch_event_get_header(fh->params,"record_write_only")) && switch_true(p)) {
3153  flags &= ~SMBF_READ_STREAM;
3154  flags |= SMBF_WRITE_STREAM;
3155  }
3156 
3157 
3158  if ((p = switch_event_get_header(fh->params, "record_read_only")) && switch_true(p)) {
3159  flags &= ~SMBF_WRITE_STREAM;
3160  flags |= SMBF_READ_STREAM;
3161  }
3162  }
3163 
3165  //switch_core_media_set_video_file(session, fh, SWITCH_RW_READ);
3166  //switch_channel_set_flag_recursive(session->channel, CF_VIDEO_DECODED_READ);
3167 
3168  if (recording_var_true(channel, vars, "record_concat_video")) {
3169  flags |= SMBF_READ_VIDEO_STREAM;
3170  flags |= SMBF_WRITE_VIDEO_STREAM;
3171  } else if (recording_var_true(channel, vars, "record_bleg_video")) {
3172  flags |= SMBF_WRITE_VIDEO_STREAM;
3173  } else {
3174  flags |= SMBF_READ_VIDEO_STREAM;
3175  }
3176  } else {
3177  flags &= ~SMBF_READ_VIDEO_PING;
3178  flags &= ~SMBF_READ_VIDEO_STREAM;
3179  flags &= ~SMBF_WRITE_VIDEO_STREAM;
3180  }
3181 
3182  } else {
3183  int tflags = 0;
3184 
3185  ext = read_impl.iananame;
3186 
3187  in_file = switch_core_sprintf(rh->helper_pool, "%s-in.%s", file, ext);
3188  out_file = switch_core_sprintf(rh->helper_pool, "%s-out.%s", file, ext);
3190  channels = 1;
3193 
3194  if (switch_core_file_open(&rh->in_fh, in_file, channels, read_impl.actual_samples_per_second, file_flags, NULL) != SWITCH_STATUS_SUCCESS) {
3195  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error opening %s\n", in_file);
3196  if (hangup_on_error) {
3199  }
3200  set_completion_cause(rh, "uri-failure");
3202  }
3203 
3204  if (switch_core_file_open(&rh->out_fh, out_file, channels, read_impl.actual_samples_per_second, file_flags, NULL) != SWITCH_STATUS_SUCCESS) {
3205  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error opening %s\n", out_file);
3207  if (hangup_on_error) {
3210  }
3211  set_completion_cause(rh, "uri-failure");
3213  }
3214 
3215  rh->native = 1;
3216  fh = NULL;
3217 
3218  if ((flags & SMBF_WRITE_STREAM)) {
3219  tflags |= SMBF_TAP_NATIVE_WRITE;
3220  }
3221 
3222  if ((flags & SMBF_READ_STREAM)) {
3223  tflags |= SMBF_TAP_NATIVE_READ;
3224  }
3225 
3226  flags = tflags;
3227  }
3228 
3229  if ((p = get_recording_var(channel, vars, "RECORD_TITLE"))) {
3230  vval = (const char *) switch_core_strdup(rh->helper_pool, p);
3232  switch_channel_set_variable(channel, "RECORD_TITLE", NULL);
3233  }
3234 
3235  if ((p = get_recording_var(channel, vars, "RECORD_COPYRIGHT"))) {
3236  vval = (const char *) switch_core_strdup(rh->helper_pool, p);
3238  switch_channel_set_variable(channel, "RECORD_COPYRIGHT", NULL);
3239  }
3240 
3241  if ((p = get_recording_var(channel, vars, "RECORD_SOFTWARE"))) {
3242  vval = (const char *) switch_core_strdup(rh->helper_pool, p);
3244  switch_channel_set_variable(channel, "RECORD_SOFTWARE", NULL);
3245  }
3246 
3247  if ((p = get_recording_var(channel, vars, "RECORD_ARTIST"))) {
3248  vval = (const char *) switch_core_strdup(rh->helper_pool, p);
3250  switch_channel_set_variable(channel, "RECORD_ARTIST", NULL);
3251  }
3252 
3253  if ((p = get_recording_var(channel, vars, "RECORD_COMMENT"))) {
3254  vval = (const char *) switch_core_strdup(rh->helper_pool, p);
3256  switch_channel_set_variable(channel, "RECORD_COMMENT", NULL);
3257  }
3258 
3259  if ((p = get_recording_var(channel, vars, "RECORD_DATE"))) {
3260  vval = (const char *) switch_core_strdup(rh->helper_pool, p);
3262  switch_channel_set_variable(channel, "RECORD_DATE", NULL);
3263  }
3264 
3265  if (limit) {
3266  to = switch_epoch_time_now(NULL) + limit;
3267  }
3268 
3269  rh->fh = fh;
3270  rh->file = switch_core_strdup(rh->helper_pool, file);
3271  rh->packet_len = read_impl.decoded_bytes_per_packet;
3272 
3273  if (file_flags & SWITCH_FILE_WRITE_APPEND) {
3274  rh->min_sec = 3;
3275  }
3276 
3277  if ((p = get_recording_var(channel, vars, "RECORD_MIN_SEC"))) {
3278  int tmp = atoi(p);
3279  if (tmp >= 0) {
3280  rh->min_sec = tmp;
3281  }
3282  }
3283 
3284  if ((p = get_recording_var(channel, vars, "RECORD_INITIAL_TIMEOUT_MS"))) {
3285  int tmp = atoi(p);
3286  if (tmp >= 0) {
3287  rh->initial_timeout_ms = tmp;
3288  rh->silence_threshold = 200;
3289  }
3290  }
3291 
3292  if ((p = get_recording_var(channel, vars, "RECORD_FINAL_TIMEOUT_MS"))) {
3293  int tmp = atoi(p);
3294  if (tmp >= 0) {
3295  rh->final_timeout_ms = tmp;
3296  rh->silence_threshold = 200;
3297  }
3298  }
3299 
3300  if ((p = get_recording_var(channel, vars, "RECORD_SILENCE_THRESHOLD"))) {
3301  int tmp = atoi(p);
3302  if (tmp >= 0) {
3303  rh->silence_threshold = tmp;
3304  }
3305  }
3306 
3307  if (vars) {
3308  switch_event_dup(&rh->variables, vars);
3309  }
3310 
3312 
3313  if ((status = switch_core_media_bug_add(session, "session_record", file,
3314  record_callback, rh, to, flags, &bug)) != SWITCH_STATUS_SUCCESS) {
3315  if (switch_channel_ready(channel)) {
3316  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error adding media bug for file %s\n", file);
3317  } else {
3318  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Error adding media bug for file %s\n", file);
3319  }
3320  switch_goto_status(status, err);
3321  }
3322 
3323  if ((p = get_recording_var(channel, vars, "RECORD_PRE_BUFFER_FRAMES"))) {
3324  int tmp = atoi(p);
3325 
3326  if (tmp > 0) {
3328  }
3329  } else {
3331  }
3332 
3333  switch_channel_set_private(channel, file, bug);
3334 
3335  if (switch_channel_test_flag(channel, CF_VIDEO)) {
3336  switch_core_session_message_t msg = { 0 };
3337 
3338  msg.from = __FILE__;
3340 
3341  switch_core_session_receive_message(session, &msg);
3342  }
3343 
3344  return SWITCH_STATUS_SUCCESS;
3345 
3346 err:
3347  if (!zstr(rh->completion_cause)) {
3348  switch_channel_set_variable_printf(channel, "record_completion_cause", "%s", rh->completion_cause);
3349  }
3350  record_helper_destroy(&rh, session);
3351 
3352  return status;
3353 }
3354 
3356 {
3357  return switch_ivr_record_session_event(session, file, limit, fh, NULL);
3358 }
3359 
3360 typedef struct {
3361  SpeexPreprocessState *read_st;
3362  SpeexPreprocessState *write_st;
3363  SpeexEchoState *read_ec;
3364  SpeexEchoState *write_ec;
3365  switch_byte_t read_data[2048];
3366  switch_byte_t write_data[2048];
3367  switch_byte_t read_out[2048];
3368  switch_byte_t write_out[2048];
3371  int done;
3372 } pp_cb_t;
3373 
3375 {
3378  pp_cb_t *cb = (pp_cb_t *) user_data;
3379  switch_codec_implementation_t read_impl = { 0 };
3380  switch_frame_t *frame = NULL;
3381 
3382  switch_core_session_get_read_impl(session, &read_impl);
3383 
3384  switch (type) {
3385  case SWITCH_ABC_TYPE_INIT:
3386  {
3389  }
3390  break;
3391  case SWITCH_ABC_TYPE_CLOSE:
3392  {
3393  if (cb->read_st) {
3394  speex_preprocess_state_destroy(cb->read_st);
3395  }
3396 
3397  if (cb->write_st) {
3398  speex_preprocess_state_destroy(cb->write_st);
3399  }
3400 
3401  if (cb->read_ec) {
3402  speex_echo_state_destroy(cb->read_ec);
3403  }
3404 
3405  if (cb->write_ec) {
3406  speex_echo_state_destroy(cb->write_ec);
3407  }
3408 
3409  switch_channel_set_private(channel, "_preprocess", NULL);
3410  }
3411  break;
3413  {
3414  if (cb->done)
3415  return SWITCH_FALSE;
3417 
3418  if (cb->read_st) {
3419 
3420  if (cb->read_ec) {
3421  speex_echo_cancellation(cb->read_ec, (int16_t *) frame->data, (int16_t *) cb->write_data, (int16_t *) cb->read_out);
3422  memcpy(frame->data, cb->read_out, frame->datalen);
3423  }
3424 
3425  speex_preprocess_run(cb->read_st, frame->data);
3426  }
3427 
3428  if (cb->write_ec) {
3429  memcpy(cb->read_data, frame->data, frame->datalen);
3430  }
3431  }
3432  break;
3434  {
3435  if (cb->done)
3436  return SWITCH_FALSE;
3438 
3439  if (cb->write_st) {
3440 
3441  if (cb->write_ec) {
3442  speex_echo_cancellation(cb->write_ec, (int16_t *) frame->data, (int16_t *) cb->read_data, (int16_t *) cb->write_out);
3443  memcpy(frame->data, cb->write_out, frame->datalen);
3444  }
3445 
3446  speex_preprocess_run(cb->write_st, frame->data);
3447  }
3448 
3449  if (cb->read_ec) {
3450  memcpy(cb->write_data, frame->data, frame->datalen);
3451  }
3452  }
3453  break;
3454  default:
3455  break;
3456  }
3457 
3458  return SWITCH_TRUE;
3459 }
3460 
3462 {
3464  switch_media_bug_t *bug;
3465  switch_status_t status;
3466  time_t to = 0;
3468  switch_codec_implementation_t read_impl = { 0 };
3469  pp_cb_t *cb;
3470  int update = 0;
3471  int argc;
3472  char *mydata = NULL, *argv[5];
3473  int i = 0;
3474 
3475  switch_core_session_get_read_impl(session, &read_impl);
3476 
3477  if ((cb = switch_channel_get_private(channel, "_preprocess"))) {
3478  update = 1;
3479  } else {
3480  cb = switch_core_session_alloc(session, sizeof(*cb));
3481  }
3482 
3483 
3484  if (update) {
3485  if (!strcasecmp(cmds, "stop")) {
3486  cb->done = 1;
3487  return SWITCH_STATUS_SUCCESS;
3488  }
3489  }
3490 
3491  mydata = strdup(cmds);
3492  argc = switch_separate_string(mydata, ',', argv, (sizeof(argv) / sizeof(argv[0])));
3493 
3494  for (i = 0; i < argc; i++) {
3495  char *var = argv[i];
3496  char *val = NULL;
3497  char rw;
3498  int tr;
3499  int err = 1;
3500  SpeexPreprocessState *st = NULL;
3501  SpeexEchoState *ec = NULL;
3502  switch_mutex_t *mutex = NULL;
3503  int r = 0;
3504 
3505  if (var) {
3506  if ((val = strchr(var, '='))) {
3507  *val++ = '\0';
3508 
3509  rw = *var++;
3510  while (*var == '.' || *var == '_') {
3511  var++;
3512  }
3513 
3514  if (rw == 'r') {
3515  if (!cb->read_st) {
3516  cb->read_st = speex_preprocess_state_init(read_impl.samples_per_packet, read_impl.samples_per_second);
3517  flags |= SMBF_READ_REPLACE;
3518  }
3519  st = cb->read_st;
3520  ec = cb->read_ec;
3521  mutex = cb->read_mutex;
3522  } else if (rw == 'w') {
3523  if (!cb->write_st) {
3524  cb->write_st = speex_preprocess_state_init(read_impl.samples_per_packet, read_impl.samples_per_second);
3525  flags |= SMBF_WRITE_REPLACE;
3526  }
3527  st = cb->write_st;
3528  ec = cb->write_ec;
3529  mutex = cb->write_mutex;
3530  }
3531 
3532  if (mutex)
3533  switch_mutex_lock(mutex);
3534 
3535  if (st) {
3536  err = 0;
3537  tr = switch_true(val);
3538  if (!strcasecmp(var, "agc")) {
3539  int l = read_impl.samples_per_second;
3540  int tmp = atoi(val);
3541 
3542  if (!tr) {
3543  l = tmp;
3544  }
3545 
3546  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setting AGC on %c to %d\n", rw, tr);
3547  speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC, &tr);
3548  speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &l);
3549 
3550  } else if (!strcasecmp(var, "noise_suppress")) {
3551  int db = atoi(val);
3552  if (db < 0) {
3553  r = speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &db);
3554  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setting NOISE_SUPPRESS on %c to %d [%d]\n", rw, db,
3555  r);
3556  } else {
3557  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Syntax error noise_suppress should be in -db\n");
3558  }
3559  } else if (!strcasecmp(var, "echo_cancel")) {
3560  int tail = 1024;
3561  int tmp = atoi(val);
3562 
3563  if (!tr && tmp > 0) {
3564  tail = tmp;
3565  } else if (!tr) {
3566  if (ec) {
3567  if (rw == 'r') {
3568  speex_echo_state_destroy(cb->read_ec);
3569  cb->read_ec = NULL;
3570  } else {
3571  speex_echo_state_destroy(cb->write_ec);
3572  cb->write_ec = NULL;
3573  }
3574  }
3575 
3576  ec = NULL;
3577  }
3578 
3579  if (!ec) {
3580  if (rw == 'r') {
3581  ec = cb->read_ec = speex_echo_state_init(read_impl.samples_per_packet, tail);
3582  speex_echo_ctl(ec, SPEEX_ECHO_SET_SAMPLING_RATE, &read_impl.samples_per_second);
3583  flags |= SMBF_WRITE_REPLACE;
3584  } else {
3585  ec = cb->write_ec = speex_echo_state_init(read_impl.samples_per_packet, tail);
3586  speex_echo_ctl(ec, SPEEX_ECHO_SET_SAMPLING_RATE, &read_impl.samples_per_second);
3587  flags |= SMBF_READ_REPLACE;
3588  }
3589  speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_ECHO_STATE, ec);
3590  }
3591 
3592 
3593  } else if (!strcasecmp(var, "echo_suppress")) {
3594  int db = atoi(val);
3595  if (db < 0) {
3596  speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS, &db);
3597  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setting ECHO_SUPPRESS on %c to %d [%d]\n", rw, db,
3598  r);
3599  } else {
3600  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Syntax error echo_suppress should be in -db\n");
3601  }
3602  } else {
3603  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Warning unknown parameter [%s] \n", var);
3604  }
3605  }
3606  }
3607 
3608  if (mutex)
3609  switch_mutex_unlock(mutex);
3610 
3611  if (err) {
3612  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Syntax error parsing preprocessor commands\n");
3613  }
3614 
3615  } else {
3616  break;
3617  }
3618  }
3619 
3620 
3621  switch_safe_free(mydata);
3622 
3623  if (update) {
3624  return SWITCH_STATUS_SUCCESS;
3625  }
3626 
3627 
3628  if ((status = switch_core_media_bug_add(session, "preprocess", NULL,
3629  preprocess_callback, cb, to, flags, &bug)) != SWITCH_STATUS_SUCCESS) {
3630  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error adding media bug.\n");
3631  if (cb->read_st) {
3632  speex_preprocess_state_destroy(cb->read_st);
3633  }
3634 
3635  if (cb->write_st) {
3636  speex_preprocess_state_destroy(cb->write_st);
3637  }
3638 
3639  if (cb->read_ec) {
3640  speex_echo_state_destroy(cb->read_ec);
3641  }
3642 
3643  if (cb->write_ec) {
3644  speex_echo_state_destroy(cb->write_ec);
3645  }
3646 
3647  return status;
3648  }
3649 
3650  switch_channel_set_private(channel, "_preprocess", cb);
3651 
3652  return SWITCH_STATUS_SUCCESS;
3653 }
3654 
3655 
3656 typedef struct {
3658  int mute;
3664 
3666 {
3667  switch_session_audio_t *pvt = (switch_session_audio_t *) user_data;
3668  switch_frame_t *frame = NULL;
3669  int level = 0, mute = 0;
3671  switch_codec_implementation_t read_impl = { 0 };
3672 
3673  switch_core_session_get_read_impl(session, &read_impl);
3674 
3675 
3677  if (!(pvt->read_level || pvt->write_level || pvt->read_mute || pvt->write_mute)) {
3679  return SWITCH_FALSE;
3680  }
3681  }
3682 
3683  if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
3684  level = pvt->read_level;
3685  mute = pvt->read_mute;
3687  } else if (type == SWITCH_ABC_TYPE_WRITE_REPLACE) {
3688  level = pvt->write_level;
3689  mute = pvt->write_mute;
3691  }
3692 
3693  if (frame) {
3694  if (mute) {
3695  if (mute > 1) {
3696  switch_generate_sln_silence(frame->data, frame->datalen / 2, read_impl.number_of_channels, mute);
3697  } else {
3698  memset(frame->data, 0, frame->datalen);
3699  }
3700  } else if (level) {
3701  switch_change_sln_volume(frame->data, frame->datalen / 2, level);
3702  }
3703 
3704  if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
3706  } else if (type == SWITCH_ABC_TYPE_WRITE_REPLACE) {
3708  }
3709  }
3710 
3711  return SWITCH_TRUE;
3712 }
3713 
3715 {
3716  switch_media_bug_t *bug;
3718 
3719  if ((bug = switch_channel_get_private(channel, "__audio"))) {
3720  switch_channel_set_private(channel, "__audio", NULL);
3721  switch_core_media_bug_remove(session, &bug);
3722  return SWITCH_STATUS_SUCCESS;
3723  }
3724  return SWITCH_STATUS_FALSE;
3725 }
3726 
3727 SWITCH_DECLARE(switch_status_t) switch_ivr_session_audio(switch_core_session_t *session, const char *cmd, const char *direction, int level)
3728 {
3730  switch_media_bug_t *bug;
3731  switch_status_t status;
3733  switch_codec_implementation_t read_impl = { 0 };
3734  int existing = 0, c_read = 0, c_write = 0, flags = SMBF_NO_PAUSE;
3735 
3737  return SWITCH_STATUS_FALSE;
3738  }
3739 
3740  switch_core_session_get_read_impl(session, &read_impl);
3741 
3742 
3743  if ((bug = switch_channel_get_private(channel, "__audio"))) {
3745  existing = 1;
3746  } else {
3747  if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt)))) {
3748  return SWITCH_STATUS_MEMERR;
3749  }
3750 
3751  pvt->session = session;
3752  }
3753 
3754 
3755  if (!strcasecmp(direction, "write")) {
3756  flags = SMBF_WRITE_REPLACE;
3757  c_write = 1;
3758  } else if (!strcasecmp(direction, "read")) {
3759  flags = SMBF_READ_REPLACE;
3760  c_read = 1;
3761  } else if (!strcasecmp(direction, "both")) {
3763  c_read = c_write = 1;
3764  }
3765 
3766 
3767  if (!strcasecmp(cmd, "mute")) {
3768  if (c_read) {
3769  pvt->read_mute = level;
3770  pvt->read_level = 0;
3771  }
3772  if (c_write) {
3773  pvt->write_mute = level;
3774  pvt->write_level = 0;
3775  }
3776  } else if (!strcasecmp(cmd, "level")) {
3777  if (level < 5 && level > -5) {
3778  if (c_read) {
3779  pvt->read_level = level;
3780  }
3781  if (c_write) {
3782  pvt->write_level = level;
3783  }
3784  }
3785  }
3786 
3787  if (existing) {
3788  switch_core_media_bug_set_flag(bug, flags);
3789  } else {
3790  if ((status = switch_core_media_bug_add(session, "audio", cmd,
3791  session_audio_callback, pvt, 0, flags, &bug)) != SWITCH_STATUS_SUCCESS) {
3792  return status;
3793  }
3794 
3795  switch_channel_set_private(channel, "__audio", bug);
3796  }
3797 
3798 
3799  return SWITCH_STATUS_SUCCESS;
3800 }
3801 
3802 
3803 typedef struct {
3807 
3809 {
3810  switch_inband_dtmf_t *pvt = (switch_inband_dtmf_t *) user_data;
3811  switch_frame_t *frame = NULL;
3813 
3814  switch (type) {
3815  case SWITCH_ABC_TYPE_INIT:
3816  break;
3817  case SWITCH_ABC_TYPE_CLOSE:
3818  break;
3820  if ((frame = switch_core_media_bug_get_read_replace_frame(bug))) {
3821  if (teletone_dtmf_detect(&pvt->dtmf_detect, frame->data, frame->samples) == TT_HIT_END) {
3822  switch_dtmf_t dtmf = {0};
3823 
3824  teletone_dtmf_get(&pvt->dtmf_detect, &dtmf.digit, &dtmf.duration);
3826  dtmf.digit, dtmf.duration);
3828  switch_channel_queue_dtmf(channel, &dtmf);
3829  }
3831  }
3832  break;
3833  case SWITCH_ABC_TYPE_WRITE:
3834  default:
3835  break;
3836  }
3837 
3838  return SWITCH_TRUE;
3839 }
3840 
3842 {
3843  switch_media_bug_t *bug;
3845 
3846  if ((bug = switch_channel_get_private(channel, "dtmf"))) {
3847  switch_channel_set_private(channel, "dtmf", NULL);
3848  switch_core_media_bug_remove(session, &bug);
3849  return SWITCH_STATUS_SUCCESS;
3850  }
3851  return SWITCH_STATUS_FALSE;
3852 }
3853 
3855 {
3857  switch_media_bug_t *bug;
3858  switch_status_t status;
3859  switch_inband_dtmf_t *pvt;
3860  switch_codec_implementation_t read_impl = { 0 };
3861 
3862  switch_core_session_get_read_impl(session, &read_impl);
3863 
3864  if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt)))) {
3865  return SWITCH_STATUS_MEMERR;
3866  }
3867 
3869 
3870  pvt->session = session;
3871 
3872 
3874  return SWITCH_STATUS_FALSE;
3875  }
3876 
3877  if ((status = switch_core_media_bug_add(session, "inband_dtmf", NULL,
3879  return status;
3880  }
3881 
3882  switch_channel_set_private(channel, "dtmf", bug);
3883 
3884  return SWITCH_STATUS_SUCCESS;
3885 }
3886 
3887 typedef struct {
3893  int read;
3894  int ready;
3895  int skip;
3897 
3899 {
3900  switch_buffer_t *audio_buffer = ts->user_data;
3901  int wrote;
3902 
3903  if (!audio_buffer) {
3904  return -1;
3905  }
3906 
3907  wrote = teletone_mux_tones(ts, map);
3908  switch_buffer_write(audio_buffer, ts->buffer, wrote * 2);
3909 
3910  return 0;
3911 }
3912 
3914 {
3916  switch_media_bug_t *bug = switch_channel_get_private(channel, "dtmf_generate");
3918 
3919  if (bug) {
3921 
3922  if (pvt) {
3923  switch_mutex_lock(pvt->mutex);
3924 
3925  if (pvt->ready) {
3926  switch_dtmf_t *dt = NULL;
3927  switch_zmalloc(dt, sizeof(*dt));
3928  *dt = *dtmf;
3929  if (!switch_buffer_inuse(pvt->audio_buffer)) {
3930  pvt->skip = 10;
3931  }
3933  switch_event_t *event;
3934 
3936  switch_channel_event_set_data(channel, event);
3937  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "DTMF-Digit", "%c", dtmf->digit);
3938  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "DTMF-Duration", "%u", dtmf->duration);
3939  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "DTMF-Source", "APP");
3940  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "DTMF-Conversion", "native:inband");
3942  switch_core_session_queue_event(session, &event);
3943  } else {
3944  switch_event_fire(&event);
3945  }
3946  }
3947 
3948  dt = NULL;
3949  /*
3950  SWITCH_STATUS_FALSE indicates pretend there never was a DTMF
3951  since we will be generating it inband now.
3952  */
3953  status = SWITCH_STATUS_FALSE;
3954  } else {
3955  free(dt);
3956  }
3957  }
3958  switch_mutex_unlock(pvt->mutex);
3959  }
3960  }
3961 
3962  return status;
3963 }
3964 
3965 
3967 {
3969  switch_frame_t *frame;
3970  switch_codec_implementation_t read_impl = { 0 };
3971  switch_core_session_get_read_impl(pvt->session, &read_impl);
3972 
3973  switch (type) {
3974  case SWITCH_ABC_TYPE_INIT:
3975  {
3977  switch_buffer_create_dynamic(&pvt->audio_buffer, 512, 1024, 0);
3979  pvt->ts.rate = read_impl.actual_samples_per_second;
3980  pvt->ts.channels = 1;
3982  if (pvt->read) {
3983  switch_core_event_hook_add_recv_dtmf(pvt->session, generate_on_dtmf);
3984  } else {
3985  switch_core_event_hook_add_send_dtmf(pvt->session, generate_on_dtmf);
3986  }
3987  switch_mutex_lock(pvt->mutex);
3988  pvt->ready = 1;
3989  switch_mutex_unlock(pvt->mutex);
3990  }
3991  break;
3992  case SWITCH_ABC_TYPE_CLOSE:
3993  {
3994  switch_mutex_lock(pvt->mutex);
3995  pvt->ready = 0;
3996  switch_core_event_hook_remove_recv_dtmf(pvt->session, generate_on_dtmf);
3999  switch_mutex_unlock(pvt->mutex);
4000  }
4001  break;
4004  {
4005  switch_size_t bytes;
4006  void *pop;
4007 
4008  if (pvt->skip) {
4009  pvt->skip--;
4010  return SWITCH_TRUE;
4011  }
4012 
4013 
4014  switch_mutex_lock(pvt->mutex);
4015 
4016  if (!pvt->ready) {
4017  switch_mutex_unlock(pvt->mutex);
4018  return SWITCH_FALSE;
4019  }
4020 
4021  if (pvt->read) {
4023  } else {
4025  }
4026 
4027  if (!switch_buffer_inuse(pvt->audio_buffer)) {
4029  switch_dtmf_t *dtmf = (switch_dtmf_t *) pop;
4030 
4031 
4032  if (dtmf->source != SWITCH_DTMF_INBAND_AUDIO) {
4033  char buf[2] = "";
4034  int duration = dtmf->duration;
4035 
4036  buf[0] = dtmf->digit;
4037  if (duration > (int)switch_core_max_dtmf_duration(0)) {
4038  duration = switch_core_default_dtmf_duration(0);
4040  SWITCH_LOG_WARNING, "%s Truncating DTMF duration %d ms to %d ms\n",
4042  }
4043 
4044 
4045  pvt->ts.duration = duration;
4046  teletone_run(&pvt->ts, buf);
4047  }
4048  free(pop);
4049  }
4050  }
4051 
4052  if (switch_buffer_inuse(pvt->audio_buffer) && (bytes = switch_buffer_read(pvt->audio_buffer, frame->data, frame->datalen))) {
4053  if (bytes < frame->datalen) {
4054  switch_byte_t *dp = frame->data;
4055  memset(dp + bytes, 0, frame->datalen - bytes);
4056  }
4057  }
4058 
4059  if (pvt->read) {
4061  } else {
4063  }
4064 
4065  switch_mutex_unlock(pvt->mutex);
4066  }
4067  break;
4068  default:
4069  break;
4070  }
4071 
4072  return SWITCH_TRUE;
4073 }
4074 
4076 {
4078  switch_media_bug_t *bug = switch_channel_get_private(channel, "dtmf_generate");
4079 
4080  if (bug) {
4081  switch_channel_set_private(channel, "dtmf_generate", NULL);
4082  switch_core_media_bug_remove(session, &bug);
4083  return SWITCH_STATUS_SUCCESS;
4084  }
4085 
4086  return SWITCH_STATUS_FALSE;
4087 
4088 }
4089 
4091 {
4093  switch_media_bug_t *bug;
4094  switch_status_t status;
4096 
4097  if ((status = switch_channel_pre_answer(channel)) != SWITCH_STATUS_SUCCESS) {
4098  return SWITCH_STATUS_FALSE;
4099  }
4100 
4101  if (!switch_channel_media_up(channel) || !switch_core_session_get_read_codec(session)) {
4102  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can not install inband dtmf generate. Media not enabled on channel\n");
4103  return status;
4104  }
4105 
4106  if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt)))) {
4107  return SWITCH_STATUS_MEMERR;
4108  }
4109 
4110  pvt->session = session;
4111  pvt->read = !!read_stream;
4112 
4113  if ((status = switch_core_media_bug_add(session, "inband_dtmf_generate", NULL,
4116  return status;
4117  }
4118 
4119  switch_channel_set_private(channel, "dtmf_generate", bug);
4120 
4121  return SWITCH_STATUS_SUCCESS;
4122 }
4123 
4124 #define MAX_TONES 16
4125 typedef struct {
4127  char *app;
4128  char *data;
4129  char *key;
4131  int up;
4133  int hits;
4134  int sleep;
4135  int expires;
4138  int once;
4142 
4143 typedef struct {
4145  int index;
4151 
4152 
4154 {
4155  char *total_time = switch_mprintf("%d", (int)(switch_micro_time_now() - cont->list[index].start_time) / 1000);
4156 
4157  switch_channel_set_variable_name_printf(switch_core_session_get_channel(cont->session), total_time, "tone_detect_%s_total_time",
4158  cont->list[index].key);
4159  switch_safe_free(total_time);
4160 }
4161 
4163 {
4165  switch_tone_container_t *cont = switch_channel_get_private(channel, "_tone_detect_");
4166  int i;
4167 
4168  if (!cont || !cont->detect_fax || dtmf->digit != 'f') {
4169  return SWITCH_STATUS_SUCCESS;
4170  }
4171 
4172  i = cont->detect_fax;
4173 
4174  tone_detect_set_total_time(cont, i);
4175  if (cont->list[i].callback) {
4176  cont->list[i].callback(cont->session, cont->list[i].app, cont->list[i].data);
4177  } else {
4180 
4181  if (cont->list[i].app) {
4183  }
4184  }
4185 
4186  return SWITCH_STATUS_SUCCESS;
4187 
4188 }
4189 
4191 {
4192  switch_tone_container_t *cont = (switch_tone_container_t *) user_data;
4193  switch_frame_t *frame = NULL;
4194  int i = 0;
4195  switch_bool_t rval = SWITCH_TRUE;
4196 
4197  switch (type) {
4198  case SWITCH_ABC_TYPE_INIT:
4199  if (cont) {
4200  cont->bug_running = 1;
4201  }
4202  break;
4203  case SWITCH_ABC_TYPE_CLOSE:
4204  break;
4207  {
4208 
4209  if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
4211  } else {
4213  }
4214 
4215  for (i = 0; i < cont->index; i++) {
4216  int skip = 0;
4217 
4218  if (cont->list[i].sleep) {
4219  cont->list[i].sleep--;
4220  if (cont->list[i].sleep) {
4221  skip = 1;
4222  }
4223  }
4224 
4225  if (cont->list[i].expires) {
4226  cont->list[i].expires--;
4227  if (!cont->list[i].expires) {
4228  cont->list[i].hits = 0;
4229  cont->list[i].sleep = 0;
4230  cont->list[i].expires = 0;
4231  }
4232  }
4233 
4234  if (!cont->list[i].up)
4235  skip = 1;
4236 
4237  if (skip)
4238  continue;
4239 
4240  if (teletone_multi_tone_detect(&cont->list[i].mt, frame->data, frame->samples)) {
4241  switch_event_t *event;
4242  cont->list[i].hits++;
4243 
4245  cont->list[i].key, cont->list[i].hits, cont->list[i].total_hits);
4246  cont->list[i].sleep = cont->list[i].default_sleep;
4247  cont->list[i].expires = cont->list[i].default_expires;
4248 
4249  if (cont->list[i].hits >= cont->list[i].total_hits) {
4251  cont->list[i].key);
4252  tone_detect_set_total_time(cont, i);
4253  cont->list[i].up = 0;
4254 
4255  if (cont->list[i].callback) {
4256  if ((rval = cont->list[i].callback(cont->session, cont->list[i].app, cont->list[i].data)) == SWITCH_TRUE) {
4258  cont->list[i].key);
4259  cont->list[i].up = 1;
4260  cont->list[i].hits = 0;
4261  cont->list[i].sleep = 0;
4262  cont->list[i].expires = 0;
4263  }
4264  } else {
4266  if (cont->list[i].app) {
4268  }
4269  }
4270 
4271  if (cont->list[i].once) {
4272  rval = SWITCH_FALSE;
4273  }
4274 
4276  switch_event_t *dup;
4277  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Detected-Tone", cont->list[i].key);
4278 
4279  if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {
4280  switch_event_fire(&dup);
4281  }
4282 
4285  "Event queue failed!\n");
4286  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
4287  switch_event_fire(&event);
4288  }
4289  }
4290  }
4291  }
4292  }
4293  }
4294  break;
4295  case SWITCH_ABC_TYPE_WRITE:
4296  default:
4297  break;
4298  }
4299 
4300  if (rval == SWITCH_FALSE) {
4301  cont->bug_running = 0;
4302  }
4303 
4304  return rval;
4305 }
4306 
4308 {
4310  switch_tone_container_t *cont = switch_channel_get_private(channel, "_tone_detect_");
4311  int i = 0;
4312 
4313  if (cont) {
4314  switch_channel_set_private(channel, "_tone_detect_", NULL);
4315  for (i = 0; i < cont->index; i++) {
4316  cont->list[i].up = 0;
4317  }
4318  switch_core_media_bug_remove(session, &cont->bug);
4319  if (cont->detect_fax) {
4320  cont->detect_fax = 0;
4321  }
4322  return SWITCH_STATUS_SUCCESS;
4323  }
4324  return SWITCH_STATUS_FALSE;
4325 }
4326 
4328  const char *key, const char *tone_spec,
4329  const char *flags, time_t timeout,
4330  int hits, const char *app, const char *data, switch_tone_detect_callback_t callback)
4331 {
4333  switch_status_t status;
4334  switch_tone_container_t *cont = switch_channel_get_private(channel, "_tone_detect_");
4335  char *p, *next;
4336  int i = 0, ok = 0, detect_fax = 0;
4337  switch_media_bug_flag_t bflags = 0;
4338  const char *var;
4339  switch_codec_implementation_t read_impl = { 0 };
4340  switch_core_session_get_read_impl(session, &read_impl);
4341 
4342 
4343  if (zstr(key)) {
4344  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No Key Specified!\n");
4345  return SWITCH_STATUS_FALSE;
4346  }
4347 
4348  if (cont) {
4349  if (cont->index >= MAX_TONES) {
4350  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Max Tones Reached!\n");
4351  return SWITCH_STATUS_FALSE;
4352  }
4353 
4354  for (i = 0; i < cont->index; i++) {
4355  if (!zstr(cont->list[i].key) && !strcasecmp(key, cont->list[i].key)) {
4356  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Re-enabling %s\n", key);
4357  cont->list[i].up = 1;
4358  cont->list[i].hits = 0;
4359  cont->list[i].sleep = 0;
4360  cont->list[i].expires = 0;
4361  return SWITCH_STATUS_SUCCESS;
4362  }
4363  }
4364  }
4365 
4366  if (zstr(tone_spec)) {
4367  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No Spec Specified!\n");
4368  return SWITCH_STATUS_FALSE;
4369  }
4370 
4371  if (!cont && !(cont = switch_core_session_alloc(session, sizeof(*cont)))) {
4372  return SWITCH_STATUS_MEMERR;
4373  }
4374 
4375  if ((var = switch_channel_get_variable(channel, "tone_detect_hits"))) {
4376  int tmp = atoi(var);
4377  if (tmp > 0) {
4378  hits = tmp;
4379  }
4380  }
4381 
4382  if (!hits) hits = 1;
4383 
4384  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);
4385 
4386  i = 0;
4387  p = (char *) tone_spec;
4388 
4389  do {
4390  teletone_process_t this;
4391  next = strchr(p, ',');
4392  while (*p == ' ')
4393  p++;
4394  if ((this = (teletone_process_t) atof(p))) {
4395  ok++;
4396  cont->list[cont->index].map.freqs[i++] = this;
4397  }
4398  if (!strncasecmp(p, "1100", 4)) {
4399  detect_fax = cont->index;
4400  }
4401 
4402  if (next) {
4403  p = next + 1;
4404  }
4405  } while (next);
4406  cont->list[cont->index].map.freqs[i++] = 0;
4407 
4408  if (!ok) {
4409  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid tone spec!\n");
4410  return SWITCH_STATUS_FALSE;
4411  }
4412 
4413  cont->detect_fax = detect_fax;
4414 
4415  cont->list[cont->index].key = switch_core_session_strdup(session, key);
4416 
4417  if (app) {
4418  cont->list[cont->index].app = switch_core_session_strdup(session, app);
4419  }
4420 
4421  if (data) {
4422  cont->list[cont->index].data = switch_core_session_strdup(session, data);
4423  }
4424 
4425  cont->list[cont->index].callback = callback;
4426  cont->list[cont->index].hits = 0;
4427  cont->list[cont->index].total_hits = hits;
4428  cont->list[cont->index].start_time = switch_micro_time_now();
4429 
4430  cont->list[cont->index].up = 1;
4431  memset(&cont->list[cont->index].mt, 0, sizeof(cont->list[cont->index].mt));
4432  cont->list[cont->index].mt.sample_rate = read_impl.actual_samples_per_second;
4433  teletone_multi_tone_init(&cont->list[cont->index].mt, &cont->list[cont->index].map);
4434  cont->session = session;
4435 
4437  return SWITCH_STATUS_FALSE;
4438  }
4439 
4440  cont->list[cont->index].default_sleep = 25;
4441  cont->list[cont->index].default_expires = 250;
4442 
4443  if ((var = switch_channel_get_variable(channel, "tone_detect_sleep"))) {
4444  int tmp = atoi(var);
4445  if (tmp > 0) {
4446  cont->list[cont->index].default_sleep = tmp;
4447  }
4448  }
4449 
4450  if ((var = switch_channel_get_variable(channel, "tone_detect_expires"))) {
4451  int tmp = atoi(var);
4452  if (tmp > 0) {
4453  cont->list[cont->index].default_expires = tmp;
4454  }
4455  }
4456 
4457 
4458  if (zstr(flags)) {
4459  bflags = SMBF_READ_REPLACE;
4460  } else {
4461  if (strchr(flags, 'o')) {
4462  cont->list[cont->index].once = 1;
4463  }
4464 
4465  if (strchr(flags, 'r')) {
4466  bflags |= SMBF_READ_REPLACE;
4467  } else if (strchr(flags, 'w')) {
4468  bflags |= SMBF_WRITE_REPLACE;
4469  }
4470  }
4471 
4472  bflags |= SMBF_NO_PAUSE;
4473 
4474  if (cont->bug_running) {
4475  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s bug already running\n", switch_channel_get_name(channel));
4476  } else {
4477  cont->bug_running = 1;
4478  if (cont->detect_fax) {
4479  switch_core_event_hook_add_send_dtmf(session, tone_on_dtmf);
4480  switch_core_event_hook_add_recv_dtmf(session, tone_on_dtmf);
4481  }
4482 
4483  if ((status = switch_core_media_bug_add(session, "tone_detect", key,
4484  tone_detect_callback, cont, timeout, bflags, &cont->bug)) != SWITCH_STATUS_SUCCESS) {
4485  cont->bug_running = 0;
4486  return status;
4487  }
4488  switch_channel_set_private(channel, "_tone_detect_", cont);
4489  }
4490 
4491  cont->index++;
4492 
4493  return SWITCH_STATUS_SUCCESS;
4494 }
4495 
4496 
4497 typedef struct {
4498  const char *app;
4499  uint32_t flags;
4501 } dtmf_meta_app_t;
4502 
4503 typedef struct {
4505  time_t last_digit;
4507  char meta;
4508  int up;
4510 
4511 typedef struct {
4514 
4515 #define SWITCH_META_VAR_KEY "__dtmf_meta"
4516 #define SWITCH_BLOCK_DTMF_KEY "__dtmf_block"
4517 
4518 typedef struct {
4520  const char *app;
4521  int flags;
4522 } bch_t;
4523 
4525 {
4526  bch_t *bch = (bch_t *) obj;
4527 
4528  if (!bch->session) {
4529  return NULL;
4530  }
4531 
4535  }
4536 
4537  return NULL;
4538 
4539 }
4540 SWITCH_DECLARE(void) switch_ivr_broadcast_in_thread(switch_core_session_t *session, const char *app, int flags)
4541 {
4543  switch_threadattr_t *thd_attr = NULL;
4545  bch_t *bch;
4546 
4547  switch_assert(session);
4548 
4549  pool = switch_core_session_get_pool(session);
4550 
4551  bch = switch_core_session_alloc(session, sizeof(*bch));
4552  bch->session = session;
4553  bch->app = app;
4554  bch->flags = flags;
4555 
4556 
4557  switch_threadattr_create(&thd_attr, pool);
4558  switch_threadattr_detach_set(thd_attr, 1);
4560  switch_thread_create(&thread, thd_attr, bcast_thread, bch, pool);
4561 }
4562 
4564 {
4567  time_t now = switch_epoch_time_now(NULL);
4568  char digit[2] = "";
4569  int dval;
4570 
4571  if (!md || switch_channel_test_flag(channel, CF_INNER_BRIDGE)) {
4572  return SWITCH_STATUS_SUCCESS;
4573  }
4574 
4575  if (direction == SWITCH_DTMF_RECV && !md->sr[SWITCH_DTMF_RECV].up) {
4576  return SWITCH_STATUS_SUCCESS;
4577  }
4578 
4579  if (direction == SWITCH_DTMF_SEND && !md->sr[SWITCH_DTMF_SEND].up) {
4580  return SWITCH_STATUS_SUCCESS;
4581  }
4582 
4583  if (md->sr[direction].meta_on && now - md->sr[direction].last_digit > 5) {
4584  md->sr[direction].meta_on = SWITCH_FALSE;
4585  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s Meta digit timeout parsing %c\n", switch_channel_get_name(channel),
4586  dtmf->digit);
4587  return SWITCH_STATUS_SUCCESS;
4588  }
4589 
4590  md->sr[direction].last_digit = now;
4591 
4592  if (dtmf->digit == md->sr[direction].meta) {
4593  if (md->sr[direction].meta_on) {
4594  md->sr[direction].meta_on = SWITCH_FALSE;
4595  return SWITCH_STATUS_SUCCESS;
4596  } else {
4597  md->sr[direction].meta_on = SWITCH_TRUE;
4598  return SWITCH_STATUS_FALSE;
4599  }
4600  }
4601 
4602  if (md->sr[direction].meta_on) {
4603  if (is_dtmf(dtmf->digit)) {
4604  int ok = 0;
4605  *digit = dtmf->digit;
4606  dval = switch_dtmftoi(digit);
4607 
4608  if (direction == SWITCH_DTMF_RECV && (md->sr[direction].map[dval].bind_flags & SBF_DIAL_ALEG)) {
4609  ok = 1;
4610  } else if (direction == SWITCH_DTMF_SEND && (md->sr[direction].map[dval].bind_flags & SBF_DIAL_BLEG)) {
4611  ok = 1;
4612  }
4613 
4614  if (ok && md->sr[direction].map[dval].app) {
4615  uint32_t flags = md->sr[direction].map[dval].flags;
4616 
4617  if ((md->sr[direction].map[dval].bind_flags & SBF_EXEC_OPPOSITE)) {
4618  if (direction == SWITCH_DTMF_SEND) {
4619  flags |= SMF_ECHO_ALEG;
4620  } else {
4621  flags |= SMF_ECHO_BLEG;
4622  }
4623  } else if ((md->sr[direction].map[dval].bind_flags & SBF_EXEC_SAME)) {
4624  if (direction == SWITCH_DTMF_SEND) {
4625  flags |= SMF_ECHO_BLEG;
4626  } else {
4627  flags |= SMF_ECHO_ALEG;
4628  }
4629  } else if ((md->sr[direction].map[dval].bind_flags & SBF_EXEC_ALEG)) {
4630  flags |= SMF_ECHO_ALEG;
4631  } else if ((md->sr[direction].map[dval].bind_flags & SBF_EXEC_BLEG)) {
4632  flags |= SMF_ECHO_BLEG;
4633  } else {
4634  flags |= SMF_ECHO_ALEG;
4635  }
4636 
4637  if ((md->sr[direction].map[dval].bind_flags & SBF_EXEC_INLINE)) {
4638  flags |= SMF_EXEC_INLINE;
4639  }
4640 
4641  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Processing meta digit '%c' [%s]\n",
4642  switch_channel_get_name(channel), dtmf->digit, md->sr[direction].map[dval].app);
4643 
4644  if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
4645  switch_ivr_broadcast_in_thread(session, md->sr[direction].map[dval].app, flags | SMF_REBRIDGE);
4646  } else {
4647  switch_ivr_broadcast(switch_core_session_get_uuid(session), md->sr[direction].map[dval].app, flags);
4648  }
4649 
4650  if ((md->sr[direction].map[dval].bind_flags & SBF_ONCE)) {
4651  memset(&md->sr[direction].map[dval], 0, sizeof(md->sr[direction].map[dval]));
4652  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Unbinding meta digit '%c'\n",
4653  switch_channel_get_name(channel), dtmf->digit);
4654  }
4655 
4656  } else {
4657  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Ignoring meta digit '%c' not mapped\n",
4658  switch_channel_get_name(channel), dtmf->digit);
4659 
4660  }
4661  }
4662  md->sr[direction].meta_on = SWITCH_FALSE;
4663  return SWITCH_STATUS_FALSE;
4664  }
4665 
4666  return SWITCH_STATUS_SUCCESS;
4667 }
4668 
4670 {
4672 
4673  if (key) {
4675 
4676  if (!md || key > 9) {
4677  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid key %u\n", key);
4678  return SWITCH_STATUS_FALSE;
4679  }
4680 
4681  memset(&md->sr[SWITCH_DTMF_RECV].map[key], 0, sizeof(md->sr[SWITCH_DTMF_RECV].map[key]));
4682  memset(&md->sr[SWITCH_DTMF_SEND].map[key], 0, sizeof(md->sr[SWITCH_DTMF_SEND].map[key]));
4683  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "UnBound A-Leg: %d\n", key);
4684 
4685  } else {
4686  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "UnBound A-Leg: ALL\n");
4688  }
4689 
4690  return SWITCH_STATUS_SUCCESS;
4691 }
4692 
4694 {
4696  uint8_t enabled = (uint8_t)(intptr_t)switch_channel_get_private(channel, SWITCH_BLOCK_DTMF_KEY);
4697 
4698  if (!enabled || switch_channel_test_flag(channel, CF_INNER_BRIDGE)) {
4699  return SWITCH_STATUS_SUCCESS;
4700  }
4701 
4702  return SWITCH_STATUS_FALSE;
4703 }
4704 
4706 {
4708  uint8_t enabled = (uint8_t)(intptr_t)switch_channel_get_private(channel, SWITCH_BLOCK_DTMF_KEY);
4709 
4710  if (enabled) {
4712  }
4713 
4714  return SWITCH_STATUS_SUCCESS;
4715 }
4716 
4718 {
4720  uint8_t enabled = (uint8_t)(intptr_t)switch_channel_get_private(channel, SWITCH_BLOCK_DTMF_KEY);
4721 
4722  if (!enabled) {
4723  switch_channel_set_private(channel, SWITCH_BLOCK_DTMF_KEY, (void *)(intptr_t)1);
4724  switch_core_event_hook_add_send_dtmf(session, block_on_dtmf);
4725  switch_core_event_hook_add_recv_dtmf(session, block_on_dtmf);
4726  }
4727 
4728  return SWITCH_STATUS_SUCCESS;
4729 }
4730 
4732  switch_bind_flag_t bind_flags, const char *app)
4733 {
4736  const char *meta_var = switch_channel_get_variable(channel, "bind_meta_key");
4737  char meta = '*';
4738  char str[2] = "";
4739 
4740  if (meta_var) {
4741  char t_meta = *meta_var;
4742  if (is_dtmf(t_meta)) {
4743  meta = t_meta;
4744  } else {
4745  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Invalid META KEY %c\n", t_meta);
4746  }
4747  }
4748 
4749  if (meta != '*' && meta != '#') {
4750  str[0] = meta;
4751 
4752  if (switch_dtmftoi(str) == (char)key) {
4753  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid key %u, same as META CHAR\n", key);
4754  return SWITCH_STATUS_FALSE;
4755  }
4756  }
4757 
4758 
4759  if (key > 13) {
4760  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid key %u\n", key);
4761  return SWITCH_STATUS_FALSE;
4762  }
4763 
4764  if (!md) {
4765  md = switch_core_session_alloc(session, sizeof(*md));
4767  switch_core_event_hook_add_send_dtmf(session, meta_on_dtmf);
4768  switch_core_event_hook_add_recv_dtmf(session, meta_on_dtmf);
4769  }
4770 
4771  if (!zstr(app)) {
4772  if ((bind_flags & SBF_DIAL_ALEG)) {
4773  md->sr[SWITCH_DTMF_RECV].meta = meta;
4774  md->sr[SWITCH_DTMF_RECV].up = 1;
4775  md->sr[SWITCH_DTMF_RECV].map[key].app = switch_core_session_strdup(session, app);
4777  md->sr[SWITCH_DTMF_RECV].map[key].bind_flags = bind_flags;
4778 
4779  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Bound A-Leg: %c%c %s\n", meta, switch_itodtmf((char)key), app);
4780  }
4781  if ((bind_flags & SBF_DIAL_BLEG)) {
4782  md->sr[SWITCH_DTMF_SEND].meta = meta;
4783  md->sr[SWITCH_DTMF_SEND].up = 1;
4784  md->sr[SWITCH_DTMF_SEND].map[key].app = switch_core_session_strdup(session, app);
4786  md->sr[SWITCH_DTMF_SEND].map[key].bind_flags = bind_flags;
4787  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Bound B-Leg: %c%c %s\n", meta, switch_itodtmf((char)key), app);
4788  }
4789 
4790  } else {
4791  if ((bind_flags & SBF_DIAL_ALEG)) {
4792  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "UnBound A-Leg: %c%c\n", meta, switch_itodtmf((char)key));
4793  md->sr[SWITCH_DTMF_SEND].map[key].app = NULL;
4794  } else {
4795  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "UnBound: B-Leg %c%d\n", meta, key);
4796  md->sr[SWITCH_DTMF_SEND].map[key].app = NULL;
4797  }
4798  }
4799 
4800  return SWITCH_STATUS_SUCCESS;
4801 }
4802 
4803 #define PLAY_AND_DETECT_DONE 1
4804 #define PLAY_AND_DETECT_DONE_RECOGNIZING 2
4805 typedef struct {
4806  int done;
4807  char *result;
4810 
4812 {
4813  if (args && args->input_callback) {
4814  args->input_callback(session, (void *)event, SWITCH_INPUT_TYPE_EVENT, args->buf, args->buflen);
4815  }
4816 }
4817 
4818 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)
4819 {
4821  if (!state->done) {
4823  if (input_type == SWITCH_INPUT_TYPE_EVENT) {
4824  switch_event_t *event;
4825  event = (switch_event_t *)input;
4826  if (event->event_id == SWITCH_EVENT_DETECTED_SPEECH) {
4827  const char *speech_type = switch_event_get_header(event, "Speech-Type");
4828 
4829  if (!zstr(speech_type)) {
4830  deliver_asr_event(session, event, state->original_args);
4831 
4832  if (!strcasecmp(speech_type, "detected-speech")) {
4833  const char *result;
4834  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "(%s) DETECTED SPEECH\n", switch_channel_get_name(channel));
4835  result = switch_event_get_body(event);
4836  if (!zstr(result)) {
4837  state->result = switch_core_session_strdup(session, result);
4838  } else {
4839  state->result = "";
4840  }
4841  state->original_args = NULL;
4843  return SWITCH_STATUS_BREAK;
4844  } else if (!strcasecmp(speech_type, "detected-partial-speech")) {
4845  // ok
4846  } else if (!strcasecmp(speech_type, "begin-speaking")) {
4847  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "(%s) START OF SPEECH\n", switch_channel_get_name(channel));
4848  return SWITCH_STATUS_BREAK;
4849  } else if (!strcasecmp("closed", speech_type)) {
4851  state->result = "";
4852  return SWITCH_STATUS_BREAK;
4853  } else {
4854  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unhandled speech type %s\n", speech_type);
4855  }
4856  }
4857  }
4858  } else if (input_type == SWITCH_INPUT_TYPE_DTMF) {
4859  switch_dtmf_t *dtmf = (switch_dtmf_t *) input;
4860  const char *terminators = switch_channel_get_variable(channel, SWITCH_PLAYBACK_TERMINATORS_VARIABLE);
4861  if (terminators) {
4862  if (!strcasecmp(terminators, "any")) {
4863  terminators = "1234567890*#";
4864  } else if (!strcasecmp(terminators, "none")) {
4865  terminators = NULL;
4866  }
4867  }
4868  if (terminators && strchr(terminators, dtmf->digit)) {
4869  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "(%s) ACCEPT TERMINATOR %c\n", switch_channel_get_name(channel), dtmf->digit);
4871  state->result = switch_core_session_sprintf(session, "DIGIT: %c", dtmf->digit);
4872  state->done = PLAY_AND_DETECT_DONE;
4873  return SWITCH_STATUS_BREAK;
4874  } else {
4875  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);
4876  }
4877  }
4878  }
4879  return SWITCH_STATUS_SUCCESS;
4880 }
4881 
4883  const char *file,
4884  const char *mod_name,
4885  const char *grammar,
4886  char **result,
4887  uint32_t input_timeout,
4888  switch_input_args_t *args)
4889 {
4891  int recognizing = 0;
4892  switch_input_args_t myargs = { 0 };
4893  play_and_detect_speech_state_t state = { 0, "", NULL };
4895 
4897 
4898  if (result == NULL) {
4899  goto done;
4900  }
4901 
4902  if (!input_timeout) input_timeout = 5000;
4903 
4904  /* start speech detection */
4905  if ((status = switch_ivr_detect_speech(session, mod_name, grammar, "", NULL, NULL)) != SWITCH_STATUS_SUCCESS) {
4906  /* map SWITCH_STATUS_FALSE to SWITCH_STATUS_GENERR to indicate grammar load failed
4907  SWITCH_STATUS_NOT_INITALIZED will be passed back to indicate ASR resource problem */
4908  if (status == SWITCH_STATUS_FALSE) {
4909  status = SWITCH_STATUS_GENERR;
4910  }
4911  goto done;
4912  }
4913  recognizing = 1;
4914 
4915  /* play the prompt, looking for detection result */
4916 
4917  if (args) {
4918  state.original_args = args;
4919  myargs.dmachine = args->dmachine;
4921  myargs.user_data = args->user_data;
4922  }
4923 
4925  myargs.buf = &state;
4926  myargs.buflen = sizeof(state);
4927 
4928  status = switch_ivr_play_file(session, NULL, file, &myargs);
4929 
4930  if (args && args->dmachine && switch_ivr_dmachine_last_ping(args->dmachine) != SWITCH_STATUS_SUCCESS) {
4931  state.done |= PLAY_AND_DETECT_DONE;
4932  goto done;
4933  }
4934 
4935  if (status != SWITCH_STATUS_BREAK && status != SWITCH_STATUS_SUCCESS) {
4936  status = SWITCH_STATUS_FALSE;
4937  goto done;
4938  }
4939 
4940  /* wait for result if not done */
4941  if (!state.done) {
4943  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "(%s) WAITING FOR RESULT\n", switch_channel_get_name(channel));
4944  while (!state.done && switch_channel_ready(channel)) {
4945  status = switch_ivr_sleep(session, input_timeout, SWITCH_FALSE, &myargs);
4946 
4947  if (args && args->dmachine && switch_ivr_dmachine_last_ping(args->dmachine) != SWITCH_STATUS_SUCCESS) {
4948  state.done |= PLAY_AND_DETECT_DONE;
4949  goto done;
4950  }
4951 
4952  if (status != SWITCH_STATUS_BREAK && status != SWITCH_STATUS_SUCCESS) {
4953  status = SWITCH_STATUS_FALSE;
4954  goto done;
4955  }
4956  }
4957  }
4958 
4959 done:
4960  if (recognizing && !(state.done & PLAY_AND_DETECT_DONE_RECOGNIZING)) {
4962  }
4963  if (recognizing && switch_channel_var_true(channel, "play_and_detect_speech_close_asr")) {
4965  }
4966 
4967  if (state.done) {
4968  status = SWITCH_STATUS_SUCCESS;
4969  }
4970  if (result) {
4971  *result = state.result;
4972  }
4973 
4975 
4976  return status;
4977 }
4978 
4987  int ready;
4988 };
4989 
4991 {
4992  struct speech_thread_handle *sth = (struct speech_thread_handle *) obj;
4995  switch_status_t status;
4996  switch_event_t *event;
4997 
4998  switch_thread_cond_create(&sth->cond, sth->pool);
5000 
5002  sth->ready = 0;
5003  return NULL;
5004  }
5005 
5006  switch_mutex_lock(sth->mutex);
5007 
5008  sth->ready = 1;
5009 
5011  char *xmlstr = NULL;
5012  switch_event_t *headers = NULL;
5013 
5014  switch_thread_cond_wait(sth->cond, sth->mutex);
5015 
5017  break;
5018  }
5019 
5021 
5022  status = switch_core_asr_get_results(sth->ah, &xmlstr, &flags);
5023 
5024  if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK && status != SWITCH_STATUS_MORE_DATA) {
5025  goto done;
5026  } else {
5027  /* Try to fetch extra information for this result, the return value doesn't really matter here - it's just optional data. */
5028  switch_core_asr_get_result_headers(sth->ah, &headers, &flags);
5029  }
5030 
5031  if (status == SWITCH_STATUS_SUCCESS && switch_true(switch_channel_get_variable(channel, "asr_intercept_dtmf"))) {
5032  const char *p;
5033 
5034  if ((p = switch_stristr("<input>", xmlstr))) {
5035  p += 7;
5036  }
5037 
5038  while (p && *p) {
5039  char c;
5040 
5041  if (*p == '<') {
5042  break;
5043  }
5044 
5045  if (!strncasecmp(p, "pound", 5)) {
5046  c = '#';
5047  p += 5;
5048  } else if (!strncasecmp(p, "hash", 4)) {
5049  c = '#';
5050  p += 4;
5051  } else if (!strncasecmp(p, "star", 4)) {
5052  c = '*';
5053  p += 4;
5054  } else if (!strncasecmp(p, "asterisk", 8)) {
5055  c = '*';
5056  p += 8;
5057  } else {
5058  c = *p;
5059  p++;
5060  }
5061 
5062  if (is_dtmf(c)) {
5063  switch_dtmf_t dtmf = {0};
5064  dtmf.digit = c;
5067  switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Queue speech detected dtmf %c\n", c);
5068  switch_channel_queue_dtmf(channel, &dtmf);
5069  }
5070 
5071  }
5073  }
5074 
5076  if (status == SWITCH_STATUS_SUCCESS) {
5077  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "detected-speech");
5078 
5079  if (headers) {
5080  switch_event_merge(event, headers);
5081  }
5082 
5083  switch_event_add_body(event, "%s", xmlstr);
5084  } else if (status == SWITCH_STATUS_MORE_DATA) {
5085  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "detected-partial-speech");
5086 
5087  if (headers) {
5088  switch_event_merge(event, headers);
5089  }
5090 
5091  switch_event_add_body(event, "%s", xmlstr);
5092  } else {
5093  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "begin-speaking");
5094  }
5095 
5097  switch_event_t *dup;
5098 
5099  if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {
5100  switch_channel_event_set_data(channel, dup);
5101  switch_event_fire(&dup);
5102  }
5103 
5104  }
5105 
5107  switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Event queue failed!\n");
5108  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
5109  switch_event_fire(&event);
5110  }
5111  }
5112 
5113  switch_safe_free(xmlstr);
5114 
5115  if (headers) {
5116  switch_event_destroy(&headers);
5117  }
5118  }
5119  }
5120  done:
5121 
5123  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "closed");
5125  switch_event_t *dup;
5126 
5127  if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {
5128  switch_channel_event_set_data(channel, dup);
5129  switch_event_fire(&dup);
5130  }
5131 
5132  }
5133 
5135  switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Event queue failed!\n");
5136  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
5137  switch_event_fire(&event);
5138  }
5139  }
5140 
5141  switch_mutex_unlock(sth->mutex);
5143 
5144  return NULL;
5145 }
5146 
5148 {
5149  struct speech_thread_handle *sth = (struct speech_thread_handle *) user_data;
5150  uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE];
5151  switch_frame_t frame = { 0 };
5153 
5154  frame.data = data;
5156 
5157  switch (type) {
5158  case SWITCH_ABC_TYPE_INIT:
5159  {
5160  switch_threadattr_t *thd_attr = NULL;
5161 
5162  switch_threadattr_create(&thd_attr, sth->pool);
5164  switch_thread_create(&sth->thread, thd_attr, speech_thread, sth, sth->pool);
5165  }
5166  break;
5167  case SWITCH_ABC_TYPE_CLOSE:
5168  {
5169  switch_status_t st;
5172 
5174  switch_core_event_hook_remove_recv_dtmf(session, speech_on_dtmf);
5175 
5176  switch_core_asr_close(sth->ah, &flags);
5177  if (sth->mutex && sth->cond && sth->ready) {
5180  switch_mutex_unlock(sth->mutex);
5181  }
5182  }
5183 
5184  switch_thread_join(&st, sth->thread);
5185 
5186  }
5187  break;
5188  case SWITCH_ABC_TYPE_READ:
5189  if (sth->ah) {
5191  if (switch_core_asr_feed(sth->ah, frame.data, frame.datalen, &flags) != SWITCH_STATUS_SUCCESS) {
5193  return SWITCH_FALSE;
5194  }
5196  if (sth->mutex && sth->cond && sth->ready) {
5197  switch_mutex_lock(sth->mutex);
5199  switch_mutex_unlock(sth->mutex);
5200  }
5201  }
5202  }
5203  }
5204  break;
5205  case SWITCH_ABC_TYPE_WRITE:
5206  default:
5207  break;
5208  }
5209 
5210  return SWITCH_TRUE;
5211 }
5212 
5214 {
5219 
5220  if (sth) {
5221  if (switch_core_asr_feed_dtmf(sth->ah, dtmf, &flags) != SWITCH_STATUS_SUCCESS) {
5222  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error Feeding DTMF\n");
5223  }
5224  }
5225 
5226  return status;
5227 }
5228 
5230 {
5232  struct speech_thread_handle *sth;
5233 
5234  switch_assert(channel != NULL);
5235  if ((sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY))) {
5237  switch_core_event_hook_remove_recv_dtmf(session, speech_on_dtmf);
5238  switch_core_media_bug_remove(session, &sth->bug);
5239  return SWITCH_STATUS_SUCCESS;
5240  }
5241 
5242  return SWITCH_STATUS_FALSE;
5243 }
5244 
5246 {
5249 
5250  if (sth) {
5251  switch_core_asr_pause(sth->ah);
5252  return SWITCH_STATUS_SUCCESS;
5253  }
5254  return SWITCH_STATUS_FALSE;
5255 }
5256 
5258 {
5261 
5262  if (sth) {
5263  switch_channel_audio_sync(channel);
5264  switch_core_asr_resume(sth->ah);
5265  return SWITCH_STATUS_SUCCESS;
5266  }
5267  return SWITCH_STATUS_FALSE;
5268 }
5269 
5271 {
5274  switch_status_t status;
5275 
5276  if (sth) {
5277  if ((status = switch_core_asr_load_grammar(sth->ah, grammar, name)) != SWITCH_STATUS_SUCCESS) {
5278  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Error loading Grammar\n");
5280  }
5281  return status;
5282  }
5283  return SWITCH_STATUS_FALSE;
5284 }
5285 
5287 {
5290 
5291  if (sth && sth->ah && name && val) {
5292  switch_core_asr_text_param(sth->ah, (char *) name, val);
5293  status = SWITCH_STATUS_SUCCESS;
5294  }
5295 
5296  return status;
5297 }
5298 
5300 {
5303 
5304  if (sth) {
5306  return SWITCH_STATUS_SUCCESS;
5307  }
5308  return SWITCH_STATUS_FALSE;
5309 }
5310 
5312 {
5315  switch_status_t status;
5316 
5317  if (sth) {
5318  if ((status = switch_core_asr_unload_grammar(sth->ah, name)) != SWITCH_STATUS_SUCCESS) {
5319  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Error unloading Grammar\n");
5321  }
5322  return status;
5323  }
5324  return SWITCH_STATUS_FALSE;
5325 }
5326 
5328 {
5331  switch_status_t status;
5332 
5333  if (sth) {
5334  if ((status = switch_core_asr_enable_grammar(sth->ah, name)) != SWITCH_STATUS_SUCCESS) {
5335  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Error enabling Grammar\n");
5337  }
5338  return status;
5339  }
5340  return SWITCH_STATUS_FALSE;
5341 }
5342 
5344 {
5347  switch_status_t status;
5348 
5349  if (sth) {
5350  if ((status = switch_core_asr_disable_grammar(sth->ah, name)) != SWITCH_STATUS_SUCCESS) {
5351  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Error disabling Grammar\n");
5353  }
5354  return status;
5355  }
5356  return SWITCH_STATUS_FALSE;
5357 }
5358 
5360 {
5363  switch_status_t status;
5364 
5365  if (sth) {
5367  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Error disabling all Grammars\n");
5369  }
5370  return status;
5371  }
5372  return SWITCH_STATUS_FALSE;
5373 }
5374 
5376  const char *dest, switch_asr_handle_t *ah)
5377 {
5379  switch_status_t status;
5382  switch_codec_implementation_t read_impl = { 0 };
5383  const char *p;
5384  char key[512] = "";
5385 
5386  if (sth) {
5387  /* Already initialized */
5388  return SWITCH_STATUS_SUCCESS;
5389  }
5390 
5391  if (!ah) {
5392  if (!(ah = switch_core_session_alloc(session, sizeof(*ah)))) {
5393  return SWITCH_STATUS_MEMERR;
5394  }
5395  }
5396 
5397  switch_core_session_get_read_impl(session, &read_impl);
5398 
5399  if ((status = switch_core_asr_open(ah,
5400  mod_name,
5401  "L16",
5402  read_impl.actual_samples_per_second, dest, &flags,
5404  return status;
5405  }
5406 
5407  sth = switch_core_session_alloc(session, sizeof(*sth));
5408  sth->pool = switch_core_session_get_pool(session);
5409  sth->session = session;
5410  sth->ah = ah;
5411 
5412  if ((p = switch_channel_get_variable(channel, "fire_asr_events")) && switch_true(p)) {
5414  }
5415 
5416  switch_snprintf(key, sizeof(key), "%s/%s/%s/%s", mod_name, NULL, NULL, dest);
5417 
5418  if ((status = switch_core_media_bug_add(session, "detect_speech", key,
5420  switch_core_asr_close(ah, &flags);
5421  return status;
5422  }
5423 
5424  if ((status = switch_core_event_hook_add_recv_dtmf(session, speech_on_dtmf)) != SWITCH_STATUS_SUCCESS) {
5426  return status;
5427  }
5428 
5430 
5431  return SWITCH_STATUS_SUCCESS;
5432 }
5433 
5435 {
5437  switch_event_t *event, *cevent;
5438  const char *variable_prefix = "asr_json_param_";
5440 
5441  switch_core_get_variables(&event);
5442  switch_channel_get_variables(channel, &cevent);
5443  switch_event_merge(event, cevent);
5444 
5445  for (hp = event->headers; hp; hp = hp->next) {
5446  char *var = hp->name;
5447  char *val = hp->value;
5448 
5449  if (!strncasecmp(var, variable_prefix, strlen(variable_prefix)) && !zstr(val)) {
5450  char *json_var = var + strlen(variable_prefix);
5451 
5452  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "setting json param %s = %s\n", json_var, val);
5453  switch_core_asr_text_param(ah, json_var, val);
5454  }
5455  }
5456 
5457  switch_event_destroy(&event);
5458  switch_event_destroy(&cevent);
5459 }
5460 
5462  const char *mod_name,
5463  const char *grammar, const char *name, const char *dest, switch_asr_handle_t *ah)
5464 {
5467  const char *p;
5468  int resume = 0;
5469 
5470 
5471  if (!sth) {
5472  /* No speech thread handle available yet, init speech detection first. */
5473  if (switch_ivr_detect_speech_init(session, mod_name, dest, ah) != SWITCH_STATUS_SUCCESS) {
5475  }
5476 
5477  /* Fetch the new speech thread handle */
5478  if (!(sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY))) {
5480  }
5481  } else {
5482  resume = 1;
5483  }
5484 
5485  asr_set_json_text_params(session, sth->ah);
5486 
5487  if (switch_core_asr_load_grammar(sth->ah, grammar, name) != SWITCH_STATUS_SUCCESS) {
5488  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Error loading Grammar\n");
5490  return SWITCH_STATUS_FALSE;
5491  }
5492 
5493  if (resume) {
5495  }
5496 
5497  if ((p = switch_channel_get_variable(channel, "fire_asr_events")) && switch_true(p)) {
5499  }
5500 
5501  return SWITCH_STATUS_SUCCESS;
5502 }
5503 
5505  char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
5508 };
5509 
5510 SWITCH_STANDARD_SCHED_FUNC(sch_hangup_callback)
5511 {
5512  struct hangup_helper *helper;
5513  switch_core_session_t *session, *other_session;
5514 
5515  switch_assert(task);
5516 
5517  helper = (struct hangup_helper *) task->cmd_arg;
5518 
5519  if ((session = switch_core_session_locate(helper->uuid_str))) {
5521 
5522  if (helper->bleg) {
5523  if (SWITCH_STATUS_SUCCESS == switch_core_session_get_partner(session, &other_session)) {
5524  switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
5525  switch_channel_hangup(other_channel, helper->cause);
5526  switch_core_session_rwunlock(other_session);
5527  } else {
5528  switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "No channel to hangup\n");
5529  }
5530  } else {
5531  switch_channel_hangup(channel, helper->cause);
5532  }
5533 
5535  }
5536 }
5537 
5539 {
5540  struct hangup_helper *helper;
5541  size_t len = sizeof(*helper);
5542 
5543  switch_zmalloc(helper, len);
5544 
5545  switch_copy_string(helper->uuid_str, uuid, sizeof(helper->uuid_str));
5546  helper->cause = cause;
5547  helper->bleg = bleg;
5548 
5549  return switch_scheduler_add_task(runtime, sch_hangup_callback, (char *) __SWITCH_FUNC__, uuid, 0, helper, SSHF_FREE_ARG);
5550 }
5551 
5553  char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
5554  char *extension;
5555  char *dialplan;
5556  char *context;
5557 };
5558 
5559 SWITCH_STANDARD_SCHED_FUNC(sch_transfer_callback)
5560 {
5561  struct transfer_helper *helper;
5562  switch_core_session_t *session;
5563 
5564  switch_assert(task);
5565 
5566  helper = (struct transfer_helper *) task->cmd_arg;
5567 
5568  if ((session = switch_core_session_locate(helper->uuid_str))) {
5569  switch_ivr_session_transfer(session, helper->extension, helper->dialplan, helper->context);
5571  }
5572 
5573 }
5574 
5575 SWITCH_DECLARE(uint32_t) switch_ivr_schedule_transfer(time_t runtime, const char *uuid, char *extension, char *dialplan, char *context)
5576 {
5577  struct transfer_helper *helper;
5578  size_t len = sizeof(*helper);
5579  char *cur = NULL;
5580 
5581  if (extension) {
5582  len += strlen(extension) + 1;
5583  }
5584 
5585  if (dialplan) {
5586  len += strlen(dialplan) + 1;
5587  }
5588 
5589  if (context) {
5590  len += strlen(context) + 1;
5591  }
5592 
5593  switch_zmalloc(cur, len);
5594  helper = (struct transfer_helper *) cur;
5595 
5596  switch_copy_string(helper->uuid_str, uuid, sizeof(helper->uuid_str));
5597 
5598  cur += sizeof(*helper);
5599 
5600  if (extension) {
5601  switch_copy_string(cur, extension, strlen(extension) + 1);
5602  helper->extension = cur;
5603  cur += strlen(helper->extension) + 1;
5604  }
5605 
5606  if (dialplan) {
5607  switch_copy_string(cur, dialplan, strlen(dialplan) + 1);
5608  helper->dialplan = cur;
5609  cur += strlen(helper->dialplan) + 1;
5610  }
5611 
5612  if (context) {
5613  switch_copy_string(cur, context, strlen(context) + 1);
5614  helper->context = cur;
5615  }
5616 
5617  return switch_scheduler_add_task(runtime, sch_transfer_callback, (char *) __SWITCH_FUNC__, uuid, 0, helper, SSHF_FREE_ARG);
5618 }
5619 
5621  char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
5622  char *path;
5624 };
5625 
5626 SWITCH_STANDARD_SCHED_FUNC(sch_broadcast_callback)
5627 {
5628  struct broadcast_helper *helper;
5629  switch_assert(task);
5630 
5631  helper = (struct broadcast_helper *) task->cmd_arg;
5632  switch_ivr_broadcast(helper->uuid_str, helper->path, helper->flags);
5633 }
5634 
5635 SWITCH_DECLARE(uint32_t) switch_ivr_schedule_broadcast(time_t runtime, const char *uuid, const char *path, switch_media_flag_t flags)
5636 {
5637  struct broadcast_helper *helper;
5638  size_t len = sizeof(*helper) + strlen(path) + 1;
5639  char *cur = NULL;
5640 
5641  switch_zmalloc(cur, len);
5642  helper = (struct broadcast_helper *) cur;
5643 
5644  cur += sizeof(*helper);
5645  switch_copy_string(helper->uuid_str, uuid, sizeof(helper->uuid_str));
5646  helper->flags = flags;
5647 
5648  switch_copy_string(cur, path, len - sizeof(*helper));
5649  helper->path = cur;
5650 
5651  return switch_scheduler_add_task(runtime, sch_broadcast_callback, (char *) __SWITCH_FUNC__, uuid, 0, helper, SSHF_FREE_ARG);
5652 }
5653 
5655 {
5656  switch_channel_t *channel;
5657  switch_core_session_t *session;
5658  switch_event_t *event;
5659  switch_core_session_t *other_session = NULL;
5660  const char *other_uuid = NULL;
5661  char *app = "playback";
5662  char *cause = NULL;
5663  char *mypath;
5664  char *p;
5665  int app_flags = 0, nomedia = 0;
5666 
5667  switch_assert(path);
5668 
5669  if (!(session = switch_core_session_locate(uuid))) {
5670  return SWITCH_STATUS_FALSE;
5671  }
5672 
5673  channel = switch_core_session_get_channel(session);
5674 
5675  mypath = strdup(path);
5676  switch_assert(mypath);
5677 
5678  if ((p = strchr(mypath, ':')) && *(p + 1) == ':') {
5679  app = mypath;
5680  *p++ = '\0';
5681  *p++ = '\0';
5682  path = p;
5683  }
5684 
5685  if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
5686  nomedia = 1;
5688  }
5689 
5690  if ((cause = strchr(app, '!'))) {
5691  *cause++ = '\0';
5692  if (!*cause) {
5693  cause = "normal_clearing";
5694  }
5695  }
5696 
5697  if ((flags & SMF_ECHO_BLEG) && (other_uuid = switch_channel_get_partner_uuid(channel))
5698  && (other_session = switch_core_session_locate(other_uuid))) {
5699  if ((flags & SMF_EXEC_INLINE)) {
5700  switch_core_session_execute_application_get_flags(other_session, app, path, &app_flags);
5701  nomedia = 0;
5702  } else {
5703  switch_core_session_get_app_flags(app, &app_flags);
5705  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
5706  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-name", app);
5707  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-arg", path);
5708  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, (flags & SMF_PRIORITY) ? "event-lock-pri" : "event-lock", "true");
5709 
5710  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "lead-frames", "%d", 5);
5711 
5712  if ((flags & SMF_LOOP)) {
5713  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "loops", "%d", -1);
5714  }
5715 
5716  if ((flags & SMF_HOLD_BLEG)) {
5717  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "hold-bleg", "true");
5718  }
5719 
5720  switch_core_session_queue_private_event(other_session, &event, (flags & SMF_PRIORITY));
5721  }
5722  }
5723 
5724  switch_core_session_rwunlock(other_session);
5725  other_session = NULL;
5726  }
5727 
5728  if ((app_flags & SAF_MEDIA_TAP)) {
5729  nomedia = 0;
5730  }
5731 
5732  if ((flags & SMF_ECHO_ALEG)) {
5733  if ((flags & SMF_EXEC_INLINE)) {
5734  switch_core_session_execute_application(session, app, path);
5735  } else {
5737  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
5738  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-name", app);
5739  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-arg", path);
5740  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, (flags & SMF_PRIORITY) ? "event-lock-pri" : "event-lock", "true");
5741  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "lead-frames", "%d", 5);
5742 
5743  if ((flags & SMF_LOOP)) {
5744  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "loops", "%d", -1);
5745  }
5746  if ((flags & SMF_HOLD_BLEG)) {
5747  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "hold-bleg", "true");
5748  }
5749 
5750  switch_core_session_queue_private_event(session, &event, (flags & SMF_PRIORITY));
5751 
5752  if (nomedia)
5754  }
5755  }
5756  }
5757 
5758  if (cause) {
5760  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
5761  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-name", "hangup");
5762  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-arg", cause);
5763  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, (flags & SMF_PRIORITY) ? "event-lock-pri" : "event-lock", "true");
5764  switch_core_session_queue_private_event(session, &event, (flags & SMF_PRIORITY));
5765  }
5766  }
5767 
5769  switch_safe_free(mypath);
5770 
5771  return SWITCH_STATUS_SUCCESS;
5772 }
5773 
5774 
5775 typedef struct oht_s {
5778  uint8_t alpha;
5779 } overly_helper_t;
5780 
5782 {
5783  overly_helper_t *oht = (overly_helper_t *) user_data;
5786 
5787  switch (type) {
5788  case SWITCH_ABC_TYPE_INIT:
5789  {
5790  }
5791  break;
5792  case SWITCH_ABC_TYPE_CLOSE:
5793  {
5794  switch_img_free(&oht->img);
5795  }
5796  break;
5800  int x = 0, y = 0;
5801  switch_image_t *oimg = NULL;
5802 
5803  if (frame->img && oht->img) {
5804  switch_img_copy(oht->img, &oimg);
5805  switch_img_fit(&oimg, frame->img->d_w, frame->img->d_h, SWITCH_FIT_SIZE);
5806  switch_img_find_position(oht->pos, frame->img->d_w, frame->img->d_h, oimg->d_w, oimg->d_h, &x, &y);
5807  switch_img_overlay(frame->img, oimg, x, y, oht->alpha);
5808  //switch_img_patch(frame->img, oimg, x, y);
5809  switch_img_free(&oimg);
5810  }
5811  }
5812  break;
5813  default:
5814  break;
5815  }
5816 
5817  return SWITCH_TRUE;
5818 }
5819 
5820 
5822 {
5824  switch_media_bug_t *bug = switch_channel_get_private(channel, "_video_write_overlay_bug_");
5825 
5826  if (bug) {
5827  switch_channel_set_private(channel, "_video_write_overlay_bug_", NULL);
5828  switch_core_media_bug_remove(session, &bug);
5829  return SWITCH_STATUS_SUCCESS;
5830  }
5831 
5832  return SWITCH_STATUS_FALSE;
5833 }
5834 
5836  switch_img_position_t pos, uint8_t alpha)
5837 {
5839  switch_status_t status;
5841  switch_media_bug_t *bug;
5842  overly_helper_t *oht;
5843  switch_image_t *img;
5844 
5845  bflags |= SMBF_NO_PAUSE;
5846 
5847  if (switch_channel_get_private(channel, "_video_write_overlay_bug_")) {
5848  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Only one of this type of bug per channel\n");
5849  return SWITCH_STATUS_FALSE;
5850  }
5851 
5852  if (!(img = switch_img_read_png(img_path, SWITCH_IMG_FMT_ARGB))) {
5853  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening file: %s\n", img_path);
5854  return SWITCH_STATUS_FALSE;
5855  }
5856 
5857  oht = switch_core_session_alloc(session, sizeof(*oht));
5858  oht->img = img;
5859  oht->pos = pos;
5860  oht->alpha = alpha;
5861 
5862  if ((status = switch_core_media_bug_add(session, "video_write_overlay", NULL,
5863  video_write_overlay_callback, oht, 0, bflags, &bug)) != SWITCH_STATUS_SUCCESS) {
5864 
5865  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating bug, file: %s\n", img_path);
5866  switch_img_free(&oht->img);
5867  return status;
5868  }
5869 
5870  switch_channel_set_private(channel, "_video_write_overlay_bug_", bug);
5871 
5872  return SWITCH_STATUS_SUCCESS;
5873 }
5874 
5875 /* For Emacs:
5876  * Local Variables:
5877  * mode:c
5878  * indent-tabs-mode:t
5879  * tab-width:4
5880  * c-basic-offset:4
5881  * End:
5882  * For VIM:
5883  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
5884  */
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:318
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:311
#define switch_event_fire(event)
Fire an event filling in most of the arguements with obvious values.
Definition: switch_event.h:413
#define switch_channel_hangup(channel, hangup_cause)
Hangup a channel flagging it&#39;s state machine to end.
#define switch_regex_safe_free(re)
Definition: switch_regex.h:79
#define switch_core_media_gen_key_frame(_session)
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&#39;s master pool.
Definition: switch_core.h:633
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_file_pre_close(_In_ switch_file_handle_t *fh)
Pre close an open file handle, then can get file size etc., no more wirte to the file.
switch_status_t switch_core_asr_start_input_timers(switch_asr_handle_t *ah)
Start input timers on an asr handle.
uint8_t thread_needs_transfer
switch_input_args_t * original_args
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:373
switch_mutex_t * read_mutex
static switch_bool_t switch_true(const char *expr)
Evaluate the truthfullness of a string expression.
Definition: switch_utils.h:519
#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:700
#define SWITCH_THREAD_FUNC
switch_abc_type_t
Definition: switch_types.h:516
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_status_t switch_mutex_destroy(switch_mutex_t *lock)
Definition: switch_apr.c:303
switch_core_session_message_types_t message_id
Definition: switch_core.h:183
#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:318
switch_status_t switch_core_hash_destroy(_Inout_ switch_hash_t **hash)
Destroy an existing hash table.
const char *const const double number
Definition: switch_cJSON.h:254
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:796
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_channel_execute_on_value(switch_channel_t *channel, const char *variable_value)
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:1431
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)
void switch_perform_substitution(switch_regex_t *re, int match_count, const char *data, const char *field_data, char *substituted, switch_size_t len, int *ovector)
Definition: switch_regex.c:131
#define switch_core_file_open(_fh, _file_path, _channels, _rate, _flags, _pool)
Open a media file using file format modules.
Definition: switch_core.h:1963
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]
switch_mutex_t * cond_mutex
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_buffer_t * wbuffer
SWITCH_STANDARD_SCHED_FUNC(sch_hangup_callback)
static void deliver_asr_event(switch_core_session_t *session, switch_event_t *event, switch_input_args_t *args)
struct oht_s overly_helper_t
#define switch_channel_up(_channel)
#define SWITCH_RECORD_POST_PROCESS_EXEC_APP_VARIABLE
Definition: switch_types.h:147
switch_memory_pool_t * helper_pool
#define SWITCH_RECOMMENDED_BUFFER_SIZE
Definition: switch_types.h:590
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.
cJSON *const to
switch_bool_t
Definition: switch_types.h:437
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:733
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:126
const cJSON *const b
Definition: switch_cJSON.h:243
void switch_core_media_bug_set_media_params(switch_media_bug_t *bug, switch_mm_t *mm)
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:683
void switch_core_session_raw_read(switch_core_session_t *session)
static switch_status_t record_helper_destroy(struct record_helper **rh, 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:642
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_core_file_get_string(_In_ switch_file_handle_t *fh, switch_audio_col_t col, const char **string)
get metadata of the desired string
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.
switch_thread_cond_t * cond
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)
An event Header.
Definition: switch_event.h:65
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:1264
#define SWITCH_PLAYBACK_TERMINATOR_USED
Definition: switch_types.h:187
switch_digit_action_target_t
Definition: switch_types.h:283
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 uint32_t switch_gcd(uint32_t x, uint32_t y)
static switch_bool_t is_silence_frame(switch_frame_t *frame, int silence_threshold, switch_codec_implementation_t *codec_impl)
static void asr_set_json_text_params(switch_core_session_t *session, switch_asr_handle_t *ah)
switch_status_t switch_core_session_get_real_read_impl(switch_core_session_t *session, switch_codec_implementation_t *impp)
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:378
const char * string_array_arg[MESSAGE_STRING_ARG_MAX]
Definition: switch_core.h:211
switch_time_t last_write_time
#define switch_core_session_get_name(_s)
Definition: switch_core.h:265
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:298
struct real_pcre switch_regex_t
Definition: switch_regex.h:43
#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:913
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&#39;s remote end.
Definition: switch_ivr.c:1773
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:486
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:86
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_core_session_t * recording_session
switch_status_t switch_core_file_handle_dup(switch_file_handle_t *oldfh, switch_file_handle_t **newfh, switch_memory_pool_t *pool)
Duplicates a file handle using another pool.
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
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:56
A message object designed to allow unlike technologies to exchange data.
Definition: switch_core.h:179
switch_status_t switch_ivr_unblock_dtmf_session(switch_core_session_t *session)
uint8_t switch_byte_t
Definition: switch_types.h:256
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:314
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:452
switch_buffer_t * thread_buffer
uint32_t switch_core_max_dtmf_duration(uint32_t duration)
Definition: switch_core.c:1704
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.
const char * switch_core_media_bug_get_text(switch_media_bug_t *bug)
#define SWITCH_SPEECH_KEY
Definition: switch_types.h:233
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:683
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:313
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_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:1129
_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.
switch_status_t switch_ivr_dmachine_bind(switch_ivr_dmachine_t *dmachine, const char *realm, const char *digits, switch_byte_t is_priority, int32_t key, switch_ivr_dmachine_callback_t callback, void *user_data)
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:724
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:124
switch_status_t switch_threadattr_detach_set(switch_threadattr_t *attr, int32_t on)
Definition: switch_apr.c:678
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:70
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)
if((uint32_t)(unpack->cur - unpack->buf) > unpack->buflen)
switch_status_t switch_core_get_variables(switch_event_t **event)
Definition: switch_core.c:386
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:998
#define switch_channel_audio_sync(_c)
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
static void exec_app(switch_core_session_t *session, char *app_str)
uint32_t datalen
Definition: switch_frame.h:68
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
static switch_status_t record_helper_create(struct record_helper **rh, switch_core_session_t *session)
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:308
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:867
switch_status_t switch_ivr_stop_detect_speech(switch_core_session_t *session)
Stop background Speech detection on a session.
#define switch_core_session_request_video_refresh(_s)
Definition: switch_core.h:2881
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:684
switch_status_t switch_ivr_record_session_event(switch_core_session_t *session, const char *file, uint32_t limit, switch_file_handle_t *fh, switch_event_t *vars)
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:74
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
int index
Definition: switch_cJSON.h:160
#define SWITCH_THREAD_STACKSIZE
Definition: switch_types.h:584
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:885
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_capture_text(switch_core_session_t *session, switch_bool_t on)
switch_status_t switch_ivr_preprocess_session(switch_core_session_t *session, const char *cmds)
switch_input_callback_function_t input_callback
switch_status_t switch_channel_get_variables(switch_channel_t *channel, switch_event_t **event)
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:293
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_status_t switch_thread_join(switch_status_t *retval, switch_thread_t *thd)
Definition: switch_apr.c:1379
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:54
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:1693
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:1028
uint32_t switch_eavesdrop_flag_t
Definition: switch_types.h:358
dm_match_t
switch_status_t switch_ivr_record_session_pause(switch_core_session_t *session, const char *file, switch_bool_t on)
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_core_get_variable(_In_z_ const char *varname)
Retrieve a global variable from the core.
int switch_regex_perform(const char *field, const char *expression, switch_regex_t **new_re, int *ovector, uint32_t olen)
Definition: switch_regex.c:55
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.
int32_t switch_fileperms_t
Definition: switch_apr.h:687
switch_call_cause_t
switch_dtmf_direction_t
Definition: switch_types.h:320
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:1247
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:82
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_read_frame_callback_function_t read_frame_callback
switch_mutex_t * mutex
switch_media_bug_flag_enum_t
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:993
static void record_helper_post_process(struct record_helper *rh, switch_core_session_t *session)
static char switch_itodtmf(char i)
Definition: switch_utils.h:450
struct fspr_thread_mutex_t switch_mutex_t
Definition: switch_apr.h:314
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
static void merge_recording_variables(struct record_helper *rh, switch_event_t *event)
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:394
static int switch_channel_var_true(switch_channel_t *channel, const char *variable)
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:120
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:1721
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_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.
#define switch_event_safe_destroy(_event)
Definition: switch_event.h:219
switch_bool_t speech_detected
switch_status_t switch_ivr_stop_video_write_overlay_session(switch_core_session_t *session)
switch_image_t * img
Definition: switch_frame.h:88
static int recording_var_true(switch_channel_t *channel, switch_event_t *vars, const char *name)
#define SWITCH_SIZE_T_FMT
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.
static const char * get_recording_var(switch_channel_t *channel, switch_event_t *vars, const char *name)
switch_status_t(* switch_ivr_dmachine_callback_t)(switch_ivr_dmachine_match_t *match)
const char *const const char *const path
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
#define switch_goto_status(_status, _label)
Definition: switch_utils.h:287
const cJSON *const target
switch_bool_t(* switch_tone_detect_callback_t)(switch_core_session_t *, const char *, const char *)
uint8_t transfer_complete
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]
struct switch_event_header * next
Definition: switch_event.h:76
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_event_t * variables
switch_status_t switch_dir_make_recursive(const char *path, switch_fileperms_t perm, switch_memory_pool_t *pool)
Definition: switch_apr.c:551
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.
#define switch_core_hash_insert(_h, _k, _d)
Definition: switch_core.h:1479
void switch_buffer_unlock(_In_ switch_buffer_t *buffer)
#define switch_core_session_locate(uuid_str)
Locate a session based on it&#39;s uuid.
Definition: switch_core.h:932
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:384
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:72
struct fspr_thread_cond_t switch_thread_cond_t
Definition: switch_apr.h:463
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:76
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:154
#define switch_set_string(_dst, _src)
Definition: switch_utils.h:734
switch_status_t switch_queue_trypush(switch_queue_t *queue, void *data)
Definition: switch_apr.c:1279
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_ping(switch_ivr_dmachine_t *dmachine, switch_ivr_dmachine_match_t **match_p)
#define switch_channel_media_ack(_channel)
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:322
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:186
#define switch_core_session_alloc(_session, _memory)
Allocate memory from a session&#39;s pool.
Definition: switch_core.h:696
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:463
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:509
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:693
switch_dtmf_source_t source
Definition: switch_types.h:300
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.
#define SWITCH_VA_NONE
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:665
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:698
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:378
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:292
#define switch_ivr_phrase_macro(session, macro_name, data, lang, args)
Definition: switch_ivr.h:936
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)
int count
Definition: switch_cJSON.h:204
struct fspr_pool_t switch_memory_pool_t
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
const char *const name
Definition: switch_cJSON.h:250
#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:1233
#define switch_core_session_strdup(_session, _todup)
Copy a string using memory allocation from a session&#39;s pool.
Definition: switch_core.h:719
switch_mutex_t * mutex
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)
switch_core_session_t * transfer_from_session
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:148
int switch_channel_test_app_flag_key(const char *app, switch_channel_t *channel, uint32_t flags)
char * switch_core_sprintf(_In_ switch_memory_pool_t *pool, _In_z_ _Printf_format_string_ const char *fmt,...)
printf-style style printing routine. The data is output to a string allocated from the pool ...
void switch_ivr_dmachine_destroy(switch_ivr_dmachine_t **dmachine)
#define switch_assert(expr)
struct fspr_thread_t switch_thread_t
Definition: switch_apr.h:941
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:325
switch_status_t switch_ivr_record_session(switch_core_session_t *session, const char *file, uint32_t limit, switch_file_handle_t *fh)
Record a session to disk.
static switch_bool_t text_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
#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&#39;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.
static uint32_t switch_lcm(uint32_t x, uint32_t y)
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)
switch_media_bug_t * bug
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:166
#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:300
#define SWITCH_DEFAULT_FILE_BUFFER_LEN
Definition: switch_types.h:236
switch_event_header_t * headers
Definition: switch_event.h:90
switch_ivr_dmachine_t * dmachine
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
switch_status_t switch_threadattr_priority_set(switch_threadattr_t *attr, switch_thread_priority_t priority)
Definition: switch_apr.c:688