[asterisk-commits] jrose: branch group/bridge_construction r381508 - in /team/group/bridge_const...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Feb 14 15:39:12 CST 2013


Author: jrose
Date: Thu Feb 14 15:39:09 2013
New Revision: 381508

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=381508
Log:
bridging: Interval Hooks - Phase 2

Changes interval hooks for limits so that they are installable
from the bridge_builtin_interval_features module.

Review: https://reviewboard.asterisk.org/r/2328/

Added:
    team/group/bridge_construction/bridges/bridge_builtin_interval_features.c   (with props)
Modified:
    team/group/bridge_construction/   (props changed)
    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/features.c

Propchange: team/group/bridge_construction/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Feb 14 15:39:09 2013
@@ -1,1 +1,1 @@
-/team/jrose/bridge_projects:380850,380966-380967
+/team/jrose/bridge_projects:380850,380966-380967,381253,381279,381343,381363,381468,381504

Added: 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=auto&rev=381508
==============================================================================
--- team/group/bridge_construction/bridges/bridge_builtin_interval_features.c (added)
+++ team/group/bridge_construction/bridges/bridge_builtin_interval_features.c Thu Feb 14 15:39:09 2013
@@ -1,0 +1,220 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Jonathan Rose <jrose at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Built in bridging interval features
+ *
+ * \author Jonathan Rose <jrose at digium.com>
+ *
+ * \ingroup bridges
+ */
+
+/*** MODULEINFO
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$REVISION: 381278 $")
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "asterisk/module.h"
+#include "asterisk/channel.h"
+#include "asterisk/bridging.h"
+#include "asterisk/file.h"
+#include "asterisk/app.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/test.h"
+
+#include "asterisk/say.h"
+#include "asterisk/stringfields.h"
+#include "asterisk/musiconhold.h"
+
+static int bridge_features_duration_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+	struct ast_bridge_features_limits *limits = hook_pvt;
+
+	if (!ast_strlen_zero(limits->duration_sound)) {
+		ast_stream_and_wait(bridge_channel->chan, limits->duration_sound, AST_DIGIT_NONE);
+	}
+
+	ao2_lock(bridge_channel);
+	switch (bridge_channel->state) {
+	case AST_BRIDGE_CHANNEL_STATE_WAIT:
+		ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+		break;
+	default:
+		break;
+	}
+	ao2_unlock(bridge_channel);
+
+	ast_test_suite_event_notify("BRIDGE_TIMELIMIT", "Channel1: %s", ast_channel_name(bridge_channel->chan));
+	return -1;
+}
+
+static void limits_interval_playback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_bridge_features_limits *limits, const char *file)
+{
+	if (!strcasecmp(file, "timeleft")) {
+		unsigned int remaining = ast_tvdiff_ms(limits->quitting_time, ast_tvnow()) / 1000;
+		unsigned int min;
+		unsigned int sec;
+
+		if (remaining <= 0) {
+			return;
+		}
+
+		if ((remaining / 60) > 1) {
+			min = remaining / 60;
+			sec = remaining % 60;
+		} else {
+			min = 0;
+			sec = remaining;
+		}
+
+		ast_stream_and_wait(bridge_channel->chan, "vm-youhave", AST_DIGIT_NONE);
+		if (min) {
+			ast_say_number(bridge_channel->chan, min, AST_DIGIT_NONE,
+				ast_channel_language(bridge_channel->chan), NULL);
+			ast_stream_and_wait(bridge_channel->chan, "queue-minutes", AST_DIGIT_NONE);
+		}
+		if (sec) {
+			ast_say_number(bridge_channel->chan, sec, AST_DIGIT_NONE,
+				ast_channel_language(bridge_channel->chan), NULL);
+			ast_stream_and_wait(bridge_channel->chan, "queue-seconds", AST_DIGIT_NONE);
+		}
+	} else {
+		ast_stream_and_wait(bridge_channel->chan, file, AST_DIGIT_NONE);
+	}
+
+	/* It may be necessary to resume music on hold after we finish playing the announcment. */
+	if (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_MOH)) {
+		ast_moh_start(bridge_channel->chan, NULL, NULL);
+	}
+}
+
+static int bridge_features_connect_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+	struct ast_bridge_features_limits *limits = hook_pvt;
+
+	if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
+		return -1;
+	}
+
+	limits_interval_playback(bridge, bridge_channel, limits, limits->connect_sound);
+	return -1;
+}
+
+static int bridge_features_warning_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+	struct ast_bridge_features_limits *limits = hook_pvt;
+
+	if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+		/* If we aren't in the wait state, something more important than this warning is happening and we should skip it. */
+		limits_interval_playback(bridge, bridge_channel, limits, limits->warning_sound);
+	}
+
+	if (limits->frequency) {
+		ast_bridge_features_interval_update(bridge_channel, limits->frequency);
+	}
+
+	return !limits->frequency ? -1 : 0;
+}
+
+static void copy_bridge_features_limits(struct ast_bridge_features_limits *dst, struct ast_bridge_features_limits *src)
+{
+	dst->duration = src->duration;
+	dst->warning = src->warning;
+	dst->frequency = src->frequency;
+	dst->quitting_time = src->quitting_time;
+
+	ast_string_field_set(dst, duration_sound, src->duration_sound);
+	ast_string_field_set(dst, warning_sound, src->warning_sound);
+	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)
+{
+	struct ast_bridge_features_limits *feature_limits;
+
+	if (!limits->duration) {
+		return -1;
+	}
+
+	if (features->limits) {
+		ast_log(LOG_ERROR, "Tried to apply limits to a feature set that already has limits.\n");
+		return -1;
+	}
+
+	feature_limits = ast_malloc(sizeof(*feature_limits));
+	if (!feature_limits) {
+		return -1;
+	}
+
+	if (ast_bridge_features_limits_construct(feature_limits)) {
+		return -1;
+	}
+
+	copy_bridge_features_limits(feature_limits, limits);
+	features->limits = feature_limits;
+
+	if (ast_bridge_features_interval_hook(features, feature_limits->duration,
+		bridge_features_duration_callback, feature_limits, NULL)) {
+		ast_log(LOG_ERROR, "Failed to schedule the duration limiter to the bridge channel.\n");
+		return -1;
+	}
+
+	feature_limits->quitting_time = ast_tvadd(ast_tvnow(), ast_samp2tv(feature_limits->duration, 1000));
+
+	if (!ast_strlen_zero(feature_limits->connect_sound)) {
+		if (ast_bridge_features_interval_hook(features, 1, bridge_features_connect_callback, feature_limits, NULL)) {
+			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_features_interval_hook(features, feature_limits->duration - feature_limits->warning,
+			bridge_features_warning_callback,
+			feature_limits, NULL)) {
+			ast_log(LOG_WARNING, "Failed to schedule warning sound playback to the bridge channel.\n");
+		}
+	}
+
+	return 0;
+}
+
+static int unload_module(void)
+{
+	return 0;
+}
+
+static int load_module(void)
+{
+	ast_bridge_interval_register(AST_BRIDGE_BUILTIN_INTERVAL_LIMITS, bridge_builtin_set_limits);
+
+	/* Bump up our reference count so we can't be unloaded. */
+	ast_module_ref(ast_module_info->self);
+
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Built in bridging interval features");

Propchange: team/group/bridge_construction/bridges/bridge_builtin_interval_features.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/group/bridge_construction/bridges/bridge_builtin_interval_features.c
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Rev URL"

Propchange: team/group/bridge_construction/bridges/bridge_builtin_interval_features.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

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=381508&r1=381507&r2=381508
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging.h Thu Feb 14 15:39:09 2013
@@ -544,6 +544,17 @@
 int ast_bridge_unsuspend(struct ast_bridge *bridge, struct ast_channel *chan);
 
 /*!
+ * \brief Change the state of a bridged channel without taking and releasing the bridge channel lock
+ *
+ * \param bridge_channel Channel to change the state on
+ * \param new_state The new state to place the channel into
+ *
+ * \note Do not use this call outside the context of either interval hook callbacks or bridging core.
+ *       This function assumes the bridge_channel is locked.
+ */
+void ast_bridge_change_state_nolock(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state);
+
+/*!
  * \brief Change the state of a bridged channel
  *
  * \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=381508&r1=381507&r2=381508
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging_features.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging_features.h Thu Feb 14 15:39:09 2013
@@ -79,6 +79,14 @@
 	AST_BRIDGE_BUILTIN_END
 };
 
+enum ast_bridge_builtin_interval {
+	/*! Apply Call Duration Limits */
+	AST_BRIDGE_BUILTIN_INTERVAL_LIMITS,
+
+	/*! End terminator for list of built in interval features. Must remain last. */
+	AST_BRIDGE_BUILTIN_INTERVAL_END
+};
+
 struct ast_bridge;
 struct ast_bridge_channel;
 
