[asterisk-commits] rmudgett: branch group/bridge_construction r383793 - in /team/group/bridge_co...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Mar 25 17:28:57 CDT 2013


Author: rmudgett
Date: Mon Mar 25 17:28:53 2013
New Revision: 383793

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=383793
Log:
Bridge API Enhancements - add subclassing ability to ast_bridge

* Added ability to subclass struct ast_bridge to create new bridge types.
Parking, Queues, and ConfBridge are examples of subclassing ast_bridge.

* Made callers of ast_bridge_features_init(), ast_bridge_hangup_hook(),
ast_bridge_dtmf_hook(), and ast_bridge_interval_hook() pay attention to
the return value.

* Made bridging code use the ast_bridge_lock(), ast_bridge_unlock(),
ast_bridge_trylock(), ast_bridge_channel_lock(),
ast_bridge_channel_unlock(), and ast_bridge_channel_trylock() wrapper
functions to easily find where they are used.

* Converted the DTMF, hangup, and interval hooks to use ao2 objects and
ao2 containers.

* Made remove marked hooks on a channel when it is pulled from the bridge.

(closes issue ASTERISK-21270)
Reported by: Matt Jordan

Modified:
    team/group/bridge_construction/apps/app_bridgewait.c
    team/group/bridge_construction/apps/app_confbridge.c
    team/group/bridge_construction/apps/confbridge/conf_config_parser.c
    team/group/bridge_construction/bridges/bridge_builtin_features.c
    team/group/bridge_construction/bridges/bridge_builtin_interval_features.c
    team/group/bridge_construction/bridges/bridge_softmix.c
    team/group/bridge_construction/include/asterisk/bridging.h
    team/group/bridge_construction/include/asterisk/bridging_features.h
    team/group/bridge_construction/main/bridging.c
    team/group/bridge_construction/main/channel.c
    team/group/bridge_construction/main/features.c

Modified: team/group/bridge_construction/apps/app_bridgewait.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/apps/app_bridgewait.c?view=diff&rev=383793&r1=383792&r2=383793
==============================================================================
--- team/group/bridge_construction/apps/app_bridgewait.c (original)
+++ team/group/bridge_construction/apps/app_bridgewait.c Mon Mar 25 17:28:53 2013
@@ -140,7 +140,7 @@
 
 	/* Limits struct holds time as milliseconds, so muliply 1000x */
 	hold_limits.duration *= 1000;
-	ast_bridge_features_set_limits(features, &hold_limits);
+	ast_bridge_features_set_limits(features, &hold_limits, 1 /* remove_on_pull */);
 	ast_bridge_features_limits_destroy(&hold_limits);
 
 	return 0;
@@ -195,10 +195,10 @@
 
 	ast_mutex_lock(&bridgewait_lock);
 	if (!holding_bridge) {
-		holding_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_HOLDING, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM);
+		holding_bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_HOLDING,
+			AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM);
 	}
 	ast_mutex_unlock(&bridgewait_lock);
-
 	if (!holding_bridge) {
 		ast_log(LOG_ERROR, "Could not create holding bridge for '%s'.\n", ast_channel_name(chan));
 		return -1;
@@ -207,7 +207,10 @@
 	parse = ast_strdupa(data);
 	AST_STANDARD_APP_ARGS(args, parse);
 
-	ast_bridge_features_init(&chan_features);
+	if (ast_bridge_features_init(&chan_features)) {
+		ast_bridge_features_cleanup(&chan_features);
+		return -1;
+	}
 
 	if (args.options) {
 		char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };

Modified: team/group/bridge_construction/apps/app_confbridge.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/apps/app_confbridge.c?view=diff&rev=383793&r1=383792&r2=383793
==============================================================================
--- team/group/bridge_construction/apps/app_confbridge.c (original)
+++ team/group/bridge_construction/apps/app_confbridge.c Mon Mar 25 17:28:53 2013
@@ -1285,8 +1285,9 @@
 		conf_bridge_profile_copy(&conference->b_profile, &user->b_profile);
 
 		/* Create an actual bridge that will do the audio mixing */
-		if (!(conference->bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_MULTIMIX,
-			AST_BRIDGE_FLAG_MASQUERADE_ONLY))) {
+		conference->bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_MULTIMIX,
+			AST_BRIDGE_FLAG_MASQUERADE_ONLY);
+		if (!conference->bridge) {
 			ao2_ref(conference, -1);
 			conference = NULL;
 			ao2_unlock(conference_bridges);
@@ -1644,10 +1645,14 @@
 		AST_APP_ARG(u_profile_name);
 		AST_APP_ARG(menu_name);
 	);
