From d213dfa30ffbc834dcc643beb46a8ba0b0f49f01 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 21 Aug 2013 15:51:19 +0000 Subject: Fix several interrelated issues dealing with the holding bridge technology. * Added an option flags parameter to interval hooks. Interval hooks now can specify if the callback will affect the media path or not. * Added an option flags parameter to the bridge action custom callback. The action callback now can specify if the callback will affect the media path or not. * Made the holding bridge technology reexamine the participant idle mode option whenever the entertainment is restarted. * Fixed app_agent_pool waiting agents needlessly starting and stopping MOH every second by specifying the heartbeat interval hook as not affecting the media path. * Fixed app_agent_pool agent alert from restarting the MOH after the alert beep. The agent entertainment is now changed from MOH to silence after the alert beep. * Fixed holding bridge technology to defer starting the entertainment. It was previously a mixture of immediate and deferred. * Fixed holding bridge technology to immediately stop the entertainment. It was previously a mixture of immediate and deferred. If the channel left the bridging system, any deferred stopping was discarded before taking effect. * Miscellaneous holding bridge technology rework coding improvements. Review: https://reviewboard.asterisk.org/r/2761/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397294 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- main/bridge_channel.c | 206 +++++++++++++++++++++++++++----------------------- 1 file changed, 110 insertions(+), 96 deletions(-) (limited to 'main/bridge_channel.c') diff --git a/main/bridge_channel.c b/main/bridge_channel.c index c46f9c029..f6d909cbc 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -320,6 +320,87 @@ static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, return 0; } +/*! + * \internal + * \brief Suspend a channel from a bridge. + * + * \param bridge_channel Channel to suspend. + * + * \note This function assumes bridge_channel->bridge is locked. + * + * \return Nothing + */ +void bridge_channel_internal_suspend_nolock(struct ast_bridge_channel *bridge_channel) +{ + bridge_channel->suspended = 1; + if (bridge_channel->in_bridge) { + --bridge_channel->bridge->num_active; + } + + /* Get technology bridge threads off of the channel. */ + if (bridge_channel->bridge->technology->suspend) { + bridge_channel->bridge->technology->suspend(bridge_channel->bridge, bridge_channel); + } +} + +/*! + * \internal + * \brief Suspend a channel from a bridge. + * + * \param bridge_channel Channel to suspend. + * + * \return Nothing + */ +static void bridge_channel_suspend(struct ast_bridge_channel *bridge_channel) +{ + ast_bridge_channel_lock_bridge(bridge_channel); + bridge_channel_internal_suspend_nolock(bridge_channel); + ast_bridge_unlock(bridge_channel->bridge); +} + +/*! + * \internal + * \brief Unsuspend a channel from a bridge. + * + * \param bridge_channel Channel to unsuspend. + * + * \note This function assumes bridge_channel->bridge is locked. + * + * \return Nothing + */ +void bridge_channel_internal_unsuspend_nolock(struct ast_bridge_channel *bridge_channel) +{ + bridge_channel->suspended = 0; + if (bridge_channel->in_bridge) { + ++bridge_channel->bridge->num_active; + } + + /* Wake technology bridge threads to take care of channel again. */ + if (bridge_channel->bridge->technology->unsuspend) { + bridge_channel->bridge->technology->unsuspend(bridge_channel->bridge, bridge_channel); + } + + /* Wake suspended channel. */ + ast_bridge_channel_lock(bridge_channel); + ast_cond_signal(&bridge_channel->cond); + ast_bridge_channel_unlock(bridge_channel); +} + +/*! + * \internal + * \brief Unsuspend a channel from a bridge. + * + * \param bridge_channel Channel to unsuspend. + * + * \return Nothing + */ +static void bridge_channel_unsuspend(struct ast_bridge_channel *bridge_channel) +{ + ast_bridge_channel_lock_bridge(bridge_channel); + bridge_channel_internal_unsuspend_nolock(bridge_channel); + ast_bridge_unlock(bridge_channel->bridge); +} + /*! * \internal * \brief Queue an action frame onto the bridge channel with data. @@ -680,6 +761,8 @@ struct bridge_custom_callback { ast_bridge_custom_callback_fn callback; /*! Size of the payload if it exists. A number otherwise. */ size_t payload_size; + /*! Option flags determining how callback is called. */ + unsigned int flags; /*! Nonzero if the payload exists. */ char payload_exists; /*! Payload to give to callback. */ @@ -691,14 +774,22 @@ struct bridge_custom_callback { * \brief Handle the do custom callback bridge action. * \since 12.0.0 * - * \param bridge_channel Which channel to run the application on. - * \param data Action frame data to run the application. + * \param bridge_channel Which channel to call the callback on. + * \param data Action frame data to call the callback. * * \return Nothing */ static void bridge_channel_do_callback(struct ast_bridge_channel *bridge_channel, struct bridge_custom_callback *data) { + if (ast_test_flag(data, AST_BRIDGE_CHANNEL_CB_OPTION_MEDIA)) { + bridge_channel_suspend(bridge_channel); + ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); + } data->callback(bridge_channel, data->payload_exists ? data->payload : NULL, data->payload_size); + if (ast_test_flag(data, AST_BRIDGE_CHANNEL_CB_OPTION_MEDIA)) { + ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); + bridge_channel_unsuspend(bridge_channel); + } } /*! @@ -706,7 +797,9 @@ static void bridge_channel_do_callback(struct ast_bridge_channel *bridge_channel * \brief Marshal a custom callback function to be called on a bridge_channel */ static int payload_helper_cb(ast_bridge_channel_post_action_data post_it, - struct ast_bridge_channel *bridge_channel, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size) + struct ast_bridge_channel *bridge_channel, + enum ast_bridge_channel_custom_callback_option flags, + ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size) { struct bridge_custom_callback *cb_data; size_t len_data = sizeof(*cb_data) + (payload ? payload_size : 0); @@ -721,6 +814,7 @@ static int payload_helper_cb(ast_bridge_channel_post_action_data post_it, cb_data = alloca(len_data); cb_data->callback = callback; cb_data->payload_size = payload_size; + cb_data->flags = flags; cb_data->payload_exists = payload && payload_size; if (cb_data->payload_exists) { memcpy(cb_data->payload, payload, payload_size);/* Safe */ @@ -729,16 +823,20 @@ static int payload_helper_cb(ast_bridge_channel_post_action_data post_it, return post_it(bridge_channel, BRIDGE_CHANNEL_ACTION_CALLBACK, cb_data, len_data); } -int ast_bridge_channel_write_callback(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size) +int ast_bridge_channel_write_callback(struct ast_bridge_channel *bridge_channel, + enum ast_bridge_channel_custom_callback_option flags, + ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size) { return payload_helper_cb(bridge_channel_write_action_data, - bridge_channel, callback, payload, payload_size); + bridge_channel, flags, callback, payload, payload_size); } -int ast_bridge_channel_queue_callback(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size) +int ast_bridge_channel_queue_callback(struct ast_bridge_channel *bridge_channel, + enum ast_bridge_channel_custom_callback_option flags, + ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size) { return payload_helper_cb(bridge_channel_queue_action_data, - bridge_channel, callback, payload, payload_size); + bridge_channel, flags, callback, payload, payload_size); } struct bridge_park { @@ -802,87 +900,6 @@ int ast_bridge_channel_write_park(struct ast_bridge_channel *bridge_channel, con bridge_channel, parkee_uuid, parker_uuid, app_data); } -/*! - * \internal - * \brief Suspend a channel from a bridge. - * - * \param bridge_channel Channel to suspend. - * - * \note This function assumes bridge_channel->bridge is locked. - * - * \return Nothing - */ -void bridge_channel_internal_suspend_nolock(struct ast_bridge_channel *bridge_channel) -{ - bridge_channel->suspended = 1; - if (bridge_channel->in_bridge) { - --bridge_channel->bridge->num_active; - } - - /* Get technology bridge threads off of the channel. */ - if (bridge_channel->bridge->technology->suspend) { - bridge_channel->bridge->technology->suspend(bridge_channel->bridge, bridge_channel); - } -} - -/*! - * \internal - * \brief Suspend a channel from a bridge. - * - * \param bridge_channel Channel to suspend. - * - * \return Nothing - */ -static void bridge_channel_suspend(struct ast_bridge_channel *bridge_channel) -{ - ast_bridge_channel_lock_bridge(bridge_channel); - bridge_channel_internal_suspend_nolock(bridge_channel); - ast_bridge_unlock(bridge_channel->bridge); -} - -/*! - * \internal - * \brief Unsuspend a channel from a bridge. - * - * \param bridge_channel Channel to unsuspend. - * - * \note This function assumes bridge_channel->bridge is locked. - * - * \return Nothing - */ -void bridge_channel_internal_unsuspend_nolock(struct ast_bridge_channel *bridge_channel) -{ - bridge_channel->suspended = 0; - if (bridge_channel->in_bridge) { - ++bridge_channel->bridge->num_active; - } - - /* Wake technology bridge threads to take care of channel again. */ - if (bridge_channel->bridge->technology->unsuspend) { - bridge_channel->bridge->technology->unsuspend(bridge_channel->bridge, bridge_channel); - } - - /* Wake suspended channel. */ - ast_bridge_channel_lock(bridge_channel); - ast_cond_signal(&bridge_channel->cond); - ast_bridge_channel_unlock(bridge_channel); -} - -/*! - * \internal - * \brief Unsuspend a channel from a bridge. - * - * \param bridge_channel Channel to unsuspend. - * - * \return Nothing - */ -static void bridge_channel_unsuspend(struct ast_bridge_channel *bridge_channel) -{ - ast_bridge_channel_lock_bridge(bridge_channel); - bridge_channel_internal_unsuspend_nolock(bridge_channel); - ast_bridge_unlock(bridge_channel->bridge); -} - /*! * \internal * \brief Handle bridge channel interval expiration. @@ -897,7 +914,7 @@ static void bridge_channel_handle_interval(struct ast_bridge_channel *bridge_cha struct ast_heap *interval_hooks; struct ast_bridge_hook_timer *hook; struct timeval start; - int hook_run = 0; + int chan_suspended = 0; interval_hooks = bridge_channel->features->interval_hooks; ast_heap_wrlock(interval_hooks); @@ -914,8 +931,9 @@ static void bridge_channel_handle_interval(struct ast_bridge_channel *bridge_cha ao2_ref(hook, +1); ast_heap_unlock(interval_hooks); - if (!hook_run) { - hook_run = 1; + if (!chan_suspended + && ast_test_flag(&hook->timer, AST_BRIDGE_HOOK_TIMER_OPTION_MEDIA)) { + chan_suspended = 1; bridge_channel_suspend(bridge_channel); ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); } @@ -970,7 +988,7 @@ static void bridge_channel_handle_interval(struct ast_bridge_channel *bridge_cha } ast_heap_unlock(interval_hooks); - if (hook_run) { + if (chan_suspended) { ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); bridge_channel_unsuspend(bridge_channel); } @@ -1276,11 +1294,7 @@ static void bridge_channel_handle_action(struct ast_bridge_channel *bridge_chann bridge_channel_unsuspend(bridge_channel); break; case BRIDGE_CHANNEL_ACTION_CALLBACK: - bridge_channel_suspend(bridge_channel); - ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); bridge_channel_do_callback(bridge_channel, action->data.ptr); - ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); - bridge_channel_unsuspend(bridge_channel); break; case BRIDGE_CHANNEL_ACTION_PARK: bridge_channel_suspend(bridge_channel); -- cgit v1.2.3