@@ -142,12 +150,12 @@
 	ast_bridge_features_hook_pvt_destructor destructor;
 	/*! Unique data that was passed into us */
 	void *hook_pvt;
+	/*! Sequence number for the hook if it is an interval hook */
+	unsigned int seqno;
 	/*! Linked list information */
 	AST_LIST_ENTRY(ast_bridge_features_hook) entry;
 	/*! Heap index for interval hooks */
 	ssize_t __heap_index;
-	/*! TRUE if we should take into account the time spent executing the callback when rescheduling the interval hook */
-	unsigned int interval_strict:1;
 };
 
 #define BRIDGE_FEATURES_INTERVAL_RATE 10
@@ -170,6 +178,10 @@
 	void *talker_pvt_data;
 	/*! Feature flags that are enabled */
 	struct ast_flags feature_flags;
+	/*! Limits feature data */
+	struct ast_bridge_features_limits *limits;
+	/*! Used to assign the sequence number to the next interval hook added. */
+	unsigned int interval_sequence;
 	/*! Bit to indicate that the feature_flags and hook list is setup */
 	unsigned int usable:1;
 	/*! Bit to indicate whether the channel/bridge is muted or not */
@@ -212,10 +224,17 @@
 	unsigned int warning;
 	/*! Interval between the warnings (specified in milliseconds or 0 to disable) */
 	unsigned int frequency;
