summaryrefslogtreecommitdiff
path: root/main/features.c
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2013-06-06 22:46:54 +0000
committerRichard Mudgett <rmudgett@digium.com>2013-06-06 22:46:54 +0000
commitbad8caa8c65ac1937ae1c85a0c5fb45f3e8a7fe4 (patch)
treed077d5d84638645d10508c15bb6f00538e8e1f64 /main/features.c
parent2dc8a060064f359a17f5ebcd515d85fe5203c019 (diff)
Reimplement bridging and DTMF features related channel variables in the bridging core.
* The channel variable ATTENDED_TRANSFER_COMPLETE_SOUND is no longer channel driver specific. If the channel variable is set on the transferrer channel, the sound will be played to the target of an attended transfer. * The channel variable BRIDGEPEER becomes a comma separated list of peers in a multi-party bridge. The BRIDGEPEER value can have a maximum of 10 peers listed. Any more peers in the bridge will not be included in the list. BRIDGEPEER is not valid in holding bridges like parking since those channels do not talk to each other even though they are in a bridge. * The channel variable BRIDGEPVTCALLID is only valid for two party bridges and will contain a value if the BRIDGEPEER's channel driver supports it. * The channel variable DYNAMIC_PEERNAME is redundant with BRIDGEPEER and is removed. The more useful DYNAMIC_WHO_ACTIVATED gives the channel name that activated the dynamic feature. * The channel variables DYNAMIC_FEATURENAME and DYNAMIC_WHO_ACTIVATED are set only on the channel executing the dynamic feature. Executing a dynamic feature on the bridge peer in a multi-party bridge will execute it on all peers of the activating channel. (closes issue ASTERISK-21555) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2582/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@390771 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/features.c')
-rw-r--r--main/features.c148
1 files changed, 103 insertions, 45 deletions
diff --git a/main/features.c b/main/features.c
index e0c6548a9..c71e73710 100644
--- a/main/features.c
+++ b/main/features.c
@@ -3289,9 +3289,46 @@ static int setup_bridge_features_builtin(struct ast_bridge_features *features, s
#endif
}
-struct dtmf_hook_run_app {
+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);
+}
+
+static void dynamic_dtmf_hook_run_callback(struct ast_bridge_channel *bridge_channel,
+ ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size)
+{
+ callback(bridge_channel, payload, payload_size);
+}
+
+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) */
@@ -3302,7 +3339,7 @@ struct dtmf_hook_run_app {
/*!
* \internal
- * \brief Setup bridge dynamic features.
+ * \brief Activated dynamic DTMF feature hook.
* \since 12.0.0
*
* \param bridge The bridge that the channel is part of
@@ -3312,27 +3349,55 @@ struct dtmf_hook_run_app {
* \retval 0 Keep the callback hook.
* \retval -1 Remove the callback hook.
*/
-static int app_dtmf_feature_hook(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+static int dynamic_dtmf_hook_trip(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
{
- struct dtmf_hook_run_app *pvt = hook_pvt;
- void (*run_it)(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class);
+ struct dynamic_dtmf_hook_data *pvt = hook_pvt;
+ void (*run_it)(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size);
+ 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)) {
- run_it = ast_bridge_channel_write_app;
+ run_it = ast_bridge_channel_write_callback;
} else {
- run_it = ast_bridge_channel_run_app;
+ run_it = dynamic_dtmf_hook_run_callback;
}
-
-/*
- * BUGBUG need to pass to run_it the triggering channel name so DYNAMIC_WHO_TRIGGERED can be set on the channel when it is run.
- *
- * This would replace DYNAMIC_PEERNAME which is redundant with
- * BRIDGEPEER anyway. The value of DYNAMIC_WHO_TRIGGERED is
- * really useful in the case of a multi-party bridge.
- */
- run_it(bridge_channel, pvt->app_name,
- pvt->app_args_offset ? &pvt->app_name[pvt->app_args_offset] : NULL,
- pvt->moh_offset ? &pvt->app_name[pvt->moh_offset] : NULL);
+ run_it(bridge_channel, dynamic_dtmf_hook_callback, run_data, len_data);
return 0;
}
@@ -3344,6 +3409,7 @@ static int app_dtmf_feature_hook(struct ast_bridge *bridge, struct ast_bridge_ch
* \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)
@@ -3351,32 +3417,35 @@ static int app_dtmf_feature_hook(struct ast_bridge *bridge, struct ast_bridge_ch
* \retval 0 on success.
* \retval -1 on error.
*/
-static int add_dynamic_dtmf_hook(struct ast_bridge_features *features, unsigned int flags, const char *dtmf, const char *app_name, const char *app_args, const char *moh_class)
+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 dtmf_hook_run_app *app_data;
+ 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_data = sizeof(*app_data) + len_name + len_args + len_moh;
+ size_t len_feature = strlen(feature_name) + 1;
+ size_t len_data = sizeof(*hook_data) + len_name + len_args + len_moh + len_feature;
/* Fill in application run hook data. */
- app_data = ast_malloc(len_data);
- if (!app_data) {
+ hook_data = ast_malloc(len_data);
+ if (!hook_data) {
return -1;
}
- app_data->flags = flags;
- app_data->app_args_offset = len_args ? len_name : 0;
- app_data->moh_offset = len_moh ? len_name + len_args : 0;
- strcpy(app_data->app_name, app_name);/* Safe */
+ 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(&app_data->app_name[app_data->app_args_offset], app_args);/* Safe */
+ strcpy(&hook_data->app_name[hook_data->app_args_offset], app_args);/* Safe */
}
if (len_moh) {
- strcpy(&app_data->app_name[app_data->moh_offset], moh_class);/* Safe */
+ strcpy(&hook_data->app_name[hook_data->moh_offset], moh_class);/* Safe */
}
+ strcpy(&hook_data->app_name[hook_data->feature_offset], feature_name);/* Safe */
- return ast_bridge_dtmf_hook(features, dtmf, app_dtmf_feature_hook,
- app_data, ast_free_ptr, AST_BRIDGE_HOOK_REMOVE_ON_PULL);
+ return ast_bridge_dtmf_hook(features, dtmf, dynamic_dtmf_hook_trip, hook_data,
+ ast_free_ptr, AST_BRIDGE_HOOK_REMOVE_ON_PULL);
}
static int setup_dynamic_feature(void *obj, void *arg, void *data, int flags)
@@ -3385,10 +3454,9 @@ static int setup_dynamic_feature(void *obj, void *arg, void *data, int flags)
struct ast_bridge_features *features = arg;
int *res = data;
- /* BUGBUG need to pass to add_dynamic_dtmf_hook the applicationmap name (item->name) so the DYNAMIC_FEATURENAME can be set on the channel when it is run. */
- *res |= add_dynamic_dtmf_hook(features, item->activate_on_self ? AST_FEATURE_FLAG_ONSELF :
- AST_FEATURE_FLAG_ONPEER, item->dtmf, item->app, item->app_data,
- item->moh_class);
+ *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;
}
@@ -3421,7 +3489,6 @@ static int setup_bridge_features_dynamic(struct ast_bridge_features *features, s
return res;
}
-/* BUGBUG struct ast_call_feature needs to be made an ao2 object so the basic bridge class can own the code setting up it's DTMF hooks. */
/* BUGBUG this really should be made a private function of bridging_basic.c after struct ast_call_feature is made an ao2 object. */
int ast_bridge_channel_setup_features(struct ast_bridge_channel *bridge_channel)
{
@@ -3540,15 +3607,6 @@ static int pre_bridge_setup(struct ast_channel *chan, struct ast_channel *peer,
{
int res;
-/* BUGBUG these channel vars may need to be made dynamic so they update when transfers happen. */
- pbx_builtin_setvar_helper(chan, "BRIDGEPEER", ast_channel_name(peer));
- pbx_builtin_setvar_helper(peer, "BRIDGEPEER", ast_channel_name(chan));
-
-/* BUGBUG revisit how BLINDTRANSFER operates with the new bridging model. */
- /* Clear any BLINDTRANSFER since the transfer has completed. */
- pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
- pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", NULL);
-
set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
add_features_datastores(chan, peer, config);