From 9e85723e3f40ac70f9baefab88e3f5f27e2ada6c Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 7 Feb 2006 20:47:15 +0000 Subject: [PATCH] Fresh updates (Beware... all coded today) *) Rename *event_handler* to state_handler to avoid confusion with newer eventing engine. *) Allow application level of state_handler to be layered/stacked (up to 30) *) Add new core global state_handler stack (also up to 30.. seems reasonable, constant in switch_types.h) git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@554 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/include/switch_channel.h | 16 +- src/include/switch_core.h | 20 ++ src/include/switch_module_interfaces.h | 16 +- src/include/switch_types.h | 6 +- .../mod_bridgecall/mod_bridgecall.c | 8 +- .../applications/mod_ivrtest/mod_ivrtest.c | 22 ++ src/switch_channel.c | 25 +- src/switch_core.c | 255 ++++++++++++++---- 8 files changed, 293 insertions(+), 75 deletions(-) diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index cea017691a..7de22e8c7c 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -192,18 +192,20 @@ SWITCH_DECLARE(switch_status) switch_channel_clear_flag(switch_channel *channel, SWITCH_DECLARE(switch_status) switch_channel_answer(switch_channel *channel); /*! - \brief Assign an event handler table to a given channel - \param channel channel on which to assign the event handler table - \param event_handlers table of event handler functions + \brief add an event handler table to a given channel + \param channel channel on which to add the event handler table + \param state_handler table of event handler functions + \return the index number/priority of the table negative value indicates failure */ -SWITCH_DECLARE(void) switch_channel_set_event_handlers(switch_channel *channel, const struct switch_event_handler_table *event_handlers); +SWITCH_DECLARE(int) switch_channel_add_state_handler(switch_channel *channel, const switch_state_handler_table *state_handler); /*! - \brief Retrieve an event handler tablefrom a given channel + \brief Retrieve an event handler tablefrom a given channel at given index level \param channel channel from which to retrieve the event handler table - \return given channel's event handler table + \param index the index of the event handler table (start from 0) + \return given channel's event handler table at given index or NULL if requested index does not exist. */ -SWITCH_DECLARE(const struct switch_event_handler_table *) switch_channel_get_event_handlers(switch_channel *channel); +SWITCH_DECLARE(const switch_state_handler_table *) switch_channel_get_state_handler(switch_channel *channel, int index); /*! \brief Set private data on channel diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 91a50152ba..e6fa2240ee 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -115,6 +115,26 @@ SWITCH_DECLARE(switch_status) switch_core_destroy(void); ///\} + +///\defgroup sh State Handlers +///\ingroup core1 +///\{ +/*! + \brief Add a global state handler + \param state_handler a state handler to add + \return the current index/priority of this handler +*/ +SWITCH_DECLARE(int) switch_core_add_state_handler(const switch_state_handler_table *state_handler); + +/*! + \brief Access a state handler + \param index the desired index to access + \return the desired state handler table or NULL when it does not exist. +*/ +SWITCH_DECLARE(const switch_state_handler_table *) switch_core_get_state_handler(int index); +///\} + + ///\defgroup memp Memory Pooling/Allocation ///\ingroup core1 ///\{ diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h index b0fd603c34..30dd8a9f43 100644 --- a/src/include/switch_module_interfaces.h +++ b/src/include/switch_module_interfaces.h @@ -47,19 +47,19 @@ extern "C" { /*! \brief A table of functions to execute at various states */ -struct switch_event_handler_table { +struct switch_state_handler_table { /*! executed when the state changes to init */ - switch_event_handler on_init; + switch_state_handler on_init; /*! executed when the state changes to ring */ - switch_event_handler on_ring; + switch_state_handler on_ring; /*! executed when the state changes to execute */ - switch_event_handler on_execute; + switch_state_handler on_execute; /*! executed when the state changes to hangup */ - switch_event_handler on_hangup; + switch_state_handler on_hangup; /*! executed when the state changes to loopback*/ - switch_event_handler on_loopback; + switch_state_handler on_loopback; /*! executed when the state changes to transmit*/ - switch_event_handler on_transmit; + switch_state_handler on_transmit; }; /*! \brief Node in which to store custom outgoing channel callback hooks */ @@ -183,7 +183,7 @@ struct switch_endpoint_interface { const switch_io_routines *io_routines; /*! state machine methods */ - const switch_event_handler_table *event_handlers; + const switch_state_handler_table *state_handler; /*! private information */ void *private; diff --git a/src/include/switch_types.h b/src/include/switch_types.h index aff3a6f4a8..7b549c39c5 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -43,7 +43,7 @@ extern "C" { #define SWITCH_RECCOMMENDED_BUFFER_SIZE 131072 #define SWITCH_MAX_CODECS 30 - +#define SWITCH_MAX_STATE_HANDLERS 30 /*! \enum switch_ivr_option_t @@ -359,7 +359,7 @@ typedef struct switch_caller_profile switch_caller_profile; typedef struct switch_caller_step switch_caller_step; typedef struct switch_caller_extension switch_caller_extension; typedef struct switch_caller_application switch_caller_application; -typedef struct switch_event_handler_table switch_event_handler_table; +typedef struct switch_state_handler_table switch_state_handler_table; typedef struct switch_timer switch_timer; typedef struct switch_codec switch_codec; typedef struct switch_core_thread_session switch_core_thread_session; @@ -383,7 +383,7 @@ typedef struct switch_speech_interface switch_speech_interface; typedef void (*switch_application_function)(switch_core_session *, char *); typedef void (*switch_event_callback_t)(switch_event *); typedef switch_caller_extension *(*switch_dialplan_hunt_function)(switch_core_session *); -typedef switch_status (*switch_event_handler)(switch_core_session *); +typedef switch_status (*switch_state_handler)(switch_core_session *); typedef switch_status (*switch_outgoing_channel_hook)(switch_core_session *, switch_caller_profile *, switch_core_session *); typedef switch_status (*switch_answer_channel_hook)(switch_core_session *); typedef switch_status (*switch_receive_message_hook)(switch_core_session *, switch_core_session_message *); diff --git a/src/mod/applications/mod_bridgecall/mod_bridgecall.c b/src/mod/applications/mod_bridgecall/mod_bridgecall.c index e533f8e516..6a34e4fb67 100644 --- a/src/mod/applications/mod_bridgecall/mod_bridgecall.c +++ b/src/mod/applications/mod_bridgecall/mod_bridgecall.c @@ -144,7 +144,7 @@ static switch_status audio_bridge_on_ring(switch_core_session *session) return SWITCH_STATUS_SUCCESS; } -static const switch_event_handler_table audio_bridge_peer_event_handlers = { +static const switch_state_handler_table audio_bridge_peer_state_handlers = { /*.on_init */ NULL, /*.on_ring */ audio_bridge_on_ring, /*.on_execute */ NULL, @@ -153,7 +153,7 @@ static const switch_event_handler_table audio_bridge_peer_event_handlers = { /*.on_transmit */ NULL }; -static const switch_event_handler_table audio_bridge_caller_event_handlers = { +static const switch_state_handler_table audio_bridge_caller_state_handlers = { /*.on_init */ NULL, /*.on_ring */ NULL, /*.on_execute */ NULL, @@ -215,8 +215,8 @@ static void audio_bridge_function(switch_core_session *session, char *data) switch_channel_set_private(caller_channel, peer_session); switch_channel_set_private(peer_channel, session); - switch_channel_set_event_handlers(caller_channel, &audio_bridge_caller_event_handlers); - switch_channel_set_event_handlers(peer_channel, &audio_bridge_peer_event_handlers); + 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 (;;) { diff --git a/src/mod/applications/mod_ivrtest/mod_ivrtest.c b/src/mod/applications/mod_ivrtest/mod_ivrtest.c index 3c3d627357..a5803a7333 100644 --- a/src/mod/applications/mod_ivrtest/mod_ivrtest.c +++ b/src/mod/applications/mod_ivrtest/mod_ivrtest.c @@ -92,6 +92,26 @@ static void ivrtest_function(switch_core_session *session, char *data) } +static switch_status my_on_hangup(switch_core_session *session) +{ + switch_channel *channel; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_console_printf(SWITCH_CHANNEL_CONSOLE, "I globally hooked to [%s] on the hangup event\n", switch_channel_get_name(channel)); + +} + +static const switch_state_handler_table state_handlers = { + /*.on_init */ NULL, + /*.on_ring */ NULL, + /*.on_execute */ NULL, + /*.on_hangup */ my_on_hangup, + /*.on_loopback */ NULL, + /*.on_transmit */ NULL +}; + static const switch_application_interface ivrtest_application_interface = { /*.interface_name */ "ivrtest", /*.application_function */ ivrtest_function @@ -112,6 +132,8 @@ SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_modul /* connect my internal structure to the blank pointer passed to me */ *interface = &mod_ivrtest_module_interface; + /* test global state handlers */ + switch_core_add_state_handler(&state_handlers); /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS; diff --git a/src/switch_channel.c b/src/switch_channel.c index d60dca668d..919ba1173f 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -43,7 +43,8 @@ struct switch_channel { switch_caller_profile *originator_caller_profile; switch_caller_profile *originatee_caller_profile; switch_caller_extension *caller_extension; - const struct switch_event_handler_table *event_handlers; + const struct switch_state_handler_table *state_handlers[SWITCH_MAX_STATE_HANDLERS]; + int state_handler_index; switch_hash *variables; void *private; int freq; @@ -484,17 +485,29 @@ SWITCH_DECLARE(switch_caller_profile *) switch_channel_get_originatee_caller_pro return channel->originatee_caller_profile; } -SWITCH_DECLARE(void) switch_channel_set_event_handlers(switch_channel *channel, - const struct switch_event_handler_table *event_handlers) +SWITCH_DECLARE(int) switch_channel_add_state_handler(switch_channel *channel, + const switch_state_handler_table *state_handler) { assert(channel != NULL); - channel->event_handlers = event_handlers; + int index = channel->state_handler_index++; + + if (channel->state_handler_index >= SWITCH_MAX_STATE_HANDLERS) { + return -1; + } + + channel->state_handlers[index] = state_handler; + return index; } -SWITCH_DECLARE(const struct switch_event_handler_table *) switch_channel_get_event_handlers(switch_channel *channel) +SWITCH_DECLARE(const switch_state_handler_table *) switch_channel_get_state_handler(switch_channel *channel, int index) { assert(channel != NULL); - return channel->event_handlers; + + if (index > SWITCH_MAX_STATE_HANDLERS || index > channel->state_handler_index) { + return NULL; + } + + return channel->state_handlers[index]; } SWITCH_DECLARE(void) switch_channel_set_caller_extension(switch_channel *channel, diff --git a/src/switch_core.c b/src/switch_core.c index 425cbfe5c0..911d261b0a 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -91,6 +91,8 @@ struct switch_core_runtime { apr_pool_t *memory_pool; switch_hash *session_table; switch_core_db *db; + const struct switch_state_handler_table *state_handlers[SWITCH_MAX_STATE_HANDLERS]; + int state_handler_index; #ifdef EMBED_PERL PerlInterpreter *my_perl; #endif @@ -186,6 +188,29 @@ SWITCH_DECLARE(switch_status) switch_core_do_perl(char *txt) } #endif + +SWITCH_DECLARE(int) switch_core_add_state_handler(const switch_state_handler_table *state_handler) +{ + int index = runtime.state_handler_index++; + + if (runtime.state_handler_index >= SWITCH_MAX_STATE_HANDLERS) { + return -1; + } + + runtime.state_handlers[index] = state_handler; + return index; +} + +SWITCH_DECLARE(const switch_state_handler_table *) switch_core_get_state_handler(int index) +{ + + if (index > SWITCH_MAX_STATE_HANDLERS || index > runtime.state_handler_index) { + return NULL; + } + + return runtime.state_handlers[index]; +} + SWITCH_DECLARE(switch_status) switch_core_session_message_send(char *uuid_str, switch_core_session_message *message) { switch_core_session *session = NULL; @@ -1604,8 +1629,8 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session *session) { switch_channel_state state = CS_NEW, laststate = CS_HANGUP, midstate = CS_DONE; const switch_endpoint_interface *endpoint_interface; - const switch_event_handler_table *driver_event_handlers = NULL; - const switch_event_handler_table *application_event_handlers = NULL; + const switch_state_handler_table *driver_state_handler = NULL; + const switch_state_handler_table *application_state_handler = NULL; /* Life of the channel. you have channel and pool in your session @@ -1623,13 +1648,13 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session *session) */ assert(session != NULL); - application_event_handlers = switch_channel_get_event_handlers(session->channel); + endpoint_interface = session->endpoint_interface; assert(endpoint_interface != NULL); - driver_event_handlers = endpoint_interface->event_handlers; - assert(driver_event_handlers != NULL); + driver_state_handler = endpoint_interface->state_handler; + assert(driver_state_handler != NULL); switch_mutex_lock(session->mutex); @@ -1637,6 +1662,8 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session *session) switch_event *event; if (state != laststate) { + int index = 0; + int proceed = 1; midstate = state; if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_STATE) == SWITCH_STATUS_SUCCESS) { @@ -1653,14 +1680,37 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session *session) break; case CS_HANGUP: /* Deactivate and end the thread */ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "State HANGUP\n"); - if (!driver_event_handlers->on_hangup || - (driver_event_handlers->on_hangup && - driver_event_handlers->on_hangup(session) == SWITCH_STATUS_SUCCESS && + if (!driver_state_handler->on_hangup || + (driver_state_handler->on_hangup && + driver_state_handler->on_hangup(session) == SWITCH_STATUS_SUCCESS && midstate == switch_channel_get_state(session->channel))) { - if (!application_event_handlers || !application_event_handlers->on_hangup || - (application_event_handlers->on_hangup && - application_event_handlers->on_hangup(session) == SWITCH_STATUS_SUCCESS && - midstate == switch_channel_get_state(session->channel))) { + while((application_state_handler = switch_channel_get_state_handler(session->channel, index++))) { + if (!application_state_handler || !application_state_handler->on_hangup || + (application_state_handler->on_hangup && + application_state_handler->on_hangup(session) == SWITCH_STATUS_SUCCESS && + midstate == switch_channel_get_state(session->channel))) { + proceed++; + continue; + } else { + proceed = 0; + break; + } + } + index = 0; + while(proceed && (application_state_handler = switch_core_get_state_handler(index++))) { + if (!application_state_handler || !application_state_handler->on_hangup || + (application_state_handler->on_hangup && + application_state_handler->on_hangup(session) == SWITCH_STATUS_SUCCESS && + midstate == switch_channel_get_state(session->channel))) { + proceed++; + continue; + } else { + proceed = 0; + break; + } + } + + if (proceed) { switch_core_standard_on_hangup(session); } } @@ -1668,70 +1718,181 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session *session) break; case CS_INIT: /* Basic setup tasks */ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "State INIT\n"); - if (!driver_event_handlers->on_init || - (driver_event_handlers->on_init && - driver_event_handlers->on_init(session) == SWITCH_STATUS_SUCCESS && + if (!driver_state_handler->on_init || + (driver_state_handler->on_init && + driver_state_handler->on_init(session) == SWITCH_STATUS_SUCCESS && midstate == switch_channel_get_state(session->channel))) { - if (!application_event_handlers || !application_event_handlers->on_init || - (application_event_handlers->on_init && - application_event_handlers->on_init(session) == SWITCH_STATUS_SUCCESS && - midstate == switch_channel_get_state(session->channel))) { + while((application_state_handler = switch_channel_get_state_handler(session->channel, index++))) { + if (!application_state_handler || !application_state_handler->on_init || + (application_state_handler->on_init && + application_state_handler->on_init(session) == SWITCH_STATUS_SUCCESS && + midstate == switch_channel_get_state(session->channel))) { + proceed++; + continue; + } else { + proceed = 0; + break; + } + } + index = 0; + while(proceed && (application_state_handler = switch_core_get_state_handler(index++))) { + if (!application_state_handler || !application_state_handler->on_init || + (application_state_handler->on_init && + application_state_handler->on_init(session) == SWITCH_STATUS_SUCCESS && + midstate == switch_channel_get_state(session->channel))) { + proceed++; + continue; + } else { + proceed = 0; + break; + } + } + if (proceed) { switch_core_standard_on_init(session); } } break; case CS_RING: /* Look for a dialplan and find something to do */ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "State RING\n"); - if (!driver_event_handlers->on_ring || - (driver_event_handlers->on_ring && - driver_event_handlers->on_ring(session) == SWITCH_STATUS_SUCCESS && + if (!driver_state_handler->on_ring || + (driver_state_handler->on_ring && + driver_state_handler->on_ring(session) == SWITCH_STATUS_SUCCESS && midstate == switch_channel_get_state(session->channel))) { - if (!application_event_handlers || !application_event_handlers->on_ring || - (application_event_handlers->on_ring && - application_event_handlers->on_ring(session) == SWITCH_STATUS_SUCCESS && - midstate == switch_channel_get_state(session->channel))) { + while((application_state_handler = switch_channel_get_state_handler(session->channel, index++))) { + if (!application_state_handler || !application_state_handler->on_ring || + (application_state_handler->on_ring && + application_state_handler->on_ring(session) == SWITCH_STATUS_SUCCESS && + midstate == switch_channel_get_state(session->channel))) { + proceed++; + continue; + } else { + proceed = 0; + break; + } + } + index = 0; + while(proceed && (application_state_handler = switch_core_get_state_handler(index++))) { + if (!application_state_handler || !application_state_handler->on_ring || + (application_state_handler->on_ring && + application_state_handler->on_ring(session) == SWITCH_STATUS_SUCCESS && + midstate == switch_channel_get_state(session->channel))) { + proceed++; + continue; + } else { + proceed = 0; + break; + } + } + if (proceed) { switch_core_standard_on_ring(session); } } break; case CS_EXECUTE: /* Execute an Operation */ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "State EXECUTE\n"); - if (!driver_event_handlers->on_execute || - (driver_event_handlers->on_execute && - driver_event_handlers->on_execute(session) == SWITCH_STATUS_SUCCESS && + if (!driver_state_handler->on_execute || + (driver_state_handler->on_execute && + driver_state_handler->on_execute(session) == SWITCH_STATUS_SUCCESS && midstate == switch_channel_get_state(session->channel))) { - if (!application_event_handlers || !application_event_handlers->on_execute || - (application_event_handlers->on_execute && - application_event_handlers->on_execute(session) == SWITCH_STATUS_SUCCESS && - midstate == switch_channel_get_state(session->channel))) { + while((application_state_handler = switch_channel_get_state_handler(session->channel, index++))) { + if (!application_state_handler || !application_state_handler->on_execute || + (application_state_handler->on_execute && + application_state_handler->on_execute(session) == SWITCH_STATUS_SUCCESS && + midstate == switch_channel_get_state(session->channel))) { + proceed++; + continue; + } else { + proceed = 0; + break; + } + } + index = 0; + while(proceed && (application_state_handler = switch_core_get_state_handler(index++))) { + if (!application_state_handler || !application_state_handler->on_execute || + (application_state_handler->on_execute && + application_state_handler->on_execute(session) == SWITCH_STATUS_SUCCESS && + midstate == switch_channel_get_state(session->channel))) { + proceed++; + continue; + } else { + proceed = 0; + break; + } + } + if (proceed) { switch_core_standard_on_execute(session); } } break; case CS_LOOPBACK: /* loop all data back to source */ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "State LOOPBACK\n"); - if (!driver_event_handlers->on_loopback || - (driver_event_handlers->on_loopback && - driver_event_handlers->on_loopback(session) == SWITCH_STATUS_SUCCESS && + if (!driver_state_handler->on_loopback || + (driver_state_handler->on_loopback && + driver_state_handler->on_loopback(session) == SWITCH_STATUS_SUCCESS && midstate == switch_channel_get_state(session->channel))) { - if (!application_event_handlers || !application_event_handlers->on_loopback || - (application_event_handlers->on_loopback && - application_event_handlers->on_loopback(session) == SWITCH_STATUS_SUCCESS && - midstate == switch_channel_get_state(session->channel))) { + while((application_state_handler = switch_channel_get_state_handler(session->channel, index++))) { + if (!application_state_handler || !application_state_handler->on_loopback || + (application_state_handler->on_loopback && + application_state_handler->on_loopback(session) == SWITCH_STATUS_SUCCESS && + midstate == switch_channel_get_state(session->channel))) { + proceed++; + continue; + } else { + proceed = 0; + break; + } + } + index = 0; + while(proceed && (application_state_handler = switch_core_get_state_handler(index++))) { + if (!application_state_handler || !application_state_handler->on_loopback || + (application_state_handler->on_loopback && + application_state_handler->on_loopback(session) == SWITCH_STATUS_SUCCESS && + midstate == switch_channel_get_state(session->channel))) { + proceed++; + continue; + } else { + proceed = 0; + break; + } + } + if (proceed) { switch_core_standard_on_loopback(session); } } break; case CS_TRANSMIT: /* send/recieve data to/from another channel */ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "State TRANSMIT\n"); - if (!driver_event_handlers->on_transmit || - (driver_event_handlers->on_transmit && - driver_event_handlers->on_transmit(session) == SWITCH_STATUS_SUCCESS && + if (!driver_state_handler->on_transmit || + (driver_state_handler->on_transmit && + driver_state_handler->on_transmit(session) == SWITCH_STATUS_SUCCESS && midstate == switch_channel_get_state(session->channel))) { - if (!application_event_handlers || !application_event_handlers->on_transmit || - (application_event_handlers->on_transmit && - application_event_handlers->on_transmit(session) == SWITCH_STATUS_SUCCESS && - midstate == switch_channel_get_state(session->channel))) { + + while((application_state_handler = switch_channel_get_state_handler(session->channel, index++))) { + if (!application_state_handler || !application_state_handler->on_transmit || + (application_state_handler->on_transmit && + application_state_handler->on_transmit(session) == SWITCH_STATUS_SUCCESS && + midstate == switch_channel_get_state(session->channel))) { + proceed++; + continue; + } else { + proceed = 0; + break; + } + } + index = 0; + while(proceed && (application_state_handler = switch_core_get_state_handler(index++))) { + if (!application_state_handler || !application_state_handler->on_transmit || + (application_state_handler->on_transmit && + application_state_handler->on_transmit(session) == SWITCH_STATUS_SUCCESS && + midstate == switch_channel_get_state(session->channel))) { + proceed++; + continue; + } else { + proceed = 0; + break; + } + } + if (proceed) { switch_core_standard_on_transmit(session); } }