-	/*! Sound file to play when the maximum duration is reached (if empty, then nothing will be played) */
-	char duration_sound[256];
-	/*! Sound file to play when the warning time is reached (if empty, then the remaining time will be played) */
-	char warning_sound[256];
+
+	AST_DECLARE_STRING_FIELDS(
+		/*! Sound file to play when the maximum duration is reached (if empty, then nothing will be played) */
+		AST_STRING_FIELD(duration_sound);
+		/*! Sound file to play when the warning time is reached (if empty, then the remaining time will be played) */
+		AST_STRING_FIELD(warning_sound);
+		/*! Sound file to play when the call is first entered (if empty, then the remaining time will be played) */
+		AST_STRING_FIELD(connect_sound);
+	);
+	/*! Time when the bridge will be terminated by the limits feature */
+	struct timeval quitting_time;
 };
 
 /*!
@@ -256,6 +275,44 @@
  * This unregisters the function that is handling the built in attended transfer feature.
  */
 int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature);
+
+/*!
+ * \brief Register a handler for a built in interval feature
+ *
+ * \param interval The interval feature that the handler will be responsible for
+ * \param callback the Callback function that will handle it
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_bridge_interval_register(AST_BRIDGE_BUILTIN_INTERVAL_LIMITS, bridge_builtin_set_limits);
+ * \endcode
+ *
+ * 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);
+
+/*!
+ * \brief Unregisters a handler for a built in interval feature
+ *
+ * \param interval the interval feature to unregister
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_bridge_interval_unregister(AST_BRIDGE_BULTIN_INTERVAL_LIMITS)
+ * /endcode
+ *
+ * This unregisters the function that is handling the built in duration limit feature.
+ */
+int ast_bridge_interval_unregister(enum ast_bridge_builtin_interval interval);
 
 /*!
  * \brief Attach a custom hook to a bridge features structure
@@ -311,7 +368,6 @@
  */
 int ast_bridge_features_interval_hook(struct ast_bridge_features *features,
 	unsigned int interval,
-	unsigned int strict,
 	ast_bridge_features_hook_callback callback,
 	void *hook_pvt,
 	ast_bridge_features_hook_pvt_destructor destructor);
