提交 dec2ae05 authored 作者: Anthony Minessale's avatar Anthony Minessale

more ivr goodies

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@705 d0543943-73ff-0310-b7d9-9358b9ac24b2
上级 12094ad7
......@@ -80,7 +80,9 @@ SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_count(switch_core_sessio
unsigned int buflen,
unsigned int maxdigits,
const char *terminators,
char *terminator);
char *terminator,
unsigned int timeout,
unsigned int poll_channel);
/*!
\brief play a file from the disk to the session
......@@ -121,6 +123,18 @@ SWITCH_DECLARE(switch_status) switch_ivr_record_file(switch_core_session *sessio
unsigned int buflen);
/*!
\brief Speak given text with given tts engine
\param session the session to speak on
\param voice_name the desired voice
\param timer_name optional timer to use for async behaviour
\param rate the sample rate
\param dtmf_callback code to execute if any dtmf is dialed during the audio
\param text the text to speak
\param buf an option data pointer to pass to the callback or a string to put encountered digits in
\param buflen the len of buf
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status) switch_ivr_speak_text(switch_core_session *session,
char *tts_name,
char *voice_name,
......@@ -131,6 +145,17 @@ SWITCH_DECLARE(switch_status) switch_ivr_speak_text(switch_core_session *session
void *buf,
unsigned int buflen);
/*!
\brief Bridge Audio from one session to another
\param session one session
\param peer_session the other session
\param timelimit maximum number of seconds to wait for both channels to be answered
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_session *session,
switch_core_session *peer_session,
unsigned int timelimit);
/** @} */
#ifdef __cplusplus
......
......@@ -36,159 +36,13 @@
static const char modname[] = "mod_bridgecall";
struct audio_bridge_data {
switch_core_session *session_a;
switch_core_session *session_b;
int running;
};
static void *audio_bridge_thread(switch_thread *thread, void *obj)
{
struct switch_core_thread_session *data = obj;
int *stream_id_p;
int stream_id = 0, ans_a = 0, ans_b = 0;
switch_channel *chan_a, *chan_b;
switch_frame *read_frame;
switch_core_session *session_a, *session_b;
session_a = data->objs[0];
session_b = data->objs[1];
stream_id_p = data->objs[2];
if (stream_id_p) {
stream_id = *stream_id_p;
}
chan_a = switch_core_session_get_channel(session_a);
chan_b = switch_core_session_get_channel(session_b);
ans_a = switch_channel_test_flag(chan_a, CF_ANSWERED);
ans_b = switch_channel_test_flag(chan_b, CF_ANSWERED);
while (data->running > 0) {
switch_channel_state b_state = switch_channel_get_state(chan_b);
switch (b_state) {
case CS_HANGUP:
data->running = -1;
continue;
break;
default:
break;
}
/* If this call is running on early media and it answers for real, pass it along... */
if (!ans_b && switch_channel_test_flag(chan_a, CF_ANSWERED)) {
if (!switch_channel_test_flag(chan_b, CF_ANSWERED)) {
switch_channel_answer(chan_b);
}
ans_b++;
}
if (!ans_a && switch_channel_test_flag(chan_b, CF_ANSWERED)) {
if (!switch_channel_test_flag(chan_a, CF_ANSWERED)) {
switch_channel_answer(chan_a);
}
ans_a++;
}
/* if 1 channel has DTMF pass it to the other */
if (switch_channel_has_dtmf(chan_a)) {
char dtmf[128];
switch_channel_dequeue_dtmf(chan_a, dtmf, sizeof(dtmf));
switch_core_session_send_dtmf(session_b, dtmf);
}
/* read audio from 1 channel and write it to the other */
if (switch_core_session_read_frame(session_a, &read_frame, -1, stream_id) == SWITCH_STATUS_SUCCESS
&& read_frame->datalen) {
if (switch_core_session_write_frame(session_b, read_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "write: %s Bad Frame.... Bubye!\n", switch_channel_get_name(chan_b));
data->running = -1;
}
} else {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "read: %s Bad Frame.... Bubye!\n", switch_channel_get_name(chan_a));
data->running = -1;
}
}
switch_channel_hangup(chan_b);
data->running = 0;
return NULL;
}
static switch_status audio_bridge_on_hangup(switch_core_session *session)
{
switch_core_session *other_session;
switch_channel *channel = NULL, *other_channel = NULL;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
other_session = switch_channel_get_private(channel);
assert(other_session != NULL);
other_channel = switch_core_session_get_channel(other_session);
assert(other_channel != NULL);
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CUSTOM HANGUP %s kill %s\n", switch_channel_get_name(channel),
switch_channel_get_name(other_channel));
switch_core_session_kill_channel(other_session, SWITCH_SIG_KILL);
switch_core_session_kill_channel(session, SWITCH_SIG_KILL);
return SWITCH_STATUS_SUCCESS;
}
static switch_status audio_bridge_on_ring(switch_core_session *session)
{
switch_channel *channel = NULL;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CUSTOM RING\n");
/* put the channel in a passive state so we can loop audio to it */
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
switch_channel_set_state(channel, CS_TRANSMIT);
return SWITCH_STATUS_FALSE;
}
return SWITCH_STATUS_SUCCESS;
}
static const switch_state_handler_table audio_bridge_peer_state_handlers = {
/*.on_init */ NULL,
/*.on_ring */ audio_bridge_on_ring,
/*.on_execute */ NULL,
/*.on_hangup */ audio_bridge_on_hangup,
/*.on_loopback */ NULL,
/*.on_transmit */ NULL
};
static const switch_state_handler_table audio_bridge_caller_state_handlers = {
/*.on_init */ NULL,
/*.on_ring */ NULL,
/*.on_execute */ NULL,
/*.on_hangup */ audio_bridge_on_hangup,
/*.on_loopback */ NULL,
/*.on_transmit */ NULL
};
static void audio_bridge_function(switch_core_session *session, char *data)
{
switch_channel *caller_channel, *peer_channel;
switch_channel *caller_channel;
switch_core_session *peer_session;
switch_caller_profile *caller_profile, *caller_caller_profile;
char chan_type[128] = { '\0' }, *chan_data;
int timelimit = 60; /* probably a useful option to pass in when there's time */
unsigned int timelimit = 60; /* probably a useful option to pass in when there's time */
caller_channel = switch_core_session_get_channel(session);
assert(caller_channel != NULL);
......@@ -211,76 +65,12 @@ static void audio_bridge_function(switch_core_session *session, char *data)
if (switch_core_session_outgoing_channel(session, chan_type, caller_profile, &peer_session) !=
SWITCH_STATUS_SUCCESS) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "DOH!\n");
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cannot Create Outgoing Channel!\n");
switch_channel_hangup(caller_channel);
return;
} else {
struct switch_core_thread_session this_audio_thread, other_audio_thread;
time_t start;
int stream_id = 0;
peer_channel = switch_core_session_get_channel(peer_session);
memset(&other_audio_thread, 0, sizeof(other_audio_thread));
memset(&this_audio_thread, 0, sizeof(this_audio_thread));
other_audio_thread.objs[0] = session;
other_audio_thread.objs[1] = peer_session;
other_audio_thread.objs[2] = &stream_id;
other_audio_thread.running = 5;
this_audio_thread.objs[0] = peer_session;
this_audio_thread.objs[1] = session;
this_audio_thread.objs[2] = &stream_id;
this_audio_thread.running = 2;
switch_channel_set_private(caller_channel, peer_session);
switch_channel_set_private(peer_channel, session);
switch_channel_add_state_handler(caller_channel, &audio_bridge_caller_state_handlers);
switch_channel_add_state_handler(peer_channel, &audio_bridge_peer_state_handlers);
switch_core_session_thread_launch(peer_session);
for (;;) {
int state = switch_channel_get_state(peer_channel);
if (state > CS_RING) {
break;
}
switch_yield(1000);
}
time(&start);
while (switch_channel_get_state(caller_channel) == CS_EXECUTE &&
switch_channel_get_state(peer_channel) == CS_TRANSMIT &&
!switch_channel_test_flag(peer_channel, CF_ANSWERED) &&
!switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA) &&
((time(NULL) - start) < timelimit)) {
switch_yield(20000);
}
if (switch_channel_test_flag(peer_channel, CF_ANSWERED)) {
switch_channel_answer(caller_channel);
}
if (switch_channel_test_flag(peer_channel, CF_ANSWERED) ||
switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA)) {
switch_core_session_launch_thread(session, audio_bridge_thread, (void *) &other_audio_thread);
audio_bridge_thread(NULL, (void *) &this_audio_thread);
switch_channel_hangup(peer_channel);
if (other_audio_thread.running > 0) {
other_audio_thread.running = -1;
/* wait for the other audio thread */
while (other_audio_thread.running) {
switch_yield(1000);
}
}
}
switch_ivr_multi_threaded_bridge(session, peer_session, timelimit);
}
switch_channel_hangup(caller_channel);
switch_channel_hangup(peer_channel);
}
......
......@@ -157,7 +157,7 @@ static void ivrtest_function(switch_core_session *session, char *data)
}
}
if (switch_ivr_collect_digits_count(session, buf, sizeof(buf), 10, "#*", &term) != SWITCH_STATUS_SUCCESS) {
if (switch_ivr_collect_digits_count(session, buf, sizeof(buf), 10, "#*", &term, 10000, 1) != SWITCH_STATUS_SUCCESS) {
switch_channel_hangup(channel);
break;
}
......
......@@ -857,7 +857,9 @@ SWITCH_MOD_DECLARE(switch_status) switch_module_runtime(void)
int refresh;
struct iax_event *iaxevent = NULL;
switch_event *s_event;
load_config();
if (load_config() != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_TERM;
}
if (globals.debug) {
iax_enable_debug();
......
......@@ -69,6 +69,7 @@ all: depends $(MODNAME).so
depends:
MAKE=$(MAKE) $(BASE)/build/buildlib.sh $(BASE) mozilla --prefix=$(PREFIX)
MAKE=$(MAKE) $(BASE)/build/buildlib.sh $(BASE) install curl-7.15.2.tar.gz --prefix=$(PREFIX)
$(MODNAME).so: $(MODNAME).c
$(CC) $(CFLAGS) -fPIC -c $(MODNAME).c -o $(MODNAME).o
......
......@@ -77,27 +77,44 @@ SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_count(switch_core_sessio
unsigned int buflen,
unsigned int maxdigits,
const char *terminators,
char *terminator)
char *terminator,
unsigned int timeout,
unsigned int poll_channel
)
{
unsigned int i = 0, x = (unsigned int) strlen(buf);
switch_channel *channel;
switch_status status = SWITCH_STATUS_SUCCESS;
switch_time_t started = 0;
unsigned int elapsed;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
*terminator = '\0';
for (i = 0 ; i < x; i++) {
if (strchr(terminators, buf[i])) {
*terminator = buf[i];
return SWITCH_STATUS_SUCCESS;
if (terminators) {
for (i = 0 ; i < x; i++) {
if (strchr(terminators, buf[i])) {
*terminator = buf[i];
return SWITCH_STATUS_SUCCESS;
}
}
}
if (timeout) {
started = switch_time_now();
}
while (switch_channel_get_state(channel) == CS_EXECUTE) {
switch_frame *read_frame;
if (timeout) {
elapsed = (switch_time_now() - started) / 1000;
if (elapsed >= timeout) {
break;
}
}
if (switch_channel_has_dtmf(channel)) {
char dtmf[128];
switch_channel_dequeue_dtmf(channel, dtmf, sizeof(dtmf));
......@@ -116,9 +133,12 @@ SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_count(switch_core_sessio
}
}
}
if ((status = switch_core_session_read_frame(session, &read_frame, -1, 0)) != SWITCH_STATUS_SUCCESS) {
break;
if (poll_channel) {
if ((status = switch_core_session_read_frame(session, &read_frame, -1, 0)) != SWITCH_STATUS_SUCCESS) {
break;
}
} else {
switch_yield(1000);
}
}
......@@ -639,7 +659,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_speak_text(switch_core_session *session
}
}
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "done playing file\n");
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "done speaking text\n");
switch_core_codec_destroy(&codec);
flags = 0;
switch_core_codec_destroy(&codec);
......@@ -654,4 +674,225 @@ SWITCH_DECLARE(switch_status) switch_ivr_speak_text(switch_core_session *session
}
/* Bridge Related Stuff*/
/*********************************************************************************/
struct audio_bridge_data {
switch_core_session *session_a;
switch_core_session *session_b;
int running;
};
static void *audio_bridge_thread(switch_thread *thread, void *obj)
{
struct switch_core_thread_session *data = obj;
int *stream_id_p;
int stream_id = 0, ans_a = 0, ans_b = 0;
switch_channel *chan_a, *chan_b;
switch_frame *read_frame;
switch_core_session *session_a, *session_b;
session_a = data->objs[0];
session_b = data->objs[1];
stream_id_p = data->objs[2];
if (stream_id_p) {
stream_id = *stream_id_p;
}
chan_a = switch_core_session_get_channel(session_a);
chan_b = switch_core_session_get_channel(session_b);
ans_a = switch_channel_test_flag(chan_a, CF_ANSWERED);
ans_b = switch_channel_test_flag(chan_b, CF_ANSWERED);
while (data->running > 0) {
switch_channel_state b_state = switch_channel_get_state(chan_b);
switch (b_state) {
case CS_HANGUP:
data->running = -1;
continue;
break;
default:
break;
}
/* If this call is running on early media and it answers for real, pass it along... */
if (!ans_b && switch_channel_test_flag(chan_a, CF_ANSWERED)) {
if (!switch_channel_test_flag(chan_b, CF_ANSWERED)) {
switch_channel_answer(chan_b);
}
ans_b++;
}
if (!ans_a && switch_channel_test_flag(chan_b, CF_ANSWERED)) {
if (!switch_channel_test_flag(chan_a, CF_ANSWERED)) {
switch_channel_answer(chan_a);
}
ans_a++;
}
/* if 1 channel has DTMF pass it to the other */
if (switch_channel_has_dtmf(chan_a)) {
char dtmf[128];
switch_channel_dequeue_dtmf(chan_a, dtmf, sizeof(dtmf));
switch_core_session_send_dtmf(session_b, dtmf);
}
/* read audio from 1 channel and write it to the other */
if (switch_core_session_read_frame(session_a, &read_frame, -1, stream_id) == SWITCH_STATUS_SUCCESS
&& read_frame->datalen) {
if (switch_core_session_write_frame(session_b, read_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "write: %s Bad Frame.... Bubye!\n", switch_channel_get_name(chan_b));
data->running = -1;
}
} else {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "read: %s Bad Frame.... Bubye!\n", switch_channel_get_name(chan_a));
data->running = -1;
}
}
switch_channel_hangup(chan_b);
data->running = 0;
return NULL;
}
static switch_status audio_bridge_on_hangup(switch_core_session *session)
{
switch_core_session *other_session;
switch_channel *channel = NULL, *other_channel = NULL;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
other_session = switch_channel_get_private(channel);
assert(other_session != NULL);
other_channel = switch_core_session_get_channel(other_session);
assert(other_channel != NULL);
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CUSTOM HANGUP %s kill %s\n", switch_channel_get_name(channel),
switch_channel_get_name(other_channel));
switch_core_session_kill_channel(other_session, SWITCH_SIG_KILL);
switch_core_session_kill_channel(session, SWITCH_SIG_KILL);
return SWITCH_STATUS_SUCCESS;
}
static switch_status audio_bridge_on_ring(switch_core_session *session)
{
switch_channel *channel = NULL;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CUSTOM RING\n");
/* put the channel in a passive state so we can loop audio to it */
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
switch_channel_set_state(channel, CS_TRANSMIT);
return SWITCH_STATUS_FALSE;
}
return SWITCH_STATUS_SUCCESS;
}
static const switch_state_handler_table audio_bridge_peer_state_handlers = {
/*.on_init */ NULL,
/*.on_ring */ audio_bridge_on_ring,
/*.on_execute */ NULL,
/*.on_hangup */ audio_bridge_on_hangup,
/*.on_loopback */ NULL,
/*.on_transmit */ NULL
};
static const switch_state_handler_table audio_bridge_caller_state_handlers = {
/*.on_init */ NULL,
/*.on_ring */ NULL,
/*.on_execute */ NULL,
/*.on_hangup */ audio_bridge_on_hangup,
/*.on_loopback */ NULL,
/*.on_transmit */ NULL
};
SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_session *session,
switch_core_session *peer_session,
unsigned int timelimit)
{
struct switch_core_thread_session this_audio_thread, other_audio_thread;
switch_channel *caller_channel, *peer_channel;
time_t start;
int stream_id = 0;
caller_channel = switch_core_session_get_channel(session);
assert(caller_channel != NULL);
peer_channel = switch_core_session_get_channel(peer_session);
assert(peer_channel != NULL);
memset(&other_audio_thread, 0, sizeof(other_audio_thread));
memset(&this_audio_thread, 0, sizeof(this_audio_thread));
other_audio_thread.objs[0] = session;
other_audio_thread.objs[1] = peer_session;
other_audio_thread.objs[2] = &stream_id;
other_audio_thread.running = 5;
this_audio_thread.objs[0] = peer_session;
this_audio_thread.objs[1] = session;
this_audio_thread.objs[2] = &stream_id;
this_audio_thread.running = 2;
switch_channel_set_private(caller_channel, peer_session);
switch_channel_set_private(peer_channel, session);
switch_channel_add_state_handler(caller_channel, &audio_bridge_caller_state_handlers);
switch_channel_add_state_handler(peer_channel, &audio_bridge_peer_state_handlers);
switch_core_session_thread_launch(peer_session);
for (;;) {
int state = switch_channel_get_state(peer_channel);
if (state > CS_RING) {
break;
}
switch_yield(1000);
}
time(&start);
while (switch_channel_get_state(caller_channel) == CS_EXECUTE &&
switch_channel_get_state(peer_channel) == CS_TRANSMIT &&
!switch_channel_test_flag(peer_channel, CF_ANSWERED) &&
!switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA) &&
((time(NULL) - start) < timelimit)) {
switch_yield(20000);
}
if (switch_channel_test_flag(peer_channel, CF_ANSWERED)) {
switch_channel_answer(caller_channel);
}
if (switch_channel_test_flag(peer_channel, CF_ANSWERED) ||
switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA)) {
switch_core_session_launch_thread(session, audio_bridge_thread, (void *) &other_audio_thread);
audio_bridge_thread(NULL, (void *) &this_audio_thread);
switch_channel_hangup(peer_channel);
if (other_audio_thread.running > 0) {
other_audio_thread.running = -1;
/* wait for the other audio thread */
while (other_audio_thread.running) {
switch_yield(1000);
}
}
}
return SWITCH_STATUS_SUCCESS;
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论