-	ast_bridge_features_init(&user.features);
 
 	if (ast_channel_state(chan) != AST_STATE_UP) {
 		ast_answer(chan);
+	}
+
+	if (ast_bridge_features_init(&user.features)) {
+		res = -1;
+		goto confbridge_cleanup;
 	}
 
 	if (ast_strlen_zero(data)) {

Modified: team/group/bridge_construction/apps/confbridge/conf_config_parser.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/apps/confbridge/conf_config_parser.c?view=diff&rev=383793&r1=383792&r2=383793
==============================================================================
--- team/group/bridge_construction/apps/confbridge/conf_config_parser.c (original)
+++ team/group/bridge_construction/apps/confbridge/conf_config_parser.c Mon Mar 25 17:28:53 2013
@@ -2053,7 +2053,8 @@
 		ao2_ref(menu, +1);
 		pvt->menu = menu;
 
-		ast_bridge_dtmf_hook(&user->features, pvt->menu_entry.dtmf, menu_hook_callback, pvt, menu_hook_destroy);
+		ast_bridge_dtmf_hook(&user->features, pvt->menu_entry.dtmf, menu_hook_callback,
+			pvt, menu_hook_destroy, 0);
 	}
 
 	ao2_unlock(menu);

Modified: team/group/bridge_construction/bridges/bridge_builtin_features.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/bridges/bridge_builtin_features.c?view=diff&rev=383793&r1=383792&r2=383793
==============================================================================
--- team/group/bridge_construction/bridges/bridge_builtin_features.c (original)
+++ team/group/bridge_construction/bridges/bridge_builtin_features.c Mon Mar 25 17:28:53 2013
@@ -269,16 +269,42 @@
 	/* Get a channel that is the destination we wish to call */
 	peer = dial_transfer(bridge_channel->chan, exten, context);
 	if (!peer) {
+/* BUGBUG beeperr needs to be configurable from features.conf */
 		ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_NONE);
 		return 0;
 	}
 
-/* BUGBUG we need to wait for Party C (peer) to answer before dumping into the transient B-C bridge. */
+/* BUGBUG bridging API features does not support features.conf featuremap */
+/* BUGBUG bridging API features does not support the features.conf atxfer bounce between C & B channels */
+	/* Setup a DTMF menu to control the transfer. */
+	if (ast_bridge_features_init(&caller_features)
+		|| ast_bridge_hangup_hook(&caller_features,
+			attended_transfer_complete, &transfer_code, NULL, 0)
+		|| ast_bridge_dtmf_hook(&caller_features,
+			attended_transfer && !ast_strlen_zero(attended_transfer->abort)
+				? attended_transfer->abort : "*1",
+			attended_transfer_abort, &transfer_code, NULL, 0)
+		|| ast_bridge_dtmf_hook(&caller_features,
+			attended_transfer && !ast_strlen_zero(attended_transfer->complete)
+				? attended_transfer->complete : "*2",
+			attended_transfer_complete, &transfer_code, NULL, 0)
+		|| ast_bridge_dtmf_hook(&caller_features,
+			attended_transfer && !ast_strlen_zero(attended_transfer->threeway)
+				? attended_transfer->threeway : "*3",
+			attended_transfer_threeway, &transfer_code, NULL, 0)) {
+		ast_bridge_features_cleanup(&caller_features);
+		ast_hangup(peer);
+/* BUGBUG beeperr needs to be configurable from features.conf */
+		ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_NONE);
+		return 0;
+	}
 
 	/* Create a bridge to use to talk to the person we are calling */
-	attended_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_1TO1MIX,
+	attended_bridge = ast_bridge_base_new(
+		AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_1TO1MIX,
 		AST_BRIDGE_FLAG_DISSOLVE_HANGUP);
 	if (!attended_bridge) {
+		ast_bridge_features_cleanup(&caller_features);
 		ast_hangup(peer);
 /* BUGBUG beeperr needs to be configurable from features.conf */
 		ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_NONE);
@@ -289,29 +315,12 @@
 /* BUGBUG we should impart the peer as an independent and move it to the original bridge. */
 	if (ast_bridge_impart(attended_bridge, peer, NULL, NULL, 0)) {
 		ast_bridge_destroy(attended_bridge);
+		ast_bridge_features_cleanup(&caller_features);
 		ast_hangup(peer);
+/* BUGBUG beeperr needs to be configurable from features.conf */
 		ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_NONE);
 		return 0;
 	}
-
-	/* Setup a DTMF menu to control the transfer. */
-	ast_bridge_features_init(&caller_features);
-/* BUGBUG bridging API features does not support features.conf featuremap */
-/* BUGBUG bridging API features does not support the features.conf atxfer bounce between C & B channels */
-	ast_bridge_hangup_hook(&caller_features,
-		attended_transfer_complete, &transfer_code, NULL);
-	ast_bridge_dtmf_hook(&caller_features,
-		attended_transfer && !ast_strlen_zero(attended_transfer->abort)
-			? attended_transfer->abort : "*1",
-		attended_transfer_abort, &transfer_code, NULL);
-	ast_bridge_dtmf_hook(&caller_features,
-		attended_transfer && !ast_strlen_zero(attended_transfer->complete)
-			? attended_transfer->complete : "*2",
-		attended_transfer_complete, &transfer_code, NULL);
-	ast_bridge_dtmf_hook(&caller_features,
-		attended_transfer && !ast_strlen_zero(attended_transfer->threeway)
-			? attended_transfer->threeway : "*3",
-		attended_transfer_threeway, &transfer_code, NULL);
 
 	/*
 	 * For the caller we want to join the bridge in a blocking
@@ -329,8 +338,8 @@
 	}
 
 	/* Now that all channels are out of it we can destroy the bridge and the feature structures */