@@ -379,18 +435,43 @@
 int ast_bridge_features_enable(struct ast_bridge_features *features, enum ast_bridge_builtin_feature feature, const char *dtmf, void *config);
 
 /*!
+ * \brief Constructor function for ast_bridge_features_limits
+ *
+ * \param limits pointer to a ast_bridge_features_limits struct that has been allocted, but not initialized
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+int ast_bridge_features_limits_construct(struct ast_bridge_features_limits *limits);
+
+/*!
+ * \brief Destructor function for ast_bridge_features_limits
+ *
+ * \param limits pointer to an ast_bridge_features_limits struct that needs to be destroyed
+ *
+ * This function does not free memory allocated to the ast_bridge_features_limits struct, it only frees elements within the struct.
+ * You must still call ast_free on the the struct if you allocated it with malloc.
+ */
+void ast_bridge_features_limits_destroy(struct ast_bridge_features_limits *limits);
+
+/*!
  * \brief Limit the amount of time a channel may stay in the bridge and optionally play warning messages as time runs out
  *
  * \param features Bridge features structure
  * \param limits Configured limits applicable to the channel
  *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
  * Example usage:
  *
  * \code
  * struct ast_bridge_features features;
- * struct ast_bridge_features_limits limits = { .duration = 10000, };
+ * 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_limits_destroy(&limits);
  * \endcode
  *
  * This sets the maximum time the channel can be in the bridge to 10 seconds and does not play any warnings.
@@ -398,7 +479,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.
  */
-void 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);
 
 /*!
  * \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=381508&r1=381507&r2=381508
==============================================================================
--- team/group/bridge_construction/main/bridging.c (original)
+++ team/group/bridge_construction/main/bridging.c Thu Feb 14 15:39:09 2013
@@ -50,6 +50,7 @@
 #include "asterisk/heap.h"
 #include "asterisk/say.h"
 #include "asterisk/timing.h"
+#include "asterisk/stringfields.h"
 #include "asterisk/musiconhold.h"
 
 static AST_RWLIST_HEAD_STATIC(bridge_technologies, ast_bridge_technology);
@@ -67,6 +68,9 @@
 
 /*! Function handlers for the built in features */
 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];
 
 int __ast_bridge_technology_register(struct ast_bridge_technology *technology, struct ast_module *module)
 {
@@ -131,8 +135,7 @@
 	ao2_unlock(bridge_channel);
 }
 
-/*! \note This function assumes the bridge_channel is locked. */
-static void ast_bridge_change_state_nolock(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state)
+void ast_bridge_change_state_nolock(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state)
 {
 	ast_debug(1, "BUGBUG Setting bridge channel %p state from:%d to:%d\n",
 		bridge_channel, bridge_channel->state, new_state);
@@ -1086,9 +1089,7 @@
 
 		ast_debug(1, "Updating hook '%p' and adding it back to '%p'\n", hook, bridge_channel);
 
-		if (hook->interval_strict) {
-			execution_time = ast_tvdiff_ms(ast_tvnow(), start);
-		}
+		execution_time = ast_tvdiff_ms(ast_tvnow(), start);
 
 		/* resetting start */
 		start = ast_tvnow();
@@ -1096,6 +1097,8 @@
 		hook->interval_trip_time = ast_tvadd(start, ast_samp2tv(hook->interval - execution_time, 1000));
 
 		ast_debug(1, "Sticking hook '%p' in heap on '%p'\n", hook, bridge_channel->features);
+
+		hook->seqno = ast_atomic_fetchadd_int((int *)&bridge_channel->features->interval_sequence, +1);
 		ast_heap_push(bridge_channel->features->interval_hooks, hook);
 	}
 }
@@ -1899,6 +1902,31 @@
 	return 0;
 }
 
