Bug Summary

File:src/switch_ivr_async.c
Location:line 3511, column 3
Description:Value stored to 'status' is never read

Annotated Source Code

1/*
2 * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3 * Copyright (C) 2005-2014, 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>
37#include <speex/speex_preprocess.h>
38#include <speex/speex_echo.h>
39
40struct switch_ivr_dmachine_binding {
41 char *digits;
42 int32_t key;
43 uint8_t rmatch;
44 switch_ivr_dmachine_callback_t callback;
45 switch_byte_t is_regex;
46 void *user_data;
47 struct switch_ivr_dmachine_binding *next;
48};
49typedef struct switch_ivr_dmachine_binding switch_ivr_dmachine_binding_t;
50
51typedef struct {
52 switch_ivr_dmachine_binding_t *binding_list;
53 switch_ivr_dmachine_binding_t *tail;
54 char *name;
55 char *terminators;
56} dm_binding_head_t;
57
58struct switch_ivr_dmachine {
59 switch_memory_pool_t *pool;
60 switch_byte_t my_pool;
61 char *name;
62 uint32_t digit_timeout_ms;
63 uint32_t input_timeout_ms;
64 switch_hash_t *binding_hash;
65 switch_ivr_dmachine_match_t match;
66 switch_digit_action_target_t target;
67 char digits[DMACHINE_MAX_DIGIT_LEN512];
68 char last_matching_digits[DMACHINE_MAX_DIGIT_LEN512];
69 char last_failed_digits[DMACHINE_MAX_DIGIT_LEN512];
70 uint32_t cur_digit_len;
71 uint32_t max_digit_len;
72 switch_time_t last_digit_time;
73 switch_byte_t is_match;
74 switch_ivr_dmachine_callback_t match_callback;
75 switch_ivr_dmachine_callback_t nonmatch_callback;
76 dm_binding_head_t *realm;
77 switch_ivr_dmachine_binding_t *last_matching_binding;
78 void *user_data;
79 switch_mutex_t *mutex;
80 switch_status_t last_return;
81};
82
83
84SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_dmachine_last_ping(switch_ivr_dmachine_t *dmachine)
85{
86 return dmachine->last_return;
87}
88
89SWITCH_DECLARE(switch_digit_action_target_t)__attribute__((visibility("default"))) switch_digit_action_target_t switch_ivr_dmachine_get_target(switch_ivr_dmachine_t *dmachine)
90{
91 switch_assert(dmachine)((dmachine) ? (void) (0) : __assert_fail ("dmachine", "src/switch_ivr_async.c"
, 91, __PRETTY_FUNCTION__))
;
92 return dmachine->target;
93}
94
95SWITCH_DECLARE(void)__attribute__((visibility("default"))) void switch_ivr_dmachine_set_target(switch_ivr_dmachine_t *dmachine, switch_digit_action_target_t target)
96{
97 switch_assert(dmachine)((dmachine) ? (void) (0) : __assert_fail ("dmachine", "src/switch_ivr_async.c"
, 97, __PRETTY_FUNCTION__))
;
98 dmachine->target = target;
99}
100
101
102SWITCH_DECLARE(void)__attribute__((visibility("default"))) void switch_ivr_dmachine_set_match_callback(switch_ivr_dmachine_t *dmachine, switch_ivr_dmachine_callback_t match_callback)
103{
104
105 switch_assert(dmachine)((dmachine) ? (void) (0) : __assert_fail ("dmachine", "src/switch_ivr_async.c"
, 105, __PRETTY_FUNCTION__))
;
106 dmachine->match_callback = match_callback;
107
108}
109
110SWITCH_DECLARE(void)__attribute__((visibility("default"))) void switch_ivr_dmachine_set_nonmatch_callback(switch_ivr_dmachine_t *dmachine, switch_ivr_dmachine_callback_t nonmatch_callback)
111{
112
113 switch_assert(dmachine)((dmachine) ? (void) (0) : __assert_fail ("dmachine", "src/switch_ivr_async.c"
, 113, __PRETTY_FUNCTION__))
;
114 dmachine->nonmatch_callback = nonmatch_callback;
115
116}
117
118SWITCH_DECLARE(const char *)__attribute__((visibility("default"))) const char * switch_ivr_dmachine_get_name(switch_ivr_dmachine_t *dmachine)
119{
120 return (const char *) dmachine->name;
121}
122
123SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_dmachine_create(switch_ivr_dmachine_t **dmachine_p,
124 const char *name,
125 switch_memory_pool_t *pool,
126 uint32_t digit_timeout_ms,
127 uint32_t input_timeout_ms,
128 switch_ivr_dmachine_callback_t match_callback,
129 switch_ivr_dmachine_callback_t nonmatch_callback,
130 void *user_data)
131{
132 switch_byte_t my_pool = 0;
133 switch_ivr_dmachine_t *dmachine;
134
135 if (!pool) {
136 switch_core_new_memory_pool(&pool)switch_core_perform_new_memory_pool(&pool, "src/switch_ivr_async.c"
, (const char *)__func__, 136)
;
137 my_pool = 1;
138 }
139
140 dmachine = switch_core_alloc(pool, sizeof(*dmachine))switch_core_perform_alloc(pool, sizeof(*dmachine), "src/switch_ivr_async.c"
, (const char *)__func__, 140)
;
141 dmachine->pool = pool;
142 dmachine->my_pool = my_pool;
143 dmachine->digit_timeout_ms = digit_timeout_ms;
144 dmachine->input_timeout_ms = input_timeout_ms;
145 dmachine->match.dmachine = dmachine;
146 dmachine->name = switch_core_strdup(dmachine->pool, name)switch_core_perform_strdup(dmachine->pool, name, "src/switch_ivr_async.c"
, (const char *)__func__, 146)
;
147 switch_mutex_init(&dmachine->mutex, SWITCH_MUTEX_NESTED0x1, dmachine->pool);
148
149 switch_core_hash_init(&dmachine->binding_hash)switch_core_hash_init_case(&dmachine->binding_hash, SWITCH_TRUE
)
;
150
151 if (match_callback) {
152 dmachine->match_callback = match_callback;
153 }
154
155 if (nonmatch_callback) {
156 dmachine->nonmatch_callback = nonmatch_callback;
157 }
158
159 dmachine->user_data = user_data;
160
161 *dmachine_p = dmachine;
162
163 return SWITCH_STATUS_SUCCESS;
164}
165
166
167SWITCH_DECLARE(void)__attribute__((visibility("default"))) void switch_ivr_dmachine_set_digit_timeout_ms(switch_ivr_dmachine_t *dmachine, uint32_t digit_timeout_ms)
168{
169 dmachine->digit_timeout_ms = digit_timeout_ms;
170}
171
172SWITCH_DECLARE(void)__attribute__((visibility("default"))) void switch_ivr_dmachine_set_input_timeout_ms(switch_ivr_dmachine_t *dmachine, uint32_t input_timeout_ms)
173{
174 dmachine->input_timeout_ms = input_timeout_ms;
175}
176
177SWITCH_DECLARE(void)__attribute__((visibility("default"))) void switch_ivr_dmachine_destroy(switch_ivr_dmachine_t **dmachine)
178{
179 switch_memory_pool_t *pool;
180
181 if (!(dmachine && *dmachine)) return;
182
183 pool = (*dmachine)->pool;
184
185 switch_core_hash_destroy(&(*dmachine)->binding_hash);
186
187 if ((*dmachine)->my_pool) {
188 switch_core_destroy_memory_pool(&pool)switch_core_perform_destroy_memory_pool(&pool, "src/switch_ivr_async.c"
, (const char *)__func__, 188)
;
189 }
190}
191
192SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_dmachine_set_terminators(switch_ivr_dmachine_t *dmachine, const char *terminators)
193{
194 if (!dmachine->realm) {
195 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_async.c", (const char *
)__func__, 195, ((void*)0)
, SWITCH_LOG_ERROR, "No realm selected.\n");
196 return SWITCH_STATUS_FALSE;
197 }
198
199
200 dmachine->realm->terminators = switch_core_strdup(dmachine->pool, terminators)switch_core_perform_strdup(dmachine->pool, terminators, "src/switch_ivr_async.c"
, (const char *)__func__, 200)
;
201 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_async.c", (const char *
)__func__, 201, ((void*)0)
, SWITCH_LOG_INFO, "Digit parser %s: Setting terminators for realm '%s' to '%s'\n",
202 dmachine->name, dmachine->realm->name, terminators);
203
204 return SWITCH_STATUS_SUCCESS;
205}
206
207SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_dmachine_set_realm(switch_ivr_dmachine_t *dmachine, const char *realm)
208{
209 dm_binding_head_t *headp = switch_core_hash_find(dmachine->binding_hash, realm);
210
211 if (headp) {
212 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_async.c", (const char *
)__func__, 212, ((void*)0)
, SWITCH_LOG_INFO, "Digit parser %s: Setting realm to '%s'\n", dmachine->name, realm);
213 dmachine->realm = headp;
214 return SWITCH_STATUS_SUCCESS;
215 }
216
217 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_async.c", (const char *
)__func__, 217, ((void*)0)
, SWITCH_LOG_ERROR, "Digit parser %s: Error Setting realm to '%s'\n", dmachine->name, realm);
218
219 return SWITCH_STATUS_FALSE;
220}
221
222SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_dmachine_clear_realm(switch_ivr_dmachine_t *dmachine, const char *realm)
223{
224 dm_binding_head_t *headp;
225
226 if (zstr(realm)_zstr(realm)) {
227 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_async.c", (const char *
)__func__, 227, ((void*)0)
, SWITCH_LOG_ERROR, "Digit parser %s: Error unknown realm: '%s'\n", dmachine->name, realm);
228 return SWITCH_STATUS_FALSE;
229 }
230
231 headp = switch_core_hash_find(dmachine->binding_hash, realm);
232
233 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_async.c", (const char *
)__func__, 233, ((void*)0)
, SWITCH_LOG_INFO, "Digit parser %s: Clearing realm '%s'\n", dmachine->name, realm);
234
235 if (headp == dmachine->realm) {
236 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_async.c", (const char *
)__func__, 236, ((void*)0)
, SWITCH_LOG_WARNING,
237 "Digit parser %s: '%s' was the active realm, no realm currently selected.\n", dmachine->name, realm);
238 dmachine->realm = NULL((void*)0);
239 }
240
241 /* pool alloc'd just ditch it and it will give back the memory when we destroy ourselves */
242 switch_core_hash_delete(dmachine->binding_hash, realm);
243 return SWITCH_STATUS_SUCCESS;
244}
245
246SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_dmachine_bind(switch_ivr_dmachine_t *dmachine,
247 const char *realm,
248 const char *digits,
249 int32_t key,
250 switch_ivr_dmachine_callback_t callback,
251 void *user_data)
252{
253 switch_ivr_dmachine_binding_t *binding = NULL((void*)0), *ptr;
254 switch_size_t len;
255 dm_binding_head_t *headp;
256 const char *msg = "";
257
258 if (strlen(digits) > DMACHINE_MAX_DIGIT_LEN512 -1) {
259 return SWITCH_STATUS_FALSE;
260 }
261
262 if (zstr(realm)_zstr(realm)) {
263 realm = "default";
264 }
265
266 if (!(headp = switch_core_hash_find(dmachine->binding_hash, realm))) {
267 headp = switch_core_alloc(dmachine->pool, sizeof(*headp))switch_core_perform_alloc(dmachine->pool, sizeof(*headp), "src/switch_ivr_async.c"
, (const char *)__func__, 267)
;
268 headp->name = switch_core_strdup(dmachine->pool, realm)switch_core_perform_strdup(dmachine->pool, realm, "src/switch_ivr_async.c"
, (const char *)__func__, 268)
;
269 switch_core_hash_insert(dmachine->binding_hash, realm, headp)switch_core_hash_insert_destructor(dmachine->binding_hash,
realm, headp, ((void*)0))
;
270 }
271
272 for(ptr = headp->binding_list; ptr; ptr = ptr->next) {
273 if ((ptr->is_regex && !strcmp(ptr->digits, digits+1)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(ptr->digits) && __builtin_constant_p (digits+1) &&
(__s1_len = __builtin_strlen (ptr->digits), __s2_len = __builtin_strlen
(digits+1), (!((size_t)(const void *)((ptr->digits) + 1) -
(size_t)(const void *)(ptr->digits) == 1) || __s1_len >=
4) && (!((size_t)(const void *)((digits+1) + 1) - (size_t
)(const void *)(digits+1) == 1) || __s2_len >= 4)) ? __builtin_strcmp
(ptr->digits, digits+1) : (__builtin_constant_p (ptr->
digits) && ((size_t)(const void *)((ptr->digits) +
1) - (size_t)(const void *)(ptr->digits) == 1) &&
(__s1_len = __builtin_strlen (ptr->digits), __s1_len <
4) ? (__builtin_constant_p (digits+1) && ((size_t)(const
void *)((digits+1) + 1) - (size_t)(const void *)(digits+1) ==
1) ? __builtin_strcmp (ptr->digits, digits+1) : (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (digits+1); int __result = (((const unsigned char *)
(const char *) (ptr->digits))[0] - __s2[0]); if (__s1_len
> 0 && __result == 0) { __result = (((const unsigned
char *) (const char *) (ptr->digits))[1] - __s2[1]); if (
__s1_len > 1 && __result == 0) { __result = (((const
unsigned char *) (const char *) (ptr->digits))[2] - __s2[
2]); if (__s1_len > 2 && __result == 0) __result =
(((const unsigned char *) (const char *) (ptr->digits))[3
] - __s2[3]); } } __result; }))) : (__builtin_constant_p (digits
+1) && ((size_t)(const void *)((digits+1) + 1) - (size_t
)(const void *)(digits+1) == 1) && (__s2_len = __builtin_strlen
(digits+1), __s2_len < 4) ? (__builtin_constant_p (ptr->
digits) && ((size_t)(const void *)((ptr->digits) +
1) - (size_t)(const void *)(ptr->digits) == 1) ? __builtin_strcmp
(ptr->digits, digits+1) : (- (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (ptr->
digits); int __result = (((const unsigned char *) (const char
*) (digits+1))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (digits+1))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (digits+1))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (digits+1))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(ptr->digits, digits+1)))); })
) || !strcmp(ptr->digits, digits)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(ptr->digits) && __builtin_constant_p (digits) &&
(__s1_len = __builtin_strlen (ptr->digits), __s2_len = __builtin_strlen
(digits), (!((size_t)(const void *)((ptr->digits) + 1) - (
size_t)(const void *)(ptr->digits) == 1) || __s1_len >=
4) && (!((size_t)(const void *)((digits) + 1) - (size_t
)(const void *)(digits) == 1) || __s2_len >= 4)) ? __builtin_strcmp
(ptr->digits, digits) : (__builtin_constant_p (ptr->digits
) && ((size_t)(const void *)((ptr->digits) + 1) - (
size_t)(const void *)(ptr->digits) == 1) && (__s1_len
= __builtin_strlen (ptr->digits), __s1_len < 4) ? (__builtin_constant_p
(digits) && ((size_t)(const void *)((digits) + 1) - (
size_t)(const void *)(digits) == 1) ? __builtin_strcmp (ptr->
digits, digits) : (__extension__ ({ const unsigned char *__s2
= (const unsigned char *) (const char *) (digits); int __result
= (((const unsigned char *) (const char *) (ptr->digits))
[0] - __s2[0]); if (__s1_len > 0 && __result == 0)
{ __result = (((const unsigned char *) (const char *) (ptr->
digits))[1] - __s2[1]); if (__s1_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
ptr->digits))[2] - __s2[2]); if (__s1_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (ptr->digits))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
(digits) && ((size_t)(const void *)((digits) + 1) - (
size_t)(const void *)(digits) == 1) && (__s2_len = __builtin_strlen
(digits), __s2_len < 4) ? (__builtin_constant_p (ptr->
digits) && ((size_t)(const void *)((ptr->digits) +
1) - (size_t)(const void *)(ptr->digits) == 1) ? __builtin_strcmp
(ptr->digits, digits) : (- (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (ptr->
digits); int __result = (((const unsigned char *) (const char
*) (digits))[0] - __s2[0]); if (__s2_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
digits))[1] - __s2[1]); if (__s2_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
digits))[2] - __s2[2]); if (__s2_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (digits
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (ptr
->digits, digits)))); })
) {
274 msg = "Reuse Existing ";
275 binding = ptr;
276 binding->callback = callback;
277 binding->user_data = user_data;
278 goto done;
279 }
280 }
281
282
283 binding = switch_core_alloc(dmachine->pool, sizeof(*binding))switch_core_perform_alloc(dmachine->pool, sizeof(*binding)
, "src/switch_ivr_async.c", (const char *)__func__, 283)
;
284
285 if (*digits == '~') {
286 binding->is_regex = 1;
287 digits++;
288 }
289
290 binding->key = key;
291 binding->digits = switch_core_strdup(dmachine->pool, digits)switch_core_perform_strdup(dmachine->pool, digits, "src/switch_ivr_async.c"
, (const char *)__func__, 291)
;
292 binding->callback = callback;
293 binding->user_data = user_data;
294
295 if (headp->tail) {
296 headp->tail->next = binding;
297 } else {
298 headp->binding_list = binding;
299 }
300
301 headp->tail = binding;
302
303 len = strlen(digits);
304
305 if (dmachine->realm != headp) {
306 switch_ivr_dmachine_set_realm(dmachine, realm);
307 }
308
309 if (binding->is_regex && dmachine->max_digit_len != DMACHINE_MAX_DIGIT_LEN512 -1) {
310 dmachine->max_digit_len = DMACHINE_MAX_DIGIT_LEN512 -1;
311 } else if (len > dmachine->max_digit_len) {
312 dmachine->max_digit_len = (uint32_t) len;
313 }
314
315 done:
316
317 if (binding->is_regex) {
318 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_async.c", (const char *
)__func__, 318, ((void*)0)
, SWITCH_LOG_DEBUG, "%sDigit parser %s: binding %s/%s/%d callback: %p data: %p\n",
319 msg, dmachine->name, digits, realm, key, (void *)(intptr_t) callback, user_data);
320 } else {
321 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_async.c", (const char *
)__func__, 321, ((void*)0)
, SWITCH_LOG_DEBUG, "%sDigit parser %s: binding %s/%s/%d callback: %p data: %p\n",
322 msg, dmachine->name, digits, realm, key, (void *)(intptr_t) callback, user_data);
323 }
324
325 return SWITCH_STATUS_SUCCESS;
326}
327
328typedef enum {
329 DM_MATCH_NONE,
330 DM_MATCH_EXACT,
331 DM_MATCH_PARTIAL,
332 DM_MATCH_BOTH,
333 DM_MATCH_NEVER
334} dm_match_t;
335
336
337static dm_match_t switch_ivr_dmachine_check_match(switch_ivr_dmachine_t *dmachine, switch_bool_t is_timeout)
338{
339 dm_match_t best = DM_MATCH_NONE;
340 switch_ivr_dmachine_binding_t *bp, *exact_bp = NULL((void*)0), *partial_bp = NULL((void*)0), *both_bp = NULL((void*)0), *r_bp = NULL((void*)0);
341 int pmatches = 0, ematches = 0, rmatches = 0;
342
343 if (!dmachine->cur_digit_len || !dmachine->realm) goto end;
344
345 for(bp = dmachine->realm->binding_list; bp; bp = bp->next) {
346 if (bp->is_regex) {
347 switch_status_t r_status = switch_regex_match(dmachine->digits, bp->digits);
348
349 if (r_status == SWITCH_STATUS_SUCCESS) {
350 bp->rmatch++;
351 } else {
352 bp->rmatch = 0;
353 }
354
355 rmatches++;
356 pmatches++;
357
358 } else {
359 if (!strncmp(dmachine->digits, bp->digits, strlen(dmachine->digits))(__extension__ (__builtin_constant_p (strlen(dmachine->digits
)) && ((__builtin_constant_p (dmachine->digits) &&
strlen (dmachine->digits) < ((size_t) (strlen(dmachine
->digits)))) || (__builtin_constant_p (bp->digits) &&
strlen (bp->digits) < ((size_t) (strlen(dmachine->digits
))))) ? __extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(dmachine->digits) && __builtin_constant_p (bp->
digits) && (__s1_len = __builtin_strlen (dmachine->
digits), __s2_len = __builtin_strlen (bp->digits), (!((size_t
)(const void *)((dmachine->digits) + 1) - (size_t)(const void
*)(dmachine->digits) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)((bp->digits) + 1) - (size_t)(const
void *)(bp->digits) == 1) || __s2_len >= 4)) ? __builtin_strcmp
(dmachine->digits, bp->digits) : (__builtin_constant_p
(dmachine->digits) && ((size_t)(const void *)((dmachine
->digits) + 1) - (size_t)(const void *)(dmachine->digits
) == 1) && (__s1_len = __builtin_strlen (dmachine->
digits), __s1_len < 4) ? (__builtin_constant_p (bp->digits
) && ((size_t)(const void *)((bp->digits) + 1) - (
size_t)(const void *)(bp->digits) == 1) ? __builtin_strcmp
(dmachine->digits, bp->digits) : (__extension__ ({ const
unsigned char *__s2 = (const unsigned char *) (const char *)
(bp->digits); int __result = (((const unsigned char *) (const
char *) (dmachine->digits))[0] - __s2[0]); if (__s1_len >
0 && __result == 0) { __result = (((const unsigned char
*) (const char *) (dmachine->digits))[1] - __s2[1]); if (
__s1_len > 1 && __result == 0) { __result = (((const
unsigned char *) (const char *) (dmachine->digits))[2] - __s2
[2]); if (__s1_len > 2 && __result == 0) __result =
(((const unsigned char *) (const char *) (dmachine->digits
))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
bp->digits) && ((size_t)(const void *)((bp->digits
) + 1) - (size_t)(const void *)(bp->digits) == 1) &&
(__s2_len = __builtin_strlen (bp->digits), __s2_len < 4
) ? (__builtin_constant_p (dmachine->digits) && ((
size_t)(const void *)((dmachine->digits) + 1) - (size_t)(const
void *)(dmachine->digits) == 1) ? __builtin_strcmp (dmachine
->digits, bp->digits) : (- (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (dmachine
->digits); int __result = (((const unsigned char *) (const
char *) (bp->digits))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (bp->digits))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (bp->digits))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (bp->digits))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(dmachine->digits, bp->digits)))); }) : strncmp (dmachine
->digits, bp->digits, strlen(dmachine->digits))))
) {
360 pmatches++;
361 ematches = 1;
362 }
363 }
364 }
365
366 if (!zstr(dmachine->realm->terminators)_zstr(dmachine->realm->terminators)) {
367 char *p = dmachine->realm->terminators;
368 char *q;
369
370 while(p && *p) {
371 if ((q=strrchr(dmachine->digits, *p))) {
372 *q = '\0';
373 is_timeout = 1;
374 break;
375 }
376 p++;
377 }
378 }
379
380 for(bp = dmachine->realm->binding_list; bp; bp = bp->next) {
381 if (bp->is_regex) {
382 if (bp->rmatch) {
383 if (is_timeout || (bp == dmachine->realm->binding_list && !bp->next)) {
384 best = DM_MATCH_EXACT;
385 exact_bp = bp;
386 break;
387 }
388 best = DM_MATCH_PARTIAL;
389 }
390 } else {
391 int pmatch = !strncmp(dmachine->digits, bp->digits, strlen(dmachine->digits))(__extension__ (__builtin_constant_p (strlen(dmachine->digits
)) && ((__builtin_constant_p (dmachine->digits) &&
strlen (dmachine->digits) < ((size_t) (strlen(dmachine
->digits)))) || (__builtin_constant_p (bp->digits) &&
strlen (bp->digits) < ((size_t) (strlen(dmachine->digits
))))) ? __extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(dmachine->digits) && __builtin_constant_p (bp->
digits) && (__s1_len = __builtin_strlen (dmachine->
digits), __s2_len = __builtin_strlen (bp->digits), (!((size_t
)(const void *)((dmachine->digits) + 1) - (size_t)(const void
*)(dmachine->digits) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)((bp->digits) + 1) - (size_t)(const
void *)(bp->digits) == 1) || __s2_len >= 4)) ? __builtin_strcmp
(dmachine->digits, bp->digits) : (__builtin_constant_p
(dmachine->digits) && ((size_t)(const void *)((dmachine
->digits) + 1) - (size_t)(const void *)(dmachine->digits
) == 1) && (__s1_len = __builtin_strlen (dmachine->
digits), __s1_len < 4) ? (__builtin_constant_p (bp->digits
) && ((size_t)(const void *)((bp->digits) + 1) - (
size_t)(const void *)(bp->digits) == 1) ? __builtin_strcmp
(dmachine->digits, bp->digits) : (__extension__ ({ const
unsigned char *__s2 = (const unsigned char *) (const char *)
(bp->digits); int __result = (((const unsigned char *) (const
char *) (dmachine->digits))[0] - __s2[0]); if (__s1_len >
0 && __result == 0) { __result = (((const unsigned char
*) (const char *) (dmachine->digits))[1] - __s2[1]); if (
__s1_len > 1 && __result == 0) { __result = (((const
unsigned char *) (const char *) (dmachine->digits))[2] - __s2
[2]); if (__s1_len > 2 && __result == 0) __result =
(((const unsigned char *) (const char *) (dmachine->digits
))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
bp->digits) && ((size_t)(const void *)((bp->digits
) + 1) - (size_t)(const void *)(bp->digits) == 1) &&
(__s2_len = __builtin_strlen (bp->digits), __s2_len < 4
) ? (__builtin_constant_p (dmachine->digits) && ((
size_t)(const void *)((dmachine->digits) + 1) - (size_t)(const
void *)(dmachine->digits) == 1) ? __builtin_strcmp (dmachine
->digits, bp->digits) : (- (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (dmachine
->digits); int __result = (((const unsigned char *) (const
char *) (bp->digits))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (bp->digits))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (bp->digits))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (bp->digits))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(dmachine->digits, bp->digits)))); }) : strncmp (dmachine
->digits, bp->digits, strlen(dmachine->digits))))
;
392
393 if (!exact_bp && pmatch && (((pmatches == 1 || ematches == 1) && !rmatches) || is_timeout) && !strcmp(bp->digits, dmachine->digits)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(bp->digits) && __builtin_constant_p (dmachine->
digits) && (__s1_len = __builtin_strlen (bp->digits
), __s2_len = __builtin_strlen (dmachine->digits), (!((size_t
)(const void *)((bp->digits) + 1) - (size_t)(const void *)
(bp->digits) == 1) || __s1_len >= 4) && (!((size_t
)(const void *)((dmachine->digits) + 1) - (size_t)(const void
*)(dmachine->digits) == 1) || __s2_len >= 4)) ? __builtin_strcmp
(bp->digits, dmachine->digits) : (__builtin_constant_p
(bp->digits) && ((size_t)(const void *)((bp->digits
) + 1) - (size_t)(const void *)(bp->digits) == 1) &&
(__s1_len = __builtin_strlen (bp->digits), __s1_len < 4
) ? (__builtin_constant_p (dmachine->digits) && ((
size_t)(const void *)((dmachine->digits) + 1) - (size_t)(const
void *)(dmachine->digits) == 1) ? __builtin_strcmp (bp->
digits, dmachine->digits) : (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (dmachine
->digits); int __result = (((const unsigned char *) (const
char *) (bp->digits))[0] - __s2[0]); if (__s1_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (bp->digits))[1] - __s2[1]); if (__s1_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (bp->digits))[2] - __s2[2]); if (__s1_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (bp->digits))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
(dmachine->digits) && ((size_t)(const void *)((dmachine
->digits) + 1) - (size_t)(const void *)(dmachine->digits
) == 1) && (__s2_len = __builtin_strlen (dmachine->
digits), __s2_len < 4) ? (__builtin_constant_p (bp->digits
) && ((size_t)(const void *)((bp->digits) + 1) - (
size_t)(const void *)(bp->digits) == 1) ? __builtin_strcmp
(bp->digits, dmachine->digits) : (- (__extension__ ({ const
unsigned char *__s2 = (const unsigned char *) (const char *)
(bp->digits); int __result = (((const unsigned char *) (const
char *) (dmachine->digits))[0] - __s2[0]); if (__s2_len >
0 && __result == 0) { __result = (((const unsigned char
*) (const char *) (dmachine->digits))[1] - __s2[1]); if (
__s2_len > 1 && __result == 0) { __result = (((const
unsigned char *) (const char *) (dmachine->digits))[2] - __s2
[2]); if (__s2_len > 2 && __result == 0) __result =
(((const unsigned char *) (const char *) (dmachine->digits
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (bp->
digits, dmachine->digits)))); })
) {
394 best = DM_MATCH_EXACT;
395 exact_bp = bp;
396 if (dmachine->cur_digit_len == dmachine->max_digit_len) break;
397 }
398
399 if (!(both_bp && partial_bp) && strlen(bp->digits) != strlen(dmachine->digits) && pmatch) {
400
401 if (exact_bp) {
402 best = DM_MATCH_BOTH;
403 both_bp = bp;
404 } else {
405 best = DM_MATCH_PARTIAL;
406 partial_bp = bp;
407 }
408 }
409
410 if (both_bp && exact_bp && partial_bp) break;
411 }
412 }
413
414 if (!pmatches) {
415 best = DM_MATCH_NEVER;
416 }
417
418
419 end:
420
421 if (is_timeout) {
422 if (both_bp) {
423 r_bp = exact_bp ? exact_bp : both_bp;
424 }
425 }
426
427 if (best == DM_MATCH_EXACT && exact_bp) {
428 r_bp = exact_bp;
429 }
430
431
432 if (r_bp) {
433 dmachine->last_matching_binding = r_bp;
434 switch_set_string(dmachine->last_matching_digits, dmachine->digits)switch_copy_string(dmachine->last_matching_digits, dmachine
->digits, sizeof(dmachine->last_matching_digits))
;
435 best = DM_MATCH_EXACT;
436 }
437
438 return best;
439
440}
441
442static switch_bool_t switch_ivr_dmachine_check_timeout(switch_ivr_dmachine_t *dmachine)
443{
444 switch_time_t now = switch_time_now();
445 uint32_t timeout = dmachine->cur_digit_len ? dmachine->digit_timeout_ms : dmachine->input_timeout_ms;
446
447 if (!dmachine->last_digit_time) dmachine->last_digit_time = now;
448
449 if (timeout) {
450 if ((uint32_t)((now - dmachine->last_digit_time) / 1000) > timeout) {
451 return SWITCH_TRUE;
452 }
453 }
454
455 return SWITCH_FALSE;
456}
457
458SWITCH_DECLARE(switch_ivr_dmachine_match_t *)__attribute__((visibility("default"))) switch_ivr_dmachine_match_t
*
switch_ivr_dmachine_get_match(switch_ivr_dmachine_t *dmachine)
459{
460 if (dmachine->is_match) {
461 dmachine->is_match = 0;
462 return &dmachine->match;
463 }
464
465 return NULL((void*)0);
466}
467
468SWITCH_DECLARE(const char *)__attribute__((visibility("default"))) const char * switch_ivr_dmachine_get_failed_digits(switch_ivr_dmachine_t *dmachine)
469{
470
471 return dmachine->last_failed_digits;
472}
473
474SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_dmachine_ping(switch_ivr_dmachine_t *dmachine, switch_ivr_dmachine_match_t **match_p)
475{
476 switch_bool_t is_timeout = switch_ivr_dmachine_check_timeout(dmachine);
477 dm_match_t is_match = switch_ivr_dmachine_check_match(dmachine, is_timeout);
478 switch_status_t r, s;
479 int clear = 0;
480
481 if (is_match == DM_MATCH_NEVER) {
482 is_timeout++;
483 }
484
485 if (switch_mutex_trylock(dmachine->mutex) != SWITCH_STATUS_SUCCESS) {
486 return SWITCH_STATUS_SUCCESS;
487 }
488
489 if (zstr(dmachine->digits)_zstr(dmachine->digits) && !is_timeout) {
490 r = SWITCH_STATUS_SUCCESS;
491 } else if (dmachine->cur_digit_len > dmachine->max_digit_len) {
492 r = SWITCH_STATUS_FALSE;
493 } else if (is_match == DM_MATCH_EXACT || (is_match == DM_MATCH_BOTH && is_timeout)) {
494 r = SWITCH_STATUS_FOUND;
495
496 dmachine->match.match_digits = dmachine->last_matching_digits;
497 dmachine->match.match_key = dmachine->last_matching_binding->key;
498 dmachine->match.user_data = dmachine->last_matching_binding->user_data;
499
500 if (match_p) {
501 *match_p = &dmachine->match;
502 }
503
504 dmachine->is_match = 1;
505
506 dmachine->match.type = DM_MATCH_POSITIVE;
507
508 if (dmachine->last_matching_binding->callback) {
509 s = dmachine->last_matching_binding->callback(&dmachine->match);
510
511 switch(s) {
512 case SWITCH_STATUS_CONTINUE:
513 r = SWITCH_STATUS_SUCCESS;
514 break;
515 case SWITCH_STATUS_SUCCESS:
516 break;
517 default:
518 r = SWITCH_STATUS_BREAK;
519 break;
520 }
521 }
522
523 if (dmachine->match_callback) {
524 dmachine->match.user_data = dmachine->user_data;
525 s = dmachine->match_callback(&dmachine->match);
526
527 switch(s) {
528 case SWITCH_STATUS_CONTINUE:
529 r = SWITCH_STATUS_SUCCESS;
530 break;
531 case SWITCH_STATUS_SUCCESS:
532 break;
533 default:
534 r = SWITCH_STATUS_BREAK;
535 break;
536 }
537
538 }
539
540 clear++;
541 } else if (is_timeout) {
542 r = SWITCH_STATUS_TIMEOUT;
543 } else if (is_match == DM_MATCH_NONE && dmachine->cur_digit_len == dmachine->max_digit_len) {
544 r = SWITCH_STATUS_NOTFOUND;
545 } else {
546 r = SWITCH_STATUS_SUCCESS;
547 }
548
549 if (r != SWITCH_STATUS_FOUND && r != SWITCH_STATUS_SUCCESS && r != SWITCH_STATUS_BREAK) {
550 switch_set_string(dmachine->last_failed_digits, dmachine->digits)switch_copy_string(dmachine->last_failed_digits, dmachine->
digits, sizeof(dmachine->last_failed_digits))
;
551 dmachine->match.match_digits = dmachine->last_failed_digits;
552
553 dmachine->match.type = DM_MATCH_NEGATIVE;
554
555 if (dmachine->nonmatch_callback) {
556 dmachine->match.user_data = dmachine->user_data;
557 s = dmachine->nonmatch_callback(&dmachine->match);
558
559 switch(s) {
560 case SWITCH_STATUS_CONTINUE:
561 r = SWITCH_STATUS_SUCCESS;
562 break;
563 case SWITCH_STATUS_SUCCESS:
564 break;
565 default:
566 r = SWITCH_STATUS_BREAK;
567 break;
568 }
569
570 }
571
572 clear++;
573 }
574
575 if (clear) {
576 switch_ivr_dmachine_clear(dmachine);
577 }
578
579 dmachine->last_return = r;
580
581 switch_mutex_unlock(dmachine->mutex);
582
583 return r;
584}
585
586SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_dmachine_feed(switch_ivr_dmachine_t *dmachine, const char *digits, switch_ivr_dmachine_match_t **match)
587{
588 const char *p;
589 switch_status_t status = SWITCH_STATUS_BREAK;
590
591 if (!zstr(digits)_zstr(digits)) {
592 status = SWITCH_STATUS_SUCCESS;
593 }
594
595 for (p = digits; p && *p; p++) {
596 switch_mutex_lock(dmachine->mutex);
597 if (dmachine->cur_digit_len < dmachine->max_digit_len) {
598 switch_status_t istatus;
599 char *e = dmachine->digits + strlen(dmachine->digits);
600
601 *e++ = *p;
602 *e = '\0';
603 dmachine->cur_digit_len++;
604 switch_mutex_unlock(dmachine->mutex);
605 dmachine->last_digit_time = switch_time_now();
606 if (status == SWITCH_STATUS_SUCCESS && (istatus = switch_ivr_dmachine_ping(dmachine, match)) != SWITCH_STATUS_SUCCESS) {
607 status = istatus;
608 }
609 } else {
610 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_async.c", (const char *
)__func__, 610, ((void*)0)
, SWITCH_LOG_ERROR, "dmachine overflow error!\n");
611 status = SWITCH_STATUS_FALSE;
612 }
613 }
614
615 return status;
616}
617
618SWITCH_DECLARE(switch_bool_t)__attribute__((visibility("default"))) switch_bool_t switch_ivr_dmachine_is_parsing(switch_ivr_dmachine_t *dmachine)
619{
620 return !!dmachine->cur_digit_len;
621}
622
623SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_dmachine_clear(switch_ivr_dmachine_t *dmachine)
624{
625
626 memset(dmachine->digits, 0, sizeof(dmachine->digits));
627 dmachine->cur_digit_len = 0;
628 dmachine->last_digit_time = 0;
629 return SWITCH_STATUS_SUCCESS;
630}
631
632
633
634SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_session_echo(switch_core_session_t *session, switch_input_args_t *args)
635{
636 switch_status_t status;
637 switch_frame_t *read_frame;
638 switch_channel_t *channel = switch_core_session_get_channel(session);
639 int orig_vid = switch_channel_test_flag(channel, CF_VIDEO);
640
641 if (switch_channel_pre_answer(channel)switch_channel_perform_pre_answer(channel, "src/switch_ivr_async.c"
, (const char *)__func__, 641)
!= SWITCH_STATUS_SUCCESS) {
642 return SWITCH_STATUS_FALSE;
643 }
644
645 arg_recursion_check_start(args)if (args) { if (args->loops >= 25) { switch_log_printf(
SWITCH_CHANNEL_ID_LOG, "src/switch_ivr_async.c", (const char *
)__func__, 645, ((void*)0), SWITCH_LOG_ERROR, "RECURSION ERROR! It's not the best idea to call things that collect input recursively from an input callback.\n"
); return SWITCH_STATUS_GENERR; } else {args->loops++;} }
;
646
647 restart:
648
649 while (switch_channel_ready(channel)switch_channel_test_ready(channel, SWITCH_TRUE, SWITCH_FALSE)) {
650 status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
651 if (!SWITCH_READ_ACCEPTABLE(status)(status == SWITCH_STATUS_SUCCESS || status == SWITCH_STATUS_BREAK
|| status == SWITCH_STATUS_INUSE)
) {
652 break;
653 }
654
655 if (!orig_vid && switch_channel_test_flag(channel, CF_VIDEO)) {
656 orig_vid = 1;
657 goto restart;
658 }
659
660
661 switch_ivr_parse_all_events(session);
662
663 if (args && (args->input_callback || args->buf || args->buflen)) {
664 switch_dtmf_t dtmf = {0};
665
666 /*
667 dtmf handler function you can hook up to be executed when a digit is dialed during playback
668 if you return anything but SWITCH_STATUS_SUCCESS the playback will stop.
669 */
670 if (switch_channel_has_dtmf(channel)) {
671 if (!args->input_callback && !args->buf) {
672 status = SWITCH_STATUS_BREAK;
673 break;
674 }
675 switch_channel_dequeue_dtmf(channel, &dtmf);
676 if (args->input_callback) {
677 status = args->input_callback(session, (void *) &dtmf, SWITCH_INPUT_TYPE_DTMF, args->buf, args->buflen);
678 } else {
679 *((char *) args->buf) = dtmf.digit;
680 status = SWITCH_STATUS_BREAK;
681 }
682 }
683
684 if (args->input_callback) {
685 switch_event_t *event = NULL((void*)0);
686
687 if (switch_core_session_dequeue_event(session, &event, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
688 status = args->input_callback(session, event, SWITCH_INPUT_TYPE_EVENT, args->buf, args->buflen);
689 switch_event_destroy(&event);
690 }
691 }
692
693 if (status != SWITCH_STATUS_SUCCESS) {
694 break;
695 }
696 }
697
698
699 switch_core_session_write_frame(session, read_frame, SWITCH_IO_FLAG_NONE, 0);
700
701#ifndef SWITCH_VIDEO_IN_THREADS
702 status = switch_core_session_read_video_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
703
704 if (!SWITCH_READ_ACCEPTABLE(status)(status == SWITCH_STATUS_SUCCESS || status == SWITCH_STATUS_BREAK
|| status == SWITCH_STATUS_INUSE)
) {
705 break;
706 }
707
708 if (switch_test_flag(read_frame, SFF_CNG)((read_frame)->flags & SFF_CNG)) {
709 continue;
710 }
711
712 switch_core_session_write_video_frame(session, read_frame, SWITCH_IO_FLAG_NONE, 0);
713#endif
714
715 if (switch_channel_test_flag(channel, CF_BREAK)) {
716 switch_channel_clear_flag(channel, CF_BREAK);
717 break;
718 }
719 }
720
721 return SWITCH_STATUS_SUCCESS;
722}
723
724typedef struct {
725 switch_file_handle_t fh;
726 int mux;
727 int loop;
728 char *file;
729} displace_helper_t;
730
731static switch_bool_t write_displace_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
732{
733 displace_helper_t *dh = (displace_helper_t *) user_data;
734
735 switch (type) {
736 case SWITCH_ABC_TYPE_INIT:
737 break;
738 case SWITCH_ABC_TYPE_CLOSE:
739 if (dh) {
740 switch_core_session_t *session = switch_core_media_bug_get_session(bug);
741 switch_channel_t *channel;
742
743 switch_core_file_close(&dh->fh);
744
745 if (session && (channel = switch_core_session_get_channel(session))) {
746 switch_channel_set_private(channel, dh->file, NULL((void*)0));
747 }
748 }
749 break;
750 case SWITCH_ABC_TYPE_READ_REPLACE:
751 {
752 switch_frame_t *rframe = switch_core_media_bug_get_read_replace_frame(bug);
753 if (dh && !dh->mux) {
754 memset(rframe->data, 255, rframe->datalen);
755 }
756 switch_core_media_bug_set_read_replace_frame(bug, rframe);
757 }
758 break;
759 case SWITCH_ABC_TYPE_WRITE_REPLACE:
760 if (dh) {
761 switch_frame_t *rframe = NULL((void*)0);
762 switch_size_t len;
763 switch_status_t st;
764
765 rframe = switch_core_media_bug_get_write_replace_frame(bug);
766 len = rframe->samples;
767
768 if (dh->mux) {
769 int16_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE8192];
770 int16_t *fp = rframe->data;
771 uint32_t x;
772
773 st = switch_core_file_read(&dh->fh, buf, &len);
774
775 for (x = 0; x < (uint32_t) len * dh->fh.channels; x++) {
776 int32_t mixed = fp[x] + buf[x];
777 switch_normalize_to_16bit(mixed)if (mixed > 32767) mixed = 32767; else if (mixed < -32768
) mixed = -32768;
;
778 fp[x] = (int16_t) mixed;
779 }
780 } else {
781 st = switch_core_file_read(&dh->fh, rframe->data, &len);
782 if (len < rframe->samples) {
783 memset((char *)rframe->data + len * 2 * dh->fh.channels, 0, (rframe->datalen - len) * 2 * dh->fh.channels);
784 }
785 }
786
787 rframe->datalen = rframe->samples * 2 * dh->fh.channels;
788
789 if (st != SWITCH_STATUS_SUCCESS || len == 0) {
790 if (dh->loop) {
791 uint32_t pos = 0;
792 switch_core_file_seek(&dh->fh, &pos, 0, SEEK_SET0);
793 } else {
794 switch_core_session_t *session = switch_core_media_bug_get_session(bug);
795 switch_channel_t *channel;
796
797 if (session && (channel = switch_core_session_get_channel(session))) {
798 switch_channel_set_private(channel, dh->file, NULL((void*)0));
799 }
800 return SWITCH_FALSE;
801 }
802 }
803
804 switch_core_media_bug_set_write_replace_frame(bug, rframe);
805 }
806 break;
807 case SWITCH_ABC_TYPE_WRITE:
808 default:
809 break;
810 }
811
812 return SWITCH_TRUE;
813}
814
815static switch_bool_t read_displace_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
816{
817 displace_helper_t *dh = (displace_helper_t *) user_data;
818
819 switch (type) {
820 case SWITCH_ABC_TYPE_INIT:
821 break;
822 case SWITCH_ABC_TYPE_CLOSE:
823 if (dh) {
824 switch_core_session_t *session = switch_core_media_bug_get_session(bug);
825 switch_channel_t *channel;
826
827 switch_core_file_close(&dh->fh);
828
829 if (session && (channel = switch_core_session_get_channel(session))) {
830 switch_channel_set_private(channel, dh->file, NULL((void*)0));
831 }
832 }
833 break;
834 case SWITCH_ABC_TYPE_WRITE_REPLACE:
835 {
836 switch_frame_t *rframe = switch_core_media_bug_get_write_replace_frame(bug);
837 if (dh && !dh->mux) {
838 memset(rframe->data, 255, rframe->datalen);
839 }
840 switch_core_media_bug_set_write_replace_frame(bug, rframe);
841 }
842 break;
843 case SWITCH_ABC_TYPE_READ_REPLACE:
844 if (dh) {
845 switch_frame_t *rframe = NULL((void*)0);
846 switch_size_t len;
847 switch_status_t st;
848 rframe = switch_core_media_bug_get_read_replace_frame(bug);
849 len = rframe->samples;
850
851 if (dh->mux) {
852 int16_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE8192];
853 int16_t *fp = rframe->data;
854 uint32_t x;
855
856 st = switch_core_file_read(&dh->fh, buf, &len);
857
858 for (x = 0; x < (uint32_t) len * dh->fh.channels; x++) {
859 int32_t mixed = fp[x] + buf[x];
860 switch_normalize_to_16bit(mixed)if (mixed > 32767) mixed = 32767; else if (mixed < -32768
) mixed = -32768;
;
861 fp[x] = (int16_t) mixed;
862 }
863
864 } else {
865 st = switch_core_file_read(&dh->fh, rframe->data, &len);
866 rframe->samples = (uint32_t) len;
867 }
868
869 rframe->datalen = rframe->samples * 2 * dh->fh.channels;
870
871
872 if (st != SWITCH_STATUS_SUCCESS || len == 0) {
873 if (dh->loop) {
874 uint32_t pos = 0;
875 switch_core_file_seek(&dh->fh, &pos, 0, SEEK_SET0);
876 } else {
877 switch_core_session_t *session = switch_core_media_bug_get_session(bug);
878 switch_channel_t *channel;
879
880 if (session && (channel = switch_core_session_get_channel(session))) {
881 switch_channel_set_private(channel, dh->file, NULL((void*)0));
882 }
883 return SWITCH_FALSE;
884 }
885 }
886
887 switch_core_media_bug_set_read_replace_frame(bug, rframe);
888 }
889 break;
890 case SWITCH_ABC_TYPE_WRITE:
891 default:
892 break;
893 }
894
895 return SWITCH_TRUE;
896}
897
898SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_stop_displace_session(switch_core_session_t *session, const char *file)
899{
900 switch_media_bug_t *bug;
901 switch_channel_t *channel = switch_core_session_get_channel(session);
902
903 if ((bug = switch_channel_get_private(channel, file))) {
904 switch_channel_set_private(channel, file, NULL((void*)0));
905 switch_core_media_bug_remove(session, &bug);
906 return SWITCH_STATUS_SUCCESS;
907 }
908
909 return SWITCH_STATUS_FALSE;
910}
911
912SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_displace_session(switch_core_session_t *session, const char *file, uint32_t limit, const char *flags)
913{
914 switch_channel_t *channel = switch_core_session_get_channel(session);
915 switch_media_bug_t *bug;
916 switch_status_t status;
917 time_t to = 0;
918 char *ext;
919 const char *prefix;
920 displace_helper_t *dh;
921 const char *p;
922 switch_bool_t hangup_on_error = SWITCH_FALSE;
923 switch_codec_implementation_t read_impl = { 0 };
924 switch_core_session_get_read_impl(session, &read_impl);
925
926 if ((p = switch_channel_get_variable(channel, "DISPLACE_HANGUP_ON_ERROR")switch_channel_get_variable_dup(channel, "DISPLACE_HANGUP_ON_ERROR"
, SWITCH_TRUE, -1)
)) {
927 hangup_on_error = switch_true(p);
928 }
929
930 if (zstr(file)_zstr(file)) {
931 return SWITCH_STATUS_FALSE;
932 }
933
934 if ((status = switch_channel_pre_answer(channel)switch_channel_perform_pre_answer(channel, "src/switch_ivr_async.c"
, (const char *)__func__, 934)
) != SWITCH_STATUS_SUCCESS) {
935 return SWITCH_STATUS_FALSE;
936 }
937
938 if (!switch_channel_media_up(channel)(switch_channel_test_flag(channel, CF_ANSWERED) || switch_channel_test_flag
(channel, CF_EARLY_MEDIA))
|| !switch_core_session_get_read_codec(session)) {
939 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 939, (const char*)(session)
, SWITCH_LOG_ERROR, "Can not displace session. Media not enabled on channel\n");
940 return SWITCH_STATUS_FALSE;
941 }
942
943 if ((bug = switch_channel_get_private(channel, file))) {
944 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 944, (const char*)(session)
, SWITCH_LOG_ERROR, "Only 1 of the same file per channel please!\n");
945 return SWITCH_STATUS_FALSE;
946 }
947
948 if (!(dh = switch_core_session_alloc(session, sizeof(*dh))switch_core_perform_session_alloc(session, sizeof(*dh), "src/switch_ivr_async.c"
, (const char *)__func__, 948)
)) {
949 return SWITCH_STATUS_MEMERR;
950 }
951
952 if (!(prefix = switch_channel_get_variable(channel, "sound_prefix")switch_channel_get_variable_dup(channel, "sound_prefix", SWITCH_TRUE
, -1)
)) {
953 prefix = SWITCH_GLOBAL_dirs.base_dir;
954 }
955
956 if (!strstr(file, SWITCH_URL_SEPARATOR"://")) {
957 if (!switch_is_file_path(file)) {
958 char *tfile = NULL((void*)0);
959 char *e;
960
961 if (*file == '[') {
962 tfile = switch_core_session_strdup(session, file)switch_core_perform_session_strdup(session, file, "src/switch_ivr_async.c"
, (const char *)__func__, 962)
;
963 if ((e = switch_find_end_paren(tfile, '[', ']'))) {
964 *e = '\0';
965 file = e + 1;
966 } else {
967 tfile = NULL((void*)0);
968 }
969 }
970
971 file = switch_core_session_sprintf(session, "%s%s%s%s%s", switch_str_nil(tfile)(tfile ? tfile : ""), tfile ? "]" : "", prefix, SWITCH_PATH_SEPARATOR"/", file);
972 }
973 if ((ext = strrchr(file, '.'))) {
974 ext++;
975 } else {
976 ext = read_impl.iananame;
977 file = switch_core_session_sprintf(session, "%s.%s", file, ext);
978 }
979 }
980
981 dh->fh.channels = read_impl.number_of_channels;
982 dh->fh.samplerate = read_impl.actual_samples_per_second;
983 dh->file = switch_core_session_strdup(session, file)switch_core_perform_session_strdup(session, file, "src/switch_ivr_async.c"
, (const char *)__func__, 983)
;
984
985 if (switch_core_file_open(&dh->fh,switch_core_perform_file_open("src/switch_ivr_async.c", (const
char *)__func__, 988, &dh->fh, file, read_impl.number_of_channels
, read_impl.actual_samples_per_second, SWITCH_FILE_FLAG_READ |
SWITCH_FILE_DATA_SHORT, ((void*)0))
986 file,switch_core_perform_file_open("src/switch_ivr_async.c", (const
char *)__func__, 988, &dh->fh, file, read_impl.number_of_channels
, read_impl.actual_samples_per_second, SWITCH_FILE_FLAG_READ |
SWITCH_FILE_DATA_SHORT, ((void*)0))
987 read_impl.number_of_channels,switch_core_perform_file_open("src/switch_ivr_async.c", (const
char *)__func__, 988, &dh->fh, file, read_impl.number_of_channels
, read_impl.actual_samples_per_second, SWITCH_FILE_FLAG_READ |
SWITCH_FILE_DATA_SHORT, ((void*)0))
988 read_impl.actual_samples_per_second, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL)switch_core_perform_file_open("src/switch_ivr_async.c", (const
char *)__func__, 988, &dh->fh, file, read_impl.number_of_channels
, read_impl.actual_samples_per_second, SWITCH_FILE_FLAG_READ |
SWITCH_FILE_DATA_SHORT, ((void*)0))
!= SWITCH_STATUS_SUCCESS) {
989 if (hangup_on_error) {
990 switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER)switch_channel_perform_hangup(channel, "src/switch_ivr_async.c"
, (const char *)__func__, 990, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER
)
;
991 switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
992 }
993 return SWITCH_STATUS_GENERR;
994 }
995
996 if (limit) {
997 to = switch_epoch_time_now(NULL((void*)0)) + limit;
998 }
999
1000 if (flags && strchr(flags, 'm')(__extension__ (__builtin_constant_p ('m') && !__builtin_constant_p
(flags) && ('m') == '\0' ? (char *) __rawmemchr (flags
, 'm') : __builtin_strchr (flags, 'm')))
) {
1001 dh->mux++;
1002 }
1003
1004 if (flags && strchr(flags, 'l')(__extension__ (__builtin_constant_p ('l') && !__builtin_constant_p
(flags) && ('l') == '\0' ? (char *) __rawmemchr (flags
, 'l') : __builtin_strchr (flags, 'l')))
) {
1005 dh->loop++;
1006 }
1007
1008 if (flags && strchr(flags, 'r')(__extension__ (__builtin_constant_p ('r') && !__builtin_constant_p
(flags) && ('r') == '\0' ? (char *) __rawmemchr (flags
, 'r') : __builtin_strchr (flags, 'r')))
) {
1009 status = switch_core_media_bug_add(session, "displace", file,
1010 read_displace_callback, dh, to, SMBF_WRITE_REPLACE | SMBF_READ_REPLACE | SMBF_NO_PAUSE, &bug);
1011 } else {
1012 status = switch_core_media_bug_add(session, "displace", file,
1013 write_displace_callback, dh, to, SMBF_WRITE_REPLACE | SMBF_READ_REPLACE | SMBF_NO_PAUSE, &bug);
1014 }
1015
1016 if (status != SWITCH_STATUS_SUCCESS) {
1017 switch_core_file_close(&dh->fh);
1018 return status;
1019 }
1020
1021 switch_channel_set_private(channel, file, bug);
1022
1023 return SWITCH_STATUS_SUCCESS;
1024}
1025
1026
1027struct record_helper {
1028 char *file;
1029 switch_file_handle_t *fh;
1030 switch_file_handle_t in_fh;
1031 switch_file_handle_t out_fh;
1032 int native;
1033 uint32_t packet_len;
1034 int min_sec;
1035 int final_timeout_ms;
1036 int initial_timeout_ms;
1037 int silence_threshold;
1038 int silence_timeout_ms;
1039 switch_time_t silence_time;
1040 int rready;
1041 int wready;
1042 switch_time_t last_read_time;
1043 switch_time_t last_write_time;
1044 switch_bool_t hangup_on_error;
1045 switch_codec_implementation_t read_impl;
1046 switch_bool_t speech_detected;
1047 switch_buffer_t *thread_buffer;
1048 switch_thread_t *thread;
1049 switch_mutex_t *buffer_mutex;
1050 int thread_ready;
1051 const char *completion_cause;
1052};
1053
1054/**
1055 * Set the recording completion cause. The cause can only be set once, to minimize the logic in the record_callback.
1056 * [The completion_cause strings are essentially those of an MRCP Recorder resource.]
1057 */
1058static void set_completion_cause(struct record_helper *rh, const char *completion_cause)
1059{
1060 if (!rh->completion_cause) {
1061 rh->completion_cause = completion_cause;
1062 }
1063}
1064
1065static switch_bool_t is_silence_frame(switch_frame_t *frame, int silence_threshold, switch_codec_implementation_t *codec_impl)
1066{
1067 int16_t *fdata = (int16_t *) frame->data;
1068 uint32_t samples = frame->datalen / sizeof(*fdata);
1069 switch_bool_t is_silence = SWITCH_TRUE;
1070 uint32_t channel_num = 0;
1071
1072 int divisor = 0;
1073 if (!(divisor = codec_impl->samples_per_second / 8000)) {
1074 divisor = 1;
1075 }
1076
1077 /* is silence only if every channel is silent */
1078 for (channel_num = 0; channel_num < codec_impl->number_of_channels && is_silence; channel_num++) {
1079 uint32_t count = 0, j = channel_num;
1080 double energy = 0;
1081 for (count = 0; count < samples; count++) {
1082 energy += abs(fdata[j]);
1083 j += codec_impl->number_of_channels;
1084 }
1085 is_silence &= (uint32_t) ((energy / (samples / divisor)) < silence_threshold);
1086 }
1087
1088 return is_silence;
1089}
1090
1091static void send_record_stop_event(switch_channel_t *channel, switch_codec_implementation_t *read_impl, struct record_helper *rh)
1092{
1093 switch_event_t *event;
1094
1095 if (rh->fh) {
1096 switch_channel_set_variable_printf(channel, "record_samples", "%d", rh->fh->samples_out);
1097 if (read_impl->actual_samples_per_second) {
1098 switch_channel_set_variable_printf(channel, "record_seconds", "%d", rh->fh->samples_out / read_impl->actual_samples_per_second);
1099 switch_channel_set_variable_printf(channel, "record_ms", "%d", rh->fh->samples_out / (read_impl->actual_samples_per_second / 1000));
1100 }
1101 }
1102
1103 if (!zstr(rh->completion_cause)_zstr(rh->completion_cause)) {
1104 switch_channel_set_variable_printf(channel, "record_completion_cause", "%s", rh->completion_cause);
1105 }
1106
1107 if (switch_event_create(&event, SWITCH_EVENT_RECORD_STOP)switch_event_create_subclass_detailed("src/switch_ivr_async.c"
, (const char * )(const char *)__func__, 1107, &event, SWITCH_EVENT_RECORD_STOP
, ((void*)0))
== SWITCH_STATUS_SUCCESS) {
1108 switch_channel_event_set_data(channel, event);
1109 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-File-Path", rh->file);
1110 if (!zstr(rh->completion_cause)_zstr(rh->completion_cause)) {
1111 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-Completion-Cause", rh->completion_cause);
1112 }
1113 switch_event_fire(&event)switch_event_fire_detailed("src/switch_ivr_async.c", (const char
* )(const char *)__func__, 1113, &event, ((void*)0))
;
1114 }
1115}
1116
1117static void *SWITCH_THREAD_FUNC recording_thread(switch_thread_t *thread, void *obj)
1118{
1119 switch_media_bug_t *bug = (switch_media_bug_t *) obj;
1120 switch_core_session_t *session = switch_core_media_bug_get_session(bug);
1121 switch_channel_t *channel = switch_core_session_get_channel(session);
1122 struct record_helper *rh;
1123 switch_size_t bsize = SWITCH_RECOMMENDED_BUFFER_SIZE8192, samples = 0, inuse = 0;
1124 unsigned char *data = switch_core_session_alloc(session, bsize)switch_core_perform_session_alloc(session, bsize, "src/switch_ivr_async.c"
, (const char *)__func__, 1124)
;
1125 int channels = switch_core_media_bug_test_flag(bug, SMBF_STEREO) ? 2 : 1;
1126
1127 if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) {
1128 return NULL((void*)0);
1129 }
1130
1131 rh = switch_core_media_bug_get_user_data(bug);
1132 switch_buffer_create_dynamic(&rh->thread_buffer, 1024 * 512, 1024 * 64, 0);
1133 rh->thread_ready = 1;
1134
1135 while(switch_test_flag(rh->fh, SWITCH_FILE_OPEN)((rh->fh)->flags & SWITCH_FILE_OPEN)) {
1136 switch_mutex_lock(rh->buffer_mutex);
1137 inuse = switch_buffer_inuse(rh->thread_buffer);
1138
1139 if (rh->thread_ready && switch_channel_up_nosig(channel)(switch_channel_get_state(channel) < CS_HANGUP) && inuse < bsize) {
1140 switch_mutex_unlock(rh->buffer_mutex);
1141 switch_yield(20000)switch_sleep(20000);;
1142 continue;
1143 } else if ((!rh->thread_ready || switch_channel_down_nosig(channel)(switch_channel_get_state(channel) >= CS_HANGUP)) && !inuse) {
1144 break;
1145 }
1146
1147 samples = switch_buffer_read(rh->thread_buffer, data, bsize) / 2 / channels;
1148 switch_mutex_unlock(rh->buffer_mutex);
1149
1150 if (switch_core_file_write(rh->fh, data, &samples) != SWITCH_STATUS_SUCCESS) {
1151 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 1151, (const char*)(session)
, SWITCH_LOG_ERROR, "Error writing %s\n", rh->file);
1152 /* File write failed */
1153 set_completion_cause(rh, "uri-failure");
1154 if (rh->hangup_on_error) {
1155 switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER)switch_channel_perform_hangup(channel, "src/switch_ivr_async.c"
, (const char *)__func__, 1155, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER
)
;
1156 switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
1157 }
1158 }
1159 }
1160
1161 switch_core_session_rwunlock(session);
1162
1163 return NULL((void*)0);
1164}
1165
1166static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
1167{
1168 switch_core_session_t *session = switch_core_media_bug_get_session(bug);
1169 switch_channel_t *channel = switch_core_session_get_channel(session);
1170 struct record_helper *rh = (struct record_helper *) user_data;
1171 switch_event_t *event;
1172 switch_frame_t *nframe;
1173 switch_size_t len = 0;
1174 int mask = switch_core_media_bug_test_flag(bug, SMBF_MASK);
1175 unsigned char null_data[SWITCH_RECOMMENDED_BUFFER_SIZE8192] = {0};
1176
1177 switch (type) {
1178 case SWITCH_ABC_TYPE_INIT:
1179 {
1180 const char *var = switch_channel_get_variable(channel, "RECORD_USE_THREAD")switch_channel_get_variable_dup(channel, "RECORD_USE_THREAD",
SWITCH_TRUE, -1)
;
1181
1182 if (zstr(var)_zstr(var) || switch_true(var)) {
1183 switch_threadattr_t *thd_attr = NULL((void*)0);
1184 switch_memory_pool_t *pool = switch_core_session_get_pool(session);
1185 int sanity = 200;
1186
1187
1188 switch_core_session_get_read_impl(session, &rh->read_impl);
1189 switch_mutex_init(&rh->buffer_mutex, SWITCH_MUTEX_NESTED0x1, pool);
1190 switch_threadattr_create(&thd_attr, pool);
1191 switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE240 * 1024);
1192 switch_thread_create(&rh->thread, thd_attr, recording_thread, bug, pool);
1193
1194 while(--sanity > 0 && !rh->thread_ready) {
1195 switch_yield(10000)switch_sleep(10000);;
1196 }
1197 }
1198
1199
1200 if (switch_event_create(&event, SWITCH_EVENT_RECORD_START)switch_event_create_subclass_detailed("src/switch_ivr_async.c"
, (const char * )(const char *)__func__, 1200, &event, SWITCH_EVENT_RECORD_START
, ((void*)0))
== SWITCH_STATUS_SUCCESS) {
1201 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-File-Path", rh->file);
1202 switch_channel_event_set_data(channel, event);
1203 switch_event_fire(&event)switch_event_fire_detailed("src/switch_ivr_async.c", (const char
* )(const char *)__func__, 1203, &event, ((void*)0))
;
1204 }
1205
1206 rh->silence_time = switch_micro_time_now();
1207 rh->silence_timeout_ms = rh->initial_timeout_ms;
1208 rh->speech_detected = SWITCH_FALSE;
1209 rh->completion_cause = NULL((void*)0);
1210
1211 switch_core_session_get_read_impl(session, &rh->read_impl);
1212 }
1213 break;
1214 case SWITCH_ABC_TYPE_TAP_NATIVE_READ:
1215 {
1216 switch_time_t now = switch_micro_time_now();
1217 switch_time_t diff;
1218
1219 rh->rready = 1;
1220
1221 nframe = switch_core_media_bug_get_native_read_frame(bug);
1222 len = nframe->datalen;
1223
1224 if (!rh->wready) {
1225 unsigned char fill_data[SWITCH_RECOMMENDED_BUFFER_SIZE8192] = {0};
1226 switch_size_t fill_len = len;
1227
1228 switch_core_gen_encoded_silence(fill_data, &rh->read_impl, len);
1229 switch_core_file_write(&rh->out_fh, fill_data, &fill_len);
1230 }
1231
1232
1233 if (rh->last_read_time && rh->last_read_time < now) {
1234 diff = ((now - rh->last_read_time) + 3000 ) / rh->read_impl.microseconds_per_packet;
1235
1236 if (diff > 1) {
1237 unsigned char fill_data[SWITCH_RECOMMENDED_BUFFER_SIZE8192] = {0};
1238 switch_core_gen_encoded_silence(fill_data, &rh->read_impl, len);
1239
1240 while(diff > 1) {
1241 switch_size_t fill_len = len;
1242 switch_core_file_write(&rh->in_fh, fill_data, &fill_len);
1243 diff--;
1244 }
1245 }
1246 }
1247
1248 switch_core_file_write(&rh->in_fh, mask ? null_data : nframe->data, &len);
1249 rh->last_read_time = now;
1250
1251 }
1252 break;
1253 case SWITCH_ABC_TYPE_TAP_NATIVE_WRITE:
1254 {
1255 switch_time_t now = switch_micro_time_now();
1256 switch_time_t diff;
1257 rh->wready = 1;
1258
1259 nframe = switch_core_media_bug_get_native_write_frame(bug);
1260 len = nframe->datalen;
1261
1262 if (!rh->rready) {
1263 unsigned char fill_data[SWITCH_RECOMMENDED_BUFFER_SIZE8192] = {0};
1264 switch_size_t fill_len = len;
1265 switch_core_gen_encoded_silence(fill_data, &rh->read_impl, len);
1266 switch_core_file_write(&rh->in_fh, fill_data, &fill_len);
1267 }
1268
1269
1270
1271
1272 if (rh->last_write_time && rh->last_write_time < now) {
1273 diff = ((now - rh->last_write_time) + 3000 ) / rh->read_impl.microseconds_per_packet;
1274
1275 if (diff > 1) {
1276 unsigned char fill_data[SWITCH_RECOMMENDED_BUFFER_SIZE8192] = {0};
1277 switch_core_gen_encoded_silence(fill_data, &rh->read_impl, len);
1278
1279 while(diff > 1) {
1280 switch_size_t fill_len = len;
1281 switch_core_file_write(&rh->out_fh, fill_data, &fill_len);
1282 diff--;
1283 }
1284 }
1285 }
1286
1287 switch_core_file_write(&rh->out_fh, mask ? null_data : nframe->data, &len);
1288 rh->last_write_time = now;
1289
1290 }
1291 break;
1292 case SWITCH_ABC_TYPE_CLOSE:
1293 {
1294 const char *var;
1295
1296 switch_codec_implementation_t read_impl = { 0 };
1297 switch_core_session_get_read_impl(session, &read_impl);
1298
1299 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 1299, (const char*)(session)
, SWITCH_LOG_DEBUG, "Stop recording file %s\n", rh->file);
1300 switch_channel_set_private(channel, rh->file, NULL((void*)0));
1301
1302 if (rh->native) {
1303 switch_core_file_close(&rh->in_fh);
1304 switch_core_file_close(&rh->out_fh);
1305 } else if (rh->fh) {
1306 switch_size_t len;
1307 uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE8192];
1308 switch_frame_t frame = { 0 };
1309
1310 if (rh->thread_ready) {
1311 switch_status_t st;
1312
1313 rh->thread_ready = 0;
1314 switch_thread_join(&st, rh->thread);
1315 }
1316
1317 if (rh->thread_buffer) {
1318 switch_buffer_destroy(&rh->thread_buffer);
1319 }
1320
1321
1322 frame.data = data;
1323 frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE8192;
1324
1325 while (switch_core_media_bug_read(bug, &frame, SWITCH_TRUE) == SWITCH_STATUS_SUCCESS) {
1326 len = (switch_size_t) frame.datalen / 2;
1327
1328 if (len && switch_core_file_write(rh->fh, mask ? null_data : data, &len) != SWITCH_STATUS_SUCCESS) {
1329 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 1329, (const char*)(session)
, SWITCH_LOG_ERROR, "Error writing %s\n", rh->file);
1330 /* File write failed */
1331 set_completion_cause(rh, "uri-failure");
1332 if (rh->hangup_on_error) {
1333 switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER)switch_channel_perform_hangup(channel, "src/switch_ivr_async.c"
, (const char *)__func__, 1333, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER
)
;
1334 switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
1335 }
1336 send_record_stop_event(channel, &read_impl, rh);
1337 return SWITCH_FALSE;
1338 }
1339 }
1340
1341
1342 switch_core_file_close(rh->fh);
1343 if (rh->fh->samples_out < rh->fh->samplerate * rh->min_sec) {
1344 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 1344, (const char*)(session)
, SWITCH_LOG_DEBUG, "Discarding short file %s\n", rh->file);
1345 switch_channel_set_variable(channel, "RECORD_DISCARDED", "true")switch_channel_set_variable_var_check(channel, "RECORD_DISCARDED"
, "true", SWITCH_TRUE)
;
1346 switch_file_remove(rh->file, switch_core_session_get_pool(session));
1347 set_completion_cause(rh, "input-too-short");
1348 }
1349
1350 if (switch_channel_down_nosig(channel)(switch_channel_get_state(channel) >= CS_HANGUP)) {
1351 /* We got hung up */
1352 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 1352, (const char*)(session)
, SWITCH_LOG_DEBUG, "Channel is hung up\n");
1353 if (rh->speech_detected) {
1354 /* Treat it as equivalent with final-silence */
1355 set_completion_cause(rh, "success-silence");
1356 } else {
1357 /* Treat it as equivalent with inital-silence timeout */
1358 set_completion_cause(rh, "no-input-timeout");
1359 }
1360 } else {
1361 /* Set the completion_cause to maxtime reached, unless it's already set */
1362 set_completion_cause(rh, "success-maxtime");
1363 }
1364 }
1365
1366 send_record_stop_event(channel, &read_impl, rh);
1367
1368 switch_channel_execute_on(channel, SWITCH_RECORD_POST_PROCESS_EXEC_APP_VARIABLE"record_post_process_exec_app");
1369
1370 if ((var = switch_channel_get_variable(channel, SWITCH_RECORD_POST_PROCESS_EXEC_API_VARIABLE)switch_channel_get_variable_dup(channel, "record_post_process_exec_api"
, SWITCH_TRUE, -1)
)) {
1371 char *cmd = switch_core_session_strdup(session, var)switch_core_perform_session_strdup(session, var, "src/switch_ivr_async.c"
, (const char *)__func__, 1371)
;
1372 char *data, *expanded = NULL((void*)0);
1373 switch_stream_handle_t stream = { 0 };
1374
1375 SWITCH_STANDARD_STREAM(stream)memset(&stream, 0, sizeof(stream)); stream.data = malloc(
1024); ((stream.data) ? (void) (0) : __assert_fail ("stream.data"
, "src/switch_ivr_async.c", 1375, __PRETTY_FUNCTION__)); memset
(stream.data, 0, 1024); stream.end = stream.data; stream.data_size
= 1024; stream.write_function = switch_console_stream_write;
stream.raw_write_function = switch_console_stream_raw_write;
stream.alloc_len = 1024; stream.alloc_chunk = 1024
;
1376
1377 if ((data = strchr(cmd, ':')(__extension__ (__builtin_constant_p (':') && !__builtin_constant_p
(cmd) && (':') == '\0' ? (char *) __rawmemchr (cmd, ':'
) : __builtin_strchr (cmd, ':')))
)) {
1378 *data++ = '\0';
1379 expanded = switch_channel_expand_variables(channel, data)switch_channel_expand_variables_check(channel, data, ((void*)
0), ((void*)0), 0)
;
1380 }
1381
1382 switch_api_execute(cmd, expanded, session, &stream);
1383
1384 if (expanded && expanded != data) {
1385 free(expanded);
1386 }
1387
1388 switch_safe_free(stream.data)if (stream.data) {free(stream.data);stream.data=((void*)0);};
1389
1390 }
1391
1392
1393 }
1394
1395 break;
1396 case SWITCH_ABC_TYPE_READ_PING:
1397
1398 if (rh->fh) {
1399 switch_size_t len;
1400 uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE8192];
1401 switch_frame_t frame = { 0 };
1402 switch_status_t status;
1403 int i = 0;
1404
1405 frame.data = data;
1406 frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE8192;
1407
1408 for (;;) {
1409 status = switch_core_media_bug_read(bug, &frame, i++ == 0 ? SWITCH_FALSE : SWITCH_TRUE);
1410
1411 if (status != SWITCH_STATUS_SUCCESS || !frame.datalen) {
1412 break;
1413 } else {
1414 len = (switch_size_t) frame.datalen / 2 / frame.channels;
1415
1416 if (rh->thread_buffer) {
1417 switch_mutex_lock(rh->buffer_mutex);
1418 switch_buffer_write(rh->thread_buffer, mask ? null_data : data, frame.datalen);
1419 switch_mutex_unlock(rh->buffer_mutex);
1420 } else if (switch_core_file_write(rh->fh, mask ? null_data : data, &len) != SWITCH_STATUS_SUCCESS) {
1421 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 1421, (const char*)(session)
, SWITCH_LOG_ERROR, "Error writing %s\n", rh->file);
1422 /* File write failed */
1423 set_completion_cause(rh, "uri-failure");
1424 if (rh->hangup_on_error) {
1425 switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER)switch_channel_perform_hangup(channel, "src/switch_ivr_async.c"
, (const char *)__func__, 1425, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER
)
;
1426 switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
1427 }
1428 return SWITCH_FALSE;
1429 }
1430
1431 /* check for silence timeout */
1432 if (rh->silence_threshold) {
1433 switch_codec_implementation_t read_impl = { 0 };
1434 switch_core_session_get_read_impl(session, &read_impl);
1435 if (is_silence_frame(&frame, rh->silence_threshold, &read_impl)) {
1436 if (!rh->silence_time) {
1437 /* start of silence */
1438 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 1438, (const char*)(session)
, SWITCH_LOG_DEBUG, "Start of silence detected\n");
1439 rh->silence_time = switch_micro_time_now();
1440 } else {
1441 /* continuing silence */
1442 int duration_ms = (int)((switch_micro_time_now() - rh->silence_time) / 1000);
1443 if (rh->silence_timeout_ms > 0 && duration_ms >= rh->silence_timeout_ms) {
1444 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 1444, (const char*)(session)
, SWITCH_LOG_DEBUG, "Recording file %s timeout: %i >= %i\n", rh->file, duration_ms, rh->silence_timeout_ms);
1445 switch_core_media_bug_set_flag(bug, SMBF_PRUNE);
1446 if (rh->speech_detected) {
1447 /* Reached final silence timeout */
1448 set_completion_cause(rh, "success-silence");
1449 } else {
1450 /* Reached initial silence timeout */
1451 set_completion_cause(rh, "no-input-timeout");
1452 /* Discard the silent file? */
1453 }
1454 }
1455 }
1456 } else { /* not silence */
1457 if (rh->silence_time) {
1458 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 1458, (const char*)(session)
, SWITCH_LOG_DEBUG, "Start of speech detected\n");
1459 rh->speech_detected = SWITCH_TRUE;
1460 /* end of silence */
1461 rh->silence_time = 0;
1462 /* switch from initial timeout to final timeout */
1463 rh->silence_timeout_ms = rh->final_timeout_ms;
1464 }
1465 }
1466 } else {
1467 /* no silence detection */
1468 if (!rh->speech_detected) {
1469 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 1469, (const char*)(session)
, SWITCH_LOG_DEBUG, "No silence detection configured; assuming start of speech\n");
1470 rh->speech_detected = SWITCH_TRUE;
1471 }
1472 }
1473 }
1474 }
1475 }
1476 break;
1477 case SWITCH_ABC_TYPE_WRITE:
1478 default:
1479 break;
1480 }
1481
1482 return SWITCH_TRUE;
1483}
1484
1485SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_record_session_mask(switch_core_session_t *session, const char *file, switch_bool_t on)
1486{
1487 switch_media_bug_t *bug;
1488 switch_channel_t *channel = switch_core_session_get_channel(session);
1489
1490 if ((bug = switch_channel_get_private(channel, file))) {
1491 if (on) {
1492 switch_core_media_bug_set_flag(bug, SMBF_MASK);
1493 } else {
1494 switch_core_media_bug_clear_flag(bug, SMBF_MASK);
1495 }
1496 return SWITCH_STATUS_SUCCESS;
1497 }
1498 return SWITCH_STATUS_FALSE;
1499}
1500
1501SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_stop_record_session(switch_core_session_t *session, const char *file)
1502{
1503 switch_media_bug_t *bug;
1504 switch_channel_t *channel = switch_core_session_get_channel(session);
1505
1506 if (!strcasecmp(file, "all")) {
1507 return switch_core_media_bug_remove_callback(session, record_callback);
1508 } else if ((bug = switch_channel_get_private(channel, file))) {
1509 switch_core_media_bug_remove(session, &bug);
1510 return SWITCH_STATUS_SUCCESS;
1511 }
1512 return SWITCH_STATUS_FALSE;
1513}
1514
1515static void* switch_ivr_record_user_data_dup(switch_core_session_t *session, void *user_data)
1516{
1517 struct record_helper *rh = (struct record_helper *) user_data, *dup = NULL((void*)0);
1518
1519 dup = switch_core_session_alloc(session, sizeof(*dup))switch_core_perform_session_alloc(session, sizeof(*dup), "src/switch_ivr_async.c"
, (const char *)__func__, 1519)
;
1520 memcpy(dup, rh, sizeof(*rh));
1521 dup->file = switch_core_session_strdup(session, rh->file)switch_core_perform_session_strdup(session, rh->file, "src/switch_ivr_async.c"
, (const char *)__func__, 1521)
;
1522 dup->fh = switch_core_session_alloc(session, sizeof(switch_file_handle_t))switch_core_perform_session_alloc(session, sizeof(switch_file_handle_t
), "src/switch_ivr_async.c", (const char *)__func__, 1522)
;
1523 memcpy(dup->fh, rh->fh, sizeof(switch_file_handle_t));
1524
1525 return dup;
1526}
1527
1528SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_transfer_recordings(switch_core_session_t *orig_session, switch_core_session_t *new_session)
1529{
1530 const char *var = NULL((void*)0);
1531 switch_channel_t *orig_channel = switch_core_session_get_channel(orig_session);
1532 switch_channel_t *new_channel = switch_core_session_get_channel(new_session);
1533
1534 if ((var = switch_channel_get_variable(orig_channel, SWITCH_RECORD_POST_PROCESS_EXEC_API_VARIABLE)switch_channel_get_variable_dup(orig_channel, "record_post_process_exec_api"
, SWITCH_TRUE, -1)
)) {
1535 switch_channel_set_variable(new_channel, SWITCH_RECORD_POST_PROCESS_EXEC_API_VARIABLE, var)switch_channel_set_variable_var_check(new_channel, "record_post_process_exec_api"
, var, SWITCH_TRUE)
;
1536 }
1537 switch_channel_transfer_variable_prefix(orig_channel, new_channel, SWITCH_RECORD_POST_PROCESS_EXEC_APP_VARIABLE"record_post_process_exec_app");
1538
1539 return switch_core_media_bug_transfer_callback(orig_session, new_session, record_callback, switch_ivr_record_user_data_dup);
1540}
1541
1542struct eavesdrop_pvt {
1543 switch_buffer_t *buffer;
1544 switch_mutex_t *mutex;
1545 switch_buffer_t *r_buffer;
1546 switch_mutex_t *r_mutex;
1547 switch_buffer_t *w_buffer;
1548 switch_mutex_t *w_mutex;
1549 switch_core_session_t *eavesdropper;
1550 uint32_t flags;
1551 switch_frame_t demux_frame;
1552 uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE8192];
1553};
1554
1555
1556
1557static switch_bool_t eavesdrop_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
1558{
1559 struct eavesdrop_pvt *ep = (struct eavesdrop_pvt *) user_data;
1560 uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE8192];
1561 switch_frame_t frame = { 0 };
1562
1563 frame.data = data;
1564 frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE8192;
1565
1566 switch (type) {
1567 case SWITCH_ABC_TYPE_INIT:
1568 break;
1569 case SWITCH_ABC_TYPE_CLOSE:
1570 break;
1571 case SWITCH_ABC_TYPE_WRITE:
1572 break;
1573 case SWITCH_ABC_TYPE_READ_PING:
1574 if (ep->buffer) {
1575 if (switch_core_media_bug_read(bug, &frame, SWITCH_FALSE) != SWITCH_STATUS_FALSE) {
1576 switch_buffer_lock(ep->buffer);
1577 switch_buffer_zwrite(ep->buffer, frame.data, frame.datalen);
1578 switch_buffer_unlock(ep->buffer);
1579 }
1580 } else {
1581 return SWITCH_FALSE;
1582 }
1583 break;
1584 case SWITCH_ABC_TYPE_READ:
1585 break;
1586
1587 case SWITCH_ABC_TYPE_READ_REPLACE:
1588 {
1589
1590 if (switch_test_flag(ep, ED_MUX_READ)((ep)->flags & ED_MUX_READ)) {
1591 switch_frame_t *rframe = switch_core_media_bug_get_read_replace_frame(bug);
1592
1593 if (switch_buffer_inuse(ep->r_buffer) >= rframe->datalen) {
1594 uint32_t bytes;
1595 switch_buffer_lock(ep->r_buffer);
1596 bytes = (uint32_t) switch_buffer_read(ep->r_buffer, ep->data, rframe->datalen);
1597
1598 rframe->datalen = switch_merge_sln(rframe->data, rframe->samples, (int16_t *) ep->data, bytes / 2) * 2;
1599 rframe->samples = rframe->datalen / 2;
1600
1601 ep->demux_frame.data = ep->data;
1602 ep->demux_frame.datalen = bytes;
1603 ep->demux_frame.samples = bytes / 2;
1604
1605 switch_buffer_unlock(ep->r_buffer);
1606 switch_core_media_bug_set_read_replace_frame(bug, rframe);
1607 switch_core_media_bug_set_read_demux_frame(bug, &ep->demux_frame);
1608 }
1609 }
1610 }
1611 break;
1612
1613 case SWITCH_ABC_TYPE_WRITE_REPLACE:
1614 {
1615 if (switch_test_flag(ep, ED_MUX_WRITE)((ep)->flags & ED_MUX_WRITE)) {
1616 switch_frame_t *rframe = switch_core_media_bug_get_write_replace_frame(bug);
1617
1618 if (switch_buffer_inuse(ep->w_buffer) >= rframe->datalen) {
1619 uint32_t bytes;
1620 switch_buffer_lock(ep->w_buffer);
1621 bytes = (uint32_t) switch_buffer_read(ep->w_buffer, data, rframe->datalen);
1622
1623 rframe->datalen = switch_merge_sln(rframe->data, rframe->samples, (int16_t *) data, bytes / 2) * 2;
1624 rframe->samples = rframe->datalen / 2;
1625
1626 switch_buffer_unlock(ep->w_buffer);
1627 switch_core_media_bug_set_write_replace_frame(bug, rframe);
1628 }
1629 }
1630 }
1631 break;
1632
1633 default:
1634 break;
1635 }
1636
1637 return SWITCH_TRUE;
1638}
1639
1640SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_eavesdrop_pop_eavesdropper(switch_core_session_t *session, switch_core_session_t **sessionp)
1641{
1642 switch_media_bug_t *bug;
1643 switch_status_t status = SWITCH_STATUS_FALSE;
1644
1645 if (switch_core_media_bug_pop(session, "eavesdrop", &bug) == SWITCH_STATUS_SUCCESS) {
1646 struct eavesdrop_pvt *ep = (struct eavesdrop_pvt *) switch_core_media_bug_get_user_data(bug);
1647
1648 if (ep && ep->eavesdropper && ep->eavesdropper != session) {
1649 switch_core_session_read_lock(ep->eavesdropper);
1650 *sessionp = ep->eavesdropper;
1651 switch_core_media_bug_set_flag(bug, SMBF_PRUNE);
1652 status = SWITCH_STATUS_SUCCESS;
1653 }
1654 }
1655
1656
1657 return status;
1658}
1659
1660struct exec_cb_data {
1661 switch_core_session_t *caller;
1662 char *var;
1663 char *val;
1664};
1665
1666static void exec_cb(switch_media_bug_t *bug, void *user_data)
1667{
1668 struct exec_cb_data *data = (struct exec_cb_data *) user_data;
1669 struct eavesdrop_pvt *ep = (struct eavesdrop_pvt *) switch_core_media_bug_get_user_data(bug);
1670
1671 if (ep && ep->eavesdropper && ep->eavesdropper != data->caller) {
1672 switch_channel_t *a = switch_core_session_get_channel(ep->eavesdropper);
1673 switch_channel_t *b = switch_core_session_get_channel(data->caller);
1674
1675 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_async.c", (const char *
)__func__, 1675, ((void*)0)
, SWITCH_LOG_DEBUG, "%s telling %s to exec %s:%s\n",
1676 switch_channel_get_name(b), switch_channel_get_name(a), data->var, data->val);
1677
1678 switch_core_session_execute_application(ep->eavesdropper, data->var, data->val)switch_core_session_execute_application_get_flags(ep->eavesdropper
, data->var, data->val, ((void*)0))
;
1679 }
1680}
1681
1682static void display_exec_cb(switch_media_bug_t *bug, void *user_data)
1683{
1684 struct exec_cb_data *data = (struct exec_cb_data *) user_data;
1685 struct eavesdrop_pvt *ep = (struct eavesdrop_pvt *) switch_core_media_bug_get_user_data(bug);
1686
1687 if (ep && ep->eavesdropper && ep->eavesdropper != data->caller) {
1688 switch_core_session_message_t msg = { 0 };
1689
1690 msg.from = __FILE__"src/switch_ivr_async.c";
1691 msg.message_id = SWITCH_MESSAGE_INDICATE_DISPLAY;
1692 msg.string_array_arg[0] = data->var;
1693 msg.string_array_arg[1] = data->val;
1694
1695 switch_core_session_receive_message(ep->eavesdropper, &msg)switch_core_session_perform_receive_message(ep->eavesdropper
, &msg, "src/switch_ivr_async.c", (const char *)__func__,
1695)
;
1696 }
1697}
1698
1699SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_eavesdrop_exec_all(switch_core_session_t *session, const char *app, const char *arg)
1700{
1701 struct exec_cb_data *data = NULL((void*)0);
1702
1703 data = switch_core_session_alloc(session, sizeof(*data))switch_core_perform_session_alloc(session, sizeof(*data), "src/switch_ivr_async.c"
, (const char *)__func__, 1703)
;
1704 data->var = switch_core_session_strdup(session, app)switch_core_perform_session_strdup(session, app, "src/switch_ivr_async.c"
, (const char *)__func__, 1704)
;
1705 data->val = switch_core_session_strdup(session, arg)switch_core_perform_session_strdup(session, arg, "src/switch_ivr_async.c"
, (const char *)__func__, 1705)
;
1706 data->caller = session;
1707
1708 return switch_core_media_bug_exec_all(session, "eavesdrop", exec_cb, data);
1709}
1710
1711
1712SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_eavesdrop_update_display(switch_core_session_t *session, const char *name, const char *number)
1713{
1714 struct exec_cb_data *data = NULL((void*)0);
1715 switch_channel_t *channel = switch_core_session_get_channel(session);
1716 switch_status_t status = SWITCH_STATUS_FALSE;
1717
1718 data = switch_core_session_alloc(session, sizeof(*data))switch_core_perform_session_alloc(session, sizeof(*data), "src/switch_ivr_async.c"
, (const char *)__func__, 1718)
;
1719 data->var = switch_core_session_strdup(session, name)switch_core_perform_session_strdup(session, name, "src/switch_ivr_async.c"
, (const char *)__func__, 1719)
;
1720 data->val = switch_core_session_strdup(session, number)switch_core_perform_session_strdup(session, number, "src/switch_ivr_async.c"
, (const char *)__func__, 1720)
;
1721 data->caller = session;
1722
1723 if (!switch_channel_test_app_flag_key("EAVESDROP", channel, 1)) {
1724 switch_channel_set_app_flag_key("EAVESDROP", channel, 1);
1725 status = switch_core_media_bug_exec_all(session, "eavesdrop", display_exec_cb, data);
1726 switch_channel_clear_app_flag_key("EAVESDROP", channel, 1);
1727 }
1728
1729 return status;
1730}
1731
1732
1733SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_eavesdrop_session(switch_core_session_t *session,
1734 const char *uuid, const char *require_group, switch_eavesdrop_flag_t flags)
1735{
1736 switch_core_session_t *tsession;
1737 switch_status_t status = SWITCH_STATUS_FALSE;
1738 switch_channel_t *channel = switch_core_session_get_channel(session);
1739 int codec_initialized = 0;
1740 const char *name, *num;
1741
1742 if ((tsession = switch_core_session_locate(uuid)switch_core_session_perform_locate(uuid, "src/switch_ivr_async.c"
, (const char *)__func__, 1742)
)) {
1743 struct eavesdrop_pvt *ep = NULL((void*)0);
1744 switch_media_bug_t *bug = NULL((void*)0);
1745 switch_channel_t *tchannel = switch_core_session_get_channel(tsession);
1746 switch_frame_t *read_frame, write_frame = { 0 };
1747 switch_codec_t codec = { 0 };
1748 int16_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE8192 / 2];
1749 uint32_t tlen;
1750 const char *macro_name = "eavesdrop_announce";
1751 const char *id_name = NULL((void*)0);
1752 switch_codec_implementation_t tread_impl = { 0 }, read_impl = { 0 };
1753 switch_core_session_message_t msg = { 0 };
1754 char cid_buf[1024] = "";
1755 switch_caller_profile_t *cp = NULL((void*)0);
1756 uint32_t sanity = 600;
1757
1758 if (!switch_channel_media_up(channel)(switch_channel_test_flag(channel, CF_ANSWERED) || switch_channel_test_flag
(channel, CF_EARLY_MEDIA))
) {
1759 goto end;
1760 }
1761
1762 while(switch_channel_state_change_pending(tchannel) || !switch_channel_media_up(tchannel)(switch_channel_test_flag(tchannel, CF_ANSWERED) || switch_channel_test_flag
(tchannel, CF_EARLY_MEDIA))
) {
1763 switch_yield(10000)switch_sleep(10000);;
1764 if (!--sanity) break;
1765 }
1766
1767 if (!switch_channel_media_up(tchannel)(switch_channel_test_flag(tchannel, CF_ANSWERED) || switch_channel_test_flag
(tchannel, CF_EARLY_MEDIA))
) {
1768 goto end;
1769 }
1770
1771 switch_core_session_get_read_impl(tsession, &tread_impl);
1772 switch_core_session_get_read_impl(session, &read_impl);
1773
1774 if ((id_name = switch_channel_get_variable(tchannel, "eavesdrop_announce_id")switch_channel_get_variable_dup(tchannel, "eavesdrop_announce_id"
, SWITCH_TRUE, -1)
)) {
1775 const char *tmp = switch_channel_get_variable(tchannel, "eavesdrop_annnounce_macro")switch_channel_get_variable_dup(tchannel, "eavesdrop_annnounce_macro"
, SWITCH_TRUE, -1)
;
1776 if (tmp) {
1777 macro_name = tmp;
1778 }
1779
1780 switch_ivr_phrase_macro(session, macro_name, id_name, NULL, NULL)switch_ivr_phrase_macro_event(session, macro_name, id_name, (
(void*)0), ((void*)0), ((void*)0))
;
1781 }
1782
1783
1784 if (!zstr(require_group)_zstr(require_group)) {
1785 int argc, i;
1786 int ok = 0;
1787 char *argv[10] = { 0 };
1788 char *data;
1789
1790 const char *group_name = switch_channel_get_variable(tchannel, "eavesdrop_group")switch_channel_get_variable_dup(tchannel, "eavesdrop_group", SWITCH_TRUE
, -1)
;
1791 /* If we don't have a group, then return */
1792 if (!group_name) {
1793 status = SWITCH_STATUS_BREAK;
1794 goto end;
1795 }
1796 /* Separate the group */
1797 data = strdup(group_name)(__extension__ (__builtin_constant_p (group_name) && (
(size_t)(const void *)((group_name) + 1) - (size_t)(const void
*)(group_name) == 1) ? (((const char *) (group_name))[0] == '\0'
? (char *) calloc ((size_t) 1, (size_t) 1) : ({ size_t __len
= strlen (group_name) + 1; char *__retval = (char *) malloc (
__len); if (__retval != ((void*)0)) __retval = (char *) memcpy
(__retval, group_name, __len); __retval; })) : __strdup (group_name
)))
;
1798 if ((argc = switch_separate_string(data, ',', argv, (sizeof(argv) / sizeof(argv[0]))))) {
1799 for (i = 0; i < argc; i++) {
1800 /* If one of the group matches, then ok */
1801 if (argv[i] && !strcmp(argv[i], require_group)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(argv[i]) && __builtin_constant_p (require_group) &&
(__s1_len = __builtin_strlen (argv[i]), __s2_len = __builtin_strlen
(require_group), (!((size_t)(const void *)((argv[i]) + 1) - (
size_t)(const void *)(argv[i]) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)((require_group) + 1) - (size_t)(const
void *)(require_group) == 1) || __s2_len >= 4)) ? __builtin_strcmp
(argv[i], require_group) : (__builtin_constant_p (argv[i]) &&
((size_t)(const void *)((argv[i]) + 1) - (size_t)(const void
*)(argv[i]) == 1) && (__s1_len = __builtin_strlen (argv
[i]), __s1_len < 4) ? (__builtin_constant_p (require_group
) && ((size_t)(const void *)((require_group) + 1) - (
size_t)(const void *)(require_group) == 1) ? __builtin_strcmp
(argv[i], require_group) : (__extension__ ({ const unsigned char
*__s2 = (const unsigned char *) (const char *) (require_group
); int __result = (((const unsigned char *) (const char *) (argv
[i]))[0] - __s2[0]); if (__s1_len > 0 && __result ==
0) { __result = (((const unsigned char *) (const char *) (argv
[i]))[1] - __s2[1]); if (__s1_len > 1 && __result ==
0) { __result = (((const unsigned char *) (const char *) (argv
[i]))[2] - __s2[2]); if (__s1_len > 2 && __result ==
0) __result = (((const unsigned char *) (const char *) (argv
[i]))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
(require_group) && ((size_t)(const void *)((require_group
) + 1) - (size_t)(const void *)(require_group) == 1) &&
(__s2_len = __builtin_strlen (require_group), __s2_len < 4
) ? (__builtin_constant_p (argv[i]) && ((size_t)(const
void *)((argv[i]) + 1) - (size_t)(const void *)(argv[i]) == 1
) ? __builtin_strcmp (argv[i], require_group) : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (argv[i]); int __result = (((const unsigned char *) (
const char *) (require_group))[0] - __s2[0]); if (__s2_len >
0 && __result == 0) { __result = (((const unsigned char
*) (const char *) (require_group))[1] - __s2[1]); if (__s2_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (require_group))[2] - __s2[2]); if (__s2_len
> 2 && __result == 0) __result = (((const unsigned
char *) (const char *) (require_group))[3] - __s2[3]); } } __result
; })))) : __builtin_strcmp (argv[i], require_group)))); })
) {
1802 ok = 1;
1803 }
1804 }
1805 }
1806 switch_safe_free(data)if (data) {free(data);data=((void*)0);};
1807 /* If we didn't find any match, then end */
1808 if (!ok) {
1809 status = SWITCH_STATUS_BREAK;
1810 goto end;
1811 }
1812 }
1813
1814
1815 ep = switch_core_session_alloc(session, sizeof(*ep))switch_core_perform_session_alloc(session, sizeof(*ep), "src/switch_ivr_async.c"
, (const char *)__func__, 1815)
;
1816
1817 tlen = tread_impl.decoded_bytes_per_packet;
1818
1819
1820 if (switch_channel_pre_answer(channel)switch_channel_perform_pre_answer(channel, "src/switch_ivr_async.c"
, (const char *)__func__, 1820)
!= SWITCH_STATUS_SUCCESS) {
1821 goto end;
1822 }
1823
1824
1825 if (switch_core_codec_init(&codec,switch_core_codec_init_with_bitrate(&codec, "L16", ((void
*)0), tread_impl.actual_samples_per_second, tread_impl.microseconds_per_packet
/ 1000, tread_impl.number_of_channels, 0, SWITCH_CODEC_FLAG_ENCODE
| SWITCH_CODEC_FLAG_DECODE, ((void*)0), switch_core_session_get_pool
(session))
1826 "L16",switch_core_codec_init_with_bitrate(&codec, "L16", ((void
*)0), tread_impl.actual_samples_per_second, tread_impl.microseconds_per_packet
/ 1000, tread_impl.number_of_channels, 0, SWITCH_CODEC_FLAG_ENCODE
| SWITCH_CODEC_FLAG_DECODE, ((void*)0), switch_core_session_get_pool
(session))
1827 NULL,switch_core_codec_init_with_bitrate(&codec, "L16", ((void
*)0), tread_impl.actual_samples_per_second, tread_impl.microseconds_per_packet
/ 1000, tread_impl.number_of_channels, 0, SWITCH_CODEC_FLAG_ENCODE
| SWITCH_CODEC_FLAG_DECODE, ((void*)0), switch_core_session_get_pool
(session))
1828 tread_impl.actual_samples_per_second,switch_core_codec_init_with_bitrate(&codec, "L16", ((void
*)0), tread_impl.actual_samples_per_second, tread_impl.microseconds_per_packet
/ 1000, tread_impl.number_of_channels, 0, SWITCH_CODEC_FLAG_ENCODE
| SWITCH_CODEC_FLAG_DECODE, ((void*)0), switch_core_session_get_pool
(session))
1829 tread_impl.microseconds_per_packet / 1000,switch_core_codec_init_with_bitrate(&codec, "L16", ((void
*)0), tread_impl.actual_samples_per_second, tread_impl.microseconds_per_packet
/ 1000, tread_impl.number_of_channels, 0, SWITCH_CODEC_FLAG_ENCODE
| SWITCH_CODEC_FLAG_DECODE, ((void*)0), switch_core_session_get_pool
(session))
1830 tread_impl.number_of_channels,switch_core_codec_init_with_bitrate(&codec, "L16", ((void
*)0), tread_impl.actual_samples_per_second, tread_impl.microseconds_per_packet
/ 1000, tread_impl.number_of_channels, 0, SWITCH_CODEC_FLAG_ENCODE
| SWITCH_CODEC_FLAG_DECODE, ((void*)0), switch_core_session_get_pool
(session))
1831 SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,switch_core_codec_init_with_bitrate(&codec, "L16", ((void
*)0), tread_impl.actual_samples_per_second, tread_impl.microseconds_per_packet
/ 1000, tread_impl.number_of_channels, 0, SWITCH_CODEC_FLAG_ENCODE
| SWITCH_CODEC_FLAG_DECODE, ((void*)0), switch_core_session_get_pool
(session))
1832 NULL, switch_core_session_get_pool(session))switch_core_codec_init_with_bitrate(&codec, "L16", ((void
*)0), tread_impl.actual_samples_per_second, tread_impl.microseconds_per_packet
/ 1000, tread_impl.number_of_channels, 0, SWITCH_CODEC_FLAG_ENCODE
| SWITCH_CODEC_FLAG_DECODE, ((void*)0), switch_core_session_get_pool
(session))
!= SWITCH_STATUS_SUCCESS) {
1833 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 1833, (const char*)(session)
, SWITCH_LOG_ERROR, "Cannot init codec\n");
1834 switch_core_session_rwunlock(tsession);
1835 goto end;
1836 }
1837
1838 codec_initialized = 1;
1839
1840 switch_core_session_set_read_codec(session, &codec);
1841 write_frame.codec = &codec;
1842 write_frame.data = buf;
1843 write_frame.buflen = sizeof(buf);
1844 write_frame.rate = codec.implementation->actual_samples_per_second;
1845
1846 ep->eavesdropper = session;
1847 ep->flags = flags;
1848 switch_mutex_init(&ep->mutex, SWITCH_MUTEX_NESTED0x1, switch_core_session_get_pool(tsession));
1849 switch_buffer_create_dynamic(&ep->buffer, 2048, 2048, 8192);
1850 switch_buffer_add_mutex(ep->buffer, ep->mutex);
1851
1852 switch_mutex_init(&ep->w_mutex, SWITCH_MUTEX_NESTED0x1, switch_core_session_get_pool(tsession));
1853 switch_buffer_create_dynamic(&ep->w_buffer, 2048, 2048, 8192);
1854 switch_buffer_add_mutex(ep->w_buffer, ep->w_mutex);
1855
1856 switch_mutex_init(&ep->r_mutex, SWITCH_MUTEX_NESTED0x1, switch_core_session_get_pool(tsession));
1857 switch_buffer_create_dynamic(&ep->r_buffer, 2048, 2048, 8192);
1858 switch_buffer_add_mutex(ep->r_buffer, ep->r_mutex);
1859
1860
1861 if (switch_core_media_bug_add(tsession, "eavesdrop", uuid,
1862 eavesdrop_callback, ep, 0,
1863 SMBF_READ_STREAM | SMBF_WRITE_STREAM | SMBF_READ_REPLACE | SMBF_WRITE_REPLACE |
1864 SMBF_READ_PING | SMBF_THREAD_LOCK | SMBF_NO_PAUSE,
1865 &bug) != SWITCH_STATUS_SUCCESS) {
1866 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 1866, (const char*)(session)
, SWITCH_LOG_ERROR, "Cannot attach bug\n");
1867 goto end;
1868 }
1869
1870
1871 msg.from = __FILE__"src/switch_ivr_async.c";
1872
1873 /* Tell the channel we are going to be in a bridge */
1874 msg.message_id = SWITCH_MESSAGE_INDICATE_BRIDGE;
1875 switch_core_session_receive_message(session, &msg)switch_core_session_perform_receive_message(session, &msg
, "src/switch_ivr_async.c", (const char *)__func__, 1875)
;
1876 cp = switch_channel_get_caller_profile(tchannel);
1877
1878 name = cp->caller_id_name;
1879 num = cp->caller_id_number;
1880
1881 if (flags & ED_COPY_DISPLAY) {
1882 if (switch_channel_test_flag(tchannel, CF_BRIDGE_ORIGINATOR) || !switch_channel_test_flag(tchannel, CF_BRIDGED)) {
1883 name = cp->callee_id_name;
1884 num = cp->callee_id_number;
1885 } else {
1886 name = cp->caller_id_name;
1887 num = cp->caller_id_number;
1888 }
1889 }
1890
1891 sanity = 300;
1892 while(switch_channel_up(channel)(switch_channel_check_signal(channel, SWITCH_TRUE) || switch_channel_get_state
(channel) < CS_HANGUP)
&& !switch_channel_media_ack(channel)(!switch_channel_test_cap(channel, CC_MEDIA_ACK) || switch_channel_test_flag
(channel, CF_MEDIA_ACK))
&& --sanity) {
1893 switch_yield(10000)switch_sleep(10000);;
1894 }
1895
1896
1897 switch_snprintf(cid_buf, sizeof(cid_buf), "%s|%s", name, num);
1898 msg.string_arg = cid_buf;
1899 msg.message_id = SWITCH_MESSAGE_INDICATE_DISPLAY;
1900 switch_core_session_receive_message(session, &msg)switch_core_session_perform_receive_message(session, &msg
, "src/switch_ivr_async.c", (const char *)__func__, 1900)
;
1901
1902 while (switch_channel_up_nosig(tchannel)(switch_channel_get_state(tchannel) < CS_HANGUP) && switch_channel_ready(channel)switch_channel_test_ready(channel, SWITCH_TRUE, SWITCH_FALSE)) {
1903 uint32_t len = sizeof(buf);
1904 switch_event_t *event = NULL((void*)0);
1905 char *fcommand = NULL((void*)0);
1906 char db[2] = "";
1907
1908 status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
1909
1910 if (!SWITCH_READ_ACCEPTABLE(status)(status == SWITCH_STATUS_SUCCESS || status == SWITCH_STATUS_BREAK
|| status == SWITCH_STATUS_INUSE)
) {
1911 goto end_loop;
1912 }
1913
1914 if (switch_core_session_dequeue_event(session, &event, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
1915 char *command = switch_event_get_header(event, "eavesdrop-command")switch_event_get_header_idx(event, "eavesdrop-command", -1);
1916 if (command) {
1917 fcommand = switch_core_session_strdup(session, command)switch_core_perform_session_strdup(session, command, "src/switch_ivr_async.c"
, (const char *)__func__, 1917)
;
1918 }
1919 switch_event_destroy(&event);
1920 }
1921
1922 if ((flags & ED_DTMF) && switch_channel_has_dtmf(channel)) {
1923 switch_dtmf_t dtmf = { 0 };
1924 switch_channel_dequeue_dtmf(channel, &dtmf);
1925 db[0] = dtmf.digit;
1926 fcommand = db;
1927 }
1928
1929 if (fcommand) {
1930 char *d;
1931 for (d = fcommand; *d; d++) {
1932 int z = 1;
1933
1934 switch (*d) {
1935 case '1':
1936 switch_set_flag(ep, ED_MUX_READ)(ep)->flags |= (ED_MUX_READ);
1937 switch_clear_flag(ep, ED_MUX_WRITE)(ep)->flags &= ~(ED_MUX_WRITE);
1938 break;
1939 case '2':
1940 switch_set_flag(ep, ED_MUX_WRITE)(ep)->flags |= (ED_MUX_WRITE);
1941 switch_clear_flag(ep, ED_MUX_READ)(ep)->flags &= ~(ED_MUX_READ);
1942 break;
1943 case '3':
1944 switch_set_flag(ep, ED_MUX_READ)(ep)->flags |= (ED_MUX_READ);
1945 switch_set_flag(ep, ED_MUX_WRITE)(ep)->flags |= (ED_MUX_WRITE);
1946 break;
1947 case '0':
1948 switch_clear_flag(ep, ED_MUX_READ)(ep)->flags &= ~(ED_MUX_READ);
1949 switch_clear_flag(ep, ED_MUX_WRITE)(ep)->flags &= ~(ED_MUX_WRITE);
1950 break;
1951 case '*':
1952 goto end_loop;
1953 default:
1954 z = 0;
1955 break;
1956
1957 }
1958
1959 if (z) {
1960 if (ep->r_buffer) {
1961 switch_buffer_lock(ep->r_buffer);
1962 switch_buffer_zero(ep->r_buffer);
1963 switch_buffer_unlock(ep->r_buffer);
1964 }
1965
1966 if (ep->w_buffer) {
1967 switch_buffer_lock(ep->w_buffer);
1968 switch_buffer_zero(ep->w_buffer);
1969 switch_buffer_unlock(ep->w_buffer);
1970 }
1971 }
1972 }
1973 }
1974
1975 if (!switch_test_flag(read_frame, SFF_CNG)((read_frame)->flags & SFF_CNG)) {
1976 switch_buffer_lock(ep->r_buffer);
1977 switch_buffer_zwrite(ep->r_buffer, read_frame->data, read_frame->datalen);
1978 switch_buffer_unlock(ep->r_buffer);
1979
1980 switch_buffer_lock(ep->w_buffer);
1981 switch_buffer_zwrite(ep->w_buffer, read_frame->data, read_frame->datalen);
1982 switch_buffer_unlock(ep->w_buffer);
1983 }
1984
1985 if (len > tlen) {
1986 len = tlen;
1987 }
1988
1989 if (switch_buffer_inuse(ep->buffer) >= len) {
1990 switch_buffer_lock(ep->buffer);
1991 while (switch_buffer_inuse(ep->buffer) >= len) {
1992 write_frame.datalen = (uint32_t) switch_buffer_read(ep->buffer, buf, len);
1993 write_frame.samples = write_frame.datalen / 2;
1994
1995 if ((status = switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0)) != SWITCH_STATUS_SUCCESS) {
1996 break;
1997 }
1998 }
1999 switch_buffer_unlock(ep->buffer);
2000 }
2001
2002 }
2003
2004 end_loop:
2005
2006 /* Tell the channel we are no longer going to be in a bridge */
2007 msg.message_id = SWITCH_MESSAGE_INDICATE_UNBRIDGE;
2008 switch_core_session_receive_message(session, &msg)switch_core_session_perform_receive_message(session, &msg
, "src/switch_ivr_async.c", (const char *)__func__, 2008)
;
2009
2010
2011
2012 end:
2013
2014 if (codec_initialized)
2015 switch_core_codec_destroy(&codec);
2016
2017 if (bug) {
2018 switch_core_media_bug_remove(tsession, &bug);
2019 }
2020
2021 if (ep) {
2022 if (ep->buffer) {
2023 switch_buffer_destroy(&ep->buffer);
2024 }
2025
2026 if (ep->r_buffer) {
2027 switch_buffer_destroy(&ep->r_buffer);
2028 }
2029
2030 if (ep->w_buffer) {
2031 switch_buffer_destroy(&ep->w_buffer);
2032 }
2033 }
2034
2035 switch_core_session_rwunlock(tsession);
2036 status = SWITCH_STATUS_SUCCESS;
2037
2038 switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
2039 }
2040
2041 return status;
2042}
2043
2044SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_record_session(switch_core_session_t *session, char *file, uint32_t limit, switch_file_handle_t *fh)
2045{
2046 switch_channel_t *channel = switch_core_session_get_channel(session);
2047 const char *p;
2048 const char *vval;
2049 switch_media_bug_t *bug;
2050 switch_status_t status;
2051 time_t to = 0;
2052 switch_media_bug_flag_t flags = SMBF_READ_STREAM | SMBF_WRITE_STREAM | SMBF_READ_PING;
2053 uint8_t channels;
2054 switch_codec_implementation_t read_impl = { 0 };
2055 struct record_helper *rh = NULL((void*)0);
2056 int file_flags = SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT;
2057 switch_bool_t hangup_on_error = SWITCH_FALSE;
2058 char *file_path = NULL((void*)0);
2059 char *ext;
2060 char *in_file = NULL((void*)0), *out_file = NULL((void*)0);
2061
2062 if ((p = switch_channel_get_variable(channel, "RECORD_HANGUP_ON_ERROR")switch_channel_get_variable_dup(channel, "RECORD_HANGUP_ON_ERROR"
, SWITCH_TRUE, -1)
)) {
2063 hangup_on_error = switch_true(p);
2064 }
2065
2066 if ((status = switch_channel_pre_answer(channel)switch_channel_perform_pre_answer(channel, "src/switch_ivr_async.c"
, (const char *)__func__, 2066)
) != SWITCH_STATUS_SUCCESS) {
2067 return SWITCH_STATUS_FALSE;
2068 }
2069
2070 if (!switch_channel_media_up(channel)(switch_channel_test_flag(channel, CF_ANSWERED) || switch_channel_test_flag
(channel, CF_EARLY_MEDIA))
|| !switch_core_session_get_read_codec(session)) {
2071 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2071, (const char*)(session)
, SWITCH_LOG_ERROR, "Can not record session. Media not enabled on channel\n");
2072 return SWITCH_STATUS_FALSE;
2073 }
2074
2075 switch_core_session_get_read_impl(session, &read_impl);
2076 channels = read_impl.number_of_channels;
2077
2078 if ((bug = switch_channel_get_private(channel, file))) {
2079 if (switch_true(switch_channel_get_variable(channel, "RECORD_TOGGLE_ON_REPEAT")switch_channel_get_variable_dup(channel, "RECORD_TOGGLE_ON_REPEAT"
, SWITCH_TRUE, -1)
)) {
2080 return switch_ivr_stop_record_session(session, file);
2081 }
2082
2083 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2083, (const char*)(session)
, SWITCH_LOG_WARNING, "Already recording [%s]\n", file);
2084 return SWITCH_STATUS_SUCCESS;
2085 }
2086
2087
2088 if ((p = switch_channel_get_variable(channel, "RECORD_CHECK_BRIDGE")switch_channel_get_variable_dup(channel, "RECORD_CHECK_BRIDGE"
, SWITCH_TRUE, -1)
) && switch_true(p)) {
2089 switch_core_session_t *other_session;
2090 int exist = 0;
2091 switch_status_t rstatus = SWITCH_STATUS_SUCCESS;
2092
2093 if (switch_core_session_get_partner(session, &other_session)switch_core_session_perform_get_partner(session, &other_session
, "src/switch_ivr_async.c", (const char *)__func__, 2093)
== SWITCH_STATUS_SUCCESS) {
2094 switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
2095 if ((bug = switch_channel_get_private(other_channel, file))) {
2096 if (switch_true(switch_channel_get_variable(other_channel, "RECORD_TOGGLE_ON_REPEAT")switch_channel_get_variable_dup(other_channel, "RECORD_TOGGLE_ON_REPEAT"
, SWITCH_TRUE, -1)
)) {
2097 rstatus = switch_ivr_stop_record_session(other_session, file);
2098 } else {
2099 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(other_session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2099, (const char*)(other_session)
, SWITCH_LOG_WARNING, "Already recording [%s]\n", file);
2100 }
2101 exist = 1;
2102 }
2103 switch_core_session_rwunlock(other_session);
2104 }
2105
2106 if (exist) {
2107 return rstatus;
2108 }
2109 }
2110
2111 if (!fh) {
2112 if (!(fh = switch_core_session_alloc(session, sizeof(*fh))switch_core_perform_session_alloc(session, sizeof(*fh), "src/switch_ivr_async.c"
, (const char *)__func__, 2112)
)) {
2113 return SWITCH_STATUS_MEMERR;
2114 }
2115 }
2116
2117 if ((p = switch_channel_get_variable(channel, "RECORD_WRITE_ONLY")switch_channel_get_variable_dup(channel, "RECORD_WRITE_ONLY",
SWITCH_TRUE, -1)
) && switch_true(p)) {
2118 flags &= ~SMBF_READ_STREAM;
2119 flags |= SMBF_WRITE_STREAM;
2120 }
2121
2122 if ((p = switch_channel_get_variable(channel, "RECORD_READ_ONLY")switch_channel_get_variable_dup(channel, "RECORD_READ_ONLY", SWITCH_TRUE
, -1)
) && switch_true(p)) {
2123 flags &= ~SMBF_WRITE_STREAM;
2124 flags |= SMBF_READ_STREAM;
2125 }
2126
2127 if ((p = switch_channel_get_variable(channel, "RECORD_STEREO")switch_channel_get_variable_dup(channel, "RECORD_STEREO", SWITCH_TRUE
, -1)
) && switch_true(p)) {
2128 flags |= SMBF_STEREO;
2129 flags &= ~SMBF_STEREO_SWAP;
2130 channels = 2;
2131 }
2132
2133 if ((p = switch_channel_get_variable(channel, "RECORD_STEREO_SWAP")switch_channel_get_variable_dup(channel, "RECORD_STEREO_SWAP"
, SWITCH_TRUE, -1)
) && switch_true(p)) {
2134 flags |= SMBF_STEREO;
2135 flags |= SMBF_STEREO_SWAP;
2136 channels = 2;
2137 }
2138
2139 if ((p = switch_channel_get_variable(channel, "RECORD_ANSWER_REQ")switch_channel_get_variable_dup(channel, "RECORD_ANSWER_REQ",
SWITCH_TRUE, -1)
) && switch_true(p)) {
2140 flags |= SMBF_ANSWER_REQ;
2141 }
2142
2143 if ((p = switch_channel_get_variable(channel, "RECORD_BRIDGE_REQ")switch_channel_get_variable_dup(channel, "RECORD_BRIDGE_REQ",
SWITCH_TRUE, -1)
) && switch_true(p)) {
2144 flags |= SMBF_BRIDGE_REQ;
2145 }
2146
2147 if ((p = switch_channel_get_variable(channel, "RECORD_APPEND")switch_channel_get_variable_dup(channel, "RECORD_APPEND", SWITCH_TRUE
, -1)
) && switch_true(p)) {
2148 file_flags |= SWITCH_FILE_WRITE_APPEND;
2149 }
2150
2151
2152 fh->samplerate = 0;
2153 if ((vval = switch_channel_get_variable(channel, "record_sample_rate")switch_channel_get_variable_dup(channel, "record_sample_rate"
, SWITCH_TRUE, -1)
)) {
2154 int tmp = 0;
2155
2156 tmp = atoi(vval);
2157
2158 if (switch_is_valid_rate(tmp)(tmp == 8000 || tmp == 12000 || tmp == 16000 || tmp == 24000 ||
tmp == 32000 || tmp == 11025 || tmp == 22050 || tmp == 44100
|| tmp == 48000)
) {
2159 fh->samplerate = tmp;
2160 }
2161 }
2162
2163 if (!fh->samplerate) {
2164 fh->samplerate = read_impl.actual_samples_per_second;
2165 }
2166
2167 fh->channels = channels;
2168
2169 if ((vval = switch_channel_get_variable(channel, "enable_file_write_buffering")switch_channel_get_variable_dup(channel, "enable_file_write_buffering"
, SWITCH_TRUE, -1)
)) {
2170 int tmp = atoi(vval);
2171
2172 if (tmp > 0) {
2173 fh->pre_buffer_datalen = tmp;
2174 } else if (switch_true(vval)) {
2175 fh->pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN65536;
2176 }
2177
2178 } else {
2179 fh->pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN65536;
2180 }
2181
2182
2183 if (!switch_is_file_path(file)) {
2184 char *tfile = NULL((void*)0);
2185 char *e;
2186 const char *prefix;
2187
2188 prefix = switch_channel_get_variable(channel, "sound_prefix")switch_channel_get_variable_dup(channel, "sound_prefix", SWITCH_TRUE
, -1)
;
2189
2190 if (!prefix) {
2191 prefix = SWITCH_GLOBAL_dirs.base_dir;
2192 }
2193
2194 if (*file == '[') {
2195 tfile = switch_core_session_strdup(session, file)switch_core_perform_session_strdup(session, file, "src/switch_ivr_async.c"
, (const char *)__func__, 2195)
;
2196 if ((e = switch_find_end_paren(tfile, '[', ']'))) {
2197 *e = '\0';
2198 file = e + 1;
2199 } else {
2200 tfile = NULL((void*)0);
2201 }
2202 } else {
2203 file_path = switch_core_session_sprintf(session, "%s%s%s", prefix, SWITCH_PATH_SEPARATOR"/", file);
2204 }
2205
2206 file = switch_core_session_sprintf(session, "%s%s%s%s%s", switch_str_nil(tfile)(tfile ? tfile : ""), tfile ? "]" : "", prefix, SWITCH_PATH_SEPARATOR"/", file);
2207 } else {
2208 file_path = switch_core_session_strdup(session, file)switch_core_perform_session_strdup(session, file, "src/switch_ivr_async.c"
, (const char *)__func__, 2208)
;
2209 }
2210
2211 if (file_path && !strstr(file_path, SWITCH_URL_SEPARATOR"://")) {
2212 char *p;
2213 char *path = switch_core_session_strdup(session, file_path)switch_core_perform_session_strdup(session, file_path, "src/switch_ivr_async.c"
, (const char *)__func__, 2213)
;
2214
2215 if ((p = strrchr(path, *SWITCH_PATH_SEPARATOR"/"))) {
2216 *p = '\0';
2217 if (switch_dir_make_recursive(path, SWITCH_DEFAULT_DIR_PERMS0x0400 | 0x0200 | 0x0100 | 0x0040 | 0x0010, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
2218 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2218, (const char*)(session)
, SWITCH_LOG_ERROR, "Error creating %s\n", path);
2219 return SWITCH_STATUS_GENERR;
2220 }
2221
2222 } else {
2223 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2223, (const char*)(session)
, SWITCH_LOG_ERROR, "Error finding the folder path section in '%s'\n", path);
2224 path = NULL((void*)0);
2225 }
2226 }
2227
2228 rh = switch_core_session_alloc(session, sizeof(*rh))switch_core_perform_session_alloc(session, sizeof(*rh), "src/switch_ivr_async.c"
, (const char *)__func__, 2228)
;
2229
2230 if ((ext = strrchr(file, '.'))) {
2231 ext++;
2232 if (switch_core_file_open(fh, file, channels, read_impl.actual_samples_per_second, file_flags, NULL)switch_core_perform_file_open("src/switch_ivr_async.c", (const
char *)__func__, 2232, fh, file, channels, read_impl.actual_samples_per_second
, file_flags, ((void*)0))
!= SWITCH_STATUS_SUCCESS) {
2233 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2233, (const char*)(session)
, SWITCH_LOG_ERROR, "Error opening %s\n", file);
2234 if (hangup_on_error) {
2235 switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER)switch_channel_perform_hangup(channel, "src/switch_ivr_async.c"
, (const char *)__func__, 2235, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER
)
;
2236 switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
2237 }
2238 return SWITCH_STATUS_GENERR;
2239 }
2240 } else {
2241 int tflags = 0;
2242
2243 ext = read_impl.iananame;
2244
2245 in_file = switch_core_session_sprintf(session, "%s-in.%s", file, ext);
2246 out_file = switch_core_session_sprintf(session, "%s-out.%s", file, ext);
2247
2248
2249 if (switch_core_file_open(&rh->in_fh, in_file, channels, read_impl.actual_samples_per_second, file_flags, NULL)switch_core_perform_file_open("src/switch_ivr_async.c", (const
char *)__func__, 2249, &rh->in_fh, in_file, channels,
read_impl.actual_samples_per_second, file_flags, ((void*)0))
!= SWITCH_STATUS_SUCCESS) {
2250 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2250, (const char*)(session)
, SWITCH_LOG_ERROR, "Error opening %s\n", in_file);
2251 if (hangup_on_error) {
2252 switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER)switch_channel_perform_hangup(channel, "src/switch_ivr_async.c"
, (const char *)__func__, 2252, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER
)
;
2253 switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
2254 }
2255 return SWITCH_STATUS_GENERR;
2256 }
2257
2258 if (switch_core_file_open(&rh->out_fh, out_file, channels, read_impl.actual_samples_per_second, file_flags, NULL)switch_core_perform_file_open("src/switch_ivr_async.c", (const
char *)__func__, 2258, &rh->out_fh, out_file, channels
, read_impl.actual_samples_per_second, file_flags, ((void*)0)
)
!= SWITCH_STATUS_SUCCESS) {
2259 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2259, (const char*)(session)
, SWITCH_LOG_ERROR, "Error opening %s\n", out_file);
2260 switch_core_file_close(&rh->in_fh);
2261 if (hangup_on_error) {
2262 switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER)switch_channel_perform_hangup(channel, "src/switch_ivr_async.c"
, (const char *)__func__, 2262, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER
)
;
2263 switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
2264 }
2265 return SWITCH_STATUS_GENERR;
2266 }
2267
2268 rh->native = 1;
2269 fh = NULL((void*)0);
2270
2271 if ((flags & SMBF_WRITE_STREAM)) {
2272 tflags |= SMBF_TAP_NATIVE_WRITE;
2273 }
2274
2275 if ((flags & SMBF_READ_STREAM)) {
2276 tflags |= SMBF_TAP_NATIVE_READ;
2277 }
2278
2279 flags = tflags;
2280 }
2281
2282
2283
2284 if ((p = switch_channel_get_variable(channel, "RECORD_TITLE")switch_channel_get_variable_dup(channel, "RECORD_TITLE", SWITCH_TRUE
, -1)
)) {
2285 vval = (const char *) switch_core_session_strdup(session, p)switch_core_perform_session_strdup(session, p, "src/switch_ivr_async.c"
, (const char *)__func__, 2285)
;
2286 if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_TITLE, vval);
2287 switch_channel_set_variable(channel, "RECORD_TITLE", NULL)switch_channel_set_variable_var_check(channel, "RECORD_TITLE"
, ((void*)0), SWITCH_TRUE)
;
2288 }
2289
2290 if ((p = switch_channel_get_variable(channel, "RECORD_COPYRIGHT")switch_channel_get_variable_dup(channel, "RECORD_COPYRIGHT", SWITCH_TRUE
, -1)
)) {
2291 vval = (const char *) switch_core_session_strdup(session, p)switch_core_perform_session_strdup(session, p, "src/switch_ivr_async.c"
, (const char *)__func__, 2291)
;
2292 if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_COPYRIGHT, vval);
2293 switch_channel_set_variable(channel, "RECORD_COPYRIGHT", NULL)switch_channel_set_variable_var_check(channel, "RECORD_COPYRIGHT"
, ((void*)0), SWITCH_TRUE)
;
2294 }
2295
2296 if ((p = switch_channel_get_variable(channel, "RECORD_SOFTWARE")switch_channel_get_variable_dup(channel, "RECORD_SOFTWARE", SWITCH_TRUE
, -1)
)) {
2297 vval = (const char *) switch_core_session_strdup(session, p)switch_core_perform_session_strdup(session, p, "src/switch_ivr_async.c"
, (const char *)__func__, 2297)
;
2298 if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_SOFTWARE, vval);
2299 switch_channel_set_variable(channel, "RECORD_SOFTWARE", NULL)switch_channel_set_variable_var_check(channel, "RECORD_SOFTWARE"
, ((void*)0), SWITCH_TRUE)
;
2300 }
2301
2302 if ((p = switch_channel_get_variable(channel, "RECORD_ARTIST")switch_channel_get_variable_dup(channel, "RECORD_ARTIST", SWITCH_TRUE
, -1)
)) {
2303 vval = (const char *) switch_core_session_strdup(session, p)switch_core_perform_session_strdup(session, p, "src/switch_ivr_async.c"
, (const char *)__func__, 2303)
;
2304 if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_ARTIST, vval);
2305 switch_channel_set_variable(channel, "RECORD_ARTIST", NULL)switch_channel_set_variable_var_check(channel, "RECORD_ARTIST"
, ((void*)0), SWITCH_TRUE)
;
2306 }
2307
2308 if ((p = switch_channel_get_variable(channel, "RECORD_COMMENT")switch_channel_get_variable_dup(channel, "RECORD_COMMENT", SWITCH_TRUE
, -1)
)) {
2309 vval = (const char *) switch_core_session_strdup(session, p)switch_core_perform_session_strdup(session, p, "src/switch_ivr_async.c"
, (const char *)__func__, 2309)
;
2310 if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_COMMENT, vval);
2311 switch_channel_set_variable(channel, "RECORD_COMMENT", NULL)switch_channel_set_variable_var_check(channel, "RECORD_COMMENT"
, ((void*)0), SWITCH_TRUE)
;
2312 }
2313
2314 if ((p = switch_channel_get_variable(channel, "RECORD_DATE")switch_channel_get_variable_dup(channel, "RECORD_DATE", SWITCH_TRUE
, -1)
)) {
2315 vval = (const char *) switch_core_session_strdup(session, p)switch_core_perform_session_strdup(session, p, "src/switch_ivr_async.c"
, (const char *)__func__, 2315)
;
2316 if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_DATE, vval);
2317 switch_channel_set_variable(channel, "RECORD_DATE", NULL)switch_channel_set_variable_var_check(channel, "RECORD_DATE",
((void*)0), SWITCH_TRUE)
;
2318 }
2319
2320 if (limit) {
2321 to = switch_epoch_time_now(NULL((void*)0)) + limit;
2322 }
2323
2324 rh->fh = fh;
2325 rh->file = switch_core_session_strdup(session, file)switch_core_perform_session_strdup(session, file, "src/switch_ivr_async.c"
, (const char *)__func__, 2325)
;
2326 rh->packet_len = read_impl.decoded_bytes_per_packet;
2327
2328 if (file_flags & SWITCH_FILE_WRITE_APPEND) {
2329 rh->min_sec = 3;
2330 }
2331
2332 if ((p = switch_channel_get_variable(channel, "RECORD_MIN_SEC")switch_channel_get_variable_dup(channel, "RECORD_MIN_SEC", SWITCH_TRUE
, -1)
)) {
2333 int tmp = atoi(p);
2334 if (tmp >= 0) {
2335 rh->min_sec = tmp;
2336 }
2337 }
2338
2339 if ((p = switch_channel_get_variable(channel, "RECORD_INITIAL_TIMEOUT_MS")switch_channel_get_variable_dup(channel, "RECORD_INITIAL_TIMEOUT_MS"
, SWITCH_TRUE, -1)
)) {
2340 int tmp = atoi(p);
2341 if (tmp >= 0) {
2342 rh->initial_timeout_ms = tmp;
2343 rh->silence_threshold = 200;
2344 }
2345 }
2346
2347 if ((p = switch_channel_get_variable(channel, "RECORD_FINAL_TIMEOUT_MS")switch_channel_get_variable_dup(channel, "RECORD_FINAL_TIMEOUT_MS"
, SWITCH_TRUE, -1)
)) {
2348 int tmp = atoi(p);
2349 if (tmp >= 0) {
2350 rh->final_timeout_ms = tmp;
2351 rh->silence_threshold = 200;
2352 }
2353 }
2354
2355 if ((p = switch_channel_get_variable(channel, "RECORD_SILENCE_THRESHOLD")switch_channel_get_variable_dup(channel, "RECORD_SILENCE_THRESHOLD"
, SWITCH_TRUE, -1)
)) {
2356 int tmp = atoi(p);
2357 if (tmp >= 0) {
2358 rh->silence_threshold = tmp;
2359 }
2360 }
2361
2362 rh->hangup_on_error = hangup_on_error;
2363
2364 if ((status = switch_core_media_bug_add(session, "session_record", file,
2365 record_callback, rh, to, flags, &bug)) != SWITCH_STATUS_SUCCESS) {
2366 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2366, (const char*)(session)
, SWITCH_LOG_ERROR, "Error adding media bug for file %s\n", file);
2367 if (rh->native) {
2368 switch_core_file_close(&rh->in_fh);
2369 switch_core_file_close(&rh->out_fh);
2370 } else {
2371 switch_core_file_close(fh);
2372 }
2373 return status;
2374 }
2375
2376 if ((p = switch_channel_get_variable(channel, "RECORD_PRE_BUFFER_FRAMES")switch_channel_get_variable_dup(channel, "RECORD_PRE_BUFFER_FRAMES"
, SWITCH_TRUE, -1)
)) {
2377 int tmp = atoi(p);
2378
2379 if (tmp > 0) {
2380 switch_core_media_bug_set_pre_buffer_framecount(bug, tmp);
2381 }
2382 } else {
2383 switch_core_media_bug_set_pre_buffer_framecount(bug, 25);
2384 }
2385
2386 switch_channel_set_private(channel, file, bug);
2387
2388 return SWITCH_STATUS_SUCCESS;
2389}
2390
2391
2392typedef struct {
2393 SpeexPreprocessState *read_st;
2394 SpeexPreprocessState *write_st;
2395 SpeexEchoState *read_ec;
2396 SpeexEchoState *write_ec;
2397 switch_byte_t read_data[2048];
2398 switch_byte_t write_data[2048];
2399 switch_byte_t read_out[2048];
2400 switch_byte_t write_out[2048];
2401 switch_mutex_t *read_mutex;
2402 switch_mutex_t *write_mutex;
2403 int done;
2404} pp_cb_t;
2405
2406static switch_bool_t preprocess_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
2407{
2408 switch_core_session_t *session = switch_core_media_bug_get_session(bug);
2409 switch_channel_t *channel = switch_core_session_get_channel(session);
2410 pp_cb_t *cb = (pp_cb_t *) user_data;
2411 switch_codec_implementation_t read_impl = { 0 };
2412 switch_frame_t *frame = NULL((void*)0);
2413
2414 switch_core_session_get_read_impl(session, &read_impl);
2415
2416 switch (type) {
2417 case SWITCH_ABC_TYPE_INIT:
2418 {
2419 switch_mutex_init(&cb->read_mutex, SWITCH_MUTEX_NESTED0x1, switch_core_session_get_pool(session));
2420 switch_mutex_init(&cb->write_mutex, SWITCH_MUTEX_NESTED0x1, switch_core_session_get_pool(session));
2421 }
2422 break;
2423 case SWITCH_ABC_TYPE_CLOSE:
2424 {
2425 if (cb->read_st) {
2426 speex_preprocess_state_destroy(cb->read_st);
2427 }
2428
2429 if (cb->write_st) {
2430 speex_preprocess_state_destroy(cb->write_st);
2431 }
2432
2433 if (cb->read_ec) {
2434 speex_echo_state_destroy(cb->read_ec);
2435 }
2436
2437 if (cb->write_ec) {
2438 speex_echo_state_destroy(cb->write_ec);
2439 }
2440
2441 switch_channel_set_private(channel, "_preprocess", NULL((void*)0));
2442 }
2443 break;
2444 case SWITCH_ABC_TYPE_READ_REPLACE:
2445 {
2446 if (cb->done)
2447 return SWITCH_FALSE;
2448 frame = switch_core_media_bug_get_read_replace_frame(bug);
2449
2450 if (cb->read_st) {
2451
2452 if (cb->read_ec) {
2453 speex_echo_cancellation(cb->read_ec, (int16_t *) frame->data, (int16_t *) cb->write_data, (int16_t *) cb->read_out);
2454 memcpy(frame->data, cb->read_out, frame->datalen);
2455 }
2456
2457 speex_preprocess_run(cb->read_st, frame->data);
2458 }
2459
2460 if (cb->write_ec) {
2461 memcpy(cb->read_data, frame->data, frame->datalen);
2462 }
2463 }
2464 break;
2465 case SWITCH_ABC_TYPE_WRITE_REPLACE:
2466 {
2467 if (cb->done)
2468 return SWITCH_FALSE;
2469 frame = switch_core_media_bug_get_write_replace_frame(bug);
2470
2471 if (cb->write_st) {
2472
2473 if (cb->write_ec) {
2474 speex_echo_cancellation(cb->write_ec, (int16_t *) frame->data, (int16_t *) cb->read_data, (int16_t *) cb->write_out);
2475 memcpy(frame->data, cb->write_out, frame->datalen);
2476 }
2477
2478 speex_preprocess_run(cb->write_st, frame->data);
2479 }
2480
2481 if (cb->read_ec) {
2482 memcpy(cb->write_data, frame->data, frame->datalen);
2483 }
2484 }
2485 break;
2486 default:
2487 break;
2488 }
2489
2490 return SWITCH_TRUE;
2491}
2492
2493SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_preprocess_session(switch_core_session_t *session, const char *cmds)
2494{
2495 switch_channel_t *channel = switch_core_session_get_channel(session);
2496 switch_media_bug_t *bug;
2497 switch_status_t status;
2498 time_t to = 0;
2499 switch_media_bug_flag_t flags = SMBF_NO_PAUSE;
2500 switch_codec_implementation_t read_impl = { 0 };
2501 pp_cb_t *cb;
2502 int update = 0;
2503 int argc;
2504 char *mydata = NULL((void*)0), *argv[5];
2505 int i = 0;
2506
2507 switch_core_session_get_read_impl(session, &read_impl);
2508
2509 if ((cb = switch_channel_get_private(channel, "_preprocess"))) {
2510 update = 1;
2511 } else {
2512 cb = switch_core_session_alloc(session, sizeof(*cb))switch_core_perform_session_alloc(session, sizeof(*cb), "src/switch_ivr_async.c"
, (const char *)__func__, 2512)
;
2513 }
2514
2515
2516 if (update) {
2517 if (!strcasecmp(cmds, "stop")) {
2518 cb->done = 1;
2519 return SWITCH_STATUS_SUCCESS;
2520 }
2521 }
2522
2523 mydata = strdup(cmds)(__extension__ (__builtin_constant_p (cmds) && ((size_t
)(const void *)((cmds) + 1) - (size_t)(const void *)(cmds) ==
1) ? (((const char *) (cmds))[0] == '\0' ? (char *) calloc (
(size_t) 1, (size_t) 1) : ({ size_t __len = strlen (cmds) + 1
; char *__retval = (char *) malloc (__len); if (__retval != (
(void*)0)) __retval = (char *) memcpy (__retval, cmds, __len)
; __retval; })) : __strdup (cmds)))
;
2524 argc = switch_separate_string(mydata, ',', argv, (sizeof(argv) / sizeof(argv[0])));
2525
2526 for (i = 0; i < argc; i++) {
2527 char *var = argv[i];
2528 char *val = NULL((void*)0);
2529 char rw;
2530 int tr;
2531 int err = 1;
2532 SpeexPreprocessState *st = NULL((void*)0);
2533 SpeexEchoState *ec = NULL((void*)0);
2534 switch_mutex_t *mutex = NULL((void*)0);
2535 int r = 0;
2536
2537 if (var) {
2538 if ((val = strchr(var, '=')(__extension__ (__builtin_constant_p ('=') && !__builtin_constant_p
(var) && ('=') == '\0' ? (char *) __rawmemchr (var, '='
) : __builtin_strchr (var, '=')))
)) {
2539 *val++ = '\0';
2540
2541 rw = *var++;
2542 while (*var == '.' || *var == '_') {
2543 var++;
2544 }
2545
2546 if (rw == 'r') {
2547 if (!cb->read_st) {
2548 cb->read_st = speex_preprocess_state_init(read_impl.samples_per_packet, read_impl.samples_per_second);
2549 flags |= SMBF_READ_REPLACE;
2550 }
2551 st = cb->read_st;
2552 ec = cb->read_ec;
2553 mutex = cb->read_mutex;
2554 } else if (rw == 'w') {
2555 if (!cb->write_st) {
2556 cb->write_st = speex_preprocess_state_init(read_impl.samples_per_packet, read_impl.samples_per_second);
2557 flags |= SMBF_WRITE_REPLACE;
2558 }
2559 st = cb->write_st;
2560 ec = cb->write_ec;
2561 mutex = cb->write_mutex;
2562 }
2563
2564 if (mutex)
2565 switch_mutex_lock(mutex);
2566
2567 if (st) {
2568 err = 0;
2569 tr = switch_true(val);
2570 if (!strcasecmp(var, "agc")) {
2571 int l = read_impl.samples_per_second;
2572 int tmp = atoi(val);
2573
2574 if (!tr) {
2575 l = tmp;
2576 }
2577
2578 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2578, (const char*)(session)
, SWITCH_LOG_DEBUG, "Setting AGC on %c to %d\n", rw, tr);
2579 speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC2, &tr);
2580 speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL6, &l);
2581
2582 } else if (!strcasecmp(var, "noise_suppress")) {
2583 int db = atoi(val);
2584 if (db < 0) {
2585 r = speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS18, &db);
2586 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2586, (const char*)(session)
, SWITCH_LOG_DEBUG, "Setting NOISE_SUPPRESS on %c to %d [%d]\n", rw, db,
2587 r);
2588 } else {
2589 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2589, (const char*)(session)
, SWITCH_LOG_ERROR, "Syntax error noise_suppress should be in -db\n");
2590 }
2591 } else if (!strcasecmp(var, "echo_cancel")) {
2592 int tail = 1024;
2593 int tmp = atoi(val);
2594
2595 if (!tr && tmp > 0) {
2596 tail = tmp;
2597 } else if (!tr) {
2598 if (ec) {
2599 if (rw == 'r') {
2600 speex_echo_state_destroy(cb->read_ec);
2601 cb->read_ec = NULL((void*)0);
2602 } else {
2603 speex_echo_state_destroy(cb->write_ec);
2604 cb->write_ec = NULL((void*)0);
2605 }
2606 }
2607
2608 ec = NULL((void*)0);
2609 }
2610
2611 if (!ec) {
2612 if (rw == 'r') {
2613 ec = cb->read_ec = speex_echo_state_init(read_impl.samples_per_packet, tail);
2614 speex_echo_ctl(ec, SPEEX_ECHO_SET_SAMPLING_RATE24, &read_impl.samples_per_second);
2615 flags |= SMBF_WRITE_REPLACE;
2616 } else {
2617 ec = cb->write_ec = speex_echo_state_init(read_impl.samples_per_packet, tail);
2618 speex_echo_ctl(ec, SPEEX_ECHO_SET_SAMPLING_RATE24, &read_impl.samples_per_second);
2619 flags |= SMBF_READ_REPLACE;
2620 }
2621 speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_ECHO_STATE24, ec);
2622 }
2623
2624
2625 } else if (!strcasecmp(var, "echo_suppress")) {
2626 int db = atoi(val);
2627 if (db < 0) {
2628 speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS20, &db);
2629 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2629, (const char*)(session)
, SWITCH_LOG_DEBUG, "Setting ECHO_SUPPRESS on %c to %d [%d]\n", rw, db,
2630 r);
2631 } else {
2632 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2632, (const char*)(session)
, SWITCH_LOG_ERROR, "Syntax error echo_suppress should be in -db\n");
2633 }
2634 } else {
2635 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2635, (const char*)(session)
, SWITCH_LOG_WARNING, "Warning unknown parameter [%s] \n", var);
2636 }
2637 }
2638 }
2639
2640 if (mutex)
2641 switch_mutex_unlock(mutex);
2642
2643 if (err) {
2644 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2644, (const char*)(session)
, SWITCH_LOG_ERROR, "Syntax error parsing preprocessor commands\n");
2645 }
2646
2647 } else {
2648 break;
2649 }
2650 }
2651
2652
2653 switch_safe_free(mydata)if (mydata) {free(mydata);mydata=((void*)0);};
2654
2655 if (update) {
2656 return SWITCH_STATUS_SUCCESS;
2657 }
2658
2659
2660 if ((status = switch_core_media_bug_add(session, "preprocess", NULL((void*)0),
2661 preprocess_callback, cb, to, flags, &bug)) != SWITCH_STATUS_SUCCESS) {
2662 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2662, (const char*)(session)
, SWITCH_LOG_ERROR, "Error adding media bug.\n");
2663 if (cb->read_st) {
2664 speex_preprocess_state_destroy(cb->read_st);
2665 }
2666
2667 if (cb->write_st) {
2668 speex_preprocess_state_destroy(cb->write_st);
2669 }
2670
2671 if (cb->read_ec) {
2672 speex_echo_state_destroy(cb->read_ec);
2673 }
2674
2675 if (cb->write_ec) {
2676 speex_echo_state_destroy(cb->write_ec);
2677 }
2678
2679 return status;
2680 }
2681
2682 switch_channel_set_private(channel, "_preprocess", cb);
2683
2684 return SWITCH_STATUS_SUCCESS;
2685}
2686
2687
2688typedef struct {
2689 switch_core_session_t *session;
2690 int mute;
2691 int read_level;
2692 int write_level;
2693 int read_mute;
2694 int write_mute;
2695} switch_session_audio_t;
2696
2697static switch_bool_t session_audio_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
2698{
2699 switch_session_audio_t *pvt = (switch_session_audio_t *) user_data;
2700 switch_frame_t *frame = NULL((void*)0);
2701 int level = 0, mute = 0;
2702 switch_core_session_t *session = switch_core_media_bug_get_session(bug);
2703 switch_codec_implementation_t read_impl = { 0 };
2704
2705 switch_core_session_get_read_impl(session, &read_impl);
2706
2707
2708 if (type == SWITCH_ABC_TYPE_READ_REPLACE || type == SWITCH_ABC_TYPE_WRITE_REPLACE) {
2709 if (!(pvt->read_level || pvt->write_level || pvt->read_mute || pvt->write_mute)) {
2710 switch_channel_set_private(switch_core_session_get_channel(pvt->session), "__audio", NULL((void*)0));
2711 return SWITCH_FALSE;
2712 }
2713 }
2714
2715 if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
2716 level = pvt->read_level;
2717 mute = pvt->read_mute;
2718 frame = switch_core_media_bug_get_read_replace_frame(bug);
2719 } else if (type == SWITCH_ABC_TYPE_WRITE_REPLACE) {
2720 level = pvt->write_level;
2721 mute = pvt->write_mute;
2722 frame = switch_core_media_bug_get_write_replace_frame(bug);
2723 }
2724
2725 if (frame) {
2726 if (mute) {
2727 if (mute > 1) {
2728 switch_generate_sln_silence(frame->data, frame->datalen / 2, read_impl.number_of_channels, mute);
2729 } else {
2730 memset(frame->data, 0, frame->datalen);
2731 }
2732 } else if (level) {
2733 switch_change_sln_volume(frame->data, frame->datalen / 2, level);
2734 }
2735
2736 if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
2737 switch_core_media_bug_set_read_replace_frame(bug, frame);
2738 } else if (type == SWITCH_ABC_TYPE_WRITE_REPLACE) {
2739 switch_core_media_bug_set_write_replace_frame(bug, frame);
2740 }
2741 }
2742
2743 return SWITCH_TRUE;
2744}
2745
2746SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_stop_session_audio(switch_core_session_t *session)
2747{
2748 switch_media_bug_t *bug;
2749 switch_channel_t *channel = switch_core_session_get_channel(session);
2750
2751 if ((bug = switch_channel_get_private(channel, "__audio"))) {
2752 switch_channel_set_private(channel, "__audio", NULL((void*)0));
2753 switch_core_media_bug_remove(session, &bug);
2754 return SWITCH_STATUS_SUCCESS;
2755 }
2756 return SWITCH_STATUS_FALSE;
2757}
2758
2759SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_session_audio(switch_core_session_t *session, const char *cmd, const char *direction, int level)
2760{
2761 switch_channel_t *channel = switch_core_session_get_channel(session);
2762 switch_media_bug_t *bug;
2763 switch_status_t status;
2764 switch_session_audio_t *pvt;
2765 switch_codec_implementation_t read_impl = { 0 };
2766 int existing = 0, c_read = 0, c_write = 0, flags = SMBF_NO_PAUSE;
2767
2768 if (switch_channel_pre_answer(channel)switch_channel_perform_pre_answer(channel, "src/switch_ivr_async.c"
, (const char *)__func__, 2768)
!= SWITCH_STATUS_SUCCESS) {
2769 return SWITCH_STATUS_FALSE;
2770 }
2771
2772 switch_core_session_get_read_impl(session, &read_impl);
2773
2774
2775 if ((bug = switch_channel_get_private(channel, "__audio"))) {
2776 pvt = switch_core_media_bug_get_user_data(bug);
2777 existing = 1;
2778 } else {
2779 if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt))switch_core_perform_session_alloc(session, sizeof(*pvt), "src/switch_ivr_async.c"
, (const char *)__func__, 2779)
)) {
2780 return SWITCH_STATUS_MEMERR;
2781 }
2782
2783 pvt->session = session;
2784 }
2785
2786
2787 if (!strcasecmp(direction, "write")) {
2788 flags = SMBF_WRITE_REPLACE;
2789 c_write = 1;
2790 } else if (!strcasecmp(direction, "read")) {
2791 flags = SMBF_READ_REPLACE;
2792 c_read = 1;
2793 } else if (!strcasecmp(direction, "both")) {
2794 flags = SMBF_READ_REPLACE | SMBF_WRITE_REPLACE;
2795 c_read = c_write = 1;
2796 }
2797
2798
2799 if (!strcasecmp(cmd, "mute")) {
2800 if (c_read) {
2801 pvt->read_mute = level;
2802 pvt->read_level = 0;
2803 }
2804 if (c_write) {
2805 pvt->write_mute = level;
2806 pvt->write_level = 0;
2807 }
2808 } else if (!strcasecmp(cmd, "level")) {
2809 if (level < 5 && level > -5) {
2810 if (c_read) {
2811 pvt->read_level = level;
2812 }
2813 if (c_write) {
2814 pvt->write_level = level;
2815 }
2816 }
2817 }
2818
2819 if (existing) {
2820 switch_core_media_bug_set_flag(bug, flags);
2821 } else {
2822 if ((status = switch_core_media_bug_add(session, "audio", cmd,
2823 session_audio_callback, pvt, 0, flags, &bug)) != SWITCH_STATUS_SUCCESS) {
2824 return status;
2825 }
2826
2827 switch_channel_set_private(channel, "__audio", bug);
2828 }
2829
2830
2831 return SWITCH_STATUS_SUCCESS;
2832}
2833
2834
2835typedef struct {
2836 switch_core_session_t *session;
2837 teletone_dtmf_detect_state_t dtmf_detect;
2838} switch_inband_dtmf_t;
2839
2840static switch_bool_t inband_dtmf_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
2841{
2842 switch_inband_dtmf_t *pvt = (switch_inband_dtmf_t *) user_data;
2843 switch_frame_t *frame = NULL((void*)0);
2844 switch_channel_t *channel = switch_core_session_get_channel(pvt->session);
2845 teletone_hit_type_t hit;
2846
2847 switch (type) {
2848 case SWITCH_ABC_TYPE_INIT:
2849 break;
2850 case SWITCH_ABC_TYPE_CLOSE:
2851 break;
2852 case SWITCH_ABC_TYPE_READ_REPLACE:
2853 if ((frame = switch_core_media_bug_get_read_replace_frame(bug))) {
2854 if ((hit = teletone_dtmf_detect(&pvt->dtmf_detect, frame->data, frame->samples)) == TT_HIT_END) {
2855 switch_dtmf_t dtmf = {0};
2856
2857 teletone_dtmf_get(&pvt->dtmf_detect, &dtmf.digit, &dtmf.duration);
2858 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug))SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 2858, (const char*)(switch_core_media_bug_get_session
(bug))
, SWITCH_LOG_DEBUG, "DTMF DETECTED: [%c][%d]\n",
2859 dtmf.digit, dtmf.duration);
2860 dtmf.source = SWITCH_DTMF_INBAND_AUDIO;
2861 switch_channel_queue_dtmf(channel, &dtmf);
2862 }
2863 switch_core_media_bug_set_read_replace_frame(bug, frame);
2864 }
2865 break;
2866 case SWITCH_ABC_TYPE_WRITE:
2867 default:
2868 break;
2869 }
2870
2871 return SWITCH_TRUE;
2872}
2873
2874SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_stop_inband_dtmf_session(switch_core_session_t *session)
2875{
2876 switch_media_bug_t *bug;
2877 switch_channel_t *channel = switch_core_session_get_channel(session);
2878
2879 if ((bug = switch_channel_get_private(channel, "dtmf"))) {
2880 switch_channel_set_private(channel, "dtmf", NULL((void*)0));
2881 switch_core_media_bug_remove(session, &bug);
2882 return SWITCH_STATUS_SUCCESS;
2883 }
2884 return SWITCH_STATUS_FALSE;
2885}
2886
2887SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_inband_dtmf_session(switch_core_session_t *session)
2888{
2889 switch_channel_t *channel = switch_core_session_get_channel(session);
2890 switch_media_bug_t *bug;
2891 switch_status_t status;
2892 switch_inband_dtmf_t *pvt;
2893 switch_codec_implementation_t read_impl = { 0 };
2894
2895 switch_core_session_get_read_impl(session, &read_impl);
2896
2897 if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt))switch_core_perform_session_alloc(session, sizeof(*pvt), "src/switch_ivr_async.c"
, (const char *)__func__, 2897)
)) {
2898 return SWITCH_STATUS_MEMERR;
2899 }
2900
2901 teletone_dtmf_detect_init(&pvt->dtmf_detect, read_impl.actual_samples_per_second);
2902
2903 pvt->session = session;
2904
2905
2906 if (switch_channel_pre_answer(channel)switch_channel_perform_pre_answer(channel, "src/switch_ivr_async.c"
, (const char *)__func__, 2906)
!= SWITCH_STATUS_SUCCESS) {
2907 return SWITCH_STATUS_FALSE;
2908 }
2909
2910 if ((status = switch_core_media_bug_add(session, "inband_dtmf", NULL((void*)0),
2911 inband_dtmf_callback, pvt, 0, SMBF_READ_REPLACE | SMBF_NO_PAUSE | SMBF_ONE_ONLY, &bug)) != SWITCH_STATUS_SUCCESS) {
2912 return status;
2913 }
2914
2915 switch_channel_set_private(channel, "dtmf", bug);
2916
2917 return SWITCH_STATUS_SUCCESS;
2918}
2919
2920typedef struct {
2921 switch_core_session_t *session;
2922 teletone_generation_session_t ts;
2923 switch_queue_t *digit_queue;
2924 switch_buffer_t *audio_buffer;
2925 switch_mutex_t *mutex;
2926 int read;
2927 int ready;
2928 int skip;
2929} switch_inband_dtmf_generate_t;
2930
2931static int teletone_dtmf_generate_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
2932{
2933 switch_buffer_t *audio_buffer = ts->user_data;
2934 int wrote;
2935
2936 if (!audio_buffer) {
2937 return -1;
2938 }
2939
2940 wrote = teletone_mux_tones(ts, map);
2941 switch_buffer_write(audio_buffer, ts->buffer, wrote * 2);
2942
2943 return 0;
2944}
2945
2946static switch_status_t generate_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction)
2947{
2948 switch_channel_t *channel = switch_core_session_get_channel(session);
2949 switch_media_bug_t *bug = switch_channel_get_private(channel, "dtmf_generate");
2950 switch_status_t status = SWITCH_STATUS_SUCCESS;
2951
2952 if (bug) {
2953 switch_inband_dtmf_generate_t *pvt = (switch_inband_dtmf_generate_t *) switch_core_media_bug_get_user_data(bug);
2954
2955 if (pvt) {
2956 switch_mutex_lock(pvt->mutex);
2957
2958 if (pvt->ready) {
2959 switch_dtmf_t *dt = NULL((void*)0);
2960 switch_zmalloc(dt, sizeof(*dt))(void)((((dt = calloc(1, (sizeof(*dt))))) ? (void) (0) : __assert_fail
("(dt = calloc(1, (sizeof(*dt))))", "src/switch_ivr_async.c"
, 2960, __PRETTY_FUNCTION__)),dt)
;
2961 *dt = *dtmf;
2962 if (!switch_buffer_inuse(pvt->audio_buffer)) {
2963 pvt->skip = 10;
2964 }
2965 if (switch_queue_trypush(pvt->digit_queue, dt) == SWITCH_STATUS_SUCCESS) {
2966 switch_event_t *event;
2967
2968 if (switch_event_create(&event, SWITCH_EVENT_DTMF)switch_event_create_subclass_detailed("src/switch_ivr_async.c"
, (const char * )(const char *)__func__, 2968, &event, SWITCH_EVENT_DTMF
, ((void*)0))
== SWITCH_STATUS_SUCCESS) {
2969 switch_channel_event_set_data(channel, event);
2970 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "DTMF-Digit", "%c", dtmf->digit);
2971 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "DTMF-Duration", "%u", dtmf->duration);
2972 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "DTMF-Conversion", "native:inband");
2973 if (switch_channel_test_flag(channel, CF_DIVERT_EVENTS)) {
2974 switch_core_session_queue_event(session, &event);
2975 } else {
2976 switch_event_fire(&event)switch_event_fire_detailed("src/switch_ivr_async.c", (const char
* )(const char *)__func__, 2976, &event, ((void*)0))
;
2977 }
2978 }
2979
2980 dt = NULL((void*)0);
2981 /*
2982 SWITCH_STATUS_FALSE indicates pretend there never was a DTMF
2983 since we will be generating it inband now.
2984 */
2985 status = SWITCH_STATUS_FALSE;
2986 } else {
2987 free(dt);
2988 }
2989 }
2990 switch_mutex_unlock(pvt->mutex);
2991 }
2992 }
2993
2994 return status;
2995}
2996
2997
2998static switch_bool_t inband_dtmf_generate_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
2999{
3000 switch_inband_dtmf_generate_t *pvt = (switch_inband_dtmf_generate_t *) user_data;
3001 switch_frame_t *frame;
3002 switch_codec_implementation_t read_impl = { 0 };
3003 switch_core_session_get_read_impl(pvt->session, &read_impl);
3004
3005 switch (type) {
3006 case SWITCH_ABC_TYPE_INIT:
3007 {
3008 switch_queue_create(&pvt->digit_queue, 100, switch_core_session_get_pool(pvt->session));
3009 switch_buffer_create_dynamic(&pvt->audio_buffer, 512, 1024, 0);
3010 teletone_init_session(&pvt->ts, 0, teletone_dtmf_generate_handler, pvt->audio_buffer);
3011 pvt->ts.rate = read_impl.actual_samples_per_second;
3012 pvt->ts.channels = 1;
3013 switch_mutex_init(&pvt->mutex, SWITCH_MUTEX_NESTED0x1, switch_core_session_get_pool(pvt->session));
3014 if (pvt->read) {
3015 switch_core_event_hook_add_recv_dtmf(pvt->session, generate_on_dtmf);
3016 } else {
3017 switch_core_event_hook_add_send_dtmf(pvt->session, generate_on_dtmf);
3018 }
3019 switch_mutex_lock(pvt->mutex);
3020 pvt->ready = 1;
3021 switch_mutex_unlock(pvt->mutex);
3022 }
3023 break;
3024 case SWITCH_ABC_TYPE_CLOSE:
3025 {
3026 switch_mutex_lock(pvt->mutex);
3027 pvt->ready = 0;
3028 switch_core_event_hook_remove_recv_dtmf(pvt->session, generate_on_dtmf);
3029 switch_buffer_destroy(&pvt->audio_buffer);
3030 teletone_destroy_session(&pvt->ts);
3031 switch_mutex_unlock(pvt->mutex);
3032 }
3033 break;
3034 case SWITCH_ABC_TYPE_READ_REPLACE:
3035 case SWITCH_ABC_TYPE_WRITE_REPLACE:
3036 {
3037 switch_size_t bytes;
3038 void *pop;
3039
3040 if (pvt->skip) {
3041 pvt->skip--;
3042 return SWITCH_TRUE;
3043 }
3044
3045
3046 switch_mutex_lock(pvt->mutex);
3047
3048 if (!pvt->ready) {
3049 switch_mutex_unlock(pvt->mutex);
3050 return SWITCH_FALSE;
3051 }
3052
3053 if (pvt->read) {
3054 frame = switch_core_media_bug_get_read_replace_frame(bug);
3055 } else {
3056 frame = switch_core_media_bug_get_write_replace_frame(bug);
3057 }
3058
3059 if (!switch_buffer_inuse(pvt->audio_buffer)) {
3060 if (switch_queue_trypop(pvt->digit_queue, &pop) == SWITCH_STATUS_SUCCESS) {
3061 switch_dtmf_t *dtmf = (switch_dtmf_t *) pop;
3062
3063
3064 if (dtmf->source != SWITCH_DTMF_INBAND_AUDIO) {
3065 char buf[2] = "";
3066 int duration = dtmf->duration;
3067
3068 buf[0] = dtmf->digit;
3069 if (duration > (int)switch_core_max_dtmf_duration(0)) {
3070 duration = switch_core_default_dtmf_duration(0);
3071 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug))SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3071, (const char*)(switch_core_media_bug_get_session
(bug))
,
3072 SWITCH_LOG_WARNING, "%s Truncating DTMF duration %d ms to %d ms\n",
3073 switch_channel_get_name(switch_core_session_get_channel(pvt->session)), dtmf->duration / 8, duration);
3074 }
3075
3076
3077 pvt->ts.duration = duration;
3078 teletone_run(&pvt->ts, buf);
3079 }
3080 free(pop);
3081 }
3082 }
3083
3084 if (switch_buffer_inuse(pvt->audio_buffer) && (bytes = switch_buffer_read(pvt->audio_buffer, frame->data, frame->datalen))) {
3085 if (bytes < frame->datalen) {
3086 switch_byte_t *dp = frame->data;
3087 memset(dp + bytes, 0, frame->datalen - bytes);
3088 }
3089 }
3090
3091 if (pvt->read) {
3092 switch_core_media_bug_set_read_replace_frame(bug, frame);
3093 } else {
3094 switch_core_media_bug_set_write_replace_frame(bug, frame);
3095 }
3096
3097 switch_mutex_unlock(pvt->mutex);
3098 }
3099 break;
3100 default:
3101 break;
3102 }
3103
3104 return SWITCH_TRUE;
3105}
3106
3107SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_stop_inband_dtmf_generate_session(switch_core_session_t *session)
3108{
3109 switch_channel_t *channel = switch_core_session_get_channel(session);
3110 switch_media_bug_t *bug = switch_channel_get_private(channel, "dtmf_generate");
3111
3112 if (bug) {
3113 switch_channel_set_private(channel, "dtmf_generate", NULL((void*)0));
3114 switch_core_media_bug_remove(session, &bug);
3115 return SWITCH_STATUS_SUCCESS;
3116 }
3117
3118 return SWITCH_STATUS_FALSE;
3119
3120}
3121
3122SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_inband_dtmf_generate_session(switch_core_session_t *session, switch_bool_t read_stream)
3123{
3124 switch_channel_t *channel = switch_core_session_get_channel(session);
3125 switch_media_bug_t *bug;
3126 switch_status_t status;
3127 switch_inband_dtmf_generate_t *pvt;
3128
3129 if ((status = switch_channel_pre_answer(channel)switch_channel_perform_pre_answer(channel, "src/switch_ivr_async.c"
, (const char *)__func__, 3129)
) != SWITCH_STATUS_SUCCESS) {
3130 return SWITCH_STATUS_FALSE;
3131 }
3132
3133 if (!switch_channel_media_up(channel)(switch_channel_test_flag(channel, CF_ANSWERED) || switch_channel_test_flag
(channel, CF_EARLY_MEDIA))
|| !switch_core_session_get_read_codec(session)) {
3134 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3134, (const char*)(session)
, SWITCH_LOG_ERROR, "Can not install inband dtmf generate. Media not enabled on channel\n");
3135 return status;
3136 }
3137
3138 if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt))switch_core_perform_session_alloc(session, sizeof(*pvt), "src/switch_ivr_async.c"
, (const char *)__func__, 3138)
)) {
3139 return SWITCH_STATUS_MEMERR;
3140 }
3141
3142 pvt->session = session;
3143 pvt->read = !!read_stream;
3144
3145 if ((status = switch_core_media_bug_add(session, "inband_dtmf_generate", NULL((void*)0),
3146 inband_dtmf_generate_callback, pvt, 0,
3147 SMBF_NO_PAUSE | (pvt->read ? SMBF_READ_REPLACE : SMBF_WRITE_REPLACE) , &bug)) != SWITCH_STATUS_SUCCESS) {
3148 return status;
3149 }
3150
3151 switch_channel_set_private(channel, "dtmf_generate", bug);
3152
3153 return SWITCH_STATUS_SUCCESS;
3154}
3155
3156#define MAX_TONES16 16
3157typedef struct {
3158 teletone_multi_tone_t mt;
3159 char *app;
3160 char *data;
3161 char *key;
3162 teletone_tone_map_t map;
3163 int up;
3164 int total_hits;
3165 int hits;
3166 int sleep;
3167 int expires;
3168 int default_sleep;
3169 int default_expires;
3170 int once;
3171 switch_time_t start_time;
3172 switch_tone_detect_callback_t callback;
3173} switch_tone_detect_t;
3174
3175typedef struct {
3176 switch_tone_detect_t list[MAX_TONES16 + 1];
3177 int index;
3178 switch_media_bug_t *bug;
3179 switch_core_session_t *session;
3180 int bug_running;
3181 int detect_fax;
3182} switch_tone_container_t;
3183
3184
3185static void tone_detect_set_total_time(switch_tone_container_t *cont, int index)
3186{
3187 char *total_time = switch_mprintf("%d", (int)(switch_micro_time_now() - cont->list[index].start_time) / 1000);
3188
3189 switch_channel_set_variable_name_printf(switch_core_session_get_channel(cont->session), total_time, "tone_detect_%s_total_time",
3190 cont->list[index].key);
3191 switch_safe_free(total_time)if (total_time) {free(total_time);total_time=((void*)0);};
3192}
3193
3194static switch_status_t tone_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction)
3195{
3196 switch_channel_t *channel = switch_core_session_get_channel(session);
3197 switch_tone_container_t *cont = switch_channel_get_private(channel, "_tone_detect_");
3198 int i;
3199
3200 if (!cont || !cont->detect_fax || dtmf->digit != 'f') {
3201 return SWITCH_STATUS_SUCCESS;
3202 }
3203
3204 i = cont->detect_fax;
3205
3206 tone_detect_set_total_time(cont, i);
3207 if (cont->list[i].callback) {
3208 cont->list[i].callback(cont->session, cont->list[i].app, cont->list[i].data);
3209 } else {
3210 switch_channel_execute_on(switch_core_session_get_channel(cont->session), SWITCH_CHANNEL_EXECUTE_ON_TONE_DETECT_VARIABLE"execute_on_tone_detect");
3211 switch_channel_api_on(switch_core_session_get_channel(cont->session), SWITCH_CHANNEL_API_ON_TONE_DETECT_VARIABLE"api_on_tone_detect");
3212
3213 if (cont->list[i].app) {
3214 switch_core_session_execute_application_async(cont->session, cont->list[i].app, cont->list[i].data);
3215 }
3216 }
3217
3218 return SWITCH_STATUS_SUCCESS;
3219
3220}
3221
3222static switch_bool_t tone_detect_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
3223{
3224 switch_tone_container_t *cont = (switch_tone_container_t *) user_data;
3225 switch_frame_t *frame = NULL((void*)0);
3226 int i = 0;
3227 switch_bool_t rval = SWITCH_TRUE;
3228
3229 switch (type) {
3230 case SWITCH_ABC_TYPE_INIT:
3231 if (cont) {
3232 cont->bug_running = 1;
3233 }
3234 break;
3235 case SWITCH_ABC_TYPE_CLOSE:
3236 break;
3237 case SWITCH_ABC_TYPE_READ_REPLACE:
3238 case SWITCH_ABC_TYPE_WRITE_REPLACE:
3239 {
3240
3241 if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
3242 frame = switch_core_media_bug_get_read_replace_frame(bug);
3243 } else {
3244 frame = switch_core_media_bug_get_write_replace_frame(bug);
3245 }
3246
3247 for (i = 0; i < cont->index; i++) {
3248 int skip = 0;
3249
3250 if (cont->list[i].sleep) {
3251 cont->list[i].sleep--;
3252 if (cont->list[i].sleep) {
3253 skip = 1;
3254 }
3255 }
3256
3257 if (cont->list[i].expires) {
3258 cont->list[i].expires--;
3259 if (!cont->list[i].expires) {
3260 cont->list[i].hits = 0;
3261 cont->list[i].sleep = 0;
3262 cont->list[i].expires = 0;
3263 }
3264 }
3265
3266 if (!cont->list[i].up)
3267 skip = 1;
3268
3269 if (skip)
3270 continue;
3271
3272 if (teletone_multi_tone_detect(&cont->list[i].mt, frame->data, frame->samples)) {
3273 switch_event_t *event;
3274 cont->list[i].hits++;
3275
3276 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug))SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3276, (const char*)(switch_core_media_bug_get_session
(bug))
, SWITCH_LOG_DEBUG, "TONE %s HIT %d/%d\n",
3277 cont->list[i].key, cont->list[i].hits, cont->list[i].total_hits);
3278 cont->list[i].sleep = cont->list[i].default_sleep;
3279 cont->list[i].expires = cont->list[i].default_expires;
3280
3281 if (cont->list[i].hits >= cont->list[i].total_hits) {
3282 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug))SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3282, (const char*)(switch_core_media_bug_get_session
(bug))
, SWITCH_LOG_DEBUG, "TONE %s DETECTED\n",
3283 cont->list[i].key);
3284 tone_detect_set_total_time(cont, i);
3285 cont->list[i].up = 0;
3286
3287 if (cont->list[i].callback) {
3288 if ((rval = cont->list[i].callback(cont->session, cont->list[i].app, cont->list[i].data)) == SWITCH_TRUE) {
3289 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug))SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3289, (const char*)(switch_core_media_bug_get_session
(bug))
, SWITCH_LOG_DEBUG, "Re-enabling %s\n",
3290 cont->list[i].key);
3291 cont->list[i].up = 1;
3292 cont->list[i].hits = 0;
3293 cont->list[i].sleep = 0;
3294 cont->list[i].expires = 0;
3295 }
3296 } else {
3297 switch_channel_execute_on(switch_core_session_get_channel(cont->session), SWITCH_CHANNEL_EXECUTE_ON_TONE_DETECT_VARIABLE"execute_on_tone_detect");
3298 if (cont->list[i].app) {
3299 switch_core_session_execute_application_async(cont->session, cont->list[i].app, cont->list[i].data);
3300 }
3301 }
3302
3303 if (cont->list[i].once) {
3304 rval = SWITCH_FALSE;
3305 }
3306
3307 if (switch_event_create(&event, SWITCH_EVENT_DETECTED_TONE)switch_event_create_subclass_detailed("src/switch_ivr_async.c"
, (const char * )(const char *)__func__, 3307, &event, SWITCH_EVENT_DETECTED_TONE
, ((void*)0))
== SWITCH_STATUS_SUCCESS) {
3308 switch_event_t *dup;
3309 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Detected-Tone", cont->list[i].key);
3310
3311 if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {
3312 switch_event_fire(&dup)switch_event_fire_detailed("src/switch_ivr_async.c", (const char
* )(const char *)__func__, 3312, &dup, ((void*)0))
;
3313 }
3314
3315 if (switch_core_session_queue_event(cont->session, &event) != SWITCH_STATUS_SUCCESS) {
3316 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug))SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3316, (const char*)(switch_core_media_bug_get_session
(bug))
, SWITCH_LOG_ERROR,
3317 "Event queue failed!\n");
3318 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
3319 switch_event_fire(&event)switch_event_fire_detailed("src/switch_ivr_async.c", (const char
* )(const char *)__func__, 3319, &event, ((void*)0))
;
3320 }
3321 }
3322 }
3323 }
3324 }
3325 }
3326 break;
3327 case SWITCH_ABC_TYPE_WRITE:
3328 default:
3329 break;
3330 }
3331
3332 if (rval == SWITCH_FALSE) {
3333 cont->bug_running = 0;
3334 }
3335
3336 return rval;
3337}
3338
3339SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_stop_tone_detect_session(switch_core_session_t *session)
3340{
3341 switch_channel_t *channel = switch_core_session_get_channel(session);
3342 switch_tone_container_t *cont = switch_channel_get_private(channel, "_tone_detect_");
3343 int i = 0;
3344
3345 if (cont) {
3346 switch_channel_set_private(channel, "_tone_detect_", NULL((void*)0));
3347 for (i = 0; i < cont->index; i++) {
3348 cont->list[i].up = 0;
3349 }
3350 switch_core_media_bug_remove(session, &cont->bug);
3351 if (cont->detect_fax) {
3352 cont->detect_fax = 0;
3353 }
3354 return SWITCH_STATUS_SUCCESS;
3355 }
3356 return SWITCH_STATUS_FALSE;
3357}
3358
3359SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_tone_detect_session(switch_core_session_t *session,
3360 const char *key, const char *tone_spec,
3361 const char *flags, time_t timeout,
3362 int hits, const char *app, const char *data, switch_tone_detect_callback_t callback)
3363{
3364 switch_channel_t *channel = switch_core_session_get_channel(session);
3365 switch_status_t status;
3366 switch_tone_container_t *cont = switch_channel_get_private(channel, "_tone_detect_");
3367 char *p, *next;
3368 int i = 0, ok = 0, detect_fax = 0;
3369 switch_media_bug_flag_t bflags = 0;
3370 const char *var;
3371 switch_codec_implementation_t read_impl = { 0 };
3372 switch_core_session_get_read_impl(session, &read_impl);
3373
3374
3375 if (zstr(key)_zstr(key)) {
3376 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3376, (const char*)(session)
, SWITCH_LOG_ERROR, "No Key Specified!\n");
3377 return SWITCH_STATUS_FALSE;
3378 }
3379
3380 if (cont) {
3381 if (cont->index >= MAX_TONES16) {
3382 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3382, (const char*)(session)
, SWITCH_LOG_ERROR, "Max Tones Reached!\n");
3383 return SWITCH_STATUS_FALSE;
3384 }
3385
3386 for (i = 0; i < cont->index; i++) {
3387 if (!zstr(cont->list[i].key)_zstr(cont->list[i].key) && !strcasecmp(key, cont->list[i].key)) {
3388 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3388, (const char*)(session)
, SWITCH_LOG_DEBUG, "Re-enabling %s\n", key);
3389 cont->list[i].up = 1;
3390 cont->list[i].hits = 0;
3391 cont->list[i].sleep = 0;
3392 cont->list[i].expires = 0;
3393 return SWITCH_STATUS_SUCCESS;
3394 }
3395 }
3396 }
3397
3398 if (zstr(tone_spec)_zstr(tone_spec)) {
3399 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3399, (const char*)(session)
, SWITCH_LOG_ERROR, "No Spec Specified!\n");
3400 return SWITCH_STATUS_FALSE;
3401 }
3402
3403 if (!cont && !(cont = switch_core_session_alloc(session, sizeof(*cont))switch_core_perform_session_alloc(session, sizeof(*cont), "src/switch_ivr_async.c"
, (const char *)__func__, 3403)
)) {
3404 return SWITCH_STATUS_MEMERR;
3405 }
3406
3407 if ((var = switch_channel_get_variable(channel, "tone_detect_hits")switch_channel_get_variable_dup(channel, "tone_detect_hits", SWITCH_TRUE
, -1)
)) {
3408 int tmp = atoi(var);
3409 if (tmp > 0) {
3410 hits = tmp;
3411 }
3412 }
3413
3414 if (!hits) hits = 1;
3415
3416 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3416, (const char*)(session)
, SWITCH_LOG_DEBUG, "Adding tone spec %s index %d hits %d\n", tone_spec, cont->index, hits);
3417
3418 i = 0;
3419 p = (char *) tone_spec;
3420
3421 do {
3422 teletone_process_t this;
3423 next = strchr(p, ',')(__extension__ (__builtin_constant_p (',') && !__builtin_constant_p
(p) && (',') == '\0' ? (char *) __rawmemchr (p, ',')
: __builtin_strchr (p, ',')))
;
3424 while (*p == ' ')
3425 p++;
3426 if ((this = (teletone_process_t) atof(p))) {
3427 ok++;
3428 cont->list[cont->index].map.freqs[i++] = this;
3429 }
3430 if (!strncasecmp(p, "1100", 4)) {
3431 detect_fax = cont->index;
3432 }
3433
3434 if (next) {
3435 p = next + 1;
3436 }
3437 } while (next);
3438 cont->list[cont->index].map.freqs[i++] = 0;
3439
3440 if (!ok) {
3441 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3441, (const char*)(session)
, SWITCH_LOG_ERROR, "Invalid tone spec!\n");
3442 return SWITCH_STATUS_FALSE;
3443 }
3444
3445 cont->detect_fax = detect_fax;
3446
3447 cont->list[cont->index].key = switch_core_session_strdup(session, key)switch_core_perform_session_strdup(session, key, "src/switch_ivr_async.c"
, (const char *)__func__, 3447)
;
3448
3449 if (app) {
3450 cont->list[cont->index].app = switch_core_session_strdup(session, app)switch_core_perform_session_strdup(session, app, "src/switch_ivr_async.c"
, (const char *)__func__, 3450)
;
3451 }
3452
3453 if (data) {
3454 cont->list[cont->index].data = switch_core_session_strdup(session, data)switch_core_perform_session_strdup(session, data, "src/switch_ivr_async.c"
, (const char *)__func__, 3454)
;
3455 }
3456
3457 cont->list[cont->index].callback = callback;
3458
3459 if (!hits)
3460 hits = 1;
3461
3462 cont->list[cont->index].hits = 0;
3463 cont->list[cont->index].total_hits = hits;
3464 cont->list[cont->index].start_time = switch_micro_time_now();
3465
3466 cont->list[cont->index].up = 1;
3467 memset(&cont->list[cont->index].mt, 0, sizeof(cont->list[cont->index].mt));
3468 cont->list[cont->index].mt.sample_rate = read_impl.actual_samples_per_second;
3469 teletone_multi_tone_init(&cont->list[cont->index].mt, &cont->list[cont->index].map);
3470 cont->session = session;
3471
3472 if (switch_channel_pre_answer(channel)switch_channel_perform_pre_answer(channel, "src/switch_ivr_async.c"
, (const char *)__func__, 3472)
!= SWITCH_STATUS_SUCCESS) {
3473 return SWITCH_STATUS_FALSE;
3474 }
3475
3476 cont->list[cont->index].default_sleep = 25;
3477 cont->list[cont->index].default_expires = 250;
3478
3479 if ((var = switch_channel_get_variable(channel, "tone_detect_sleep")switch_channel_get_variable_dup(channel, "tone_detect_sleep",
SWITCH_TRUE, -1)
)) {
3480 int tmp = atoi(var);
3481 if (tmp > 0) {
3482 cont->list[cont->index].default_sleep = tmp;
3483 }
3484 }
3485
3486 if ((var = switch_channel_get_variable(channel, "tone_detect_expires")switch_channel_get_variable_dup(channel, "tone_detect_expires"
, SWITCH_TRUE, -1)
)) {
3487 int tmp = atoi(var);
3488 if (tmp > 0) {
3489 cont->list[cont->index].default_expires = tmp;
3490 }
3491 }
3492
3493
3494 if (zstr(flags)_zstr(flags)) {
3495 bflags = SMBF_READ_REPLACE;
3496 } else {
3497 if (strchr(flags, 'o')(__extension__ (__builtin_constant_p ('o') && !__builtin_constant_p
(flags) && ('o') == '\0' ? (char *) __rawmemchr (flags
, 'o') : __builtin_strchr (flags, 'o')))
) {
3498 cont->list[cont->index].once = 1;
3499 }
3500
3501 if (strchr(flags, 'r')(__extension__ (__builtin_constant_p ('r') && !__builtin_constant_p
(flags) && ('r') == '\0' ? (char *) __rawmemchr (flags
, 'r') : __builtin_strchr (flags, 'r')))
) {
3502 bflags |= SMBF_READ_REPLACE;
3503 } else if (strchr(flags, 'w')(__extension__ (__builtin_constant_p ('w') && !__builtin_constant_p
(flags) && ('w') == '\0' ? (char *) __rawmemchr (flags
, 'w') : __builtin_strchr (flags, 'w')))
) {
3504 bflags |= SMBF_WRITE_REPLACE;
3505 }
3506 }
3507
3508 bflags |= SMBF_NO_PAUSE;
3509
3510 if (cont->bug_running) {
3511 status = SWITCH_STATUS_SUCCESS;
Value stored to 'status' is never read
3512 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3512, (const char*)(session)
, SWITCH_LOG_DEBUG, "%s bug already running\n", switch_channel_get_name(channel));
3513 } else {
3514 cont->bug_running = 1;
3515 if (cont->detect_fax) {
3516 switch_core_event_hook_add_send_dtmf(session, tone_on_dtmf);
3517 switch_core_event_hook_add_recv_dtmf(session, tone_on_dtmf);
3518 }
3519
3520 if ((status = switch_core_media_bug_add(session, "tone_detect", key,
3521 tone_detect_callback, cont, timeout, bflags, &cont->bug)) != SWITCH_STATUS_SUCCESS) {
3522 cont->bug_running = 0;
3523 return status;
3524 }
3525 switch_channel_set_private(channel, "_tone_detect_", cont);
3526 }
3527
3528 cont->index++;
3529
3530 return SWITCH_STATUS_SUCCESS;
3531}
3532
3533typedef struct {
3534 const char *app;
3535 uint32_t flags;
3536 switch_bind_flag_t bind_flags;
3537} dtmf_meta_app_t;
3538
3539typedef struct {
3540 dtmf_meta_app_t map[14];
3541 time_t last_digit;
3542 switch_bool_t meta_on;
3543 char meta;
3544 int up;
3545} dtmf_meta_settings_t;
3546
3547typedef struct {
3548 dtmf_meta_settings_t sr[3];
3549} dtmf_meta_data_t;
3550
3551#define SWITCH_META_VAR_KEY"__dtmf_meta" "__dtmf_meta"
3552#define SWITCH_BLOCK_DTMF_KEY"__dtmf_block" "__dtmf_block"
3553
3554typedef struct {
3555 switch_core_session_t *session;
3556 const char *app;
3557 int flags;
3558} bch_t;
3559
3560static void *SWITCH_THREAD_FUNC bcast_thread(switch_thread_t *thread, void *obj)
3561{
3562 bch_t *bch = (bch_t *) obj;
3563
3564 if (!bch->session) {
3565 return NULL((void*)0);
3566 }
3567
3568 switch_core_session_read_lock(bch->session);
3569 switch_ivr_broadcast(switch_core_session_get_uuid(bch->session), bch->app, bch->flags);
3570 switch_core_session_rwunlock(bch->session);
3571
3572 return NULL((void*)0);
3573
3574}
3575SWITCH_DECLARE(void)__attribute__((visibility("default"))) void switch_ivr_broadcast_in_thread(switch_core_session_t *session, const char *app, int flags)
3576{
3577 switch_thread_t *thread;
3578 switch_threadattr_t *thd_attr = NULL((void*)0);
3579 switch_memory_pool_t *pool;
3580 bch_t *bch;
3581
3582 switch_assert(session)((session) ? (void) (0) : __assert_fail ("session", "src/switch_ivr_async.c"
, 3582, __PRETTY_FUNCTION__))
;
3583
3584 pool = switch_core_session_get_pool(session);
3585
3586 bch = switch_core_session_alloc(session, sizeof(*bch))switch_core_perform_session_alloc(session, sizeof(*bch), "src/switch_ivr_async.c"
, (const char *)__func__, 3586)
;
3587 bch->session = session;
3588 bch->app = app;
3589 bch->flags = flags;
3590
3591
3592 switch_threadattr_create(&thd_attr, pool);
3593 switch_threadattr_detach_set(thd_attr, 1);
3594 switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE240 * 1024);
3595 switch_thread_create(&thread, thd_attr, bcast_thread, bch, pool);
3596}
3597
3598static switch_status_t meta_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction)
3599{
3600 switch_channel_t *channel = switch_core_session_get_channel(session);
3601 dtmf_meta_data_t *md = switch_channel_get_private(channel, SWITCH_META_VAR_KEY"__dtmf_meta");
3602 time_t now = switch_epoch_time_now(NULL((void*)0));
3603 char digit[2] = "";
3604 int dval;
3605
3606 if (!md || switch_channel_test_flag(channel, CF_INNER_BRIDGE)) {
3607 return SWITCH_STATUS_SUCCESS;
3608 }
3609
3610 if (direction == SWITCH_DTMF_RECV && !md->sr[SWITCH_DTMF_RECV].up) {
3611 return SWITCH_STATUS_SUCCESS;
3612 }
3613
3614 if (direction == SWITCH_DTMF_SEND && !md->sr[SWITCH_DTMF_SEND].up) {
3615 return SWITCH_STATUS_SUCCESS;
3616 }
3617
3618 if (md->sr[direction].meta_on && now - md->sr[direction].last_digit > 5) {
3619 md->sr[direction].meta_on = SWITCH_FALSE;
3620 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3620, (const char*)(session)
, SWITCH_LOG_ERROR, "%s Meta digit timeout parsing %c\n", switch_channel_get_name(channel),
3621 dtmf->digit);
3622 return SWITCH_STATUS_SUCCESS;
3623 }
3624
3625 md->sr[direction].last_digit = now;
3626
3627 if (dtmf->digit == md->sr[direction].meta) {
3628 if (md->sr[direction].meta_on) {
3629 md->sr[direction].meta_on = SWITCH_FALSE;
3630 return SWITCH_STATUS_SUCCESS;
3631 } else {
3632 md->sr[direction].meta_on = SWITCH_TRUE;
3633 return SWITCH_STATUS_FALSE;
3634 }
3635 }
3636
3637 if (md->sr[direction].meta_on) {
3638 if (is_dtmf(dtmf->digit)((dtmf->digit > 47 && dtmf->digit < 58) ||
(dtmf->digit > 64 && dtmf->digit < 69) ||
(dtmf->digit > 96 && dtmf->digit < 101) ||
dtmf->digit == 35 || dtmf->digit == 42 || dtmf->digit
== 87 || dtmf->digit == 119 || dtmf->digit == 70 || dtmf
->digit == 102)
) {
3639 int ok = 0;
3640 *digit = dtmf->digit;
3641 dval = switch_dtmftoi(digit);
3642
3643 if (direction == SWITCH_DTMF_RECV && (md->sr[direction].map[dval].bind_flags & SBF_DIAL_ALEG)) {
3644 ok = 1;
3645 } else if (direction == SWITCH_DTMF_SEND && (md->sr[direction].map[dval].bind_flags & SBF_DIAL_BLEG)) {
3646 ok = 1;
3647 }
3648
3649 if (ok && md->sr[direction].map[dval].app) {
3650 uint32_t flags = md->sr[direction].map[dval].flags;
3651
3652 if ((md->sr[direction].map[dval].bind_flags & SBF_EXEC_OPPOSITE)) {
3653 if (direction == SWITCH_DTMF_SEND) {
3654 flags |= SMF_ECHO_ALEG;
3655 } else {
3656 flags |= SMF_ECHO_BLEG;
3657 }
3658 } else if ((md->sr[direction].map[dval].bind_flags & SBF_EXEC_SAME)) {
3659 if (direction == SWITCH_DTMF_SEND) {
3660 flags |= SMF_ECHO_BLEG;
3661 } else {
3662 flags |= SMF_ECHO_ALEG;
3663 }
3664 } else if ((md->sr[direction].map[dval].bind_flags & SBF_EXEC_ALEG)) {
3665 flags |= SMF_ECHO_ALEG;
3666 } else if ((md->sr[direction].map[dval].bind_flags & SBF_EXEC_BLEG)) {
3667 flags |= SMF_ECHO_BLEG;
3668 } else {
3669 flags |= SMF_ECHO_ALEG;
3670 }
3671
3672 if ((md->sr[direction].map[dval].bind_flags & SBF_EXEC_INLINE)) {
3673 flags |= SMF_EXEC_INLINE;
3674 }
3675
3676 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3676, (const char*)(session)
, SWITCH_LOG_DEBUG, "%s Processing meta digit '%c' [%s]\n",
3677 switch_channel_get_name(channel), dtmf->digit, md->sr[direction].map[dval].app);
3678
3679 if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
3680 switch_ivr_broadcast_in_thread(session, md->sr[direction].map[dval].app, flags | SMF_REBRIDGE);
3681 } else {
3682 switch_ivr_broadcast(switch_core_session_get_uuid(session), md->sr[direction].map[dval].app, flags);
3683 }
3684
3685 if ((md->sr[direction].map[dval].bind_flags & SBF_ONCE)) {
3686 memset(&md->sr[direction].map[dval], 0, sizeof(md->sr[direction].map[dval]));
3687 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3687, (const char*)(session)
, SWITCH_LOG_DEBUG, "%s Unbinding meta digit '%c'\n",
3688 switch_channel_get_name(channel), dtmf->digit);
3689 }
3690
3691 } else {
3692 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3692, (const char*)(session)
, SWITCH_LOG_WARNING, "%s Ignoring meta digit '%c' not mapped\n",
3693 switch_channel_get_name(channel), dtmf->digit);
3694
3695 }
3696 }
3697 md->sr[direction].meta_on = SWITCH_FALSE;
3698 return SWITCH_STATUS_FALSE;
3699 }
3700
3701 return SWITCH_STATUS_SUCCESS;
3702}
3703
3704SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_unbind_dtmf_meta_session(switch_core_session_t *session, uint32_t key)
3705{
3706 switch_channel_t *channel = switch_core_session_get_channel(session);
3707
3708 if (key) {
3709 dtmf_meta_data_t *md = switch_channel_get_private(channel, SWITCH_META_VAR_KEY"__dtmf_meta");
3710
3711 if (!md || key > 9) {
3712 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3712, (const char*)(session)
, SWITCH_LOG_ERROR, "Invalid key %u\n", key);
3713 return SWITCH_STATUS_FALSE;
3714 }
3715
3716 memset(&md->sr[SWITCH_DTMF_RECV].map[key], 0, sizeof(md->sr[SWITCH_DTMF_RECV].map[key]));
3717 memset(&md->sr[SWITCH_DTMF_SEND].map[key], 0, sizeof(md->sr[SWITCH_DTMF_SEND].map[key]));
3718 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3718, (const char*)(session)
, SWITCH_LOG_INFO, "UnBound A-Leg: %d\n", key);
3719
3720 } else {
3721 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3721, (const char*)(session)
, SWITCH_LOG_INFO, "UnBound A-Leg: ALL\n");
3722 switch_channel_set_private(channel, SWITCH_META_VAR_KEY"__dtmf_meta", NULL((void*)0));
3723 }
3724
3725 return SWITCH_STATUS_SUCCESS;
3726}
3727
3728static switch_status_t block_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction)
3729{
3730 switch_channel_t *channel = switch_core_session_get_channel(session);
3731 uint8_t enabled = (uint8_t)(intptr_t)switch_channel_get_private(channel, SWITCH_BLOCK_DTMF_KEY"__dtmf_block");
3732
3733 if (!enabled || switch_channel_test_flag(channel, CF_INNER_BRIDGE)) {
3734 return SWITCH_STATUS_SUCCESS;
3735 }
3736
3737 return SWITCH_STATUS_FALSE;
3738}
3739
3740SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_unblock_dtmf_session(switch_core_session_t *session)
3741{
3742 switch_channel_t *channel = switch_core_session_get_channel(session);
3743 uint8_t enabled = (uint8_t)(intptr_t)switch_channel_get_private(channel, SWITCH_BLOCK_DTMF_KEY"__dtmf_block");
3744
3745 if (enabled) {
3746 switch_channel_set_private(channel, SWITCH_BLOCK_DTMF_KEY"__dtmf_block", NULL((void*)0));
3747 }
3748
3749 return SWITCH_STATUS_SUCCESS;
3750}
3751
3752SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_block_dtmf_session(switch_core_session_t *session)
3753{
3754 switch_channel_t *channel = switch_core_session_get_channel(session);
3755 uint8_t enabled = (uint8_t)(intptr_t)switch_channel_get_private(channel, SWITCH_BLOCK_DTMF_KEY"__dtmf_block");
3756
3757 if (!enabled) {
3758 switch_channel_set_private(channel, SWITCH_BLOCK_DTMF_KEY"__dtmf_block", (void *)(intptr_t)1);
3759 switch_core_event_hook_add_send_dtmf(session, block_on_dtmf);
3760 switch_core_event_hook_add_recv_dtmf(session, block_on_dtmf);
3761 }
3762
3763 return SWITCH_STATUS_SUCCESS;
3764}
3765
3766SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_bind_dtmf_meta_session(switch_core_session_t *session, uint32_t key,
3767 switch_bind_flag_t bind_flags, const char *app)
3768{
3769 switch_channel_t *channel = switch_core_session_get_channel(session);
3770 dtmf_meta_data_t *md = switch_channel_get_private(channel, SWITCH_META_VAR_KEY"__dtmf_meta");
3771 const char *meta_var = switch_channel_get_variable(channel, "bind_meta_key")switch_channel_get_variable_dup(channel, "bind_meta_key", SWITCH_TRUE
, -1)
;
3772 char meta = '*';
3773 char str[2] = "";
3774
3775 if (meta_var) {
3776 char t_meta = *meta_var;
3777 if (is_dtmf(t_meta)((t_meta > 47 && t_meta < 58) || (t_meta > 64
&& t_meta < 69) || (t_meta > 96 && t_meta
< 101) || t_meta == 35 || t_meta == 42 || t_meta == 87 ||
t_meta == 119 || t_meta == 70 || t_meta == 102)
) {
3778 meta = t_meta;
3779 } else {
3780 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3780, (const char*)(session)
, SWITCH_LOG_WARNING, "Invalid META KEY %c\n", t_meta);
3781 }
3782 }
3783
3784 if (meta != '*' && meta != '#') {
3785 str[0] = meta;
3786
3787 if (switch_dtmftoi(str) == (char)key) {
3788 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3788, (const char*)(session)
, SWITCH_LOG_ERROR, "Invalid key %u, same as META CHAR\n", key);
3789 return SWITCH_STATUS_FALSE;
3790 }
3791 }
3792
3793
3794 if (key > 13) {
3795 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3795, (const char*)(session)
, SWITCH_LOG_ERROR, "Invalid key %u\n", key);
3796 return SWITCH_STATUS_FALSE;
3797 }
3798
3799 if (!md) {
3800 md = switch_core_session_alloc(session, sizeof(*md))switch_core_perform_session_alloc(session, sizeof(*md), "src/switch_ivr_async.c"
, (const char *)__func__, 3800)
;
3801 switch_channel_set_private(channel, SWITCH_META_VAR_KEY"__dtmf_meta", md);
3802 switch_core_event_hook_add_send_dtmf(session, meta_on_dtmf);
3803 switch_core_event_hook_add_recv_dtmf(session, meta_on_dtmf);
3804 }
3805
3806 if (!zstr(app)_zstr(app)) {
3807 if ((bind_flags & SBF_DIAL_ALEG)) {
3808 md->sr[SWITCH_DTMF_RECV].meta = meta;
3809 md->sr[SWITCH_DTMF_RECV].up = 1;
3810 md->sr[SWITCH_DTMF_RECV].map[key].app = switch_core_session_strdup(session, app)switch_core_perform_session_strdup(session, app, "src/switch_ivr_async.c"
, (const char *)__func__, 3810)
;
3811 md->sr[SWITCH_DTMF_RECV].map[key].flags |= SMF_HOLD_BLEG;
3812 md->sr[SWITCH_DTMF_RECV].map[key].bind_flags = bind_flags;
3813
3814 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3814, (const char*)(session)
, SWITCH_LOG_INFO, "Bound A-Leg: %c%c %s\n", meta, switch_itodtmf((char)key), app);
3815 }
3816 if ((bind_flags & SBF_DIAL_BLEG)) {
3817 md->sr[SWITCH_DTMF_SEND].meta = meta;
3818 md->sr[SWITCH_DTMF_SEND].up = 1;
3819 md->sr[SWITCH_DTMF_SEND].map[key].app = switch_core_session_strdup(session, app)switch_core_perform_session_strdup(session, app, "src/switch_ivr_async.c"
, (const char *)__func__, 3819)
;
3820 md->sr[SWITCH_DTMF_SEND].map[key].flags |= SMF_HOLD_BLEG;
3821 md->sr[SWITCH_DTMF_SEND].map[key].bind_flags = bind_flags;
3822 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3822, (const char*)(session)
, SWITCH_LOG_INFO, "Bound B-Leg: %c%c %s\n", meta, switch_itodtmf((char)key), app);
3823 }
3824
3825 } else {
3826 if ((bind_flags & SBF_DIAL_ALEG)) {
3827 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3827, (const char*)(session)
, SWITCH_LOG_INFO, "UnBound A-Leg: %c%c\n", meta, switch_itodtmf((char)key));
3828 md->sr[SWITCH_DTMF_SEND].map[key].app = NULL((void*)0);
3829 } else {
3830 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3830, (const char*)(session)
, SWITCH_LOG_INFO, "UnBound: B-Leg %c%d\n", meta, key);
3831 md->sr[SWITCH_DTMF_SEND].map[key].app = NULL((void*)0);
3832 }
3833 }
3834
3835 return SWITCH_STATUS_SUCCESS;
3836}
3837
3838typedef struct {
3839 int done;
3840 char *result;
3841} play_and_detect_speech_state_t;
3842
3843static 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)
3844{
3845 play_and_detect_speech_state_t *state = (play_and_detect_speech_state_t *)data;
3846 switch_event_t *event;
3847 switch_channel_t *channel = switch_core_session_get_channel(session);
3848 if (input_type == SWITCH_INPUT_TYPE_EVENT) {
3849 event = (switch_event_t *)input;
3850 if (event->event_id == SWITCH_EVENT_DETECTED_SPEECH && !state->done) {
3851 const char *speech_type = switch_event_get_header(event, "Speech-Type")switch_event_get_header_idx(event, "Speech-Type", -1);
3852 if (!zstr(speech_type)_zstr(speech_type)) {
3853 if (!strcasecmp(speech_type, "detected-speech")) {
3854 const char *result;
3855 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3855, (const char*)(session)
, SWITCH_LOG_INFO, "(%s) DETECTED SPEECH\n", switch_channel_get_name(channel));
3856 result = switch_event_get_body(event);
3857 if (!zstr(result)_zstr(result)) {
3858 state->result = switch_core_session_strdup(session, result)switch_core_perform_session_strdup(session, result, "src/switch_ivr_async.c"
, (const char *)__func__, 3858)
;
3859 } else {
3860 state->result = "";
3861 }
3862 state->done = 1;
3863 return SWITCH_STATUS_BREAK;
3864 } else if (!strcasecmp(speech_type, "begin-speaking")) {
3865 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3865, (const char*)(session)
, SWITCH_LOG_INFO, "(%s) START OF SPEECH\n", switch_channel_get_name(channel));
3866 return SWITCH_STATUS_BREAK;
3867 }
3868 }
3869 }
3870 }
3871 return SWITCH_STATUS_SUCCESS;
3872}
3873
3874SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_play_and_detect_speech(switch_core_session_t *session,
3875 const char *file,
3876 const char *mod_name,
3877 const char *grammar,
3878 char **result,
3879 uint32_t input_timeout,
3880 switch_input_args_t *args)
3881{
3882 switch_status_t status = SWITCH_STATUS_SUCCESS;
3883 int recognizing = 0;
3884 switch_input_args_t myargs = { 0 };
3885 play_and_detect_speech_state_t state = { 0, "" };
3886 switch_channel_t *channel = switch_core_session_get_channel(session);
3887
3888 arg_recursion_check_start(args)if (args) { if (args->loops >= 25) { switch_log_printf(
SWITCH_CHANNEL_ID_LOG, "src/switch_ivr_async.c", (const char *
)__func__, 3888, ((void*)0), SWITCH_LOG_ERROR, "RECURSION ERROR! It's not the best idea to call things that collect input recursively from an input callback.\n"
); return SWITCH_STATUS_GENERR; } else {args->loops++;} }
;
3889
3890 if (result == NULL((void*)0)) {
3891 goto done;
3892 }
3893
3894 if (!input_timeout) input_timeout = 5000;
3895
3896 if (!args) {
3897 args = &myargs;
3898 }
3899
3900 /* start speech detection */
3901 if (switch_ivr_detect_speech(session, mod_name, grammar, "", NULL((void*)0), NULL((void*)0)) != SWITCH_STATUS_SUCCESS) {
3902 goto done;
3903 }
3904 recognizing = 1;
3905
3906 /* play the prompt, looking for detection result */
3907 args->input_callback = play_and_detect_input_callback;
3908 args->buf = &state;
3909 args->buflen = sizeof(state);
3910 status = switch_ivr_play_file(session, NULL((void*)0), file, args);
3911
3912 if (args->dmachine && switch_ivr_dmachine_last_ping(args->dmachine) != SWITCH_STATUS_SUCCESS) {
3913 state.done = 1;
3914 goto done;
3915 }
3916
3917 if (status != SWITCH_STATUS_BREAK && status != SWITCH_STATUS_SUCCESS) {
3918 goto done;
3919 }
3920
3921 /* wait for result if not done */
3922 if (!state.done) {
3923 switch_ivr_detect_speech_start_input_timers(session);
3924 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 3924, (const char*)(session)
, SWITCH_LOG_INFO, "(%s) WAITING FOR RESULT\n", switch_channel_get_name(channel));
3925 while (!state.done && switch_channel_ready(channel)switch_channel_test_ready(channel, SWITCH_TRUE, SWITCH_FALSE)) {
3926 status = switch_ivr_sleep(session, input_timeout, SWITCH_FALSE, args);
3927
3928 if (args->dmachine && switch_ivr_dmachine_last_ping(args->dmachine) != SWITCH_STATUS_SUCCESS) {
3929 state.done = 1;
3930 goto done;
3931 }
3932
3933 if (status != SWITCH_STATUS_BREAK && status != SWITCH_STATUS_SUCCESS) {
3934 goto done;
3935 }
3936 }
3937 }
3938 recognizing = !state.done;
3939
3940done:
3941 if (recognizing) {
3942 switch_ivr_pause_detect_speech(session);
3943 }
3944
3945 *result = state.result;
3946
3947 if (!state.done) {
3948 status = SWITCH_STATUS_FALSE;
3949 }
3950
3951 arg_recursion_check_stop(args)if (args) args->loops--;
3952
3953 return status;;
3954}
3955
3956struct speech_thread_handle {
3957 switch_core_session_t *session;
3958 switch_asr_handle_t *ah;
3959 switch_media_bug_t *bug;
3960 switch_mutex_t *mutex;
3961 switch_thread_cond_t *cond;
3962 switch_memory_pool_t *pool;
3963 int ready;
3964};
3965
3966static void *SWITCH_THREAD_FUNC speech_thread(switch_thread_t *thread, void *obj)
3967{
3968 struct speech_thread_handle *sth = (struct speech_thread_handle *) obj;
3969 switch_channel_t *channel = switch_core_session_get_channel(sth->session);
3970 switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE;
3971 switch_status_t status;
3972 switch_event_t *event;
3973
3974 switch_thread_cond_create(&sth->cond, sth->pool);
3975 switch_mutex_init(&sth->mutex, SWITCH_MUTEX_NESTED0x1, sth->pool);
3976
3977 if (switch_core_session_read_lock(sth->session) != SWITCH_STATUS_SUCCESS) {
3978 sth->ready = 0;
3979 return NULL((void*)0);
3980 }
3981
3982 switch_mutex_lock(sth->mutex);
3983
3984 sth->ready = 1;
3985
3986 while (switch_channel_up_nosig(channel)(switch_channel_get_state(channel) < CS_HANGUP) && !switch_test_flag(sth->ah, SWITCH_ASR_FLAG_CLOSED)((sth->ah)->flags & SWITCH_ASR_FLAG_CLOSED)) {
3987 char *xmlstr = NULL((void*)0);
3988 switch_event_t *headers = NULL((void*)0);
3989
3990 switch_thread_cond_wait(sth->cond, sth->mutex);
3991
3992 if (switch_channel_down_nosig(channel)(switch_channel_get_state(channel) >= CS_HANGUP) || switch_test_flag(sth->ah, SWITCH_ASR_FLAG_CLOSED)((sth->ah)->flags & SWITCH_ASR_FLAG_CLOSED)) {
3993 break;
3994 }
3995
3996 if (switch_core_asr_check_results(sth->ah, &flags) == SWITCH_STATUS_SUCCESS) {
3997
3998 status = switch_core_asr_get_results(sth->ah, &xmlstr, &flags);
3999
4000 if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
4001 goto done;
4002 } else if (status == SWITCH_STATUS_SUCCESS) {
4003 /* Try to fetch extra information for this result, the return value doesn't really matter here - it's just optional data. */
4004 switch_core_asr_get_result_headers(sth->ah, &headers, &flags);
4005 }
4006
4007 if (status == SWITCH_STATUS_SUCCESS && switch_true(switch_channel_get_variable(channel, "asr_intercept_dtmf")switch_channel_get_variable_dup(channel, "asr_intercept_dtmf"
, SWITCH_TRUE, -1)
)) {
4008 const char *p;
4009
4010 if ((p = switch_stristr("<input>", xmlstr))) {
4011 p += 7;
4012 }
4013
4014 while (p && *p) {
4015 char c;
4016
4017 if (*p == '<') {
4018 break;
4019 }
4020
4021 if (!strncasecmp(p, "pound", 5)) {
4022 c = '#';
4023 p += 5;
4024 } else if (!strncasecmp(p, "hash", 4)) {
4025 c = '#';
4026 p += 4;
4027 } else if (!strncasecmp(p, "star", 4)) {
4028 c = '*';
4029 p += 4;
4030 } else if (!strncasecmp(p, "asterisk", 8)) {
4031 c = '*';
4032 p += 8;
4033 } else {
4034 c = *p;
4035 p++;
4036 }
4037
4038 if (is_dtmf(c)((c > 47 && c < 58) || (c > 64 && c <
69) || (c > 96 && c < 101) || c == 35 || c == 42
|| c == 87 || c == 119 || c == 70 || c == 102)
) {
4039 switch_dtmf_t dtmf = {0};
4040 dtmf.digit = c;
4041 dtmf.duration = switch_core_default_dtmf_duration(0);
4042 dtmf.source = SWITCH_DTMF_INBAND_AUDIO;
4043 switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 4043, (const char*)switch_channel_get_session(channel
)
, SWITCH_LOG_DEBUG, "Queue speech detected dtmf %c\n", c);
4044 switch_channel_queue_dtmf(channel, &dtmf);
4045 }
4046
4047 }
4048 switch_ivr_resume_detect_speech(sth->session);
4049 }
4050
4051 if (switch_event_create(&event, SWITCH_EVENT_DETECTED_SPEECH)switch_event_create_subclass_detailed("src/switch_ivr_async.c"
, (const char * )(const char *)__func__, 4051, &event, SWITCH_EVENT_DETECTED_SPEECH
, ((void*)0))
== SWITCH_STATUS_SUCCESS) {
4052 if (status == SWITCH_STATUS_SUCCESS) {
4053 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "detected-speech");
4054
4055 if (headers) {
4056 switch_event_merge(event, headers);
4057 }
4058
4059 switch_event_add_body(event, "%s", xmlstr);
4060 } else {
4061 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "begin-speaking");
4062 }
4063
4064 if (switch_test_flag(sth->ah, SWITCH_ASR_FLAG_FIRE_EVENTS)((sth->ah)->flags & SWITCH_ASR_FLAG_FIRE_EVENTS)) {
4065 switch_event_t *dup;
4066
4067 if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {
4068 switch_channel_event_set_data(channel, dup);
4069 switch_event_fire(&dup)switch_event_fire_detailed("src/switch_ivr_async.c", (const char
* )(const char *)__func__, 4069, &dup, ((void*)0))
;
4070 }
4071
4072 }
4073
4074 if (switch_core_session_queue_event(sth->session, &event) != SWITCH_STATUS_SUCCESS) {
4075 switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 4075, (const char*)switch_channel_get_session(channel
)
, SWITCH_LOG_ERROR, "Event queue failed!\n");
4076 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
4077 switch_event_fire(&event)switch_event_fire_detailed("src/switch_ivr_async.c", (const char
* )(const char *)__func__, 4077, &event, ((void*)0))
;
4078 }
4079 }
4080
4081 switch_safe_free(xmlstr)if (xmlstr) {free(xmlstr);xmlstr=((void*)0);};
4082
4083 if (headers) {
4084 switch_event_destroy(&headers);
4085 }
4086 }
4087 }
4088 done:
4089
4090 if (switch_event_create(&event, SWITCH_EVENT_DETECTED_SPEECH)switch_event_create_subclass_detailed("src/switch_ivr_async.c"
, (const char * )(const char *)__func__, 4090, &event, SWITCH_EVENT_DETECTED_SPEECH
, ((void*)0))
== SWITCH_STATUS_SUCCESS) {
4091 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "closed");
4092 if (switch_test_flag(sth->ah, SWITCH_ASR_FLAG_FIRE_EVENTS)((sth->ah)->flags & SWITCH_ASR_FLAG_FIRE_EVENTS)) {
4093 switch_event_t *dup;
4094
4095 if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {
4096 switch_channel_event_set_data(channel, dup);
4097 switch_event_fire(&dup)switch_event_fire_detailed("src/switch_ivr_async.c", (const char
* )(const char *)__func__, 4097, &dup, ((void*)0))
;
4098 }
4099
4100 }
4101
4102 if (switch_core_session_queue_event(sth->session, &event) != SWITCH_STATUS_SUCCESS) {
4103 switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 4103, (const char*)switch_channel_get_session(channel
)
, SWITCH_LOG_ERROR, "Event queue failed!\n");
4104 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
4105 switch_event_fire(&event)switch_event_fire_detailed("src/switch_ivr_async.c", (const char
* )(const char *)__func__, 4105, &event, ((void*)0))
;
4106 }
4107 }
4108
4109 switch_mutex_unlock(sth->mutex);
4110 switch_core_session_rwunlock(sth->session);
4111
4112 return NULL((void*)0);
4113}
4114
4115static switch_bool_t speech_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
4116{
4117 struct speech_thread_handle *sth = (struct speech_thread_handle *) user_data;
4118 uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE8192];
4119 switch_frame_t frame = { 0 };
4120 switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE;
4121
4122 frame.data = data;
4123 frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE8192;
4124
4125 switch (type) {
4126 case SWITCH_ABC_TYPE_INIT:{
4127 switch_thread_t *thread;
4128 switch_threadattr_t *thd_attr = NULL((void*)0);
4129
4130 switch_threadattr_create(&thd_attr, sth->pool);
4131 switch_threadattr_detach_set(thd_attr, 1);
4132 switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE240 * 1024);
4133 switch_thread_create(&thread, thd_attr, speech_thread, sth, sth->pool);
4134 }
4135 break;
4136 case SWITCH_ABC_TYPE_CLOSE:{
4137 switch_core_asr_close(sth->ah, &flags);
4138 if (sth->mutex && sth->cond && sth->ready) {
4139 switch_mutex_lock(sth->mutex);
4140 switch_thread_cond_signal(sth->cond);
4141 switch_mutex_unlock(sth->mutex);
4142 }
4143 }
4144 break;
4145 case SWITCH_ABC_TYPE_READ:
4146 if (sth->ah) {
4147 if (switch_core_media_bug_read(bug, &frame, SWITCH_FALSE) != SWITCH_STATUS_FALSE) {
4148 if (switch_core_asr_feed(sth->ah, frame.data, frame.datalen, &flags) != SWITCH_STATUS_SUCCESS) {
4149 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug))SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 4149, (const char*)(switch_core_media_bug_get_session
(bug))
, SWITCH_LOG_DEBUG, "Error Feeding Data\n");
4150 return SWITCH_FALSE;
4151 }
4152 if (switch_core_asr_check_results(sth->ah, &flags) == SWITCH_STATUS_SUCCESS) {
4153 if (sth->mutex && sth->cond && sth->ready) {
4154 switch_mutex_lock(sth->mutex);
4155 switch_thread_cond_signal(sth->cond);
4156 switch_mutex_unlock(sth->mutex);
4157 }
4158 }
4159 }
4160 }
4161 break;
4162 case SWITCH_ABC_TYPE_WRITE:
4163 default:
4164 break;
4165 }
4166
4167 return SWITCH_TRUE;
4168}
4169
4170static switch_status_t speech_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction)
4171{
4172 switch_channel_t *channel = switch_core_session_get_channel(session);
4173 struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY"speech");
4174 switch_status_t status = SWITCH_STATUS_SUCCESS;
4175 switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE;
4176
4177 if (sth) {
4178 if (switch_core_asr_feed_dtmf(sth->ah, dtmf, &flags) != SWITCH_STATUS_SUCCESS) {
4179 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 4179, (const char*)(session)
, SWITCH_LOG_ERROR, "Error Feeding DTMF\n");
4180 }
4181 }
4182
4183 return status;
4184}
4185
4186SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_stop_detect_speech(switch_core_session_t *session)
4187{
4188 switch_channel_t *channel = switch_core_session_get_channel(session);
4189 struct speech_thread_handle *sth;
4190
4191 switch_assert(channel != NULL)((channel != ((void*)0)) ? (void) (0) : __assert_fail ("channel != ((void*)0)"
, "src/switch_ivr_async.c", 4191, __PRETTY_FUNCTION__))
;
4192 if ((sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY"speech"))) {
4193 switch_channel_set_private(channel, SWITCH_SPEECH_KEY"speech", NULL((void*)0));
4194 switch_core_event_hook_remove_recv_dtmf(session, speech_on_dtmf);
4195 switch_core_media_bug_remove(session, &sth->bug);
4196 return SWITCH_STATUS_SUCCESS;
4197 }
4198
4199 return SWITCH_STATUS_FALSE;
4200}
4201
4202SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_pause_detect_speech(switch_core_session_t *session)
4203{
4204 switch_channel_t *channel = switch_core_session_get_channel(session);
4205 struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY"speech");
4206
4207 if (sth) {
4208 switch_core_asr_pause(sth->ah);
4209 return SWITCH_STATUS_SUCCESS;
4210 }
4211 return SWITCH_STATUS_FALSE;
4212}
4213
4214SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_resume_detect_speech(switch_core_session_t *session)
4215{
4216 switch_channel_t *channel = switch_core_session_get_channel(session);
4217 struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY"speech");
4218
4219 if (sth) {
4220 switch_core_asr_resume(sth->ah);
4221 return SWITCH_STATUS_SUCCESS;
4222 }
4223 return SWITCH_STATUS_FALSE;
4224}
4225
4226SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_detect_speech_load_grammar(switch_core_session_t *session, const char *grammar, const char *name)
4227{
4228 switch_channel_t *channel = switch_core_session_get_channel(session);
4229 struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY"speech");
4230 switch_status_t status;
4231
4232 if (sth) {
4233 if ((status = switch_core_asr_load_grammar(sth->ah, grammar, name)) != SWITCH_STATUS_SUCCESS) {
4234 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 4234, (const char*)(session)
, SWITCH_LOG_DEBUG, "Error loading Grammar\n");
4235 switch_ivr_stop_detect_speech(session);
4236 }
4237 return status;
4238 }
4239 return SWITCH_STATUS_FALSE;
4240}
4241
4242SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_set_param_detect_speech(switch_core_session_t *session, const char *name, const char *val)
4243{
4244 struct speech_thread_handle *sth = switch_channel_get_private(switch_core_session_get_channel(session), SWITCH_SPEECH_KEY"speech");
4245 switch_status_t status = SWITCH_STATUS_FALSE;
4246
4247 if (sth && sth->ah && name && val) {
4248 switch_core_asr_text_param(sth->ah, (char *) name, val);
4249 status = SWITCH_STATUS_SUCCESS;
4250 }
4251
4252 return status;
4253}
4254
4255SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_detect_speech_start_input_timers(switch_core_session_t *session)
4256{
4257 switch_channel_t *channel = switch_core_session_get_channel(session);
4258 struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY"speech");
4259
4260 if (sth) {
4261 switch_core_asr_start_input_timers(sth->ah);
4262 return SWITCH_STATUS_SUCCESS;
4263 }
4264 return SWITCH_STATUS_FALSE;
4265}
4266
4267SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_detect_speech_unload_grammar(switch_core_session_t *session, const char *name)
4268{
4269 switch_channel_t *channel = switch_core_session_get_channel(session);
4270 struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY"speech");
4271 switch_status_t status;
4272
4273 if (sth) {
4274 if ((status = switch_core_asr_unload_grammar(sth->ah, name)) != SWITCH_STATUS_SUCCESS) {
4275 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 4275, (const char*)(session)
, SWITCH_LOG_DEBUG, "Error unloading Grammar\n");
4276 switch_ivr_stop_detect_speech(session);
4277 }
4278 return status;
4279 }
4280 return SWITCH_STATUS_FALSE;
4281}
4282
4283SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_detect_speech_enable_grammar(switch_core_session_t *session, const char *name)
4284{
4285 switch_channel_t *channel = switch_core_session_get_channel(session);
4286 struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY"speech");
4287 switch_status_t status;
4288
4289 if (sth) {
4290 if ((status = switch_core_asr_enable_grammar(sth->ah, name)) != SWITCH_STATUS_SUCCESS) {
4291 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 4291, (const char*)(session)
, SWITCH_LOG_DEBUG, "Error enabling Grammar\n");
4292 switch_ivr_stop_detect_speech(session);
4293 }
4294 return status;
4295 }
4296 return SWITCH_STATUS_FALSE;
4297}
4298
4299SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_detect_speech_disable_grammar(switch_core_session_t *session, const char *name)
4300{
4301 switch_channel_t *channel = switch_core_session_get_channel(session);
4302 struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY"speech");
4303 switch_status_t status;
4304
4305 if (sth) {
4306 if ((status = switch_core_asr_disable_grammar(sth->ah, name)) != SWITCH_STATUS_SUCCESS) {
4307 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 4307, (const char*)(session)
, SWITCH_LOG_DEBUG, "Error disabling Grammar\n");
4308 switch_ivr_stop_detect_speech(session);
4309 }
4310 return status;
4311 }
4312 return SWITCH_STATUS_FALSE;
4313}
4314
4315SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_detect_speech_disable_all_grammars(switch_core_session_t *session)
4316{
4317 switch_channel_t *channel = switch_core_session_get_channel(session);
4318 struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY"speech");
4319 switch_status_t status;
4320
4321 if (sth) {
4322 if ((status = switch_core_asr_disable_all_grammars(sth->ah)) != SWITCH_STATUS_SUCCESS) {
4323 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 4323, (const char*)(session)
, SWITCH_LOG_DEBUG, "Error disabling all Grammars\n");
4324 switch_ivr_stop_detect_speech(session);
4325 }
4326 return status;
4327 }
4328 return SWITCH_STATUS_FALSE;
4329}
4330
4331SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_detect_speech_init(switch_core_session_t *session, const char *mod_name,
4332 const char *dest, switch_asr_handle_t *ah)
4333{
4334 switch_channel_t *channel = switch_core_session_get_channel(session);
4335 switch_status_t status;
4336 switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE;
4337 struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY"speech");
4338 switch_codec_implementation_t read_impl = { 0 };
4339 const char *p;
4340 char key[512] = "";
4341
4342 if (sth) {
4343 /* Already initialized */
4344 return SWITCH_STATUS_SUCCESS;
4345 }
4346
4347 if (!ah) {
4348 if (!(ah = switch_core_session_alloc(session, sizeof(*ah))switch_core_perform_session_alloc(session, sizeof(*ah), "src/switch_ivr_async.c"
, (const char *)__func__, 4348)
)) {
4349 return SWITCH_STATUS_MEMERR;
4350 }
4351 }
4352
4353 switch_core_session_get_read_impl(session, &read_impl);
4354
4355 if ((status = switch_core_asr_open(ah,
4356 mod_name,
4357 "L16",
4358 read_impl.actual_samples_per_second, dest, &flags,
4359 switch_core_session_get_pool(session))) != SWITCH_STATUS_SUCCESS) {
4360 return status;
4361 }
4362
4363 sth = switch_core_session_alloc(session, sizeof(*sth))switch_core_perform_session_alloc(session, sizeof(*sth), "src/switch_ivr_async.c"
, (const char *)__func__, 4363)
;
4364 sth->pool = switch_core_session_get_pool(session);
4365 sth->session = session;
4366 sth->ah = ah;
4367
4368 if ((p = switch_channel_get_variable(channel, "fire_asr_events")switch_channel_get_variable_dup(channel, "fire_asr_events", SWITCH_TRUE
, -1)
) && switch_true(p)) {
4369 switch_set_flag(ah, SWITCH_ASR_FLAG_FIRE_EVENTS)(ah)->flags |= (SWITCH_ASR_FLAG_FIRE_EVENTS);
4370 }
4371
4372 switch_snprintf(key, sizeof(key), "%s/%s/%s/%s", mod_name, NULL((void*)0), NULL((void*)0), dest);
4373
4374 if ((status = switch_core_media_bug_add(session, "detect_speech", key,
4375 speech_callback, sth, 0, SMBF_READ_STREAM | SMBF_NO_PAUSE, &sth->bug)) != SWITCH_STATUS_SUCCESS) {
4376 switch_core_asr_close(ah, &flags);
4377 return status;
4378 }
4379
4380 if ((status = switch_core_event_hook_add_recv_dtmf(session, speech_on_dtmf)) != SWITCH_STATUS_SUCCESS) {
4381 switch_ivr_stop_detect_speech(session);
4382 return status;
4383 }
4384
4385 switch_channel_set_private(channel, SWITCH_SPEECH_KEY"speech", sth);
4386
4387 return SWITCH_STATUS_SUCCESS;
4388}
4389
4390SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_detect_speech(switch_core_session_t *session,
4391 const char *mod_name,
4392 const char *grammar, const char *name, const char *dest, switch_asr_handle_t *ah)
4393{
4394 switch_channel_t *channel = switch_core_session_get_channel(session);
4395 switch_status_t status;
4396 struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY"speech");
4397 const char *p;
4398
4399 if (!sth) {
4400 /* No speech thread handle available yet, init speech detection first. */
4401 if ((status = switch_ivr_detect_speech_init(session, mod_name, dest, ah)) != SWITCH_STATUS_SUCCESS) {
4402 return status;
4403 }
4404
4405 /* Fetch the new speech thread handle */
4406 if (!(sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY"speech"))) {
4407 return SWITCH_STATUS_FALSE;
4408 }
4409 }
4410
4411 if (switch_core_asr_load_grammar(sth->ah, grammar, name) != SWITCH_STATUS_SUCCESS) {
4412 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 4412, (const char*)(session)
, SWITCH_LOG_DEBUG, "Error loading Grammar\n");
4413 switch_ivr_stop_detect_speech(session);
4414 return SWITCH_STATUS_FALSE;
4415 }
4416
4417 if ((p = switch_channel_get_variable(channel, "fire_asr_events")switch_channel_get_variable_dup(channel, "fire_asr_events", SWITCH_TRUE
, -1)
) && switch_true(p)) {
4418 switch_set_flag(sth->ah, SWITCH_ASR_FLAG_FIRE_EVENTS)(sth->ah)->flags |= (SWITCH_ASR_FLAG_FIRE_EVENTS);
4419 }
4420
4421 return SWITCH_STATUS_SUCCESS;
4422}
4423
4424struct hangup_helper {
4425 char uuid_str[SWITCH_UUID_FORMATTED_LENGTH256 + 1];
4426 switch_bool_t bleg;
4427 switch_call_cause_t cause;
4428};
4429
4430SWITCH_STANDARD_SCHED_FUNC(sch_hangup_callback)static void sch_hangup_callback (switch_scheduler_task_t *task
)
4431{
4432 struct hangup_helper *helper;
4433 switch_core_session_t *session, *other_session;
4434 const char *other_uuid;
4435
4436 switch_assert(task)((task) ? (void) (0) : __assert_fail ("task", "src/switch_ivr_async.c"
, 4436, __PRETTY_FUNCTION__))
;
4437
4438 helper = (struct hangup_helper *) task->cmd_arg;
4439
4440 if ((session = switch_core_session_locate(helper->uuid_str)switch_core_session_perform_locate(helper->uuid_str, "src/switch_ivr_async.c"
, (const char *)__func__, 4440)
)) {
4441 switch_channel_t *channel = switch_core_session_get_channel(session);
4442
4443 if (helper->bleg) {
4444 if ((other_uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)switch_channel_get_variable_dup(channel, "bridge_to", SWITCH_TRUE
, -1)
) && (other_session = switch_core_session_locate(other_uuid)switch_core_session_perform_locate(other_uuid, "src/switch_ivr_async.c"
, (const char *)__func__, 4444)
)) {
4445 switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
4446 switch_channel_hangup(other_channel, helper->cause)switch_channel_perform_hangup(other_channel, "src/switch_ivr_async.c"
, (const char *)__func__, 4446, helper->cause)
;
4447 switch_core_session_rwunlock(other_session);
4448 } else {
4449 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_async.c", (const char
*)__func__, 4449, (const char*)(session)
, SWITCH_LOG_WARNING, "No channel to hangup\n");
4450 }
4451 } else {
4452 switch_channel_hangup(channel, helper->cause)switch_channel_perform_hangup(channel, "src/switch_ivr_async.c"
, (const char *)__func__, 4452, helper->cause)
;
4453 }
4454
4455 switch_core_session_rwunlock(session);
4456 }
4457}
4458
4459SWITCH_DECLARE(uint32_t)__attribute__((visibility("default"))) uint32_t switch_ivr_schedule_hangup(time_t runtime, const char *uuid, switch_call_cause_t cause, switch_bool_t bleg)
4460{
4461 struct hangup_helper *helper;
4462 size_t len = sizeof(*helper);
4463
4464 switch_zmalloc(helper, len)(void)((((helper = calloc(1, (len)))) ? (void) (0) : __assert_fail
("(helper = calloc(1, (len)))", "src/switch_ivr_async.c", 4464
, __PRETTY_FUNCTION__)),helper)
;
4465
4466 switch_copy_string(helper->uuid_str, uuid, sizeof(helper->uuid_str));
4467 helper->cause = cause;
4468 helper->bleg = bleg;
4469
4470 return switch_scheduler_add_task(runtime, sch_hangup_callback, (char *) __SWITCH_FUNC__(const char *)__func__, uuid, 0, helper, SSHF_FREE_ARG);
4471}
4472
4473struct transfer_helper {
4474 char uuid_str[SWITCH_UUID_FORMATTED_LENGTH256 + 1];
4475 char *extension;
4476 char *dialplan;
4477 char *context;
4478};
4479
4480SWITCH_STANDARD_SCHED_FUNC(sch_transfer_callback)static void sch_transfer_callback (switch_scheduler_task_t *task
)
4481{
4482 struct transfer_helper *helper;
4483 switch_core_session_t *session;
4484
4485 switch_assert(task)((task) ? (void) (0) : __assert_fail ("task", "src/switch_ivr_async.c"
, 4485, __PRETTY_FUNCTION__))
;
4486
4487 helper = (struct transfer_helper *) task->cmd_arg;
4488
4489 if ((session = switch_core_session_locate(helper->uuid_str)switch_core_session_perform_locate(helper->uuid_str, "src/switch_ivr_async.c"
, (const char *)__func__, 4489)
)) {
4490 switch_ivr_session_transfer(session, helper->extension, helper->dialplan, helper->context);
4491 switch_core_session_rwunlock(session);
4492 }
4493
4494}
4495
4496SWITCH_DECLARE(uint32_t)__attribute__((visibility("default"))) uint32_t switch_ivr_schedule_transfer(time_t runtime, const char *uuid, char *extension, char *dialplan, char *context)
4497{
4498 struct transfer_helper *helper;
4499 size_t len = sizeof(*helper);
4500 char *cur = NULL((void*)0);
4501
4502 if (extension) {
4503 len += strlen(extension) + 1;
4504 }
4505
4506 if (dialplan) {
4507 len += strlen(dialplan) + 1;
4508 }
4509
4510 if (context) {
4511 len += strlen(context) + 1;
4512 }
4513
4514 switch_zmalloc(cur, len)(void)((((cur = calloc(1, (len)))) ? (void) (0) : __assert_fail
("(cur = calloc(1, (len)))", "src/switch_ivr_async.c", 4514,
__PRETTY_FUNCTION__)),cur)
;
4515 helper = (struct transfer_helper *) cur;
4516
4517 switch_copy_string(helper->uuid_str, uuid, sizeof(helper->uuid_str));
4518
4519 cur += sizeof(*helper);
4520
4521 if (extension) {
4522 switch_copy_string(cur, extension, strlen(extension) + 1);
4523 helper->extension = cur;
4524 cur += strlen(helper->extension) + 1;
4525 }
4526
4527 if (dialplan) {
4528 switch_copy_string(cur, dialplan, strlen(dialplan) + 1);
4529 helper->dialplan = cur;
4530 cur += strlen(helper->dialplan) + 1;
4531 }
4532
4533 if (context) {
4534 switch_copy_string(cur, context, strlen(context) + 1);
4535 helper->context = cur;
4536 }
4537
4538 return switch_scheduler_add_task(runtime, sch_transfer_callback, (char *) __SWITCH_FUNC__(const char *)__func__, uuid, 0, helper, SSHF_FREE_ARG);
4539}
4540
4541struct broadcast_helper {
4542 char uuid_str[SWITCH_UUID_FORMATTED_LENGTH256 + 1];
4543 char *path;
4544 switch_media_flag_t flags;
4545};
4546
4547SWITCH_STANDARD_SCHED_FUNC(sch_broadcast_callback)static void sch_broadcast_callback (switch_scheduler_task_t *
task)
4548{
4549 struct broadcast_helper *helper;
4550 switch_assert(task)((task) ? (void) (0) : __assert_fail ("task", "src/switch_ivr_async.c"
, 4550, __PRETTY_FUNCTION__))
;
4551
4552 helper = (struct broadcast_helper *) task->cmd_arg;
4553 switch_ivr_broadcast(helper->uuid_str, helper->path, helper->flags);
4554}
4555
4556SWITCH_DECLARE(uint32_t)__attribute__((visibility("default"))) uint32_t switch_ivr_schedule_broadcast(time_t runtime, const char *uuid, const char *path, switch_media_flag_t flags)
4557{
4558 struct broadcast_helper *helper;
4559 size_t len = sizeof(*helper) + strlen(path) + 1;
4560 char *cur = NULL((void*)0);
4561
4562 switch_zmalloc(cur, len)(void)((((cur = calloc(1, (len)))) ? (void) (0) : __assert_fail
("(cur = calloc(1, (len)))", "src/switch_ivr_async.c", 4562,
__PRETTY_FUNCTION__)),cur)
;
4563 helper = (struct broadcast_helper *) cur;
4564
4565 cur += sizeof(*helper);
4566 switch_copy_string(helper->uuid_str, uuid, sizeof(helper->uuid_str));
4567 helper->flags = flags;
4568
4569 switch_copy_string(cur, path, len - sizeof(helper));
4570 helper->path = cur;
4571
4572 return switch_scheduler_add_task(runtime, sch_broadcast_callback, (char *) __SWITCH_FUNC__(const char *)__func__, uuid, 0, helper, SSHF_FREE_ARG);
4573}
4574
4575SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_broadcast(const char *uuid, const char *path, switch_media_flag_t flags)
4576{
4577 switch_channel_t *channel;
4578 switch_core_session_t *session, *master;
4579 switch_event_t *event;
4580 switch_core_session_t *other_session = NULL((void*)0);
4581 const char *other_uuid = NULL((void*)0);
4582 char *app = "playback";
4583 char *cause = NULL((void*)0);
4584 char *mypath;
4585 char *p;
4586 int app_flags = 0, nomedia = 0;
4587
4588 switch_assert(path)((path) ? (void) (0) : __assert_fail ("path", "src/switch_ivr_async.c"
, 4588, __PRETTY_FUNCTION__))
;
4589
4590 if (!(master = session = switch_core_session_locate(uuid)switch_core_session_perform_locate(uuid, "src/switch_ivr_async.c"
, (const char *)__func__, 4590)
)) {
4591 return SWITCH_STATUS_FALSE;
4592 }
4593
4594 channel = switch_core_session_get_channel(session);
4595
4596 mypath = strdup(path)(__extension__ (__builtin_constant_p (path) && ((size_t
)(const void *)((path) + 1) - (size_t)(const void *)(path) ==
1) ? (((const char *) (path))[0] == '\0' ? (char *) calloc (
(size_t) 1, (size_t) 1) : ({ size_t __len = strlen (path) + 1
; char *__retval = (char *) malloc (__len); if (__retval != (
(void*)0)) __retval = (char *) memcpy (__retval, path, __len)
; __retval; })) : __strdup (path)))
;
4597 assert(mypath)((mypath) ? (void) (0) : __assert_fail ("mypath", "src/switch_ivr_async.c"
, 4597, __PRETTY_FUNCTION__))
;
4598
4599 if ((p = strchr(mypath, ':')(__extension__ (__builtin_constant_p (':') && !__builtin_constant_p
(mypath) && (':') == '\0' ? (char *) __rawmemchr (mypath
, ':') : __builtin_strchr (mypath, ':')))
) && *(p + 1) == ':') {
4600 app = mypath;
4601 *p++ = '\0';
4602 *p++ = '\0';
4603 path = p;
4604 }
4605
4606 if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
4607 nomedia = 1;
4608 switch_ivr_media(uuid, SMF_REBRIDGE);
4609 }
4610
4611 if ((cause = strchr(app, '!')(__extension__ (__builtin_constant_p ('!') && !__builtin_constant_p
(app) && ('!') == '\0' ? (char *) __rawmemchr (app, '!'
) : __builtin_strchr (app, '!')))
)) {
4612 *cause++ = '\0';
4613 if (!cause) {
4614 cause = "normal_clearing";
4615 }
4616 }
4617
4618 if ((flags & SMF_ECHO_BLEG) && (other_uuid = switch_channel_get_partner_uuid(channel))
4619 && (other_session = switch_core_session_locate(other_uuid)switch_core_session_perform_locate(other_uuid, "src/switch_ivr_async.c"
, (const char *)__func__, 4619)
)) {
4620 if ((flags & SMF_EXEC_INLINE)) {
4621 switch_core_session_execute_application_get_flags(other_session, app, path, &app_flags);
4622 nomedia = 0;
4623 } else {
4624 switch_core_session_get_app_flags(app, &app_flags);
4625 if (switch_event_create(&event, SWITCH_EVENT_COMMAND)switch_event_create_subclass_detailed("src/switch_ivr_async.c"
, (const char * )(const char *)__func__, 4625, &event, SWITCH_EVENT_COMMAND
, ((void*)0))
== SWITCH_STATUS_SUCCESS) {
4626 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
4627 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-name", app);
4628 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-arg", path);
4629 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, (flags & SMF_PRIORITY) ? "event-lock-pri" : "event-lock", "true");
4630
4631 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "lead-frames", "%d", 5);
4632
4633 if ((flags & SMF_LOOP)) {
4634 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "loops", "%d", -1);
4635 }
4636
4637 if ((flags & SMF_HOLD_BLEG)) {
4638 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "hold-bleg", "true");
4639 }
4640
4641 switch_core_session_queue_private_event(other_session, &event, (flags & SMF_PRIORITY));
4642 }
4643 }
4644
4645 switch_core_session_rwunlock(other_session);
4646 master = other_session;
4647 other_session = NULL((void*)0);
4648 }
4649
4650 if ((app_flags & SAF_MEDIA_TAP)) {
4651 nomedia = 0;
4652 }
4653
4654 if ((flags & SMF_ECHO_ALEG)) {
4655 if ((flags & SMF_EXEC_INLINE)) {
4656 nomedia = 0;
4657 switch_core_session_execute_application(session, app, path)switch_core_session_execute_application_get_flags(session, app
, path, ((void*)0))
;
4658 } else {
4659 if (switch_event_create(&event, SWITCH_EVENT_COMMAND)switch_event_create_subclass_detailed("src/switch_ivr_async.c"
, (const char * )(const char *)__func__, 4659, &event, SWITCH_EVENT_COMMAND
, ((void*)0))
== SWITCH_STATUS_SUCCESS) {
4660 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
4661 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-name", app);
4662 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-arg", path);
4663 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, (flags & SMF_PRIORITY) ? "event-lock-pri" : "event-lock", "true");
4664 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "lead-frames", "%d", 5);
4665
4666 if ((flags & SMF_LOOP)) {
4667 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "loops", "%d", -1);
4668 }
4669 if ((flags & SMF_HOLD_BLEG)) {
4670 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "hold-bleg", "true");
4671 }
4672
4673 switch_core_session_queue_private_event(session, &event, (flags & SMF_PRIORITY));
4674
4675 if (nomedia)
4676 switch_channel_set_flag(channel, CF_BROADCAST_DROP_MEDIA)switch_channel_set_flag_value(channel, CF_BROADCAST_DROP_MEDIA
, 1)
;
4677 }
4678 }
4679 master = session;
4680 }
4681
4682 if (cause) {
4683 if (switch_event_create(&event, SWITCH_EVENT_COMMAND)switch_event_create_subclass_detailed("src/switch_ivr_async.c"
, (const char * )(const char *)__func__, 4683, &event, SWITCH_EVENT_COMMAND
, ((void*)0))
== SWITCH_STATUS_SUCCESS) {
4684 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
4685 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-name", "hangup");
4686 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-arg", cause);
4687 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, (flags & SMF_PRIORITY) ? "event-lock-pri" : "event-lock", "true");
4688 switch_core_session_queue_private_event(session, &event, (flags & SMF_PRIORITY));
4689 }
4690 }
4691
4692 switch_core_session_rwunlock(session);
4693 switch_safe_free(mypath)if (mypath) {free(mypath);mypath=((void*)0);};
4694
4695 return SWITCH_STATUS_SUCCESS;
4696}
4697
4698/* For Emacs:
4699 * Local Variables:
4700 * mode:c
4701 * indent-tabs-mode:t
4702 * tab-width:4
4703 * c-basic-offset:4
4704 * End:
4705 * For VIM:
4706 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
4707 */