[asterisk-commits] rmudgett: branch rmudgett/bridge_phase r392142 - /team/rmudgett/bridge_phase/...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Jun 18 11:13:33 CDT 2013
Author: rmudgett
Date: Tue Jun 18 11:13:31 2013
New Revision: 392142
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=392142
Log:
* Add initial agent_hold bridge subclass code.
* Removed endcall and enddtmf option code in favor of using the normal
bridge disconnect DTMF feature.
* Removed max_login_tries override value since it will be used
immediately.
Modified:
team/rmudgett/bridge_phase/apps/app_agent_pool.c
Modified: team/rmudgett/bridge_phase/apps/app_agent_pool.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/apps/app_agent_pool.c?view=diff&rev=392142&r1=392141&r2=392142
==============================================================================
--- team/rmudgett/bridge_phase/apps/app_agent_pool.c (original)
+++ team/rmudgett/bridge_phase/apps/app_agent_pool.c Tue Jun 18 11:13:31 2013
@@ -41,7 +41,10 @@
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/channel.h"
+#include "asterisk/bridging.h"
+#include "asterisk/bridging_basic.h"
#include "asterisk/config_options.h"
+#include "asterisk/features_config.h"
#include "asterisk/astobj2.h"
#include "asterisk/stringfields.h"
@@ -147,6 +150,8 @@
#define AST_MAX_BUF 256
+/* BUGBUG Document in CHANGES that endcall and enddtmf are going away in favor of the normal bridge disconnect feature. Override using FEATUREMAP. */
+
/*! Agent config parameters. */
struct agent_cfg {
AST_DECLARE_STRING_FIELDS(
@@ -163,12 +168,6 @@
* \note The channel variable AGENTACCEPTDTMF overrides on login.
*/
AST_STRING_FIELD(dtmf_accept);
- /*!
- * \brief DTMF string for an agent to end a call.
- *
- * \note The channel variable AGENTENDDTMF overrides on login.
- */
- AST_STRING_FIELD(dtmf_end);
/*! Beep sound file to use. Alert the agent a call is waiting. */
AST_STRING_FIELD(beep_sound);
/*! MOH class to use while agent waiting for call. */
@@ -206,8 +205,6 @@
* \note The channel variable AGENTACKCALL overrides on login.
*/
int ack_call;
- /*! \brief TRUE if agent can use DTMF to end a call. */
- int end_call;
/*! TRUE if agent calls are recorded. */
int record_agent_calls;
};
@@ -479,9 +476,6 @@
aco_option_register(&cfg_info, "autologoff", ACO_EXACT, agent_types, "0", OPT_UINT_T, 0, FLDSET(struct agent_cfg, auto_logoff));
aco_option_register(&cfg_info, "ackcall", ACO_EXACT, agent_types, "no", OPT_BOOL_T, 1, FLDSET(struct agent_cfg, ack_call));
aco_option_register(&cfg_info, "acceptdtmf", ACO_EXACT, agent_types, "#", OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, dtmf_accept));
-/* BUGBUG endcall and enddtmf need to go away in favor of using the normal bridge disconnect DTMF feature. */
- aco_option_register(&cfg_info, "endcall", ACO_EXACT, agent_types, "yes", OPT_BOOL_T, 1, FLDSET(struct agent_cfg, end_call));
- aco_option_register(&cfg_info, "enddtmf", ACO_EXACT, agent_types, "*", OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, dtmf_end));
aco_option_register(&cfg_info, "wrapuptime", ACO_EXACT, agent_types, "0", OPT_UINT_T, 0, FLDSET(struct agent_cfg, wrapup_time));
aco_option_register(&cfg_info, "musiconhold", ACO_EXACT, agent_types, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, moh));
aco_option_register_custom(&cfg_info, "group", ACO_EXACT, agent_types, "", agent_group_handler, 0);
@@ -508,12 +502,9 @@
/*! Agent config option override flags. */
enum agent_override_flags {
AGENT_FLAG_ACK_CALL = (1 << 0),
- AGENT_FLAG_END_CALL = (1 << 1),
- AGENT_FLAG_DTMF_ACCEPT = (1 << 2),
- AGENT_FLAG_DTMF_END = (1 << 3),
- AGENT_FLAG_AUTO_LOGOFF = (1 << 4),
- AGENT_FLAG_WRAPUP_TIME = (1 << 5),
- AGENT_FLAG_MAX_LOGIN_TRIES = (1 << 6),
+ AGENT_FLAG_DTMF_ACCEPT = (1 << 1),
+ AGENT_FLAG_AUTO_LOGOFF = (1 << 2),
+ AGENT_FLAG_WRAPUP_TIME = (1 << 3),
};
/*! \brief Structure representing an agent. */
@@ -523,21 +514,15 @@
AST_STRING_FIELD(username);
/*! Login override DTMF string for an agent to accept a call. */
AST_STRING_FIELD(override_dtmf_accept);
- /*! Login override DTMF string for an agent to end a call. */
- AST_STRING_FIELD(override_dtmf_end);
);
/*! Flags show if settings were overridden by channel vars. */
unsigned int flags;
- /*! Login override number of failed login attempts allowed. */
- unsigned int override_max_login_tries;
/*! Login override number of seconds for agent to ack a call before being logged off. */
unsigned int override_auto_logoff;
/*! Login override time after a call in ms before the agent can get a new call. */
unsigned int override_wrapup_time;
/*! Login override if agent needs to ack a call to accept it. */
unsigned int override_ack_call:1;
- /*! Login override if agent can use DTMF to end a call. */
- unsigned int override_end_call:1;
/*! TRUE if the agent is requested to logoff when the current call ends. */
unsigned int deferred_logoff:1;
@@ -853,6 +838,132 @@
}
agent_unlock(agent);
return 0;
+}
+
+/*! Agent holding bridge instance. */
+static struct ast_bridge *agent_holding;
+
+static int bridge_agent_hold_ack(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+ /*! \todo BUGBUG bridge_agent_hold_ack() not written */
+ return 0;
+}
+
+static int bridge_agent_hold_disconnect(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+ ast_softhangup(bridge_channel->chan, AST_SOFTHANGUP_EXPLICIT);
+ ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief ast_bridge agent_hold push method.
+ * \since 12.0.0
+ *
+ * \param self Bridge to operate upon.
+ * \param bridge_channel Bridge channel to push.
+ * \param swap Bridge channel to swap places with if not NULL.
+ *
+ * \note On entry, self is already locked.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+static int bridge_agent_hold_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
+{
+ int res = 0;
+ char dtmf[AST_FEATURE_MAX_LEN];
+ struct ast_channel *chan;
+ struct ast_flags *flags;
+ const char *moh_class;
+ RAII_VAR(struct agent_pvt *, agent, NULL, ao2_cleanup);
+
+ chan = bridge_channel->chan;
+
+ agent = ao2_find(agents, swap ? swap->chan : chan, 0);
+ if (!agent) {
+ /* Could not find the agent. */
+ return -1;
+ }
+
+/*! \todo BUGBUG bridge_agent_hold_push() needs one second heartbeat interval hook added. */
+
+ /* Add DTMF disconnect hook. */
+ dtmf[0] = '\0';
+ ast_channel_lock(chan);
+ flags = ast_bridge_features_ds_get(chan);
+ if (flags && ast_test_flag(flags, AST_FEATURE_DISCONNECT)) {
+ ast_get_builtin_feature(chan, "disconnect", dtmf, sizeof(dtmf));
+ }
+ ast_channel_unlock(chan);
+ if (!ast_strlen_zero(dtmf)) {
+ res |= ast_bridge_dtmf_hook(bridge_channel->features, dtmf,
+ bridge_agent_hold_disconnect, NULL, NULL, AST_BRIDGE_HOOK_REMOVE_ON_PULL);
+ }
+
+ agent_lock(agent);
+ moh_class = ast_strdupa(agent->cfg->moh);
+
+ /* Add DTMF acknowledge hook. */
+ dtmf[0] = '\0';
+ if (ast_test_flag(agent, AGENT_FLAG_ACK_CALL) ? agent->override_ack_call : agent->cfg->ack_call) {
+ const char *dtmf_accept;
+
+ dtmf_accept = ast_test_flag(agent, AGENT_FLAG_DTMF_ACCEPT)
+ ? agent->override_dtmf_accept : agent->cfg->dtmf_accept;
+ ast_copy_string(dtmf, dtmf_accept, sizeof(dtmf));
+ }
+ agent_unlock(agent);
+ if (!ast_strlen_zero(dtmf)) {
+ res |= ast_bridge_dtmf_hook(bridge_channel->features, dtmf,
+ bridge_agent_hold_ack, NULL, NULL, AST_BRIDGE_HOOK_REMOVE_ON_PULL);
+ }
+
+ /* Setup agent entertainment */
+ res |= ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "musiconhold");
+ res |= ast_channel_set_bridge_role_option(chan, "holding_participant", "moh_class", moh_class);
+
+ if (res) {
+ return -1;
+ }
+
+ res = ast_bridge_base_v_table.push(self, bridge_channel, swap);
+ if (res) {
+ return -1;
+ }
+
+ if (swap) {
+/*! \todo BUGBUG bridge_agent_hold_push() needs swap after bridge callback added. */
+ agent_lock(agent);
+ ast_channel_unref(agent->logged);
+ agent->logged = ast_channel_ref(chan);
+ agent->we_joined = 0;
+ agent_unlock(agent);
+ }
+ return 0;
+}
+
+static struct ast_bridge_methods bridge_agent_hold_v_table;
+
+static struct ast_bridge *bridge_agent_hold_new(void)
+{
+ struct ast_bridge *bridge;
+
+ bridge = ast_bridge_alloc(sizeof(struct ast_bridge), &bridge_agent_hold_v_table);
+ bridge = ast_bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_HOLDING,
+ AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
+ | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_TRANSFER_PROHIBITED);
+ bridge = ast_bridge_register(bridge);
+ return bridge;
+}
+
+static void bridging_init_agent_hold(void)
+{
+ /* Setup bridge agent_hold subclass v_table. */
+ bridge_agent_hold_v_table = ast_bridge_base_v_table;
+ bridge_agent_hold_v_table.name = "agent_hold";
+ bridge_agent_hold_v_table.push = bridge_agent_hold_push;
}
static int agent_function_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
@@ -1318,6 +1429,13 @@
ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents));
ast_devstate_prov_del("Agent");
+
+ /* Destroy agent holding bridge. */
+ if (agent_holding) {
+ ast_bridge_destroy(agent_holding);
+ agent_holding = NULL;
+ }
+
destroy_config();
ao2_ref(agents, -1);
agents = NULL;
@@ -1340,6 +1458,14 @@
return AST_MODULE_LOAD_DECLINE;
}
+ /* Create agent holding bridge. */
+ bridging_init_agent_hold();
+ agent_holding = bridge_agent_hold_new();
+ if (!agent_holding) {
+ unload_module();
+ return AST_MODULE_LOAD_FAILURE;
+ }
+
/* BUGBUG Agent:agent-id device state not written. */
/* Setup to provide Agent:agent-id device state. */
res |= ast_devstate_prov_add("Agent", agent_pvt_devstate_get);
@@ -1354,7 +1480,6 @@
/* Dialplan Functions */
res |= ast_custom_function_register(&agent_function);
-/* BUGBUG Agent holding bridge subclass not written. */
/* BUGBUG bridge channel swap hook not written. */
/* BUGBUG AgentLogin dialplan application not written. */
/* BUGBUG AgentRequest dialplan application not written. */
More information about the asterisk-commits
mailing list