diff options
author | Richard Mudgett <rmudgett@digium.com> | 2014-07-09 16:34:51 +0000 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2014-07-09 16:34:51 +0000 |
commit | f962448eee1a2dee763e90441edd79cd99842ef6 (patch) | |
tree | 3c8b026758db2317294d301a3eb58975a32d7fc6 | |
parent | 5a3023a114af06a41bcea9cf4cf883939270e997 (diff) |
ARI: Make mixing bridges propagate linkedids and accountcodes.
* Create a Stasis bridge sub-class to propagate linkedids and
accountcodes.
* Fixed the basic bridge sub-class to update peeraccount codes when the
number of channels in the bridge drops back down to two parties.
* Refactored ast_bridge_channel_update_accountcodes() to handle channels
joining/leaving the bridge.
* Fixed the basic bridge sub-class to not call the base bridge class pull
method twice.
AFS-105 #close
ASTERISK-23852 #close
Reported by: Richard Mudgett
Review: https://reviewboard.asterisk.org/r/3720/
........
Merged revisions 418225 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@418226 65c4cc65-6c06-0410-ace0-fbb531ad65f3
-rw-r--r-- | include/asterisk/bridge_channel.h | 21 | ||||
-rw-r--r-- | main/bridge_basic.c | 19 | ||||
-rw-r--r-- | main/bridge_channel.c | 235 | ||||
-rw-r--r-- | res/res_stasis.c | 14 | ||||
-rw-r--r-- | res/stasis/stasis_bridge.c | 108 | ||||
-rw-r--r-- | res/stasis/stasis_bridge.h | 74 |
6 files changed, 409 insertions, 62 deletions
diff --git a/include/asterisk/bridge_channel.h b/include/asterisk/bridge_channel.h index c8aaf8906..ae8369d15 100644 --- a/include/asterisk/bridge_channel.h +++ b/include/asterisk/bridge_channel.h @@ -326,14 +326,15 @@ struct ast_bridge *ast_bridge_channel_merge_inhibit(struct ast_bridge_channel *b * \param bridge_channel The channel joining the bridge * \param swap The channel being swapped out of the bridge. May be NULL. * - * \note The bridge must be locked prior to calling this function. This should be called - * during a \ref bridge_channel_internal_push operation, typically by a sub-class of a bridge + * \note The bridge must be locked prior to calling this function. + * \note This should be called during a \ref bridge_channel_internal_push + * operation, typically by a sub-class of a bridge. */ void ast_bridge_channel_update_linkedids(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap); /*! * \internal - * \brief Update the accountcodes for a channel entering a bridge + * \brief Update the accountcodes for channels joining/leaving a bridge * \since 12.0.0 * * This function updates the accountcode and peeraccount on channels in two-party @@ -341,13 +342,17 @@ void ast_bridge_channel_update_linkedids(struct ast_bridge_channel *bridge_chann * however accountcode propagation will still occur if the channel joining has an * accountcode. * - * \param bridge_channel The channel joining the bridge - * \param swap The channel being swapped out of the bridge. May be NULL. + * \param joining The channel joining the bridge. May be NULL. + * \param leaving The channel leaving or being swapped out of the bridge. May be NULL. + * + * \note The joining and leaving parameters cannot both be NULL. * - * \note The bridge must be locked prior to calling this function. This should be called - * during a \ref bridge_channel_internal_push operation, typically by a sub-class of a bridge + * \note The bridge must be locked prior to calling this function. + * \note This should be called during a \ref bridge_channel_internal_push + * or \ref bridge_channel_internal_pull operation, typically by a + * sub-class of a bridge. */ -void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap); +void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *joining, struct ast_bridge_channel *leaving); /*! * \brief Write a frame to the specified bridge_channel. diff --git a/main/bridge_basic.c b/main/bridge_basic.c index cee56b1b5..eb44867f1 100644 --- a/main/bridge_basic.c +++ b/main/bridge_basic.c @@ -665,8 +665,6 @@ static int bridge_personality_normal_push(struct ast_bridge *self, struct ast_br return -1; } - ast_bridge_channel_update_accountcodes(bridge_channel, swap); - ast_bridge_channel_update_linkedids(bridge_channel, swap); return 0; } @@ -676,10 +674,14 @@ static int bridge_basic_push(struct ast_bridge *self, struct ast_bridge_channel ast_assert(personality != NULL); - if (personality->details[personality->current].v_table->push(self, bridge_channel, swap)) { + if (personality->details[personality->current].v_table->push + && personality->details[personality->current].v_table->push(self, bridge_channel, swap)) { return -1; } + ast_bridge_channel_update_linkedids(bridge_channel, swap); + ast_bridge_channel_update_accountcodes(bridge_channel, swap); + return ast_bridge_base_v_table.push(self, bridge_channel, swap); } @@ -693,6 +695,8 @@ static void bridge_basic_pull(struct ast_bridge *self, struct ast_bridge_channel personality->details[personality->current].v_table->pull(self, bridge_channel); } + ast_bridge_channel_update_accountcodes(NULL, bridge_channel); + ast_bridge_base_v_table.pull(self, bridge_channel); } @@ -3315,11 +3319,16 @@ void ast_bridging_init_basic(void) ast_bridge_basic_v_table.pull = bridge_basic_pull; ast_bridge_basic_v_table.destroy = bridge_basic_destroy; - personality_normal_v_table = ast_bridge_base_v_table; + /* + * Personality vtables don't have the same rules as + * normal bridge vtables. These vtable functions are + * used as alterations to the ast_bridge_basic_v_table + * method functionality and are checked for NULL before + * calling. + */ personality_normal_v_table.name = "normal"; personality_normal_v_table.push = bridge_personality_normal_push; - personality_atxfer_v_table = ast_bridge_base_v_table; personality_atxfer_v_table.name = "attended transfer"; personality_atxfer_v_table.push = bridge_personality_atxfer_push; personality_atxfer_v_table.pull = bridge_personality_atxfer_pull; diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 7d1c65367..4e1377558 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -357,7 +357,7 @@ struct ast_bridge *ast_bridge_channel_merge_inhibit(struct ast_bridge_channel *b void ast_bridge_channel_update_linkedids(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap) { - struct ast_bridge_channel *other = NULL; + struct ast_bridge_channel *other; struct ast_bridge *bridge = bridge_channel->bridge; struct ast_channel *oldest_linkedid_chan = bridge_channel->chan; @@ -370,68 +370,215 @@ void ast_bridge_channel_update_linkedids(struct ast_bridge_channel *bridge_chann } ast_channel_lock(bridge_channel->chan); - ast_channel_internal_copy_linkedid(bridge_channel->chan, - oldest_linkedid_chan); + ast_channel_internal_copy_linkedid(bridge_channel->chan, oldest_linkedid_chan); ast_channel_unlock(bridge_channel->chan); AST_LIST_TRAVERSE(&bridge->channels, other, entry) { if (other == swap) { continue; } ast_channel_lock(other->chan); - ast_channel_internal_copy_linkedid(other->chan, - oldest_linkedid_chan); + ast_channel_internal_copy_linkedid(other->chan, oldest_linkedid_chan); ast_channel_unlock(other->chan); } } -void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap) +/*! + * \internal + * \brief Set dest's empty peeraccount with the src's non-empty accountcode. + * \since 12.5.0 + * + * \param dest Channel to update peeraccount. + * \param src Channel to get accountcode from. + * + * \note Both channels are already locked. + * + * \return Nothing + */ +static void channel_fill_empty_peeraccount(struct ast_channel *dest, struct ast_channel *src) { - struct ast_bridge *bridge = bridge_channel->bridge; - struct ast_bridge_channel *other = NULL; + if (ast_strlen_zero(ast_channel_peeraccount(dest)) + && !ast_strlen_zero(ast_channel_accountcode(src))) { + ast_debug(1, "Setting channel %s peeraccount with channel %s accountcode '%s'.\n", + ast_channel_name(dest), + ast_channel_name(src), ast_channel_accountcode(src)); + ast_channel_peeraccount_set(dest, ast_channel_accountcode(src)); + } +} + +/*! + * \internal + * \brief Set dest's empty accountcode with the src's non-empty peeraccount. + * \since 12.5.0 + * + * \param dest Channel to update accountcode. + * \param src Channel to get peeraccount from. + * + * \note Both channels are already locked. + * + * \return Nothing + */ +static void channel_fill_empty_accountcode(struct ast_channel *dest, struct ast_channel *src) +{ + if (ast_strlen_zero(ast_channel_accountcode(dest)) + && !ast_strlen_zero(ast_channel_peeraccount(src))) { + ast_debug(1, "Setting channel %s accountcode with channel %s peeraccount '%s'.\n", + ast_channel_name(dest), + ast_channel_name(src), ast_channel_peeraccount(src)); + ast_channel_accountcode_set(dest, ast_channel_peeraccount(src)); + } +} + +/*! + * \internal + * \brief Set empty peeraccount and accountcode in a channel from the other channel. + * \since 12.5.0 + * + * \param c0 First bridge channel to update. + * \param c1 Second bridge channel to update. + * + * \note Both channels are already locked. + * + * \return Nothing + */ +static void channel_set_empty_accountcodes(struct ast_channel *c0, struct ast_channel *c1) +{ + /* Set empty peeraccount from the other channel's accountcode. */ + channel_fill_empty_peeraccount(c0, c1); + channel_fill_empty_peeraccount(c1, c0); + + /* Set empty accountcode from the other channel's peeraccount. */ + channel_fill_empty_accountcode(c0, c1); + channel_fill_empty_accountcode(c1, c0); +} + +/*! + * \internal + * \brief Update dest's peeraccount with the src's different accountcode. + * \since 12.5.0 + * + * \param dest Channel to update peeraccount. + * \param src Channel to get accountcode from. + * + * \note Both channels are already locked. + * + * \return Nothing + */ +static void channel_update_peeraccount(struct ast_channel *dest, struct ast_channel *src) +{ + if (strcmp(ast_channel_accountcode(src), ast_channel_peeraccount(dest))) { + ast_debug(1, "Changing channel %s peeraccount '%s' to match channel %s accountcode '%s'.\n", + ast_channel_name(dest), ast_channel_peeraccount(dest), + ast_channel_name(src), ast_channel_accountcode(src)); + ast_channel_peeraccount_set(dest, ast_channel_accountcode(src)); + } +} + +/*! + * \internal + * \brief Update peeraccounts to match the other channel's accountcode. + * \since 12.5.0 + * + * \param c0 First channel to update. + * \param c1 Second channel to update. + * + * \note Both channels are already locked. + * + * \return Nothing + */ +static void channel_update_peeraccounts(struct ast_channel *c0, struct ast_channel *c1) +{ + channel_update_peeraccount(c0, c1); + channel_update_peeraccount(c1, c0); +} + +/*! + * \internal + * \brief Update channel accountcodes because a channel is joining a bridge. + * \since 12.5.0 + * + * \param joining Channel joining the bridge. + * \param swap Channel being replaced by the joining channel. May be NULL. + * + * \note The bridge must be locked prior to calling this function. + * + * \return Nothing + */ +static void bridge_channel_update_accountcodes_joining(struct ast_bridge_channel *joining, struct ast_bridge_channel *swap) +{ + struct ast_bridge *bridge = joining->bridge; + struct ast_bridge_channel *other; + unsigned int swap_in_bridge = 0; + unsigned int will_be_two_party; + + /* + * Only update the peeraccount to match if the joining channel + * will make it a two party bridge. + */ + if (bridge->num_channels <= 2 && swap) { + AST_LIST_TRAVERSE(&bridge->channels, other, entry) { + if (other == swap) { + swap_in_bridge = 1; + break; + } + } + } + will_be_two_party = (1 == bridge->num_channels - swap_in_bridge); AST_LIST_TRAVERSE(&bridge->channels, other, entry) { if (other == swap) { continue; } - ast_channel_lock_both(bridge_channel->chan, other->chan); - - if (!ast_strlen_zero(ast_channel_accountcode(bridge_channel->chan)) && ast_strlen_zero(ast_channel_peeraccount(other->chan))) { - ast_debug(1, "Setting peeraccount to %s for %s from data on channel %s\n", - ast_channel_accountcode(bridge_channel->chan), ast_channel_name(other->chan), ast_channel_name(bridge_channel->chan)); - ast_channel_peeraccount_set(other->chan, ast_channel_accountcode(bridge_channel->chan)); - } - if (!ast_strlen_zero(ast_channel_accountcode(other->chan)) && ast_strlen_zero(ast_channel_peeraccount(bridge_channel->chan))) { - ast_debug(1, "Setting peeraccount to %s for %s from data on channel %s\n", - ast_channel_accountcode(other->chan), ast_channel_name(bridge_channel->chan), ast_channel_name(other->chan)); - ast_channel_peeraccount_set(bridge_channel->chan, ast_channel_accountcode(other->chan)); - } - if (!ast_strlen_zero(ast_channel_peeraccount(bridge_channel->chan)) && ast_strlen_zero(ast_channel_accountcode(other->chan))) { - ast_debug(1, "Setting accountcode to %s for %s from data on channel %s\n", - ast_channel_peeraccount(bridge_channel->chan), ast_channel_name(other->chan), ast_channel_name(bridge_channel->chan)); - ast_channel_accountcode_set(other->chan, ast_channel_peeraccount(bridge_channel->chan)); + ast_assert(joining != other); + ast_channel_lock_both(joining->chan, other->chan); + channel_set_empty_accountcodes(joining->chan, other->chan); + if (will_be_two_party) { + channel_update_peeraccounts(joining->chan, other->chan); } - if (!ast_strlen_zero(ast_channel_peeraccount(other->chan)) && ast_strlen_zero(ast_channel_accountcode(bridge_channel->chan))) { - ast_debug(1, "Setting accountcode to %s for %s from data on channel %s\n", - ast_channel_peeraccount(other->chan), ast_channel_name(bridge_channel->chan), ast_channel_name(other->chan)); - ast_channel_accountcode_set(bridge_channel->chan, ast_channel_peeraccount(other->chan)); - } - if (bridge->num_channels == 2) { - if (strcmp(ast_channel_accountcode(bridge_channel->chan), ast_channel_peeraccount(other->chan))) { - ast_debug(1, "Changing peeraccount from %s to %s on %s to match channel %s\n", - ast_channel_peeraccount(other->chan), ast_channel_peeraccount(bridge_channel->chan), ast_channel_name(other->chan), ast_channel_name(bridge_channel->chan)); - ast_channel_peeraccount_set(other->chan, ast_channel_accountcode(bridge_channel->chan)); - } - if (strcmp(ast_channel_accountcode(other->chan), ast_channel_peeraccount(bridge_channel->chan))) { - ast_debug(1, "Changing peeraccount from %s to %s on %s to match channel %s\n", - ast_channel_peeraccount(bridge_channel->chan), ast_channel_peeraccount(other->chan), ast_channel_name(bridge_channel->chan), ast_channel_name(other->chan)); - ast_channel_peeraccount_set(bridge_channel->chan, ast_channel_accountcode(other->chan)); - } - } - ast_channel_unlock(bridge_channel->chan); + ast_channel_unlock(joining->chan); ast_channel_unlock(other->chan); } } +/*! + * \internal + * \brief Update channel peeraccount codes because a channel has left a bridge. + * \since 12.5.0 + * + * \param leaving Channel leaving the bridge. (Has already been removed actually) + * + * \note The bridge must be locked prior to calling this function. + * + * \return Nothing + */ +static void bridge_channel_update_accountcodes_leaving(struct ast_bridge_channel *leaving) +{ + struct ast_bridge *bridge = leaving->bridge; + struct ast_bridge_channel *first; + struct ast_bridge_channel *second; + + if (bridge->num_channels != 2 || bridge->dissolved) { + return; + } + + first = AST_LIST_FIRST(&bridge->channels); + second = AST_LIST_LAST(&bridge->channels); + ast_assert(first && first != second); + ast_channel_lock_both(first->chan, second->chan); + channel_set_empty_accountcodes(first->chan, second->chan); + channel_update_peeraccounts(first->chan, second->chan); + ast_channel_unlock(second->chan); + ast_channel_unlock(first->chan); +} + +void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *joining, struct ast_bridge_channel *leaving) +{ + if (joining) { + bridge_channel_update_accountcodes_joining(joining, leaving); + } else { + bridge_channel_update_accountcodes_leaving(leaving); + } +} + void ast_bridge_channel_kick(struct ast_bridge_channel *bridge_channel, int cause) { struct ast_bridge_features *features = bridge_channel->features; @@ -1747,6 +1894,8 @@ void bridge_channel_internal_pull(struct ast_bridge_channel *bridge_channel) } --bridge->num_channels; AST_LIST_REMOVE(&bridge->channels, bridge_channel, entry); + + bridge_channel_dissolve_check(bridge_channel); bridge->v_table->pull(bridge, bridge_channel); ast_bridge_channel_clear_roles(bridge_channel); @@ -1761,8 +1910,6 @@ void bridge_channel_internal_pull(struct ast_bridge_channel *bridge_channel) ast_clear_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_OUTGOING); } - bridge_channel_dissolve_check(bridge_channel); - bridge->reconfigured = 1; ast_bridge_publish_leave(bridge, bridge_channel->chan); } diff --git a/res/res_stasis.c b/res/res_stasis.c index ff7424503..d915914d5 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -66,6 +66,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/strings.h" #include "stasis/app.h" #include "stasis/control.h" +#include "stasis/stasis_bridge.h" #include "asterisk/core_unreal.h" #include "asterisk/musiconhold.h" #include "asterisk/causes.h" @@ -687,9 +688,7 @@ struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name, requested_type = ast_strip(requested_type); if (!strcmp(requested_type, "mixing")) { - capabilities |= AST_BRIDGE_CAPABILITY_1TO1MIX | - AST_BRIDGE_CAPABILITY_MULTIMIX | - AST_BRIDGE_CAPABILITY_NATIVE; + capabilities |= STASIS_BRIDGE_MIXING_CAPABILITIES; flags |= AST_BRIDGE_FLAG_SMART; } else if (!strcmp(requested_type, "holding")) { capabilities |= AST_BRIDGE_CAPABILITY_HOLDING; @@ -699,11 +698,14 @@ struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name, } } - if (!capabilities) { + if (!capabilities + /* Holding and mixing capabilities don't mix. */ + || ((capabilities & AST_BRIDGE_CAPABILITY_HOLDING) + && (capabilities & (STASIS_BRIDGE_MIXING_CAPABILITIES)))) { return NULL; } - bridge = ast_bridge_base_new(capabilities, flags, "Stasis", name, id); + bridge = bridge_stasis_new(capabilities, flags, name, id); if (bridge) { if (!ao2_link(app_bridges, bridge)) { ast_bridge_destroy(bridge, 0); @@ -1493,6 +1495,8 @@ static int load_module(void) return AST_MODULE_LOAD_FAILURE; } + bridge_stasis_init(); + stasis_app_register_event_sources(); return AST_MODULE_LOAD_SUCCESS; diff --git a/res/stasis/stasis_bridge.c b/res/stasis/stasis_bridge.c new file mode 100644 index 000000000..c3a266a11 --- /dev/null +++ b/res/stasis/stasis_bridge.c @@ -0,0 +1,108 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Richard Mudgett <rmudgett@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 Stasis bridge subclass. + * + * \author Richard Mudgett <rmudgett@digium.com> + * + * See Also: + * \arg \ref AstCREDITS + */ + + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/bridge.h" +#include "asterisk/bridge_internal.h" +#include "stasis_bridge.h" + +/* ------------------------------------------------------------------- */ + +/*! + * \internal + * \brief Push this channel into the Stasis bridge. + * \since 12.5.0 + * + * \param self Bridge to operate upon. + * \param bridge_channel Bridge channel to push. + * \param swap Bridge channel to swap places with if not NULL. + * + * \note On entry, self is already locked. + * + * \retval 0 on success. + * \retval -1 on failure. The channel did not get pushed. + */ +static int bridge_stasis_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap) +{ + if (self->allowed_capabilities & STASIS_BRIDGE_MIXING_CAPABILITIES) { + ast_bridge_channel_update_linkedids(bridge_channel, swap); + if (ast_test_flag(&self->feature_flags, AST_BRIDGE_FLAG_SMART)) { + ast_bridge_channel_update_accountcodes(bridge_channel, swap); + } + } + + return ast_bridge_base_v_table.push(self, bridge_channel, swap); +} + +/*! + * \internal + * \brief Pull this channel from the Stasis bridge. + * \since 12.5.0 + * + * \param self Bridge to operate upon. + * \param bridge_channel Bridge channel to pull. + * + * \note On entry, self is already locked. + * + * \return Nothing + */ +static void bridge_stasis_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel) +{ + if ((self->allowed_capabilities & STASIS_BRIDGE_MIXING_CAPABILITIES) + && ast_test_flag(&self->feature_flags, AST_BRIDGE_FLAG_SMART)) { + ast_bridge_channel_update_accountcodes(NULL, bridge_channel); + } + + ast_bridge_base_v_table.pull(self, bridge_channel); +} + +static struct ast_bridge_methods bridge_stasis_v_table; + +struct ast_bridge *bridge_stasis_new(uint32_t capabilities, unsigned int flags, const char *name, const char *id) +{ + void *bridge; + + bridge = bridge_alloc(sizeof(struct ast_bridge), &bridge_stasis_v_table); + bridge = bridge_base_init(bridge, capabilities, flags, "Stasis", name, id); + bridge = bridge_register(bridge); + + return bridge; +} + +void bridge_stasis_init(void) +{ + /* Setup the Stasis bridge subclass v_table. */ + bridge_stasis_v_table = ast_bridge_base_v_table; + bridge_stasis_v_table.name = "stasis"; + bridge_stasis_v_table.push = bridge_stasis_push; + bridge_stasis_v_table.pull = bridge_stasis_pull; +} diff --git a/res/stasis/stasis_bridge.h b/res/stasis/stasis_bridge.h new file mode 100644 index 000000000..2590fd799 --- /dev/null +++ b/res/stasis/stasis_bridge.h @@ -0,0 +1,74 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Richard Mudgett <rmudgett@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 Internal API for the Stasis bridge subclass. + * + * \author Richard Mudgett <rmudgett@digium.com> + * + * See Also: + * \arg \ref AstCREDITS + */ + +#ifndef _ASTERISK_STASIS_BRIDGE_H +#define _ASTERISK_STASIS_BRIDGE_H + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* ------------------------------------------------------------------- */ + +/*! Normal capabilities of mixing bridges */ +#define STASIS_BRIDGE_MIXING_CAPABILITIES \ + (AST_BRIDGE_CAPABILITY_NATIVE \ + | AST_BRIDGE_CAPABILITY_1TO1MIX \ + | AST_BRIDGE_CAPABILITY_MULTIMIX) + +/*! + * \internal + * \brief Create a new Stasis bridge. + * \since 12.5.0 + * + * \param capabilities The capabilities that we require to be used on the bridge + * \param flags Flags that will alter the behavior of the bridge + * \param name Name given to the bridge by Stasis (optional) + * \param id Unique ID given to the bridge by Stasis (optional) + * + * \retval a pointer to a new bridge on success + * \retval NULL on failure + */ +struct ast_bridge *bridge_stasis_new(uint32_t capabilities, unsigned int flags, const char *name, const char *id); + +/*! + * \internal + * \brief Initialize the Stasis bridge subclass. + * \since 12.5.0 + * + * \return Nothing + */ +void bridge_stasis_init(void); + +/* ------------------------------------------------------------------- */ + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* _ASTERISK_STASIS_BRIDGE_H */ |