diff options
-rw-r--r-- | apps/app_agent_pool.c | 14 | ||||
-rw-r--r-- | bridges/bridge_builtin_features.c | 2 | ||||
-rw-r--r-- | bridges/bridge_builtin_interval_features.c | 2 | ||||
-rw-r--r-- | include/asterisk/bridging_channel.h | 183 | ||||
-rw-r--r-- | include/asterisk/bridging_channel_internal.h | 150 | ||||
-rw-r--r-- | include/asterisk/bridging_features.h | 2 | ||||
-rw-r--r-- | main/bridging.c | 97 | ||||
-rw-r--r-- | main/bridging_basic.c | 8 | ||||
-rw-r--r-- | main/bridging_channel.c | 192 | ||||
-rw-r--r-- | res/parking/parking_bridge_features.c | 6 |
10 files changed, 337 insertions, 319 deletions
diff --git a/apps/app_agent_pool.c b/apps/app_agent_pool.c index fb73d869f..956a97e3f 100644 --- a/apps/app_agent_pool.c +++ b/apps/app_agent_pool.c @@ -1055,7 +1055,7 @@ static void agent_connect_caller(struct ast_bridge_channel *bridge_channel, stru if (!caller_bridge) { /* Reset agent. */ - ast_bridge_channel_leave_bridge(bridge_channel); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END); return; } res = ast_bridge_move(caller_bridge, bridge_channel->bridge, bridge_channel->chan, @@ -1063,7 +1063,7 @@ static void agent_connect_caller(struct ast_bridge_channel *bridge_channel, stru if (res) { /* Reset agent. */ ast_bridge_destroy(caller_bridge); - ast_bridge_channel_leave_bridge(bridge_channel); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END); return; } ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_ANSWER, NULL, 0); @@ -1159,13 +1159,13 @@ static int bridge_agent_hold_heartbeat(struct ast_bridge *bridge, struct ast_bri if (deferred_logoff) { ast_debug(1, "Agent %s: Deferred logoff.\n", agent->username); - ast_bridge_channel_leave_bridge(bridge_channel); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END); } else if (probation_timedout) { ast_debug(1, "Agent %s: Login complete.\n", agent->username); agent_devstate_changed(agent->username); } else if (ack_timedout) { ast_debug(1, "Agent %s: Ack call timeout.\n", agent->username); - ast_bridge_channel_leave_bridge(bridge_channel); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END); } else if (wrapup_timedout) { ast_debug(1, "Agent %s: Wrapup timeout. Ready for new call.\n", agent->username); agent_devstate_changed(agent->username); @@ -1270,7 +1270,7 @@ static int bridge_agent_hold_push(struct ast_bridge *self, struct ast_bridge_cha * agent will have some slightly different behavior in corner * cases. */ - ast_bridge_channel_leave_bridge(bridge_channel); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END); return 0; } @@ -1704,7 +1704,7 @@ static void caller_abort_agent(struct agent_pvt *agent) } /* Kick the agent out of the holding bridge to reset it. */ - ast_bridge_channel_leave_bridge_nolock(logged); + ast_bridge_channel_leave_bridge_nolock(logged, AST_BRIDGE_CHANNEL_STATE_END); ast_bridge_channel_unlock(logged); } @@ -1714,7 +1714,7 @@ static int caller_safety_timeout(struct ast_bridge *bridge, struct ast_bridge_ch if (agent->state == AGENT_STATE_CALL_PRESENT) { ast_verb(3, "Agent '%s' did not respond. Safety timeout.\n", agent->username); - ast_bridge_channel_leave_bridge(bridge_channel); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END); caller_abort_agent(agent); } diff --git a/bridges/bridge_builtin_features.c b/bridges/bridge_builtin_features.c index 8554495eb..1252240ac 100644 --- a/bridges/bridge_builtin_features.c +++ b/bridges/bridge_builtin_features.c @@ -483,7 +483,7 @@ static int feature_hangup(struct ast_bridge *bridge, struct ast_bridge_channel * * bridge_channel to force the channel out of the bridge and the * core takes care of the rest. */ - ast_bridge_channel_leave_bridge(bridge_channel); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END); return 0; } diff --git a/bridges/bridge_builtin_interval_features.c b/bridges/bridge_builtin_interval_features.c index 2ca3f7ddb..7e5291ac8 100644 --- a/bridges/bridge_builtin_interval_features.c +++ b/bridges/bridge_builtin_interval_features.c @@ -58,7 +58,7 @@ static int bridge_features_duration_callback(struct ast_bridge *bridge, struct a ast_stream_and_wait(bridge_channel->chan, limits->duration_sound, AST_DIGIT_NONE); } - ast_bridge_channel_leave_bridge(bridge_channel); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END); ast_test_suite_event_notify("BRIDGE_TIMELIMIT", "Channel1: %s", ast_channel_name(bridge_channel->chan)); return -1; diff --git a/include/asterisk/bridging_channel.h b/include/asterisk/bridging_channel.h index 630e6d6f0..cdbb2ec5d 100644 --- a/include/asterisk/bridging_channel.h +++ b/include/asterisk/bridging_channel.h @@ -22,7 +22,20 @@ * \file * \brief Bridging Channel API * - * An API that act on a channel in a bridge + * An API that act on a channel in a bridge. Note that while the + * \ref ast_bridge_channel is owned by a channel, it should only be used + * by members of the bridging system. The only places where this API should + * be used is: + * - The \ref AstBridging API itself + * - Bridge mixing technologies + * - Bridge sub-classes + * + * In general, anywhere else it is unsafe to use this API. Care should be + * taken when using this API to ensure that the locking order remains + * correct. The locking order must be: + * - The \ref ast_bridge + * - The \ref ast_bridge_channel + * - The \ref ast_channel * * \author Joshua Colp <jcolp@digium.com> * \author Richard Mudgett <rmudgett@digium.com> @@ -48,8 +61,8 @@ enum ast_bridge_channel_state { AST_BRIDGE_CHANNEL_STATE_WAIT = 0, /*! Bridged channel was forced out and should be hung up (Bridge may dissolve.) */ AST_BRIDGE_CHANNEL_STATE_END, - /*! Bridged channel was forced out and should be hung up */ - AST_BRIDGE_CHANNEL_STATE_HANGUP, + /*! Bridged channel was forced out. Don't dissolve the bridge regardless */ + AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, }; enum ast_bridge_channel_thread_state { @@ -61,43 +74,6 @@ enum ast_bridge_channel_thread_state { AST_BRIDGE_CHANNEL_THREAD_FRAME, }; -/*! \brief Actions that can be taken on a channel in a bridge */ -enum ast_bridge_action_type { - /*! Bridged channel is to detect a feature hook */ - AST_BRIDGE_ACTION_FEATURE, - /*! Bridged channel is to act on an interval hook */ - AST_BRIDGE_ACTION_INTERVAL, - /*! Bridged channel is to send a DTMF stream out */ - AST_BRIDGE_ACTION_DTMF_STREAM, - /*! Bridged channel is to indicate talking start */ - AST_BRIDGE_ACTION_TALKING_START, - /*! Bridged channel is to indicate talking stop */ - AST_BRIDGE_ACTION_TALKING_STOP, - /*! Bridge channel is to play the indicated sound file. */ - AST_BRIDGE_ACTION_PLAY_FILE, - /*! Bridge channel is to run the indicated application. */ - AST_BRIDGE_ACTION_RUN_APP, - /*! Bridge channel is to run the custom callback routine. */ - AST_BRIDGE_ACTION_CALLBACK, - /*! Bridge channel is to get parked. */ - AST_BRIDGE_ACTION_PARK, - /*! Bridge channel is to execute a blind transfer. */ - AST_BRIDGE_ACTION_BLIND_TRANSFER, - /*! Bridge channel is to execute an attended transfer */ - AST_BRIDGE_ACTION_ATTENDED_TRANSFER, - - /* - * Bridge actions put after this comment must never be put onto - * the bridge_channel wr_queue because they have other resources - * that must be freed. - */ - - /*! Bridge reconfiguration deferred technology destruction. */ - AST_BRIDGE_ACTION_DEFERRED_TECH_DESTROY = 1000, - /*! Bridge deferred dissolving. */ - AST_BRIDGE_ACTION_DEFERRED_DISSOLVING, -}; - struct ast_bridge; struct ast_bridge_tech_optimizations; @@ -241,77 +217,52 @@ static inline void _ast_bridge_channel_unlock(struct ast_bridge_channel *bridge_ void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel); /*! - * \brief Ask the bridged channel to leave the bridge it is currently in - * - * \param bridge_channel Channel to leave the bridge - */ -void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel); - -/*! - * \brief Ask the bridged channel to leave the bridge it is currently in + * \brief Set bridge channel state to leave bridge (if not leaving already). * - * \param bridge_channel Channel to leave the bridge + * \param bridge_channel Channel to change the state on + * \param new_state The new state to place the channel into * - * \note This function assumes the bridge_channel is locked. - */ -void ast_bridge_channel_leave_bridge_nolock(struct ast_bridge_channel *bridge_channel); - -/*! - * \brief Write a frame to the specified bridge_channel. - * \since 12.0.0 - * - * \param bridge_channel Channel to queue the frame. - * \param fr Frame to write. + * Example usage: * - * \retval 0 on success. - * \retval -1 on error. + * \code + * ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END); + * \endcode * - * \note This API call is meant for internal bridging operations. - * \note BUGBUG This may get moved. + * This places the channel pointed to by bridge_channel into the + * state AST_BRIDGE_CHANNEL_STATE_END if it was + * AST_BRIDGE_CHANNEL_STATE_WAIT before. */ -int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *fr); +void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state); /*! - * \brief Used to queue an action frame onto a bridge channel and write an action frame into a bridge. - * \since 12.0.0 + * \brief Set bridge channel state to leave bridge (if not leaving already). * - * \param bridge_channel Which channel work with. - * \param action Type of bridge action frame. - * \param data Frame payload data to pass. - * \param datalen Frame payload data length to pass. + * \param bridge_channel Channel to change the state on + * \param new_state The new state to place the channel into * - * \retval 0 on success. - * \retval -1 on error. - */ -typedef int (*ast_bridge_channel_post_action_data)(struct ast_bridge_channel *bridge_channel, enum ast_bridge_action_type action, const void *data, size_t datalen); - -/*! - * \brief Queue an action frame onto the bridge channel with data. - * \since 12.0.0 + * Example usage: * - * \param bridge_channel Which channel to queue the frame onto. - * \param action Type of bridge action frame. - * \param data Frame payload data to pass. - * \param datalen Frame payload data length to pass. + * \code + * ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END); + * \endcode * - * \retval 0 on success. - * \retval -1 on error. + * This places the channel pointed to by bridge_channel into the + * state AST_BRIDGE_CHANNEL_STATE_END if it was + * AST_BRIDGE_CHANNEL_STATE_WAIT before. */ -int ast_bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_channel, enum ast_bridge_action_type action, const void *data, size_t datalen); +void ast_bridge_channel_leave_bridge_nolock(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state); /*! - * \brief Write an action frame into the bridge with data. + * \brief Write a frame to the specified bridge_channel. * \since 12.0.0 * - * \param bridge_channel Which channel is putting the frame into the bridge. - * \param action Type of bridge action frame. - * \param data Frame payload data to pass. - * \param datalen Frame payload data length to pass. + * \param bridge_channel Channel to queue the frame. + * \param fr Frame to write. * * \retval 0 on success. * \retval -1 on error. */ -int ast_bridge_channel_write_action_data(struct ast_bridge_channel *bridge_channel, enum ast_bridge_action_type action, const void *data, size_t datalen); +int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *fr); /*! * \brief Queue a control frame onto the bridge channel with data. @@ -569,6 +520,56 @@ void ast_bridge_channel_restore_formats(struct ast_bridge_channel *bridge_channe */ struct ast_bridge_channel *ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel); +struct blind_transfer_data { + char exten[AST_MAX_EXTENSION]; + char context[AST_MAX_CONTEXT]; +}; + +/*! + * \brief Adjust the bridge_channel's bridge merge inhibit request count. + * \since 12.0.0 + * + * \param bridge_channel What to operate on. + * \param request Inhibit request increment. + * (Positive to add requests. Negative to remove requests.) + * + * \note This API call is meant for internal bridging operations. + * + * \retval bridge adjusted merge inhibit with reference count. + */ +struct ast_bridge *ast_bridge_channel_merge_inhibit(struct ast_bridge_channel *bridge_channel, int request); + +/*! + * \internal + * \brief Update the linkedids for all channels in a bridge + * \since 12.0.0 + * + * \param bridge_channel The channel joining the bridge + * \param swap The channel being swapped out of the bridge. May be NULL. + * + * \note The bridge must be locked prior to calling this function. This should be called + * during a \ref bridge_channel_push operation, typically by a sub-class of a bridge + */ +void ast_bridge_channel_update_linkedids(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap); + +/*! + * \internal + * \brief Update the accountcodes for a channel entering a bridge + * \since 12.0.0 + * + * This function updates the accountcode and peeraccount on channels in two-party + * bridges. In multi-party bridges, peeraccount is not set - it doesn't make much sense - + * however accountcode propagation will still occur if the channel joining has an + * accountcode. + * + * \param bridge_channel The channel joining the bridge + * \param swap The channel being swapped out of the bridge. May be NULL. + * + * \note The bridge must be locked prior to calling this function. This should be called + * during a \ref bridge_channel_push operation, typically by a sub-class of a bridge + */ +void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/include/asterisk/bridging_channel_internal.h b/include/asterisk/bridging_channel_internal.h index b22b8d69e..9bc9b11f9 100644 --- a/include/asterisk/bridging_channel_internal.h +++ b/include/asterisk/bridging_channel_internal.h @@ -33,24 +33,59 @@ #ifndef _ASTERISK_PRIVATE_BRIDGING_CHANNEL_H #define _ASTERISK_PRIVATE_BRIDGING_CHANNEL_H -struct blind_transfer_data { - char exten[AST_MAX_EXTENSION]; - char context[AST_MAX_CONTEXT]; +/*! + * \internal + * \brief Actions that can be taken on a channel in a bridge + */ +enum bridge_channel_action_type { + /*! Bridged channel is to detect a feature hook */ + BRIDGE_CHANNEL_ACTION_FEATURE, + /*! Bridged channel is to act on an interval hook */ + BRIDGE_CHANNEL_ACTION_INTERVAL, + /*! Bridged channel is to send a DTMF stream out */ + BRIDGE_CHANNEL_ACTION_DTMF_STREAM, + /*! Bridged channel is to indicate talking start */ + BRIDGE_CHANNEL_ACTION_TALKING_START, + /*! Bridged channel is to indicate talking stop */ + BRIDGE_CHANNEL_ACTION_TALKING_STOP, + /*! Bridge channel is to play the indicated sound file. */ + BRIDGE_CHANNEL_ACTION_PLAY_FILE, + /*! Bridge channel is to run the indicated application. */ + BRIDGE_CHANNEL_ACTION_RUN_APP, + /*! Bridge channel is to run the custom callback routine. */ + BRIDGE_CHANNEL_ACTION_CALLBACK, + /*! Bridge channel is to get parked. */ + BRIDGE_CHANNEL_ACTION_PARK, + /*! Bridge channel is to execute a blind transfer. */ + BRIDGE_CHANNEL_ACTION_BLIND_TRANSFER, + /*! Bridge channel is to execute an attended transfer */ + BRIDGE_CHANNEL_ACTION_ATTENDED_TRANSFER, + + /* + * Bridge actions put after this comment must never be put onto + * the bridge_channel wr_queue because they have other resources + * that must be freed. + */ + + /*! Bridge reconfiguration deferred technology destruction. */ + BRIDGE_CHANNEL_ACTION_DEFERRED_TECH_DESTROY = 1000, + /*! Bridge deferred dissolving. */ + BRIDGE_CHANNEL_ACTION_DEFERRED_DISSOLVING, }; /*! - * \brief Adjust the bridge_channel's bridge merge inhibit request count. + * \internal + * \brief Push the bridge channel into its specified bridge. * \since 12.0.0 * - * \param bridge_channel What to operate on. - * \param request Inhibit request increment. - * (Positive to add requests. Negative to remove requests.) + * \param bridge_channel Channel to push. * - * \note This API call is meant for internal bridging operations. + * \note On entry, bridge_channel->bridge is already locked. * - * \retval bridge adjusted merge inhibit with reference count. + * \retval 0 on success. + * \retval -1 on failure. The channel did not get pushed. */ -struct ast_bridge *bridge_channel_merge_inhibit(struct ast_bridge_channel *bridge_channel, int request); +int bridge_channel_push(struct ast_bridge_channel *bridge_channel); /*! * \internal @@ -67,90 +102,57 @@ void bridge_channel_pull(struct ast_bridge_channel *bridge_channel); /*! * \internal - * \brief Push the bridge channel into its specified bridge. - * \since 12.0.0 - * - * \param bridge_channel Channel to push. + * \brief Join the bridge_channel to the bridge * - * \note On entry, bridge_channel->bridge is already locked. + * \param bridge_channel The Channel in the bridge * - * \retval 0 on success. - * \retval -1 on failure. The channel did not get pushed. + * \note This API call starts the bridge_channel's processing of events while + * it is in the bridge. It will return when the channel has been instructed to + * leave the bridge. */ -int bridge_channel_push(struct ast_bridge_channel *bridge_channel); - void bridge_channel_join(struct ast_bridge_channel *bridge_channel); -void bridge_channel_suspend_nolock(struct ast_bridge_channel *bridge_channel); - -void bridge_channel_unsuspend_nolock(struct ast_bridge_channel *bridge_channel); - /*! * \internal - * \brief Update the linkedids for all channels in a bridge - * \since 12.0.0 - * - * \param bridge_channel The channel joining the bridge - * \param swap The channel being swapped out of the bridge. May be NULL. + * \brief Temporarily suspend a channel from a bridge, handing control over to some + * other system * - * \note The bridge must be locked prior to calling this function. This should be called - * during a \ref bridge_channel_push operation, typically by a sub-class of a bridge + * \param bridge_channel The channel in the bridge + * \note This function assumes that \ref bridge_channel is already locked */ -void bridge_channel_update_linkedids(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap); +void bridge_channel_suspend_nolock(struct ast_bridge_channel *bridge_channel); /*! * \internal - * \brief Update the accountcodes for a channel entering a bridge - * \since 12.0.0 - * - * This function updates the accountcode and peeraccount on channels in two-party - * bridges. In multi-party bridges, peeraccount is not set - it doesn't make much sense - - * however accountcode propagation will still occur if the channel joining has an - * accountcode. + * \brief Unsuspend a channel that was previously suspended * - * \param bridge_channel The channel joining the bridge - * \param swap The channel being swapped out of the bridge. May be NULL. - * - * \note The bridge must be locked prior to calling this function. This should be called - * during a \ref bridge_channel_push operation, typically by a sub-class of a bridge + * \param bridge_channel The channel in the bridge + * \note This function assumes that \ref bridge_channel is already locked */ -void bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap); - +void bridge_channel_unsuspend_nolock(struct ast_bridge_channel *bridge_channel); /*! - * \brief Set bridge channel state to leave bridge (if not leaving already) with no lock. + * \internal + * \brief Queue a blind transfer action on a transferee bridge channel * - * \param bridge_channel Channel to change the state on - * \param new_state The new state to place the channel into + * This is only relevant for when a blind transfer is performed on a two-party + * bridge. The transferee's bridge channel will have a blind transfer bridge + * action queued onto it, resulting in the party being redirected to a new + * destination * - * \note This API call is only meant to be used within the - * bridging module and hook callbacks to request the channel - * exit the bridge. + * \param transferee The channel to have the action queued on + * \param exten The destination extension for the transferee + * \param context The destination context for the transferee + * \param hook Frame hook to attach to transferee * - * \note This function assumes the bridge_channel is locked. + * \retval 0 on success. + * \retval -1 on error. */ -void ast_bridge_change_state_nolock(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state); +int bridge_channel_queue_blind_transfer(struct ast_channel *transferee, + const char *exten, const char *context, + transfer_channel_cb new_channel_cb, void *user_data); -/*! - * \brief Set bridge channel state to leave bridge (if not leaving already). - * - * \param bridge_channel Channel to change the state on - * \param new_state The new state to place the channel into - * - * Example usage: - * - * \code - * ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); - * \endcode - * - * This places the channel pointed to by bridge_channel into the - * state AST_BRIDGE_CHANNEL_STATE_HANGUP if it was - * AST_BRIDGE_CHANNEL_STATE_WAIT before. - * - * \note This API call is only meant to be used within the - * bridging module and hook callbacks to request the channel - * exit the bridge. - */ -void ast_bridge_change_state(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state); +int bridge_channel_queue_attended_transfer(struct ast_channel *transferee, + struct ast_channel *unbridged_chan); #endif /* _ASTERISK_PRIVATE_BRIDGING_H */ diff --git a/include/asterisk/bridging_features.h b/include/asterisk/bridging_features.h index 736441f6a..7ab46327d 100644 --- a/include/asterisk/bridging_features.h +++ b/include/asterisk/bridging_features.h @@ -75,7 +75,7 @@ enum ast_bridge_builtin_feature { * how it was imparted. * * \note Joined channels exit the bridge with - * AST_BRIDGE_CHANNEL_STATE_END. + * AST_BRIDGE_CHANNEL_STATE_END_WITH_DISSOLVE. */ AST_BRIDGE_BUILTIN_HANGUP, /*! diff --git a/main/bridging.c b/main/bridging.c index 5f001d1f5..6be48c7ce 100644 --- a/main/bridging.c +++ b/main/bridging.c @@ -256,7 +256,7 @@ void bridge_dissolve(struct ast_bridge *bridge) struct ast_bridge_channel *bridge_channel; struct ast_frame action = { .frametype = AST_FRAME_BRIDGE_ACTION, - .subclass.integer = AST_BRIDGE_ACTION_DEFERRED_DISSOLVING, + .subclass.integer = BRIDGE_CHANNEL_ACTION_DEFERRED_DISSOLVING, }; if (bridge->dissolved) { @@ -268,7 +268,7 @@ void bridge_dissolve(struct ast_bridge *bridge) /* BUGBUG need a cause code on the bridge for the later ejected channels. */ AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { - ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE); } /* Must defer dissolving bridge because it is already locked. */ @@ -518,12 +518,12 @@ static void bridge_action_bridge(struct ast_bridge *bridge, struct ast_frame *ac #endif switch (action->subclass.integer) { - case AST_BRIDGE_ACTION_DEFERRED_TECH_DESTROY: + case BRIDGE_CHANNEL_ACTION_DEFERRED_TECH_DESTROY: ast_bridge_unlock(bridge); bridge_tech_deferred_destroy(bridge, action); ast_bridge_lock(bridge); break; - case AST_BRIDGE_ACTION_DEFERRED_DISSOLVING: + case BRIDGE_CHANNEL_ACTION_DEFERRED_DISSOLVING: ast_bridge_unlock(bridge); bridge->v_table->dissolving(bridge); ast_bridge_lock(bridge); @@ -999,7 +999,7 @@ static int smart_bridge_operation(struct ast_bridge *bridge) }; struct ast_frame action = { .frametype = AST_FRAME_BRIDGE_ACTION, - .subclass.integer = AST_BRIDGE_ACTION_DEFERRED_TECH_DESTROY, + .subclass.integer = BRIDGE_CHANNEL_ACTION_DEFERRED_TECH_DESTROY, .data.ptr = &deferred_tech_destroy, .datalen = sizeof(deferred_tech_destroy), }; @@ -2161,14 +2161,14 @@ enum ast_bridge_channel_state ast_bridge_join(struct ast_bridge *bridge, ao2_ref(bridge, -1); } if (!bridge_channel) { - state = AST_BRIDGE_CHANNEL_STATE_HANGUP; + state = AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE; goto join_exit; } /* BUGBUG features cannot be NULL when passed in. When it is changed to allocated we can do like ast_bridge_impart() and allocate one. */ ast_assert(features != NULL); if (!features) { ao2_ref(bridge_channel, -1); - state = AST_BRIDGE_CHANNEL_STATE_HANGUP; + state = AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE; goto join_exit; } if (tech_args) { @@ -2350,7 +2350,7 @@ int ast_bridge_depart(struct ast_channel *chan) * channel thread. */ - ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE); /* Wait for the depart thread to die */ ast_debug(1, "Waiting for %p(%s) bridge thread to die.\n", @@ -2378,7 +2378,7 @@ int ast_bridge_remove(struct ast_bridge *bridge, struct ast_channel *chan) return -1; } - ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE); ast_bridge_unlock(bridge); @@ -2443,7 +2443,7 @@ void bridge_do_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridg if (kick_me) { for (idx = 0; idx < num_kick; ++idx) { if (bridge_channel == kick_me[idx]) { - ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE); break; } } @@ -2461,7 +2461,7 @@ void bridge_do_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridg bridge_channel_change_bridge(bridge_channel, dst_bridge); if (bridge_channel_push(bridge_channel)) { - ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE); } } AST_LIST_TRAVERSE_SAFE_END; @@ -2475,7 +2475,7 @@ void bridge_do_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridg bridge_channel = kick_me[idx]; ast_bridge_channel_lock(bridge_channel); if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) { - ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); + ast_bridge_channel_leave_bridge_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE); bridge_channel_pull(bridge_channel); } ast_bridge_channel_unlock(bridge_channel); @@ -2710,10 +2710,10 @@ int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bri bridge_channel_change_bridge(bridge_channel, orig_bridge); if (bridge_channel_push(bridge_channel)) { - ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE); } } else { - ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE); } res = -1; } @@ -3111,7 +3111,7 @@ static int try_swap_optimize_out(struct ast_bridge *chan_bridge, } other->swap = dst_bridge_channel->chan; if (!bridge_do_move(dst_bridge, other, 1, 1)) { - ast_bridge_change_state(src_bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); + ast_bridge_channel_leave_bridge(src_bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE); res = -1; if (pvt && pvt->callbacks && pvt->callbacks->optimization_finished) { pvt->callbacks->optimization_finished(pvt); @@ -4567,71 +4567,6 @@ static struct ast_channel *get_transferee(struct ao2_container *channels, struct return transferee; } -/*! - * \internal - * \brief Queue a blind transfer action on a transferee bridge channel - * - * This is only relevant for when a blind transfer is performed on a two-party - * bridge. The transferee's bridge channel will have a blind transfer bridge - * action queued onto it, resulting in the party being redirected to a new - * destination - * - * \param transferee The channel to have the action queued on - * \param exten The destination extension for the transferee - * \param context The destination context for the transferee - * \param hook Frame hook to attach to transferee - * - * \retval 0 on success. - * \retval -1 on error. - */ -static int bridge_channel_queue_blind_transfer(struct ast_channel *transferee, - const char *exten, const char *context, - transfer_channel_cb new_channel_cb, void *user_data) -{ - RAII_VAR(struct ast_bridge_channel *, transferee_bridge_channel, NULL, ao2_cleanup); - struct blind_transfer_data blind_data; - - ast_channel_lock(transferee); - transferee_bridge_channel = ast_channel_get_bridge_channel(transferee); - ast_channel_unlock(transferee); - - if (!transferee_bridge_channel) { - return -1; - } - - if (new_channel_cb) { - new_channel_cb(transferee, user_data, AST_BRIDGE_TRANSFER_SINGLE_PARTY); - } - - ast_copy_string(blind_data.exten, exten, sizeof(blind_data.exten)); - ast_copy_string(blind_data.context, context, sizeof(blind_data.context)); - - return ast_bridge_channel_queue_action_data(transferee_bridge_channel, - AST_BRIDGE_ACTION_BLIND_TRANSFER, &blind_data, sizeof(blind_data)); -} - -static int bridge_channel_queue_attended_transfer(struct ast_channel *transferee, - struct ast_channel *unbridged_chan) -{ - RAII_VAR(struct ast_bridge_channel *, transferee_bridge_channel, NULL, ao2_cleanup); - char unbridged_chan_name[AST_CHANNEL_NAME]; - - ast_channel_lock(transferee); - transferee_bridge_channel = ast_channel_get_bridge_channel(transferee); - ast_channel_unlock(transferee); - - if (!transferee_bridge_channel) { - return -1; - } - - ast_copy_string(unbridged_chan_name, ast_channel_name(unbridged_chan), - sizeof(unbridged_chan_name)); - - return ast_bridge_channel_queue_action_data(transferee_bridge_channel, - AST_BRIDGE_ACTION_ATTENDED_TRANSFER, unbridged_chan_name, - sizeof(unbridged_chan_name)); -} - enum try_parking_result { PARKING_SUCCESS, PARKING_FAILURE, @@ -4851,7 +4786,7 @@ static enum ast_transfer_result bridge_swap_attended_transfer(struct ast_bridge return AST_BRIDGE_TRANSFER_FAIL; } /* Must kick the source channel out of its bridge. */ - ast_bridge_change_state(source_bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); + ast_bridge_channel_leave_bridge(source_bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE); return AST_BRIDGE_TRANSFER_SUCCESS; } else { return AST_BRIDGE_TRANSFER_INVALID; diff --git a/main/bridging_basic.c b/main/bridging_basic.c index 27cbce35c..8fcad7560 100644 --- a/main/bridging_basic.c +++ b/main/bridging_basic.c @@ -285,7 +285,7 @@ static int basic_hangup_hook(struct ast_bridge *bridge, struct ast_bridge_channe } if (2 <= bridge_count) { /* Just allow this channel to leave the multi-party bridge. */ - ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE); } ast_bridge_unlock(bridge_channel->bridge); return 0; @@ -342,8 +342,8 @@ static int bridge_personality_normal_push(struct ast_bridge *self, struct ast_br return -1; } - bridge_channel_update_accountcodes(bridge_channel, swap); - bridge_channel_update_linkedids(bridge_channel, swap); + ast_bridge_channel_update_accountcodes(bridge_channel, swap); + ast_bridge_channel_update_linkedids(bridge_channel, swap); return 0; } @@ -2659,7 +2659,7 @@ static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridg } ast_bridge_channel_write_hold(bridge_channel, NULL); - props->transferee_bridge = bridge_channel_merge_inhibit(bridge_channel, +1); + props->transferee_bridge = ast_bridge_channel_merge_inhibit(bridge_channel, +1); /* Grab the extension to transfer to */ if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), props->context)) { diff --git a/main/bridging_channel.c b/main/bridging_channel.c index 8261a421a..674f14add 100644 --- a/main/bridging_channel.c +++ b/main/bridging_channel.c @@ -53,8 +53,21 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/features_config.h" #include "asterisk/parking.h" +/*! + * \brief Used to queue an action frame onto a bridge channel and write an action frame into a bridge. + * \since 12.0.0 + * + * \param bridge_channel Which channel work with. + * \param action Type of bridge action frame. + * \param data Frame payload data to pass. + * \param datalen Frame payload data length to pass. + * + * \retval 0 on success. + * \retval -1 on error. + */ +typedef int (*ast_bridge_channel_post_action_data)(struct ast_bridge_channel *bridge_channel, enum bridge_channel_action_type action, const void *data, size_t datalen); -struct ast_bridge *bridge_channel_merge_inhibit(struct ast_bridge_channel *bridge_channel, int request) +struct ast_bridge *ast_bridge_channel_merge_inhibit(struct ast_bridge_channel *bridge_channel, int request) { struct ast_bridge *bridge; @@ -98,31 +111,7 @@ static void bridge_channel_poke(struct ast_bridge_channel *bridge_channel) } } -void ast_bridge_change_state_nolock(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state) -{ -/* BUGBUG need cause code for the bridge_channel leaving the bridge. */ - if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) { - return; - } - - ast_debug(1, "Setting %p(%s) state from:%d to:%d\n", - bridge_channel, ast_channel_name(bridge_channel->chan), bridge_channel->state, - new_state); - - /* Change the state on the bridge channel */ - bridge_channel->state = new_state; - - bridge_channel_poke(bridge_channel); -} - -void ast_bridge_change_state(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state) -{ - ast_bridge_channel_lock(bridge_channel); - ast_bridge_change_state_nolock(bridge_channel, new_state); - ast_bridge_channel_unlock(bridge_channel); -} - -void bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap) +void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap) { struct ast_bridge *bridge = bridge_channel->bridge; struct ast_bridge_channel *other = NULL; @@ -167,7 +156,7 @@ void bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_channe } } -void bridge_channel_update_linkedids(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap) +void ast_bridge_channel_update_linkedids(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap) { struct ast_bridge_channel *other = NULL; struct ast_bridge *bridge = bridge_channel->bridge; @@ -233,7 +222,19 @@ int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, st return 0; } -int ast_bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_channel, enum ast_bridge_action_type action, const void *data, size_t datalen) +/*! + * \brief Queue an action frame onto the bridge channel with data. + * \since 12.0.0 + * + * \param bridge_channel Which channel to queue the frame onto. + * \param action Type of bridge action frame. + * \param data Frame payload data to pass. + * \param datalen Frame payload data length to pass. + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int ast_bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_channel, enum bridge_channel_action_type action, const void *data, size_t datalen) { struct ast_frame frame = { .frametype = AST_FRAME_BRIDGE_ACTION, @@ -322,7 +323,7 @@ static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, return 0; } -int ast_bridge_channel_write_action_data(struct ast_bridge_channel *bridge_channel, enum ast_bridge_action_type action, const void *data, size_t datalen) +static int ast_bridge_channel_write_action_data(struct ast_bridge_channel *bridge_channel, enum bridge_channel_action_type action, const void *data, size_t datalen) { struct ast_frame frame = { .frametype = AST_FRAME_BRIDGE_ACTION, @@ -423,7 +424,7 @@ static void bridge_channel_handle_hangup(struct ast_bridge_channel *bridge_chann ao2_iterator_destroy(&iter); /* Default hangup action. */ - ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END); } void ast_bridge_channel_run_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class) @@ -488,7 +489,7 @@ static int payload_helper_app(ast_bridge_channel_post_action_data post_it, strcpy(&app_data->app_name[app_data->moh_offset], moh_class);/* Safe */ } - return post_it(bridge_channel, AST_BRIDGE_ACTION_RUN_APP, app_data, len_data); + return post_it(bridge_channel, BRIDGE_CHANNEL_ACTION_RUN_APP, app_data, len_data); } int ast_bridge_channel_write_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class) @@ -573,7 +574,7 @@ static int payload_helper_playfile(ast_bridge_channel_post_action_data post_it, strcpy(&payload->playfile[payload->moh_offset], moh_class);/* Safe */ } - return post_it(bridge_channel, AST_BRIDGE_ACTION_PLAY_FILE, payload, len_payload); + return post_it(bridge_channel, BRIDGE_CHANNEL_ACTION_PLAY_FILE, payload, len_payload); } int ast_bridge_channel_write_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class) @@ -635,7 +636,7 @@ static int payload_helper_cb(ast_bridge_channel_post_action_data post_it, memcpy(cb_data->payload, payload, payload_size);/* Safe */ } - return post_it(bridge_channel, AST_BRIDGE_ACTION_CALLBACK, cb_data, len_data); + 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) @@ -685,7 +686,7 @@ static int payload_helper_park(ast_bridge_channel_post_action_data post_it, strcpy(&payload->parkee_uuid[payload->app_data_offset], app_data); } - return post_it(bridge_channel, AST_BRIDGE_ACTION_PARK, payload, len_payload); + return post_it(bridge_channel, BRIDGE_CHANNEL_ACTION_PARK, payload, len_payload); } int ast_bridge_channel_write_park(struct ast_bridge_channel *bridge_channel, const char *parkee_uuid, const char *parker_uuid, const char *app_data) @@ -713,7 +714,7 @@ int ast_bridge_notify_talking(struct ast_bridge_channel *bridge_channel, int sta struct ast_frame action = { .frametype = AST_FRAME_BRIDGE_ACTION, .subclass.integer = started_talking - ? AST_BRIDGE_ACTION_TALKING_START : AST_BRIDGE_ACTION_TALKING_STOP, + ? BRIDGE_CHANNEL_ACTION_TALKING_START : BRIDGE_CHANNEL_ACTION_TALKING_STOP, }; return ast_bridge_channel_queue_frame(bridge_channel, &action); @@ -904,7 +905,7 @@ static void bridge_channel_interval(struct ast_bridge_channel *bridge_channel) static int bridge_channel_write_dtmf_stream(struct ast_bridge_channel *bridge_channel, const char *dtmf) { return ast_bridge_channel_write_action_data(bridge_channel, - AST_BRIDGE_ACTION_DTMF_STREAM, dtmf, strlen(dtmf) + 1); + BRIDGE_CHANNEL_ACTION_DTMF_STREAM, dtmf, strlen(dtmf) + 1); } /*! @@ -1115,64 +1116,64 @@ static void bridge_channel_attended_transfer(struct ast_bridge_channel *bridge_c static void bridge_channel_handle_action(struct ast_bridge_channel *bridge_channel, struct ast_frame *action) { switch (action->subclass.integer) { - case AST_BRIDGE_ACTION_INTERVAL: + case BRIDGE_CHANNEL_ACTION_INTERVAL: bridge_channel_suspend(bridge_channel); ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); bridge_channel_interval(bridge_channel); ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); bridge_channel_unsuspend(bridge_channel); break; - case AST_BRIDGE_ACTION_FEATURE: + case BRIDGE_CHANNEL_ACTION_FEATURE: bridge_channel_suspend(bridge_channel); ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); bridge_channel_feature(bridge_channel); ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); bridge_channel_unsuspend(bridge_channel); break; - case AST_BRIDGE_ACTION_DTMF_STREAM: + case BRIDGE_CHANNEL_ACTION_DTMF_STREAM: bridge_channel_suspend(bridge_channel); ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); bridge_channel_dtmf_stream(bridge_channel, action->data.ptr); ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); bridge_channel_unsuspend(bridge_channel); break; - case AST_BRIDGE_ACTION_TALKING_START: - case AST_BRIDGE_ACTION_TALKING_STOP: + case BRIDGE_CHANNEL_ACTION_TALKING_START: + case BRIDGE_CHANNEL_ACTION_TALKING_STOP: bridge_channel_talking(bridge_channel, - action->subclass.integer == AST_BRIDGE_ACTION_TALKING_START); + action->subclass.integer == BRIDGE_CHANNEL_ACTION_TALKING_START); break; - case AST_BRIDGE_ACTION_PLAY_FILE: + case BRIDGE_CHANNEL_ACTION_PLAY_FILE: bridge_channel_suspend(bridge_channel); ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); bridge_channel_playfile(bridge_channel, action->data.ptr); ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); bridge_channel_unsuspend(bridge_channel); break; - case AST_BRIDGE_ACTION_RUN_APP: + case BRIDGE_CHANNEL_ACTION_RUN_APP: bridge_channel_suspend(bridge_channel); ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); bridge_channel_run_app(bridge_channel, action->data.ptr); ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); bridge_channel_unsuspend(bridge_channel); break; - case AST_BRIDGE_ACTION_CALLBACK: + 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 AST_BRIDGE_ACTION_PARK: + case BRIDGE_CHANNEL_ACTION_PARK: bridge_channel_suspend(bridge_channel); ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); bridge_channel_park(bridge_channel, action->data.ptr); ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); bridge_channel_unsuspend(bridge_channel); break; - case AST_BRIDGE_ACTION_BLIND_TRANSFER: + case BRIDGE_CHANNEL_ACTION_BLIND_TRANSFER: bridge_channel_blind_transfer(bridge_channel, action->data.ptr); break; - case AST_BRIDGE_ACTION_ATTENDED_TRANSFER: + case BRIDGE_CHANNEL_ACTION_ATTENDED_TRANSFER: bridge_channel_attended_transfer(bridge_channel, action->data.ptr); break; default: @@ -1350,7 +1351,7 @@ int bridge_channel_push(struct ast_bridge_channel *bridge_channel) ast_bridge_publish_enter(bridge, bridge_channel->chan); if (swap) { - ast_bridge_change_state(swap, AST_BRIDGE_CHANNEL_STATE_HANGUP); + ast_bridge_channel_leave_bridge(swap, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE); bridge_channel_pull(swap); } @@ -1519,7 +1520,7 @@ static void bridge_channel_handle_interval(struct ast_bridge_channel *bridge_cha /* BUGBUG since this is now only run by the channel thread, there is no need to queue the action once this intervals become a first class wait item in bridge_channel_wait(). */ struct ast_frame interval_action = { .frametype = AST_FRAME_BRIDGE_ACTION, - .subclass.integer = AST_BRIDGE_ACTION_INTERVAL, + .subclass.integer = BRIDGE_CHANNEL_ACTION_INTERVAL, }; ast_bridge_channel_queue_frame(bridge_channel, &interval_action); @@ -1544,7 +1545,7 @@ static struct ast_frame *bridge_handle_dtmf(struct ast_bridge_channel *bridge_ch if (hook) { struct ast_frame action = { .frametype = AST_FRAME_BRIDGE_ACTION, - .subclass.integer = AST_BRIDGE_ACTION_FEATURE, + .subclass.integer = BRIDGE_CHANNEL_ACTION_FEATURE, }; ast_frfree(frame); @@ -1769,7 +1770,7 @@ void bridge_channel_join(struct ast_bridge_channel *bridge_channel) } if (bridge_channel_push(bridge_channel)) { - ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE); } bridge_reconfigured(bridge_channel->bridge, 1); @@ -1827,12 +1828,91 @@ void bridge_channel_join(struct ast_bridge_channel *bridge_channel) ast_bridge_channel_restore_formats(bridge_channel); } -void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel) +void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state) { - ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END); + ast_bridge_channel_lock(bridge_channel); + ast_bridge_channel_leave_bridge_nolock(bridge_channel, new_state); + ast_bridge_channel_unlock(bridge_channel); } -void ast_bridge_channel_leave_bridge_nolock(struct ast_bridge_channel *bridge_channel) +void ast_bridge_channel_leave_bridge_nolock(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state) { - ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END); +/* BUGBUG need cause code for the bridge_channel leaving the bridge. */ + if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) { + return; + } + + ast_debug(1, "Setting %p(%s) state from:%d to:%d\n", + bridge_channel, ast_channel_name(bridge_channel->chan), bridge_channel->state, + new_state); + + /* Change the state on the bridge channel */ + bridge_channel->state = new_state; + + bridge_channel_poke(bridge_channel); +} + +/*! + * \internal + * \brief Queue a blind transfer action on a transferee bridge channel + * + * This is only relevant for when a blind transfer is performed on a two-party + * bridge. The transferee's bridge channel will have a blind transfer bridge + * action queued onto it, resulting in the party being redirected to a new + * destination + * + * \param transferee The channel to have the action queued on + * \param exten The destination extension for the transferee + * \param context The destination context for the transferee + * \param hook Frame hook to attach to transferee + * + * \retval 0 on success. + * \retval -1 on error. + */ +int bridge_channel_queue_blind_transfer(struct ast_channel *transferee, + const char *exten, const char *context, + transfer_channel_cb new_channel_cb, void *user_data) +{ + RAII_VAR(struct ast_bridge_channel *, transferee_bridge_channel, NULL, ao2_cleanup); + struct blind_transfer_data blind_data; + + ast_channel_lock(transferee); + transferee_bridge_channel = ast_channel_get_bridge_channel(transferee); + ast_channel_unlock(transferee); + + if (!transferee_bridge_channel) { + return -1; + } + + if (new_channel_cb) { + new_channel_cb(transferee, user_data, AST_BRIDGE_TRANSFER_SINGLE_PARTY); + } + + ast_copy_string(blind_data.exten, exten, sizeof(blind_data.exten)); + ast_copy_string(blind_data.context, context, sizeof(blind_data.context)); + + return ast_bridge_channel_queue_action_data(transferee_bridge_channel, + BRIDGE_CHANNEL_ACTION_BLIND_TRANSFER, &blind_data, sizeof(blind_data)); +} + +int bridge_channel_queue_attended_transfer(struct ast_channel *transferee, + struct ast_channel *unbridged_chan) +{ + RAII_VAR(struct ast_bridge_channel *, transferee_bridge_channel, NULL, ao2_cleanup); + char unbridged_chan_name[AST_CHANNEL_NAME]; + + ast_channel_lock(transferee); + transferee_bridge_channel = ast_channel_get_bridge_channel(transferee); + ast_channel_unlock(transferee); + + if (!transferee_bridge_channel) { + return -1; + } + + ast_copy_string(unbridged_chan_name, ast_channel_name(unbridged_chan), + sizeof(unbridged_chan_name)); + + return ast_bridge_channel_queue_action_data(transferee_bridge_channel, + BRIDGE_CHANNEL_ACTION_ATTENDED_TRANSFER, unbridged_chan_name, + sizeof(unbridged_chan_name)); } diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c index e8ec1809b..ced288caf 100644 --- a/res/parking/parking_bridge_features.c +++ b/res/parking/parking_bridge_features.c @@ -404,7 +404,7 @@ static int parking_duration_callback(struct ast_bridge *bridge, struct ast_bridg user->resolution = PARK_TIMEOUT; ao2_unlock(user); - ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE); /* Set parking timeout channel variables */ snprintf(parking_space, sizeof(parking_space), "%d", user->parking_space); @@ -492,14 +492,14 @@ void say_parking_space(struct ast_bridge_channel *bridge_channel, const char *pa if (sscanf(payload, "%u %u", &hangup_after, &numeric_value) != 2) { /* If say_parking_space is called with a non-numeric string, we have a problem. */ ast_assert(0); - ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE); return; } ast_say_digits(bridge_channel->chan, numeric_value, "", ast_channel_language(bridge_channel->chan)); if (hangup_after) { - ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); + ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE); } } |