diff options
author | Richard Mudgett <rmudgett@digium.com> | 2013-08-21 20:02:24 +0000 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2013-08-21 20:02:24 +0000 |
commit | b816fe45b6bf3d61f873013b833908f500054d76 (patch) | |
tree | 3e052c51c32e530e9c9d397fb5f1e9f05b6acb1c /main | |
parent | 0c6328af5b6f6a80b170ae8db5fbede2e74d98cb (diff) |
* Move ast_bridge_channel_setup_features() into bridge_basic.c.
* Made application map hooks be removed on a basic bridge personality
change.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397355 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main')
-rw-r--r-- | main/bridge_basic.c | 311 | ||||
-rw-r--r-- | main/features.c | 296 |
2 files changed, 310 insertions, 297 deletions
diff --git a/main/bridge_basic.c b/main/bridge_basic.c index 35782de28..70556d748 100644 --- a/main/bridge_basic.c +++ b/main/bridge_basic.c @@ -45,6 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/dial.h" #include "asterisk/stasis_bridges.h" +#include "asterisk/features.h" #define NORMAL_FLAGS (AST_BRIDGE_FLAG_DISSOLVE_HANGUP | AST_BRIDGE_FLAG_DISSOLVE_EMPTY \ | AST_BRIDGE_FLAG_SMART) @@ -329,11 +330,319 @@ struct bridge_basic_personality { struct personality_details details[BRIDGE_BASIC_PERSONALITY_END]; }; +/* + * \internal + * \brief Get the extension for a given builtin feature. + * + * \param chan Get the feature extension for this channel. + * \param feature_name features.conf name of feature. + * \param buf Where to put the extension. + * \param len Length of the given extension buffer. + * + * \retval 0 success + * \retval non-zero failiure + */ +static int builtin_feature_get_exten(struct ast_channel *chan, const char *feature_name, char *buf, size_t len) +{ + SCOPED_CHANNELLOCK(lock, chan); + + return ast_get_builtin_feature(chan, feature_name, buf, len); +} + +/*! + * \internal + * \brief Helper to add a builtin DTMF feature hook to the features struct. + * \since 12.0.0 + * + * \param features Bridge features to setup. + * \param chan Get features from this channel. + * \param flags Feature flags on the channel. + * \param feature_flag Feature flag to test. + * \param feature_name features.conf name of feature. + * \param feature_bridge Bridge feature enum to get hook callback. + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int builtin_features_helper(struct ast_bridge_features *features, struct ast_channel *chan, + struct ast_flags *flags, unsigned int feature_flag, const char *feature_name, enum ast_bridge_builtin_feature feature_bridge) +{ + char dtmf[AST_FEATURE_MAX_LEN]; + int res; + + res = 0; + if (ast_test_flag(flags, feature_flag) + && !builtin_feature_get_exten(chan, feature_name, dtmf, sizeof(dtmf)) + && !ast_strlen_zero(dtmf)) { + res = ast_bridge_features_enable(features, feature_bridge, dtmf, NULL, NULL, + AST_BRIDGE_HOOK_REMOVE_ON_PULL | AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE); + if (res) { + ast_log(LOG_ERROR, "Channel %s: Requested DTMF feature %s not available.\n", + ast_channel_name(chan), feature_name); + } + } + + return res; +} + +/*! + * \internal + * \brief Setup bridge builtin features. + * \since 12.0.0 + * + * \param features Bridge features to setup. + * \param chan Get features from this channel. + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int setup_bridge_features_builtin(struct ast_bridge_features *features, struct ast_channel *chan) +{ + struct ast_flags *flags; + int res; + + ast_channel_lock(chan); + flags = ast_bridge_features_ds_get(chan); + ast_channel_unlock(chan); + if (!flags) { + return 0; + } + + res = 0; + res |= builtin_features_helper(features, chan, flags, AST_FEATURE_REDIRECT, "blindxfer", AST_BRIDGE_BUILTIN_BLINDTRANSFER); + res |= builtin_features_helper(features, chan, flags, AST_FEATURE_REDIRECT, "atxfer", AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER); + res |= builtin_features_helper(features, chan, flags, AST_FEATURE_DISCONNECT, "disconnect", AST_BRIDGE_BUILTIN_HANGUP); + res |= builtin_features_helper(features, chan, flags, AST_FEATURE_PARKCALL, "parkcall", AST_BRIDGE_BUILTIN_PARKCALL); + res |= builtin_features_helper(features, chan, flags, AST_FEATURE_AUTOMON, "automon", AST_BRIDGE_BUILTIN_AUTOMON); + res |= builtin_features_helper(features, chan, flags, AST_FEATURE_AUTOMIXMON, "automixmon", AST_BRIDGE_BUILTIN_AUTOMIXMON); + + return res ? -1 : 0; +} + +struct dynamic_dtmf_hook_run { + /*! Offset into app_name[] where the channel name that activated the hook starts. */ + int activated_offset; + /*! Offset into app_name[] where the dynamic feature name starts. */ + int feature_offset; + /*! Offset into app_name[] where the MOH class name starts. (zero if no MOH) */ + int moh_offset; + /*! Offset into app_name[] where the application argument string starts. (zero if no arguments) */ + int app_args_offset; + /*! Application name to run. */ + char app_name[0]; +}; + +static void dynamic_dtmf_hook_callback(struct ast_bridge_channel *bridge_channel, + const void *payload, size_t payload_size) +{ + struct ast_channel *chan = bridge_channel->chan; + const struct dynamic_dtmf_hook_run *run_data = payload; + + pbx_builtin_setvar_helper(chan, "DYNAMIC_FEATURENAME", + &run_data->app_name[run_data->feature_offset]); + pbx_builtin_setvar_helper(chan, "DYNAMIC_WHO_ACTIVATED", + &run_data->app_name[run_data->activated_offset]); + + ast_bridge_channel_run_app(bridge_channel, run_data->app_name, + run_data->app_args_offset ? &run_data->app_name[run_data->app_args_offset] : NULL, + run_data->moh_offset ? &run_data->app_name[run_data->moh_offset] : NULL); +} + +struct dynamic_dtmf_hook_data { + /*! Which side of bridge to run app (AST_FEATURE_FLAG_ONSELF/AST_FEATURE_FLAG_ONPEER) */ + unsigned int flags; + /*! Offset into app_name[] where the dynamic feature name starts. */ + int feature_offset; + /*! Offset into app_name[] where the MOH class name starts. (zero if no MOH) */ + int moh_offset; + /*! Offset into app_name[] where the application argument string starts. (zero if no arguments) */ + int app_args_offset; + /*! Application name to run. */ + char app_name[0]; +}; + +/*! + * \internal + * \brief Activated dynamic DTMF feature hook. + * \since 12.0.0 + * + * \param bridge_channel Channel executing the feature + * \param hook_pvt Private data passed in when the hook was created + * + * \retval 0 Keep the callback hook. + * \retval -1 Remove the callback hook. + */ +static int dynamic_dtmf_hook_trip(struct ast_bridge_channel *bridge_channel, void *hook_pvt) +{ + struct dynamic_dtmf_hook_data *pvt = hook_pvt; + struct dynamic_dtmf_hook_run *run_data; + const char *activated_name; + size_t len_name; + size_t len_args; + size_t len_moh; + size_t len_feature; + size_t len_activated; + size_t len_data; + + /* Determine lengths of things. */ + len_name = strlen(pvt->app_name) + 1; + len_args = pvt->app_args_offset ? strlen(&pvt->app_name[pvt->app_args_offset]) + 1 : 0; + len_moh = pvt->moh_offset ? strlen(&pvt->app_name[pvt->moh_offset]) + 1 : 0; + len_feature = strlen(&pvt->app_name[pvt->feature_offset]) + 1; + ast_channel_lock(bridge_channel->chan); + activated_name = ast_strdupa(ast_channel_name(bridge_channel->chan)); + ast_channel_unlock(bridge_channel->chan); + len_activated = strlen(activated_name) + 1; + len_data = sizeof(*run_data) + len_name + len_args + len_moh + len_feature + len_activated; + + /* Fill in dynamic feature run hook data. */ + run_data = ast_alloca(len_data); + run_data->app_args_offset = len_args ? len_name : 0; + run_data->moh_offset = len_moh ? len_name + len_args : 0; + run_data->feature_offset = len_name + len_args + len_moh; + run_data->activated_offset = len_name + len_args + len_moh + len_feature; + strcpy(run_data->app_name, pvt->app_name);/* Safe */ + if (len_args) { + strcpy(&run_data->app_name[run_data->app_args_offset], + &pvt->app_name[pvt->app_args_offset]);/* Safe */ + } + if (len_moh) { + strcpy(&run_data->app_name[run_data->moh_offset], + &pvt->app_name[pvt->moh_offset]);/* Safe */ + } + strcpy(&run_data->app_name[run_data->feature_offset], + &pvt->app_name[pvt->feature_offset]);/* Safe */ + strcpy(&run_data->app_name[run_data->activated_offset], activated_name);/* Safe */ + + if (ast_test_flag(pvt, AST_FEATURE_FLAG_ONPEER)) { + ast_bridge_channel_write_callback(bridge_channel, + AST_BRIDGE_CHANNEL_CB_OPTION_MEDIA, + dynamic_dtmf_hook_callback, run_data, len_data); + } else { + dynamic_dtmf_hook_callback(bridge_channel, run_data, len_data); + } + return 0; +} + +/*! + * \internal + * \brief Add a dynamic DTMF feature hook to the bridge features. + * \since 12.0.0 + * + * \param features Bridge features to setup. + * \param flags Which side of bridge to run app (AST_FEATURE_FLAG_ONSELF/AST_FEATURE_FLAG_ONPEER). + * \param dtmf DTMF trigger sequence. + * \param feature_name Name of the dynamic feature. + * \param app_name Dialplan application name to run. + * \param app_args Dialplan application arguments. (Empty or NULL if no arguments) + * \param moh_class MOH class to play to peer. (Empty or NULL if no MOH played) + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int dynamic_dtmf_hook_add(struct ast_bridge_features *features, unsigned int flags, const char *dtmf, const char *feature_name, const char *app_name, const char *app_args, const char *moh_class) +{ + struct dynamic_dtmf_hook_data *hook_data; + size_t len_name = strlen(app_name) + 1; + size_t len_args = ast_strlen_zero(app_args) ? 0 : strlen(app_args) + 1; + size_t len_moh = ast_strlen_zero(moh_class) ? 0 : strlen(moh_class) + 1; + size_t len_feature = strlen(feature_name) + 1; + size_t len_data = sizeof(*hook_data) + len_name + len_args + len_moh + len_feature; + int res; + + /* Fill in application run hook data. */ + hook_data = ast_malloc(len_data); + if (!hook_data) { + return -1; + } + hook_data->flags = flags; + hook_data->app_args_offset = len_args ? len_name : 0; + hook_data->moh_offset = len_moh ? len_name + len_args : 0; + hook_data->feature_offset = len_name + len_args + len_moh; + strcpy(hook_data->app_name, app_name);/* Safe */ + if (len_args) { + strcpy(&hook_data->app_name[hook_data->app_args_offset], app_args);/* Safe */ + } + if (len_moh) { + strcpy(&hook_data->app_name[hook_data->moh_offset], moh_class);/* Safe */ + } + strcpy(&hook_data->app_name[hook_data->feature_offset], feature_name);/* Safe */ + + res = ast_bridge_dtmf_hook(features, dtmf, dynamic_dtmf_hook_trip, hook_data, + ast_free_ptr, + AST_BRIDGE_HOOK_REMOVE_ON_PULL | AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE); + if (res) { + ast_free(hook_data); + } + return res; +} + +static int setup_dynamic_feature(void *obj, void *arg, void *data, int flags) +{ + struct ast_applicationmap_item *item = obj; + struct ast_bridge_features *features = arg; + int *res = data; + + *res |= dynamic_dtmf_hook_add(features, + item->activate_on_self ? AST_FEATURE_FLAG_ONSELF : AST_FEATURE_FLAG_ONPEER, + item->dtmf, item->name, item->app, item->app_data, item->moh_class); + + return 0; +} + +/*! + * \internal + * \brief Setup bridge dynamic features. + * \since 12.0.0 + * + * \param features Bridge features to setup. + * \param chan Get features from this channel. + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int setup_bridge_features_dynamic(struct ast_bridge_features *features, struct ast_channel *chan) +{ + RAII_VAR(struct ao2_container *, applicationmap, NULL, ao2_cleanup); + int res = 0; + + ast_channel_lock(chan); + applicationmap = ast_get_chan_applicationmap(chan); + ast_channel_unlock(chan); + if (!applicationmap) { + return 0; + } + + ao2_callback_data(applicationmap, 0, setup_dynamic_feature, features, &res); + + return res; +} + +/*! + * \internal + * \brief Setup DTMF feature hooks using the channel features datastore property. + * \since 12.0.0 + * + * \param bridge_channel What to setup DTMF features on. + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int bridge_basic_setup_features(struct ast_bridge_channel *bridge_channel) +{ + int res = 0; + + res |= setup_bridge_features_builtin(bridge_channel->features, bridge_channel->chan); + res |= setup_bridge_features_dynamic(bridge_channel->features, bridge_channel->chan); + + return res; +} + static int add_normal_hooks(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) { return ast_bridge_hangup_hook(bridge_channel->features, basic_hangup_hook, NULL, NULL, AST_BRIDGE_HOOK_REMOVE_ON_PULL) - || ast_bridge_channel_setup_features(bridge_channel); + || bridge_basic_setup_features(bridge_channel); } /*! diff --git a/main/features.c b/main/features.c index 4d19fa6d7..2601a4106 100644 --- a/main/features.c +++ b/main/features.c @@ -323,23 +323,6 @@ static const struct ast_datastore_info channel_app_data_datastore = { .destroy = ast_free_ptr, }; -/* - * \internal - * \brief Get the extension for a given builtin feature - * - * \pre expects features_lock to be readlocked - * - * \retval 0 success - * \retval non-zero failiure - */ -static int builtin_feature_get_exten(struct ast_channel *chan, const char *feature_name, - char *buf, size_t len) -{ - SCOPED_CHANNELLOCK(lock, chan); - - return ast_get_builtin_feature(chan, feature_name, buf, len); -} - static void set_config_flags(struct ast_channel *chan, struct ast_bridge_config *config) { ast_clear_flag(config, AST_FLAGS_ALL); @@ -459,285 +442,6 @@ static void clear_dialed_interfaces(struct ast_channel *chan) ast_channel_unlock(chan); } -/*! - * \internal - * \brief Helper to add a builtin DTMF feature hook to the features struct. - * \since 12.0.0 - * - * \param features Bridge features to setup. - * \param chan Get features from this channel. - * \param flags Feature flags on the channel. - * \param feature_flag Feature flag to test. - * \param feature_name features.conf name of feature. - * \param feature_bridge Bridge feature enum to get hook callback. - * - * \retval 0 on success. - * \retval -1 on error. - */ -static int builtin_features_helper(struct ast_bridge_features *features, struct ast_channel *chan, - struct ast_flags *flags, unsigned int feature_flag, const char *feature_name, enum ast_bridge_builtin_feature feature_bridge) -{ - char dtmf[AST_FEATURE_MAX_LEN]; - int res; - - res = 0; - if (ast_test_flag(flags, feature_flag) - && !builtin_feature_get_exten(chan, feature_name, dtmf, sizeof(dtmf)) - && !ast_strlen_zero(dtmf)) { - res = ast_bridge_features_enable(features, feature_bridge, dtmf, NULL, NULL, - AST_BRIDGE_HOOK_REMOVE_ON_PULL | AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE); - if (res) { - ast_log(LOG_ERROR, "Channel %s: Requested DTMF feature %s not available.\n", - ast_channel_name(chan), feature_name); - } - } - - return res; -} - -/*! - * \internal - * \brief Setup bridge builtin features. - * \since 12.0.0 - * - * \param features Bridge features to setup. - * \param chan Get features from this channel. - * - * \retval 0 on success. - * \retval -1 on error. - */ -static int setup_bridge_features_builtin(struct ast_bridge_features *features, struct ast_channel *chan) -{ - struct ast_flags *flags; - int res; - - ast_channel_lock(chan); - flags = ast_bridge_features_ds_get(chan); - ast_channel_unlock(chan); - if (!flags) { - return 0; - } - - res = 0; - res |= builtin_features_helper(features, chan, flags, AST_FEATURE_REDIRECT, "blindxfer", AST_BRIDGE_BUILTIN_BLINDTRANSFER); - res |= builtin_features_helper(features, chan, flags, AST_FEATURE_REDIRECT, "atxfer", AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER); - res |= builtin_features_helper(features, chan, flags, AST_FEATURE_DISCONNECT, "disconnect", AST_BRIDGE_BUILTIN_HANGUP); - res |= builtin_features_helper(features, chan, flags, AST_FEATURE_PARKCALL, "parkcall", AST_BRIDGE_BUILTIN_PARKCALL); - res |= builtin_features_helper(features, chan, flags, AST_FEATURE_AUTOMON, "automon", AST_BRIDGE_BUILTIN_AUTOMON); - res |= builtin_features_helper(features, chan, flags, AST_FEATURE_AUTOMIXMON, "automixmon", AST_BRIDGE_BUILTIN_AUTOMIXMON); - - return res ? -1 : 0; -} - -struct dynamic_dtmf_hook_run { - /*! Offset into app_name[] where the channel name that activated the hook starts. */ - int activated_offset; - /*! Offset into app_name[] where the dynamic feature name starts. */ - int feature_offset; - /*! Offset into app_name[] where the MOH class name starts. (zero if no MOH) */ - int moh_offset; - /*! Offset into app_name[] where the application argument string starts. (zero if no arguments) */ - int app_args_offset; - /*! Application name to run. */ - char app_name[0]; -}; - -static void dynamic_dtmf_hook_callback(struct ast_bridge_channel *bridge_channel, - const void *payload, size_t payload_size) -{ - struct ast_channel *chan = bridge_channel->chan; - const struct dynamic_dtmf_hook_run *run_data = payload; - - pbx_builtin_setvar_helper(chan, "DYNAMIC_FEATURENAME", - &run_data->app_name[run_data->feature_offset]); - pbx_builtin_setvar_helper(chan, "DYNAMIC_WHO_ACTIVATED", - &run_data->app_name[run_data->activated_offset]); - - ast_bridge_channel_run_app(bridge_channel, run_data->app_name, - run_data->app_args_offset ? &run_data->app_name[run_data->app_args_offset] : NULL, - run_data->moh_offset ? &run_data->app_name[run_data->moh_offset] : NULL); -} - -struct dynamic_dtmf_hook_data { - /*! Which side of bridge to run app (AST_FEATURE_FLAG_ONSELF/AST_FEATURE_FLAG_ONPEER) */ - unsigned int flags; - /*! Offset into app_name[] where the dynamic feature name starts. */ - int feature_offset; - /*! Offset into app_name[] where the MOH class name starts. (zero if no MOH) */ - int moh_offset; - /*! Offset into app_name[] where the application argument string starts. (zero if no arguments) */ - int app_args_offset; - /*! Application name to run. */ - char app_name[0]; -}; - -/*! - * \internal - * \brief Activated dynamic DTMF feature hook. - * \since 12.0.0 - * - * \param bridge_channel Channel executing the feature - * \param hook_pvt Private data passed in when the hook was created - * - * \retval 0 Keep the callback hook. - * \retval -1 Remove the callback hook. - */ -static int dynamic_dtmf_hook_trip(struct ast_bridge_channel *bridge_channel, void *hook_pvt) -{ - struct dynamic_dtmf_hook_data *pvt = hook_pvt; - struct dynamic_dtmf_hook_run *run_data; - const char *activated_name; - size_t len_name; - size_t len_args; - size_t len_moh; - size_t len_feature; - size_t len_activated; - size_t len_data; - - /* Determine lengths of things. */ - len_name = strlen(pvt->app_name) + 1; - len_args = pvt->app_args_offset ? strlen(&pvt->app_name[pvt->app_args_offset]) + 1 : 0; - len_moh = pvt->moh_offset ? strlen(&pvt->app_name[pvt->moh_offset]) + 1 : 0; - len_feature = strlen(&pvt->app_name[pvt->feature_offset]) + 1; - ast_channel_lock(bridge_channel->chan); - activated_name = ast_strdupa(ast_channel_name(bridge_channel->chan)); - ast_channel_unlock(bridge_channel->chan); - len_activated = strlen(activated_name) + 1; - len_data = sizeof(*run_data) + len_name + len_args + len_moh + len_feature + len_activated; - - /* Fill in dynamic feature run hook data. */ - run_data = ast_alloca(len_data); - run_data->app_args_offset = len_args ? len_name : 0; - run_data->moh_offset = len_moh ? len_name + len_args : 0; - run_data->feature_offset = len_name + len_args + len_moh; - run_data->activated_offset = len_name + len_args + len_moh + len_feature; - strcpy(run_data->app_name, pvt->app_name);/* Safe */ - if (len_args) { - strcpy(&run_data->app_name[run_data->app_args_offset], - &pvt->app_name[pvt->app_args_offset]);/* Safe */ - } - if (len_moh) { - strcpy(&run_data->app_name[run_data->moh_offset], - &pvt->app_name[pvt->moh_offset]);/* Safe */ - } - strcpy(&run_data->app_name[run_data->feature_offset], - &pvt->app_name[pvt->feature_offset]);/* Safe */ - strcpy(&run_data->app_name[run_data->activated_offset], activated_name);/* Safe */ - - if (ast_test_flag(pvt, AST_FEATURE_FLAG_ONPEER)) { - ast_bridge_channel_write_callback(bridge_channel, - AST_BRIDGE_CHANNEL_CB_OPTION_MEDIA, - dynamic_dtmf_hook_callback, run_data, len_data); - } else { - dynamic_dtmf_hook_callback(bridge_channel, run_data, len_data); - } - return 0; -} - -/*! - * \internal - * \brief Add a dynamic DTMF feature hook to the bridge features. - * \since 12.0.0 - * - * \param features Bridge features to setup. - * \param flags Which side of bridge to run app (AST_FEATURE_FLAG_ONSELF/AST_FEATURE_FLAG_ONPEER). - * \param dtmf DTMF trigger sequence. - * \param feature_name Name of the dynamic feature. - * \param app_name Dialplan application name to run. - * \param app_args Dialplan application arguments. (Empty or NULL if no arguments) - * \param moh_class MOH class to play to peer. (Empty or NULL if no MOH played) - * - * \retval 0 on success. - * \retval -1 on error. - */ -static int dynamic_dtmf_hook_add(struct ast_bridge_features *features, unsigned int flags, const char *dtmf, const char *feature_name, const char *app_name, const char *app_args, const char *moh_class) -{ - struct dynamic_dtmf_hook_data *hook_data; - size_t len_name = strlen(app_name) + 1; - size_t len_args = ast_strlen_zero(app_args) ? 0 : strlen(app_args) + 1; - size_t len_moh = ast_strlen_zero(moh_class) ? 0 : strlen(moh_class) + 1; - size_t len_feature = strlen(feature_name) + 1; - size_t len_data = sizeof(*hook_data) + len_name + len_args + len_moh + len_feature; - int res; - - /* Fill in application run hook data. */ - hook_data = ast_malloc(len_data); - if (!hook_data) { - return -1; - } - hook_data->flags = flags; - hook_data->app_args_offset = len_args ? len_name : 0; - hook_data->moh_offset = len_moh ? len_name + len_args : 0; - hook_data->feature_offset = len_name + len_args + len_moh; - strcpy(hook_data->app_name, app_name);/* Safe */ - if (len_args) { - strcpy(&hook_data->app_name[hook_data->app_args_offset], app_args);/* Safe */ - } - if (len_moh) { - strcpy(&hook_data->app_name[hook_data->moh_offset], moh_class);/* Safe */ - } - strcpy(&hook_data->app_name[hook_data->feature_offset], feature_name);/* Safe */ - - res = ast_bridge_dtmf_hook(features, dtmf, dynamic_dtmf_hook_trip, hook_data, - ast_free_ptr, AST_BRIDGE_HOOK_REMOVE_ON_PULL); - if (res) { - ast_free(hook_data); - } - return res; -} - -static int setup_dynamic_feature(void *obj, void *arg, void *data, int flags) -{ - struct ast_applicationmap_item *item = obj; - struct ast_bridge_features *features = arg; - int *res = data; - - *res |= dynamic_dtmf_hook_add(features, - item->activate_on_self ? AST_FEATURE_FLAG_ONSELF : AST_FEATURE_FLAG_ONPEER, - item->dtmf, item->name, item->app, item->app_data, item->moh_class); - - return 0; -} - -/*! - * \internal - * \brief Setup bridge dynamic features. - * \since 12.0.0 - * - * \param features Bridge features to setup. - * \param chan Get features from this channel. - * - * \retval 0 on success. - * \retval -1 on error. - */ -static int setup_bridge_features_dynamic(struct ast_bridge_features *features, struct ast_channel *chan) -{ - RAII_VAR(struct ao2_container *, applicationmap, NULL, ao2_cleanup); - int res = 0; - - ast_channel_lock(chan); - applicationmap = ast_get_chan_applicationmap(chan); - ast_channel_unlock(chan); - if (!applicationmap) { - return 0; - } - - ao2_callback_data(applicationmap, 0, setup_dynamic_feature, features, &res); - - return res; -} - -/* BUGBUG this really should be made a private function of bridge_basic.c after struct ast_call_feature is made an ao2 object. */ -int ast_bridge_channel_setup_features(struct ast_bridge_channel *bridge_channel) -{ - int res = 0; - - res |= setup_bridge_features_builtin(bridge_channel->features, bridge_channel->chan); - res |= setup_bridge_features_dynamic(bridge_channel->features, bridge_channel->chan); - - return res; -} - static void bridge_config_set_limits_warning_values(struct ast_bridge_config *config, struct ast_bridge_features_limits *limits) { if (config->end_sound) { |