[svn-commits] mmichelson: branch mmichelson/agent_experiment r371632 - /team/mmichelson/age...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Wed Aug 22 23:10:15 CDT 2012


Author: mmichelson
Date: Wed Aug 22 23:10:12 2012
New Revision: 371632

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=371632
Log:
Some initial tinkering with agent channels.

This employs a state machine for moving agents to
their various states throughout the process. Currently
two states are defined. Moving beyond this will require
me to start defining the channel tech for agents, which
is where the trickery will begin.

If this ever makes it in, a lot of this will probably
be split into multiple files since the actual channel
part of agents will be minimal compared to the state
machine and other logic associated with them.


Added:
    team/mmichelson/agent_experiment/channels/chan_agent2.c   (with props)

Added: team/mmichelson/agent_experiment/channels/chan_agent2.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/agent_experiment/channels/chan_agent2.c?view=auto&rev=371632
==============================================================================
--- team/mmichelson/agent_experiment/channels/chan_agent2.c (added)
+++ team/mmichelson/agent_experiment/channels/chan_agent2.c Wed Aug 22 23:10:12 2012
@@ -1,0 +1,199 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson 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.
+ */
+
+#include "asterisk.h"
+#include "asterisk/module.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/app.h"
+#include "asterisk/channel.h"
+#include "asterisk/bridging.h"
+
+enum agent_states {
+	AGENT_LOGGED_OUT,
+	AGENT_LOGGED_IN,
+	AGENT_RINGING,
+	AGENT_ON_CALL,
+	AGENT_WRAPPING_UP,
+};
+
+struct agent_state;
+
+struct agent {
+	/*! The name of the agent */
+	const char *name;
+	/*! The current state of the agent */
+	const struct agent_state *current_state;
+	/*! The bridge the agent waits in while logged in */
+	struct ast_bridge *bridge;
+	/*! The channel the agent logged in with */
+	struct ast_channel *channel;
+};
+
+#define AGENT_BUCKETS 37
+
+struct ao2_container *agents;
+
+static int agent_hash(const void *obj, int flags)
+{
+	const struct agent *agent = obj;
+	const char *name = (flags & OBJ_KEY) ? obj : agent->name;
+
+	return ast_str_case_hash(flags & OBJ_KEY ? name : agent->name);
+}
+
+static int agent_cmp(void *obj1, void *arg, int flags)
+{
+	const struct agent *agent1 = obj1;
+	const struct agent *agent2 = arg;
+	const char *name = (flags & OBJ_KEY) ? arg : agent2->name;
+
+	return (!strcasecmp(agent1->name, name) ? (CMP_MATCH | CMP_STOP) : 0);
+}
+
+/*!
+ * \brief Callback function for entering and exiting a state
+ *
+ * \param agent The agent whose state is affected
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+typedef int (*agent_state_fn)(struct agent *agent);
+
+/*!
+ * \brief Describes the state of an agent
+ */
+struct agent_state {
+	/*! Name of the state */
+	const char *name;
+	/*! Numerical value of the state */
+	enum agent_states state;
+	/*! Function called when agent enters the state */
+	agent_state_fn enter;
+	/*! Function called when agent exits the state */
+	agent_state_fn exit;
+};
+
+static int enter_logged_in(struct agent *agent)
+{
+	return ast_bridge_impart(agent->bridge, agent->channel, NULL, NULL, 0);
+}
+
+static int exit_logged_in(struct agent *agent)
+{
+	ast_assert(agent->current_state->state == AGENT_LOGGED_IN);
+	return ast_bridge_depart(agent->bridge, agent->channel);
+}
+
+static const struct agent_state LOGGED_IN = {
+	.name = "LOGGED_IN",
+	.state = AGENT_LOGGED_IN,
+	.enter = enter_logged_in,
+	.exit = exit_logged_in,
+};
+
+static int enter_ringing(struct agent *agent)
+{
+	return ast_stream_and_wait(agent->channel, "beep", "");
+}
+
+static const struct agent_state RINGING = {
+	.name = "RINGING",
+	.state = AGENT_RINGING,
+	.enter = enter_ringing,
+};
+
+static int change_agent_state(struct agent *agent, const struct agent_state *new_state)
+{
+	if (agent->current_state->exit && agent->current_state->exit(agent)) {
+		return -1;
+	}
+
+	agent->current_state = new_state;
+
+	if (agent->current_state->enter && agent->current_state->enter(agent)) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static struct agent *find_agent(const char *name)
+{
+	return ao2_find(agents, name, OBJ_KEY);
+}
+
+static int login_exec(struct ast_channel *chan, const char *data)
+{
+	/* Need to find the corresponding agent. If the agent is in anything
+	 * other than the AGENT_LOGGED_OUT state, then this operation is invalid.
+	 */
+	RAII_VAR(struct agent *, agent, find_agent(data), ao2_cleanup);
+	SCOPED_AO2LOCK(lock, agent);
+
+	if (!agent) {
+		ast_log(LOG_WARNING, "Invalid agent %s specified for AgentLogin\n", data);
+		return -1;
+	}
+
+	if (agent->current_state->state != AGENT_LOGGED_OUT) {
+		ast_log(LOG_WARNING, "Attempting to log in already logged-in agent %s\n", data);
+		return -1;
+	}
+
+	if (change_agent_state(agent, &LOGGED_IN)) {
+		ast_log(LOG_WARNING, "Problem attempting to log agent %s in\n", data);
+		return -1;
+	}
+
+	/* XXX Presumably, we need to devise a way to wait here until
+	 * the agent has logged out. The logical way to do this would be
+	 * to use ast_cond_wait(). The problem is that ast_cond_wait()
+	 * requires an ast_mutex_t as the second argument. With ao2 objects,
+	 * we can't get direct access to the lock.
+	 *
+	 * Possible solution: Create an ao2_cond_wait/ao2_cond_signal?
+	 */
+
+	return 0;
+}
+
+const char login_app[] = "AgentLogin";
+
+static int unload_module(void)
+{
+	ao2_cleanup(agents);
+	return ast_unregister_application(login_app);
+}
+
+static int load_module(void)
+{
+	if (ast_register_application_xml(login_app, login_exec) < 0) {
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	agents = ao2_container_alloc(AGENT_BUCKETS, agent_hash, agent_cmp); 
+	if (!agents) {
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk agent channel and applications",
+		.load = load_module,
+		.unload = unload_module,
+		.nonoptreq = "chan_agent2",
+		);

Propchange: team/mmichelson/agent_experiment/channels/chan_agent2.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/mmichelson/agent_experiment/channels/chan_agent2.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/mmichelson/agent_experiment/channels/chan_agent2.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain




More information about the svn-commits mailing list