The move from chan_agent to app_agent_pool
The idea behind chan_agent was simple. The agent channel created by chan_agent acts as a proxy for the corresponding “real” channel which is logged in as the agent. When the call connected to the agent channel is done, the proxied “real” channel goes back to waiting for the next call.
Unfortunately, in versions of Asterisk leading up to 12, the implementation of the agent channel within Asterisk required exposing unexpected internal operational details. When the Asterisk’s architecture was updated to provide better APIs, a side effect was the inability to support chan_agent ‘s proxy mechanism. Making it work under the new architecture would have required re-breaking the very things we were fixing! Avoiding the surprises an agent channel requires, starting in Asterisk 12, the app_agent_pool application replaced chan_agent . The goal of app_agent_pool is to provide the essential functionality of chan_agent without exposing unexpected internal details to the user.
The idea behind the agent pool is similar to chan_agent . A call requests connection to the channel logged in as the agent. When the call is done, the channel logged in as the agent goes back to waiting for the next call. The agent pool uses the new AgentRequest application. AgentRequest takes the role the Dial application has with chan_agent . AgentRequest bridges the requesting channel with the channel logged in as the agent.
A secondary goal when writing app_agent_pool was to support as many configuration options as was reasonable from chan_agent . This makes converting to app_agent_pool as easy as possible. Options that were removed either were no longer supported by chan_agent or could no longer be feasibly supported in Asterisk 12. In some cases, options were removed because there was a generic means to accomplish the same thing. For example, endcall and enddtmf were redundant with CHANNEL(dtmf-features) when applied to the channel logged in as the agent. As another example, the authentication options were removed as authentication is already provided through the AgentLogin application.
Setting up an agent pool
First we need to configure agents in the agents.conf file. Assuming you want the defaults documented in the agents.conf.sample file, you just need to create an empty section for each agent named. If you need other settings you can create a config file template and have each agent section apply that template. Below I have created two agents with agent-id’s of 101 and 102 . These agents use the my_agents template that requires the agent to acknowledge the incoming call by pressing ‘#’ within 20 seconds.
[my_agents](!) ackcall=yes acceptdtmf=# autologoff=20 [101](my_agents) fullname=Mark Spencer [102](my_agents) fullname=Will Meadows
Note: The agent-id in chan_agent and app_agent_pool does not have to be numeric. It can be whatever name you want to give the agent. However, it is best to just stick with numeric characters to avoid any limitations in the contexts where you need to use the agent-id.
Next we need some dialplan in extensions.conf for the agents to login to the agent pool and some dialplan to request the agents. The dialplan shown below allows the logged in agent to disconnect from the incoming call and sets what the agent sees on his phone between calls. Other than those two additions, the dialplan is the minimum needed to login and request the agent. Both AgentLogin and AgentRequest applications will continue in the dialplan if an error happens. You can determine why the applications continued in the dialplan by testing the AGENT_STATUS channel variable. See the Asterisk wiki for documentation of AgentLogin and AgentRequest .
[agent_login] exten = _XXX,1,NoOp() same = n,Set(CHANNEL(dtmf-features)=H) same = n,Set(CONNECTEDLINE(all)="Awaiting call" <${EXTEN}>) same = n,Answer() same = n,AgentLogin(${EXTEN}) same = n,Hangup() [agents] exten = _XXX,1,NoOp() same = n,AgentRequest(${EXTEN}) same = n,Congestion()
Finally we need to configure the queue members in queues.conf for the queue to send calls to the agents. As you can see, the queue members have to be Local channel members that monitor the agent’s custom device state “Agent:<agent-id> “. I am only showing the lines needed to define queue members and not a complete queue definition. Setting up queues is well documented in Asterisk: The Definitive Guide and other places.
; syntax: member = interface,[,penalty][,membername][,state_interface][,ringinuse] member = Local/101@agents,,Wall Flower,Agent:101 member = Local/102@agents,,Garden Wall,Agent:102
For comparison, the following are equivalent configurations for chan_agent :
[agents] endcall=yes enddtmf=* ackcall=yes acceptdtmf=# autologoff=20 agent=101,,Mark Spencer agent=102,,Will Meadows
[agent_login] exten = _XXX,1,NoOp() same = n,Answer() same = n,AgentLogin(${EXTEN}) same = n,Hangup() [agents] exten = _XXX,1,NoOp() same = n,Dial(Agent/${EXTEN},30) same = n,Congestion()
; syntax: member = interface,[,penalty][,membername][,state_interface][,ringinuse] member = Local/101@agents,,Wall Flower,Agent/101 member = Local/102@agents,,Garden Wall,Agent/102
Agents: the future
The Asterisk project does not make major backwards incompatible changes lightly. Despite major architectural improvements taken during the Asterisk 12 development, chan_agent was one of the very few major pieces of removed functionality. Even so, we hope that this shows that an alternative in the agent pool is readily available, and still allows for the use case of having a permanently logged in call queue agent to be met in Asterisk.
3 Responses
Hi,
Currently we are using Asterisk 11, which uses endcall=no & enddtmf= in agent.conf. But we couldn’t find these options in Asterisk 13 Version. Can you please help me out to fix this issue.
This post helped me a lot. Now, I have my Laravel app and websocket set up with an agent permanently connected to my app. Thank you.