[asterisk-commits] mmichelson: branch mmichelson/agent_experiment r371649 - /team/mmichelson/age...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Aug 23 22:41:10 CDT 2012
Author: mmichelson
Date: Thu Aug 23 22:41:06 2012
New Revision: 371649
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=371649
Log:
Progress towards agent channel.
This is where the fun happens. When an agent logs
in, we actually override/decorate certain channel
tech callbacks with our own versions. Currently, I
have the requester and call methods defined. There
will need to be a hangup method defined and most
likely a read, as well. Those will wait until a
separate time though.
Next step on the agenda will be to devise the
configuration code so that we can start configuring
agents.
Modified:
team/mmichelson/agent_experiment/channels/chan_agent2.c
Modified: team/mmichelson/agent_experiment/channels/chan_agent2.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/agent_experiment/channels/chan_agent2.c?view=diff&rev=371649&r1=371648&r2=371649
==============================================================================
--- team/mmichelson/agent_experiment/channels/chan_agent2.c (original)
+++ team/mmichelson/agent_experiment/channels/chan_agent2.c Thu Aug 23 22:41:06 2012
@@ -22,6 +22,10 @@
#include "asterisk/app.h"
#include "asterisk/channel.h"
#include "asterisk/bridging.h"
+
+static int agent_call(struct ast_channel *chan, const char *addr, int timeout);
+static struct ast_channel *agent_request(const char *type, struct ast_format_cap *cap,
+ const struct ast_channel *requestor, const char *addr, int *cause);
enum agent_states {
AGENT_LOGGED_OUT,
@@ -42,6 +46,8 @@
struct ast_bridge *bridge;
/*! The channel the agent logged in with */
struct ast_channel *channel;
+ /*! The original channel tech for the logged-in channel */
+ const struct ast_channel_tech *saved_channel_tech;
};
#define AGENT_BUCKETS 37
@@ -88,6 +94,97 @@
agent_state_fn exit;
};
+static int enter_logged_out(struct agent *agent)
+{
+ const struct ast_channel_tech *to_free;
+ SCOPED_CHANNELLOCK(lock, agent->channel);
+
+ to_free = ast_channel_tech(agent->channel);
+ ast_channel_tech_set(agent->channel, agent->saved_channel_tech);
+ ast_free((void *)to_free);
+
+ agent->saved_channel_tech = NULL;
+ return 0;
+}
+
+static struct ast_channel_tech *get_modified_channel_tech(const struct ast_channel *chan)
+{
+ const struct ast_channel_tech *src = ast_channel_tech(chan);
+ struct ast_channel_tech agent_tech = {
+ .type = src->type,
+ .description = src->description,
+ .capabilities = src->capabilities,
+ .properties = src->properties,
+ .requester = agent_request,
+ .devicestate = src->devicestate,
+ .send_digit_begin = src->send_digit_begin,
+ .send_digit_end = src->send_digit_end,
+ .call = agent_call,
+ /* XXX Need to decorate/override hangup */
+ .hangup = src->hangup,
+ .answer = src->answer,
+ /* XXX May need to decorate read based on agent settings */
+ .read = src->read,
+ .write = src->write,
+ .send_text = src->send_text,
+ .send_image = src->send_image,
+ .send_html = src->send_html,
+ .exception = src->exception,
+ .bridge = src->bridge,
+ .early_bridge = src->early_bridge,
+ .indicate = src->indicate,
+ /* XXX May need to decorate/override fixup (?)*/
+ .fixup = src->fixup,
+ .setoption = src->setoption,
+ .queryoption = src->queryoption,
+ .transfer = src->transfer,
+ .write_video = src->write_video,
+ .write_text = src->write_text,
+ .bridged_channel = src->bridged_channel,
+ .func_channel_read = src->func_channel_read,
+ .func_channel_write = src->func_channel_write,
+ .get_base_channel = src->get_base_channel,
+ .set_base_channel = src->set_base_channel,
+ .cc_callback = src->cc_callback,
+ .pre_call = src->pre_call,
+ };
+ struct ast_channel_tech *copy = ast_calloc(1, sizeof(*copy));
+
+ if (!copy) {
+ return NULL;
+ }
+
+ /* Doing a struct assignment generates a warning because
+ * it violates the constness of copy's fields
+ */
+ memcpy(copy, &agent_tech, sizeof(*copy));
+ return copy;
+}
+
+static int exit_logged_out(struct agent *agent)
+{
+ struct ast_channel_tech *copy;
+ SCOPED_CHANNELLOCK(lock, agent->channel);
+
+ copy = get_modified_channel_tech(agent->channel);
+
+ if (!copy) {
+ return -1;
+ }
+
+ agent->saved_channel_tech = ast_channel_tech(agent->channel);
+ ast_channel_tech_set(agent->channel, copy);
+
+ return 0;
+}
+
+static const struct agent_state LOGGED_OUT = {
+ .name = "LOGGED_OUT",
+ .state = AGENT_LOGGED_OUT,
+ .enter = enter_logged_out,
+ .exit = exit_logged_out,
+};
+
static int enter_logged_in(struct agent *agent)
{
return ast_bridge_impart(agent->bridge, agent->channel, NULL, NULL, 0);
@@ -119,12 +216,14 @@
static int change_agent_state(struct agent *agent, const struct agent_state *new_state)
{
+ ast_debug(1, "Agent %s exiting state %s\n", agent->name, agent->current_state->name);
if (agent->current_state->exit && agent->current_state->exit(agent)) {
return -1;
}
agent->current_state = new_state;
+ ast_debug(1, "Agent %s entering state %s\n", agent->name, agent->current_state->name);
if (agent->current_state->enter && agent->current_state->enter(agent)) {
return -1;
}
@@ -135,6 +234,55 @@
static struct agent *find_agent(const char *name)
{
return ao2_find(agents, name, OBJ_KEY);
+}
+
+static struct ast_channel *agent_request(const char *type, struct ast_format_cap *cap,
+ const struct ast_channel *requestor, const char *addr, int *cause)
+{
+ RAII_VAR(struct agent *, agent, find_agent(addr), ao2_cleanup);
+ SCOPED_AO2LOCK(lock, agent);
+
+ if (!agent) {
+ ast_log(LOG_WARNING, "Unable to allocate agent channel. Could not find agent %s\n",
+ addr);
+ return NULL;
+ }
+
+ /* XXX Presumably, we need to pay attention to cap here so we can determine
+ * if agent->channel is compatible with the requestor.
+ */
+
+ /* agent->channel could be NULL if the agent is logged out. That's fine. */
+ return agent->channel;
+}
+
+static int agent_call(struct ast_channel *chan, const char *addr, int timeout)
+{
+ RAII_VAR(struct agent *, agent, find_agent(addr), ao2_cleanup);
+ SCOPED_AO2LOCK(lock, agent);
+
+ if (!agent) {
+ ast_log(LOG_WARNING, "Unable to call agent channel. Could not find agent %s\n",
+ addr);
+ return -1;
+ }
+
+ if (agent->current_state->state != AGENT_LOGGED_IN) {
+ ast_log(LOG_WARNING, "Agent %s is in a state where he/she cannot be called: %s\n",
+ addr, agent->current_state->name);
+ return -1;
+ }
+
+ if (agent->channel != chan) {
+ ast_log(LOG_WARNING, "Unexpected channel %s given for call to agent %s. Expected %s.\n",
+ ast_channel_name(chan), addr, ast_channel_name(agent->channel));
+ return -1;
+ }
+
+ ast_debug(1, "Agent %s (channel %s) is ringing\n", addr, ast_channel_name(agent->channel));
+
+ /* Everything seems good. Time to change the state to RINGING */
+ change_agent_state(agent, &RINGING);
}
static int login_exec(struct ast_channel *chan, const char *data)
@@ -154,6 +302,8 @@
ast_log(LOG_WARNING, "Attempting to log in already logged-in agent %s\n", data);
return -1;
}
+
+ agent->channel = ast_channel_ref(chan);
if (change_agent_state(agent, &LOGGED_IN)) {
ast_log(LOG_WARNING, "Problem attempting to log agent %s in\n", data);
@@ -169,6 +319,8 @@
* Possible solution: Create an ao2_cond_wait/ao2_cond_signal?
*/
+ agent->channel = ast_channel_unref(chan);
+
return 0;
}
More information about the asterisk-commits
mailing list