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/bridge_basic.c | |
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/bridge_basic.c')
-rw-r--r-- | main/bridge_basic.c | 311 |
1 files changed, 310 insertions, 1 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); } /*! |