[asterisk-commits] russell: branch russell/events r74157 - /team/russell/events/channels/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Jul 9 15:07:04 CDT 2007


Author: russell
Date: Mon Jul  9 15:07:03 2007
New Revision: 74157

URL: http://svn.digium.com/view/asterisk?view=rev&rev=74157
Log:
Add support for explicitly setting the state of agent groups.  There are many
benefits to doing this, such as moving one step closer to having app_queue not
be required to poll chan_agent for device state changes.  Also, the last known
state of agent groups will be cached, so checking for it doesn't require calling
into chan_agent and locking up the agents container while it figures it out.

Modified:
    team/russell/events/channels/chan_agent.c

Modified: team/russell/events/channels/chan_agent.c
URL: http://svn.digium.com/view/asterisk/team/russell/events/channels/chan_agent.c?view=diff&rev=74157&r1=74156&r2=74157
==============================================================================
--- team/russell/events/channels/chan_agent.c (original)
+++ team/russell/events/channels/chan_agent.c Mon Jul  9 15:07:03 2007
@@ -147,6 +147,8 @@
 static char savecallsin[AST_MAX_BUF] = "";
 static int updatecdr = 0;
 static char beep[AST_MAX_BUF] = "beep";
+
+static enum ast_device_state group_states[sizeof(ast_group_t) * 8];
 
 #define GETAGENTBYCALLERID	"AGENTBYCALLERID"
 
@@ -176,6 +178,7 @@
 	char loginchan[80];            /**< channel they logged in from */
 	char logincallerid[80];        /**< Caller ID they had when they logged in */
 	struct ast_channel *chan;      /**< Channel we use */
+	enum ast_device_state state;    /*!< the last known state of this agent */
 	AST_LIST_ENTRY(agent_pvt) list;	/**< Next Agent in the linked list. */
 };
 
@@ -316,6 +319,7 @@
 		p->app_sleep_cond = 1;
 		p->group = group;
 		p->pending = pending;
+		p->state = AST_DEVICE_UNAVAILABLE;
 		AST_LIST_INSERT_TAIL(&agents, p, list);
 	}
 	
@@ -694,9 +698,87 @@
 	pbx_builtin_setvar_helper(NULL, buf, agent);
 }
 
+static void agent_set_group_state(int group_bit, enum ast_device_state state)
+{
+	int group = ffs(group_bit);
+
+	/* Should never happen ... */
+	if (!group)
+		return;
+
+	group--;
+
+	if (group >= ARRAY_LEN(group_states)) {
+		ast_log(LOG_ERROR, "Group '%d' is not a valid agent group!\n", group);
+		return;
+	}
+
+	if (state == group_states[group])
+		return;
+
+	group_states[group] = state;
+
+	/* Groups can be encoded in 2 formats ... */
+	ast_devstate_changed(state, "Agent/@%d", group);
+	ast_devstate_changed(state, "Agent/:%d", group);
+}
+
+/*!
+ * \brief Set the state of an agent and its groups as appropriate
+ *
+ * \note Agents are currently one of the following:
+ *   AST_DEVICE_UNAVAILABLE
+ *   AST_DEVICE_NOT_INUSE
+ *   AST_DEVICE_BUSY
+ */
 static void agent_set_state(struct agent_pvt *pvt, enum ast_device_state state)
 {
+	int i;
+
+	if (pvt->state == state)
+		return;
+
+	pvt->state = state;
 	ast_devstate_changed(state, "Agent/%s", pvt->agent);
+
+	if (!pvt->group)
+		return;
+
+	/* Handle each group this agent is a member of */
+	for (i = 1; i < sizeof(ast_group_t) * 8; i <<= 1) {
+		/* Start with the state of this agent. */
+		enum ast_device_state group_state = state;
+		struct agent_pvt *cur;
+
+		/* If the agent is NOT_INUSE, then consider the group available */
+		if (group_state == AST_DEVICE_NOT_INUSE) {
+			agent_set_group_state(i, group_state);
+			continue;
+		}
+
+		/* Determine the group state based on the other agents in the group.
+		 * If any agent is available (NOT_INUSE) set the group as available. */
+		AST_LIST_LOCK(&agents);
+		AST_LIST_TRAVERSE(&agents, cur, list) {
+			if (cur == pvt)
+				continue;
+			if (!(cur->group & i))
+				continue;
+
+			/* This agent is a member of the group */
+
+			if (cur->state == AST_DEVICE_NOT_INUSE) {
+				group_state = AST_DEVICE_NOT_INUSE;
+				break;
+			} else if (group_state == AST_DEVICE_UNAVAILABLE &&
+				cur->state == AST_DEVICE_BUSY) {
+				group_state = AST_DEVICE_BUSY;
+			}
+		}
+		AST_LIST_UNLOCK(&agents);
+
+		agent_set_group_state(i, group_state);
+	}
 }
 
 static int agent_hangup(struct ast_channel *ast)
@@ -985,7 +1067,7 @@
  *
  * \returns Always 0, or so it seems.
  */
-static int read_agent_config(void)
+static int read_agent_config(int reload)
 {
 	struct ast_config *cfg;
 	struct ast_config *ucfg;
@@ -995,6 +1077,7 @@
 	const char *catname;
 	const char *hasagent;
 	int genhasagent;
+	int i;
 
 	group = 0;
 	autologoff = 0;
@@ -1017,6 +1100,11 @@
 	strcpy(recordformatext, "wav");
 	urlprefix[0] = '\0';
 	savecallsin[0] = '\0';
+
+	if (!reload) {
+		for (i = 0; i < ARRAY_LEN(group_states); i++)
+			group_states[i] = AST_DEVICE_UNKNOWN;
+	}
 
 	/* Read in [general] section for persistence */
 	if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
@@ -2144,11 +2232,8 @@
 
 /*! \brief Part of PBX channel interface 
  *
- * This module is now pretty close to not needing this callback at all, as it
- * provides state information explicitly in ast_devstate_changed() calls.  However,
- * this function is still used to get the state of agent groups.  To remove this
- * completely, changing the state of an agent throughout the module needs to be
- * smart enough to also change the state of agent groups as appropriate. 
+ * This function is almost not needed.  The module should set states for known agents
+ * and agent groups at load time, though, to ensure the cache gets populated.
  */ 
 static int agent_devicestate(void *data)
 {
@@ -2289,7 +2374,7 @@
 		return -1;
 	}
 	/* Read in the config */
-	if (!read_agent_config())
+	if (!read_agent_config(0))
 		return AST_MODULE_LOAD_DECLINE;
 	if (persistent_agents)
 		reload_agents();
@@ -2312,7 +2397,7 @@
 
 static int reload(void)
 {
-	read_agent_config();
+	read_agent_config(1);
 	if (persistent_agents)
 		reload_agents();
 	return 0;




More information about the asterisk-commits mailing list