[asterisk-commits] rmudgett: branch rmudgett/bridge_phase r390174 - in /team/rmudgett/bridge_pha...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu May 30 18:37:01 CDT 2013
Author: rmudgett
Date: Thu May 30 18:36:59 2013
New Revision: 390174
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=390174
Log:
Bridge API: Update DYNAMIC_FEATURENAME and DYNAMIC_WHO_ACTIVATED.
* Removed DYNAMIC_PEERNAME since it is redundant with BRIDGEPEER.
Modified:
team/rmudgett/bridge_phase/CHANGES
team/rmudgett/bridge_phase/UPGRADE.txt
team/rmudgett/bridge_phase/include/asterisk/bridging.h
team/rmudgett/bridge_phase/main/bridging.c
team/rmudgett/bridge_phase/main/features.c
Modified: team/rmudgett/bridge_phase/CHANGES
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/CHANGES?view=diff&rev=390174&r1=390173&r2=390174
==============================================================================
--- team/rmudgett/bridge_phase/CHANGES (original)
+++ team/rmudgett/bridge_phase/CHANGES Thu May 30 18:36:59 2013
@@ -248,6 +248,15 @@
* 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.
Realtime
------------------
Modified: team/rmudgett/bridge_phase/UPGRADE.txt
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/UPGRADE.txt?view=diff&rev=390174&r1=390173&r2=390174
==============================================================================
--- team/rmudgett/bridge_phase/UPGRADE.txt (original)
+++ team/rmudgett/bridge_phase/UPGRADE.txt Thu May 30 18:36:59 2013
@@ -41,7 +41,7 @@
Core:
- The following channel variables have changed behavior which is described in
the CHANGES file: TRANSFER_CONTEXT, BRIDGEPEER, BRIDGEPVTCALLID,
- ATTENDED_TRANSFER_COMPLETE_SOUND, and DYNAMIC_PEERNAME.
+ ATTENDED_TRANSFER_COMPLETE_SOUND, DYNAMIC_FEATURENAME, and DYNAMIC_PEERNAME.
Queues:
- Queue logging for PAUSEALL/UNPAUSEALL now only occurs if the interface this is
@@ -91,9 +91,12 @@
Features:
- The features.conf [applicationmap] <FeatureName> ActivatedBy option is
- no longer honored. The feature is activated by which channel
- DYNAMIC_FEATURES includes the feature is on. Use predial to set different
- values of DYNAMIC_FEATURES on the channels
+ no longer honored. The feature is always activated by the channel that has
+ DYNAMIC_FEATURES defined on it when it enters the bridge. Use predial to set
+ different values of DYNAMIC_FEATURES on the channels
+
+ - Executing a dynamic feature on the bridge peer in a multi-party bridge will
+ execute it on all peers of the activating channel.
Parking:
- The arguments for the Park, ParkedCall, and ParkAndAnnounce applications have
Modified: team/rmudgett/bridge_phase/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/include/asterisk/bridging.h?view=diff&rev=390174&r1=390173&r2=390174
==============================================================================
--- team/rmudgett/bridge_phase/include/asterisk/bridging.h (original)
+++ team/rmudgett/bridge_phase/include/asterisk/bridging.h Thu May 30 18:36:59 2013
@@ -219,10 +219,12 @@
AST_BRIDGE_ACTION_TALKING_STOP,
/*! Bridge channel is to play the indicated sound file. */
AST_BRIDGE_ACTION_PLAY_FILE,
+ /*! Bridge channel is to run the indicated application. */
+ AST_BRIDGE_ACTION_RUN_APP,
+ /*! Bridge channel is to run the custom callback routine. */
+ AST_BRIDGE_ACTION_CALLBACK,
/*! Bridge channel is to get parked. */
AST_BRIDGE_ACTION_PARK,
- /*! Bridge channel is to run the indicated application. */
- AST_BRIDGE_ACTION_RUN_APP,
/*! Bridge channel is to execute a blind transfer. */
AST_BRIDGE_ACTION_BLIND_TRANSFER,
/*! Bridge channel is to execute an attended transfer */
@@ -1209,22 +1211,6 @@
void ast_bridge_channel_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class);
/*!
- * \brief Have a bridge channel park a channel in the bridge
- * \since 12.0.0
- *
- * \param bridge_channel Bridge channel performing the parking
- * \param parkee_uuid Unique id of the channel we want to park
- * \param parker_uuid Unique id of the channel parking the call
- * \param app_data string indicating data used for park application (NULL allowed)
- *
- * \note This is intended to be called by bridge hooks.
- *
- * \return Nothing
- */
-void ast_bridge_channel_write_park(struct ast_bridge_channel *bridge_channel, const char *parkee_uuid,
- const char *parker_uuid, const char *app_data);
-
-/*!
* \brief Write a bridge action play file frame into the bridge.
* \since 12.0.0
*
@@ -1257,6 +1243,69 @@
* \return Nothing
*/
void ast_bridge_channel_queue_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class);
+
+/*!
+ * \brief Custom callback run on a bridge channel.
+ *
+ * \param bridge_channel Which channel to operate on.
+ * \param payload Data to pass to the callback. (NULL if none).
+ * \param payload_size Size of the payload if payload is non-NULL. A number otherwise.
+ *
+ * \note The payload MUST NOT have any resources that need to be freed.
+ *
+ * \return Nothing
+ */
+typedef void (*ast_bridge_custom_callback_fn)(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size);
+
+/*!
+ * \brief Write a bridge action custom callback frame into the bridge.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel is putting the frame into the bridge
+ * \param callback Custom callback run on a bridge channel.
+ * \param payload Data to pass to the callback. (NULL if none).
+ * \param payload_size Size of the payload if payload is non-NULL. A number otherwise.
+ *
+ * \note The payload MUST NOT have any resources that need to be freed.
+ *
+ * \note This is intended to be called by bridge hooks.
+ *
+ * \return Nothing
+ */
+void ast_bridge_channel_write_callback(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size);
+
+/*!
+ * \brief Queue a bridge action custom callback frame onto the bridge channel.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel to put the frame onto.
+ * \param callback Custom callback run on a bridge channel.
+ * \param payload Data to pass to the callback. (NULL if none).
+ * \param payload_size Size of the payload if payload is non-NULL. A number otherwise.
+ *
+ * \note The payload MUST NOT have any resources that need to be freed.
+ *
+ * \note This is intended to be called by bridge hooks.
+ *
+ * \return Nothing
+ */
+void ast_bridge_channel_queue_callback(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size);
+
+/*!
+ * \brief Have a bridge channel park a channel in the bridge
+ * \since 12.0.0
+ *
+ * \param bridge_channel Bridge channel performing the parking
+ * \param parkee_uuid Unique id of the channel we want to park
+ * \param parker_uuid Unique id of the channel parking the call
+ * \param app_data string indicating data used for park application (NULL allowed)
+ *
+ * \note This is intended to be called by bridge hooks.
+ *
+ * \return Nothing
+ */
+void ast_bridge_channel_write_park(struct ast_bridge_channel *bridge_channel, const char *parkee_uuid,
+ const char *parker_uuid, const char *app_data);
/*!
* \brief Restore the formats of a bridge channel's channel to how they were before bridge_channel_join
Modified: team/rmudgett/bridge_phase/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/main/bridging.c?view=diff&rev=390174&r1=390173&r2=390174
==============================================================================
--- team/rmudgett/bridge_phase/main/bridging.c (original)
+++ team/rmudgett/bridge_phase/main/bridging.c Thu May 30 18:36:59 2013
@@ -922,6 +922,68 @@
{
payload_helper_playfile(ast_bridge_channel_queue_action_data,
bridge_channel, custom_play, playfile, moh_class);
+}
+
+struct bridge_custom_callback {
+ /*! Call this function on the bridge channel thread. */
+ ast_bridge_custom_callback_fn callback;
+ /*! Size of the payload if it exists. A number otherwise. */
+ size_t payload_size;
+ /*! Nonzero if the payload exists. */
+ char payload_exists;
+ /*! Payload to give to callback. */
+ char payload[0];
+};
+
+/*!
+ * \internal
+ * \brief Handle the do custom callback bridge action.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel to run the application on.
+ * \param data Action frame data to run the application.
+ *
+ * \return Nothing
+ */
+static void bridge_channel_do_callback(struct ast_bridge_channel *bridge_channel, struct bridge_custom_callback *data)
+{
+ data->callback(bridge_channel, data->payload_exists ? data->payload : NULL, data->payload_size);
+}
+
+static void payload_helper_cb(ast_bridge_channel_post_action_data post_it,
+ struct ast_bridge_channel *bridge_channel, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size)
+{
+ struct bridge_custom_callback *cb_data;
+ size_t len_data = sizeof(*cb_data) + (payload ? payload_size : 0);
+
+ /* Sanity check. */
+ if (!callback) {
+ ast_assert(0);
+ return;
+ }
+
+ /* Fill in custom callback frame data. */
+ cb_data = alloca(len_data);
+ cb_data->callback = callback;
+ cb_data->payload_size = payload_size;
+ cb_data->payload_exists = payload && payload_size;
+ if (cb_data->payload_exists) {
+ memcpy(cb_data->payload, payload, payload_size);/* Safe */
+ }
+
+ post_it(bridge_channel, AST_BRIDGE_ACTION_CALLBACK, cb_data, len_data);
+}
+
+void ast_bridge_channel_write_callback(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size)
+{
+ payload_helper_cb(ast_bridge_channel_write_action_data,
+ bridge_channel, callback, payload, payload_size);
+}
+
+void ast_bridge_channel_queue_callback(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size)
+{
+ payload_helper_cb(ast_bridge_channel_queue_action_data,
+ bridge_channel, callback, payload, payload_size);
}
struct bridge_park {
@@ -2361,17 +2423,24 @@
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
bridge_channel_unsuspend(bridge_channel);
break;
+ case AST_BRIDGE_ACTION_RUN_APP:
+ bridge_channel_suspend(bridge_channel);
+ ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
+ bridge_channel_run_app(bridge_channel, action->data.ptr);
+ ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
+ bridge_channel_unsuspend(bridge_channel);
+ break;
+ case AST_BRIDGE_ACTION_CALLBACK:
+ bridge_channel_suspend(bridge_channel);
+ ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
+ bridge_channel_do_callback(bridge_channel, action->data.ptr);
+ ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
+ bridge_channel_unsuspend(bridge_channel);
+ break;
case AST_BRIDGE_ACTION_PARK:
bridge_channel_suspend(bridge_channel);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
bridge_channel_park(bridge_channel, action->data.ptr);
- ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
- bridge_channel_unsuspend(bridge_channel);
- break;
- case AST_BRIDGE_ACTION_RUN_APP:
- bridge_channel_suspend(bridge_channel);
- ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
- bridge_channel_run_app(bridge_channel, action->data.ptr);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
bridge_channel_unsuspend(bridge_channel);
break;
Modified: team/rmudgett/bridge_phase/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/main/features.c?view=diff&rev=390174&r1=390173&r2=390174
==============================================================================
--- team/rmudgett/bridge_phase/main/features.c (original)
+++ team/rmudgett/bridge_phase/main/features.c Thu May 30 18:36:59 2013
@@ -4049,9 +4049,11 @@
#endif
}
-struct dtmf_hook_run_app {
- /*! Which side of bridge to run app (AST_FEATURE_FLAG_ONSELF/AST_FEATURE_FLAG_ONPEER) */
- unsigned int flags;
+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) */
@@ -4060,9 +4062,44 @@
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) */
+ int app_args_offset;
+ /*! Application name to run. */
+ char app_name[0];
+};
+
/*!
* \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
@@ -4072,27 +4109,55 @@
* \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);
+static int dynamic_dtmf_hook_trip(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+ 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;
- }
-
-/*
- * 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 = dynamic_dtmf_hook_run_callback;
+ }
+ run_it(bridge_channel, dynamic_dtmf_hook_callback, run_data, len_data);
return 0;
}
@@ -4104,6 +4169,7 @@
* \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)
@@ -4111,32 +4177,35 @@
* \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;
+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_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 */
- }
-
- return ast_bridge_dtmf_hook(features, dtmf, app_dtmf_feature_hook,
- app_data, ast_free_ptr, 1);
+ 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, dynamic_dtmf_hook_trip, hook_data,
+ ast_free_ptr, 1);
}
/*!
@@ -4167,7 +4236,6 @@
return 0;
}
-/* BUGBUG need to pass to add_dynamic_dtmf_hook the applicationmap name (feature->sname) so the DYNAMIC_FEATURENAME can be set on the channel when it is run. */
res = 0;
while ((tok = strsep(&dynamic_features, "#"))) {
struct feature_group *fg;
@@ -4179,8 +4247,9 @@
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);
+ feature = fge->feature;
+ res |= dynamic_dtmf_hook_add(features, feature->flags, fge->exten,
+ feature->sname, feature->app, feature->app_args, feature->moh_class);
}
}
AST_RWLIST_UNLOCK(&feature_groups);
@@ -4188,8 +4257,8 @@
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);
+ res |= dynamic_dtmf_hook_add(features, feature->flags, feature->exten,
+ feature->sname, feature->app, feature->app_args, feature->moh_class);
}
ast_unlock_call_features();
}
More information about the asterisk-commits
mailing list