+int ast_bridge_interval_register(enum ast_bridge_builtin_interval interval, void *callback)
+{
+	if (ARRAY_LEN(builtin_interval_handlers) <= interval
+		|| builtin_interval_handlers[interval]) {
+		return -1;
+	}
+
+	builtin_interval_handlers[interval] = callback;
+
+	return 0;
+}
+
+int ast_bridge_interval_unregister(enum ast_bridge_builtin_interval interval)
+{
+	if (ARRAY_LEN(builtin_interval_handlers) <= interval
+		|| !builtin_interval_handlers[interval]) {
+		return -1;
+	}
+
+	builtin_interval_handlers[interval] = NULL;
+
+	return 0;
+
+}
+
 int ast_bridge_features_hook(struct ast_bridge_features *features,
 	const char *dtmf,
 	ast_bridge_features_hook_callback callback,
@@ -1937,7 +1965,6 @@
 
 int ast_bridge_features_interval_hook(struct ast_bridge_features *features,
 	unsigned int interval,
-	unsigned int strict,
 	ast_bridge_features_hook_callback callback,
 	void *hook_pvt,
 	ast_bridge_features_hook_pvt_destructor destructor)
@@ -1962,11 +1989,11 @@
 	hook->callback = callback;
 	hook->destructor = destructor;
 	hook->hook_pvt = hook_pvt;
-	hook->interval_strict = strict ? 1 : 0;
 
 	ast_debug(1, "Putting interval hook '%p' in the interval hooks heap on features '%p'\n",
 		hook, features);
 	hook->interval_trip_time = ast_tvadd(ast_tvnow(), ast_samp2tv(hook->interval, 1000));
+	hook->seqno = ast_atomic_fetchadd_int((int *)&features->interval_sequence, +1);
 	ast_heap_push(features->interval_hooks, hook);
 	features->usable = 1;
 
@@ -2013,125 +2040,33 @@
 	return ast_bridge_features_hook(features, dtmf, builtin_features_handlers[feature], config, NULL);
 }
 