+	ast_bridge_destroy(attended_bridge);
 	ast_bridge_features_cleanup(&caller_features);
-	ast_bridge_destroy(attended_bridge);
 
 	xfer_failed = -1;
 	switch (transfer_code) {

Modified: team/group/bridge_construction/bridges/bridge_builtin_interval_features.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/bridges/bridge_builtin_interval_features.c?view=diff&rev=383793&r1=383792&r2=383793
==============================================================================
--- team/group/bridge_construction/bridges/bridge_builtin_interval_features.c (original)
+++ team/group/bridge_construction/bridges/bridge_builtin_interval_features.c Mon Mar 25 17:28:53 2013
@@ -125,11 +125,7 @@
 		limits_interval_playback(bridge, bridge_channel, limits, limits->warning_sound);
 	}
 
-	if (limits->frequency) {
-		ast_bridge_interval_hook_update(bridge_channel, limits->frequency);
-	}
-
-	return !limits->frequency ? -1 : 0;
+	return !limits->frequency ? -1 : limits->frequency;
 }
 
 static void copy_bridge_features_limits(struct ast_bridge_features_limits *dst, struct ast_bridge_features_limits *src)
@@ -144,7 +140,7 @@
 	ast_string_field_set(dst, connect_sound, src->connect_sound);
 }
 
-static int bridge_builtin_set_limits(struct ast_bridge_features *features, struct ast_bridge_features_limits *limits)
+static int bridge_builtin_set_limits(struct ast_bridge_features *features, struct ast_bridge_features_limits *limits, int remove_on_pull)
 {
 	struct ast_bridge_features_limits *feature_limits;
 
@@ -169,8 +165,9 @@
 	copy_bridge_features_limits(feature_limits, limits);
 	features->limits = feature_limits;
 
+/* BUGBUG feature interval hooks need to be reimplemented to be more stand alone. */
 	if (ast_bridge_interval_hook(features, feature_limits->duration,
-		bridge_features_duration_callback, feature_limits, NULL)) {
+		bridge_features_duration_callback, feature_limits, NULL, remove_on_pull)) {
 		ast_log(LOG_ERROR, "Failed to schedule the duration limiter to the bridge channel.\n");
 		return -1;
 	}
@@ -179,14 +176,14 @@
 
 	if (!ast_strlen_zero(feature_limits->connect_sound)) {
 		if (ast_bridge_interval_hook(features, 1,
-			bridge_features_connect_callback, feature_limits, NULL)) {
+			bridge_features_connect_callback, feature_limits, NULL, remove_on_pull)) {
 			ast_log(LOG_WARNING, "Failed to schedule connect sound to the bridge channel.\n");
 		}
 	}
 
 	if (feature_limits->warning && feature_limits->warning < feature_limits->duration) {
 		if (ast_bridge_interval_hook(features, feature_limits->duration - feature_limits->warning,
-			bridge_features_warning_callback, feature_limits, NULL)) {
+			bridge_features_warning_callback, feature_limits, NULL, remove_on_pull)) {
 			ast_log(LOG_WARNING, "Failed to schedule warning sound playback to the bridge channel.\n");
 		}
 	}

Modified: team/group/bridge_construction/bridges/bridge_softmix.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/bridges/bridge_softmix.c?view=diff&rev=383793&r1=383792&r2=383793
==============================================================================
--- team/group/bridge_construction/bridges/bridge_softmix.c (original)
+++ team/group/bridge_construction/bridges/bridge_softmix.c Mon Mar 25 17:28:53 2013
@@ -845,17 +845,17 @@
 		}
 		stat_iteration_counter--;
 
-		ao2_unlock(bridge);
+		ast_bridge_unlock(bridge);
 		/* cleanup any translation frame data from the previous mixing iteration. */
 		softmix_translate_helper_cleanup(&trans_helper);
 		/* Wait for the timing source to tell us to wake up and get things done */
 		ast_waitfor_n_fd(&timingfd, 1, &timeout, NULL);
 		if (ast_timer_ack(timer, 1) < 0) {
 			ast_log(LOG_ERROR, "Failed to acknowledge timer in softmix bridge.\n");
-			ao2_lock(bridge);
+			ast_bridge_lock(bridge);
 			goto softmix_cleanup;
 		}
-		ao2_lock(bridge);
+		ast_bridge_lock(bridge);
 
 		/* make sure to detect mixing interval changes if they occur. */
 		if (bridge->internal_mixing_interval && (bridge->internal_mixing_interval != softmix_data->internal_mixing_interval)) {
@@ -887,7 +887,7 @@
 	struct ast_bridge *bridge = data;
 	struct softmix_bridge_data *softmix_data;
 
-	ao2_lock(bridge);
+	ast_bridge_lock(bridge);
 	if (bridge->callid) {
 		ast_callid_threadassoc_add(bridge->callid);
 	}
@@ -898,13 +898,13 @@
 	while (!softmix_data->stop) {
 		if (!bridge->num_active) {
 			/* Wait for something to happen to the bridge. */
-			ao2_unlock(bridge);
+			ast_bridge_unlock(bridge);
 			ast_mutex_lock(&softmix_data->lock);
 			if (!softmix_data->stop) {
 				ast_cond_wait(&softmix_data->cond, &softmix_data->lock);
 			}
 			ast_mutex_unlock(&softmix_data->lock);
-			ao2_lock(bridge);
+			ast_bridge_lock(bridge);
 			continue;
 		}
 
@@ -913,13 +913,13 @@
 			 * A mixing error occurred.  Sleep and try again later so we
 			 * won't flood the logs.
 			 */
-			ao2_unlock(bridge);
+			ast_bridge_unlock(bridge);
 			sleep(1);
-			ao2_lock(bridge);
-		}
-	}
-
-	ao2_unlock(bridge);
+			ast_bridge_lock(bridge);
+		}
+	}
+
+	ast_bridge_unlock(bridge);
 
 	ast_debug(1, "Stopping mixing thread for bridge %p\n", bridge);
 

