[Freeswitch-svn] [commit] r4785 - in freeswitch/trunk/src: . include mod/applications/mod_commands mod/applications/mod_dptools mod/applications/mod_ivrtest
Freeswitch SVN
anthm at freeswitch.org
Wed Mar 28 19:37:12 EDT 2007
Author: anthm
Date: Wed Mar 28 19:37:12 2007
New Revision: 4785
Modified:
freeswitch/trunk/src/include/switch_core.h
freeswitch/trunk/src/include/switch_ivr.h
freeswitch/trunk/src/include/switch_types.h
freeswitch/trunk/src/mod/applications/mod_commands/mod_commands.c
freeswitch/trunk/src/mod/applications/mod_dptools/mod_dptools.c
freeswitch/trunk/src/mod/applications/mod_ivrtest/mod_ivrtest.c
freeswitch/trunk/src/switch_channel.c
freeswitch/trunk/src/switch_core.c
freeswitch/trunk/src/switch_ivr.c
Log:
Addition of scheduler engine and a few applications to use it.
This patch adds a scheduler thread to the core and moves the heartbeat
event to use the new scheduler as an example.
Also The following features are implemented that use this scheduler:
sched_hangup dialplan application:
<action application="sched_hangup" data="+10 normal_clearing bleg"/>
** The cause code is optional and the optional bleg keyword will only hangup the
channel the current channel is bridged to if the call is in a bridge.
sched_transfer dialplan application:
<action application="sched_transfer" data="+10 1000 XML default"/>
** The last 2 args (dialplan and context) are optional
sched_broadcast dialplan application:
<action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/>
<action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/>
** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file.
sched_hangup api function:
sched_hangup +10 <uuid_string> normal_clearing
** The cause code is optional
sched_transfer api function:
sched_transfer +10 <uuid_string> 1000 XML default
** The last 2 args (dialplan and context) are optional
sched_broadcast api function:
sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav
sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav
** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file.
The new C functions in the core are documented in the doxeygen.
*NOTE* This commit should satisfy at least 2 bounties on the wiki
Modified: freeswitch/trunk/src/include/switch_core.h
==============================================================================
--- freeswitch/trunk/src/include/switch_core.h (original)
+++ freeswitch/trunk/src/include/switch_core.h Wed Mar 28 19:37:12 2007
@@ -104,17 +104,68 @@
struct switch_core_runtime;
struct switch_core_port_allocator;
+struct switch_core_scheduler_task {
+ time_t created;
+ time_t runtime;
+ uint32_t cmd_id;
+ char *group;
+ void *cmd_arg;
+ uint32_t task_id;
+};
+
+
/*!
\defgroup core1 Core Library
\ingroup FREESWITCH
\{
*/
-
///\defgroup mb1 Media Bugs
///\ingroup core1
///\{
+
+///\defgroup sched1 Scheduler
+///\ingroup core1
+///\{
+
+
+/*!
+ \brief Schedule a task in the future
+ \param runtime the time in epoch seconds to execute the task.
+ \param func the callback function to execute when the task is executed.
+ \param desc an arbitrary description of the task.
+ \param group a group id tag to link multiple tasks to a single entity.
+ \param cmd_id an arbitrary index number be used in the callback.
+ \param cmd_arg user data to be passed to the callback.
+ \param flags flags to alter behaviour
+ \return the id of the task
+*/
+SWITCH_DECLARE(uint32_t) switch_core_scheduler_add_task(time_t task_runtime,
+ switch_core_scheduler_func_t func,
+ char *desc,
+ char *group,
+ uint32_t cmd_id,
+ void *cmd_arg,
+ switch_scheduler_flag_t flags);
+
+/*!
+ \brief Delete a scheduled task
+ \param task_id the id of the task
+ \return SWITCH_STATUS_SUCCESS if the task was deleted.
+*/
+SWITCH_DECLARE(switch_status_t) switch_core_scheduler_del_task_id(uint32_t task_id);
+
+/*!
+ \brief Delete a scheduled task based on the group name
+ \param group the group name
+ \return SWITCH_STATUS_SUCCESS if any tasks were deleted
+*/
+SWITCH_DECLARE(switch_status_t) switch_core_scheduler_del_task_group(char *group);
+
+
+///\}
+
/*!
\brief Add a media bug to the session
\param session the session to add the bug to
Modified: freeswitch/trunk/src/include/switch_ivr.h
==============================================================================
--- freeswitch/trunk/src/include/switch_ivr.h (original)
+++ freeswitch/trunk/src/include/switch_ivr.h Wed Mar 28 19:37:12 2007
@@ -332,6 +332,28 @@
SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_t *session, char *extension, char *dialplan, char *context);
/*!
+ \brief Transfer an existing session to another location in the future
+ \param runtime the time (int epoch seconds) to transfer the call
+ \param uuid the uuid of the session to transfer
+ \param extension the new extension
+ \param dialplan the new dialplan (OPTIONAL, may be NULL)
+ \param context the new context (OPTIONAL, may be NULL)
+ \return the id of the task
+*/
+SWITCH_DECLARE(uint32_t) switch_ivr_schedule_transfer(time_t runtime, char *uuid, char *extension, char *dialplan, char *context);
+
+
+/*!
+ \brief Hangup an existing session in the future
+ \param runtime the time (int epoch seconds) to transfer the call
+ \param uuid the uuid of the session to hangup
+ \param cause the hanup cause code
+ \param bleg hangup up the B-Leg if possible
+ \return the id of the task
+*/
+SWITCH_DECLARE(uint32_t) switch_ivr_schedule_hangup(time_t runtime, char *uuid, switch_call_cause_t cause, switch_bool_t bleg);
+
+/*!
\brief Bridge two existing sessions
\param originator_uuid the uuid of the originator
\param originatee_uuid the uuid of the originator
@@ -384,6 +406,16 @@
SWITCH_DECLARE(switch_status_t) switch_ivr_unhold(switch_core_session_t *session);
/*!
+ \brief Signal the session to broadcast audio in the future
+ \param runtime when (in epoch time) to run the broadcast
+ \param uuid the uuid of the session to broadcast on
+ \param path the path data of the broadcast "/path/to/file.wav [<timer name>]" or "speak:<engine>|<voice>|<Text to say>"
+ \param flags flags to send to the request (SMF_ECHO_BRIDGED to send the broadcast to both sides of the call)
+ \return the id of the task
+*/
+SWITCH_DECLARE(uint32_t) switch_ivr_schedule_broadcast(time_t runtime, char *uuid, char *path, switch_media_flag_t flags);
+
+/*!
\brief Signal the session to broadcast audio
\param uuid the uuid of the session to broadcast on
\param path the path data of the broadcast "/path/to/file.wav [<timer name>]" or "speak:<engine>|<voice>|<Text to say>"
Modified: freeswitch/trunk/src/include/switch_types.h
==============================================================================
--- freeswitch/trunk/src/include/switch_types.h (original)
+++ freeswitch/trunk/src/include/switch_types.h Wed Mar 28 19:37:12 2007
@@ -168,6 +168,12 @@
} switch_management_action_t;
typedef enum {
+ SSHF_NONE = 0,
+ SSHF_OWN_THREAD = (1 << 0),
+ SSHF_FREE_ARG = (1 << 1)
+} switch_scheduler_flag_t;
+
+typedef enum {
SMF_NONE = 0,
SMF_REBRIDGE = (1 << 0),
SMF_ECHO_ALEG = (1 << 1),
@@ -910,7 +916,8 @@
SWITCH_CAUSE_LOSE_RACE = 502,
SWITCH_CAUSE_MANAGER_REQUEST = 503,
SWITCH_CAUSE_BLIND_TRANSFER = 600,
- SWITCH_CAUSE_ATTENDED_TRANSFER = 601
+ SWITCH_CAUSE_ATTENDED_TRANSFER = 601,
+ SWITCH_CAUSE_ALLOTTED_TIMEOUT = 602
} switch_call_cause_t;
typedef enum {
@@ -979,6 +986,8 @@
typedef void (*switch_application_function_t)(switch_core_session_t *, char *);
typedef void (*switch_event_callback_t)(switch_event_t *);
typedef switch_caller_extension_t *(*switch_dialplan_hunt_function_t)(switch_core_session_t *, void *);
+typedef struct switch_core_scheduler_task switch_core_scheduler_task_t;
+typedef void (*switch_core_scheduler_func_t)(switch_core_scheduler_task_t *task);
typedef switch_status_t (*switch_state_handler_t)(switch_core_session_t *);
typedef switch_status_t (*switch_outgoing_channel_hook_t)(switch_core_session_t *, switch_caller_profile_t *, switch_core_session_t *);
typedef switch_status_t (*switch_answer_channel_hook_t)(switch_core_session_t *);
Modified: freeswitch/trunk/src/mod/applications/mod_commands/mod_commands.c
==============================================================================
--- freeswitch/trunk/src/mod/applications/mod_commands/mod_commands.c (original)
+++ freeswitch/trunk/src/mod/applications/mod_commands/mod_commands.c Wed Mar 28 19:37:12 2007
@@ -51,6 +51,9 @@
static switch_api_interface_t media_api_interface;
static switch_api_interface_t hold_api_interface;
static switch_api_interface_t broadcast_api_interface;
+static switch_api_interface_t sched_broadcast_api_interface;
+static switch_api_interface_t sched_transfer_api_interface;
+static switch_api_interface_t sched_hangup_api_interface;
static switch_status_t status_function(char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream)
{
@@ -245,6 +248,89 @@
return SWITCH_STATUS_SUCCESS;
}
+
+static switch_status_t sched_transfer_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream)
+{
+ switch_core_session_t *session = NULL;
+ char *argv[6] = {0};
+ int argc = 0;
+
+ if (isession) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+
+ if (switch_strlen_zero(cmd) || argc < 2 || argc > 5) {
+ stream->write_function(stream, "USAGE: %s\n", sched_transfer_api_interface.syntax);
+ } else {
+ char *uuid = argv[1];
+ char *dest = argv[2];
+ char *dp = argv[3];
+ char *context = argv[4];
+ time_t when;
+
+ if (*argv[0] == '+') {
+ when = time (NULL) + atol(argv[0] + 1);
+ } else {
+ when = atol(argv[0]);
+ }
+
+ if ((session = switch_core_session_locate(uuid))) {
+ switch_ivr_schedule_transfer(when, uuid, dest, dp, context);
+ stream->write_function(stream, "OK\n");
+ switch_core_session_rwunlock(session);
+ } else {
+ stream->write_function(stream, "No Such Channel!\n");
+ }
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t sched_hangup_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream)
+{
+ switch_core_session_t *session = NULL;
+ char *argv[4] = {0};
+ int argc = 0;
+
+ if (isession) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+
+ if (switch_strlen_zero(cmd) || argc < 1) {
+ stream->write_function(stream, "USAGE: %s\n", sched_hangup_api_interface.syntax);
+ } else {
+ char *uuid = argv[1];
+ char *cause_str = argv[2];
+ time_t when;
+ switch_call_cause_t cause = SWITCH_CAUSE_ALLOTTED_TIMEOUT;
+
+ if (*argv[0] == '+') {
+ when = time (NULL) + atol(argv[0] + 1);
+ } else {
+ when = atol(argv[0]);
+ }
+
+ if (cause_str) {
+ cause = switch_channel_str2cause(cause_str);
+ }
+
+ if ((session = switch_core_session_locate(uuid))) {
+ switch_ivr_schedule_hangup(when, uuid, cause, SWITCH_FALSE);
+ stream->write_function(stream, "OK\n");
+ switch_core_session_rwunlock(session);
+ } else {
+ stream->write_function(stream, "No Such Channel!\n");
+ }
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
static switch_status_t uuid_media_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream)
{
char *argv[4] = {0};
@@ -313,6 +399,50 @@
return SWITCH_STATUS_SUCCESS;
}
+
+static switch_status_t sched_broadcast_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream)
+{
+ char *argv[4] = {0};
+ int argc = 0;
+ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ if (isession) {
+ return status;
+ }
+
+ argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+
+ if (switch_strlen_zero(cmd) || argc < 3) {
+ stream->write_function(stream, "USAGE: %s\n", sched_broadcast_api_interface.syntax);
+ } else {
+ switch_media_flag_t flags = SMF_NONE;
+ time_t when;
+
+ if (*argv[0] == '+') {
+ when = time (NULL) + atol(argv[0] + 1);
+ } else {
+ when = atol(argv[0]);
+ }
+
+ if (argv[3]) {
+ if (!strcmp(argv[3], "both")) {
+ flags |= (SMF_ECHO_ALEG | SMF_ECHO_BLEG);
+ } else if (!strcmp(argv[3], "aleg")) {
+ flags |= SMF_ECHO_ALEG;
+ } else if (!strcmp(argv[3], "bleg")) {
+ flags |= SMF_ECHO_BLEG;
+ }
+ } else {
+ flags |= SMF_ECHO_ALEG;
+ }
+
+ status = switch_ivr_schedule_broadcast(when, argv[1], argv[2], flags);
+ stream->write_function(stream, "+OK Message Scheduled\n");
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
static switch_status_t uuid_hold_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream)
{
char *argv[4] = {0};
@@ -707,12 +837,36 @@
return SWITCH_STATUS_SUCCESS;
}
+static switch_api_interface_t sched_transfer_api_interface = {
+ /*.interface_name */ "sched_transfer",
+ /*.desc */ "Schedule a broadcast event to a running call",
+ /*.function */ sched_transfer_function,
+ /*.syntax */ "[+]<time> <uuid> <extension> [<dialplan>] [<context>]",
+ /*.next */ NULL
+};
+
+static switch_api_interface_t sched_broadcast_api_interface = {
+ /*.interface_name */ "sched_broadcast",
+ /*.desc */ "Schedule a broadcast event to a running call",
+ /*.function */ sched_broadcast_function,
+ /*.syntax */ "[+]<time> <uuid> <path> [aleg|bleg|both]",
+ /*.next */ &sched_transfer_api_interface
+};
+
+static switch_api_interface_t sched_hangup_api_interface = {
+ /*.interface_name */ "sched_hangup",
+ /*.desc */ "Schedule a running call to hangup",
+ /*.function */ sched_hangup_function,
+ /*.syntax */ "[+]<time> <uuid> [<cause>]",
+ /*.next */ &sched_broadcast_api_interface
+};
+
static switch_api_interface_t version_api_interface = {
/*.interface_name */ "version",
/*.desc */ "Show version of the switch",
/*.function */ version_function,
/*.syntax */ "",
- /*.next */ NULL
+ /*.next */ &sched_hangup_api_interface
};
static switch_api_interface_t help_api_interface = {
Modified: freeswitch/trunk/src/mod/applications/mod_dptools/mod_dptools.c
==============================================================================
--- freeswitch/trunk/src/mod/applications/mod_dptools/mod_dptools.c (original)
+++ freeswitch/trunk/src/mod/applications/mod_dptools/mod_dptools.c Wed Mar 28 19:37:12 2007
@@ -96,6 +96,99 @@
}
}
+static void sched_transfer_function(switch_core_session_t *session, char *data)
+{
+ int argc;
+ char *argv[4] = {0};
+ char *mydata;
+
+ if (data && (mydata = switch_core_session_strdup(session, data))) {
+ if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) >= 2) {
+ time_t when;
+
+ if (*argv[0] == '+') {
+ when = time (NULL) + atol(argv[0] + 1);
+ } else {
+ when = atol(argv[0]);
+ }
+
+ switch_ivr_schedule_transfer(when, switch_core_session_get_uuid(session), argv[1], argv[2], argv[3]);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Args\n");
+ }
+ }
+}
+
+static void sched_hangup_function(switch_core_session_t *session, char *data)
+{
+ int argc;
+ char *argv[5] = {0};
+ char *mydata;
+
+ if (data && (mydata = switch_core_session_strdup(session, data))) {
+ if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) >= 1) {
+ time_t when;
+ switch_call_cause_t cause = SWITCH_CAUSE_ALLOTTED_TIMEOUT;
+ switch_bool_t bleg = SWITCH_FALSE;
+
+ if (*argv[0] == '+') {
+ when = time (NULL) + atol(argv[0] + 1);
+ } else {
+ when = atol(argv[0]);
+ }
+
+ if (argv[1]) {
+ cause = switch_channel_str2cause(argv[1]);
+ }
+
+ if (argv[2] && !strcasecmp(argv[2], "bleg")) {
+ bleg = SWITCH_TRUE;
+ }
+
+ switch_ivr_schedule_hangup(when, switch_core_session_get_uuid(session), cause, bleg);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No time specified.\n");
+ }
+ }
+}
+
+
+static void sched_broadcast_function(switch_core_session_t *session, char *data)
+{
+ int argc;
+ char *argv[6] = {0};
+ char *mydata;
+
+ if (data && (mydata = switch_core_session_strdup(session, data))) {
+ if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) >= 2) {
+ time_t when;
+ switch_media_flag_t flags = SMF_NONE;
+
+ if (*argv[0] == '+') {
+ when = time (NULL) + atol(argv[0] + 1);
+ } else {
+ when = atol(argv[0]);
+ }
+
+ if (argv[2]) {
+ if (!strcmp(argv[2], "both")) {
+ flags |= (SMF_ECHO_ALEG | SMF_ECHO_BLEG);
+ } else if (!strcmp(argv[2], "aleg")) {
+ flags |= SMF_ECHO_ALEG;
+ } else if (!strcmp(argv[2], "bleg")) {
+ flags |= SMF_ECHO_BLEG;
+ }
+ } else {
+ flags |= SMF_ECHO_ALEG;
+ }
+
+ switch_ivr_schedule_broadcast(when, switch_core_session_get_uuid(session), argv[1], flags);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Args\n");
+ }
+ }
+}
+
static void sleep_function(switch_core_session_t *session, char *data)
{
@@ -509,6 +602,7 @@
}
}
+
static switch_api_interface_t strepoch_api_interface = {
/*.interface_name */ "strepoch",
/*.desc */ "Convert a date string into epoch time",
@@ -541,6 +635,39 @@
/*.next */ &dptools_api_interface
};
+
+
+static switch_application_interface_t sched_transfer_application_interface = {
+ /*.interface_name */ "sched_transfer",
+ /*.application_function */ sched_transfer_function,
+ /*.long_desc */ "Schedule a transfer in the future",
+ /*.short_desc */ "Schedule a transfer in the future",
+ /*.syntax */ "[+]<time> <extension> <dialplan> <context>",
+ /* flags */ SAF_SUPPORT_NOMEDIA,
+ /*.next */ NULL
+};
+
+static switch_application_interface_t sched_broadcast_application_interface = {
+ /*.interface_name */ "sched_broadcast",
+ /*.application_function */ sched_broadcast_function,
+ /*.long_desc */ "Schedule a broadcast in the future",
+ /*.short_desc */ "Schedule a broadcast in the future",
+ /*.syntax */ "[+]<time> <path> [aleg|bleg|both]",
+ /* flags */ SAF_SUPPORT_NOMEDIA,
+ /*.next */ &sched_transfer_application_interface
+};
+
+static switch_application_interface_t sched_hangup_application_interface = {
+ /*.interface_name */ "sched_hangup",
+ /*.application_function */ sched_hangup_function,
+ /*.long_desc */ "Schedule a hangup in the future",
+ /*.short_desc */ "Schedule a hangup in the future",
+ /*.syntax */ "[+]<time> [<cause>]",
+ /* flags */ SAF_SUPPORT_NOMEDIA,
+ /*.next */ &sched_broadcast_application_interface
+};
+
+
static const switch_application_interface_t queuedtmf_application_interface = {
/*.interface_name */ "queue_dtmf",
/*.application_function */ queue_dtmf_function,
@@ -548,7 +675,7 @@
/* short_desc */ "Queue dtmf to be sent",
/* syntax */ "<dtmf_data>",
/* flags */ SAF_SUPPORT_NOMEDIA,
- /*.next */ NULL
+ /*.next */ &sched_hangup_application_interface
};
static const switch_application_interface_t redirect_application_interface = {
Modified: freeswitch/trunk/src/mod/applications/mod_ivrtest/mod_ivrtest.c
==============================================================================
--- freeswitch/trunk/src/mod/applications/mod_ivrtest/mod_ivrtest.c (original)
+++ freeswitch/trunk/src/mod/applications/mod_ivrtest/mod_ivrtest.c Wed Mar 28 19:37:12 2007
@@ -233,6 +233,7 @@
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Done\n");
}
+#ifdef BUGTEST
static switch_bool_t bug_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
{
switch_frame_t *frame;
@@ -249,9 +250,11 @@
return SWITCH_TRUE;
}
+#endif
static void bugtest_function(switch_core_session_t *session, char *data)
{
+#ifdef BUGTEST
switch_media_bug_t *bug;
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_status_t status;
@@ -264,6 +267,11 @@
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
return;
}
+#endif
+ //switch_ivr_schedule_broadcast(time(NULL) + 10, switch_core_session_get_uuid(session), "/Users/anthm/sr8k.wav", SMF_ECHO_ALEG);
+ //switch_ivr_schedule_transfer(time(NULL) + 10, switch_core_session_get_uuid(session), "2000", NULL, NULL);
+ //switch_ivr_schedule_hangup(time(NULL) + 10, switch_core_session_get_uuid(session), SWITCH_CAUSE_ALLOTTED_TIMEOUT);
+
switch_ivr_play_file(session, NULL, data, NULL);
}
Modified: freeswitch/trunk/src/switch_channel.c
==============================================================================
--- freeswitch/trunk/src/switch_channel.c (original)
+++ freeswitch/trunk/src/switch_channel.c Wed Mar 28 19:37:12 2007
@@ -95,6 +95,7 @@
{ "MANAGER_REQUEST", SWITCH_CAUSE_MANAGER_REQUEST },
{ "BLIND_TRANSFER", SWITCH_CAUSE_BLIND_TRANSFER },
{ "ATTENDED_TRANSFER", SWITCH_CAUSE_ATTENDED_TRANSFER },
+ { "ALLOTTED_TIMEOUT", SWITCH_CAUSE_ALLOTTED_TIMEOUT},
{ NULL, 0 }
};
Modified: freeswitch/trunk/src/switch_core.c
==============================================================================
--- freeswitch/trunk/src/switch_core.c (original)
+++ freeswitch/trunk/src/switch_core.c Wed Mar 28 19:37:12 2007
@@ -147,6 +147,19 @@
SWITCH_DECLARE_DATA switch_directories SWITCH_GLOBAL_dirs = {0};
+struct switch_core_scheduler_task_container {
+ switch_core_scheduler_task_t task;
+ time_t executed;
+ int in_thread;
+ int destroyed;
+ switch_core_scheduler_func_t func;
+ switch_memory_pool_t *pool;
+ uint32_t flags;
+ char *desc;
+ struct switch_core_scheduler_task_container *next;
+};
+typedef struct switch_core_scheduler_task_container switch_core_scheduler_task_container_t;
+
struct switch_core_runtime {
switch_time_t initiated;
uint32_t session_id;
@@ -169,6 +182,10 @@
uint32_t shutting_down;
uint8_t running;
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
+ switch_core_scheduler_task_container_t *task_list;
+ switch_mutex_t *task_mutex;
+ uint32_t task_id;
+ int task_thread_running;
};
/* Prototypes */
@@ -196,6 +213,238 @@
}
}
+static void send_heartbeat(void)
+{
+ switch_event_t *event;
+ switch_core_time_duration_t duration;
+
+ switch_core_measure_time(switch_core_uptime(), &duration);
+
+ if (switch_event_create(&event, SWITCH_EVENT_HEARTBEAT) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Event-Info", "System Ready");
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Up-Time",
+ "%u year%s, "
+ "%u day%s, "
+ "%u hour%s, "
+ "%u minute%s, "
+ "%u second%s, "
+ "%u millisecond%s, "
+ "%u microsecond%s\n",
+ duration.yr, duration.yr == 1 ? "" : "s",
+ duration.day, duration.day == 1 ? "" : "s",
+ duration.hr, duration.hr == 1 ? "" : "s",
+ duration.min, duration.min == 1 ? "" : "s",
+ duration.sec, duration.sec == 1 ? "" : "s",
+ duration.ms, duration.ms == 1 ? "" : "s",
+ duration.mms, duration.mms == 1 ? "" : "s"
+ );
+
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Session-Count", "%u", switch_core_session_count());
+ switch_event_fire(&event);
+ }
+}
+
+static void heartbeat_callback(switch_core_scheduler_task_t *task)
+{
+ send_heartbeat();
+
+ /* reschedule this task */
+ task->runtime += 20;
+}
+
+static void switch_core_scheduler_execute(switch_core_scheduler_task_container_t *tp)
+{
+ //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Executing task %u %s (%s)\n", tp->task.task_id, tp->desc, switch_str_nil(tp->task.group));
+
+ tp->func(&tp->task);
+
+ if (tp->task.runtime > tp->executed) {
+ tp->executed = 0;
+ } else {
+ tp->destroyed = 1;
+ }
+}
+
+static void *SWITCH_THREAD_FUNC task_own_thread(switch_thread_t *thread, void *obj)
+{
+ switch_core_scheduler_task_container_t *tp = (switch_core_scheduler_task_container_t *) obj;
+ switch_memory_pool_t *pool;
+
+ pool = tp->pool;
+ tp->pool = NULL;
+
+ switch_core_scheduler_execute(tp);
+ switch_core_destroy_memory_pool(&pool);
+ tp->in_thread = 0;
+
+ return NULL;
+}
+
+static int task_thread_loop(int done)
+{
+ switch_core_scheduler_task_container_t *tofree, *tp, *last = NULL;
+
+
+ switch_mutex_lock(runtime.task_mutex);
+ for (tp = runtime.task_list; tp; tp = tp->next) {
+ if (done) {
+ tp->destroyed = 1;
+ } else {
+ time_t now = time(NULL);
+ if (now >= tp->task.runtime && !tp->in_thread) {
+ tp->executed = now;
+ if (switch_test_flag(tp, SSHF_OWN_THREAD)) {
+ switch_thread_t *thread;
+ switch_threadattr_t *thd_attr;
+ assert(switch_core_new_memory_pool(&tp->pool) == SWITCH_STATUS_SUCCESS);
+ switch_threadattr_create(&thd_attr, tp->pool);
+ switch_threadattr_detach_set(thd_attr, 1);
+ tp->in_thread = 1;
+ switch_thread_create(&thread, thd_attr, task_own_thread, tp, tp->pool);
+ } else {
+ switch_core_scheduler_execute(tp);
+ }
+ }
+ }
+ }
+ switch_mutex_unlock(runtime.task_mutex);
+ switch_mutex_lock(runtime.task_mutex);
+ for (tp = runtime.task_list; tp; ) {
+ if (tp->destroyed && !tp->in_thread) {
+ tofree = tp;
+ tp = tp->next;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleting task %u %s (%s)\n",
+ tofree->task.task_id, tofree->desc, switch_str_nil(tofree->task.group));
+ if (last) {
+ last->next = tofree->next;
+ } else {
+ runtime.task_list = tofree->next;
+ }
+ switch_safe_free(tofree->task.group);
+ if (tofree->task.cmd_arg && switch_test_flag(tofree, SSHF_FREE_ARG)) {
+ free(tofree->task.cmd_arg);
+ }
+ switch_safe_free(tofree->desc);
+ free(tofree);
+ } else {
+ last = tp;
+ tp = tp->next;
+ }
+ }
+ switch_mutex_unlock(runtime.task_mutex);
+
+ return done;
+}
+
+static void *SWITCH_THREAD_FUNC switch_core_task_thread(switch_thread_t *thread, void *obj)
+{
+
+ runtime.task_thread_running = 1;
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Starting task thread\n");
+ while(runtime.task_thread_running == 1) {
+ if (task_thread_loop(0)) {
+ break;
+ }
+ switch_yield(500000);
+ }
+
+ task_thread_loop(1);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Task thread ending\n");
+ runtime.task_thread_running = 0;
+
+ return NULL;
+}
+
+static void switch_core_task_thread_launch(void)
+{
+ switch_thread_t *thread;
+ switch_threadattr_t *thd_attr;
+ switch_threadattr_create(&thd_attr, runtime.memory_pool);
+ switch_threadattr_detach_set(thd_attr, 1);
+ switch_thread_create(&thread, thd_attr, switch_core_task_thread, NULL, runtime.memory_pool);
+}
+
+SWITCH_DECLARE(uint32_t) switch_core_scheduler_add_task(time_t task_runtime,
+ switch_core_scheduler_func_t func,
+ char *desc,
+ char *group,
+ uint32_t cmd_id,
+ void *cmd_arg,
+ switch_scheduler_flag_t flags)
+{
+ switch_core_scheduler_task_container_t *container, *tp;
+
+ switch_mutex_lock(runtime.task_mutex);
+ assert((container = malloc(sizeof(*container))));
+ memset(container, 0, sizeof(*container));
+ assert(func);
+ container->func = func;
+ time(&container->task.created);
+ container->task.runtime = task_runtime;
+ container->task.group = strdup(group ? group : "none");
+ container->task.cmd_id = cmd_id;
+ container->task.cmd_arg = cmd_arg;
+ container->flags = flags;
+ container->desc = strdup(desc ? desc : "none");
+
+ for (tp = runtime.task_list; tp && tp->next; tp = tp->next);
+
+ if (tp) {
+ tp->next = container;
+ } else {
+ runtime.task_list = container;
+ }
+
+ for (container->task.task_id = 0; !container->task.task_id; container->task.task_id = ++runtime.task_id);
+
+ switch_mutex_unlock(runtime.task_mutex);
+
+ tp = container;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Added task %u %s (%s) to run at %ld\n",
+ tp->task.task_id, tp->desc, switch_str_nil(tp->task.group), task_runtime);
+
+
+ return container->task.task_id;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_core_scheduler_del_task_id(uint32_t task_id)
+{
+ switch_core_scheduler_task_container_t *tp;
+ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ switch_mutex_lock(runtime.task_mutex);
+ for (tp = runtime.task_list; tp; tp = tp->next) {
+ if (tp->task.task_id == task_id) {
+ tp->destroyed++;
+ status = SWITCH_STATUS_SUCCESS;
+ break;
+ }
+ }
+ switch_mutex_unlock(runtime.task_mutex);
+
+ return status;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_core_scheduler_del_task_group(char *group)
+{
+ switch_core_scheduler_task_container_t *tp;
+ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ switch_mutex_lock(runtime.task_mutex);
+ for (tp = runtime.task_list; tp; tp = tp->next) {
+ if (!strcmp(tp->task.group, group)) {
+ tp->destroyed++;
+ status = SWITCH_STATUS_SUCCESS;
+ }
+ }
+ switch_mutex_unlock(runtime.task_mutex);
+
+ return status;
+}
+
+
static void switch_core_media_bug_destroy(switch_media_bug_t *bug)
{
switch_buffer_destroy(&bug->raw_read_buffer);
@@ -2148,7 +2397,8 @@
}
if (!session->read_codec && (*frame)->codec) {
- need_codec = TRUE;
+ status = SWITCH_STATUS_FALSE;
+ goto done;
}
if (session->bugs && !need_codec) {
@@ -2422,7 +2672,7 @@
}
if (!session->write_codec && frame->codec) {
- need_codec = TRUE;
+ return SWITCH_STATUS_FALSE;
}
if (session->bugs && !need_codec) {
@@ -3153,11 +3403,10 @@
switch_event_t *event;
const switch_application_interface_t *application_interface;
-
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard EXECUTE\n");
+
if ((extension = switch_channel_get_caller_extension(session->channel)) == 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Extension!\n");
- switch_channel_hangup(session->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+ switch_channel_hangup(session->channel, SWITCH_CAUSE_NORMAL_CLEARING);
return;
}
@@ -3731,6 +3980,8 @@
switch_event_t *event;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Close Channel %s\n", switch_channel_get_name((*session)->channel));
+
+ switch_core_scheduler_del_task_group((*session)->uuid_str);
switch_mutex_lock(runtime.session_table_mutex);
switch_core_hash_delete(runtime.session_table, (*session)->uuid_str);
@@ -4143,7 +4394,6 @@
char *sqlbuf = (char *) malloc(sql_len);
char *sql;
switch_size_t newlen;
- uint32_t loops = 0;
if (!runtime.event_db) {
runtime.event_db = switch_core_db_handle();
@@ -4198,38 +4448,6 @@
*sqlbuf = '\0';
}
- if (loops++ >= 5000) {
- switch_event_t *event;
- switch_core_time_duration_t duration;
-
- switch_core_measure_time(switch_core_uptime(), &duration);
-
- if (switch_event_create(&event, SWITCH_EVENT_HEARTBEAT) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Event-Info", "System Ready");
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Up-Time",
- "%u year%s, "
- "%u day%s, "
- "%u hour%s, "
- "%u minute%s, "
- "%u second%s, "
- "%u millisecond%s, "
- "%u microsecond%s\n",
- duration.yr, duration.yr == 1 ? "" : "s",
- duration.day, duration.day == 1 ? "" : "s",
- duration.hr, duration.hr == 1 ? "" : "s",
- duration.min, duration.min == 1 ? "" : "s",
- duration.sec, duration.sec == 1 ? "" : "s",
- duration.ms, duration.ms == 1 ? "" : "s",
- duration.mms, duration.mms == 1 ? "" : "s"
- );
-
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Session-Count", "%u", switch_core_session_count());
- switch_event_fire(&event);
- }
-
- loops = 0;
- }
-
if (nothing_in_queue) {
switch_yield(1000);
}
@@ -4672,11 +4890,17 @@
runtime.running = 1;
switch_core_hash_init(&runtime.session_table, runtime.memory_pool);
switch_mutex_init(&runtime.session_table_mutex, SWITCH_MUTEX_NESTED, runtime.memory_pool);
+ switch_mutex_init(&runtime.task_mutex, SWITCH_MUTEX_NESTED, runtime.memory_pool);
#ifdef CRASH_PROT
switch_core_hash_init(&runtime.stack_table, runtime.memory_pool);
#endif
+
+
+ switch_core_task_thread_launch();
runtime.initiated = switch_time_now();
+ switch_core_scheduler_add_task(time(NULL), heartbeat_callback, "heartbeat", "core", 0, NULL, SSHF_NONE);
+
switch_uuid_get(&uuid);
switch_uuid_format(runtime.uuid_str, &uuid);
@@ -4836,11 +5060,28 @@
while (switch_queue_size(runtime.sql_queue) > 0) {
switch_yield(10000);
}
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Stopping Task Thread\n");
+ if (runtime.task_thread_running == 1) {
+ int sanity = 0;
+
+ runtime.task_thread_running = -1;
+
+ while(runtime.task_thread_running) {
+ switch_yield(100000);
+ if (++sanity > 10) {
+ break;
+ }
+ }
+ }
+
switch_core_db_close(runtime.db);
switch_core_db_close(runtime.event_db);
switch_xml_destroy();
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Finalizing Shutdown.\n");
switch_log_shutdown();
+
+
if(runtime.console != stdout && runtime.console != stderr) {
fclose(runtime.console);
Modified: freeswitch/trunk/src/switch_ivr.c
==============================================================================
--- freeswitch/trunk/src/switch_ivr.c (original)
+++ freeswitch/trunk/src/switch_ivr.c Wed Mar 28 19:37:12 2007
@@ -130,7 +130,7 @@
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");
@@ -3240,6 +3240,157 @@
return SWITCH_STATUS_SUCCESS;
}
+struct hangup_helper {
+ char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
+ switch_bool_t bleg;
+ switch_call_cause_t cause;
+};
+
+static void sch_hangup_callback(switch_core_scheduler_task_t *task)
+{
+ struct hangup_helper *helper;
+ switch_core_session_t *session, *other_session;
+ char *other_uuid;
+
+ assert(task);
+
+ helper = (struct hangup_helper *) task->cmd_arg;
+
+ if ((session = switch_core_session_locate(helper->uuid_str))) {
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+
+ if (helper->bleg) {
+ if ((other_uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) &&
+ (other_session = switch_core_session_locate(other_uuid))) {
+ switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
+ switch_channel_hangup(other_channel, helper->cause);
+ switch_core_session_rwunlock(other_session);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No channel to hangup\n");
+ }
+ } else {
+ switch_channel_hangup(channel, helper->cause);
+ }
+
+ switch_core_session_rwunlock(session);
+ }
+}
+
+SWITCH_DECLARE(uint32_t) switch_ivr_schedule_hangup(time_t runtime, char *uuid, switch_call_cause_t cause, switch_bool_t bleg)
+{
+ struct hangup_helper *helper;
+ size_t len = sizeof(*helper);
+
+ assert((helper = malloc(len)));
+ memset(helper, 0, len);
+
+ switch_copy_string(helper->uuid_str, uuid, sizeof(helper->uuid_str));
+ helper->cause = cause;
+ helper->bleg = bleg;
+
+ return switch_core_scheduler_add_task(runtime, sch_hangup_callback, (char *)__SWITCH_FUNC__, uuid, 0, helper, SSHF_FREE_ARG);
+}
+
+struct transfer_helper {
+ char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
+ char *extension;
+ char *dialplan;
+ char *context;
+};
+
+static void sch_transfer_callback(switch_core_scheduler_task_t *task)
+{
+ struct transfer_helper *helper;
+ switch_core_session_t *session;
+
+ assert(task);
+
+ helper = (struct transfer_helper *) task->cmd_arg;
+
+ if ((session = switch_core_session_locate(helper->uuid_str))) {
+ switch_ivr_session_transfer(session, helper->extension, helper->dialplan, helper->context);
+ switch_core_session_rwunlock(session);
+ }
+
+}
+
+SWITCH_DECLARE(uint32_t) switch_ivr_schedule_transfer(time_t runtime, char *uuid, char *extension, char *dialplan, char *context)
+{
+ struct transfer_helper *helper;
+ size_t len = sizeof(*helper);
+ char *cur = NULL;
+
+ if (extension) {
+ len += strlen(extension) + 1;
+ }
+
+ if (dialplan) {
+ len += strlen(dialplan) + 1;
+ }
+
+ if (context) {
+ len += strlen(context) + 1;
+ }
+
+ assert((helper = malloc(len)));
+ memset(helper, 0, len);
+
+ switch_copy_string(helper->uuid_str, uuid, sizeof(helper->uuid_str));
+
+ cur = (char *) helper + sizeof(*helper);
+
+ if (extension) {
+ helper->extension = cur;
+ switch_copy_string(helper->extension, extension, strlen(extension) + 1);
+ cur += strlen(helper->extension) + 1;
+ }
+
+ if (dialplan) {
+ helper->dialplan = cur;
+ switch_copy_string(helper->dialplan, dialplan, strlen(dialplan) + 1);
+ cur += strlen(helper->dialplan) + 1;
+ }
+
+ if (context) {
+ helper->context = cur;
+ switch_copy_string(helper->context, context, strlen(context)+1);
+ }
+
+ return switch_core_scheduler_add_task(runtime, sch_transfer_callback, (char *)__SWITCH_FUNC__, uuid, 0, helper, SSHF_FREE_ARG);
+}
+
+
+struct broadcast_helper {
+ char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
+ char *path;
+ switch_media_flag_t flags;
+};
+
+static void sch_broadcast_callback(switch_core_scheduler_task_t *task)
+{
+ struct broadcast_helper *helper;
+ assert(task);
+
+ helper = (struct broadcast_helper *) task->cmd_arg;
+ switch_ivr_broadcast(helper->uuid_str, helper->path, helper->flags);
+}
+
+SWITCH_DECLARE(uint32_t) switch_ivr_schedule_broadcast(time_t runtime, char *uuid, char *path, switch_media_flag_t flags)
+{
+ struct broadcast_helper *helper;
+ size_t len = sizeof(*helper) + strlen(path) + 1;
+
+ assert((helper = malloc(len)));
+ memset(helper, 0, len);
+
+ switch_copy_string(helper->uuid_str, uuid, sizeof(helper->uuid_str));
+ helper->flags = flags;
+ helper->path = (char *) helper + sizeof(*helper);
+ switch_copy_string(helper->path, path, len - sizeof(helper));
+
+
+ return switch_core_scheduler_add_task(runtime, sch_broadcast_callback, (char *)__SWITCH_FUNC__, uuid, 0, helper, SSHF_FREE_ARG);
+}
SWITCH_DECLARE(switch_status_t) switch_ivr_broadcast(char *uuid, char *path, switch_media_flag_t flags)
{
@@ -3249,9 +3400,15 @@
switch_event_t *event;
switch_core_session_t *other_session = NULL;
char *other_uuid = NULL;
+ char *app = "playback";
+
+ assert(path);
if ((session = switch_core_session_locate(uuid))) {
- char *app;
+ char *cause = NULL;
+ char *mypath = strdup(path);
+ char *p;
+
master = session;
channel = switch_core_session_get_channel(session);
@@ -3261,11 +3418,17 @@
switch_ivr_media(uuid, SMF_REBRIDGE);
}
- if (!strncasecmp(path, "speak:", 6)) {
- path += 6;
- app = "speak";
- } else {
- app = "playback";
+ if ((p = strchr(mypath, ':'))) {
+ app = mypath;
+ *p++ = '\0';
+ path = p;
+ }
+
+ if ((cause = strchr(app, '!'))) {
+ *cause++ = '\0';
+ if (!cause) {
+ cause = "normal_clearing";
+ }
}
if ((flags & SMF_ECHO_BLEG) && (other_uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE))
@@ -3299,8 +3462,21 @@
}
}
+ if (cause) {
+ if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-name", "hangup");
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-arg", "%s", cause);
+
+ switch_core_session_queue_private_event(session, &event);
+ }
+ }
+
switch_core_session_rwunlock(session);
+ switch_safe_free(mypath);
}
+
+
return SWITCH_STATUS_SUCCESS;
}
@@ -3449,11 +3625,16 @@
switch_channel_set_variable(channel, SWITCH_BRIDGE_VARIABLE, NULL);
switch_channel_set_variable(other_channel, SWITCH_BRIDGE_VARIABLE, NULL);
- switch_channel_hangup(other_channel, switch_channel_get_cause(channel));
+ if (switch_channel_get_state(other_channel) < CS_HANGUP &&
+ switch_true(switch_channel_get_variable(other_channel, SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE))) {
+ switch_channel_hangup(other_channel, switch_channel_get_cause(channel));
+ } else {
+ switch_channel_set_state(other_channel, CS_EXECUTE);
+ }
switch_core_session_rwunlock(other_session);
}
-
+
return SWITCH_STATUS_SUCCESS;
}
More information about the Freeswitch-svn
mailing list