-static int bridge_features_duration_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct ast_bridge_features_limits *limits = hook_pvt;
-
-	if (!ast_strlen_zero(limits->duration_sound)) {
-		ast_stream_and_wait(bridge_channel->chan, limits->duration_sound, AST_DIGIT_NONE);
-	}
-
-	ao2_lock(bridge_channel);
-	switch (bridge_channel->state) {
-	case AST_BRIDGE_CHANNEL_STATE_WAIT:
-		ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
-		break;
-	default:
-		break;
-	}
-	ao2_unlock(bridge_channel);
-
+int ast_bridge_features_limits_construct(struct ast_bridge_features_limits *limits)
+{
+	memset(limits, 0, sizeof(*limits));
+
+	if (ast_string_field_init(limits, 256)) {
+		ast_free(limits);
+		return -1;
+	}
+
+	return 0;
+}
+
+void ast_bridge_features_limits_destroy(struct ast_bridge_features_limits *limits)
+{
+	ast_string_field_free_memory(limits);
+}
+
+int ast_bridge_features_set_limits(struct ast_bridge_features *features, struct ast_bridge_features_limits *limits)
+{
+	if (builtin_interval_handlers[AST_BRIDGE_BUILTIN_INTERVAL_LIMITS]) {
+		int (*bridge_features_set_limits_callback)(struct ast_bridge_features *features, struct ast_bridge_features_limits *limits);
+		bridge_features_set_limits_callback = builtin_interval_handlers[AST_BRIDGE_BUILTIN_INTERVAL_LIMITS];
+		return bridge_features_set_limits_callback(features, limits);
+	}
+
+	ast_log(LOG_ERROR, "Attempted to set limits without an AST_BRIDGE_BUILTIN_INTERVAL_LIMITS callback registered.\n");
 	return -1;
-}
-
-static int bridge_features_warning_sound_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct ast_bridge_features_limits *limits = hook_pvt;
-
-	if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
-		ast_debug(1, "Skipping warning, the channel state is already set to leave bridge.\n");
-		return -1;
-	}
-
-	ast_stream_and_wait(bridge_channel->chan, limits->warning_sound, AST_DIGIT_NONE);
-
-	/* It may be necessary to resume music on hold after we play the sound file. */
-	if (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_MOH)) {
-		ast_moh_start(bridge_channel->chan, NULL, NULL);
-	}
-
-	if (limits->frequency) {
-		ast_bridge_features_interval_update(bridge_channel, limits->frequency);
-	}
-
-	return !limits->frequency ? -1 : 0;
-}
-
-static int bridge_features_warning_time_left_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	struct ast_bridge_features_limits *limits = hook_pvt;
-	struct ast_bridge_features_hook *interval_hook;
-	unsigned int remaining = 0;
-	int heap_traversal_index;
-	int heap_size;
-
-	if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
-		ast_debug(1, "Skipping warning, the channel state is already set to leave bridge.\n");
-		return -1;
-	}
-
-	heap_size = ast_heap_size(bridge_channel->features->interval_hooks);
-	for (heap_traversal_index = 0; heap_traversal_index < heap_size; heap_traversal_index++) {
-		interval_hook = ast_heap_peek(bridge_channel->features->interval_hooks, heap_traversal_index + 1);
-		if (interval_hook->callback == bridge_features_duration_callback) {
-			remaining = ast_tvdiff_ms(interval_hook->interval_trip_time, ast_tvnow()) / 1000;
-			break;
-		}
-	}
-
-	if (remaining > 0) {
-		unsigned int min;
-		unsigned int sec;
-
-		if ((remaining / 60) > 1) {
-			min = remaining / 60;
-			sec = remaining % 60;
-		} else {
-			min = 0;
-			sec = remaining;
-		}
-
-		ast_stream_and_wait(bridge_channel->chan, "vm-youhave", AST_DIGIT_NONE);
-		if (min) {
-			ast_say_number(bridge_channel->chan, min, AST_DIGIT_NONE,
-				ast_channel_language(bridge_channel->chan), NULL);
-			ast_stream_and_wait(bridge_channel->chan, "queue-minutes", AST_DIGIT_NONE);
-		}
-		if (sec) {
-			ast_say_number(bridge_channel->chan, sec, AST_DIGIT_NONE,
-				ast_channel_language(bridge_channel->chan), NULL);
-			ast_stream_and_wait(bridge_channel->chan, "queue-seconds", AST_DIGIT_NONE);
-		}
-
-		/* It may be necessary to resume music on hold after we finish playing the announcment. */
-		if (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_MOH)) {
-			ast_moh_start(bridge_channel->chan, NULL, NULL);
-		}
-	}
-
-	if (limits->frequency) {
-		ast_bridge_features_interval_update(bridge_channel, limits->frequency);
-	}
-
-	return !limits->frequency ? -1 : 0;
-}
-
-void ast_bridge_features_set_limits(struct ast_bridge_features *features, struct ast_bridge_features_limits *limits)
-{
-	if (!limits->duration) {
-		return;
-	}
-
-	ast_bridge_features_interval_hook(features, limits->duration, 0,
-		bridge_features_duration_callback, limits, NULL);
-
-	if (limits->warning && limits->warning < limits->duration) {
-		ast_bridge_features_interval_hook(features, limits->warning, 1,
-			!ast_strlen_zero(limits->warning_sound)
-				? bridge_features_warning_sound_callback
-				: bridge_features_warning_time_left_callback,
-			limits, NULL);
-	}
 }
 
 void ast_bridge_features_set_flag(struct ast_bridge_features *features, enum ast_bridge_feature_flags flag)
@@ -2144,8 +2079,14 @@
 {
 	struct ast_bridge_features_hook *hook_a = a;
 	struct ast_bridge_features_hook *hook_b = b;
-
-	return ast_tvcmp(hook_b->interval_trip_time, hook_a->interval_trip_time);
+	int cmp = ast_tvcmp(hook_b->interval_trip_time, hook_a->interval_trip_time);
+
+	if (cmp) {
+		return cmp;
+	}
+
+	cmp = hook_b->seqno - hook_a->seqno;
+	return cmp;
 }
 
 int ast_bridge_features_init(struct ast_bridge_features *features)
@@ -2181,6 +2122,13 @@
 	if (features->interval_timer) {
 		ast_timer_close(features->interval_timer);
 		features->interval_timer = NULL;
+	}
+
+	/* If the features contains a limits pvt, destroy that as well. */
+	if (features->limits) {
+		ast_bridge_features_limits_destroy(features->limits);
+		ast_free(features->limits);
+		features->limits = NULL;
 	}
 
 	/* Destroy each DTMF feature hook. */