Modified: team/group/bridge_construction/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/bridging.h?view=diff&rev=383793&r1=383792&r2=383793
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging.h Mon Mar 25 17:28:53 2013
@@ -118,6 +118,7 @@
  * \brief Structure that contains information regarding a channel in a bridge
  */
 struct ast_bridge_channel {
+/* BUGBUG cond is only here because of external party suspend/unsuspend support. */
 	/*! Condition, used if we want to wake up a thread waiting on the bridged channel */
 	ast_cond_t cond;
 	/*! Current bridged channel state */
@@ -128,7 +129,21 @@
 	struct ast_channel *swap;
 	/*! Bridge this channel is participating in */
 	struct ast_bridge *bridge;
-	/*! Private information unique to the bridge technology */
+	/*!
+	 * \brief Bridge class private channel data.
+	 *
+	 * \note This information is added when the channel is pushed
+	 * into the bridge and removed when it is pulled from the
+	 * bridge.
+	 */
+	void *bridge_pvt;
+	/*!
+	 * \brief Private information unique to the bridge technology.
+	 *
+	 * \note This information is added when the channel joins the
+	 * bridge's technology and removed when it leaves the bridge's
+	 * technology.
+	 */
 	void *tech_pvt;
 	/*! Thread handling the bridged channel (Needed by ast_bridge_depart) */
 	pthread_t thread;
@@ -214,15 +229,125 @@
 };
 
 /*!
+ * \brief Destroy the bridge.
+ *
+ * \param self Bridge to operate upon.
+ *
+ * \return Nothing
+ */
+typedef void (*ast_bridge_destructor_fn)(struct ast_bridge *self);
+
+/*!
+ * \brief Can this channel be pushed into the bridge.
+ *
+ * \param self Bridge to operate upon.
+ * \param bridge_channel Bridge channel wanting to push.
+ * \param swap Bridge channel to swap places with if not NULL.
+ *
+ * \note On entry, self is already locked.
+ *
+ * \retval TRUE if can push this channel into the bridge.
+ */
+typedef int (*ast_bridge_can_push_channel_fn)(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap);
+
+/*!
+ * \brief Push this channel into the bridge.
+ *
+ * \param self Bridge to operate upon.
+ * \param bridge_channel Bridge channel to push.
+ * \param swap Bridge channel to swap places with if not NULL.
+ *
+ * \details
+ * Setup any channel hooks controlled by the bridge.  Allocate
+ * bridge_channel->bridge_pvt and initialize any resources put
+ * in bridge_channel->bridge_pvt if needed.  If there is a swap
+ * channel, use it as a guide to setting up the bridge_channel.
+ *
+ * \note On entry, self is already locked.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+typedef int (*ast_bridge_push_channel_fn)(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap);
+
+/*!
+ * \brief Pull this channel from the bridge.
+ *
+ * \param self Bridge to operate upon.
+ * \param bridge_channel Bridge channel to pull.
+ *
+ * \details
+ * Remove any channel hooks controlled by the bridge.  Release
+ * any resources held by bridge_channel->bridge_pvt and release
+ * bridge_channel->bridge_pvt.
+ *
+ * \note On entry, self is already locked.
+ *
+ * \return Nothing
+ */
+typedef void (*ast_bridge_pull_channel_fn)(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel);
+
+/*!
+ * \brief Notify the bridge that this channel was just masqueraded.
+ *
+ * \param self Bridge to operate upon.
+ * \param bridge_channel Bridge channel that was masqueraded.
+ *
+ * \details
+ * A masquerade just happened to this channel.  The bridge needs
+ * to re-evaluate this a channel in the bridge.
+ *
+ * \note On entry, self is already locked.
+ *
+ * \return Nothing
+ */
+typedef void (*ast_bridge_notify_masquerade_fn)(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel);
+
+/*!
+ * \brief Bridge virtual methods table definition.
+ *
+ * \note Any changes to this struct must be reflected in
+ * ast_bridge_alloc() validity checking.
+ */
+struct ast_bridge_methods {
+	/*! Bridge class name for log messages. */
+	const char *name;
+	/*! Destroy the bridge. */
+	ast_bridge_destructor_fn destroy;
+	/*! TRUE if can push the bridge channel into the bridge. */
+	ast_bridge_can_push_channel_fn can_push;
+	/*! Push the bridge channel into the bridge. */
+	ast_bridge_push_channel_fn push;
+	/*! Pull the bridge channel from the bridge. */
+	ast_bridge_pull_channel_fn pull;
+	/*! Notify the bridge of a masquerade with the channel. */
+	ast_bridge_notify_masquerade_fn notify_masquerade;
+};
+
+/*!
  * \brief Structure that contains information about a bridge
  */
 struct ast_bridge {
+	/*! Bridge virtual method table. */
+	const struct ast_bridge_methods *v_table;
+	/*! Bridge technology that is handling the bridge */
+	struct ast_bridge_technology *technology;
+	/*! Private information unique to the bridge technology */
+	void *tech_pvt;
+	/*! Call ID associated with the bridge */
+	struct ast_callid *callid;
+	/*! Linked list of channels participating in the bridge */
+	AST_LIST_HEAD_NOLOCK(, ast_bridge_channel) channels;
+	/*! Queue of actions to perform on the bridge. */
+	AST_LIST_HEAD_NOLOCK(, ast_frame) action_queue;
+	/*! The video mode this bridge is using */
+	struct ast_bridge_video_mode video_mode;
+	/*! Bridge flags to tweak behavior */
+	struct ast_flags feature_flags;
 	/*! Number of channels participating in the bridge */
 	unsigned int num_channels;
 	/*! Number of active channels in the bridge. */
 	unsigned int num_active;
-	/*! The video mode this bridge is using */
-	struct ast_bridge_video_mode video_mode;
 	/*!
 	 * \brief Count of the active temporary requests to inhibit bridge merges.
 	 * Zero if merges are allowed.
@@ -241,26 +366,53 @@
 	unsigned int reconfigured:1;
 	/*! TRUE if the bridge has been dissolved.  Any channel that now tries to join is immediately ejected. */
 	unsigned int dissolved:1;
-	/*! Bridge flags to tweak behavior */
-	struct ast_flags feature_flags;
-	/*! Bridge technology that is handling the bridge */
-	struct ast_bridge_technology *technology;
-	/*! Private information unique to the bridge technology */
-	void *tech_pvt;
-	/*! Call ID associated with the bridge */
-	struct ast_callid *callid;
-	/*! Linked list of channels participating in the bridge */
-	AST_LIST_HEAD_NOLOCK(, ast_bridge_channel) channels;
-	/*! Queue of actions to perform on the bridge. */
-	AST_LIST_HEAD_NOLOCK(, ast_frame) action_queue;
 };
 
 /*!
- * \brief Create a new bridge
- *
+ * \internal
+ * \brief Allocate the bridge class object memory.
+ * \since 12.0.0
+ *
+ * \param size Size of the bridge class structure to allocate.
+ * \param v_table Bridge class virtual method table.
+ *
+ * \retval bridge on success.
+ * \retval NULL on error.
+ */
+struct ast_bridge *ast_bridge_alloc(size_t size, const struct ast_bridge_methods *v_table);
+
+/*! \brief Bridge base class virtual method table. */
+extern struct ast_bridge_methods ast_bridge_base_v_table;
+
+/*!
+ * \brief Initialize the base class of the bridge.
+ *
+ * \param self Bridge to operate upon. (Tollerates a NULL pointer)
  * \param capabilities The capabilities that we require to be used on the bridge
  * \param flags Flags that will alter the behavior of the bridge
  *
+ * \retval self on success
+ * \retval NULL on failure, self is already destroyed
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_bridge *bridge;
+ * bridge = ast_bridge_alloc(sizeof(*bridge), &ast_bridge_base_v_table);
+ * bridge = ast_bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_1TO1MIX, AST_BRIDGE_FLAG_DISSOLVE_HANGUP);
+ * \endcode
+ *
+ * This creates a no frills two party bridge that will be
+ * destroyed once one of the channels hangs up.
+ */
+struct ast_bridge *ast_bridge_base_init(struct ast_bridge *self, uint32_t capabilities, int flags);
+
+/*!
+ * \brief Create a new base class bridge
+ *
+ * \param capabilities The capabilities that we require to be used on the bridge
+ * \param flags Flags that will alter the behavior of the bridge
+ *
  * \retval a pointer to a new bridge on success
  * \retval NULL on failure
  *
@@ -268,13 +420,27 @@
  *
  * \code
  * struct ast_bridge *bridge;
- * bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_1TO1MIX, AST_BRIDGE_FLAG_DISSOLVE_HANGUP);
- * \endcode
- *
- * This creates a simple two party bridge that will be destroyed once one of
- * the channels hangs up.
- */
-struct ast_bridge *ast_bridge_new(uint32_t capabilities, int flags);
+ * bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_1TO1MIX, AST_BRIDGE_FLAG_DISSOLVE_HANGUP);
+ * \endcode
+ *
+ * This creates a no frills two party bridge that will be
+ * destroyed once one of the channels hangs up.
+ */
+struct ast_bridge *ast_bridge_base_new(uint32_t capabilities, int flags);
+
+/*!
+ * \brief Try locking the bridge.
+ *
+ * \param bridge Bridge to try locking
+ *
+ * \retval 0 on success.
+ * \retval non-zero on error.
+ */
+#define ast_bridge_trylock(bridge)	_ast_bridge_trylock(bridge, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge)
+static inline int _ast_bridge_trylock(struct ast_bridge *bridge, const char *file, const char *function, int line, const char *var)
+{
+	return __ao2_trylock(bridge, AO2_LOCK_REQ_MUTEX, file, function, line, var);
+}
 
 /*!
  * \brief Lock the bridge.
@@ -335,9 +501,19 @@
  * ast_bridge_destroy(bridge);
  * \endcode
  *
- * This destroys a bridge that was previously created using ast_bridge_new.
+ * This destroys a bridge that was previously created.
  */
 int ast_bridge_destroy(struct ast_bridge *bridge);
