[asterisk-commits] rmudgett: branch rmudgett/bridge_tasks r385393 - in /team/rmudgett/bridge_tas...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Apr 11 20:14:10 CDT 2013
Author: rmudgett
Date: Thu Apr 11 20:14:08 2013
New Revision: 385393
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=385393
Log:
Implement basic bridge subclass of ast_bridge.
* Need to make features.c struct ast_call_feature an ao2 object.
* Need to move the code putting the DTMF hooks for the basic bridge into
the basic bridge file rather than the code living in features.c. The code
lives in features.c now because that is where the user configuration data
lives.
Added:
team/rmudgett/bridge_tasks/include/asterisk/bridging_basic.h (with props)
team/rmudgett/bridge_tasks/main/bridging_basic.c (with props)
Modified:
team/rmudgett/bridge_tasks/configs/features.conf.sample
team/rmudgett/bridge_tasks/funcs/func_channel.c
team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h
team/rmudgett/bridge_tasks/main/bridging.c
team/rmudgett/bridge_tasks/main/features.c
Modified: team/rmudgett/bridge_tasks/configs/features.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/configs/features.conf.sample?view=diff&rev=385393&r1=385392&r2=385393
==============================================================================
--- team/rmudgett/bridge_tasks/configs/features.conf.sample (original)
+++ team/rmudgett/bridge_tasks/configs/features.conf.sample Thu Apr 11 20:14:08 2013
@@ -180,6 +180,9 @@
; values are "caller", "callee", and "both". "both" is the default.
; The "caller" is the channel that executed the Dial application, while
; the "callee" is the channel called by the Dial application.
+;BUGBUG ActivatedBy is no longer going to be honored.
+; It will only apply to the channel DYNAMIC_FEATURES is on.
+; Use predial to set different values of DYNAMIC_FEATURES on the channels.
; Application -> This is the application to execute.
; AppArguments -> These are the arguments to be passed into the application. If you need
; commas in your arguments, you should use either the second or third
Modified: team/rmudgett/bridge_tasks/funcs/func_channel.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/funcs/func_channel.c?view=diff&rev=385393&r1=385392&r2=385393
==============================================================================
--- team/rmudgett/bridge_tasks/funcs/func_channel.c (original)
+++ team/rmudgett/bridge_tasks/funcs/func_channel.c Thu Apr 11 20:14:08 2013
@@ -346,6 +346,8 @@
/*
* BUGBUG add CHANNEL(after_bridge_goto)=<parseable-goto> Sets an after bridge goto datastore property on the channel.
* CHANNEL(after_bridge_goto)=<empty> Deletes any after bridge goto datastore property on the channel.
+ *
+ * BUGBUG add CHANNEL(dtmf_features)=tkhwx sets channel dtmf features to specified. (transfer, park, hangup, monitor, mixmonitor)
*/
#define locked_copy_string(chan, dest, source, len) \
Added: team/rmudgett/bridge_tasks/include/asterisk/bridging_basic.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/include/asterisk/bridging_basic.h?view=auto&rev=385393
==============================================================================
--- team/rmudgett/bridge_tasks/include/asterisk/bridging_basic.h (added)
+++ team/rmudgett/bridge_tasks/include/asterisk/bridging_basic.h Thu Apr 11 20:14:08 2013
@@ -1,0 +1,107 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013 Digium, Inc.
+ *
+ * Richard Mudgett <rmudgett at 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 Basic bridge subclass API.
+ *
+ * \author Richard Mudgett <rmudgett at digium.com>
+ *
+ * See Also:
+ * \arg \ref AstCREDITS
+ */
+
+#ifndef _ASTERISK_BRIDGING_BASIC_H
+#define _ASTERISK_BRIDGING_BASIC_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* ------------------------------------------------------------------- */
+
+/*!
+ * \brief Get DTMF feature flags from the channel.
+ * \since 12.0.0
+ *
+ * \param chan Channel to get DTMF features datastore.
+ *
+ * \note The channel should be locked before calling this function.
+ *
+ * \retval flags on success.
+ * \retval NULL on error.
+ */
+struct ast_flags *ast_bridge_features_ds_get(struct ast_channel *chan);
+
+/*!
+ * \brief Set basic bridge DTMF feature flags datastore on the channel.
+ * \since 12.0.0
+ *
+ * \param chan Channel to set DTMF features datastore.
+ * \param flags Builtin DTMF feature flags. (ast_bridge_config flags)
+ *
+ * \note The channel must be locked before calling this function.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int ast_bridge_features_ds_set(struct ast_channel *chan, struct ast_flags *flags);
+
+/*!
+ * \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.
+ */
+int ast_bridge_channel_setup_features(struct ast_bridge_channel *bridge_channel);
+
+/*! \brief Bridge basic class virtual method table. */
+extern struct ast_bridge_methods ast_bridge_basic_v_table;
+
+/*!
+ * \brief Create a new basic class bridge
+ *
+ * \retval a pointer to a new bridge on success
+ * \retval NULL on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_bridge *bridge;
+ * bridge = ast_bridge_basic_new();
+ * \endcode
+ *
+ * This creates a basic two party bridge with any configured
+ * DTMF features enabled that will be destroyed once one of the
+ * channels hangs up.
+ */
+struct ast_bridge *ast_bridge_basic_new(void);
+
+/*! Initialize the basic bridge class for use by the system. */
+void ast_bridging_init_basic(void);
+
+/* ------------------------------------------------------------------- */
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* _ASTERISK_BRIDGING_BASIC_H */
Propchange: team/rmudgett/bridge_tasks/include/asterisk/bridging_basic.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/rmudgett/bridge_tasks/include/asterisk/bridging_basic.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/rmudgett/bridge_tasks/include/asterisk/bridging_basic.h
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h?view=diff&rev=385393&r1=385392&r2=385393
==============================================================================
--- team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h (original)
+++ team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h Thu Apr 11 20:14:08 2013
@@ -145,7 +145,7 @@
/*!
* \brief Maximum length of a DTMF feature string
*/
-#define MAXIMUM_DTMF_FEATURE_STRING 8
+#define MAXIMUM_DTMF_FEATURE_STRING (11 + 1)
/*! Extra parameters for a DTMF feature hook. */
struct ast_bridge_hook_dtmf {
Modified: team/rmudgett/bridge_tasks/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/main/bridging.c?view=diff&rev=385393&r1=385392&r2=385393
==============================================================================
--- team/rmudgett/bridge_tasks/main/bridging.c (original)
+++ team/rmudgett/bridge_tasks/main/bridging.c Thu Apr 11 20:14:08 2013
@@ -40,8 +40,9 @@
#include "asterisk/lock.h"
#include "asterisk/linkedlists.h"
#include "asterisk/bridging.h"
+#include "asterisk/bridging_basic.h"
+#include "asterisk/bridging_technology.h"
#include "asterisk/stasis_bridging.h"
-#include "asterisk/bridging_technology.h"
#include "asterisk/app.h"
#include "asterisk/file.h"
#include "asterisk/module.h"
@@ -4568,6 +4569,8 @@
return -1;
}
+ ast_bridging_init_basic();
+
/* BUGBUG need AMI action equivalents to the CLI commands. */
ast_cli_register_multiple(bridge_cli, ARRAY_LEN(bridge_cli));
Added: team/rmudgett/bridge_tasks/main/bridging_basic.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/main/bridging_basic.c?view=auto&rev=385393
==============================================================================
--- team/rmudgett/bridge_tasks/main/bridging_basic.c (added)
+++ team/rmudgett/bridge_tasks/main/bridging_basic.c Thu Apr 11 20:14:08 2013
@@ -1,0 +1,158 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013 Digium, Inc.
+ *
+ * Richard Mudgett <rmudgett at 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 Basic bridge class. It is a subclass of struct ast_bridge.
+ *
+ * \author Richard Mudgett <rmudgett at digium.com>
+ *
+ * See Also:
+ * \arg \ref AstCREDITS
+ */
+
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/channel.h"
+#include "asterisk/utils.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/bridging.h"
+#include "asterisk/bridging_basic.h"
+#include "asterisk/astobj2.h"
+
+/* ------------------------------------------------------------------- */
+
+static const struct ast_datastore_info dtmf_features_info = {
+ .type = "bridge-dtmf-features",
+ .destroy = ast_free_ptr,
+};
+
+int ast_bridge_features_ds_set(struct ast_channel *chan, struct ast_flags *flags)
+{
+ struct ast_datastore *datastore;
+ struct ast_flags *ds_flags;
+
+ datastore = ast_channel_datastore_find(chan, &dtmf_features_info, NULL);
+ if (datastore) {
+ ds_flags = datastore->data;
+ *ds_flags = *flags;
+ return 0;
+ }
+
+ datastore = ast_datastore_alloc(&dtmf_features_info, NULL);
+ if (!datastore) {
+ return -1;
+ }
+
+ ds_flags = ast_malloc(sizeof(*ds_flags));
+ if (!ds_flags) {
+ ast_datastore_free(datastore);
+ return -1;
+ }
+
+ *ds_flags = *flags;
+ datastore->data = ds_flags;
+ ast_channel_datastore_add(chan, datastore);
+ return 0;
+}
+
+struct ast_flags *ast_bridge_features_ds_get(struct ast_channel *chan)
+{
+ struct ast_datastore *datastore;
+
+ datastore = ast_channel_datastore_find(chan, &dtmf_features_info, NULL);
+ if (!datastore) {
+ return NULL;
+ }
+ return datastore->data;
+}
+
+/*!
+ * \internal
+ * \brief Determine if we should dissolve the bridge from a hangup.
+ * \since 12.0.0
+ *
+ * \param bridge The bridge that the channel is part of
+ * \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 basic_hangup_hook(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+ ast_bridge_channel_lock_bridge(bridge_channel);
+ if (2 < bridge_channel->bridge->num_channels) {
+ /* Just allow this channel to leave the multi-party bridge. */
+ ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+ }
+ ast_bridge_unlock(bridge_channel->bridge);
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief ast_bridge basic push method.
+ * \since 12.0.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.
+ * \note Stub because of nothing to do.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+static int bridge_basic_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
+{
+ if (ast_bridge_hangup_hook(bridge_channel->features, basic_hangup_hook, NULL, NULL, 1)
+ || ast_bridge_channel_setup_features(bridge_channel)) {
+ return -1;
+ }
+
+ return ast_bridge_base_v_table.push(self, bridge_channel, swap);
+}
+
+struct ast_bridge_methods ast_bridge_basic_v_table;
+
+struct ast_bridge *ast_bridge_basic_new(void)
+{
+ void *bridge;
+
+ bridge = ast_bridge_alloc(sizeof(struct ast_bridge), &ast_bridge_basic_v_table);
+ bridge = ast_bridge_base_init(bridge,
+ AST_BRIDGE_CAPABILITY_EARLY | AST_BRIDGE_CAPABILITY_NATIVE
+ | AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_MULTIMIX,
+ AST_BRIDGE_FLAG_DISSOLVE_HANGUP | AST_BRIDGE_FLAG_DISSOLVE_EMPTY
+ | AST_BRIDGE_FLAG_SMART);
+ bridge = ast_bridge_register(bridge);
+ return bridge;
+}
+
+void ast_bridging_init_basic(void)
+{
+ /* Setup bridge basic subclass v_table. */
+ ast_bridge_basic_v_table = ast_bridge_base_v_table;
+ ast_bridge_basic_v_table.name = "basic";
+ ast_bridge_basic_v_table.push = bridge_basic_push;
+}
Propchange: team/rmudgett/bridge_tasks/main/bridging_basic.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/rmudgett/bridge_tasks/main/bridging_basic.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/rmudgett/bridge_tasks/main/bridging_basic.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: team/rmudgett/bridge_tasks/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/main/features.c?view=diff&rev=385393&r1=385392&r2=385393
==============================================================================
--- team/rmudgett/bridge_tasks/main/features.c (original)
+++ team/rmudgett/bridge_tasks/main/features.c Thu Apr 11 20:14:08 2013
@@ -73,6 +73,7 @@
#include "asterisk/cel.h"
#include "asterisk/test.h"
#include "asterisk/bridging.h"
+#include "asterisk/bridging_basic.h"
/*
* Party A - transferee
@@ -3759,6 +3760,9 @@
{
int x;
+/* BUGBUG there is code that checks AST_BRIDGE_IGNORE_SIGS but no code to set it. */
+/* BUGBUG there is code that checks AST_BRIDGE_REC_CHANNEL_0 but no code to set it. */
+/* BUGBUG there is code that checks AST_BRIDGE_REC_CHANNEL_1 but no code to set it. */
ast_clear_flag(config, AST_FLAGS_ALL);
ast_rdlock_call_features();
@@ -4271,76 +4275,226 @@
/*!
* \internal
- * \brief Setup bridge channel features.
+ * \brief Setup bridge builtin features.
* \since 12.0.0
*
* \param features Bridge features to setup.
- * \param flags DTMF features to enable.
+ * \param chan Get features from this channel.
*
* \retval 0 on success.
- * \retval -1 on failure.
- */
-static int setup_bridge_channel_features(struct ast_bridge_features *features, struct ast_flags *flags)
-{
- struct ast_call_feature *dtmf;
- int res = 0;
-
- /* Always pass through any DTMF digits. */
- features->dtmf_passthrough = 1;
-
+ * \retval -1 on error.
+ */
+static int setup_bridge_features_builtin(struct ast_bridge_features *features, struct ast_channel *chan)
+{
+ struct ast_flags *flags;
+ char dtmf[FEATURE_MAX_LEN];
+ int res;
+
+ ast_channel_lock(chan);
+ flags = ast_bridge_features_ds_get(chan);
+ ast_channel_unlock(chan);
+ if (!flags) {
+ return 0;
+ }
+
+ res = 0;
+ ast_rdlock_call_features();
if (ast_test_flag(flags, AST_FEATURE_REDIRECT)) {
/* Add atxfer and blind transfer. */
- ast_rwlock_rdlock(&features_lock);
- dtmf = ast_find_call_feature("blindxfer");
- if (dtmf && !ast_strlen_zero(dtmf->exten)) {
+ builtin_feature_get_exten(chan, "blindxfer", dtmf, sizeof(dtmf));
+ if (!ast_strlen_zero(dtmf)) {
/* BUGBUG need to supply a blind transfer structure and destructor to use other than defaults */
- res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_BLINDTRANSFER, dtmf->exten, NULL, NULL, 0);
- }
- dtmf = ast_find_call_feature("atxfer");
- if (dtmf && !ast_strlen_zero(dtmf->exten)) {
+ res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_BLINDTRANSFER, dtmf, NULL, NULL, 1);
+ }
+ builtin_feature_get_exten(chan, "atxfer", dtmf, sizeof(dtmf));
+ if (!ast_strlen_zero(dtmf)) {
/* BUGBUG need to supply an attended transfer structure and destructor to use other than defaults */
- res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, dtmf->exten, NULL, NULL, 0);
- }
- ast_rwlock_unlock(&features_lock);
+ res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, dtmf, NULL, NULL, 1);
+ }
}
if (ast_test_flag(flags, AST_FEATURE_DISCONNECT)) {
- ast_rwlock_rdlock(&features_lock);
- dtmf = ast_find_call_feature("disconnect");
- if (dtmf && !ast_strlen_zero(dtmf->exten)) {
- res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_HANGUP, dtmf->exten, NULL, NULL, 0);
- }
- ast_rwlock_unlock(&features_lock);
+ builtin_feature_get_exten(chan, "disconnect", dtmf, sizeof(dtmf));
+ if (ast_strlen_zero(dtmf)) {
+ res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_HANGUP, dtmf, NULL, NULL, 1);
+ }
}
if (ast_test_flag(flags, AST_FEATURE_PARKCALL)) {
- ast_rwlock_rdlock(&features_lock);
- dtmf = ast_find_call_feature("parkcall");
- if (dtmf && !ast_strlen_zero(dtmf->exten)) {
- res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_PARKCALL, dtmf->exten, NULL, NULL, 0);
- }
- ast_rwlock_unlock(&features_lock);
+ builtin_feature_get_exten(chan, "parkcall", dtmf, sizeof(dtmf));
+ if (!ast_strlen_zero(dtmf)) {
+ res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_PARKCALL, dtmf, NULL, NULL, 1);
+ }
}
if (ast_test_flag(flags, AST_FEATURE_AUTOMON)) {
- ast_rwlock_rdlock(&features_lock);
- dtmf = ast_find_call_feature("automon");
- if (dtmf && !ast_strlen_zero(dtmf->exten)) {
- res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_AUTOMON, dtmf->exten, NULL, NULL, 0);
- }
- ast_rwlock_unlock(&features_lock);
+ builtin_feature_get_exten(chan, "automon", dtmf, sizeof(dtmf));
+ if (!ast_strlen_zero(dtmf)) {
+ res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_AUTOMON, dtmf, NULL, NULL, 1);
+ }
}
if (ast_test_flag(flags, AST_FEATURE_AUTOMIXMON)) {
- ast_rwlock_rdlock(&features_lock);
- dtmf = ast_find_call_feature("automixmon");
- if (dtmf && !ast_strlen_zero(dtmf->exten)) {
- res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_AUTOMIXMON, dtmf->exten, NULL, NULL, 0);
- }
- ast_rwlock_unlock(&features_lock);
- }
+ builtin_feature_get_exten(chan, "automixmon", dtmf, sizeof(dtmf));
+ if (!ast_strlen_zero(dtmf)) {
+ res |= ast_bridge_features_enable(features, AST_BRIDGE_BUILTIN_AUTOMIXMON, dtmf, NULL, NULL, 1);
+ }
+ }
+ ast_unlock_call_features();
#if 0 /* BUGBUG don't report errors untill all of the builtin features are supported. */
return res ? -1 : 0;
#else
return 0;
#endif
+}
+
+struct dtmf_hook_run_app {
+ /*! Which side of bridge to run app (AST_FEATURE_FLAG_ONSELF/AST_FEATURE_FLAG_ONPEER) */
+ unsigned int flags;
+ /*! 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 Setup bridge dynamic features.
+ * \since 12.0.0
+ *
+ * \param bridge The bridge that the channel is part of
+ * \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 app_dtmf_feature_hook(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);
+
+ if (ast_test_flag(pvt, AST_FEATURE_FLAG_ONPEER)) {
+ run_it = ast_bridge_channel_write_app;
+ } else {
+ run_it = ast_bridge_channel_run_app;
+ }
+
+ 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);
+ 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 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 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)
+{
+ struct dtmf_hook_run_app *app_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;
+
+ /* Fill in application run hook data. */
+ app_data = ast_malloc(len_data);
+ if (!app_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 */
+ if (len_args) {
+ strcpy(&app_data->app_name[app_data->app_args_offset], app_args);/* Safe */
+ }
+ if (len_moh) {
+ strcpy(&app_data->app_name[app_data->moh_offset], moh_class);/* Safe */
+ }
+
+ return ast_bridge_dtmf_hook(features, dtmf, app_dtmf_feature_hook,
+ app_data, ast_free_ptr, 1);
+}
+
+/*!
+ * \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)
+{
+ const char *feat;
+ char *dynamic_features = NULL;
+ char *tok;
+ int res;
+
+ ast_channel_lock(chan);
+ feat = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
+ if (!ast_strlen_zero(feat)) {
+ dynamic_features = ast_strdupa(feat);
+ }
+ ast_channel_unlock(chan);
+ if (!dynamic_features) {
+ return 0;
+ }
+
+ res = 0;
+ while ((tok = strsep(&dynamic_features, "#"))) {
+ struct feature_group *fg;
+ struct ast_call_feature *feature;
+
+ AST_RWLIST_RDLOCK(&feature_groups);
+ fg = find_group(tok);
+ if (fg) {
+ struct feature_group_exten *fge;
+
+ AST_LIST_TRAVERSE(&fg->features, fge, entry) {
+ res |= add_dynamic_dtmf_hook(features, fge->feature->flags, fge->exten,
+ fge->feature->app, fge->feature->app_args, fge->feature->moh_class);
+ }
+ }
+ AST_RWLIST_UNLOCK(&feature_groups);
+
+ ast_rdlock_call_features();
+ feature = find_dynamic_feature(tok);
+ if (feature) {
+ res |= add_dynamic_dtmf_hook(features, feature->flags, feature->exten,
+ feature->app, feature->app_args, feature->moh_class);
+ }
+ ast_unlock_call_features();
+ }
+ return res;
+}
+
+int ast_bridge_channel_setup_features(struct ast_bridge_channel *bridge_channel)
+{
+ int res = 0;
+
+ /* Always pass through any DTMF digits. */
+ bridge_channel->features->dtmf_passthrough = 1;
+
+ 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)
@@ -4514,12 +4668,22 @@
clear_dialed_interfaces(chan);
clear_dialed_interfaces(peer);
- /* Setup DTMF features. */
+ res = 0;
+ ast_channel_lock(chan);
+ res |= ast_bridge_features_ds_set(chan, &config->features_caller);
+ ast_channel_unlock(chan);
+ ast_channel_lock(peer);
+ res |= ast_bridge_features_ds_set(peer, &config->features_callee);
+ ast_channel_unlock(peer);
+ if (res) {
+ bridge_failed_peer_goto(chan, peer);
+ return -1;
+ }
+
+ /* Setup features. */
res = ast_bridge_features_init(&chan_features);
peer_features = ast_bridge_features_new();
- if (res || !peer_features
- || setup_bridge_channel_features(peer_features, &config->features_callee)
- || setup_bridge_channel_features(&chan_features, &config->features_caller)) {
+ if (res || !peer_features) {
ast_bridge_features_destroy(peer_features);
ast_bridge_features_cleanup(&chan_features);
bridge_failed_peer_goto(chan, peer);
@@ -4573,10 +4737,7 @@
}
/* Create bridge */
-/* BUGBUG need to create the basic bridge class that will manage the DTMF feature hooks. */
- bridge = ast_bridge_base_new(
- AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_MULTIMIX,
- AST_BRIDGE_FLAG_DISSOLVE_HANGUP | AST_BRIDGE_FLAG_DISSOLVE_EMPTY | AST_BRIDGE_FLAG_SMART);
+ bridge = ast_bridge_basic_new();
if (!bridge) {
ast_bridge_features_destroy(peer_features);
ast_bridge_features_cleanup(&chan_features);
More information about the asterisk-commits
mailing list