2 Setting up Call Queues -- A Tutorial
4 Pardon, but the dialplan in this tutorial will be expressed
5 in AEL, the new Asterisk Extension Language. If you are
6 not used to its syntax, we hope you will find it to some
7 degree intuitive. If not, there are documents explaining
8 its syntax and constructs.
11 ====== Configuring Call Queues
13 First of all, set up call queues in queue.conf
17 =========== queues.conf ===========
18 | ; Cool Digium Queues |
20 | persistentmembers = yes |
22 | ; General sales queue |
28 | leavewhenempty=strict |
30 | ; Customer service queue |
33 | context=customerservice |
36 | leavewhenempty=strict |
38 | ; Support dispatch queue |
39 | [support-dispatch] |
44 | leavewhenempty=strict |
45 ===================================
47 In the above, we have defined 3 separate calling queues:
48 sales-general, customerservice, and support-dispatch.
50 Please note that the sales-general queue specifies a
51 context of "sales", and that customerservice specifies the
52 context of "customerservice", and the support-dispatch
53 queue specifies the context "dispatch". These three
54 contexts must be defined somewhere in your dialplan.
55 We will show them after the main menu below.
57 <verbage explaining options above>
58 In the [general] section, specifying the persistentmembers=yes,
59 will cause the agent lists to be stored in astdb, and
62 The strategy=ringall will cause all agents to be dialed
63 together, the first to answer is then assigned the incoming
66 "joinempty" set to "strict" will keep incoming callers from
67 being placed in queues where there are no agents to take calls.
68 The Queue() application will return, and the dial plan can
69 determine what to do next.
71 If there are calls queued, and the last agent logs out, the
72 remaining incoming callers will immediately be removed from
73 the queue, and the Queue() call will return, IF the "leavewhenempty" is
77 =====================================
78 | Routing incoming Calls to Queues |
79 =====================================
82 Then in extensions.ael, you can do these things:
84 ================ The Main Menu
86 At Digium, incoming callers are sent to the "mainmenu" context, where they
87 are greeted, and directed to the numbers they choose...
96 0 => goto dispatch|s|1;
98 3 => goto customerservice|s|1;
99 4 => goto dispatch|s|1;
107 Background(digium/ThankYouForCallingDigium);
108 Background(digium/YourOpenSourceTelecommunicationsSupplier);
111 Set(attempts=$[${attempts} + 1]);
112 Background(digium/IfYouKnowYourPartysExtensionYouMayDialItAtAnyTime);
114 Background(digium/Otherwise);
116 Background(digium/ForSalesPleasePress2);
118 Background(digium/ForCustomerServicePleasePress3);
120 Background(digium/ForAllOtherDepartmentsPleasePress4);
122 Background(digium/ToSpeakWithAnOperatorPleasePress0AtAnyTime);
123 if( ${attempts} < 2 ) {
125 Background(digium/ToHearTheseOptionsRepeatedPleaseHold);
128 if( ${attempts} < 2 ) goto repeat;
129 Background(digium/YouHaveMadeNoSelection);
130 Background(digium/ThisCallWillBeEnded);
137 ============= The Contexts referenced from the queues.conf file
143 0 => goto dispatch|s|1;
144 8 => Voicemail(${SALESVM});
149 Background(digium/ThankYouForContactingTheDigiumSalesDepartment);
151 Background(digium/PleaseHoldAndYourCallWillBeAnsweredByOurNextAvailableSalesRepresentative);
153 Background(digium/AtAnyTimeYouMayPress0ToSpeakWithAnOperatorOr8ToLeaveAMessage);
154 Set(CALLERID(name)=Sales);
155 Queue(sales-general|t);
156 Set(CALLERID(name)=EmptySalQ);
163 Please note that there is only one attempt to queue a call in the sales queue. All sales agents that
164 are logged in will be rung.
167 context customerservice {
170 SetCIDName(CSVTrans);
173 8 => Voicemail(${CUSTSERVVM});
178 Background(digium/ThankYouForCallingDigiumCustomerService);
181 Background(digium/PleaseWaitForTheNextAvailableCustomerServiceRepresentative);
183 Background(digium/AtAnyTimeYouMayPress0ToSpeakWithAnOperatorOr8ToLeaveAMessage);
184 Set(CALLERID(name)=Cust Svc);
185 Set(QUEUE_MAX_PENALTY=10);
186 Queue(customerservice|t);
187 Set(QUEUE_MAX_PENALTY=0);
188 Queue(customerservice|t);
189 Set(CALLERID(name)=EmptyCSVQ);
191 Background(digium/NoCustomerServiceRepresentativesAreAvailableAtThisTime);
192 Background(digium/PleaseLeaveAMessageInTheCustomerServiceVoiceMailBox);
193 Voicemail(${CUSTSERVVM});
199 Note that calls coming into customerservice will first be try to queue
200 calls to those agents with a QUEUE_MAX_PENALTY of 10, and if none are available,
201 then all agents are rung.
210 Background(digium/ThankYouForCallingDigium);
212 Background(digium/YourCallWillBeAnsweredByOurNextAvailableOperator);
213 Background(digium/PleaseHold);
214 Set(QUEUE_MAX_PENALTY=10);
216 Set(QUEUE_MAX_PENALTY=20);
218 Set(QUEUE_MAX_PENALTY=0);
220 Background(digium/NoOneIsAvailableToTakeYourCall);
221 Background(digium/PleaseLeaveAMessageInOurGeneralVoiceMailBox);
222 Voicemail(${DISPATCHVM});
228 And in the dispatch context, first agents of priority 10 are tried, then
229 20, and if none are available, all agents are tried.
231 Notice that a common pattern is followed in each of the three queue contexts:
233 First, you set QUEUE_MAX_PENALTY to a value, then you call
234 Queue(<queue-name>,option,... (see the documentation for the Queue application));
236 In the above, note that the "t" option is specified, and this allows the
237 agent picking up the incoming call the luxury of transferring the call to
240 The purpose of specifying the QUEUE_MAX_PENALTY is to develop a set of priorities
241 amongst agents. By the above usage, agents with lower number priorities will
242 be given the calls first, and then, if no-one picks up the call, the QUEUE_MAX_PENALTY
243 will be incremented, and the queue tried again. Hopefully, along the line, someone
244 will pick up the call, and the Queue application will end with a hangup.
246 The final attempt to queue in most of our examples sets the QUEUE_MAX_PENALTY
247 to zero, which means to try all available agents.
250 =========================================
251 | Assigning agents to Queues |
252 =========================================
254 In this example dialplan, we want to be able to add and remove agents to
255 handle incoming calls, as they feel they are available. As they log in,
256 they are added to the queue's agent list, and as they log out, they are
257 removed. If no agents are available, the queue command will terminate, and
258 it is the duty of the dialplan to do something appropriate, be it sending
259 the incoming caller to voicemail, or trying the queue again with a higher
262 Because a single agent can make themselves available to more than one queue,
263 the process of joining multiple queues can be handled automatically by the
267 ================= Agents Log In and Out
270 context queues-loginout
274 Read(AGENT_NUMBER,agent-enternum);
275 VMAuthenticate(${AGENT_NUMBER}@default,s);
276 Set(queue-announce-success=1);
277 goto queues-manip,I${AGENT_NUMBER},1;
282 Read(AGENT_NUMBER,agent-enternum);
283 Set(queue-announce-success=1);
284 goto queues-manip,O${AGENT_NUMBER},1;
289 In the above contexts, the agents dial 6092 to log into their queues,
290 and they dial 6093 to log out of their queues. The agent is prompted
291 for their agent number, and if they are logging in, their passcode,
292 and then they are transferred to the proper extension in the
293 queues-manip context. The queues-manip context does all the
297 context queues-manip {
301 &queue-addremove(dispatch,10);
307 &queue-addremove(dispatch,20);
313 &queue-addremove(sales-general,10);
314 &queue-addremove(customerservice,20);
315 &queue-addremove(dispatch,30);
321 &queue-addremove(sales-general,20);
322 &queue-addremove(customerservice,30);
323 &queue-addremove(dispatch,30);
328 In the above extensions, note that the queue-addremove macro is used
329 to actually add or remove the agent from the applicable queue,
330 with the applicable priority level. Note that agents with a
331 priority level of 10 will be called before agents with levels
334 In the above example, Raquel will be dialed first in the dispatch
335 queue, if she has logged in. If she is not, then the second call of
336 Queue() with priority of 20 will dial Brittanica if she is present,
337 otherwise the third call of Queue() with MAX_PENALTY of 0 will
338 dial Rock and Saline simultaneously.
340 Also note that Rock will be among the first to be called in the sales-general
341 queue, and among the last in the dispatch queue. As you can see in
342 main menu, the callerID is set in the main menu so they can tell
343 which queue incoming calls are coming from.
345 The call to queue-success() gives some feedback to the agent
346 as they log in and out, that the process has completed.
348 macro queue-success()
350 if( ${queue-announce-success} > 0 )
352 switch(${MACRO_EXTEN:0:1})
355 Playback(agent-loginok);
359 Playback(agent-loggedoff);
367 The queue-addremove macro is defined in this manner:
369 macro queue-addremove(queuename,penalty)
371 switch(${MACRO_EXTEN:0:1})
374 AddQueueMember(${queuename},Local/${MACRO_EXTEN:1}@agents,${penalty});
377 RemoveQueueMember(${queuename},Local/${MACRO_EXTEN:1}@agents);
380 PauseQueueMember(${queuename},Local/${MACRO_EXTEN:1}@agents);
383 UnpauseQueueMember(${queuename},Local/${MACRO_EXTEN:1}@agents);
391 Basically, it uses the first character of the MACRO_EXTEN variable, to determine the
392 proper actions to take. In the above dial plan code, only the cases I or O are used,
393 which correspond to the Login and Logout actions.
396 =======================================================
397 | Controlling The Way Queues Call the Agents |
398 =======================================================
400 Notice in the above, that the commands to manipulate agents in queues have
401 "@agents" in their arguments. This is a reference to the agents context:
405 // General sales queue
408 Set(QUEUE_MAX_PENALTY=10);
409 Queue(sales-general|t);
410 Set(QUEUE_MAX_PENALTY=0);
411 Queue(sales-general|t);
412 Set(CALLERID(name)=EmptySalQ);
415 // Customer Service queue
418 Set(QUEUE_MAX_PENALTY=10);
419 Queue(customerservice|t);
420 Set(QUEUE_MAX_PENALTY=0);
421 Queue(customerservice|t);
422 Set(CALLERID(name)=EMptyCSVQ);
427 Dial(iax2/sweatshop/9456@from-ecstacy);
429 Set(CALLERID(name)=EmptySupQ);
430 Set(QUEUE_MAX_PENALTY=10);
431 Queue(support-dispatch,t);
432 Set(QUEUE_MAX_PENALTY=20);
433 Queue(support-dispatch,t);
434 Set(QUEUE_MAX_PENALTY=0); // means no max
435 Queue(support-dispatch,t);
438 6121 => &callagent(${RAQUEL});
439 6165 => &callagent(${SPEARS});
440 6170 => &callagent(${ROCK});
441 6070 => &callagent(${SALINE});
444 In the above, the variables ${RAQUEL}, etc stand for
445 actual devices to ring that person's
448 The 8010, 8011, and 8013 extensions are purely for transferring
449 incoming callers to queues. For instance, a customer service
450 agent might want to transfer the caller to talk to sales. The
451 agent only has to transfer to extension 8010, in this case.
453 Here is the callagent macro, note that if a person in the
454 queue is called, but does not answer, then they are automatically
455 removed from the queue.
457 macro callagent(device)
459 if( ${GROUP_COUNT(${MACRO_EXTEN}@agents)}=0 )
461 Set(OUTBOUND_GROUP=${MACRO_EXTEN}@agents);
462 Dial(${device}|300|t);
463 switch(${DIALSTATUS})
469 Set(queue-announce-success=0);
470 goto queues-manip|O${MACRO_EXTEN}|1;
482 In the callagent macro above, the ${MACRO_EXTEN} will
483 be 6121, or 6165, etc, which is the extension of the agent.
485 The use of the GROUP_COUNT, and OUTBOUND_GROUP follow this line
486 of thinking. Incoming calls can be queued to ring all agents in the
487 current priority. If some of those agents are already talking, they
488 would get bothersome call-waiting tones. To avoid this inconvenience,
489 when an agent gets a call, the OUTBOUND_GROUP assigns that
490 conversation to the group specified, for instance 6171@agents.
491 The ${GROUP_COUNT()} variable on a subsequent call should return
492 "1" for that group. If GROUP_COUNT returns 1, then the busy()
493 is returned without actually trying to dial the agent.
495 ================ Pre Acknowledgement Message
497 If you would like to have a pre acknowledge message with option to reject the message
498 you can use the following dialplan Macro as a base with the 'M' dial argument.
502 exten=>s,2,Read(ACCEPT|screen-callee-options|1)
503 exten=>s,3,Gotoif($[${ACCEPT} = 1] ?50)
504 exten=>s,4,Gotoif($[${ACCEPT} = 2] ?30)
505 exten=>s,5,Gotoif($[${ACCEPT} = 3] ?40)
506 exten=>s,6,Gotoif($[${ACCEPT} = 4] ?30:30)
507 exten=>s,30,Set(MACRO_RESULT=CONTINUE)
508 exten=>s,40,Read(TEXTEN|custom/screen-exten|)
509 exten=>s,41,Gotoif($[${LEN(${TEXTEN})} = 3]?42:45)
510 exten=>s,42,Set(MACRO_RESULT=GOTO:from-internal^${TEXTEN}^1)
511 exten=>s,45,Gotoif($[${TEXTEN} = 0] ?46:4)
512 exten=>s,46,Set(MACRO_RESULT=CONTINUE)
513 exten=>s,50,Playback(after-the-tone)
514 exten=>s,51,Playback(connected)
515 exten=>s,52,Playback(beep)
517 ================ Caveats
519 In the above examples, some of the possible error checking has been omitted,
520 to reduce clutter and make the examples clearer.