Modified: team/group/bridge_construction/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/main/features.c?view=diff&rev=381508&r1=381507&r2=381508
==============================================================================
--- team/group/bridge_construction/main/features.c (original)
+++ team/group/bridge_construction/main/features.c Thu Feb 14 15:39:09 2013
@@ -4370,11 +4370,16 @@
 
 static void bridge_config_set_limits_warning_values(struct ast_bridge_config *config, struct ast_bridge_features_limits *limits)
 {
-	ast_copy_string(limits->duration_sound, config->end_sound, sizeof(limits->duration_sound));
-
-/* BUGBUG 'timeleft' is a hard-coded value that is set when the argument isn't provided. This should probably be changed. */
-	if (strcmp("timeleft", config->warning_sound)) {
-		ast_copy_string(limits->warning_sound, config->warning_sound, sizeof(limits->warning_sound));
+	if (config->end_sound) {
+		ast_string_field_set(limits, duration_sound, config->end_sound);
+	}
+
+	if (config->warning_sound) {
+		ast_string_field_set(limits, warning_sound, config->warning_sound);
+	}
+
+	if (config->start_sound) {
+		ast_string_field_set(limits, connect_sound, config->start_sound);
 	}
 
 	limits->frequency = config->warning_freq;
@@ -4479,10 +4484,6 @@
 	struct ast_bridge *bridge;
 	struct ast_bridge_features chan_features;
 	struct ast_bridge_features *peer_features;
-
-	/* These are used for the 'L' option of Dial/Bridge */
-	struct ast_bridge_features_limits call_duration_limits_chan = {0};
-	struct ast_bridge_features_limits call_duration_limits_peer = {0};
 
 	pbx_builtin_setvar_helper(chan, "BRIDGEPEER", ast_channel_name(peer));
 	pbx_builtin_setvar_helper(peer, "BRIDGEPEER", ast_channel_name(chan));
@@ -4646,9 +4647,55 @@
 	}
 
 	if (config->timelimit) {
+		struct ast_bridge_features_limits call_duration_limits_chan;
+		struct ast_bridge_features_limits call_duration_limits_peer;
+		int abandon_call = 0; /* Flag raised if set limits fails so we can abandon the call. */
+
+		if (ast_bridge_features_limits_construct(&call_duration_limits_chan)) {
+			ast_log(LOG_ERROR, "Could not construct caller duration limits. Bridge canceled.\n");
+
+			ast_bridge_features_destroy(peer_features);
+			ast_bridge_features_cleanup(&chan_features);
+			if (bridge_cdr) {
+				ast_cdr_discard(bridge_cdr);
+			}
+			return -1;
+		}
+
+		if (ast_bridge_features_limits_construct(&call_duration_limits_peer)) {
+			ast_log(LOG_ERROR, "Could not construct callee duration limits. Bridge canceled.\n");
+			ast_bridge_features_limits_destroy(&call_duration_limits_chan);
+
+			ast_bridge_features_destroy(peer_features);
+			ast_bridge_features_cleanup(&chan_features);
+			if (bridge_cdr) {
+				ast_cdr_discard(bridge_cdr);
+			}
+			return -1;
+		}
+
 		bridge_config_set_limits(config, &call_duration_limits_chan, &call_duration_limits_peer);
-		ast_bridge_features_set_limits(&chan_features, &call_duration_limits_chan);
-		ast_bridge_features_set_limits(peer_features, &call_duration_limits_peer);
+
+		if (ast_bridge_features_set_limits(&chan_features, &call_duration_limits_chan)) {
+			abandon_call = 1;
+		}
+		if (ast_bridge_features_set_limits(peer_features, &call_duration_limits_peer)) {
+			abandon_call = 1;
+		}
+
+		/* At this point we are done with the limits structs since they have been copied to the individual feature sets. */
+		ast_bridge_features_limits_destroy(&call_duration_limits_chan);
+		ast_bridge_features_limits_destroy(&call_duration_limits_peer);
+
+		if (abandon_call) {
+			ast_log(LOG_ERROR, "Could not set duration limits on one or more sides of the call. Bridge canceled.\n");
+			ast_bridge_features_destroy(peer_features);
+			ast_bridge_features_cleanup(&chan_features);
+			if (bridge_cdr) {
+				ast_cdr_discard(bridge_cdr);
+			}
+			return -1;
+		}
 	}
 
 	ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer);/* BUGBUG expected to go away. */




More information about the asterisk-commits mailing list