2006-01-26 18:00:27 +00:00
|
|
|
/*
|
|
|
|
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
2010-02-06 03:38:24 +00:00
|
|
|
* Copyright (C) 2005-2010, Anthony Minessale II <anthm@freeswitch.org>
|
2006-01-26 18:00:27 +00:00
|
|
|
*
|
|
|
|
* Version: MPL 1.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
2009-02-04 21:20:54 +00:00
|
|
|
* Anthony Minessale II <anthm@freeswitch.org>
|
2006-01-26 18:00:27 +00:00
|
|
|
* Portions created by the Initial Developer are Copyright (C)
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
*
|
2009-02-04 21:20:54 +00:00
|
|
|
* Anthony Minessale II <anthm@freeswitch.org>
|
2006-10-28 04:40:59 +00:00
|
|
|
* Paul D. Tinsley <pdt at jackhammer.org>
|
2006-11-13 16:29:16 +00:00
|
|
|
* Neal Horman <neal at wanlink dot com>
|
2006-11-29 20:07:13 +00:00
|
|
|
* Matt Klein <mklein@nmedia.net>
|
2007-02-03 04:09:43 +00:00
|
|
|
* Michael Jerris <mike@jerris.com>
|
2008-01-16 22:13:36 +00:00
|
|
|
* Ken Rice <krice at suspicious dot org>
|
2006-01-26 18:00:27 +00:00
|
|
|
*
|
2006-12-04 05:41:03 +00:00
|
|
|
* switch_ivr.c -- IVR Library
|
2006-01-26 18:00:27 +00:00
|
|
|
*
|
|
|
|
*/
|
2008-01-27 17:36:53 +00:00
|
|
|
|
2006-01-26 18:00:27 +00:00
|
|
|
#include <switch.h>
|
|
|
|
#include <switch_ivr.h>
|
2007-10-04 15:09:44 +00:00
|
|
|
#include "stfu.h"
|
2006-10-25 04:28:49 +00:00
|
|
|
|
2009-02-05 19:53:13 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_sound_test(switch_core_session_t *session)
|
|
|
|
{
|
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
switch_codec_implementation_t imp = { 0 };
|
2009-02-05 19:53:13 +00:00
|
|
|
switch_codec_t codec = { 0 };
|
|
|
|
int16_t peak = 0;
|
|
|
|
int16_t *data;
|
|
|
|
switch_frame_t *read_frame = NULL;
|
2009-02-06 23:49:22 +00:00
|
|
|
uint32_t i;
|
2009-02-05 19:53:13 +00:00
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
|
|
|
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
|
|
|
int64_t global_total = 0, global_sum = 0, period_sum = 0;
|
|
|
|
int period_total = 0;
|
|
|
|
int period_avg = 0, global_avg = 0;
|
|
|
|
int avg = 0;
|
|
|
|
int period_len;
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2009-02-05 19:53:13 +00:00
|
|
|
switch_core_session_get_read_impl(session, &imp);
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2009-02-05 19:53:13 +00:00
|
|
|
period_len = imp.actual_samples_per_second / imp.samples_per_packet;
|
|
|
|
|
|
|
|
if (switch_core_codec_init(&codec,
|
|
|
|
"L16",
|
|
|
|
NULL,
|
|
|
|
imp.samples_per_second,
|
|
|
|
imp.microseconds_per_packet / 1000,
|
2010-02-06 03:38:24 +00:00
|
|
|
imp.number_of_channels,
|
|
|
|
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,
|
2009-02-05 19:53:13 +00:00
|
|
|
switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
2010-02-06 03:38:24 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec Error L16@%uhz %u channels %dms\n",
|
2009-02-05 19:53:13 +00:00
|
|
|
imp.samples_per_second, imp.number_of_channels, imp.microseconds_per_packet / 1000);
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
|
|
|
while (switch_channel_ready(channel)) {
|
2009-02-05 19:53:13 +00:00
|
|
|
status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2009-02-05 19:53:13 +00:00
|
|
|
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (switch_test_flag(read_frame, SFF_CNG) || !read_frame->samples) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
data = (int16_t *) read_frame->data;
|
|
|
|
peak = 0;
|
|
|
|
avg = 0;
|
|
|
|
for (i = 0; i < read_frame->samples; i++) {
|
2010-02-06 03:38:24 +00:00
|
|
|
const int16_t s = (int16_t) abs(data[i]);
|
2009-02-05 19:53:13 +00:00
|
|
|
if (s > peak) {
|
|
|
|
peak = s;
|
|
|
|
}
|
|
|
|
avg += s;
|
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2009-02-05 19:53:13 +00:00
|
|
|
avg /= read_frame->samples;
|
|
|
|
|
|
|
|
period_sum += peak;
|
|
|
|
global_sum += peak;
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2009-02-05 19:53:13 +00:00
|
|
|
global_total++;
|
|
|
|
period_total++;
|
2010-02-06 03:38:24 +00:00
|
|
|
|
|
|
|
period_avg = (int) (period_sum / period_total);
|
|
|
|
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CONSOLE,
|
|
|
|
"\npacket_avg=%d packet_peak=%d period_avg=%d global_avg=%d\n\n", avg, peak, period_avg, global_avg);
|
|
|
|
|
|
|
|
if (period_total >= period_len) {
|
|
|
|
global_avg = (int) (global_sum / global_total);
|
2009-02-05 19:53:13 +00:00
|
|
|
period_total = 0;
|
|
|
|
period_sum = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2009-02-05 19:53:13 +00:00
|
|
|
|
|
|
|
switch_core_codec_destroy(&codec);
|
|
|
|
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-12-10 00:48:24 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session, uint32_t ms, switch_bool_t sync, switch_input_args_t *args)
|
2006-07-13 13:20:20 +00:00
|
|
|
{
|
2008-01-28 07:26:10 +00:00
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
2006-07-13 13:20:20 +00:00
|
|
|
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
2009-01-25 21:23:07 +00:00
|
|
|
switch_time_t start = switch_micro_time_now(), now, done = switch_micro_time_now() + (ms * 1000);
|
2008-10-03 18:14:11 +00:00
|
|
|
switch_frame_t *read_frame, cng_frame = { 0 };
|
2006-07-13 13:20:20 +00:00
|
|
|
int32_t left, elapsed;
|
2008-10-03 18:14:11 +00:00
|
|
|
char data[2] = "";
|
|
|
|
|
2008-12-09 00:32:51 +00:00
|
|
|
switch_frame_t write_frame = { 0 };
|
|
|
|
unsigned char *abuf = NULL;
|
2010-02-06 03:38:24 +00:00
|
|
|
switch_codec_implementation_t imp = { 0 };
|
2008-12-09 00:32:51 +00:00
|
|
|
switch_codec_t codec = { 0 };
|
|
|
|
int sval = 0;
|
|
|
|
const char *var;
|
2009-01-06 22:39:48 +00:00
|
|
|
|
2009-02-03 20:33:24 +00:00
|
|
|
/*
|
2010-02-06 03:38:24 +00:00
|
|
|
if (!switch_channel_test_flag(channel, CF_OUTBOUND) && !switch_channel_test_flag(channel, CF_PROXY_MODE) &&
|
|
|
|
!switch_channel_media_ready(channel) && !switch_channel_test_flag(channel, CF_SERVICE)) {
|
|
|
|
if ((status = switch_channel_pre_answer(channel)) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot establish media.\n");
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
2009-01-06 22:39:48 +00:00
|
|
|
|
2009-01-19 16:00:11 +00:00
|
|
|
if (!switch_channel_media_ready(channel)) {
|
|
|
|
switch_yield(ms * 1000);
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ms > 100 && (var = switch_channel_get_variable(channel, SWITCH_SEND_SILENCE_WHEN_IDLE_VARIABLE)) && (sval = atoi(var))) {
|
2008-12-09 00:32:51 +00:00
|
|
|
switch_core_session_get_read_impl(session, &imp);
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2008-12-09 00:32:51 +00:00
|
|
|
if (switch_core_codec_init(&codec,
|
|
|
|
"L16",
|
|
|
|
NULL,
|
|
|
|
imp.samples_per_second,
|
|
|
|
imp.microseconds_per_packet / 1000,
|
2010-02-06 03:38:24 +00:00
|
|
|
imp.number_of_channels,
|
|
|
|
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,
|
2008-12-09 00:32:51 +00:00
|
|
|
switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
2010-02-06 03:38:24 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec Error L16@%uhz %u channels %dms\n",
|
2008-12-09 00:32:51 +00:00
|
|
|
imp.samples_per_second, imp.number_of_channels, imp.microseconds_per_packet / 1000);
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Codec Activated L16@%uhz %u channels %dms\n",
|
2008-12-09 00:32:51 +00:00
|
|
|
imp.samples_per_second, imp.number_of_channels, imp.microseconds_per_packet / 1000);
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2008-12-09 00:32:51 +00:00
|
|
|
write_frame.codec = &codec;
|
|
|
|
switch_zmalloc(abuf, SWITCH_RECOMMENDED_BUFFER_SIZE);
|
|
|
|
write_frame.data = abuf;
|
|
|
|
write_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE;
|
|
|
|
write_frame.datalen = imp.decoded_bytes_per_packet;
|
|
|
|
write_frame.samples = write_frame.datalen / sizeof(int16_t);
|
2008-12-10 00:48:24 +00:00
|
|
|
|
2008-12-09 00:32:51 +00:00
|
|
|
}
|
|
|
|
|
2009-01-06 23:26:49 +00:00
|
|
|
if (!write_frame.datalen) {
|
|
|
|
sval = 0;
|
|
|
|
}
|
|
|
|
|
2008-10-03 18:14:11 +00:00
|
|
|
cng_frame.data = data;
|
|
|
|
cng_frame.datalen = 2;
|
|
|
|
cng_frame.buflen = 2;
|
2008-11-26 18:56:37 +00:00
|
|
|
switch_set_flag((&cng_frame), SFF_CNG);
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2009-01-19 16:00:11 +00:00
|
|
|
if (sync) {
|
2008-12-01 16:21:27 +00:00
|
|
|
switch_channel_audio_sync(channel);
|
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2008-12-01 16:21:27 +00:00
|
|
|
if (!ms) {
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
2008-11-27 04:02:57 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
for (;;) {
|
2009-01-25 21:23:07 +00:00
|
|
|
now = switch_micro_time_now();
|
2007-03-29 22:31:56 +00:00
|
|
|
elapsed = (int32_t) ((now - start) / 1000);
|
2006-07-13 13:20:20 +00:00
|
|
|
left = ms - elapsed;
|
|
|
|
|
|
|
|
if (!switch_channel_ready(channel)) {
|
|
|
|
status = SWITCH_STATUS_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2008-07-08 19:26:44 +00:00
|
|
|
if (switch_channel_test_flag(channel, CF_BREAK)) {
|
|
|
|
switch_channel_clear_flag(channel, CF_BREAK);
|
|
|
|
status = SWITCH_STATUS_BREAK;
|
|
|
|
break;
|
|
|
|
}
|
2006-07-13 13:20:20 +00:00
|
|
|
|
|
|
|
if (now > done || left <= 0) {
|
|
|
|
break;
|
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2009-10-12 22:23:55 +00:00
|
|
|
|
|
|
|
switch_ivr_parse_all_events(session);
|
|
|
|
|
2008-07-08 23:13:02 +00:00
|
|
|
|
2010-10-04 23:23:43 +00:00
|
|
|
if (args && (args->input_callback || args->buf || args->buflen || args->dmachine)) {
|
2008-07-08 17:27:02 +00:00
|
|
|
switch_dtmf_t dtmf;
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2008-07-08 17:27:02 +00:00
|
|
|
/*
|
|
|
|
dtmf handler function you can hook up to be executed when a digit is dialed during playback
|
|
|
|
if you return anything but SWITCH_STATUS_SUCCESS the playback will stop.
|
|
|
|
*/
|
|
|
|
if (switch_channel_has_dtmf(channel)) {
|
2010-10-11 23:38:30 +00:00
|
|
|
if (!args->input_callback && !args->buf && !args->dmachine) {
|
2008-07-08 17:27:02 +00:00
|
|
|
status = SWITCH_STATUS_BREAK;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch_channel_dequeue_dtmf(channel, &dtmf);
|
2010-10-04 23:23:43 +00:00
|
|
|
|
|
|
|
if (args->dmachine) {
|
|
|
|
char ds[2] = {dtmf.digit, '\0'};
|
|
|
|
if ((status = switch_ivr_dmachine_feed(args->dmachine, ds, NULL)) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (args->input_callback) {
|
2008-07-08 17:27:02 +00:00
|
|
|
status = args->input_callback(session, (void *) &dtmf, SWITCH_INPUT_TYPE_DTMF, args->buf, args->buflen);
|
|
|
|
} else {
|
|
|
|
switch_copy_string((char *) args->buf, (void *) &dtmf, args->buflen);
|
|
|
|
status = SWITCH_STATUS_BREAK;
|
|
|
|
}
|
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2008-07-08 17:27:02 +00:00
|
|
|
if (args->input_callback) {
|
|
|
|
switch_event_t *event = NULL;
|
|
|
|
|
2009-02-21 23:19:58 +00:00
|
|
|
if (switch_core_session_dequeue_event(session, &event, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
|
2008-07-08 17:27:02 +00:00
|
|
|
status = args->input_callback(session, event, SWITCH_INPUT_TYPE_EVENT, args->buf, args->buflen);
|
|
|
|
switch_event_destroy(&event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (status != SWITCH_STATUS_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-07-13 13:20:20 +00:00
|
|
|
|
2009-01-06 22:39:48 +00:00
|
|
|
status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
|
|
|
|
|
|
|
|
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
|
|
|
break;
|
2006-07-13 13:20:20 +00:00
|
|
|
}
|
2008-10-03 18:14:11 +00:00
|
|
|
|
2010-10-11 23:38:30 +00:00
|
|
|
if (args && args->dmachine) {
|
|
|
|
if ((status = switch_ivr_dmachine_ping(args->dmachine, NULL)) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-06 23:26:49 +00:00
|
|
|
if (sval && write_frame.datalen) {
|
2008-12-09 00:32:51 +00:00
|
|
|
switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.samples, sval);
|
|
|
|
switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0);
|
|
|
|
} else {
|
|
|
|
switch_core_session_write_frame(session, &cng_frame, SWITCH_IO_FLAG_NONE, 0);
|
|
|
|
}
|
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2008-12-09 00:32:51 +00:00
|
|
|
if (write_frame.codec) {
|
|
|
|
switch_core_codec_destroy(&codec);
|
2006-07-13 13:20:20 +00:00
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2008-12-09 00:32:51 +00:00
|
|
|
switch_safe_free(abuf);
|
|
|
|
|
2006-07-13 13:20:20 +00:00
|
|
|
return status;
|
|
|
|
}
|
2006-01-26 18:00:27 +00:00
|
|
|
|
2007-04-09 18:38:47 +00:00
|
|
|
static void *SWITCH_THREAD_FUNC unicast_thread_run(switch_thread_t *thread, void *obj)
|
|
|
|
{
|
|
|
|
switch_unicast_conninfo_t *conninfo = (switch_unicast_conninfo_t *) obj;
|
2007-04-10 21:18:33 +00:00
|
|
|
switch_size_t len;
|
2007-04-09 18:38:47 +00:00
|
|
|
switch_channel_t *channel;
|
|
|
|
|
|
|
|
if (!conninfo) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
channel = switch_core_session_get_channel(conninfo->session);
|
2008-05-27 04:30:03 +00:00
|
|
|
|
|
|
|
while (switch_test_flag(conninfo, SUF_READY) && switch_test_flag(conninfo, SUF_THREAD_RUNNING)) {
|
2007-04-09 18:38:47 +00:00
|
|
|
len = conninfo->write_frame.buflen;
|
|
|
|
if (switch_socket_recv(conninfo->socket, conninfo->write_frame.data, &len) != SWITCH_STATUS_SUCCESS || len == 0) {
|
|
|
|
break;
|
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
conninfo->write_frame.datalen = (uint32_t) len;
|
2007-04-09 18:38:47 +00:00
|
|
|
conninfo->write_frame.samples = conninfo->write_frame.datalen / 2;
|
2008-05-08 19:19:47 +00:00
|
|
|
switch_core_session_write_frame(conninfo->session, &conninfo->write_frame, SWITCH_IO_FLAG_NONE, conninfo->stream_id);
|
2007-04-09 18:38:47 +00:00
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-04-09 18:38:47 +00:00
|
|
|
switch_clear_flag_locked(conninfo, SUF_READY);
|
|
|
|
switch_clear_flag_locked(conninfo, SUF_THREAD_RUNNING);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void unicast_thread_launch(switch_unicast_conninfo_t *conninfo)
|
|
|
|
{
|
|
|
|
switch_thread_t *thread;
|
|
|
|
switch_threadattr_t *thd_attr = NULL;
|
|
|
|
|
|
|
|
switch_threadattr_create(&thd_attr, switch_core_session_get_pool(conninfo->session));
|
|
|
|
switch_threadattr_detach_set(thd_attr, 1);
|
|
|
|
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
|
|
|
|
switch_set_flag_locked(conninfo, SUF_THREAD_RUNNING);
|
|
|
|
switch_thread_create(&thread, thd_attr, unicast_thread_run, conninfo, switch_core_session_get_pool(conninfo->session));
|
|
|
|
}
|
|
|
|
|
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_deactivate_unicast(switch_core_session_t *session)
|
|
|
|
{
|
2008-01-28 07:26:10 +00:00
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
2007-04-09 18:38:47 +00:00
|
|
|
switch_unicast_conninfo_t *conninfo;
|
|
|
|
int sanity = 0;
|
|
|
|
|
2007-12-11 04:21:54 +00:00
|
|
|
if (!switch_channel_test_flag(channel, CF_UNICAST)) {
|
2008-05-27 04:30:03 +00:00
|
|
|
return SWITCH_STATUS_FALSE;
|
2007-12-11 04:21:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((conninfo = switch_channel_get_private(channel, "unicast"))) {
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Shutting down unicast connection\n");
|
2007-12-11 04:21:54 +00:00
|
|
|
switch_clear_flag_locked(conninfo, SUF_READY);
|
|
|
|
switch_socket_shutdown(conninfo->socket, SWITCH_SHUTDOWN_READWRITE);
|
2008-05-27 04:30:03 +00:00
|
|
|
while (switch_test_flag(conninfo, SUF_THREAD_RUNNING)) {
|
2007-12-11 04:21:54 +00:00
|
|
|
switch_yield(10000);
|
|
|
|
if (++sanity >= 10000) {
|
|
|
|
break;
|
2007-04-13 16:24:02 +00:00
|
|
|
}
|
2007-04-09 18:38:47 +00:00
|
|
|
}
|
2009-04-09 17:17:12 +00:00
|
|
|
if (switch_core_codec_ready(&conninfo->read_codec)) {
|
2007-12-11 04:21:54 +00:00
|
|
|
switch_core_codec_destroy(&conninfo->read_codec);
|
|
|
|
}
|
|
|
|
switch_socket_close(conninfo->socket);
|
2007-04-09 18:38:47 +00:00
|
|
|
}
|
2007-12-11 04:21:54 +00:00
|
|
|
switch_channel_clear_flag(channel, CF_UNICAST);
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
2007-04-09 18:38:47 +00:00
|
|
|
}
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_activate_unicast(switch_core_session_t *session,
|
2007-04-09 18:38:47 +00:00
|
|
|
char *local_ip,
|
2007-04-10 17:34:53 +00:00
|
|
|
switch_port_t local_port,
|
2008-05-27 04:30:03 +00:00
|
|
|
char *remote_ip, switch_port_t remote_port, char *transport, char *flags)
|
2007-04-09 18:38:47 +00:00
|
|
|
{
|
2008-01-28 07:26:10 +00:00
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
|
|
|
switch_unicast_conninfo_t *conninfo = switch_core_session_alloc(session, sizeof(*conninfo));
|
2007-04-09 18:38:47 +00:00
|
|
|
switch_codec_t *read_codec;
|
|
|
|
|
2007-12-11 19:23:57 +00:00
|
|
|
switch_assert(conninfo != NULL);
|
2007-04-09 18:38:47 +00:00
|
|
|
|
|
|
|
conninfo->local_ip = switch_core_session_strdup(session, local_ip);
|
|
|
|
conninfo->local_port = local_port;
|
|
|
|
|
|
|
|
conninfo->remote_ip = switch_core_session_strdup(session, remote_ip);
|
|
|
|
conninfo->remote_port = remote_port;
|
|
|
|
conninfo->session = session;
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-04-09 18:38:47 +00:00
|
|
|
if (!strcasecmp(transport, "udp")) {
|
|
|
|
conninfo->type = AF_INET;
|
|
|
|
conninfo->transport = SOCK_DGRAM;
|
|
|
|
} else if (!strcasecmp(transport, "tcp")) {
|
|
|
|
conninfo->type = AF_INET;
|
|
|
|
conninfo->transport = SOCK_STREAM;
|
|
|
|
} else {
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid transport %s\n", transport);
|
2007-04-09 18:38:47 +00:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2007-04-13 16:24:02 +00:00
|
|
|
if (flags) {
|
|
|
|
if (strstr(flags, "native")) {
|
|
|
|
switch_set_flag(conninfo, SUF_NATIVE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-09 18:38:47 +00:00
|
|
|
switch_mutex_init(&conninfo->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-04-09 18:38:47 +00:00
|
|
|
read_codec = switch_core_session_get_read_codec(session);
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-04-13 16:24:02 +00:00
|
|
|
if (!switch_test_flag(conninfo, SUF_NATIVE)) {
|
|
|
|
if (switch_core_codec_init(&conninfo->read_codec,
|
|
|
|
"L16",
|
|
|
|
NULL,
|
2007-10-19 15:31:02 +00:00
|
|
|
read_codec->implementation->actual_samples_per_second,
|
2008-10-20 17:48:42 +00:00
|
|
|
read_codec->implementation->microseconds_per_packet / 1000,
|
2007-04-13 16:24:02 +00:00
|
|
|
1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
|
|
|
|
NULL, switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) {
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
|
2007-04-13 16:24:02 +00:00
|
|
|
"Raw Codec Activation Success L16@%uhz 1 channel %dms\n",
|
2008-10-20 17:48:42 +00:00
|
|
|
read_codec->implementation->actual_samples_per_second, read_codec->implementation->microseconds_per_packet / 1000);
|
2007-04-13 16:24:02 +00:00
|
|
|
} else {
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Raw Codec Activation Failed L16@%uhz 1 channel %dms\n",
|
2008-10-20 17:48:42 +00:00
|
|
|
read_codec->implementation->actual_samples_per_second, read_codec->implementation->microseconds_per_packet / 1000);
|
2007-04-13 16:24:02 +00:00
|
|
|
goto fail;
|
|
|
|
}
|
2007-04-09 18:38:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
conninfo->write_frame.data = conninfo->write_frame_data;
|
|
|
|
conninfo->write_frame.buflen = sizeof(conninfo->write_frame_data);
|
2007-04-13 16:24:02 +00:00
|
|
|
conninfo->write_frame.codec = switch_test_flag(conninfo, SUF_NATIVE) ? read_codec : &conninfo->read_codec;
|
2007-04-09 18:38:47 +00:00
|
|
|
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "connect %s:%d->%s:%d\n",
|
2007-04-09 18:38:47 +00:00
|
|
|
conninfo->local_ip, conninfo->local_port, conninfo->remote_ip, conninfo->remote_port);
|
|
|
|
|
|
|
|
if (switch_sockaddr_info_get(&conninfo->local_addr,
|
2008-05-27 04:30:03 +00:00
|
|
|
conninfo->local_ip, SWITCH_UNSPEC, conninfo->local_port, 0,
|
2007-04-09 18:38:47 +00:00
|
|
|
switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
|
|
|
if (switch_sockaddr_info_get(&conninfo->remote_addr,
|
2007-04-09 18:38:47 +00:00
|
|
|
conninfo->remote_ip, SWITCH_UNSPEC, conninfo->remote_port, 0,
|
|
|
|
switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-04-09 18:38:47 +00:00
|
|
|
if (switch_socket_create(&conninfo->socket, AF_INET, SOCK_DGRAM, 0, switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) {
|
|
|
|
if (switch_socket_bind(conninfo->socket, conninfo->local_addr) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Created unicast connection %s:%d->%s:%d\n",
|
2007-04-09 18:38:47 +00:00
|
|
|
conninfo->local_ip, conninfo->local_port, conninfo->remote_ip, conninfo->remote_port);
|
|
|
|
switch_channel_set_private(channel, "unicast", conninfo);
|
|
|
|
switch_channel_set_flag(channel, CF_UNICAST);
|
|
|
|
switch_set_flag_locked(conninfo, SUF_READY);
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
fail:
|
2007-04-09 18:38:47 +00:00
|
|
|
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failure creating unicast connection %s:%d->%s:%d\n",
|
2007-04-09 18:38:47 +00:00
|
|
|
conninfo->local_ip, conninfo->local_port, conninfo->remote_ip, conninfo->remote_port);
|
2008-05-27 04:30:03 +00:00
|
|
|
return SWITCH_STATUS_FALSE;
|
2007-04-09 18:38:47 +00:00
|
|
|
}
|
|
|
|
|
2007-01-06 17:06:18 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_event(switch_core_session_t *session, switch_event_t *event)
|
2006-09-07 03:58:01 +00:00
|
|
|
{
|
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
|
|
|
char *cmd = switch_event_get_header(event, "call-command");
|
|
|
|
unsigned long cmd_hash;
|
2007-09-29 01:06:08 +00:00
|
|
|
switch_ssize_t hlen = -1;
|
2007-03-09 20:44:13 +00:00
|
|
|
unsigned long CMD_EXECUTE = switch_hashfunc_default("execute", &hlen);
|
|
|
|
unsigned long CMD_HANGUP = switch_hashfunc_default("hangup", &hlen);
|
|
|
|
unsigned long CMD_NOMEDIA = switch_hashfunc_default("nomedia", &hlen);
|
2007-04-09 18:38:47 +00:00
|
|
|
unsigned long CMD_UNICAST = switch_hashfunc_default("unicast", &hlen);
|
2007-05-09 19:44:15 +00:00
|
|
|
char *lead_frames = switch_event_get_header(event, "lead-frames");
|
2007-06-25 21:25:33 +00:00
|
|
|
char *event_lock = switch_event_get_header(event, "event-lock");
|
2009-12-10 01:29:02 +00:00
|
|
|
char *event_lock_pri = switch_event_get_header(event, "event-lock-pri");
|
2007-06-25 21:25:33 +00:00
|
|
|
switch_status_t status = SWITCH_STATUS_FALSE;
|
2009-12-10 21:53:23 +00:00
|
|
|
int el = 0, elp = 0;
|
2007-06-25 21:25:33 +00:00
|
|
|
|
2009-10-23 16:03:42 +00:00
|
|
|
if (zstr(cmd)) {
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid Command!\n");
|
2007-05-14 20:38:18 +00:00
|
|
|
return SWITCH_STATUS_FALSE;
|
2007-03-29 22:31:56 +00:00
|
|
|
}
|
2007-01-06 17:06:18 +00:00
|
|
|
|
2007-03-09 20:44:13 +00:00
|
|
|
cmd_hash = switch_hashfunc_default(cmd, &hlen);
|
2006-09-07 03:58:01 +00:00
|
|
|
|
2009-08-26 17:42:36 +00:00
|
|
|
switch_channel_set_flag_recursive(channel, CF_EVENT_PARSE);
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2007-06-25 21:25:33 +00:00
|
|
|
if (switch_true(event_lock)) {
|
2009-08-26 17:42:36 +00:00
|
|
|
switch_channel_set_flag_recursive(channel, CF_EVENT_LOCK);
|
2009-12-10 21:53:23 +00:00
|
|
|
el = 1;
|
2007-06-25 21:25:33 +00:00
|
|
|
}
|
|
|
|
|
2009-12-10 01:29:02 +00:00
|
|
|
if (switch_true(event_lock_pri)) {
|
|
|
|
switch_channel_set_flag_recursive(channel, CF_EVENT_LOCK_PRI);
|
2009-12-10 21:53:23 +00:00
|
|
|
elp = 1;
|
2009-12-10 01:29:02 +00:00
|
|
|
}
|
|
|
|
|
2007-05-09 19:44:15 +00:00
|
|
|
if (lead_frames) {
|
|
|
|
switch_frame_t *read_frame;
|
|
|
|
int frame_count = atoi(lead_frames);
|
2008-05-19 14:30:39 +00:00
|
|
|
int max_frames = frame_count * 2;
|
2008-05-27 04:30:03 +00:00
|
|
|
|
|
|
|
while (frame_count > 0 && --max_frames > 0) {
|
2008-05-08 19:19:47 +00:00
|
|
|
status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
|
2007-05-09 19:44:15 +00:00
|
|
|
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
2007-06-25 21:25:33 +00:00
|
|
|
goto done;
|
2007-05-09 19:44:15 +00:00
|
|
|
}
|
|
|
|
if (!switch_test_flag(read_frame, SFF_CNG)) {
|
|
|
|
frame_count--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
|
|
|
|
if (cmd_hash == CMD_EXECUTE) {
|
|
|
|
char *app_name = switch_event_get_header(event, "execute-app-name");
|
|
|
|
char *app_arg = switch_event_get_header(event, "execute-app-arg");
|
2009-12-15 18:45:29 +00:00
|
|
|
char *content_type = switch_event_get_header(event, "content-type");
|
2007-03-30 22:13:19 +00:00
|
|
|
char *loop_h = switch_event_get_header(event, "loops");
|
2008-03-12 00:11:33 +00:00
|
|
|
char *hold_bleg = switch_event_get_header(event, "hold-bleg");
|
2007-04-09 18:38:47 +00:00
|
|
|
int loops = 1;
|
2007-06-25 21:25:33 +00:00
|
|
|
|
2009-12-15 18:45:29 +00:00
|
|
|
if (zstr(app_arg) && !zstr(content_type) && !strcasecmp(content_type, "text/plain")) {
|
|
|
|
app_arg = switch_event_get_body(event);
|
|
|
|
}
|
|
|
|
|
2007-03-30 22:13:19 +00:00
|
|
|
if (loop_h) {
|
|
|
|
loops = atoi(loop_h);
|
|
|
|
}
|
2007-11-02 18:34:26 +00:00
|
|
|
|
2007-06-25 21:25:33 +00:00
|
|
|
if (app_name) {
|
2009-12-11 21:51:10 +00:00
|
|
|
int x;
|
|
|
|
const char *b_uuid = NULL;
|
|
|
|
switch_core_session_t *b_session = NULL;
|
|
|
|
|
|
|
|
switch_channel_clear_flag(channel, CF_STOP_BROADCAST);
|
|
|
|
switch_channel_set_flag(channel, CF_BROADCAST);
|
|
|
|
if (hold_bleg && switch_true(hold_bleg)) {
|
|
|
|
if ((b_uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))) {
|
|
|
|
const char *stream;
|
|
|
|
b_uuid = switch_core_session_strdup(session, b_uuid);
|
|
|
|
|
|
|
|
if (!(stream = switch_channel_get_variable_partner(channel, SWITCH_HOLD_MUSIC_VARIABLE))) {
|
|
|
|
stream = switch_channel_get_variable(channel, SWITCH_HOLD_MUSIC_VARIABLE);
|
2007-03-30 22:13:19 +00:00
|
|
|
}
|
2008-03-13 01:08:42 +00:00
|
|
|
|
2009-12-11 21:51:10 +00:00
|
|
|
if (stream && switch_is_moh(stream)) {
|
2008-03-12 00:11:33 +00:00
|
|
|
if ((b_session = switch_core_session_locate(b_uuid))) {
|
|
|
|
switch_channel_t *b_channel = switch_core_session_get_channel(b_session);
|
2009-12-11 21:51:10 +00:00
|
|
|
switch_ivr_broadcast(b_uuid, stream, SMF_ECHO_ALEG | SMF_LOOP);
|
|
|
|
switch_channel_wait_for_flag(b_channel, CF_BROADCAST, SWITCH_TRUE, 5000, NULL);
|
2008-03-12 00:11:33 +00:00
|
|
|
switch_core_session_rwunlock(b_session);
|
|
|
|
}
|
2009-12-11 21:51:10 +00:00
|
|
|
} else {
|
|
|
|
b_uuid = NULL;
|
2008-03-12 00:11:33 +00:00
|
|
|
}
|
2009-12-11 21:51:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (x = 0; x < loops || loops < 0; x++) {
|
|
|
|
switch_time_t b4, aftr;
|
2008-03-13 01:08:42 +00:00
|
|
|
|
2009-12-11 21:51:10 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Command Execute %s(%s)\n",
|
|
|
|
switch_channel_get_name(channel), app_name, switch_str_nil(app_arg));
|
|
|
|
b4 = switch_micro_time_now();
|
|
|
|
if (switch_core_session_execute_application(session, app_name, app_arg) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
aftr = switch_micro_time_now();
|
|
|
|
if (!switch_channel_ready(channel) || switch_channel_test_flag(channel, CF_STOP_BROADCAST) || aftr - b4 < 500000) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (b_uuid) {
|
|
|
|
if ((b_session = switch_core_session_locate(b_uuid))) {
|
|
|
|
switch_channel_t *b_channel = switch_core_session_get_channel(b_session);
|
|
|
|
switch_channel_stop_broadcast(b_channel);
|
|
|
|
switch_channel_wait_for_flag(b_channel, CF_BROADCAST, SWITCH_FALSE, 5000, NULL);
|
|
|
|
switch_core_session_rwunlock(b_session);
|
2007-03-29 22:31:56 +00:00
|
|
|
}
|
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2009-12-11 21:51:10 +00:00
|
|
|
switch_channel_clear_flag(channel, CF_BROADCAST);
|
2007-03-29 22:31:56 +00:00
|
|
|
}
|
2007-04-09 18:38:47 +00:00
|
|
|
} else if (cmd_hash == CMD_UNICAST) {
|
2007-10-31 21:44:49 +00:00
|
|
|
char *local_ip = switch_event_get_header(event, "local-ip");
|
|
|
|
char *local_port = switch_event_get_header(event, "local-port");
|
|
|
|
char *remote_ip = switch_event_get_header(event, "remote-ip");
|
|
|
|
char *remote_port = switch_event_get_header(event, "remote-port");
|
2007-04-09 18:38:47 +00:00
|
|
|
char *transport = switch_event_get_header(event, "transport");
|
2007-04-13 16:24:02 +00:00
|
|
|
char *flags = switch_event_get_header(event, "flags");
|
2007-04-09 18:38:47 +00:00
|
|
|
|
2009-10-23 16:03:42 +00:00
|
|
|
if (zstr(local_ip)) {
|
2007-04-09 18:38:47 +00:00
|
|
|
local_ip = "127.0.0.1";
|
|
|
|
}
|
2009-10-23 16:03:42 +00:00
|
|
|
if (zstr(remote_ip)) {
|
2007-04-09 18:38:47 +00:00
|
|
|
remote_ip = "127.0.0.1";
|
|
|
|
}
|
2009-10-23 16:03:42 +00:00
|
|
|
if (zstr(local_port)) {
|
2007-04-09 18:38:47 +00:00
|
|
|
local_port = "8025";
|
|
|
|
}
|
2009-10-23 16:03:42 +00:00
|
|
|
if (zstr(remote_port)) {
|
2007-04-09 18:38:47 +00:00
|
|
|
remote_port = "8026";
|
|
|
|
}
|
2009-10-23 16:03:42 +00:00
|
|
|
if (zstr(transport)) {
|
2007-04-09 18:38:47 +00:00
|
|
|
transport = "udp";
|
|
|
|
}
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
switch_ivr_activate_unicast(session, local_ip, (switch_port_t) atoi(local_port), remote_ip, (switch_port_t) atoi(remote_port), transport, flags);
|
2007-04-09 18:38:47 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
} else if (cmd_hash == CMD_HANGUP) {
|
|
|
|
char *cause_name = switch_event_get_header(event, "hangup-cause");
|
|
|
|
switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
|
|
|
|
|
|
|
|
if (cause_name) {
|
|
|
|
cause = switch_channel_str2cause(cause_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch_channel_hangup(channel, cause);
|
|
|
|
} else if (cmd_hash == CMD_NOMEDIA) {
|
|
|
|
char *uuid = switch_event_get_header(event, "nomedia-uuid");
|
|
|
|
switch_ivr_nomedia(uuid, SMF_REBRIDGE);
|
|
|
|
}
|
|
|
|
|
2007-06-25 21:25:33 +00:00
|
|
|
status = SWITCH_STATUS_SUCCESS;
|
2007-05-14 20:38:18 +00:00
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
done:
|
2009-12-10 21:53:23 +00:00
|
|
|
|
2009-08-26 17:42:36 +00:00
|
|
|
switch_channel_clear_flag_recursive(channel, CF_EVENT_PARSE);
|
2009-12-10 21:53:23 +00:00
|
|
|
|
|
|
|
if (el) {
|
|
|
|
switch_channel_clear_flag_recursive(channel, CF_EVENT_LOCK);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (elp) {
|
|
|
|
switch_channel_clear_flag_recursive(channel, CF_EVENT_LOCK_PRI);
|
|
|
|
}
|
2007-06-25 21:25:33 +00:00
|
|
|
|
2010-03-23 15:27:13 +00:00
|
|
|
return switch_channel_test_flag(channel, CF_BREAK) ? SWITCH_STATUS_BREAK : status;
|
2006-09-07 03:58:01 +00:00
|
|
|
}
|
|
|
|
|
2008-03-25 00:24:23 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_next_event(switch_core_session_t *session)
|
2007-05-14 23:50:38 +00:00
|
|
|
{
|
|
|
|
switch_event_t *event;
|
2010-03-23 15:27:13 +00:00
|
|
|
switch_status_t status = SWITCH_STATUS_FALSE;
|
2007-05-14 23:50:38 +00:00
|
|
|
|
2008-03-25 00:24:23 +00:00
|
|
|
if (switch_core_session_dequeue_private_event(session, &event) == SWITCH_STATUS_SUCCESS) {
|
2010-03-23 15:27:13 +00:00
|
|
|
status = switch_ivr_parse_event(session, event);
|
2007-05-14 23:50:38 +00:00
|
|
|
switch_event_fire(&event);
|
|
|
|
}
|
|
|
|
|
2010-03-23 15:27:13 +00:00
|
|
|
return status;
|
2008-03-25 00:24:23 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-10-12 22:23:55 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_all_messages(switch_core_session_t *session)
|
|
|
|
{
|
|
|
|
switch_core_session_message_t *message;
|
2010-11-15 17:22:25 +00:00
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
2009-10-12 22:23:55 +00:00
|
|
|
int i = 0;
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2009-10-12 22:23:55 +00:00
|
|
|
while (switch_core_session_dequeue_message(session, &message) == SWITCH_STATUS_SUCCESS) {
|
|
|
|
i++;
|
2010-11-15 17:22:25 +00:00
|
|
|
|
|
|
|
switch(message->message_id) {
|
|
|
|
case SWITCH_MESSAGE_INDICATE_ANSWER:
|
|
|
|
if (switch_channel_answer(channel) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
|
|
|
|
}
|
|
|
|
switch_core_session_free_message(&message);
|
|
|
|
break;
|
|
|
|
case SWITCH_MESSAGE_INDICATE_PROGRESS:
|
|
|
|
if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
|
|
|
|
}
|
|
|
|
switch_core_session_free_message(&message);
|
|
|
|
break;
|
|
|
|
case SWITCH_MESSAGE_INDICATE_RINGING:
|
|
|
|
if (switch_channel_ring_ready(channel) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
|
|
|
|
}
|
|
|
|
switch_core_session_free_message(&message);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
switch_core_session_receive_message(session, message);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-10-12 22:23:55 +00:00
|
|
|
message = NULL;
|
2010-11-15 17:22:25 +00:00
|
|
|
|
2009-10-12 22:23:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return i ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
|
|
|
|
}
|
|
|
|
|
2008-03-25 00:24:23 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_all_events(switch_core_session_t *session)
|
|
|
|
{
|
2009-10-12 23:27:01 +00:00
|
|
|
int x = 0;
|
2008-03-25 00:24:23 +00:00
|
|
|
|
2009-10-12 22:23:55 +00:00
|
|
|
|
|
|
|
switch_ivr_parse_all_messages(session);
|
2009-10-12 23:27:01 +00:00
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
while (switch_ivr_parse_next_event(session) == SWITCH_STATUS_SUCCESS)
|
|
|
|
x++;
|
2009-10-12 23:27:01 +00:00
|
|
|
|
|
|
|
if (x) {
|
|
|
|
switch_ivr_sleep(session, 0, SWITCH_TRUE, NULL);
|
|
|
|
}
|
2008-12-17 21:50:34 +00:00
|
|
|
|
2007-05-14 23:50:38 +00:00
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-02-16 21:32:49 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session, switch_input_args_t *args)
|
2006-09-07 03:58:01 +00:00
|
|
|
{
|
|
|
|
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
2008-01-28 07:26:10 +00:00
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
2009-05-14 13:48:11 +00:00
|
|
|
switch_frame_t *read_frame = NULL;
|
2006-11-30 21:28:32 +00:00
|
|
|
int stream_id = 0;
|
2006-09-07 03:58:01 +00:00
|
|
|
switch_event_t *event;
|
2007-04-09 18:38:47 +00:00
|
|
|
switch_unicast_conninfo_t *conninfo = NULL;
|
2009-05-13 16:34:39 +00:00
|
|
|
uint32_t rate = 0;
|
|
|
|
uint32_t bpf = 0;
|
2008-11-13 23:25:38 +00:00
|
|
|
const char *to;
|
|
|
|
int timeout = 0;
|
|
|
|
time_t expires = 0;
|
2010-02-06 03:38:24 +00:00
|
|
|
switch_codec_implementation_t read_impl = { 0 };
|
2010-03-02 17:45:19 +00:00
|
|
|
switch_call_cause_t timeout_cause = SWITCH_CAUSE_NORMAL_CLEARING;
|
2010-11-11 16:54:04 +00:00
|
|
|
switch_codec_t codec = { 0 };
|
|
|
|
int sval = 0;
|
|
|
|
const char *var;
|
|
|
|
switch_frame_t write_frame = { 0 };
|
|
|
|
unsigned char *abuf = NULL;
|
|
|
|
switch_codec_implementation_t imp = { 0 };
|
|
|
|
|
|
|
|
if ((var = switch_channel_get_variable(channel, SWITCH_SEND_SILENCE_WHEN_IDLE_VARIABLE)) && (sval = atoi(var))) {
|
|
|
|
switch_core_session_get_read_impl(session, &imp);
|
|
|
|
|
|
|
|
if (switch_core_codec_init(&codec,
|
|
|
|
"L16",
|
|
|
|
NULL,
|
|
|
|
imp.samples_per_second,
|
|
|
|
imp.microseconds_per_packet / 1000,
|
|
|
|
imp.number_of_channels,
|
|
|
|
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,
|
|
|
|
switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec Error L16@%uhz %u channels %dms\n",
|
|
|
|
imp.samples_per_second, imp.number_of_channels, imp.microseconds_per_packet / 1000);
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2009-05-13 16:34:39 +00:00
|
|
|
|
2010-11-11 16:54:04 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Codec Activated L16@%uhz %u channels %dms\n",
|
|
|
|
imp.samples_per_second, imp.number_of_channels, imp.microseconds_per_packet / 1000);
|
|
|
|
|
|
|
|
write_frame.codec = &codec;
|
|
|
|
switch_zmalloc(abuf, SWITCH_RECOMMENDED_BUFFER_SIZE);
|
|
|
|
write_frame.data = abuf;
|
|
|
|
write_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE;
|
|
|
|
write_frame.datalen = imp.decoded_bytes_per_packet;
|
|
|
|
write_frame.samples = write_frame.datalen / sizeof(int16_t);
|
|
|
|
}
|
|
|
|
|
2010-11-24 00:03:56 +00:00
|
|
|
if (switch_channel_test_flag(channel, CF_RECOVERED) && switch_channel_test_flag(channel, CF_CONTROLLED)) {
|
|
|
|
switch_channel_clear_flag(channel, CF_CONTROLLED);
|
|
|
|
}
|
|
|
|
|
2008-04-14 14:05:22 +00:00
|
|
|
if (switch_channel_test_flag(channel, CF_CONTROLLED)) {
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot park channels that are under control already.\n");
|
2008-04-14 14:05:22 +00:00
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
|
|
|
|
2010-07-02 16:54:20 +00:00
|
|
|
if (switch_channel_get_state(channel) == CS_RESET) {
|
2008-09-19 19:58:01 +00:00
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2008-11-13 23:25:38 +00:00
|
|
|
if ((to = switch_channel_get_variable(channel, "park_timeout"))) {
|
2010-03-02 17:45:19 +00:00
|
|
|
char *cause_str;
|
|
|
|
|
2010-03-02 17:50:56 +00:00
|
|
|
if ((cause_str = strchr(to, ':'))) {
|
2010-03-02 17:45:19 +00:00
|
|
|
timeout_cause = switch_channel_str2cause(cause_str + 1);
|
|
|
|
}
|
|
|
|
|
2008-11-13 23:25:38 +00:00
|
|
|
if ((timeout = atoi(to)) < 0) {
|
|
|
|
timeout = 0;
|
|
|
|
} else {
|
2009-01-25 21:23:07 +00:00
|
|
|
expires = switch_epoch_time_now(NULL) + timeout;
|
2008-11-13 23:25:38 +00:00
|
|
|
}
|
2009-04-30 22:45:46 +00:00
|
|
|
switch_channel_set_variable(channel, "park_timeout", NULL);
|
2009-10-07 04:30:19 +00:00
|
|
|
switch_channel_set_variable(channel, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, NULL);
|
2008-11-13 23:25:38 +00:00
|
|
|
}
|
|
|
|
|
2007-10-31 23:19:30 +00:00
|
|
|
switch_channel_set_flag(channel, CF_CONTROLLED);
|
2009-04-30 22:45:46 +00:00
|
|
|
switch_channel_set_flag(channel, CF_PARK);
|
|
|
|
|
2006-09-07 03:58:01 +00:00
|
|
|
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_PARK) == SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_channel_event_set_data(channel, event);
|
|
|
|
switch_event_fire(&event);
|
|
|
|
}
|
|
|
|
|
2009-05-13 16:34:39 +00:00
|
|
|
while (switch_channel_ready(channel) && switch_channel_test_flag(channel, CF_CONTROLLED) && switch_channel_test_flag(channel, CF_PARK)) {
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2009-05-13 16:34:39 +00:00
|
|
|
if (!rate && switch_channel_media_ready(channel)) {
|
|
|
|
switch_core_session_get_read_impl(session, &read_impl);
|
|
|
|
rate = read_impl.actual_samples_per_second;
|
|
|
|
bpf = read_impl.decoded_bytes_per_packet;
|
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2009-05-13 16:34:39 +00:00
|
|
|
if (rate) {
|
2010-11-11 16:54:04 +00:00
|
|
|
if (switch_channel_test_flag(channel, CF_SERVICE)) {
|
|
|
|
switch_cond_next();
|
|
|
|
status = SWITCH_STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, stream_id);
|
|
|
|
}
|
2009-05-13 16:34:39 +00:00
|
|
|
} else {
|
|
|
|
switch_yield(20000);
|
2010-07-02 16:54:20 +00:00
|
|
|
|
|
|
|
if (switch_core_session_dequeue_private_event(session, &event) == SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_ivr_parse_event(session, event);
|
|
|
|
switch_event_destroy(&event);
|
|
|
|
}
|
|
|
|
|
2009-05-13 16:34:39 +00:00
|
|
|
status = SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2009-05-13 16:34:39 +00:00
|
|
|
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
|
|
|
break;
|
2010-11-11 16:54:04 +00:00
|
|
|
}
|
2008-11-13 23:25:38 +00:00
|
|
|
|
2010-11-11 16:54:04 +00:00
|
|
|
if (write_frame.data) {
|
|
|
|
switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.samples, sval);
|
|
|
|
switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (expires && switch_epoch_time_now(NULL) >= expires) {
|
|
|
|
switch_channel_hangup(channel, timeout_cause);
|
|
|
|
break;
|
|
|
|
}
|
2009-05-13 16:34:39 +00:00
|
|
|
|
2010-11-11 16:54:04 +00:00
|
|
|
if (switch_channel_test_flag(channel, CF_UNICAST)) {
|
|
|
|
if (!switch_channel_media_ready(channel)) {
|
|
|
|
if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2010-11-11 16:54:04 +00:00
|
|
|
if (!conninfo) {
|
|
|
|
if (!(conninfo = switch_channel_get_private(channel, "unicast"))) {
|
|
|
|
switch_channel_clear_flag(channel, CF_UNICAST);
|
2007-04-09 18:38:47 +00:00
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-04-09 18:38:47 +00:00
|
|
|
if (conninfo) {
|
2010-11-11 16:54:04 +00:00
|
|
|
unicast_thread_launch(conninfo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conninfo) {
|
|
|
|
switch_size_t len = 0;
|
|
|
|
uint32_t flags = 0;
|
|
|
|
switch_byte_t decoded[SWITCH_RECOMMENDED_BUFFER_SIZE];
|
|
|
|
uint32_t dlen = sizeof(decoded);
|
|
|
|
switch_status_t tstatus;
|
|
|
|
switch_byte_t *sendbuf = NULL;
|
|
|
|
uint32_t sendlen = 0;
|
|
|
|
|
|
|
|
switch_assert(read_frame);
|
|
|
|
|
|
|
|
if (switch_test_flag(read_frame, SFF_CNG)) {
|
|
|
|
sendlen = bpf;
|
|
|
|
switch_assert(sendlen <= SWITCH_RECOMMENDED_BUFFER_SIZE);
|
|
|
|
memset(decoded, 255, sendlen);
|
|
|
|
sendbuf = decoded;
|
|
|
|
tstatus = SWITCH_STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
if (switch_test_flag(conninfo, SUF_NATIVE)) {
|
|
|
|
tstatus = SWITCH_STATUS_NOOP;
|
|
|
|
} else {
|
|
|
|
switch_codec_t *read_codec = switch_core_session_get_read_codec(session);
|
|
|
|
tstatus = switch_core_codec_decode(read_codec,
|
|
|
|
&conninfo->read_codec,
|
|
|
|
read_frame->data,
|
|
|
|
read_frame->datalen, read_impl.actual_samples_per_second, decoded, &dlen, &rate, &flags);
|
|
|
|
}
|
|
|
|
switch (tstatus) {
|
|
|
|
case SWITCH_STATUS_NOOP:
|
|
|
|
case SWITCH_STATUS_BREAK:
|
|
|
|
sendbuf = read_frame->data;
|
|
|
|
sendlen = read_frame->datalen;
|
|
|
|
tstatus = SWITCH_STATUS_SUCCESS;
|
|
|
|
break;
|
|
|
|
case SWITCH_STATUS_SUCCESS:
|
2007-04-09 18:38:47 +00:00
|
|
|
sendbuf = decoded;
|
2010-11-11 16:54:04 +00:00
|
|
|
sendlen = dlen;
|
2007-12-18 18:31:38 +00:00
|
|
|
tstatus = SWITCH_STATUS_SUCCESS;
|
2010-11-11 16:54:04 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Codec Error\n");
|
|
|
|
switch_ivr_deactivate_unicast(session);
|
|
|
|
break;
|
2007-04-09 18:38:47 +00:00
|
|
|
}
|
2010-11-11 16:54:04 +00:00
|
|
|
}
|
2007-04-09 18:38:47 +00:00
|
|
|
|
2010-11-11 16:54:04 +00:00
|
|
|
if (tstatus == SWITCH_STATUS_SUCCESS) {
|
|
|
|
len = sendlen;
|
|
|
|
if (switch_socket_sendto(conninfo->socket, conninfo->remote_addr, 0, (void *) sendbuf, &len) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_ivr_deactivate_unicast(session);
|
2007-04-09 18:38:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-11-11 16:54:04 +00:00
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2010-11-11 16:54:04 +00:00
|
|
|
switch_ivr_parse_all_events(session);
|
2009-10-12 22:23:55 +00:00
|
|
|
|
2007-01-06 17:06:18 +00:00
|
|
|
|
2010-11-18 22:14:08 +00:00
|
|
|
if (switch_channel_has_dtmf(channel)) {
|
2010-11-11 16:54:04 +00:00
|
|
|
switch_dtmf_t dtmf = { 0 };
|
|
|
|
|
2010-11-18 15:00:24 +00:00
|
|
|
if (args && !args->input_callback && !args->buf && !args->dmachine) {
|
2010-11-11 16:54:04 +00:00
|
|
|
status = SWITCH_STATUS_BREAK;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch_channel_dequeue_dtmf(channel, &dtmf);
|
|
|
|
|
2010-11-18 22:14:08 +00:00
|
|
|
if (args) {
|
|
|
|
if (args->dmachine) {
|
|
|
|
char ds[2] = {dtmf.digit, '\0'};
|
|
|
|
if ((status = switch_ivr_dmachine_feed(args->dmachine, ds, NULL)) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (args->input_callback) {
|
|
|
|
if ((status = args->input_callback(session, (void *) &dtmf, SWITCH_INPUT_TYPE_DTMF, args->buf, args->buflen)) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
2007-02-16 21:32:49 +00:00
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
}
|
2010-11-11 16:54:04 +00:00
|
|
|
}
|
2007-01-06 17:06:18 +00:00
|
|
|
|
2010-11-11 16:54:04 +00:00
|
|
|
if (switch_core_session_dequeue_event(session, &event, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
|
|
|
|
if (args && args->input_callback) {
|
|
|
|
if ((status = args->input_callback(session, event, SWITCH_INPUT_TYPE_EVENT, args->buf, args->buflen)) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
break;
|
2007-02-16 21:32:49 +00:00
|
|
|
}
|
2010-11-11 16:54:04 +00:00
|
|
|
} else {
|
|
|
|
switch_channel_event_set_data(channel, event);
|
|
|
|
switch_event_fire(&event);
|
2007-03-29 22:31:56 +00:00
|
|
|
}
|
|
|
|
}
|
2010-11-11 16:54:04 +00:00
|
|
|
|
|
|
|
if (args && args->dmachine) {
|
|
|
|
if ((status = switch_ivr_dmachine_ping(args->dmachine, NULL)) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2006-09-07 03:58:01 +00:00
|
|
|
}
|
2008-05-24 02:39:23 +00:00
|
|
|
|
2010-11-11 16:54:04 +00:00
|
|
|
if (write_frame.codec) {
|
|
|
|
switch_core_codec_destroy(&codec);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch_safe_free(abuf);
|
|
|
|
|
2006-09-07 03:58:01 +00:00
|
|
|
switch_channel_clear_flag(channel, CF_CONTROLLED);
|
2009-04-30 22:45:46 +00:00
|
|
|
switch_channel_clear_flag(channel, CF_PARK);
|
2006-09-07 03:58:01 +00:00
|
|
|
|
|
|
|
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_UNPARK) == SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_channel_event_set_data(channel, event);
|
|
|
|
switch_event_fire(&event);
|
|
|
|
}
|
|
|
|
|
2007-04-09 18:38:47 +00:00
|
|
|
if (switch_channel_test_flag(channel, CF_UNICAST)) {
|
|
|
|
switch_ivr_deactivate_unicast(session);
|
|
|
|
}
|
|
|
|
|
2006-09-07 03:58:01 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_collect_digits_callback(switch_core_session_t *session, switch_input_args_t *args, uint32_t digit_timeout,
|
|
|
|
uint32_t abs_timeout)
|
2006-01-27 21:33:45 +00:00
|
|
|
{
|
2008-01-28 07:26:10 +00:00
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
2006-04-29 23:43:28 +00:00
|
|
|
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
2009-09-25 19:07:20 +00:00
|
|
|
switch_time_t abs_started = 0, digit_started = 0;
|
|
|
|
uint32_t abs_elapsed = 0, digit_elapsed = 0;
|
2006-11-09 05:39:04 +00:00
|
|
|
|
2010-09-23 18:31:53 +00:00
|
|
|
if (!args) {
|
2006-01-27 21:33:45 +00:00
|
|
|
return SWITCH_STATUS_GENERR;
|
|
|
|
}
|
|
|
|
|
2009-09-25 19:07:20 +00:00
|
|
|
if (abs_timeout) {
|
|
|
|
abs_started = switch_micro_time_now();
|
|
|
|
}
|
|
|
|
if (digit_timeout) {
|
|
|
|
digit_started = switch_micro_time_now();
|
2006-11-09 05:39:04 +00:00
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
while (switch_channel_ready(channel)) {
|
2008-04-04 21:43:20 +00:00
|
|
|
switch_frame_t *read_frame = NULL;
|
2006-07-12 18:39:19 +00:00
|
|
|
switch_event_t *event;
|
2008-05-27 04:30:03 +00:00
|
|
|
switch_dtmf_t dtmf = { 0 };
|
2006-01-27 21:33:45 +00:00
|
|
|
|
2008-04-03 21:27:16 +00:00
|
|
|
if (switch_channel_test_flag(channel, CF_BREAK)) {
|
|
|
|
switch_channel_clear_flag(channel, CF_BREAK);
|
|
|
|
status = SWITCH_STATUS_BREAK;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-09-25 19:07:20 +00:00
|
|
|
if (abs_timeout) {
|
|
|
|
abs_elapsed = (uint32_t) ((switch_micro_time_now() - abs_started) / 1000);
|
|
|
|
if (abs_elapsed >= abs_timeout) {
|
|
|
|
status = SWITCH_STATUS_TIMEOUT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (digit_timeout) {
|
|
|
|
digit_elapsed = (uint32_t) ((switch_micro_time_now() - digit_started) / 1000);
|
|
|
|
if (digit_elapsed >= digit_timeout) {
|
|
|
|
status = SWITCH_STATUS_TIMEOUT;
|
2006-11-09 05:39:04 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-09-07 03:58:01 +00:00
|
|
|
|
2009-10-12 22:23:55 +00:00
|
|
|
|
|
|
|
switch_ivr_parse_all_events(session);
|
|
|
|
|
2006-09-07 03:58:01 +00:00
|
|
|
|
2006-01-27 21:33:45 +00:00
|
|
|
if (switch_channel_has_dtmf(channel)) {
|
2010-10-11 23:38:30 +00:00
|
|
|
if (!args->input_callback && !args->buf && !args->dmachine) {
|
2010-09-23 18:31:53 +00:00
|
|
|
status = SWITCH_STATUS_BREAK;
|
|
|
|
break;
|
|
|
|
}
|
2007-12-22 00:32:20 +00:00
|
|
|
switch_channel_dequeue_dtmf(channel, &dtmf);
|
2010-10-11 23:38:30 +00:00
|
|
|
|
|
|
|
if (args->dmachine) {
|
|
|
|
char ds[2] = {dtmf.digit, '\0'};
|
|
|
|
if ((status = switch_ivr_dmachine_feed(args->dmachine, ds, NULL)) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (args->input_callback) {
|
|
|
|
status = args->input_callback(session, (void *) &dtmf, SWITCH_INPUT_TYPE_DTMF, args->buf, args->buflen);
|
|
|
|
}
|
|
|
|
|
2009-09-25 19:07:20 +00:00
|
|
|
if (digit_timeout) {
|
|
|
|
digit_started = switch_micro_time_now();
|
|
|
|
}
|
2006-07-12 18:39:19 +00:00
|
|
|
}
|
|
|
|
|
2009-02-21 23:19:58 +00:00
|
|
|
if (switch_core_session_dequeue_event(session, &event, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
|
2007-03-29 22:31:56 +00:00
|
|
|
status = args->input_callback(session, event, SWITCH_INPUT_TYPE_EVENT, args->buf, args->buflen);
|
2006-07-12 18:39:19 +00:00
|
|
|
switch_event_destroy(&event);
|
2006-01-27 21:33:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (status != SWITCH_STATUS_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-06-09 22:59:13 +00:00
|
|
|
if (switch_channel_test_flag(channel, CF_SERVICE)) {
|
2008-11-14 23:31:21 +00:00
|
|
|
switch_cond_next();
|
2006-06-09 22:59:13 +00:00
|
|
|
} else {
|
2008-05-08 19:19:47 +00:00
|
|
|
status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
|
2006-06-09 22:59:13 +00:00
|
|
|
}
|
2006-04-28 19:46:57 +00:00
|
|
|
|
|
|
|
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
2006-01-27 21:33:45 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-04-04 21:18:16 +00:00
|
|
|
|
2010-10-04 23:23:43 +00:00
|
|
|
if (args && args->dmachine) {
|
|
|
|
if ((status = switch_ivr_dmachine_ping(args->dmachine, NULL)) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-04 21:43:20 +00:00
|
|
|
if (read_frame && args && (args->read_frame_callback)) {
|
2010-10-04 23:23:43 +00:00
|
|
|
if ((status = args->read_frame_callback(session, read_frame, args->user_data)) != SWITCH_STATUS_SUCCESS) {
|
2008-04-04 21:18:16 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-01-27 21:33:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2006-04-29 23:43:28 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_collect_digits_count(switch_core_session_t *session,
|
2006-06-09 22:59:13 +00:00
|
|
|
char *buf,
|
2007-10-12 20:14:41 +00:00
|
|
|
switch_size_t buflen,
|
2008-05-27 04:30:03 +00:00
|
|
|
switch_size_t maxdigits,
|
|
|
|
const char *terminators, char *terminator,
|
|
|
|
uint32_t first_timeout, uint32_t digit_timeout, uint32_t abs_timeout)
|
2006-01-27 21:33:45 +00:00
|
|
|
{
|
2007-10-12 20:14:41 +00:00
|
|
|
switch_size_t i = 0, x = strlen(buf);
|
2008-01-28 07:26:10 +00:00
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
2006-12-04 05:41:03 +00:00
|
|
|
switch_status_t status = SWITCH_STATUS_FALSE;
|
2008-01-07 16:49:46 +00:00
|
|
|
switch_time_t started = 0, digit_started = 0;
|
|
|
|
uint32_t abs_elapsed = 0, digit_elapsed = 0;
|
|
|
|
uint32_t eff_timeout = 0;
|
2008-12-09 00:32:51 +00:00
|
|
|
switch_frame_t write_frame = { 0 };
|
|
|
|
unsigned char *abuf = NULL;
|
2010-02-06 03:38:24 +00:00
|
|
|
switch_codec_implementation_t imp = { 0 };
|
2008-12-09 00:32:51 +00:00
|
|
|
switch_codec_t codec = { 0 };
|
|
|
|
int sval = 0;
|
|
|
|
const char *var;
|
|
|
|
|
|
|
|
if ((var = switch_channel_get_variable(channel, SWITCH_SEND_SILENCE_WHEN_IDLE_VARIABLE)) && (sval = atoi(var))) {
|
|
|
|
switch_core_session_get_read_impl(session, &imp);
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2008-12-09 00:32:51 +00:00
|
|
|
if (switch_core_codec_init(&codec,
|
|
|
|
"L16",
|
|
|
|
NULL,
|
|
|
|
imp.samples_per_second,
|
|
|
|
imp.microseconds_per_packet / 1000,
|
2010-02-06 03:38:24 +00:00
|
|
|
imp.number_of_channels,
|
|
|
|
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,
|
2008-12-09 00:32:51 +00:00
|
|
|
switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
2010-02-06 03:38:24 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec Error L16@%uhz %u channels %dms\n",
|
2008-12-09 00:32:51 +00:00
|
|
|
imp.samples_per_second, imp.number_of_channels, imp.microseconds_per_packet / 1000);
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Codec Activated L16@%uhz %u channels %dms\n",
|
2008-12-09 00:32:51 +00:00
|
|
|
imp.samples_per_second, imp.number_of_channels, imp.microseconds_per_packet / 1000);
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2008-12-09 00:32:51 +00:00
|
|
|
write_frame.codec = &codec;
|
|
|
|
switch_zmalloc(abuf, SWITCH_RECOMMENDED_BUFFER_SIZE);
|
|
|
|
write_frame.data = abuf;
|
|
|
|
write_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE;
|
|
|
|
write_frame.datalen = imp.decoded_bytes_per_packet;
|
|
|
|
write_frame.samples = write_frame.datalen / sizeof(int16_t);
|
|
|
|
}
|
2006-03-01 00:58:32 +00:00
|
|
|
|
2008-12-09 00:32:51 +00:00
|
|
|
if (terminator != NULL) {
|
2006-12-04 05:41:03 +00:00
|
|
|
*terminator = '\0';
|
2008-12-09 00:32:51 +00:00
|
|
|
}
|
2006-01-30 16:11:21 +00:00
|
|
|
|
2009-10-23 16:03:42 +00:00
|
|
|
if (!zstr(terminators)) {
|
2007-03-29 22:31:56 +00:00
|
|
|
for (i = 0; i < x; i++) {
|
2006-12-04 05:41:03 +00:00
|
|
|
if (strchr(terminators, buf[i]) && terminator != NULL) {
|
2006-03-01 00:58:32 +00:00
|
|
|
*terminator = buf[i];
|
2008-03-12 16:40:01 +00:00
|
|
|
buf[i] = '\0';
|
2006-03-01 00:58:32 +00:00
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
2006-01-30 16:11:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-07 16:49:46 +00:00
|
|
|
if (abs_timeout) {
|
2009-01-25 21:23:07 +00:00
|
|
|
started = switch_micro_time_now();
|
2008-01-07 16:49:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (digit_timeout && first_timeout) {
|
|
|
|
eff_timeout = first_timeout;
|
|
|
|
} else if (digit_timeout && !first_timeout) {
|
|
|
|
first_timeout = eff_timeout = digit_timeout;
|
|
|
|
} else if (first_timeout) {
|
|
|
|
digit_timeout = eff_timeout = first_timeout;
|
2006-03-01 00:58:32 +00:00
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2008-01-07 16:49:46 +00:00
|
|
|
|
|
|
|
if (eff_timeout) {
|
2009-01-25 21:23:07 +00:00
|
|
|
digit_started = switch_micro_time_now();
|
2008-01-07 16:49:46 +00:00
|
|
|
}
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
while (switch_channel_ready(channel)) {
|
2006-04-29 06:05:03 +00:00
|
|
|
switch_frame_t *read_frame;
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2008-01-07 16:49:46 +00:00
|
|
|
if (abs_timeout) {
|
2009-01-25 21:23:07 +00:00
|
|
|
abs_elapsed = (uint32_t) ((switch_micro_time_now() - started) / 1000);
|
2008-01-07 16:49:46 +00:00
|
|
|
if (abs_elapsed >= abs_timeout) {
|
2009-08-17 23:03:49 +00:00
|
|
|
status = SWITCH_STATUS_TIMEOUT;
|
2006-03-01 00:58:32 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2009-10-12 22:23:55 +00:00
|
|
|
|
|
|
|
switch_ivr_parse_all_events(session);
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2008-01-07 16:49:46 +00:00
|
|
|
if (eff_timeout) {
|
2009-01-25 21:23:07 +00:00
|
|
|
digit_elapsed = (uint32_t) ((switch_micro_time_now() - digit_started) / 1000);
|
2009-03-05 16:53:31 +00:00
|
|
|
|
2008-01-07 16:49:46 +00:00
|
|
|
if (digit_elapsed >= eff_timeout) {
|
2008-08-05 21:50:48 +00:00
|
|
|
status = SWITCH_STATUS_TIMEOUT;
|
2008-01-07 16:49:46 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-27 21:33:45 +00:00
|
|
|
if (switch_channel_has_dtmf(channel)) {
|
2008-05-27 04:30:03 +00:00
|
|
|
switch_dtmf_t dtmf = { 0 };
|
2007-12-22 00:51:26 +00:00
|
|
|
switch_size_t y;
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2008-01-07 16:49:46 +00:00
|
|
|
if (eff_timeout) {
|
|
|
|
eff_timeout = digit_timeout;
|
2009-01-25 21:23:07 +00:00
|
|
|
digit_started = switch_micro_time_now();
|
2008-01-07 16:49:46 +00:00
|
|
|
}
|
|
|
|
|
2008-03-04 18:55:16 +00:00
|
|
|
for (y = 0; y <= maxdigits; y++) {
|
2007-12-22 00:32:20 +00:00
|
|
|
if (switch_channel_dequeue_dtmf(channel, &dtmf) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
2006-01-27 21:33:45 +00:00
|
|
|
|
2009-10-23 16:03:42 +00:00
|
|
|
if (!zstr(terminators) && strchr(terminators, dtmf.digit) && terminator != NULL) {
|
2007-12-22 00:32:20 +00:00
|
|
|
*terminator = dtmf.digit;
|
2006-01-27 21:33:45 +00:00
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
|
|
|
|
2007-12-22 00:32:20 +00:00
|
|
|
buf[x++] = dtmf.digit;
|
2006-01-27 21:33:45 +00:00
|
|
|
buf[x] = '\0';
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2006-01-27 21:33:45 +00:00
|
|
|
if (x >= buflen || x >= maxdigits) {
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-06-09 22:59:13 +00:00
|
|
|
|
|
|
|
if (switch_channel_test_flag(channel, CF_SERVICE)) {
|
2008-11-14 23:31:21 +00:00
|
|
|
switch_cond_next();
|
2006-06-09 22:59:13 +00:00
|
|
|
} else {
|
2008-05-08 19:19:47 +00:00
|
|
|
status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
|
2006-04-28 19:46:57 +00:00
|
|
|
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
2006-03-01 00:58:32 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-12-09 00:32:51 +00:00
|
|
|
|
|
|
|
if (write_frame.data) {
|
|
|
|
switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.samples, sval);
|
|
|
|
switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0);
|
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2006-01-27 21:33:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-09 00:32:51 +00:00
|
|
|
if (write_frame.codec) {
|
|
|
|
switch_core_codec_destroy(&codec);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch_safe_free(abuf);
|
|
|
|
|
2006-01-27 21:33:45 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2008-05-01 16:41:46 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_hold(switch_core_session_t *session, const char *message, switch_bool_t moh)
|
2006-01-27 01:46:14 +00:00
|
|
|
{
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_core_session_message_t msg = { 0 };
|
2008-01-28 07:26:10 +00:00
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
2008-03-10 16:19:55 +00:00
|
|
|
const char *stream;
|
|
|
|
const char *other_uuid;
|
2006-03-01 22:55:28 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
msg.message_id = SWITCH_MESSAGE_INDICATE_HOLD;
|
2008-03-11 03:45:16 +00:00
|
|
|
msg.string_arg = message;
|
2007-03-29 22:31:56 +00:00
|
|
|
msg.from = __FILE__;
|
2006-01-27 01:46:14 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_channel_set_flag(channel, CF_HOLD);
|
|
|
|
switch_channel_set_flag(channel, CF_SUSPEND);
|
|
|
|
|
|
|
|
switch_core_session_receive_message(session, &msg);
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2008-05-01 16:41:46 +00:00
|
|
|
if (moh && (stream = switch_channel_get_variable(channel, SWITCH_HOLD_MUSIC_VARIABLE))) {
|
2008-03-10 16:19:55 +00:00
|
|
|
if ((other_uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))) {
|
|
|
|
switch_ivr_broadcast(other_uuid, stream, SMF_ECHO_ALEG | SMF_LOOP);
|
|
|
|
}
|
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2008-03-10 16:19:55 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
2006-01-27 01:46:14 +00:00
|
|
|
|
2008-05-01 16:41:46 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_hold_uuid(const char *uuid, const char *message, switch_bool_t moh)
|
2007-03-29 22:31:56 +00:00
|
|
|
{
|
|
|
|
switch_core_session_t *session;
|
2006-01-27 01:46:14 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if ((session = switch_core_session_locate(uuid))) {
|
2008-05-01 16:41:46 +00:00
|
|
|
switch_ivr_hold(session, message, moh);
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_core_session_rwunlock(session);
|
2006-01-27 01:46:14 +00:00
|
|
|
}
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
2006-01-27 01:46:14 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_unhold(switch_core_session_t *session)
|
|
|
|
{
|
|
|
|
switch_core_session_message_t msg = { 0 };
|
2008-01-28 07:26:10 +00:00
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
2008-03-10 16:19:55 +00:00
|
|
|
const char *other_uuid;
|
|
|
|
switch_core_session_t *b_session;
|
2006-07-25 22:37:52 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
msg.message_id = SWITCH_MESSAGE_INDICATE_UNHOLD;
|
|
|
|
msg.from = __FILE__;
|
2006-07-25 22:37:52 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_channel_clear_flag(channel, CF_HOLD);
|
|
|
|
switch_channel_clear_flag(channel, CF_SUSPEND);
|
2006-07-25 22:37:52 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_core_session_receive_message(session, &msg);
|
2006-07-25 22:37:52 +00:00
|
|
|
|
2008-03-10 16:19:55 +00:00
|
|
|
|
|
|
|
if ((other_uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) && (b_session = switch_core_session_locate(other_uuid))) {
|
|
|
|
switch_channel_t *b_channel = switch_core_session_get_channel(b_session);
|
|
|
|
switch_channel_stop_broadcast(b_channel);
|
2008-09-09 16:31:53 +00:00
|
|
|
switch_channel_wait_for_flag(b_channel, CF_BROADCAST, SWITCH_FALSE, 5000, NULL);
|
2008-03-10 16:19:55 +00:00
|
|
|
switch_core_session_rwunlock(b_session);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
2006-11-29 17:10:40 +00:00
|
|
|
|
2007-11-01 11:28:26 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_unhold_uuid(const char *uuid)
|
2007-03-29 22:31:56 +00:00
|
|
|
{
|
|
|
|
switch_core_session_t *session;
|
2006-01-27 01:46:14 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if ((session = switch_core_session_locate(uuid))) {
|
|
|
|
switch_ivr_unhold(session);
|
|
|
|
switch_core_session_rwunlock(session);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
2006-09-07 03:58:01 +00:00
|
|
|
|
2007-11-01 11:28:26 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_media(const char *uuid, switch_media_flag_t flags)
|
2007-03-29 22:31:56 +00:00
|
|
|
{
|
2007-11-01 11:28:26 +00:00
|
|
|
const char *other_uuid = NULL;
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_channel_t *channel, *other_channel = NULL;
|
|
|
|
switch_core_session_t *session, *other_session;
|
|
|
|
switch_core_session_message_t msg = { 0 };
|
|
|
|
switch_status_t status = SWITCH_STATUS_GENERR;
|
|
|
|
uint8_t swap = 0;
|
2008-03-24 20:58:44 +00:00
|
|
|
switch_frame_t *read_frame = NULL;
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
msg.message_id = SWITCH_MESSAGE_INDICATE_MEDIA;
|
|
|
|
msg.from = __FILE__;
|
2006-01-27 01:46:14 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if ((session = switch_core_session_locate(uuid))) {
|
|
|
|
channel = switch_core_session_get_channel(session);
|
2008-01-28 07:26:10 +00:00
|
|
|
|
2009-10-07 04:30:19 +00:00
|
|
|
if ((flags & SMF_REBRIDGE) && !switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR)) {
|
2007-03-29 22:31:56 +00:00
|
|
|
swap = 1;
|
|
|
|
}
|
2006-07-12 18:39:19 +00:00
|
|
|
|
2008-02-21 17:48:41 +00:00
|
|
|
if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
|
2007-03-29 22:31:56 +00:00
|
|
|
status = SWITCH_STATUS_SUCCESS;
|
2010-05-04 16:24:35 +00:00
|
|
|
if (switch_core_session_receive_message(session, &msg) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't re-establsh media on %s\n", switch_channel_get_name(channel));
|
2010-06-09 16:15:07 +00:00
|
|
|
switch_core_session_rwunlock(session);
|
2010-05-04 16:24:35 +00:00
|
|
|
return SWITCH_STATUS_GENERR;
|
|
|
|
}
|
2008-09-19 20:59:23 +00:00
|
|
|
|
|
|
|
if ((flags & SMF_IMMEDIATE)) {
|
|
|
|
switch_channel_wait_for_flag(channel, CF_REQ_MEDIA, SWITCH_FALSE, 250, NULL);
|
|
|
|
switch_yield(250000);
|
|
|
|
} else {
|
2010-01-22 00:51:32 +00:00
|
|
|
switch_status_t st;
|
2008-09-19 19:58:01 +00:00
|
|
|
switch_channel_wait_for_flag(channel, CF_REQ_MEDIA, SWITCH_FALSE, 10000, NULL);
|
2010-01-22 00:51:32 +00:00
|
|
|
switch_channel_wait_for_flag(channel, CF_MEDIA_ACK, SWITCH_TRUE, 10000, NULL);
|
|
|
|
switch_channel_wait_for_flag(channel, CF_MEDIA_SET, SWITCH_TRUE, 10000, NULL);
|
|
|
|
st = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
|
2008-09-19 19:58:01 +00:00
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if ((flags & SMF_REBRIDGE)
|
|
|
|
&& (other_uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE))
|
|
|
|
&& (other_session = switch_core_session_locate(other_uuid))) {
|
|
|
|
other_channel = switch_core_session_get_channel(other_session);
|
2007-12-11 19:23:57 +00:00
|
|
|
switch_assert(other_channel != NULL);
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_core_session_receive_message(other_session, &msg);
|
2008-09-09 16:31:53 +00:00
|
|
|
switch_channel_wait_for_flag(other_channel, CF_REQ_MEDIA, SWITCH_FALSE, 10000, NULL);
|
2010-01-23 06:53:30 +00:00
|
|
|
switch_channel_wait_for_flag(other_channel, CF_MEDIA_ACK, SWITCH_TRUE, 10000, NULL);
|
|
|
|
switch_channel_wait_for_flag(other_channel, CF_MEDIA_SET, SWITCH_TRUE, 10000, NULL);
|
2008-05-08 19:19:47 +00:00
|
|
|
switch_core_session_read_frame(other_session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_channel_clear_state_handler(other_channel, NULL);
|
|
|
|
switch_core_session_rwunlock(other_session);
|
|
|
|
}
|
|
|
|
if (other_channel) {
|
|
|
|
switch_channel_clear_state_handler(channel, NULL);
|
2006-01-27 01:46:14 +00:00
|
|
|
}
|
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_core_session_rwunlock(session);
|
|
|
|
|
|
|
|
if (other_channel) {
|
|
|
|
if (swap) {
|
|
|
|
switch_ivr_uuid_bridge(other_uuid, uuid);
|
2006-12-22 21:10:20 +00:00
|
|
|
} else {
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_ivr_uuid_bridge(uuid, other_uuid);
|
2007-03-11 03:07:58 +00:00
|
|
|
}
|
2008-09-09 16:31:53 +00:00
|
|
|
switch_channel_wait_for_flag(channel, CF_BRIDGED, SWITCH_TRUE, 1000, NULL);
|
|
|
|
switch_channel_wait_for_flag(other_channel, CF_BRIDGED, SWITCH_TRUE, 1000, NULL);
|
2006-03-01 04:47:34 +00:00
|
|
|
}
|
2006-01-27 01:46:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
2006-01-26 18:00:27 +00:00
|
|
|
|
2007-11-01 11:28:26 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_nomedia(const char *uuid, switch_media_flag_t flags)
|
2006-09-09 03:39:28 +00:00
|
|
|
{
|
2007-11-01 11:28:26 +00:00
|
|
|
const char *other_uuid;
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_channel_t *channel, *other_channel = NULL;
|
|
|
|
switch_core_session_t *session, *other_session = NULL;
|
|
|
|
switch_core_session_message_t msg = { 0 };
|
|
|
|
switch_status_t status = SWITCH_STATUS_GENERR;
|
|
|
|
uint8_t swap = 0;
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
msg.message_id = SWITCH_MESSAGE_INDICATE_NOMEDIA;
|
|
|
|
msg.from = __FILE__;
|
|
|
|
|
|
|
|
if ((session = switch_core_session_locate(uuid))) {
|
|
|
|
status = SWITCH_STATUS_SUCCESS;
|
|
|
|
channel = switch_core_session_get_channel(session);
|
|
|
|
|
2009-10-07 04:30:19 +00:00
|
|
|
if ((flags & SMF_REBRIDGE) && !switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR)) {
|
2007-03-29 22:31:56 +00:00
|
|
|
swap = 1;
|
|
|
|
}
|
|
|
|
|
2010-01-28 18:21:27 +00:00
|
|
|
switch_channel_set_flag(channel, CF_REDIRECT);
|
|
|
|
switch_channel_set_flag(channel, CF_RESET);
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2008-02-21 17:48:41 +00:00
|
|
|
if ((flags & SMF_FORCE) || !switch_channel_test_flag(channel, CF_PROXY_MODE)) {
|
2007-03-29 22:31:56 +00:00
|
|
|
if ((flags & SMF_REBRIDGE) && (other_uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) &&
|
|
|
|
(other_session = switch_core_session_locate(other_uuid))) {
|
|
|
|
other_channel = switch_core_session_get_channel(other_session);
|
2010-01-28 18:21:27 +00:00
|
|
|
|
2010-01-28 17:46:57 +00:00
|
|
|
switch_channel_set_flag(other_channel, CF_RESET);
|
2010-01-23 06:53:30 +00:00
|
|
|
switch_channel_set_flag(other_channel, CF_REDIRECT);
|
2010-06-03 15:16:47 +00:00
|
|
|
|
|
|
|
if (!switch_core_session_in_thread(session)) {
|
|
|
|
switch_channel_set_state(channel, CS_PARK);
|
|
|
|
}
|
2010-01-23 06:53:30 +00:00
|
|
|
switch_channel_set_state(other_channel, CS_PARK);
|
2010-02-08 18:18:11 +00:00
|
|
|
if (switch_core_session_in_thread(session)) {
|
|
|
|
switch_yield(100000);
|
|
|
|
} else {
|
|
|
|
switch_channel_wait_for_state(other_channel, channel, CS_PARK);
|
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_core_session_receive_message(other_session, &msg);
|
2010-01-28 18:46:47 +00:00
|
|
|
switch_channel_wait_for_flag(other_channel, CF_REQ_MEDIA, SWITCH_FALSE, 10000, NULL);
|
|
|
|
switch_channel_wait_for_flag(other_channel, CF_MEDIA_ACK, SWITCH_TRUE, 10000, NULL);
|
|
|
|
switch_channel_wait_for_flag(other_channel, CF_MEDIA_SET, SWITCH_TRUE, 10000, NULL);
|
2007-03-29 22:31:56 +00:00
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2010-01-28 18:21:27 +00:00
|
|
|
switch_core_session_receive_message(session, &msg);
|
2007-05-14 23:50:38 +00:00
|
|
|
|
2010-01-23 06:53:30 +00:00
|
|
|
if (other_channel) {
|
2010-06-03 15:16:47 +00:00
|
|
|
if (!switch_core_session_in_thread(session)) {
|
2010-07-22 00:31:49 +00:00
|
|
|
switch_channel_wait_for_state(channel, NULL, CS_PARK);
|
2010-06-03 15:16:47 +00:00
|
|
|
switch_channel_wait_for_flag(channel, CF_REQ_MEDIA, SWITCH_FALSE, 10000, NULL);
|
|
|
|
switch_channel_wait_for_flag(channel, CF_MEDIA_ACK, SWITCH_TRUE, 10000, NULL);
|
|
|
|
switch_channel_wait_for_flag(channel, CF_MEDIA_SET, SWITCH_TRUE, 10000, NULL);
|
|
|
|
}
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (swap) {
|
|
|
|
switch_ivr_signal_bridge(other_session, session);
|
|
|
|
} else {
|
|
|
|
switch_ivr_signal_bridge(session, other_session);
|
|
|
|
}
|
2010-01-28 18:21:27 +00:00
|
|
|
|
2010-02-08 18:18:11 +00:00
|
|
|
if (switch_core_session_in_thread(session)) {
|
|
|
|
switch_yield(100000);
|
|
|
|
} else {
|
|
|
|
switch_channel_wait_for_state(other_channel, channel, CS_HIBERNATE);
|
|
|
|
}
|
2010-01-28 18:21:27 +00:00
|
|
|
|
|
|
|
if (!switch_core_session_in_thread(session)) {
|
|
|
|
switch_channel_wait_for_state(channel, other_channel, CS_HIBERNATE);
|
2010-01-23 18:35:05 +00:00
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_core_session_rwunlock(other_session);
|
2006-09-09 03:39:28 +00:00
|
|
|
}
|
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_core_session_rwunlock(session);
|
2006-09-09 03:39:28 +00:00
|
|
|
}
|
2007-03-20 20:37:52 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
return status;
|
2006-09-09 03:39:28 +00:00
|
|
|
}
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_t *session, const char *extension, const char *dialplan,
|
|
|
|
const char *context)
|
2006-09-09 03:39:28 +00:00
|
|
|
{
|
2008-01-28 07:26:10 +00:00
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_caller_profile_t *profile, *new_profile;
|
|
|
|
switch_core_session_message_t msg = { 0 };
|
|
|
|
switch_core_session_t *other_session;
|
|
|
|
switch_channel_t *other_channel = NULL;
|
2007-11-01 11:28:26 +00:00
|
|
|
const char *uuid = NULL;
|
2008-04-14 15:55:37 +00:00
|
|
|
const char *max_forwards;
|
|
|
|
const char *forwardvar = switch_channel_get_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE);
|
|
|
|
int forwardval = 70;
|
2010-07-22 15:49:47 +00:00
|
|
|
const char *use_dialplan = dialplan, *use_context = context;
|
2008-04-14 15:55:37 +00:00
|
|
|
|
2009-10-23 16:03:42 +00:00
|
|
|
if (!zstr(forwardvar)) {
|
2008-05-27 04:30:03 +00:00
|
|
|
forwardval = atoi(forwardvar) - 1;
|
2008-04-14 15:55:37 +00:00
|
|
|
}
|
|
|
|
if (forwardval <= 0) {
|
|
|
|
switch_channel_hangup(channel, SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR);
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
max_forwards = switch_core_session_sprintf(session, "%d", forwardval);
|
|
|
|
switch_channel_set_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE, max_forwards);
|
2006-09-09 03:39:28 +00:00
|
|
|
|
2009-01-09 20:34:01 +00:00
|
|
|
switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
|
2008-01-05 01:03:08 +00:00
|
|
|
switch_channel_clear_flag(channel, CF_ORIGINATING);
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
/* clear all state handlers */
|
|
|
|
switch_channel_clear_state_handler(channel, NULL);
|
2006-09-09 03:39:28 +00:00
|
|
|
|
2007-12-05 22:35:37 +00:00
|
|
|
if ((profile = switch_channel_get_caller_profile(channel))) {
|
2008-11-19 20:42:28 +00:00
|
|
|
const char *var;
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2010-07-22 15:49:47 +00:00
|
|
|
if (zstr(use_dialplan)) {
|
|
|
|
use_dialplan = profile->dialplan;
|
|
|
|
if (!zstr(use_dialplan) && !strcasecmp(use_dialplan, "inline")) {
|
|
|
|
use_dialplan = NULL;
|
2009-10-09 00:52:25 +00:00
|
|
|
}
|
2007-12-05 22:35:37 +00:00
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2010-07-22 15:49:47 +00:00
|
|
|
if (zstr(use_context)) {
|
|
|
|
use_context = profile->context;
|
2007-12-05 22:35:37 +00:00
|
|
|
}
|
2007-09-29 01:06:08 +00:00
|
|
|
|
2010-07-22 15:49:47 +00:00
|
|
|
if (zstr(use_dialplan)) {
|
|
|
|
use_dialplan = "XML";
|
2007-12-05 22:35:37 +00:00
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2010-07-22 15:49:47 +00:00
|
|
|
if (zstr(use_context)) {
|
|
|
|
use_context = "default";
|
2007-12-05 22:35:37 +00:00
|
|
|
}
|
|
|
|
|
2009-10-23 16:03:42 +00:00
|
|
|
if (zstr(extension)) {
|
2007-12-05 22:35:37 +00:00
|
|
|
extension = "service";
|
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2010-07-22 15:49:47 +00:00
|
|
|
if (zstr(dialplan) && (var = switch_channel_get_variable(channel, "force_transfer_dialplan"))) {
|
|
|
|
use_dialplan = var;
|
2008-11-19 20:42:28 +00:00
|
|
|
}
|
|
|
|
|
2010-07-22 15:49:47 +00:00
|
|
|
if (zstr(context) && (var = switch_channel_get_variable(channel, "force_transfer_context"))) {
|
|
|
|
use_context = var;
|
2008-11-19 20:42:28 +00:00
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
new_profile = switch_caller_profile_clone(session, profile);
|
2007-06-12 21:00:26 +00:00
|
|
|
|
2010-07-22 15:49:47 +00:00
|
|
|
new_profile->dialplan = switch_core_strdup(new_profile->pool, use_dialplan);
|
|
|
|
new_profile->context = switch_core_strdup(new_profile->pool, use_context);
|
2008-01-16 22:13:36 +00:00
|
|
|
new_profile->destination_number = switch_core_strdup(new_profile->pool, extension);
|
|
|
|
new_profile->rdnis = switch_core_strdup(new_profile->pool, profile->destination_number);
|
2006-09-09 03:39:28 +00:00
|
|
|
|
2010-06-14 23:37:40 +00:00
|
|
|
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
|
|
|
if (profile->callee_id_name) {
|
|
|
|
switch_channel_set_variable(channel, "pre_transfer_caller_id_name", new_profile->caller_id_name);
|
|
|
|
new_profile->caller_id_name = switch_core_strdup(new_profile->pool, profile->callee_id_name);
|
2010-09-20 23:39:45 +00:00
|
|
|
profile->callee_id_name = SWITCH_BLANK_STRING;
|
2010-06-14 23:37:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (profile->callee_id_number) {
|
|
|
|
switch_channel_set_variable(channel, "pre_transfer_caller_id_number", new_profile->caller_id_number);
|
|
|
|
new_profile->caller_id_number = switch_core_strdup(new_profile->pool, profile->callee_id_number);
|
2010-09-20 23:39:45 +00:00
|
|
|
profile->callee_id_number = SWITCH_BLANK_STRING;
|
2010-06-14 23:37:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_channel_set_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE, NULL);
|
2007-09-21 18:49:14 +00:00
|
|
|
|
|
|
|
/* If HANGUP_AFTER_BRIDGE is set to 'true', SWITCH_SIGNAL_BRIDGE_VARIABLE
|
|
|
|
* will not have a value, so we need to check SWITCH_BRIDGE_VARIABLE */
|
|
|
|
|
|
|
|
uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE);
|
2007-09-29 01:06:08 +00:00
|
|
|
|
2008-02-15 23:16:01 +00:00
|
|
|
if (!uuid) {
|
2007-09-21 18:49:14 +00:00
|
|
|
uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE);
|
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-09-21 18:49:14 +00:00
|
|
|
if (uuid && (other_session = switch_core_session_locate(uuid))) {
|
2007-10-01 14:57:15 +00:00
|
|
|
other_channel = switch_core_session_get_channel(other_session);
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_channel_set_variable(other_channel, SWITCH_SIGNAL_BOND_VARIABLE, NULL);
|
|
|
|
switch_core_session_rwunlock(other_session);
|
|
|
|
}
|
2006-09-09 03:39:28 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE))
|
|
|
|
&& (other_session = switch_core_session_locate(uuid))) {
|
|
|
|
other_channel = switch_core_session_get_channel(other_session);
|
2006-09-09 03:39:28 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_channel_set_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, NULL);
|
|
|
|
switch_channel_set_variable(other_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, NULL);
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_channel_set_variable(channel, SWITCH_BRIDGE_VARIABLE, NULL);
|
|
|
|
switch_channel_set_variable(other_channel, SWITCH_BRIDGE_VARIABLE, NULL);
|
2007-09-21 18:49:14 +00:00
|
|
|
|
|
|
|
/* If we are transferring the CALLER out of the bridge, we do not want to hang up on them */
|
|
|
|
switch_channel_set_variable(channel, SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE, "false");
|
2006-09-09 03:39:28 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_channel_hangup(other_channel, SWITCH_CAUSE_BLIND_TRANSFER);
|
|
|
|
switch_ivr_media(uuid, SMF_NONE);
|
2006-09-09 03:39:28 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_core_session_rwunlock(other_session);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch_channel_set_caller_profile(channel, new_profile);
|
|
|
|
switch_channel_set_flag(channel, CF_TRANSFER);
|
2007-06-25 21:25:33 +00:00
|
|
|
|
2008-05-05 15:30:55 +00:00
|
|
|
switch_channel_set_state(channel, CS_ROUTING);
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
msg.message_id = SWITCH_MESSAGE_INDICATE_TRANSFER;
|
|
|
|
msg.from = __FILE__;
|
|
|
|
switch_core_session_receive_message(session, &msg);
|
2006-09-09 03:39:28 +00:00
|
|
|
|
2010-07-22 15:49:47 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Transfer %s to %s[%s@%s]\n", switch_channel_get_name(channel), use_dialplan,
|
|
|
|
extension, use_context);
|
2007-03-29 22:31:56 +00:00
|
|
|
return SWITCH_STATUS_SUCCESS;
|
2006-09-09 03:39:28 +00:00
|
|
|
}
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
return SWITCH_STATUS_FALSE;
|
2006-09-09 03:39:28 +00:00
|
|
|
}
|
|
|
|
|
2007-03-30 00:13:31 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_transfer_variable(switch_core_session_t *sessa, switch_core_session_t *sessb, char *var)
|
2006-10-05 14:24:25 +00:00
|
|
|
{
|
|
|
|
switch_channel_t *chana = switch_core_session_get_channel(sessa);
|
|
|
|
switch_channel_t *chanb = switch_core_session_get_channel(sessb);
|
2007-11-01 11:28:26 +00:00
|
|
|
const char *val = NULL;
|
2007-02-13 01:22:17 +00:00
|
|
|
uint8_t prefix = 0;
|
2006-10-05 14:24:25 +00:00
|
|
|
|
2007-02-13 01:22:17 +00:00
|
|
|
if (var && *var == '~') {
|
|
|
|
var++;
|
|
|
|
prefix = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (var && !prefix) {
|
2006-10-05 14:24:25 +00:00
|
|
|
if ((val = switch_channel_get_variable(chana, var))) {
|
|
|
|
switch_channel_set_variable(chanb, var, val);
|
|
|
|
}
|
|
|
|
} else {
|
2007-09-29 01:06:08 +00:00
|
|
|
switch_event_header_t *hi;
|
2007-09-24 19:34:25 +00:00
|
|
|
if ((hi = switch_channel_variable_first(chana))) {
|
2007-09-29 01:06:08 +00:00
|
|
|
for (; hi; hi = hi->next) {
|
|
|
|
char *vvar = hi->name;
|
|
|
|
char *vval = hi->value;
|
2007-04-28 21:48:03 +00:00
|
|
|
if (vvar && vval && (!prefix || (var && !strncmp((char *) vvar, var, strlen(var))))) {
|
|
|
|
switch_channel_set_variable(chanb, (char *) vvar, (char *) vval);
|
|
|
|
}
|
2006-10-05 14:24:25 +00:00
|
|
|
}
|
2007-04-28 21:48:03 +00:00
|
|
|
switch_channel_variable_last(chana);
|
2006-10-05 14:24:25 +00:00
|
|
|
}
|
|
|
|
}
|
2006-04-28 19:46:57 +00:00
|
|
|
|
2006-10-05 14:24:25 +00:00
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
2006-11-12 00:32:18 +00:00
|
|
|
|
2006-12-04 05:41:03 +00:00
|
|
|
/******************************************************************************************************/
|
|
|
|
|
2006-11-13 16:29:16 +00:00
|
|
|
struct switch_ivr_digit_stream_parser {
|
|
|
|
int pool_auto_created;
|
|
|
|
switch_memory_pool_t *pool;
|
|
|
|
switch_hash_t *hash;
|
|
|
|
switch_size_t maxlen;
|
2009-02-24 18:36:45 +00:00
|
|
|
switch_size_t buflen;
|
2006-12-04 05:41:03 +00:00
|
|
|
switch_size_t minlen;
|
2006-12-10 22:22:28 +00:00
|
|
|
char terminator;
|
2006-12-04 05:41:03 +00:00
|
|
|
unsigned int digit_timeout_ms;
|
2006-12-10 22:22:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct switch_ivr_digit_stream {
|
|
|
|
char *digits;
|
2006-12-04 05:41:03 +00:00
|
|
|
switch_time_t last_digit_time;
|
2006-11-13 16:29:16 +00:00
|
|
|
};
|
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_new(switch_memory_pool_t *pool, switch_ivr_digit_stream_parser_t ** parser)
|
2007-03-29 22:31:56 +00:00
|
|
|
{
|
|
|
|
switch_status_t status = SWITCH_STATUS_FALSE;
|
2006-11-13 16:29:16 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (parser != NULL) {
|
2006-11-13 16:29:16 +00:00
|
|
|
int pool_auto_created = 0;
|
|
|
|
|
2008-09-02 10:39:39 +00:00
|
|
|
/* if the caller didn't provide a pool, make one */
|
2006-11-13 16:29:16 +00:00
|
|
|
if (pool == NULL) {
|
|
|
|
switch_core_new_memory_pool(&pool);
|
2006-12-04 05:41:03 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "created a memory pool\n");
|
2006-11-13 16:29:16 +00:00
|
|
|
if (pool != NULL) {
|
|
|
|
pool_auto_created = 1;
|
|
|
|
}
|
|
|
|
}
|
2008-09-02 10:39:39 +00:00
|
|
|
/* if we have a pool, make a parser object */
|
2006-11-13 16:29:16 +00:00
|
|
|
if (pool != NULL) {
|
2007-03-30 00:13:31 +00:00
|
|
|
*parser = (switch_ivr_digit_stream_parser_t *) switch_core_alloc(pool, sizeof(switch_ivr_digit_stream_parser_t));
|
2006-11-13 16:29:16 +00:00
|
|
|
}
|
2008-09-02 10:39:39 +00:00
|
|
|
/* if we have parser object, initialize it for the caller */
|
2008-01-28 08:47:55 +00:00
|
|
|
if (pool && *parser != NULL) {
|
2007-03-29 22:31:56 +00:00
|
|
|
memset(*parser, 0, sizeof(switch_ivr_digit_stream_parser_t));
|
2006-11-13 16:29:16 +00:00
|
|
|
(*parser)->pool_auto_created = pool_auto_created;
|
|
|
|
(*parser)->pool = pool;
|
2006-12-04 05:41:03 +00:00
|
|
|
(*parser)->digit_timeout_ms = 1000;
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_core_hash_init(&(*parser)->hash, (*parser)->pool);
|
2006-11-13 16:29:16 +00:00
|
|
|
|
|
|
|
status = SWITCH_STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
status = SWITCH_STATUS_MEMERR;
|
2008-09-02 10:39:39 +00:00
|
|
|
/* if we can't create a parser object,clean up the pool if we created it */
|
2006-11-13 16:29:16 +00:00
|
|
|
if (pool != NULL && pool_auto_created) {
|
|
|
|
switch_core_destroy_memory_pool(&pool);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
return status;
|
2006-11-12 00:32:18 +00:00
|
|
|
}
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_destroy(switch_ivr_digit_stream_parser_t *parser)
|
2006-11-12 00:32:18 +00:00
|
|
|
{
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_status_t status = SWITCH_STATUS_FALSE;
|
|
|
|
|
|
|
|
if (parser != NULL) {
|
|
|
|
if (parser->hash != NULL) {
|
2007-09-29 01:06:08 +00:00
|
|
|
switch_core_hash_destroy(&parser->hash);
|
2007-03-29 22:31:56 +00:00
|
|
|
parser->hash = NULL;
|
|
|
|
}
|
2008-09-02 10:39:39 +00:00
|
|
|
/* free the memory pool if we created it */
|
2007-03-29 22:31:56 +00:00
|
|
|
if (parser->pool_auto_created && parser->pool != NULL) {
|
|
|
|
status = switch_core_destroy_memory_pool(&parser->pool);
|
2006-11-12 20:34:04 +00:00
|
|
|
}
|
2006-11-12 00:32:18 +00:00
|
|
|
}
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
return status;
|
2006-11-12 00:32:18 +00:00
|
|
|
}
|
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_new(switch_ivr_digit_stream_parser_t *parser, switch_ivr_digit_stream_t ** stream)
|
2006-11-12 00:32:18 +00:00
|
|
|
{
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_status_t status = SWITCH_STATUS_FALSE;
|
|
|
|
|
2008-10-06 23:05:55 +00:00
|
|
|
/* if we have a parser object memory pool and a stream object pointer that is null */
|
2009-02-24 18:36:45 +00:00
|
|
|
if (parser && stream && *stream == NULL) {
|
|
|
|
*stream = (switch_ivr_digit_stream_t *) malloc(sizeof(**stream));
|
|
|
|
switch_assert(*stream);
|
|
|
|
memset(*stream, 0, sizeof(**stream));
|
|
|
|
switch_zmalloc((*stream)->digits, parser->buflen + 1);
|
|
|
|
status = SWITCH_STATUS_SUCCESS;
|
2006-11-12 00:32:18 +00:00
|
|
|
}
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
return status;
|
2006-11-12 00:32:18 +00:00
|
|
|
}
|
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_destroy(switch_ivr_digit_stream_t ** stream)
|
2006-11-12 00:32:18 +00:00
|
|
|
{
|
2006-12-04 05:41:03 +00:00
|
|
|
switch_status_t status = SWITCH_STATUS_FALSE;
|
2006-11-12 00:32:18 +00:00
|
|
|
|
2009-02-24 18:36:45 +00:00
|
|
|
if (*stream) {
|
|
|
|
switch_safe_free((*stream)->digits);
|
|
|
|
free(*stream);
|
|
|
|
*stream = NULL;
|
2007-03-29 22:31:56 +00:00
|
|
|
status = SWITCH_STATUS_SUCCESS;
|
2006-11-12 00:32:18 +00:00
|
|
|
}
|
|
|
|
|
2006-12-04 05:41:03 +00:00
|
|
|
return status;
|
2006-11-12 00:32:18 +00:00
|
|
|
}
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_set_event(switch_ivr_digit_stream_parser_t *parser, char *digits, void *data)
|
2006-11-12 20:34:04 +00:00
|
|
|
{
|
2006-12-04 05:41:03 +00:00
|
|
|
switch_status_t status = SWITCH_STATUS_FALSE;
|
2007-02-13 17:15:42 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (parser != NULL && digits != NULL && *digits && parser->hash != NULL) {
|
2006-11-12 20:34:04 +00:00
|
|
|
|
2007-09-29 01:06:08 +00:00
|
|
|
status = switch_core_hash_insert(parser->hash, digits, data);
|
2007-03-29 22:31:56 +00:00
|
|
|
if (status == SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_size_t len = strlen(digits);
|
2006-11-12 20:34:04 +00:00
|
|
|
|
2008-09-02 10:39:39 +00:00
|
|
|
/* if we don't have a terminator, then we have to try and
|
|
|
|
* figure out when a digit set is completed, therefore we
|
|
|
|
* keep track of the min and max digit lengths
|
|
|
|
*/
|
2009-02-24 18:36:45 +00:00
|
|
|
|
|
|
|
if (len > parser->buflen) {
|
|
|
|
parser->buflen = len;
|
|
|
|
}
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (parser->terminator == '\0') {
|
|
|
|
if (len > parser->maxlen) {
|
|
|
|
parser->maxlen = len;
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "max len %u\n", (uint32_t) parser->maxlen);
|
2007-02-15 21:59:59 +00:00
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
if (parser->minlen == 0 || len < parser->minlen) {
|
|
|
|
parser->minlen = len;
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "min len %u\n", (uint32_t) parser->minlen);
|
2007-02-15 21:59:59 +00:00
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
} else {
|
2008-09-02 10:39:39 +00:00
|
|
|
/* since we have a terminator, reset min and max */
|
2007-03-29 22:31:56 +00:00
|
|
|
parser->minlen = 0;
|
|
|
|
parser->maxlen = 0;
|
2007-02-13 17:15:42 +00:00
|
|
|
}
|
2006-11-12 20:34:04 +00:00
|
|
|
}
|
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
if (status != SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "unable to add hash for '%s'\n", digits);
|
|
|
|
}
|
2006-11-12 20:34:04 +00:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_del_event(switch_ivr_digit_stream_parser_t *parser, char *digits)
|
2006-11-12 00:32:18 +00:00
|
|
|
{
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_status_t status = SWITCH_STATUS_FALSE;
|
2006-11-12 00:32:18 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (parser != NULL && digits != NULL && *digits) {
|
|
|
|
status = switch_core_hash_delete(parser->hash, digits);
|
2006-12-04 05:41:03 +00:00
|
|
|
}
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (status != SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "unable to del hash for '%s'\n", digits);
|
2006-11-12 00:32:18 +00:00
|
|
|
}
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
return status;
|
|
|
|
}
|
2006-11-12 00:32:18 +00:00
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
SWITCH_DECLARE(void *) switch_ivr_digit_stream_parser_feed(switch_ivr_digit_stream_parser_t *parser, switch_ivr_digit_stream_t *stream, char digit)
|
2007-03-29 22:31:56 +00:00
|
|
|
{
|
|
|
|
void *result = NULL;
|
2009-02-24 19:58:45 +00:00
|
|
|
switch_size_t len;
|
2006-11-12 00:32:18 +00:00
|
|
|
|
2009-02-24 18:36:45 +00:00
|
|
|
switch_assert(parser);
|
|
|
|
switch_assert(stream);
|
|
|
|
switch_assert(stream->digits);
|
2006-12-23 16:40:37 +00:00
|
|
|
|
2009-02-24 19:58:45 +00:00
|
|
|
len = strlen(stream->digits);
|
|
|
|
|
2009-02-24 18:36:45 +00:00
|
|
|
/* handle new digit arrivals */
|
|
|
|
if (digit) {
|
|
|
|
/* if it's not a terminator digit, add it to the collected digits */
|
|
|
|
if (digit != parser->terminator) {
|
|
|
|
/* if collected digits length >= the max length of the keys
|
|
|
|
* in the hash table, then left shift the digit string
|
|
|
|
*/
|
|
|
|
if (len > 0 && parser->maxlen != 0 && len >= parser->maxlen) {
|
|
|
|
char *src = stream->digits + 1;
|
|
|
|
char *dst = stream->digits;
|
2006-11-12 00:32:18 +00:00
|
|
|
|
2009-02-24 18:36:45 +00:00
|
|
|
while (*src) {
|
|
|
|
*(dst++) = *(src++);
|
2006-11-12 00:32:18 +00:00
|
|
|
}
|
2009-02-24 18:36:45 +00:00
|
|
|
*dst = digit;
|
|
|
|
} else {
|
|
|
|
*(stream->digits + (len++)) = digit;
|
|
|
|
*(stream->digits + len) = '\0';
|
|
|
|
stream->last_digit_time = switch_micro_time_now() / 1000;
|
2006-11-12 00:32:18 +00:00
|
|
|
}
|
|
|
|
}
|
2009-02-24 18:36:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* don't allow collected digit string testing if there are varying sized keys until timeout */
|
|
|
|
if (parser->maxlen - parser->minlen > 0 && (switch_micro_time_now() / 1000) - stream->last_digit_time < parser->digit_timeout_ms) {
|
|
|
|
len = 0;
|
|
|
|
}
|
|
|
|
/* if we have digits to test */
|
|
|
|
if (len) {
|
|
|
|
result = switch_core_hash_find(parser->hash, stream->digits);
|
|
|
|
/* if we matched the digit string, or this digit is the terminator
|
|
|
|
* reset the collected digits for next digit string
|
|
|
|
*/
|
|
|
|
if (result != NULL || parser->terminator == digit) {
|
|
|
|
*stream->digits = '\0';
|
2006-11-12 00:32:18 +00:00
|
|
|
}
|
2006-12-04 05:41:03 +00:00
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2006-12-04 05:41:03 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
return result;
|
2006-11-12 00:32:18 +00:00
|
|
|
}
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_reset(switch_ivr_digit_stream_t *stream)
|
2006-12-04 05:41:03 +00:00
|
|
|
{
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_status_t status = SWITCH_STATUS_FALSE;
|
2009-02-24 18:36:45 +00:00
|
|
|
switch_assert(stream);
|
|
|
|
switch_assert(stream->digits);
|
2006-12-04 05:41:03 +00:00
|
|
|
|
2009-02-24 18:36:45 +00:00
|
|
|
*stream->digits = '\0';
|
|
|
|
stream->last_digit_time = 0;
|
|
|
|
status = SWITCH_STATUS_SUCCESS;
|
2006-12-04 05:41:03 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
return status;
|
2006-12-04 05:41:03 +00:00
|
|
|
}
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_set_terminator(switch_ivr_digit_stream_parser_t *parser, char digit)
|
2006-12-04 05:41:03 +00:00
|
|
|
{
|
|
|
|
switch_status_t status = SWITCH_STATUS_FALSE;
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (parser != NULL) {
|
|
|
|
parser->terminator = digit;
|
2008-09-02 10:39:39 +00:00
|
|
|
/* since we have a terminator, reset min and max */
|
2007-03-29 22:31:56 +00:00
|
|
|
parser->minlen = 0;
|
|
|
|
parser->maxlen = 0;
|
|
|
|
status = SWITCH_STATUS_SUCCESS;
|
2006-12-04 05:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2007-10-02 19:58:06 +00:00
|
|
|
SWITCH_DECLARE(int) switch_ivr_set_xml_profile_data(switch_xml_t xml, switch_caller_profile_t *caller_profile, int off)
|
2006-11-13 16:29:16 +00:00
|
|
|
{
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_xml_t param;
|
2006-12-04 05:41:03 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (!(param = switch_xml_add_child_d(xml, "username", off++))) {
|
|
|
|
return -1;
|
2006-12-04 05:41:03 +00:00
|
|
|
}
|
2009-03-20 20:41:30 +00:00
|
|
|
switch_xml_set_txt_d(param, caller_profile->username);
|
2006-12-04 05:41:03 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (!(param = switch_xml_add_child_d(xml, "dialplan", off++))) {
|
|
|
|
return -1;
|
2006-12-04 05:41:03 +00:00
|
|
|
}
|
2009-03-20 20:41:30 +00:00
|
|
|
switch_xml_set_txt_d(param, caller_profile->dialplan);
|
2006-12-04 05:41:03 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (!(param = switch_xml_add_child_d(xml, "caller_id_name", off++))) {
|
|
|
|
return -1;
|
2006-12-04 05:41:03 +00:00
|
|
|
}
|
2009-03-20 20:41:30 +00:00
|
|
|
switch_xml_set_txt_d(param, caller_profile->caller_id_name);
|
2006-12-04 05:41:03 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (!(param = switch_xml_add_child_d(xml, "ani", off++))) {
|
|
|
|
return -1;
|
2006-11-13 16:29:16 +00:00
|
|
|
}
|
2009-03-20 20:41:30 +00:00
|
|
|
switch_xml_set_txt_d(param, caller_profile->ani);
|
2006-11-13 16:29:16 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (!(param = switch_xml_add_child_d(xml, "aniii", off++))) {
|
|
|
|
return -1;
|
2006-11-13 16:29:16 +00:00
|
|
|
}
|
2009-03-20 20:41:30 +00:00
|
|
|
switch_xml_set_txt_d(param, caller_profile->aniii);
|
2006-11-13 16:29:16 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (!(param = switch_xml_add_child_d(xml, "caller_id_number", off++))) {
|
|
|
|
return -1;
|
2007-02-09 22:55:48 +00:00
|
|
|
}
|
2009-03-20 20:41:30 +00:00
|
|
|
switch_xml_set_txt_d(param, caller_profile->caller_id_number);
|
2007-02-09 22:55:48 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (!(param = switch_xml_add_child_d(xml, "network_addr", off++))) {
|
|
|
|
return -1;
|
2007-02-09 22:55:48 +00:00
|
|
|
}
|
2009-03-20 20:41:30 +00:00
|
|
|
switch_xml_set_txt_d(param, caller_profile->network_addr);
|
2007-02-09 22:55:48 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (!(param = switch_xml_add_child_d(xml, "rdnis", off++))) {
|
|
|
|
return -1;
|
2006-12-20 21:25:14 +00:00
|
|
|
}
|
2009-03-20 20:41:30 +00:00
|
|
|
switch_xml_set_txt_d(param, caller_profile->rdnis);
|
2006-12-20 21:25:14 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (!(param = switch_xml_add_child_d(xml, "destination_number", off++))) {
|
|
|
|
return -1;
|
|
|
|
}
|
2009-03-20 20:41:30 +00:00
|
|
|
switch_xml_set_txt_d(param, caller_profile->destination_number);
|
2007-02-14 15:19:01 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (!(param = switch_xml_add_child_d(xml, "uuid", off++))) {
|
2007-02-14 15:19:01 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2009-03-20 20:41:30 +00:00
|
|
|
switch_xml_set_txt_d(param, caller_profile->uuid);
|
2007-02-14 15:19:01 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (!(param = switch_xml_add_child_d(xml, "source", off++))) {
|
2007-02-14 15:19:01 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2009-03-20 20:41:30 +00:00
|
|
|
switch_xml_set_txt_d(param, caller_profile->source);
|
2007-02-14 15:19:01 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (!(param = switch_xml_add_child_d(xml, "context", off++))) {
|
2007-02-14 15:19:01 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2009-03-20 20:41:30 +00:00
|
|
|
switch_xml_set_txt_d(param, caller_profile->context);
|
2007-02-14 15:19:01 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
if (!(param = switch_xml_add_child_d(xml, "chan_name", off++))) {
|
|
|
|
return -1;
|
|
|
|
}
|
2009-03-20 20:41:30 +00:00
|
|
|
switch_xml_set_txt_d(param, caller_profile->chan_name);
|
2007-02-14 15:19:01 +00:00
|
|
|
|
2007-10-02 16:38:15 +00:00
|
|
|
return off;
|
2007-02-14 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2007-10-02 19:58:06 +00:00
|
|
|
SWITCH_DECLARE(int) switch_ivr_set_xml_chan_vars(switch_xml_t xml, switch_channel_t *channel, int off)
|
|
|
|
{
|
|
|
|
switch_xml_t variable;
|
2007-12-11 04:21:54 +00:00
|
|
|
switch_event_header_t *hi = switch_channel_variable_first(channel);
|
2007-10-02 19:58:06 +00:00
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
if (!hi)
|
|
|
|
return off;
|
2007-12-11 04:21:54 +00:00
|
|
|
|
|
|
|
for (; hi; hi = hi->next) {
|
2009-10-23 16:03:42 +00:00
|
|
|
if (!zstr(hi->name) && !zstr(hi->value) && ((variable = switch_xml_add_child_d(xml, hi->name, off++)))) {
|
2007-12-11 04:21:54 +00:00
|
|
|
char *data;
|
2010-09-23 13:15:55 +00:00
|
|
|
switch_size_t dlen = strlen(hi->value) * 3 + 1;
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-12-11 04:21:54 +00:00
|
|
|
if ((data = malloc(dlen))) {
|
|
|
|
memset(data, 0, dlen);
|
|
|
|
switch_url_encode(hi->value, data, dlen);
|
|
|
|
switch_xml_set_txt_d(variable, data);
|
|
|
|
free(data);
|
2007-10-02 19:58:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-12-11 04:21:54 +00:00
|
|
|
switch_channel_variable_last(channel);
|
2007-10-02 19:58:06 +00:00
|
|
|
|
|
|
|
return off;
|
|
|
|
}
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_generate_xml_cdr(switch_core_session_t *session, switch_xml_t *xml_cdr)
|
2007-02-14 15:19:01 +00:00
|
|
|
{
|
2008-01-28 07:26:10 +00:00
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
2007-02-14 15:19:01 +00:00
|
|
|
switch_caller_profile_t *caller_profile;
|
2008-05-27 04:30:03 +00:00
|
|
|
switch_xml_t variables, cdr, x_main_cp, x_caller_profile, x_caller_extension, x_times, time_tag,
|
2010-02-06 03:38:24 +00:00
|
|
|
x_application, x_callflow, x_inner_extension, x_apps, x_o, x_channel_data, x_field;
|
2007-04-21 01:03:58 +00:00
|
|
|
switch_app_log_t *app_log;
|
2010-02-06 03:38:24 +00:00
|
|
|
char tmp[512], *f;
|
|
|
|
int cdr_off = 0, v_off = 0, cd_off = 0;
|
2007-02-14 15:19:01 +00:00
|
|
|
|
2010-07-01 20:22:13 +00:00
|
|
|
if (*xml_cdr) {
|
|
|
|
cdr = *xml_cdr;
|
|
|
|
} else {
|
|
|
|
if (!(cdr = switch_xml_new("cdr"))) {
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
}
|
2007-02-14 15:19:01 +00:00
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
if (!(x_channel_data = switch_xml_add_child_d(cdr, "channel_data", cdr_off++))) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
x_field = switch_xml_add_child_d(x_channel_data, "state", cd_off++);
|
|
|
|
switch_xml_set_txt_d(x_field, switch_channel_state_name(switch_channel_get_state(channel)));
|
|
|
|
|
|
|
|
x_field = switch_xml_add_child_d(x_channel_data, "direction", cd_off++);
|
|
|
|
switch_xml_set_txt_d(x_field, switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND ? "outbound" : "inbound");
|
|
|
|
|
|
|
|
x_field = switch_xml_add_child_d(x_channel_data, "state_number", cd_off++);
|
|
|
|
switch_snprintf(tmp, sizeof(tmp), "%d", switch_channel_get_state(channel));
|
|
|
|
switch_xml_set_txt_d(x_field, tmp);
|
|
|
|
|
|
|
|
if ((f = switch_channel_get_flag_string(channel))) {
|
|
|
|
x_field = switch_xml_add_child_d(x_channel_data, "flags", cd_off++);
|
|
|
|
switch_xml_set_txt_d(x_field, f);
|
|
|
|
free(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((f = switch_channel_get_cap_string(channel))) {
|
|
|
|
x_field = switch_xml_add_child_d(x_channel_data, "caps", cd_off++);
|
|
|
|
switch_xml_set_txt_d(x_field, f);
|
|
|
|
free(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-02-14 15:19:01 +00:00
|
|
|
if (!(variables = switch_xml_add_child_d(cdr, "variables", cdr_off++))) {
|
|
|
|
goto error;
|
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
switch_ivr_set_xml_chan_vars(variables, channel, v_off);
|
|
|
|
|
|
|
|
|
2007-04-21 01:03:58 +00:00
|
|
|
if ((app_log = switch_core_session_get_app_log(session))) {
|
|
|
|
int app_off = 0;
|
|
|
|
switch_app_log_t *ap;
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-04-21 01:03:58 +00:00
|
|
|
if (!(x_apps = switch_xml_add_child_d(cdr, "app_log", cdr_off++))) {
|
|
|
|
goto error;
|
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
for (ap = app_log; ap; ap = ap->next) {
|
2007-04-21 01:03:58 +00:00
|
|
|
|
|
|
|
if (!(x_application = switch_xml_add_child_d(x_apps, "application", app_off++))) {
|
|
|
|
goto error;
|
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-04-21 01:03:58 +00:00
|
|
|
switch_xml_set_attr_d(x_application, "app_name", ap->app);
|
|
|
|
switch_xml_set_attr_d(x_application, "app_data", ap->arg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-02-14 15:19:01 +00:00
|
|
|
caller_profile = switch_channel_get_caller_profile(channel);
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2007-02-14 15:19:01 +00:00
|
|
|
while (caller_profile) {
|
|
|
|
int cf_off = 0;
|
2007-10-02 16:38:15 +00:00
|
|
|
int cp_off = 0;
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2007-02-14 15:19:01 +00:00
|
|
|
if (!(x_callflow = switch_xml_add_child_d(cdr, "callflow", cdr_off++))) {
|
|
|
|
goto error;
|
|
|
|
}
|
2008-02-26 23:29:58 +00:00
|
|
|
|
2009-10-23 16:03:42 +00:00
|
|
|
if (!zstr(caller_profile->dialplan)) {
|
2008-02-26 23:29:58 +00:00
|
|
|
switch_xml_set_attr_d(x_callflow, "dialplan", caller_profile->dialplan);
|
|
|
|
}
|
|
|
|
|
2009-10-23 16:03:42 +00:00
|
|
|
if (!zstr(caller_profile->profile_index)) {
|
2008-02-26 23:29:58 +00:00
|
|
|
switch_xml_set_attr_d(x_callflow, "profile_index", caller_profile->profile_index);
|
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2007-02-14 15:19:01 +00:00
|
|
|
if (caller_profile->caller_extension) {
|
|
|
|
switch_caller_application_t *ap;
|
2007-02-15 19:58:25 +00:00
|
|
|
int app_off = 0;
|
|
|
|
|
2007-02-14 15:19:01 +00:00
|
|
|
if (!(x_caller_extension = switch_xml_add_child_d(x_callflow, "extension", cf_off++))) {
|
|
|
|
goto error;
|
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-02-14 15:19:01 +00:00
|
|
|
switch_xml_set_attr_d(x_caller_extension, "name", caller_profile->caller_extension->extension_name);
|
|
|
|
switch_xml_set_attr_d(x_caller_extension, "number", caller_profile->caller_extension->extension_number);
|
|
|
|
if (caller_profile->caller_extension->current_application) {
|
2007-03-30 00:13:31 +00:00
|
|
|
switch_xml_set_attr_d(x_caller_extension, "current_app", caller_profile->caller_extension->current_application->application_name);
|
2007-02-14 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
for (ap = caller_profile->caller_extension->applications; ap; ap = ap->next) {
|
2007-02-15 19:58:25 +00:00
|
|
|
if (!(x_application = switch_xml_add_child_d(x_caller_extension, "application", app_off++))) {
|
2007-02-14 15:19:01 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-02-15 20:02:52 +00:00
|
|
|
if (ap == caller_profile->caller_extension->current_application) {
|
|
|
|
switch_xml_set_attr_d(x_application, "last_executed", "true");
|
|
|
|
}
|
2007-02-14 15:19:01 +00:00
|
|
|
switch_xml_set_attr_d(x_application, "app_name", ap->application_name);
|
|
|
|
switch_xml_set_attr_d(x_application, "app_data", ap->application_data);
|
|
|
|
}
|
2007-04-21 01:03:58 +00:00
|
|
|
|
|
|
|
if (caller_profile->caller_extension->children) {
|
|
|
|
switch_caller_profile_t *cp = NULL;
|
2010-02-06 03:38:24 +00:00
|
|
|
int i_off = 0, i_app_off = 0;
|
2007-04-21 01:03:58 +00:00
|
|
|
for (cp = caller_profile->caller_extension->children; cp; cp = cp->next) {
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-04-21 01:03:58 +00:00
|
|
|
if (!cp->caller_extension) {
|
|
|
|
continue;
|
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
if (!(x_inner_extension = switch_xml_add_child_d(x_caller_extension, "sub_extensions", app_off++))) {
|
2007-04-21 01:03:58 +00:00
|
|
|
goto error;
|
2008-05-27 04:30:03 +00:00
|
|
|
}
|
2007-04-21 01:03:58 +00:00
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
if (!(x_caller_extension = switch_xml_add_child_d(x_inner_extension, "extension", i_off++))) {
|
2007-04-21 01:03:58 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
switch_xml_set_attr_d(x_caller_extension, "name", cp->caller_extension->extension_name);
|
|
|
|
switch_xml_set_attr_d(x_caller_extension, "number", cp->caller_extension->extension_number);
|
|
|
|
switch_xml_set_attr_d(x_caller_extension, "dialplan", cp->dialplan);
|
|
|
|
if (cp->caller_extension->current_application) {
|
|
|
|
switch_xml_set_attr_d(x_caller_extension, "current_app", cp->caller_extension->current_application->application_name);
|
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
|
2007-04-21 01:03:58 +00:00
|
|
|
for (ap = cp->caller_extension->applications; ap; ap = ap->next) {
|
2010-02-06 03:38:24 +00:00
|
|
|
if (!(x_application = switch_xml_add_child_d(x_caller_extension, "application", i_app_off++))) {
|
2007-04-21 01:03:58 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (ap == cp->caller_extension->current_application) {
|
|
|
|
switch_xml_set_attr_d(x_application, "last_executed", "true");
|
|
|
|
}
|
|
|
|
switch_xml_set_attr_d(x_application, "app_name", ap->application_name);
|
|
|
|
switch_xml_set_attr_d(x_application, "app_data", ap->application_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-02-14 15:19:01 +00:00
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2007-10-02 16:38:15 +00:00
|
|
|
if (!(x_main_cp = switch_xml_add_child_d(x_callflow, "caller_profile", cf_off++))) {
|
2007-02-14 15:19:01 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-10-02 16:38:15 +00:00
|
|
|
|
2007-10-02 19:58:06 +00:00
|
|
|
cp_off += switch_ivr_set_xml_profile_data(x_main_cp, caller_profile, 0);
|
2007-02-14 15:19:01 +00:00
|
|
|
|
2010-09-08 18:19:56 +00:00
|
|
|
if (caller_profile->origination_caller_profile) {
|
|
|
|
switch_caller_profile_t *cp = NULL;
|
|
|
|
int off = 0;
|
|
|
|
if (!(x_o = switch_xml_add_child_d(x_main_cp, "origination", cp_off++))) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (cp = caller_profile->origination_caller_profile; cp; cp = cp->next) {
|
|
|
|
if (!(x_caller_profile = switch_xml_add_child_d(x_o, "origination_caller_profile", off++))) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
switch_ivr_set_xml_profile_data(x_caller_profile, cp, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-14 15:19:01 +00:00
|
|
|
if (caller_profile->originator_caller_profile) {
|
2007-10-02 16:38:15 +00:00
|
|
|
switch_caller_profile_t *cp = NULL;
|
|
|
|
int off = 0;
|
|
|
|
if (!(x_o = switch_xml_add_child_d(x_main_cp, "originator", cp_off++))) {
|
2007-02-14 15:19:01 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-10-02 16:38:15 +00:00
|
|
|
|
|
|
|
for (cp = caller_profile->originator_caller_profile; cp; cp = cp->next) {
|
|
|
|
if (!(x_caller_profile = switch_xml_add_child_d(x_o, "originator_caller_profile", off++))) {
|
|
|
|
goto error;
|
|
|
|
}
|
2007-10-02 19:58:06 +00:00
|
|
|
switch_ivr_set_xml_profile_data(x_caller_profile, cp, 0);
|
2007-10-02 16:38:15 +00:00
|
|
|
}
|
2007-02-14 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (caller_profile->originatee_caller_profile) {
|
2007-10-02 16:38:15 +00:00
|
|
|
switch_caller_profile_t *cp = NULL;
|
|
|
|
int off = 0;
|
|
|
|
if (!(x_o = switch_xml_add_child_d(x_main_cp, "originatee", cp_off++))) {
|
2007-02-14 15:19:01 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-10-02 16:38:15 +00:00
|
|
|
for (cp = caller_profile->originatee_caller_profile; cp; cp = cp->next) {
|
|
|
|
if (!(x_caller_profile = switch_xml_add_child_d(x_o, "originatee_caller_profile", off++))) {
|
|
|
|
goto error;
|
|
|
|
}
|
2008-10-30 15:18:07 +00:00
|
|
|
switch_ivr_set_xml_profile_data(x_caller_profile, cp, 0);
|
2007-10-02 16:38:15 +00:00
|
|
|
}
|
2007-02-14 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (caller_profile->times) {
|
2007-02-15 19:20:14 +00:00
|
|
|
int t_off = 0;
|
|
|
|
if (!(x_times = switch_xml_add_child_d(x_callflow, "times", cf_off++))) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!(time_tag = switch_xml_add_child_d(x_times, "created_time", t_off++))) {
|
2007-02-14 15:19:01 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-12-12 21:53:32 +00:00
|
|
|
switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->created);
|
2007-02-15 19:20:14 +00:00
|
|
|
switch_xml_set_txt_d(time_tag, tmp);
|
2007-02-14 15:19:01 +00:00
|
|
|
|
2007-12-20 17:27:11 +00:00
|
|
|
if (!(time_tag = switch_xml_add_child_d(x_times, "profile_created_time", t_off++))) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->profile_created);
|
|
|
|
switch_xml_set_txt_d(time_tag, tmp);
|
|
|
|
|
2008-05-24 01:43:12 +00:00
|
|
|
if (!(time_tag = switch_xml_add_child_d(x_times, "progress_time", t_off++))) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->progress);
|
|
|
|
switch_xml_set_txt_d(time_tag, tmp);
|
|
|
|
|
|
|
|
|
|
|
|
if (!(time_tag = switch_xml_add_child_d(x_times, "progress_media_time", t_off++))) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->progress_media);
|
|
|
|
switch_xml_set_txt_d(time_tag, tmp);
|
|
|
|
|
2007-02-15 19:20:14 +00:00
|
|
|
if (!(time_tag = switch_xml_add_child_d(x_times, "answered_time", t_off++))) {
|
2007-02-14 15:19:01 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-12-12 21:53:32 +00:00
|
|
|
switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->answered);
|
2007-02-15 19:20:14 +00:00
|
|
|
switch_xml_set_txt_d(time_tag, tmp);
|
2007-02-14 15:19:01 +00:00
|
|
|
|
2007-02-15 19:20:14 +00:00
|
|
|
if (!(time_tag = switch_xml_add_child_d(x_times, "hangup_time", t_off++))) {
|
2007-02-14 15:19:01 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-12-12 21:53:32 +00:00
|
|
|
switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->hungup);
|
2007-02-15 19:20:14 +00:00
|
|
|
switch_xml_set_txt_d(time_tag, tmp);
|
2007-02-14 15:19:01 +00:00
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
if (!(time_tag = switch_xml_add_child_d(x_times, "resurrect_time", t_off++))) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->resurrected);
|
|
|
|
switch_xml_set_txt_d(time_tag, tmp);
|
|
|
|
|
2007-02-15 19:20:14 +00:00
|
|
|
if (!(time_tag = switch_xml_add_child_d(x_times, "transfer_time", t_off++))) {
|
2007-02-14 15:19:01 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-12-12 21:53:32 +00:00
|
|
|
switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->transferred);
|
2007-02-15 19:20:14 +00:00
|
|
|
switch_xml_set_txt_d(time_tag, tmp);
|
2007-02-14 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
caller_profile = caller_profile->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
*xml_cdr = cdr;
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
|
|
|
|
error:
|
2007-02-14 15:19:01 +00:00
|
|
|
|
|
|
|
if (cdr) {
|
|
|
|
switch_xml_free(cdr);
|
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2007-02-14 15:19:01 +00:00
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
|
|
|
|
2007-12-13 22:17:20 +00:00
|
|
|
SWITCH_DECLARE(void) switch_ivr_park_session(switch_core_session_t *session)
|
|
|
|
{
|
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
|
|
|
switch_channel_set_state(channel, CS_PARK);
|
2008-10-27 17:14:55 +00:00
|
|
|
switch_channel_set_flag(channel, CF_TRANSFER);
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2007-12-13 22:17:20 +00:00
|
|
|
}
|
|
|
|
|
2007-10-04 15:09:44 +00:00
|
|
|
SWITCH_DECLARE(void) switch_ivr_delay_echo(switch_core_session_t *session, uint32_t delay_ms)
|
|
|
|
{
|
|
|
|
stfu_instance_t *jb;
|
|
|
|
int qlen = 0;
|
|
|
|
stfu_frame_t *jb_frame;
|
|
|
|
switch_frame_t *read_frame, write_frame = { 0 };
|
|
|
|
switch_status_t status;
|
2008-01-28 07:26:10 +00:00
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
2007-10-04 15:09:44 +00:00
|
|
|
uint32_t interval, samples;
|
|
|
|
uint32_t ts = 0;
|
2010-02-06 03:38:24 +00:00
|
|
|
switch_codec_implementation_t read_impl = { 0 };
|
|
|
|
switch_core_session_get_read_impl(session, &read_impl);
|
2009-02-10 19:09:06 +00:00
|
|
|
|
2007-10-04 15:09:44 +00:00
|
|
|
|
2007-10-05 00:05:41 +00:00
|
|
|
if (delay_ms < 1 || delay_ms > 10000) {
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid delay [%d] must be between 1 and 10000\n", delay_ms);
|
2007-10-04 15:09:44 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-02-10 19:09:06 +00:00
|
|
|
interval = read_impl.microseconds_per_packet / 1000;
|
|
|
|
samples = switch_samples_per_packet(read_impl.samples_per_second, interval);
|
2007-10-04 15:09:44 +00:00
|
|
|
|
|
|
|
qlen = delay_ms / (interval);
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setting delay to %dms (%d frames)\n", delay_ms, qlen);
|
2010-12-10 23:47:24 +00:00
|
|
|
jb = stfu_n_init(qlen, qlen, read_impl.samples_per_packet, read_impl.samples_per_second);
|
2007-10-04 15:09:44 +00:00
|
|
|
|
2009-02-10 19:09:06 +00:00
|
|
|
write_frame.codec = switch_core_session_get_read_codec(session);
|
2007-10-04 15:09:44 +00:00
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
while (switch_channel_ready(channel)) {
|
2008-05-08 19:19:47 +00:00
|
|
|
status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
|
2007-10-04 15:09:44 +00:00
|
|
|
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-12-10 23:47:24 +00:00
|
|
|
stfu_n_eat(jb, ts, 0, read_frame->payload, read_frame->data, read_frame->datalen);
|
2007-10-04 15:09:44 +00:00
|
|
|
ts += interval;
|
|
|
|
|
|
|
|
if ((jb_frame = stfu_n_read_a_frame(jb))) {
|
|
|
|
write_frame.data = jb_frame->data;
|
2008-05-27 04:30:03 +00:00
|
|
|
write_frame.datalen = (uint32_t) jb_frame->dlen;
|
2010-09-12 20:38:58 +00:00
|
|
|
write_frame.buflen = (uint32_t) jb_frame->dlen;
|
2008-05-08 19:19:47 +00:00
|
|
|
status = switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0);
|
2007-10-04 15:09:44 +00:00
|
|
|
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
stfu_n_destroy(&jb);
|
|
|
|
}
|
2007-02-14 15:19:01 +00:00
|
|
|
|
2010-03-07 19:34:05 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_say(switch_core_session_t *session,
|
|
|
|
const char *tosay,
|
|
|
|
const char *module_name,
|
|
|
|
const char *say_type,
|
|
|
|
const char *say_method,
|
|
|
|
const char *say_gender,
|
|
|
|
switch_input_args_t *args)
|
2008-05-09 22:16:08 +00:00
|
|
|
{
|
|
|
|
switch_say_interface_t *si;
|
2009-06-23 13:40:07 +00:00
|
|
|
switch_channel_t *channel;
|
2009-07-21 17:56:12 +00:00
|
|
|
switch_status_t status = SWITCH_STATUS_FALSE;
|
|
|
|
const char *save_path = NULL, *chan_lang = NULL, *lang = NULL, *lname = NULL, *sound_path = NULL;
|
|
|
|
switch_event_t *hint_data;
|
|
|
|
switch_xml_t cfg, xml = NULL, language, macros;
|
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2009-06-23 13:40:07 +00:00
|
|
|
switch_assert(session);
|
|
|
|
channel = switch_core_session_get_channel(session);
|
|
|
|
switch_assert(channel);
|
|
|
|
|
|
|
|
lang = switch_channel_get_variable(channel, "language");
|
|
|
|
|
|
|
|
if (!lang) {
|
|
|
|
chan_lang = switch_channel_get_variable(channel, "default_language");
|
|
|
|
if (!chan_lang) {
|
|
|
|
chan_lang = "en";
|
|
|
|
}
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No language specified - Using [%s]\n", chan_lang);
|
2009-06-23 13:40:07 +00:00
|
|
|
} else {
|
|
|
|
chan_lang = lang;
|
|
|
|
}
|
|
|
|
|
2009-07-21 17:56:12 +00:00
|
|
|
switch_event_create(&hint_data, SWITCH_EVENT_REQUEST_PARAMS);
|
|
|
|
switch_assert(hint_data);
|
|
|
|
|
|
|
|
switch_event_add_header_string(hint_data, SWITCH_STACK_BOTTOM, "macro_name", "say_app");
|
|
|
|
switch_event_add_header_string(hint_data, SWITCH_STACK_BOTTOM, "lang", chan_lang);
|
|
|
|
switch_channel_event_set_data(channel, hint_data);
|
|
|
|
|
|
|
|
if (switch_xml_locate("phrases", NULL, NULL, NULL, &xml, &cfg, hint_data, SWITCH_TRUE) != SWITCH_STATUS_SUCCESS) {
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Open of phrases failed.\n");
|
2009-07-21 17:56:12 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(macros = switch_xml_child(cfg, "macros"))) {
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find macros tag.\n");
|
2009-07-21 17:56:12 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(language = switch_xml_child(macros, "language"))) {
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find language tag.\n");
|
2009-07-21 17:56:12 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (language) {
|
|
|
|
if ((lname = (char *) switch_xml_attr(language, "name")) && !strcasecmp(lname, chan_lang)) {
|
|
|
|
const char *tmp;
|
|
|
|
|
|
|
|
if ((tmp = switch_xml_attr(language, "module"))) {
|
|
|
|
module_name = tmp;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
language = language->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!language) {
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find language %s.\n", chan_lang);
|
2009-07-21 17:56:12 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2010-09-24 21:01:05 +00:00
|
|
|
if (!module_name) {
|
|
|
|
module_name = chan_lang;
|
|
|
|
}
|
|
|
|
|
2009-07-21 17:56:12 +00:00
|
|
|
if (!(sound_path = (char *) switch_xml_attr(language, "sound-path"))) {
|
|
|
|
sound_path = (char *) switch_xml_attr(language, "sound_path");
|
|
|
|
}
|
|
|
|
|
2009-06-23 13:40:07 +00:00
|
|
|
save_path = switch_channel_get_variable(channel, "sound_prefix");
|
|
|
|
|
2009-07-21 17:56:12 +00:00
|
|
|
if (sound_path) {
|
|
|
|
switch_channel_set_variable(channel, "sound_prefix", sound_path);
|
|
|
|
}
|
2008-05-09 22:16:08 +00:00
|
|
|
|
|
|
|
if ((si = switch_loadable_module_get_say_interface(module_name))) {
|
2008-09-02 10:39:39 +00:00
|
|
|
/* should go back and proto all the say mods to const.... */
|
2010-03-07 19:34:05 +00:00
|
|
|
switch_say_args_t say_args = {0};
|
|
|
|
|
|
|
|
say_args.type = switch_ivr_get_say_type_by_name(say_type);
|
|
|
|
say_args.method = switch_ivr_get_say_method_by_name(say_method);
|
|
|
|
say_args.gender = switch_ivr_get_say_gender_by_name(say_gender);
|
|
|
|
|
|
|
|
status = si->say_function(session, (char *) tosay, &say_args, args);
|
2008-05-09 22:16:08 +00:00
|
|
|
} else {
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid SAY Interface [%s]!\n", module_name);
|
2008-05-09 22:16:08 +00:00
|
|
|
status = SWITCH_STATUS_FALSE;
|
|
|
|
}
|
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
done:
|
2009-07-21 17:56:12 +00:00
|
|
|
|
|
|
|
if (hint_data) {
|
|
|
|
switch_event_destroy(&hint_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (save_path) {
|
|
|
|
switch_channel_set_variable(channel, "sound_prefix", save_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xml) {
|
|
|
|
switch_xml_free(xml);
|
|
|
|
}
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2008-05-09 22:16:08 +00:00
|
|
|
return status;
|
|
|
|
}
|
2007-02-14 15:19:01 +00:00
|
|
|
|
2009-09-08 19:05:32 +00:00
|
|
|
static const char *get_prefixed_str(char *buffer, size_t buffer_size, const char *prefix, size_t prefix_size, const char *str)
|
|
|
|
{
|
|
|
|
size_t str_len;
|
|
|
|
|
2009-09-09 15:07:51 +00:00
|
|
|
if (!buffer) {
|
2009-09-08 19:05:32 +00:00
|
|
|
/*
|
2010-02-06 03:38:24 +00:00
|
|
|
if buffer is null then it just returns the str without the prefix appended, otherwise buffer contains the prefix followed by the original string
|
|
|
|
*/
|
2009-09-08 19:05:32 +00:00
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
str_len = strlen(str);
|
|
|
|
memcpy(buffer, prefix, prefix_size);
|
2010-02-06 03:38:24 +00:00
|
|
|
|
2009-09-08 19:05:32 +00:00
|
|
|
if (str_len + prefix_size + 1 > buffer_size) {
|
2010-02-06 03:38:24 +00:00
|
|
|
memcpy(buffer + prefix_size, str, buffer_size - prefix_size - 1);
|
|
|
|
buffer[buffer_size - prefix_size - 1] = '\0';
|
2009-09-08 19:05:32 +00:00
|
|
|
} else {
|
|
|
|
memcpy(buffer + prefix_size, str, str_len + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
2008-05-24 17:28:04 +00:00
|
|
|
|
2008-07-16 17:44:54 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_set_user(switch_core_session_t *session, const char *data)
|
|
|
|
{
|
2008-12-23 17:36:50 +00:00
|
|
|
switch_xml_t x_domain, xml = NULL, x_user, x_param, x_params, x_group = NULL;
|
2009-05-18 17:11:47 +00:00
|
|
|
char *user, *number_alias, *domain;
|
2008-07-16 17:44:54 +00:00
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
|
|
|
switch_status_t status = SWITCH_STATUS_FALSE;
|
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
char *prefix_buffer = NULL, *prefix;
|
|
|
|
size_t buffer_size = 0;
|
|
|
|
size_t prefix_size = 0;
|
2009-10-23 16:03:42 +00:00
|
|
|
if (zstr(data)) {
|
2008-07-16 17:44:54 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
user = switch_core_session_strdup(session, data);
|
2010-02-06 03:38:24 +00:00
|
|
|
|
|
|
|
if ((prefix = strchr(user, ' '))) {
|
2009-09-08 19:05:32 +00:00
|
|
|
*prefix++ = 0;
|
|
|
|
}
|
2008-07-16 17:44:54 +00:00
|
|
|
|
|
|
|
if (!(domain = strchr(user, '@'))) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
*domain++ = '\0';
|
|
|
|
|
2008-12-23 17:36:50 +00:00
|
|
|
if (switch_xml_locate_user("id", user, domain, NULL, &xml, &x_domain, &x_user, &x_group, NULL) != SWITCH_STATUS_SUCCESS) {
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "can't find user [%s@%s]\n", user, domain);
|
2008-07-16 17:44:54 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = SWITCH_STATUS_SUCCESS;
|
|
|
|
|
2009-10-23 16:03:42 +00:00
|
|
|
if (!zstr(prefix)) {
|
2009-09-08 19:05:32 +00:00
|
|
|
prefix_size = strlen(prefix);
|
|
|
|
buffer_size = 1024 + prefix_size + 1;
|
|
|
|
prefix_buffer = switch_core_session_alloc(session, buffer_size);
|
|
|
|
}
|
|
|
|
|
2009-05-18 17:11:47 +00:00
|
|
|
if ((number_alias = (char *) switch_xml_attr(x_user, "number-alias"))) {
|
2009-09-08 19:05:32 +00:00
|
|
|
switch_channel_set_variable(channel, get_prefixed_str(prefix_buffer, buffer_size, prefix, prefix_size, "number_alias"), number_alias);
|
2008-07-16 17:44:54 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 16:38:45 +00:00
|
|
|
if ((x_params = switch_xml_child(x_domain, "variables"))) {
|
|
|
|
for (x_param = switch_xml_child(x_params, "variable"); x_param; x_param = x_param->next) {
|
2008-12-23 17:36:50 +00:00
|
|
|
const char *var = switch_xml_attr(x_param, "name");
|
|
|
|
const char *val = switch_xml_attr(x_param, "value");
|
|
|
|
|
|
|
|
if (var && val) {
|
2009-09-08 19:05:32 +00:00
|
|
|
switch_channel_set_variable(channel, get_prefixed_str(prefix_buffer, buffer_size, prefix, prefix_size, var), val);
|
2008-12-23 17:36:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x_group && (x_params = switch_xml_child(x_group, "variables"))) {
|
|
|
|
for (x_param = switch_xml_child(x_params, "variable"); x_param; x_param = x_param->next) {
|
2008-09-02 16:38:45 +00:00
|
|
|
const char *var = switch_xml_attr(x_param, "name");
|
|
|
|
const char *val = switch_xml_attr(x_param, "value");
|
|
|
|
|
|
|
|
if (var && val) {
|
2009-09-08 19:05:32 +00:00
|
|
|
switch_channel_set_variable(channel, get_prefixed_str(prefix_buffer, buffer_size, prefix, prefix_size, var), val);
|
2008-09-02 16:38:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-16 17:44:54 +00:00
|
|
|
if ((x_params = switch_xml_child(x_user, "variables"))) {
|
|
|
|
for (x_param = switch_xml_child(x_params, "variable"); x_param; x_param = x_param->next) {
|
|
|
|
const char *var = switch_xml_attr(x_param, "name");
|
|
|
|
const char *val = switch_xml_attr(x_param, "value");
|
|
|
|
|
|
|
|
if (var && val) {
|
2009-09-08 19:05:32 +00:00
|
|
|
switch_channel_set_variable(channel, get_prefixed_str(prefix_buffer, buffer_size, prefix, prefix_size, var), val);
|
2008-07-16 17:44:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-06 03:38:24 +00:00
|
|
|
switch_channel_set_variable(channel, get_prefixed_str(prefix_buffer, buffer_size, prefix, prefix_size, "user_name"), user);
|
|
|
|
switch_channel_set_variable(channel, get_prefixed_str(prefix_buffer, buffer_size, prefix, prefix_size, "domain_name"), domain);
|
2008-07-16 17:44:54 +00:00
|
|
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
error:
|
2009-08-13 20:35:02 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No user@domain specified.\n");
|
2008-07-16 17:44:54 +00:00
|
|
|
|
|
|
|
done:
|
|
|
|
if (xml) {
|
|
|
|
switch_xml_free(xml);
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2009-10-08 18:09:06 +00:00
|
|
|
SWITCH_DECLARE(switch_bool_t) switch_ivr_uuid_exists(const char *uuid)
|
|
|
|
{
|
|
|
|
switch_bool_t exists = SWITCH_FALSE;
|
|
|
|
switch_core_session_t *psession = NULL;
|
|
|
|
|
|
|
|
if ((psession = switch_core_session_locate(uuid))) {
|
|
|
|
switch_core_session_rwunlock(psession);
|
|
|
|
exists = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return exists;
|
|
|
|
}
|
|
|
|
|
2010-11-30 21:34:22 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_process_fh(switch_core_session_t *session, const char *cmd, switch_file_handle_t *fhp)
|
|
|
|
{
|
|
|
|
if (zstr(cmd)) {
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fhp) {
|
|
|
|
if (!switch_test_flag(fhp, SWITCH_FILE_OPEN)) {
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncasecmp(cmd, "speed", 5)) {
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
if ((p = strchr(cmd, ':'))) {
|
|
|
|
p++;
|
|
|
|
if (*p == '+' || *p == '-') {
|
|
|
|
int step;
|
|
|
|
if (!(step = atoi(p))) {
|
|
|
|
step = 1;
|
|
|
|
}
|
|
|
|
fhp->speed += step;
|
|
|
|
} else {
|
|
|
|
int speed = atoi(p);
|
|
|
|
fhp->speed = speed;
|
|
|
|
}
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
|
|
|
|
} else if (!strncasecmp(cmd, "volume", 6)) {
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
if ((p = strchr(cmd, ':'))) {
|
|
|
|
p++;
|
|
|
|
if (*p == '+' || *p == '-') {
|
|
|
|
int step;
|
|
|
|
if (!(step = atoi(p))) {
|
|
|
|
step = 1;
|
|
|
|
}
|
|
|
|
fhp->vol += step;
|
|
|
|
} else {
|
|
|
|
int vol = atoi(p);
|
|
|
|
fhp->vol = vol;
|
|
|
|
}
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fhp->vol) {
|
|
|
|
switch_normalize_volume(fhp->vol);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
} else if (!strcasecmp(cmd, "pause")) {
|
|
|
|
if (switch_test_flag(fhp, SWITCH_FILE_PAUSE)) {
|
|
|
|
switch_clear_flag(fhp, SWITCH_FILE_PAUSE);
|
|
|
|
} else {
|
|
|
|
switch_set_flag(fhp, SWITCH_FILE_PAUSE);
|
|
|
|
}
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
} else if (!strcasecmp(cmd, "stop")) {
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
} else if (!strcasecmp(cmd, "truncate")) {
|
|
|
|
switch_core_file_truncate(fhp, 0);
|
|
|
|
} else if (!strcasecmp(cmd, "restart")) {
|
|
|
|
unsigned int pos = 0;
|
|
|
|
fhp->speed = 0;
|
|
|
|
switch_core_file_seek(fhp, &pos, 0, SEEK_SET);
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
} else if (!strncasecmp(cmd, "seek", 4)) {
|
|
|
|
switch_codec_t *codec;
|
|
|
|
unsigned int samps = 0;
|
|
|
|
unsigned int pos = 0;
|
|
|
|
char *p;
|
|
|
|
codec = switch_core_session_get_read_codec(session);
|
|
|
|
|
|
|
|
if ((p = strchr(cmd, ':'))) {
|
|
|
|
p++;
|
|
|
|
if (*p == '+' || *p == '-') {
|
|
|
|
int step;
|
|
|
|
int32_t target;
|
|
|
|
if (!(step = atoi(p))) {
|
|
|
|
step = 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
samps = step * (codec->implementation->samples_per_second / 1000);
|
|
|
|
target = (int32_t)fhp->pos + samps;
|
|
|
|
|
|
|
|
if (target < 0) {
|
|
|
|
target = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "seek to position %d\n", target);
|
|
|
|
switch_core_file_seek(fhp, &pos, target, SEEK_SET);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
samps = atoi(p) * (codec->implementation->samples_per_second / 1000);
|
|
|
|
if (samps < 0) {
|
|
|
|
samps = 0;
|
|
|
|
}
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "seek to position %d\n", samps);
|
|
|
|
switch_core_file_seek(fhp, &pos, samps, SEEK_SET);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(cmd, "true") || !strcmp(cmd, "undefined")) {
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-12-01 00:22:12 +00:00
|
|
|
#define START_SAMPLES 32768
|
|
|
|
|
|
|
|
SWITCH_DECLARE(switch_status_t) switch_ivr_insert_file(switch_core_session_t *session, const char *file, const char *insert_file, switch_size_t sample_point)
|
|
|
|
{
|
|
|
|
switch_file_handle_t orig_fh = { 0 };
|
|
|
|
switch_file_handle_t new_fh = { 0 };
|
|
|
|
switch_codec_implementation_t read_impl = { 0 };
|
|
|
|
char *tmp_file;
|
|
|
|
switch_uuid_t uuid;
|
|
|
|
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
|
|
|
|
int16_t *abuf = NULL;
|
|
|
|
switch_size_t olen = 0;
|
|
|
|
int asis = 0;
|
|
|
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
|
|
|
switch_size_t sample_count = 0;
|
|
|
|
uint32_t pos = 0;
|
|
|
|
char *ext;
|
|
|
|
|
|
|
|
switch_uuid_get(&uuid);
|
|
|
|
switch_uuid_format(uuid_str, &uuid);
|
|
|
|
|
|
|
|
if ((ext = strrchr(file, '.'))) {
|
|
|
|
ext++;
|
|
|
|
} else {
|
|
|
|
ext = "wav";
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp_file = switch_core_session_sprintf(session, "%s%smsg_%s.%s",
|
|
|
|
SWITCH_GLOBAL_dirs.temp_dir, SWITCH_PATH_SEPARATOR, uuid_str, ext);
|
|
|
|
|
|
|
|
switch_core_session_get_read_impl(session, &read_impl);
|
|
|
|
|
|
|
|
new_fh.channels = read_impl.number_of_channels;
|
|
|
|
new_fh.native_rate = read_impl.actual_samples_per_second;
|
|
|
|
|
|
|
|
|
|
|
|
if (switch_core_file_open(&new_fh,
|
|
|
|
tmp_file,
|
|
|
|
new_fh.channels,
|
|
|
|
read_impl.actual_samples_per_second, SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to open file %s\n", tmp_file);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (switch_core_file_open(&orig_fh,
|
|
|
|
file,
|
|
|
|
new_fh.channels,
|
|
|
|
read_impl.actual_samples_per_second, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to open file %s\n", file);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
switch_zmalloc(abuf, START_SAMPLES * sizeof(*abuf));
|
|
|
|
|
|
|
|
if (switch_test_flag((&orig_fh), SWITCH_FILE_NATIVE)) {
|
|
|
|
asis = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (switch_channel_ready(channel)) {
|
|
|
|
olen = START_SAMPLES;
|
|
|
|
|
|
|
|
if (!asis) {
|
|
|
|
olen /= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((sample_count + olen) > sample_point) {
|
|
|
|
olen = sample_point - sample_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!olen || switch_core_file_read(&orig_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
sample_count += olen;
|
|
|
|
|
|
|
|
switch_core_file_write(&new_fh, abuf, &olen);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch_core_file_close(&orig_fh);
|
|
|
|
|
|
|
|
|
|
|
|
if (switch_core_file_open(&orig_fh,
|
|
|
|
insert_file,
|
|
|
|
new_fh.channels,
|
|
|
|
read_impl.actual_samples_per_second, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to open file %s\n", file);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
while (switch_channel_ready(channel)) {
|
|
|
|
olen = START_SAMPLES;
|
|
|
|
|
|
|
|
if (!asis) {
|
|
|
|
olen /= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (switch_core_file_read(&orig_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
sample_count += olen;
|
|
|
|
|
|
|
|
switch_core_file_write(&new_fh, abuf, &olen);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch_core_file_close(&orig_fh);
|
|
|
|
|
|
|
|
if (switch_core_file_open(&orig_fh,
|
|
|
|
file,
|
|
|
|
new_fh.channels,
|
|
|
|
read_impl.actual_samples_per_second, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to open file %s\n", file);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = 0;
|
|
|
|
switch_core_file_seek(&orig_fh, &pos, sample_point, SEEK_SET);
|
|
|
|
|
|
|
|
while (switch_channel_ready(channel)) {
|
|
|
|
olen = START_SAMPLES;
|
|
|
|
|
|
|
|
if (!asis) {
|
|
|
|
olen /= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (switch_core_file_read(&orig_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
sample_count += olen;
|
|
|
|
|
|
|
|
switch_core_file_write(&new_fh, abuf, &olen);
|
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
if (switch_test_flag((&orig_fh), SWITCH_FILE_OPEN)) {
|
|
|
|
switch_core_file_close(&orig_fh);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (switch_test_flag((&new_fh), SWITCH_FILE_OPEN)) {
|
|
|
|
switch_core_file_close(&new_fh);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch_file_rename(tmp_file, file, switch_core_session_get_pool(session));
|
|
|
|
unlink(tmp_file);
|
|
|
|
|
|
|
|
switch_safe_free(abuf);
|
|
|
|
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-08 18:09:06 +00:00
|
|
|
|
2006-11-27 22:30:48 +00:00
|
|
|
/* For Emacs:
|
|
|
|
* Local Variables:
|
|
|
|
* mode:c
|
2008-02-03 22:14:57 +00:00
|
|
|
* indent-tabs-mode:t
|
2006-11-27 22:30:48 +00:00
|
|
|
* tab-width:4
|
|
|
|
* c-basic-offset:4
|
|
|
|
* End:
|
|
|
|
* For VIM:
|
2008-07-03 19:12:26 +00:00
|
|
|
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
|
2006-11-27 22:30:48 +00:00
|
|
|
*/
|