[asterisk-commits] rmudgett: branch rmudgett/bridge_tasks r383557 - in /team/rmudgett/bridge_tas...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Mar 21 17:19:06 CDT 2013
Author: rmudgett
Date: Thu Mar 21 17:19:02 2013
New Revision: 383557
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=383557
Log:
* Convert DTMF hooks list to an ao2 container for thread safety.
* Fix dtmf_passthrough issue for unmatched DTMF feature hook digits and
made the basic bridge always enable dtmf_passthrough.
Modified:
team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h
team/rmudgett/bridge_tasks/main/bridging.c
team/rmudgett/bridge_tasks/main/features.c
Modified: team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h?view=diff&rev=383557&r1=383556&r2=383557
==============================================================================
--- team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h (original)
+++ team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h Thu Mar 21 17:19:02 2013
@@ -191,9 +191,8 @@
* \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;
+ struct ao2_container *dtmf_hooks;
/*! Attached hangup interception hooks container */
struct ao2_container *hangup_hooks;
/*! Attached interval hooks */
Modified: team/rmudgett/bridge_tasks/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/main/bridging.c?view=diff&rev=383557&r1=383556&r2=383557
==============================================================================
--- team/rmudgett/bridge_tasks/main/bridging.c (original)
+++ team/rmudgett/bridge_tasks/main/bridging.c Thu Mar 21 17:19:02 2013
@@ -523,6 +523,7 @@
{
struct ast_bridge_features *features;
struct ast_bridge_hook *hook;
+ char dtmf[2];
features = bridge_channel->features;
if (!features) {
@@ -531,18 +532,19 @@
/* BUGBUG the feature hook matching needs to be done here. Any matching feature hook needs to be queued onto the bridge_channel. Also the feature hook digit timeout needs to be handled. */
/* See if this DTMF matches the beginnings of any feature hooks, if so we switch to the feature state to either execute the feature or collect more DTMF */
- AST_LIST_TRAVERSE(&features->dtmf_hooks, hook, entry) {
- if (hook->parms.dtmf.code[0] == frame->subclass.integer) {
- struct ast_frame action = {
- .frametype = AST_FRAME_BRIDGE_ACTION,
- .subclass.integer = AST_BRIDGE_ACTION_FEATURE,
- };
-
- ast_frfree(frame);
- frame = NULL;
- ast_bridge_channel_queue_frame(bridge_channel, &action);
- break;
- }
+ dtmf[0] = frame->subclass.integer;
+ dtmf[1] = '\0';
+ hook = ao2_find(features->dtmf_hooks, dtmf, OBJ_PARTIAL_KEY);
+ if (hook) {
+ struct ast_frame action = {
+ .frametype = AST_FRAME_BRIDGE_ACTION,
+ .subclass.integer = AST_BRIDGE_ACTION_FEATURE,
+ };
+
+ ast_frfree(frame);
+ frame = NULL;
+ ast_bridge_channel_queue_frame(bridge_channel, &action);
+ ao2_ref(hook, -1);
}
return frame;
@@ -1446,8 +1448,7 @@
struct ast_bridge_features *features = bridge_channel->features;
struct ast_bridge_hook *hook = NULL;
char dtmf[MAXIMUM_DTMF_FEATURE_STRING] = "";
- int look_for_dtmf = 1;
- int dtmf_len = 0;
+ size_t dtmf_len = 0;
if (!features) {
return;
@@ -1457,15 +1458,17 @@
ast_set_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_END_DTMF_ONLY);
/* Wait for DTMF on the channel and put it into a buffer. If the buffer matches any feature hook execute the hook. */
- while (look_for_dtmf) {
- int res = ast_waitfordigit(bridge_channel->chan, 3000);
+ do {
+ int res;
/* If the above timed out simply exit */
+ res = ast_waitfordigit(bridge_channel->chan, 3000);
if (!res) {
ast_debug(1, "DTMF feature string collection on bridge channel %p(%s) timed out\n",
bridge_channel, ast_channel_name(bridge_channel->chan));
break;
- } else if (res < 0) {
+ }
+ if (res < 0) {
ast_debug(1, "DTMF feature string collection failed on bridge channel %p(%s) for some reason\n",
bridge_channel, ast_channel_name(bridge_channel->chan));
break;
@@ -1474,38 +1477,26 @@
/* BUGBUG need to record the duration of DTMF digits so when the string is played back, they are reproduced. */
/* Add the above DTMF into the DTMF string so we can do our matching */
dtmf[dtmf_len++] = res;
-
ast_debug(1, "DTMF feature string on bridge channel %p(%s) is now '%s'\n",
bridge_channel, ast_channel_name(bridge_channel->chan), dtmf);
- /* Assume that we do not want to look for DTMF any longer */
- look_for_dtmf = 0;
-
/* See if a DTMF feature hook matches or can match */
- AST_LIST_TRAVERSE(&features->dtmf_hooks, hook, entry) {
- /* If this hook matches just break out now */
- if (!strcmp(hook->parms.dtmf.code, dtmf)) {
- ast_debug(1, "DTMF feature hook %p matched DTMF string '%s' on bridge channel %p(%s)\n",
- hook, dtmf, bridge_channel, ast_channel_name(bridge_channel->chan));
- look_for_dtmf = 0;
- break;
- } else if (!strncmp(hook->parms.dtmf.code, dtmf, dtmf_len)) {
- ast_debug(1, "DTMF feature hook %p can match DTMF string '%s', it wants '%s', on bridge channel %p(%s)\n",
- hook, dtmf, hook->parms.dtmf.code, bridge_channel,
- ast_channel_name(bridge_channel->chan));
- look_for_dtmf = 1;
- } else {
- ast_debug(1, "DTMF feature hook %p does not match DTMF string '%s', it wants '%s', on bridge channel %p(%s)\n",
- hook, dtmf, hook->parms.dtmf.code, bridge_channel,
- ast_channel_name(bridge_channel->chan));
- }
- }
-
- /* If we have reached the maximum length of a DTMF feature string bail out */
- if (dtmf_len == MAXIMUM_DTMF_FEATURE_STRING) {
+ hook = ao2_find(features->dtmf_hooks, dtmf, OBJ_PARTIAL_KEY);
+ if (!hook) {
+ ast_debug(1, "No DTMF feature hooks on bridge channel %p(%s) match '%s'\n",
+ bridge_channel, ast_channel_name(bridge_channel->chan), dtmf);
break;
}
- }
+ if (strlen(hook->parms.dtmf.code) == dtmf_len) {
+ ast_debug(1, "DTMF feature hook %p matched DTMF string '%s' on bridge channel %p(%s)\n",
+ hook, dtmf, bridge_channel, ast_channel_name(bridge_channel->chan));
+ break;
+ }
+ ao2_ref(hook, -1);
+ hook = NULL;
+
+ /* Stop if we have reached the maximum length of a DTMF feature string. */
+ } while (dtmf_len < ARRAY_LEN(dtmf) - 1);
/* Since we are done bringing DTMF in return to using both begin and end frames */
ast_clear_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_END_DTMF_ONLY);
@@ -1516,19 +1507,11 @@
failed = hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt);
if (failed) {
- struct ast_bridge_hook *cur;
-
- AST_LIST_TRAVERSE_SAFE_BEGIN(&features->dtmf_hooks, cur, entry) {
- if (cur == hook) {
- ast_debug(1, "DTMF hook %p is being removed from bridge channel %p(%s)\n",
- hook, bridge_channel, ast_channel_name(bridge_channel->chan));
- AST_LIST_REMOVE_CURRENT(entry);
- ao2_ref(hook, -1);
- break;
- }
- }
- AST_LIST_TRAVERSE_SAFE_END;
- }
+ ast_debug(1, "DTMF hook %p is being removed from bridge channel %p(%s)\n",
+ hook, bridge_channel, ast_channel_name(bridge_channel->chan));
+ ao2_unlink(features->dtmf_hooks, hook);
+ }
+ ao2_ref(hook, -1);
/*
* If we are handing the channel off to an external hook for
@@ -1539,8 +1522,7 @@
if (bridge_channel->chan && ast_check_hangup_locked(bridge_channel->chan)) {
bridge_handle_hangup(bridge_channel);
}
- } else {
-/* BUGBUG Check the features.dtmf_passthrough flag just like ast_bridge_handle_trip() before passing on the collected digits. */
+ } else if (features->dtmf_passthrough) {
ast_bridge_dtmf_stream(bridge_channel->bridge, dtmf, bridge_channel->chan);
}
}
@@ -2679,6 +2661,7 @@
ast_bridge_hook_pvt_destructor destructor)
{
struct ast_bridge_hook *hook;
+ int res;
/* Allocate new hook and setup it's various variables */
hook = bridge_hook_generic(sizeof(*hook), callback, hook_pvt, destructor);
@@ -2687,10 +2670,11 @@
}
ast_copy_string(hook->parms.dtmf.code, dtmf, sizeof(hook->parms.dtmf.code));
- /* Once done we add it onto the list. */
- AST_LIST_INSERT_TAIL(&features->dtmf_hooks, hook, entry);
-
- return 0;
+ /* Once done we put it in the container. */
+ res = ao2_link(features->dtmf_hooks, hook) ? 0 : -1;
+ ao2_ref(hook, -1);
+
+ return res;
}
int ast_bridge_hangup_hook(struct ast_bridge_features *features,
@@ -2843,23 +2827,65 @@
return cmp;
}
+/*!
+ * \internal
+ * \brief DTMF hook container sort comparison function.
+ * \since 12.0.0
+ *
+ * \param obj_left pointer to the (user-defined part) of an object.
+ * \param obj_right pointer to the (user-defined part) of an object.
+ * \param flags flags from ao2_callback()
+ * OBJ_POINTER - if set, 'obj_right', is an object.
+ * OBJ_KEY - if set, 'obj_right', is a search key item that is not an object.
+ * OBJ_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
+ *
+ * \retval <0 if obj_left < obj_right
+ * \retval =0 if obj_left == obj_right
+ * \retval >0 if obj_left > obj_right
+ */
+static int bridge_dtmf_hook_sort(const void *obj_left, const void *obj_right, int flags)
+{
+ const struct ast_bridge_hook *hook_left = obj_left;
+ const struct ast_bridge_hook *hook_right = obj_right;
+ const char *right_key = obj_right;
+ int cmp;
+
+ switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
+ default:
+ case OBJ_POINTER:
+ right_key = hook_right->parms.dtmf.code;
+ /* Fall through */
+ case OBJ_KEY:
+ cmp = strcasecmp(hook_left->parms.dtmf.code, right_key);
+ break;
+ case OBJ_PARTIAL_KEY:
+ cmp = strncasecmp(hook_left->parms.dtmf.code, right_key, strlen(right_key));
+ break;
+ }
+ return cmp;
+}
+
/* BUGBUG make ast_bridge_features_init() static when make ast_bridge_join() requires features to be allocated. */
int ast_bridge_features_init(struct ast_bridge_features *features)
{
/* Zero out the structure */
memset(features, 0, sizeof(*features));
- /* Initialize the DTMF hooks list, just in case */
- AST_LIST_HEAD_INIT_NOLOCK(&features->dtmf_hooks);
-
- /* Initialize the hangup hooks list, just in case */
- features->hangup_hooks =
- ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
+ /* Initialize the DTMF hooks container */
+ features->dtmf_hooks = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX,
+ AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, bridge_dtmf_hook_sort, NULL);
+ if (!features->dtmf_hooks) {
+ return -1;
+ }
+
+ /* Initialize the hangup hooks container */
+ features->hangup_hooks = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL,
+ NULL);
if (!features->hangup_hooks) {
return -1;
}
- /* Initialize the interval hook heap */
+ /* Initialize the interval hooks heap */
features->interval_hooks = ast_heap_create(8, interval_hook_time_cmp,
offsetof(struct ast_bridge_hook, parms.timer.heap_index));
if (!features->interval_hooks) {
@@ -2874,13 +2900,14 @@
{
struct ast_bridge_hook *hook;
- /* Destroy each interval hook. */
+ /* Destroy the interval hooks heap. */
if (features->interval_hooks) {
while ((hook = ast_heap_pop(features->interval_hooks))) {
ao2_ref(hook, -1);
}
features->interval_hooks = ast_heap_destroy(features->interval_hooks);
}
+
if (features->interval_timer) {
ast_timer_close(features->interval_timer);
features->interval_timer = NULL;
@@ -2898,14 +2925,13 @@
features->talker_pvt_data = NULL;
}
- /* Destroy the hangup hook container. */
+ /* Destroy the hangup hooks container. */
ao2_cleanup(features->hangup_hooks);
features->hangup_hooks = NULL;
- /* Destroy each DTMF feature hook. */
- while ((hook = AST_LIST_REMOVE_HEAD(&features->dtmf_hooks, entry))) {
- ao2_ref(hook, -1);
- }
+ /* Destroy the DTMF hooks container. */
+ ao2_cleanup(features->dtmf_hooks);
+ features->dtmf_hooks = NULL;
}
void ast_bridge_features_destroy(struct ast_bridge_features *features)
Modified: team/rmudgett/bridge_tasks/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/main/features.c?view=diff&rev=383557&r1=383556&r2=383557
==============================================================================
--- team/rmudgett/bridge_tasks/main/features.c (original)
+++ team/rmudgett/bridge_tasks/main/features.c Thu Mar 21 17:19:02 2013
@@ -4250,6 +4250,9 @@
struct ast_call_feature *dtmf;
int res = 0;
+ /* Always pass through any DTMF digits. */
+ features->dtmf_passthrough = 1;
+
if (ast_test_flag(flags, AST_FEATURE_REDIRECT)) {
/* Add atxfer and blind transfer. */
ast_rwlock_rdlock(&features_lock);
More information about the asterisk-commits
mailing list