[asterisk-commits] dvossel: branch dvossel/hd_confbridge r309539 - in /team/dvossel/hd_confbridg...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Mar 4 12:34:42 CST 2011
Author: dvossel
Date: Fri Mar 4 12:34:38 2011
New Revision: 309539
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=309539
Log:
Update to ConfBridge menu parser
Modified:
team/dvossel/hd_confbridge/apps/app_confbridge.c
team/dvossel/hd_confbridge/apps/confbridge/conf_config_parser.c
team/dvossel/hd_confbridge/apps/confbridge/include/confbridge.h
team/dvossel/hd_confbridge/bridges/bridge_builtin_features.c
team/dvossel/hd_confbridge/configs/confbridge.conf.sample
team/dvossel/hd_confbridge/include/asterisk/bridging_features.h
team/dvossel/hd_confbridge/main/bridging.c
Modified: team/dvossel/hd_confbridge/apps/app_confbridge.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/hd_confbridge/apps/app_confbridge.c?view=diff&rev=309539&r1=309538&r2=309539
==============================================================================
--- team/dvossel/hd_confbridge/apps/app_confbridge.c (original)
+++ team/dvossel/hd_confbridge/apps/app_confbridge.c Fri Mar 4 12:34:38 2011
@@ -595,6 +595,7 @@
/* Look for a conference bridge matching the provided name */
if (!(conference_bridge = join_conference_bridge(args.conf_name, &conference_bridge_user))) {
+ ast_bridge_features_cleanup(&conference_bridge_user.features);
return -1;
}
@@ -656,6 +657,17 @@
return res;
}
+
+int conf_handle_dtmf(
+ struct ast_bridge_channel *bridge_channel,
+ struct conference_bridge_user *conference_bridge_user,
+ struct conf_menu_entry *menu_entry,
+ struct conf_menu *menu)
+{
+ //todohere handle dtmf actions
+ return 0;
+}
+
static char *complete_confbridge_name(const char *line, const char *word, int pos, int state)
{
Modified: team/dvossel/hd_confbridge/apps/confbridge/conf_config_parser.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/hd_confbridge/apps/confbridge/conf_config_parser.c?view=diff&rev=309539&r1=309538&r2=309539
==============================================================================
--- team/dvossel/hd_confbridge/apps/confbridge/conf_config_parser.c (original)
+++ team/dvossel/hd_confbridge/apps/confbridge/conf_config_parser.c Fri Mar 4 12:34:38 2011
@@ -90,8 +90,12 @@
{
struct conf_menu *menu = obj;
struct conf_menu_entry *entry = NULL;
+ struct conf_menu_action *action = NULL;
while ((entry = AST_LIST_REMOVE_HEAD(&menu->entries, entry))) {
+ while ((action = AST_LIST_REMOVE_HEAD(&entry->actions, action))) {
+ ast_free(action);
+ }
ast_free(entry);
}
}
@@ -229,12 +233,73 @@
return 0;
}
-static int add_menu_item(struct conf_menu *menu, const char *dtmf, const char *action)
-{
-//todohere parse the dtmf and action
+static int add_action_to_menu_entry(struct conf_menu_entry *menu_entry, enum conf_menu_action_id id, char *databuf)
+{
+ struct conf_menu_action *menu_action = ast_calloc(1, sizeof(*menu_action));
+
+ if (!(menu_action)) {
+ return -1;
+ }
+ menu_action->id = id;
+
+ switch (id) {
+ case MENU_ACTION_TOGGLE_MUTE:
+ case MENU_ACTION_TOGGLE_DEAF:
+ break;
+ case MENU_ACTION_PLAYBACK:
+ if (!(ast_strlen_zero(databuf))) {
+ ast_copy_string(menu_action->data.playback_file, databuf, sizeof(menu_action->data.playback_file));
+ } else {
+ ast_free(menu_action);
+ return -1;
+ }
+ break;
+ };
+
+ AST_LIST_INSERT_HEAD(&menu_entry->actions, menu_action, action);
+
+ return 0;
+}
+
+static int add_menu_entry(struct conf_menu *menu, const char *dtmf, const char *action)
+{
+ struct conf_menu_entry *menu_entry = ast_calloc(1, sizeof(*menu_entry));
+ int res = 0;
+ unsigned int action_len = strlen(action);
+ if (!(menu_entry)) {
+ return -1;
+ }
+ ast_copy_string(menu_entry->dtmf, dtmf, sizeof(menu_entry->dtmf));
if (!strcasecmp(action, "toggle_mute")) {
-
- }
+ res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_TOGGLE_MUTE, NULL);
+ }
+ if (!strcasecmp(action, "toggle_deaf")) {
+ res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_TOGGLE_DEAF, NULL);
+ }
+ if (action_len >= 8 && !strncasecmp(action, "playback", 8)) {
+ char *filename = ast_strdupa(action);
+ char *tmp;
+ if ((filename = strchr(action, '(')) && (tmp = strrchr(filename, ')'))) {
+ *tmp = '\0';
+ filename++;
+ res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_PLAYBACK, filename);
+ } else {
+ res |= -1;
+ }
+ }
+
+ /* if adding any of the actions failed, bail */
+ if (res) {
+ struct conf_menu_action *action;
+ while ((action = AST_LIST_REMOVE_HEAD(&menu_entry->actions, action))) {
+ ast_free(action);
+ }
+ ast_free(menu_entry);
+ return -1;
+ }
+
+ AST_LIST_INSERT_HEAD(&menu->entries, menu_entry, entry);
+
return 0;
}
static int parse_menu(const char *cat, struct ast_config *cfg)
@@ -259,7 +324,7 @@
for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
if (!strcasecmp(var->name, "type")) {
continue;
- } else if (add_menu_item(menu, var->name, var->value)) {
+ } else if (add_menu_entry(menu, var->name, var->value)) {
ast_log(LOG_WARNING, "Unknown option '%s' at line %d of %s is not supported.\n",
var->name, var->lineno, CONF_CONFIG);
}
@@ -428,10 +493,13 @@
return res;
}
+
static char *handle_cli_confbridge_list_menus(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct conf_menu tmp;
struct conf_menu *menu;
+ struct conf_menu_entry *menu_entry = NULL;
+ struct conf_menu_action *menu_action = NULL;
switch (cmd) {
case CLI_INIT:
@@ -458,7 +526,30 @@
ao2_lock(menu);
ast_cli(a->fd,"Name: %s\n", menu->name);
- ast_cli(a->fd,"\n");
+ AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
+ int action_num = 0;
+ ast_cli(a->fd, "%s=", menu_entry->dtmf);
+ AST_LIST_TRAVERSE(&menu_entry->actions, menu_action, action) {
+ if (action_num) {
+ ast_cli(a->fd, ", ");
+ }
+ switch (menu_action->id) {
+ case MENU_ACTION_TOGGLE_MUTE:
+ ast_cli(a->fd, "toggle_mute");
+ break;
+ case MENU_ACTION_TOGGLE_DEAF:
+ ast_cli(a->fd, "toggle_deaf");
+ break;
+ case MENU_ACTION_PLAYBACK:
+ ast_cli(a->fd, "playback(%s)", menu_action->data.playback_file);
+ break;
+ }
+
+ action_num++;
+ }
+ ast_cli(a->fd,"\n");
+ }
+
ao2_unlock(menu);
ao2_ref(menu, -1);
@@ -596,21 +687,82 @@
return result;
}
+struct dtmf_menu_hook_pvt {
+ struct conference_bridge_user *conference_bridge_user;
+ struct conf_menu_entry menu_entry;
+ struct conf_menu *menu;
+};
+
+static void menu_hook_destroy(void *hook_pvt)
+{
+ struct dtmf_menu_hook_pvt *pvt = hook_pvt;
+ struct conf_menu_action *action = NULL;
+
+ ao2_ref(pvt->menu, -1);
+
+ while ((action = AST_LIST_REMOVE_HEAD(&pvt->menu_entry.actions, action))) {
+ ast_free(action);
+ }
+ ast_free(pvt);
+}
+
+static int menu_hook_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+ struct dtmf_menu_hook_pvt *pvt = hook_pvt;
+ return conf_handle_dtmf(bridge_channel, pvt->conference_bridge_user, &pvt->menu_entry, pvt->menu);
+}
+
+static int copy_menu_entry(struct conf_menu_entry *dst, struct conf_menu_entry *src)
+{
+ struct conf_menu_action *menu_action = NULL;
+ struct conf_menu_action *new_menu_action = NULL;
+
+ memcpy(dst, src, sizeof(*dst));
+ AST_LIST_HEAD_INIT_NOLOCK(&dst->actions);
+
+ AST_LIST_TRAVERSE(&src->actions, menu_action, action) {
+ if (!(new_menu_action = ast_calloc(1, sizeof(*new_menu_action)))) {
+ return -1;
+ }
+ memcpy(new_menu_action, menu_action, sizeof(new_menu_action));
+ AST_LIST_INSERT_HEAD(&dst->actions, new_menu_action, action);
+ }
+ return 0;
+}
+
int conf_set_menu_to_user(const char *menu_name, struct conference_bridge_user *conference_bridge_user)
{
struct conf_menu tmp;
- struct conf_menu *tmp2;
+ struct conf_menu *menu;
+ struct conf_menu_entry *menu_entry = NULL;
ast_copy_string(tmp.name, menu_name, sizeof(tmp.name));
- if (!(tmp2 = ao2_find(menus, &tmp, OBJ_POINTER))) {
- return -1;
- }
- ao2_lock(tmp2);
-//todohere add feature hooks to user.
-
-
- ao2_unlock(tmp2);
- ao2_ref(tmp2, -1);
-
- return 0;
-}
+ if (!(menu = ao2_find(menus, &tmp, OBJ_POINTER))) {
+ return -1;
+ }
+ ao2_lock(menu);
+ AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
+ struct dtmf_menu_hook_pvt *pvt;
+ if (!(pvt = ast_calloc(1, sizeof(*pvt)))) {
+ ao2_unlock(menu);
+ ao2_ref(menu, -1);
+ return -1;
+ }
+ if (copy_menu_entry(&pvt->menu_entry, menu_entry)) {
+ ast_free(pvt);
+ ao2_unlock(menu);
+ ao2_ref(menu, -1);
+ return -1;
+ }
+ pvt->conference_bridge_user = conference_bridge_user;
+ ao2_ref(menu, +1);
+ pvt->menu = menu;
+
+ ast_bridge_features_hook(&conference_bridge_user->features, pvt->menu_entry.dtmf, menu_hook_callback, pvt, menu_hook_destroy);
+ }
+
+ ao2_unlock(menu);
+ ao2_ref(menu, -1);
+
+ return 0;
+}
Modified: team/dvossel/hd_confbridge/apps/confbridge/include/confbridge.h
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/hd_confbridge/apps/confbridge/include/confbridge.h?view=diff&rev=309539&r1=309538&r2=309539
==============================================================================
--- team/dvossel/hd_confbridge/apps/confbridge/include/confbridge.h (original)
+++ team/dvossel/hd_confbridge/apps/confbridge/include/confbridge.h Fri Mar 4 12:34:38 2011
@@ -40,12 +40,38 @@
USER_OPT_WAITMARKED = (1 << 7), /*!< Set if the conference must wait for a marked user before starting */
};
+enum conf_menu_action_id {
+ MENU_ACTION_TOGGLE_MUTE = 1,
+ MENU_ACTION_TOGGLE_DEAF,
+ MENU_ACTION_PLAYBACK,
+};
+
+/*! The conference menu action contains both
+ * the action id that represents the action that
+ * must take place, along with any data associated
+ * with that action. */
+struct conf_menu_action {
+ enum conf_menu_action_id id;
+ union {
+ char playback_file[256];
+ } data;
+ AST_LIST_ENTRY(conf_menu_action) action;
+};
+
+/*! Conference menu entries contain the DTMF sequence
+ * and the list of actions that are associated with that
+ * sequence. */
struct conf_menu_entry {
- ast_bridge_features_hook_callback callback;
+ /*! the DTMF sequence that triggers the actions */
char dtmf[MAXIMUM_DTMF_FEATURE_STRING];
+ /*! The actions associated with this menu entry. */
+ AST_LIST_HEAD_NOLOCK(, conf_menu_action) actions;
AST_LIST_ENTRY(conf_menu_entry) entry;
};
+/*! Conference menu structure. Contains a list
+ * of DTMF sequences coupled with the actions those
+ * sequences invoke.*/
struct conf_menu {
char name[64];
int delme;
@@ -126,4 +152,29 @@
* \retval -1 on error, menu was not found
*/
int conf_set_menu_to_user(const char *menu_name, struct conference_bridge_user *conference_bridge_user);
+
+
+/*!
+ * \brief Once a DTMF sequence matches a sequence in the user's DTMF menu, this function will get
+ * called to perform the menu action.
+ *
+ * \param bridge_channel, Bridged channel this is involving
+ * \param conference_bridge_user, the conference user to perform the action on.
+ * \param menu_entry, the menu entry that invoked this callback to occur.
+ * \param menu, an AO2 referenced pointer to the entire menu structure the menu_entry
+ * derived from.
+ *
+ * \note The menu_entry is a deep copy of the entry found in the menu structure. This allows
+ * for the menu_entry to be accessed without requiring the menu lock. If the menu must
+ * be accessed, the menu lock must be held. Reference counting of the menu structure is
+ * handled outside of the scope of this function.
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int conf_handle_dtmf(
+ struct ast_bridge_channel *bridge_channel,
+ struct conference_bridge_user *conference_bridge_user,
+ struct conf_menu_entry *menu_entry,
+ struct conf_menu *menu);
#endif
Modified: team/dvossel/hd_confbridge/bridges/bridge_builtin_features.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/hd_confbridge/bridges/bridge_builtin_features.c?view=diff&rev=309539&r1=309538&r2=309539
==============================================================================
--- team/dvossel/hd_confbridge/bridges/bridge_builtin_features.c (original)
+++ team/dvossel/hd_confbridge/bridges/bridge_builtin_features.c Fri Mar 4 12:34:38 2011
@@ -198,9 +198,9 @@
ast_bridge_features_enable(&caller_features, AST_BRIDGE_BUILTIN_HANGUP,
(attended_transfer && !ast_strlen_zero(attended_transfer->complete) ? attended_transfer->complete : "*1"), NULL);
ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->threeway) ? attended_transfer->threeway : "*2"),
- attended_threeway_transfer, NULL);
+ attended_threeway_transfer, NULL, NULL);
ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->abort) ? attended_transfer->abort : "*3"),
- attended_abort_transfer, NULL);
+ attended_abort_transfer, NULL, NULL);
/* But for the caller we want to join the bridge in a blocking fashion so we don't spin around in this function doing nothing while waiting */
attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features);
Modified: team/dvossel/hd_confbridge/configs/confbridge.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/hd_confbridge/configs/confbridge.conf.sample?view=diff&rev=309539&r1=309538&r2=309539
==============================================================================
--- team/dvossel/hd_confbridge/configs/confbridge.conf.sample (original)
+++ team/dvossel/hd_confbridge/configs/confbridge.conf.sample Fri Mar 4 12:34:38 2011
@@ -33,4 +33,8 @@
[default_menu]
type=menu
+*1=toggle_mute ; Toggle turning on and off mute. Mute will make the user silent
+ ; to everyone else, but the user will still be able to listen in.
+*2=toggle_deaf ; Toggle turning on and off deaf. Deaf will make everyone else
+ ; silent for a user, but the user will still be able to be heard.
Modified: team/dvossel/hd_confbridge/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/hd_confbridge/include/asterisk/bridging_features.h?view=diff&rev=309539&r1=309538&r2=309539
==============================================================================
--- team/dvossel/hd_confbridge/include/asterisk/bridging_features.h (original)
+++ team/dvossel/hd_confbridge/include/asterisk/bridging_features.h Fri Mar 4 12:34:38 2011
@@ -64,6 +64,13 @@
typedef int (*ast_bridge_features_hook_callback)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt);
/*!
+ * \brief Features hook pvt destructor callback
+ *
+ * \param hook_pvt Private data passed in when the hook was create to destroy
+ */
+typedef void (*ast_bridge_features_hook_pvt_destructor)(void *hook_pvt);
+
+/*!
* \brief Maximum length of a DTMF feature string
*/
#define MAXIMUM_DTMF_FEATURE_STRING 8
@@ -76,6 +83,8 @@
char dtmf[MAXIMUM_DTMF_FEATURE_STRING];
/*! Callback that is called when DTMF string is matched */
ast_bridge_features_hook_callback callback;
+ /*! Callback to destroy hook_pvt data right before destruction. */
+ ast_bridge_features_hook_pvt_destructor destructor;
/*! Unique data that was passed into us */
void *hook_pvt;
/*! Linked list information */
@@ -161,16 +170,17 @@
* \param dtmf DTMF string to be activated upon
* \param callback Function to execute upon activation
* \param hook_pvt Unique data
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * Example usage:
- *
- * \code
- * struct ast_bridge_features features;
- * ast_bridge_features_init(&features);
- * ast_bridge_features_hook(&features, "#", pound_callback, NULL);
+ * \param Optional destructor callback for hook_pvt data
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_bridge_features features;
+ * ast_bridge_features_init(&features);
+ * ast_bridge_features_hook(&features, "#", pound_callback, NULL, NULL);
* \endcode
*
* This makes the bridging core call pound_callback if a channel that has this
@@ -180,7 +190,11 @@
* \note It is important that the callback set the bridge channel state back to
* AST_BRIDGE_CHANNEL_STATE_WAIT or the bridge thread will not service the channel.
*/
-int ast_bridge_features_hook(struct ast_bridge_features *features, const char *dtmf, ast_bridge_features_hook_callback callback, void *hook_pvt);
+int ast_bridge_features_hook(struct ast_bridge_features *features,
+ const char *dtmf,
+ ast_bridge_features_hook_callback callback,
+ void *hook_pvt,
+ ast_bridge_features_hook_pvt_destructor destructor);
/*! \brief Enable a built in feature on a bridge features structure
*
Modified: team/dvossel/hd_confbridge/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/hd_confbridge/main/bridging.c?view=diff&rev=309539&r1=309538&r2=309539
==============================================================================
--- team/dvossel/hd_confbridge/main/bridging.c (original)
+++ team/dvossel/hd_confbridge/main/bridging.c Fri Mar 4 12:34:38 2011
@@ -1268,7 +1268,12 @@
return 0;
}
-int ast_bridge_features_hook(struct ast_bridge_features *features, const char *dtmf, ast_bridge_features_hook_callback callback, void *hook_pvt)
+
+int ast_bridge_features_hook(struct ast_bridge_features *features,
+ const char *dtmf,
+ ast_bridge_features_hook_callback callback,
+ void *hook_pvt,
+ ast_bridge_features_hook_pvt_destructor destructor)
{
struct ast_bridge_features_hook *hook = NULL;
@@ -1279,6 +1284,7 @@
ast_copy_string(hook->dtmf, dtmf, sizeof(hook->dtmf));
hook->callback = callback;
+ hook->destructor = destructor;
hook->hook_pvt = hook_pvt;
/* Once done we add it onto the list. Now it will be picked up when DTMF is used */
@@ -1306,7 +1312,7 @@
}
/* The rest is basically pretty easy. We create another hook using the built in feature's callback and DTMF, easy as pie. */
- return ast_bridge_features_hook(features, dtmf, builtin_features_handlers[feature], config);
+ return ast_bridge_features_hook(features, dtmf, builtin_features_handlers[feature], config, NULL);
}
int ast_bridge_features_set_flag(struct ast_bridge_features *features, enum ast_bridge_feature_flags flag)
@@ -1333,6 +1339,9 @@
/* This is relatively simple, hooks are kept as a list on the features structure so we just pop them off and free them */
while ((hook = AST_LIST_REMOVE_HEAD(&features->hooks, entry))) {
+ if (hook->destructor) {
+ hook->destructor(hook->hook_pvt);
+ }
ast_free(hook);
}
More information about the asterisk-commits
mailing list