[svn-commits] dvossel: branch dvossel/hd_confbridge r309539 - in /team/dvossel/hd_confbridg...

SVN commits to the Digium repositories svn-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 svn-commits mailing list