+
+/*!
+ * \brief Notify bridging that this channel was just masqueraded.
+ * \since 12.0.0
+ *
+ * \param chan Channel just involved in a masquerade
+ *
+ * \return Nothing
+ */
+void ast_bridge_notify_masquerade(struct ast_channel *chan);
 
 /*!
  * \brief Join (blocking) a channel to a bridge
@@ -558,6 +734,46 @@
 int ast_bridge_unsuspend(struct ast_bridge *bridge, struct ast_channel *chan);
 
 /*!
+ * \brief Try locking the bridge_channel.
+ *
+ * \param bridge_channel What to try locking
+ *
+ * \retval 0 on success.
+ * \retval non-zero on error.
+ */
+#define ast_bridge_channel_trylock(bridge_channel)	_ast_bridge_channel_trylock(bridge_channel, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge_channel)
+static inline int _ast_bridge_channel_trylock(struct ast_bridge_channel *bridge_channel, const char *file, const char *function, int line, const char *var)
+{
+	return __ao2_trylock(bridge_channel, AO2_LOCK_REQ_MUTEX, file, function, line, var);
+}
+
+/*!
+ * \brief Lock the bridge_channel.
+ *
+ * \param bridge_channel What to lock
+ *
+ * \return Nothing
+ */
+#define ast_bridge_channel_lock(bridge_channel)	_ast_bridge_channel_lock(bridge_channel, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge_channel)
+static inline void _ast_bridge_channel_lock(struct ast_bridge_channel *bridge_channel, const char *file, const char *function, int line, const char *var)
+{
+	__ao2_lock(bridge_channel, AO2_LOCK_REQ_MUTEX, file, function, line, var);
+}
+
+/*!
+ * \brief Unlock the bridge_channel.
+ *
+ * \param bridge_channel What to unlock
+ *
+ * \return Nothing
+ */
+#define ast_bridge_channel_unlock(bridge_channel)	_ast_bridge_channel_unlock(bridge_channel, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge_channel)
+static inline void _ast_bridge_channel_unlock(struct ast_bridge_channel *bridge_channel, const char *file, const char *function, int line, const char *var)
+{
+	__ao2_unlock(bridge_channel, file, function, line, var);
+}
+
+/*!
  * \brief Set bridge channel state to leave bridge (if not leaving already) with no lock.
  *
  * \param bridge_channel Channel to change the state on

Modified: team/group/bridge_construction/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/bridging_features.h?view=diff&rev=383793&r1=383792&r2=383793
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging_features.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging_features.h Mon Mar 25 17:28:53 2013
@@ -32,16 +32,19 @@
 enum ast_bridge_feature_flags {
 	/*! Upon channel hangup all bridge participants should be kicked out. */
 	AST_BRIDGE_FLAG_DISSOLVE_HANGUP = (1 << 0),
