diff options
author | Richard Mudgett <rmudgett@digium.com> | 2013-07-24 21:13:00 +0000 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2013-07-24 21:13:00 +0000 |
commit | 07d2694f725557854142fb6ae8fafa0e708b389e (patch) | |
tree | d4acf240ded6041d72ea4aedf10a062901c51b3d /main | |
parent | 50d69a9d12c7001f37d011b2860734619b45b2a9 (diff) |
Refactor ast_bridge_features struct.
* Reduced the number of hook containers to just dtmf_hooks,
interval_hooks, and other_hooks. As a result, several functions dealing
with the different hook containers could be combined.
* Extended the generic hook struct for DTMF and interval hooks instead of
using a variant record.
* Merged the special talk detector hook into the other_hooks container.
* Replaced ast_bridge_features_set_talk_detector() with
ast_bridge_talk_detector_hook().
(issue ASTERISK-22107)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@395322 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main')
-rw-r--r-- | main/bridging.c | 193 | ||||
-rw-r--r-- | main/bridging_channel.c | 120 |
2 files changed, 135 insertions, 178 deletions
diff --git a/main/bridging.c b/main/bridging.c index 6be48c7ce..bc1d36d83 100644 --- a/main/bridging.c +++ b/main/bridging.c @@ -3509,16 +3509,17 @@ int ast_bridge_dtmf_hook(struct ast_bridge_features *features, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags) { - struct ast_bridge_hook *hook; + struct ast_bridge_hook_dtmf *hook; int res; /* Allocate new hook and setup it's various variables */ - hook = bridge_hook_generic(sizeof(*hook), callback, hook_pvt, destructor, - remove_flags); + hook = (struct ast_bridge_hook_dtmf *) bridge_hook_generic(sizeof(*hook), callback, + hook_pvt, destructor, remove_flags); if (!hook) { return -1; } - ast_copy_string(hook->parms.dtmf.code, dtmf, sizeof(hook->parms.dtmf.code)); + hook->generic.type = AST_BRIDGE_HOOK_TYPE_DTMF; + ast_copy_string(hook->dtmf.code, dtmf, sizeof(hook->dtmf.code)); /* Once done we put it in the container. */ res = ao2_link(features->dtmf_hooks, hook) ? 0 : -1; @@ -3529,18 +3530,33 @@ int ast_bridge_dtmf_hook(struct ast_bridge_features *features, * Remove the hook_pvt destructor call from the hook since we * are returning failure to install the hook. */ - hook->destructor = NULL; + hook->generic.destructor = NULL; } ao2_ref(hook, -1); return res; } -int ast_bridge_hangup_hook(struct ast_bridge_features *features, +/*! + * \internal + * \brief Attach an other hook to a bridge features structure + * + * \param features Bridge features structure + * \param callback Function to execute upon activation + * \param hook_pvt Unique data + * \param destructor Optional destructor callback for hook_pvt data + * \param remove_flags Dictates what situations the hook should be removed. + * \param type What type of hook is being attached. + * + * \retval 0 on success + * \retval -1 on failure (The caller must cleanup any hook_pvt resources.) + */ +static int bridge_other_hook(struct ast_bridge_features *features, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, - enum ast_bridge_hook_remove_flags remove_flags) + enum ast_bridge_hook_remove_flags remove_flags, + enum ast_bridge_hook_type type) { struct ast_bridge_hook *hook; int res; @@ -3551,9 +3567,10 @@ int ast_bridge_hangup_hook(struct ast_bridge_features *features, if (!hook) { return -1; } + hook->type = type; /* Once done we put it in the container. */ - res = ao2_link(features->hangup_hooks, hook) ? 0 : -1; + res = ao2_link(features->other_hooks, hook) ? 0 : -1; if (res) { /* * Could not link the hook into the container. @@ -3568,36 +3585,24 @@ int ast_bridge_hangup_hook(struct ast_bridge_features *features, return res; } -int ast_bridge_join_hook(struct ast_bridge_features *features, +int ast_bridge_hangup_hook(struct ast_bridge_features *features, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags) { - 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, - remove_flags); - if (!hook) { - return -1; - } - - /* Once done we put it in the container. */ - res = ao2_link(features->join_hooks, hook) ? 0 : -1; - if (res) { - /* - * Could not link the hook into the container. - * - * Remove the hook_pvt destructor call from the hook since we - * are returning failure to install the hook. - */ - hook->destructor = NULL; - } - ao2_ref(hook, -1); + return bridge_other_hook(features, callback, hook_pvt, destructor, remove_flags, + AST_BRIDGE_HOOK_TYPE_HANGUP); +} - return res; +int ast_bridge_join_hook(struct ast_bridge_features *features, + ast_bridge_hook_callback callback, + void *hook_pvt, + ast_bridge_hook_pvt_destructor destructor, + enum ast_bridge_hook_remove_flags remove_flags) +{ + return bridge_other_hook(features, callback, hook_pvt, destructor, remove_flags, + AST_BRIDGE_HOOK_TYPE_JOIN); } int ast_bridge_leave_hook(struct ast_bridge_features *features, @@ -3606,40 +3611,20 @@ int ast_bridge_leave_hook(struct ast_bridge_features *features, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags) { - 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, - remove_flags); - if (!hook) { - return -1; - } - - /* Once done we put it in the container. */ - res = ao2_link(features->leave_hooks, hook) ? 0 : -1; - if (res) { - /* - * Could not link the hook into the container. - * - * Remove the hook_pvt destructor call from the hook since we - * are returning failure to install the hook. - */ - hook->destructor = NULL; - } - ao2_ref(hook, -1); - - return res; + return bridge_other_hook(features, callback, hook_pvt, destructor, remove_flags, + AST_BRIDGE_HOOK_TYPE_LEAVE); } -void ast_bridge_features_set_talk_detector(struct ast_bridge_features *features, - ast_bridge_talking_indicate_callback talker_cb, - ast_bridge_talking_indicate_destructor talker_destructor, - void *pvt_data) +int ast_bridge_talk_detector_hook(struct ast_bridge_features *features, + ast_bridge_talking_indicate_callback callback, + void *hook_pvt, + ast_bridge_hook_pvt_destructor destructor, + enum ast_bridge_hook_remove_flags remove_flags) { - features->talker_cb = talker_cb; - features->talker_destructor_cb = talker_destructor; - features->talker_pvt_data = pvt_data; + ast_bridge_hook_callback hook_cb = (ast_bridge_hook_callback) callback; + + return bridge_other_hook(features, hook_cb, hook_pvt, destructor, remove_flags, + AST_BRIDGE_HOOK_TYPE_TALK); } int ast_bridge_interval_hook(struct ast_bridge_features *features, @@ -3649,7 +3634,7 @@ int ast_bridge_interval_hook(struct ast_bridge_features *features, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags) { - struct ast_bridge_hook *hook; + struct ast_bridge_hook_timer *hook; int res; if (!features ||!interval || !callback) { @@ -3665,17 +3650,18 @@ int ast_bridge_interval_hook(struct ast_bridge_features *features, } /* Allocate new hook and setup it's various variables */ - hook = bridge_hook_generic(sizeof(*hook), callback, hook_pvt, destructor, - remove_flags); + hook = (struct ast_bridge_hook_timer *) bridge_hook_generic(sizeof(*hook), callback, + hook_pvt, destructor, remove_flags); if (!hook) { return -1; } - hook->parms.timer.interval = interval; - hook->parms.timer.trip_time = ast_tvadd(ast_tvnow(), ast_samp2tv(hook->parms.timer.interval, 1000)); - hook->parms.timer.seqno = ast_atomic_fetchadd_int((int *) &features->interval_sequence, +1); + hook->generic.type = AST_BRIDGE_HOOK_TYPE_TIMER; + hook->timer.interval = interval; + hook->timer.trip_time = ast_tvadd(ast_tvnow(), ast_samp2tv(hook->timer.interval, 1000)); + hook->timer.seqno = ast_atomic_fetchadd_int((int *) &features->interval_sequence, +1); ast_debug(1, "Putting interval hook %p with interval %u in the heap on features %p\n", - hook, hook->parms.timer.interval, features); + hook, hook->timer.interval, features); ast_heap_wrlock(features->interval_hooks); res = ast_heap_push(features->interval_hooks, hook); ast_heap_unlock(features->interval_hooks); @@ -3686,7 +3672,7 @@ int ast_bridge_interval_hook(struct ast_bridge_features *features, * Remove the hook_pvt destructor call from the hook since we * are returning failure to install the hook. */ - hook->destructor = NULL; + hook->generic.destructor = NULL; ao2_ref(hook, -1); } @@ -3836,24 +3822,22 @@ static void hooks_remove_heap(struct ast_heap *hooks, enum ast_bridge_hook_remov void ast_bridge_features_remove(struct ast_bridge_features *features, enum ast_bridge_hook_remove_flags remove_flags) { hooks_remove_container(features->dtmf_hooks, remove_flags); - hooks_remove_container(features->hangup_hooks, remove_flags); - hooks_remove_container(features->join_hooks, remove_flags); - hooks_remove_container(features->leave_hooks, remove_flags); + hooks_remove_container(features->other_hooks, remove_flags); hooks_remove_heap(features->interval_hooks, remove_flags); } static int interval_hook_time_cmp(void *a, void *b) { - struct ast_bridge_hook *hook_a = a; - struct ast_bridge_hook *hook_b = b; + struct ast_bridge_hook_timer *hook_a = a; + struct ast_bridge_hook_timer *hook_b = b; int cmp; - cmp = ast_tvcmp(hook_b->parms.timer.trip_time, hook_a->parms.timer.trip_time); + cmp = ast_tvcmp(hook_b->timer.trip_time, hook_a->timer.trip_time); if (cmp) { return cmp; } - cmp = hook_b->parms.timer.seqno - hook_a->parms.timer.seqno; + cmp = hook_b->timer.seqno - hook_a->timer.seqno; return cmp; } @@ -3875,21 +3859,21 @@ static int interval_hook_time_cmp(void *a, void *b) */ 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 struct ast_bridge_hook_dtmf *hook_left = obj_left; + const struct ast_bridge_hook_dtmf *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; + right_key = hook_right->dtmf.code; /* Fall through */ case OBJ_KEY: - cmp = strcasecmp(hook_left->parms.dtmf.code, right_key); + cmp = strcasecmp(hook_left->dtmf.code, right_key); break; case OBJ_PARTIAL_KEY: - cmp = strncasecmp(hook_left->parms.dtmf.code, right_key, strlen(right_key)); + cmp = strncasecmp(hook_left->dtmf.code, right_key, strlen(right_key)); break; } return cmp; @@ -3908,30 +3892,16 @@ int ast_bridge_features_init(struct ast_bridge_features *features) 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 join hooks container */ - features->join_hooks = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, - NULL); - if (!features->join_hooks) { - return -1; - } - - /* Initialize the leave hooks container */ - features->leave_hooks = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, + /* Initialize the miscellaneous other hooks container */ + features->other_hooks = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL); - if (!features->leave_hooks) { + if (!features->other_hooks) { return -1; } /* 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)); + offsetof(struct ast_bridge_hook_timer, timer.heap_index)); if (!features->interval_hooks) { return -1; } @@ -3942,7 +3912,7 @@ int ast_bridge_features_init(struct ast_bridge_features *features) /* BUGBUG make ast_bridge_features_cleanup() static when make ast_bridge_join() requires features to be allocated. */ void ast_bridge_features_cleanup(struct ast_bridge_features *features) { - struct ast_bridge_hook *hook; + struct ast_bridge_hook_timer *hook; /* Destroy the interval hooks heap. */ if (features->interval_hooks) { @@ -3964,22 +3934,9 @@ void ast_bridge_features_cleanup(struct ast_bridge_features *features) features->limits = NULL; } - if (features->talker_destructor_cb && features->talker_pvt_data) { - features->talker_destructor_cb(features->talker_pvt_data); - features->talker_pvt_data = NULL; - } - - /* Destroy the leave hooks container. */ - ao2_cleanup(features->leave_hooks); - features->leave_hooks = NULL; - - /* Destroy the join hooks container. */ - ao2_cleanup(features->join_hooks); - features->join_hooks = NULL; - - /* Destroy the hangup hooks container. */ - ao2_cleanup(features->hangup_hooks); - features->hangup_hooks = NULL; + /* Destroy the miscellaneous other hooks container. */ + ao2_cleanup(features->other_hooks); + features->other_hooks = NULL; /* Destroy the DTMF hooks container. */ ao2_cleanup(features->dtmf_hooks); diff --git a/main/bridging_channel.c b/main/bridging_channel.c index 674f14add..e7e7c2579 100644 --- a/main/bridging_channel.c +++ b/main/bridging_channel.c @@ -410,15 +410,18 @@ static void bridge_channel_handle_hangup(struct ast_bridge_channel *bridge_chann struct ao2_iterator iter; /* Run any hangup hooks. */ - iter = ao2_iterator_init(features->hangup_hooks, 0); + iter = ao2_iterator_init(features->other_hooks, 0); for (; (hook = ao2_iterator_next(&iter)); ao2_ref(hook, -1)) { int remove_me; + if (hook->type != AST_BRIDGE_HOOK_TYPE_HANGUP) { + continue; + } remove_me = hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt); if (remove_me) { ast_debug(1, "Hangup hook %p is being removed from %p(%s)\n", hook, bridge_channel, ast_channel_name(bridge_channel->chan)); - ao2_unlink(features->hangup_hooks, hook); + ao2_unlink(features->other_hooks, hook); } } ao2_iterator_destroy(&iter); @@ -698,12 +701,12 @@ int ast_bridge_channel_write_park(struct ast_bridge_channel *bridge_channel, con static int bridge_channel_interval_ready(struct ast_bridge_channel *bridge_channel) { struct ast_bridge_features *features = bridge_channel->features; - struct ast_bridge_hook *hook; + struct ast_bridge_hook_timer *hook; int ready; ast_heap_wrlock(features->interval_hooks); hook = ast_heap_peek(features->interval_hooks, 1); - ready = hook && ast_tvdiff_ms(hook->parms.timer.trip_time, ast_tvnow()) <= 0; + ready = hook && ast_tvdiff_ms(hook->timer.trip_time, ast_tvnow()) <= 0; ast_heap_unlock(features->interval_hooks); return ready; @@ -833,7 +836,7 @@ static void bridge_channel_unsuspend(struct ast_bridge_channel *bridge_channel) /*! \brief Internal function that activates interval hooks on a bridge channel */ static void bridge_channel_interval(struct ast_bridge_channel *bridge_channel) { - struct ast_bridge_hook *hook; + struct ast_bridge_hook_timer *hook; struct timeval start; ast_heap_wrlock(bridge_channel->features->interval_hooks); @@ -842,7 +845,7 @@ static void bridge_channel_interval(struct ast_bridge_channel *bridge_channel) int interval; unsigned int execution_time; - if (ast_tvdiff_ms(hook->parms.timer.trip_time, start) > 0) { + if (ast_tvdiff_ms(hook->timer.trip_time, start) > 0) { ast_debug(1, "Hook %p on %p(%s) wants to happen in the future, stopping our traversal\n", hook, bridge_channel, ast_channel_name(bridge_channel->chan)); break; @@ -852,11 +855,12 @@ static void bridge_channel_interval(struct ast_bridge_channel *bridge_channel) ast_debug(1, "Executing hook %p on %p(%s)\n", hook, bridge_channel, ast_channel_name(bridge_channel->chan)); - interval = hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt); + interval = hook->generic.callback(bridge_channel->bridge, bridge_channel, + hook->generic.hook_pvt); ast_heap_wrlock(bridge_channel->features->interval_hooks); if (ast_heap_peek(bridge_channel->features->interval_hooks, - hook->parms.timer.heap_index) != hook + hook->timer.heap_index) != hook || !ast_heap_remove(bridge_channel->features->interval_hooks, hook)) { /* Interval hook is already removed from the bridge_channel. */ ao2_ref(hook, -1); @@ -872,11 +876,11 @@ static void bridge_channel_interval(struct ast_bridge_channel *bridge_channel) } if (interval) { /* Set new interval for the hook. */ - hook->parms.timer.interval = interval; + hook->timer.interval = interval; } ast_debug(1, "Updating interval hook %p with interval %u on %p(%s)\n", - hook, hook->parms.timer.interval, bridge_channel, + hook, hook->timer.interval, bridge_channel, ast_channel_name(bridge_channel->chan)); /* resetting start */ @@ -887,12 +891,12 @@ static void bridge_channel_interval(struct ast_bridge_channel *bridge_channel) * to skip over any missed intervals because the hook was * delayed or took too long. */ - execution_time = ast_tvdiff_ms(start, hook->parms.timer.trip_time); - while (hook->parms.timer.interval < execution_time) { - execution_time -= hook->parms.timer.interval; + execution_time = ast_tvdiff_ms(start, hook->timer.trip_time); + while (hook->timer.interval < execution_time) { + execution_time -= hook->timer.interval; } - hook->parms.timer.trip_time = ast_tvadd(start, ast_samp2tv(hook->parms.timer.interval - execution_time, 1000)); - hook->parms.timer.seqno = ast_atomic_fetchadd_int((int *) &bridge_channel->features->interval_sequence, +1); + hook->timer.trip_time = ast_tvadd(start, ast_samp2tv(hook->timer.interval - execution_time, 1000)); + hook->timer.seqno = ast_atomic_fetchadd_int((int *) &bridge_channel->features->interval_sequence, +1); if (ast_heap_push(bridge_channel->features->interval_hooks, hook)) { /* Could not push the hook back onto the heap. */ @@ -916,7 +920,7 @@ static int bridge_channel_write_dtmf_stream(struct ast_bridge_channel *bridge_ch static void bridge_channel_feature(struct ast_bridge_channel *bridge_channel) { struct ast_bridge_features *features = bridge_channel->features; - struct ast_bridge_hook *hook = NULL; + struct ast_bridge_hook_dtmf *hook = NULL; char dtmf[MAXIMUM_DTMF_FEATURE_STRING] = ""; size_t dtmf_len = 0; unsigned int digit_timeout; @@ -965,7 +969,7 @@ static void bridge_channel_feature(struct ast_bridge_channel *bridge_channel) bridge_channel, ast_channel_name(bridge_channel->chan), dtmf); break; } - if (strlen(hook->parms.dtmf.code) == dtmf_len) { + if (strlen(hook->dtmf.code) == dtmf_len) { ast_debug(1, "DTMF feature hook %p matched DTMF string '%s' on %p(%s)\n", hook, dtmf, bridge_channel, ast_channel_name(bridge_channel->chan)); break; @@ -983,7 +987,8 @@ static void bridge_channel_feature(struct ast_bridge_channel *bridge_channel) if (hook) { int remove_me; - remove_me = hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt); + remove_me = hook->generic.callback(bridge_channel->bridge, bridge_channel, + hook->generic.hook_pvt); if (remove_me) { ast_debug(1, "DTMF hook %p is being removed from %p(%s)\n", hook, bridge_channel, ast_channel_name(bridge_channel->chan)); @@ -1008,10 +1013,27 @@ static void bridge_channel_feature(struct ast_bridge_channel *bridge_channel) static void bridge_channel_talking(struct ast_bridge_channel *bridge_channel, int talking) { struct ast_bridge_features *features = bridge_channel->features; + struct ast_bridge_hook *hook; + struct ao2_iterator iter; - if (features->talker_cb) { - features->talker_cb(bridge_channel, features->talker_pvt_data, talking); + /* Run any talk detection hooks. */ + iter = ao2_iterator_init(features->other_hooks, 0); + for (; (hook = ao2_iterator_next(&iter)); ao2_ref(hook, -1)) { + int remove_me; + ast_bridge_talking_indicate_callback talk_cb; + + if (hook->type != AST_BRIDGE_HOOK_TYPE_TALK) { + continue; + } + talk_cb = (ast_bridge_talking_indicate_callback) hook->callback; + remove_me = talk_cb(bridge_channel, hook->hook_pvt, talking); + if (remove_me) { + ast_debug(1, "Talk detection hook %p is being removed from %p(%s)\n", + hook, bridge_channel, ast_channel_name(bridge_channel->chan)); + ao2_unlink(features->other_hooks, hook); + } } + ao2_iterator_destroy(&iter); } /*! \brief Internal function that plays back DTMF on a bridge channel */ @@ -1533,7 +1555,7 @@ static void bridge_channel_handle_interval(struct ast_bridge_channel *bridge_cha static struct ast_frame *bridge_handle_dtmf(struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) { struct ast_bridge_features *features = bridge_channel->features; - struct ast_bridge_hook *hook; + struct ast_bridge_hook_dtmf *hook; char dtmf[2]; /* 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. */ @@ -1678,58 +1700,36 @@ static void bridge_channel_wait(struct ast_bridge_channel *bridge_channel) /*! * \internal - * \brief Handle bridge channel join event. + * \brief Handle bridge channel join/leave event. * \since 12.0.0 * - * \param bridge_channel Which channel is joining. + * \param bridge_channel Which channel is involved. + * \param type Specified join/leave event. * * \return Nothing */ -static void bridge_channel_handle_join(struct ast_bridge_channel *bridge_channel) +static void bridge_channel_event_join_leave(struct ast_bridge_channel *bridge_channel, enum ast_bridge_hook_type type) { struct ast_bridge_features *features = bridge_channel->features; struct ast_bridge_hook *hook; struct ao2_iterator iter; - /* Run any join hooks. */ - iter = ao2_iterator_init(features->join_hooks, AO2_ITERATOR_UNLINK); - hook = ao2_iterator_next(&iter); - if (hook) { - bridge_channel_suspend(bridge_channel); - ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); - do { - hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt); - ao2_ref(hook, -1); - } while ((hook = ao2_iterator_next(&iter))); - ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); - bridge_channel_unsuspend(bridge_channel); + /* Run the specified hooks. */ + iter = ao2_iterator_init(features->other_hooks, 0); + for (; (hook = ao2_iterator_next(&iter)); ao2_ref(hook, -1)) { + if (hook->type == type) { + break; + } } - ao2_iterator_destroy(&iter); -} - -/*! - * \internal - * \brief Handle bridge channel leave event. - * \since 12.0.0 - * - * \param bridge_channel Which channel is leaving. - * - * \return Nothing - */ -static void bridge_channel_handle_leave(struct ast_bridge_channel *bridge_channel) -{ - struct ast_bridge_features *features = bridge_channel->features; - struct ast_bridge_hook *hook; - struct ao2_iterator iter; - - /* Run any leave hooks. */ - iter = ao2_iterator_init(features->leave_hooks, AO2_ITERATOR_UNLINK); - hook = ao2_iterator_next(&iter); if (hook) { + /* Found the first specified hook to run. */ bridge_channel_suspend(bridge_channel); ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); do { - hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt); + if (hook->type == type) { + hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt); + ao2_unlink(features->other_hooks, hook); + } ao2_ref(hook, -1); } while ((hook = ao2_iterator_next(&iter))); ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); @@ -1786,12 +1786,12 @@ void bridge_channel_join(struct ast_bridge_channel *bridge_channel) } ast_bridge_unlock(bridge_channel->bridge); - bridge_channel_handle_join(bridge_channel); + bridge_channel_event_join_leave(bridge_channel, AST_BRIDGE_HOOK_TYPE_JOIN); while (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) { /* Wait for something to do. */ bridge_channel_wait(bridge_channel); } - bridge_channel_handle_leave(bridge_channel); + bridge_channel_event_join_leave(bridge_channel, AST_BRIDGE_HOOK_TYPE_LEAVE); ast_bridge_channel_lock_bridge(bridge_channel); } |