+	/*! The last channel to leave the bridge dissolves it. */
+	AST_BRIDGE_FLAG_DISSOLVE_EMPTY = (1 << 1),
 	/*! Move between bridging technologies as needed. */
-	AST_BRIDGE_FLAG_SMART = (1 << 1),
-	/*! This channel leaves the bridge if all participants have this flag set. */
-	AST_BRIDGE_FLAG_LONELY = (1 << 2),
+	AST_BRIDGE_FLAG_SMART = (1 << 2),
 	/*! Bridge channels cannot be merged from this bridge. */
 	AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM = (1 << 3),
 	/*! Bridge channels cannot be merged to this bridge. */
 	AST_BRIDGE_FLAG_MERGE_INHIBIT_TO = (1 << 4),
 	/*! Bridge channels can be moved to another bridge only by masquerade (ConfBridge) */
 	AST_BRIDGE_FLAG_MASQUERADE_ONLY = (1 << 5),
+
+	/*! This channel leaves the bridge if all participants have this flag set. */
+	AST_BRIDGE_FLAG_LONELY = (1 << 10),
 };
 
 /*! \brief Built in DTMF features */
@@ -103,6 +106,12 @@
  * \param bridge_channel Channel executing the feature
  * \param hook_pvt Private data passed in when the hook was created
  *
+ * For interval hooks:
+ * \retval 0 Setup to fire again at the last interval.
+ * \retval positive Setup to fire again at the new interval returned.
+ * \retval -1 Remove the callback hook.
+ *
+ * For other hooks:
  * \retval 0 Keep the callback hook.
  * \retval -1 Remove the callback hook.
  */
@@ -149,14 +158,14 @@
 	/*! Time at which the hook should actually trip */
 	struct timeval trip_time;
 	/*! Heap index for interval hook */
-	ssize_t __heap_index;
+	ssize_t heap_index;
 	/*! Interval that the hook should execute at in milliseconds */
 	unsigned int interval;
 	/*! Sequence number for the hook to ensure expiration ordering */
 	unsigned int seqno;
 };
 
-/* BUGBUG ast_bridge_hook needs to be turned into ao2 objects so bridge push/pulls can add/remove hooks */
+/* BUGBUG Need to be able to selectively remove DTMF, hangup, and interval hooks. */
 /*! \brief Structure that is the essence of a feature hook. */
 struct ast_bridge_hook {
 	/*! Linked list information */
@@ -167,6 +176,8 @@
 	ast_bridge_hook_pvt_destructor destructor;
 	/*! Unique data that was passed into us */
 	void *hook_pvt;
+	/*! TRUE if the hook is removed when the channel is pulled from the bridge. */
+	unsigned int remove_on_pull:1;
 	/*! Extra hook parameters. */
 	union {
 		/*! Extra parameters for a DTMF feature hook. */
@@ -182,13 +193,10 @@
  * \brief Structure that contains features information
  */
 struct ast_bridge_features {
-/* BUGBUG dtmf_hooks needs to be an ao2_container so it would be possible to iterate without keeping a lock */
 	/*! Attached DTMF feature hooks */
-	AST_LIST_HEAD_NOLOCK(, ast_bridge_hook) dtmf_hooks;
-/* BUGBUG hangup_hooks needs to be an ao2_container so it would be possible to iterate without keeping a lock */
-	/*! Attached hangup interception hooks */
-	AST_LIST_HEAD_NOLOCK(, ast_bridge_hook) hangup_hooks;
-/* BUGBUG use of interval_hooks needs to be made ao2 safe */
+	struct ao2_container *dtmf_hooks;
+	/*! Attached hangup interception hooks container */
+	struct ao2_container *hangup_hooks;
 	/*! Attached interval hooks */
 	struct ast_heap *interval_hooks;
 	/*! Used to determine when interval based features should be checked */
@@ -300,6 +308,18 @@
 int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature);
 
 /*!
+ * \brief Attach interval hooks to a bridge features structure
+ *
+ * \param features Bridge features structure
+ * \param limits Configured limits applicable to the channel
+ * \param remove_on_pull TRUE if remove the hook when the channel is pulled from the bridge.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+typedef int (*ast_bridge_builtin_set_limits_fn)(struct ast_bridge_features *features, struct ast_bridge_features_limits *limits, int remove_on_pull);
+
+/*!
  * \brief Register a handler for a built in interval feature
  *
  * \param interval The interval feature that the handler will be responsible for
@@ -317,7 +337,7 @@
  * This registers the function bridge_builtin_set_limits as the function responsible for the built in
  * duration limit feature.
  */
-int ast_bridge_interval_register(enum ast_bridge_builtin_interval interval, void *callback);
+int ast_bridge_interval_register(enum ast_bridge_builtin_interval interval, ast_bridge_builtin_set_limits_fn callback);
 
 /*!
  * \brief Unregisters a handler for a built in interval feature
@@ -344,16 +364,17 @@
  * \param callback Function to execute upon activation
  * \param hook_pvt Unique data
  * \param destructor Optional destructor callback for hook_pvt data
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * ast_bridge_hangup_hook(&features, hangup_callback, NULL, NULL);
+ * \param remove_on_pull TRUE if remove the hook when the channel is pulled from the bridge.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_bridge_features features;
+ * ast_bridge_features_init(&features);
+ * ast_bridge_hangup_hook(&features, hangup_callback, NULL, NULL, 0);
  * \endcode
  *
  * This makes the bridging core call hangup_callback if a
@@ -363,7 +384,8 @@
 int ast_bridge_hangup_hook(struct ast_bridge_features *features,
 	ast_bridge_hook_callback callback,
 	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor);
+	ast_bridge_hook_pvt_destructor destructor,
+	int remove_on_pull);
 
 /*!
  * \brief Attach a DTMF hook to a bridge features structure
@@ -373,16 +395,17 @@
  * \param callback Function to execute upon activation
  * \param hook_pvt Unique data
  * \param destructor Optional destructor callback for hook_pvt data
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * ast_bridge_dtmf_hook(&features, "#", pound_callback, NULL, NULL);
+ * \param remove_on_pull TRUE if remove the hook when the channel is pulled from the bridge.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_bridge_features features;
+ * ast_bridge_features_init(&features);
+ * ast_bridge_dtmf_hook(&features, "#", pound_callback, NULL, NULL, 0);
  * \endcode
  *
  * This makes the bridging core call pound_callback if a channel that has this
@@ -393,7 +416,8 @@
 	const char *dtmf,
 	ast_bridge_hook_callback callback,
 	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor);
+	ast_bridge_hook_pvt_destructor destructor,
+	int remove_on_pull);
 
 /*!
  * \brief attach an interval hook to a bridge features structure
@@ -403,14 +427,15 @@
  * \param callback Function to execute upon activation
  * \param hook_pvt Unique data
  * \param destructor Optional destructor callback for hook_pvt data
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * ast_bridge_interval_hook(&features, 1000, playback_callback, NULL, NULL);
+ * \param remove_on_pull TRUE if remove the hook when the channel is pulled from the bridge.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * \code
+ * struct ast_bridge_features features;
+ * ast_bridge_features_init(&features);
+ * ast_bridge_interval_hook(&features, 1000, playback_callback, NULL, NULL, 0);
  * \endcode
  *
  * This makes the bridging core call playback_callback every second. A pointer to useful
@@ -420,29 +445,8 @@
 	unsigned int interval,
 	ast_bridge_hook_callback callback,
 	void *hook_pvt,
-	ast_bridge_hook_pvt_destructor destructor);
-
-/*!
- * \brief Update the interval on an interval hook that is currently executing a callback
- *
- * \param bridge_channel The bridge channel that is executing the callback
- * \param interval The new interval value or 0 to remove the interval hook
- *
- * \retval 0 on success
- * \retval 1 on failure
- *
- * Example usage:
- *
- * \code
- * ast_bridge_interval_hook_update(bridge_channel, 10000);
- * \endcode
- *
- * This updates the executing interval hook so that it will be triggered next in 10 seconds.
- *
- * \note This can only be called from the context of the interval hook callback itself. If this
- *       is called outside the callback then behavior is undefined.
- */
-int ast_bridge_interval_hook_update(struct ast_bridge_channel *bridge_channel, unsigned int interval);
+	ast_bridge_hook_pvt_destructor destructor,
+	int remove_on_pull);
 
 /*!
  * \brief Set a callback on the features structure to receive talking notifications on.
@@ -467,23 +471,29 @@
  * \param dtmf Optionally the DTMF stream to trigger the feature, if not specified it will be the default
  * \param config Configuration structure unique to the built in type
  * \param destructor Optional destructor callback for config data
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * ast_bridge_features_enable(&features, AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, NULL, NULL);
+ * \param remove_on_pull TRUE if remove the hook when the channel is pulled from the bridge.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_bridge_features features;
+ * ast_bridge_features_init(&features);
+ * ast_bridge_features_enable(&features, AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, NULL, NULL, 0);
  * \endcode
  *
  * This enables the attended transfer DTMF option using the default DTMF string. An alternate
  * string may be provided using the dtmf parameter. Internally this is simply setting up a hook
  * to a built in feature callback function.
  */
-int ast_bridge_features_enable(struct ast_bridge_features *features, enum ast_bridge_builtin_feature feature, const char *dtmf, void *config, ast_bridge_hook_pvt_destructor destructor);
+int ast_bridge_features_enable(struct ast_bridge_features *features,
+	enum ast_bridge_builtin_feature feature,
+	const char *dtmf,
+	void *config,
+	ast_bridge_hook_pvt_destructor destructor,
+	int remove_on_pull);
 
 /*!
  * \brief Constructor function for ast_bridge_features_limits
@@ -510,6 +520,7 @@
  *
  * \param features Bridge features structure
  * \param limits Configured limits applicable to the channel
+ * \param remove_on_pull TRUE if remove the hook when the channel is pulled from the bridge.
  *
  * \retval 0 on success
  * \retval -1 on failure
@@ -521,7 +532,7 @@
  * struct ast_bridge_features_limits limits;
  * ast_bridge_features_init(&features);
  * ast_bridge_features_limits_construct(&limits);
- * ast_bridge_features_set_limits(&features, &limits);
+ * ast_bridge_features_set_limits(&features, &limits, 0);
  * ast_bridge_features_limits_destroy(&limits);
  * \endcode
  *
@@ -530,7 +541,7 @@
  * \note This API call can only be used on a features structure that will be used in association with a bridge channel.
  * \note The ast_bridge_features_limits structure must remain accessible for the lifetime of the features structure.
  */
-int ast_bridge_features_set_limits(struct ast_bridge_features *features, struct ast_bridge_features_limits *limits);
+int ast_bridge_features_set_limits(struct ast_bridge_features *features, struct ast_bridge_features_limits *limits, int remove_on_pull);
 
 /*!
  * \brief Set a flag on a bridge features structure

Modified: team/group/bridge_construction/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/main/bridging.c?view=diff&rev=383793&r1=383792&r2=383793
==============================================================================
--- team/group/bridge_construction/main/bridging.c (original)
+++ team/group/bridge_construction/main/bridging.c Mon Mar 25 17:28:53 2013
@@ -66,6 +66,7 @@
 
 static void cleanup_video_mode(struct ast_bridge *bridge);
 static int bridge_make_compatible(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel);
+static void bridge_features_remove_on_pull(struct ast_bridge_features *features);
 
 /*! Default DTMF keys for built in features */
 static char builtin_features_dtmf[AST_BRIDGE_BUILTIN_END][MAXIMUM_DTMF_FEATURE_STRING];
@@ -74,7 +75,7 @@
 static void *builtin_features_handlers[AST_BRIDGE_BUILTIN_END];
 
 /*! Function handlers for built in interval features */
-static void *builtin_interval_handlers[AST_BRIDGE_BUILTIN_INTERVAL_END];
+static ast_bridge_builtin_set_limits_fn builtin_interval_handlers[AST_BRIDGE_BUILTIN_INTERVAL_END];

[... 2026 lines stripped ...]



More information about the asterisk-commits mailing list