Prerequisite: confidence with Linux shell, know how to install and configure Asterisk 13 or later, know SIP protocol.
I have a VoIP context based on OpenSIPS as B2B and an Asterisk box for multimedia services, like IVR, Voicemail and Queues.
For almost all of our offices, traditional configuration for Queues wan enough to satisfy customers relationship needs. But for one, there was the need to configure dynamic agents for queues because they decide day-per-day which had to respond to customers calls. So, my Asterisk box version is 13 and i can’t benefit on commands like AgentCallBackLogin, deprecated since 1.6, i decide to try using dialplan to create a way to add and remove agents from all queues available on my system.
Just to introduce my context and help you with this example, for some reasons (remember: i use OpenSIPS as SIP router, not Asterisk itself !) i decide to define queue agents as “MemberConnector”:
In extensions.conf i have:
; ====================================================================== ; QUEUES Member Agent ; ====================================================================== [MemberConnector] exten => _[A-Za-z0-9].,1,Verbose(2,Connecting ${CALLERID(all)} to Agent at ${EXTEN}) same => n,Set(QueueMember=${FILTER(A-Za-z0-9\-,${EXTEN})}) same => n,Set(Technology=${CUT(QueueMember,-,1)}) same => n,Set(Device=${CUT(QueueMember,-,2)}) same => n,Noop("MemberConnector: calling queue member ${Technology}/voip-trunk/${Device}") same => n,Dial(${Technology}/voip-trunk/${Device},30) same => n,Hangup()
Note that “voip-trunk” must be defined in sip.conf as, obviously, the sip trunk that interconnects OpenSIPS with Asterisk. Also in extensions.conf, i need to define all my IVR as an introductory system for all my queues (do announcements, filter by date-time, change asserted identity and so on…). In the following few lines, how i define my test queue ‘5599’:
; ==== IVR 5599 - Test queue [ivr-5599] exten => s,1,Noop("Test queue from ${CALLERID(num)}") exten => s,n,SipAddHeader(P-Asserted-Identity: "Test queue - ${CALLERID(num)}" <sip:${CALLERID(num)}>) exten => s,n,Queue(queue-5599) exten => s,n,Hangup
Now it’s time to define our queue in queues.conf as follow:
[queue-5599] # 5599 Test Queue music = queue-default strategy = ringall timeout = 15 wrapuptime = 10 announce-frequency = 30 announce-holdtime = yes joinempty = yes
I define an empty queue because all its agents are defined dynamically by users itself, using its own phone and calling *40[queue number] to be added as Agent and *41[queue number] to log out. So, in default context (or wherever you choose) inside extensions.conf i add:
exten => _*40XXXX,1,Answer exten => _*40XXXX,n,Set(AGENTID=${CALLERID(num)}) exten => _*40XXXX,n,Set(QUEUEID=${EXTEN:3}) exten => _*40XXXX,n,Noop("Add Member ${AGENTID} to Queue ${QUEUEID}") exten => _*40XXXX,n,AddQueueMember(queue-${QUEUEID},Local/SIP-${AGENTID}@MemberConnector/n,0) exten => _*40XXXX,n,Goto(ret-${AQMSTATUS}) exten => _*40XXXX,n(ret-ADDED),Playback(msg/queue-added) exten => _*40XXXX,n(ret-ADDED),Hangup() exten => _*40XXXX,n(ret-MEMBERALREADY),Playback(msg/queue-alreadyin) exten => _*40XXXX,n(ret-MEMBERALREADY),Hangup() exten => _*40XXXX,n(ret-NOSUCHQUEUE),Playback(msg/queue-iderror) exten => _*40XXXX,n,Hangup()
and to be removed as Agent:
exten => _*41XXXX,1,Answer exten => _*41XXXX,n,Set(AGENTID=${CALLERID(num)}) exten => _*41XXXX,n,Set(QUEUEID=${EXTEN:3}) exten => _*41XXXX,n,Noop("Remove Member ${AGENTID} to Queue ${QUEUEID}") exten => _*41XXXX,n,RemoveQueueMember(queue-${QUEUEID},Local/SIP-${AGENTID}@MemberConnector/n) exten => _*41XXXX,n,Goto(ret-${RQMSTATUS}) exten => _*41XXXX,n(ret-REMOVED),Playback(msg/queue-removed) exten => _*41XXXX,n(ret-REMOVED),Hangup() exten => _*41XXXX,n(ret-NOTINQUEUE),Playback(msg/queue-notin) exten => _*41XXXX,n(ret-NOTINQUEUE),Hangup() exten => _*41XXXX,n(ret-NOSUCHQUEUE),Playback(msg/queue-iderror) exten => _*41XXXX,n,Hangup()
Playback of audio files just to inform users that your request was successful or not: you can omit, if you don’t need to provide any feedback.
Just to refresh memory, _*40XXXX is an Asterisk dialplan pattern that match *40 followed by 4 digits (XXXX: our queue id), so users simply have to call certain number to be added or removed from queue immediately.
Back to the example, in the second and third line i set AGENTID and QUEUEID variables, that will be used as arguments for AddQueueMember command. Return code was used on Goto to jump to the corresponding label and say if adding was successful or not. The second part of the example is very similar to first, except for RemoveQueueMember function and different ret codes.
Connecting to Asterisk CLI (asterisk -r):
asterisk*CLI> queue show queue-5599 queue-5599 has 0 calls (max unlimited) in 'ringall' strategy (0s holdtime, 0s talktime), W:0, C:0, A:1, SL:0.0% within 0s No Members No Callers
And now, i call #405599 from my VoIP terminal, registered as 5002:
asterisk*CLI> queue show queue-5599 queue-5599 has 0 calls (max unlimited) in 'ringall' strategy (0s holdtime, 0s talktime), W:0, C:0, A:1, SL:0.0% within 0s Members: Local/SIP-5002@MemberConnector/n (ringinuse enabled) (dynamic) (Not in use) has taken no calls yet No Callers
At this point, when someone call on 5599 queue, my VoIP phone (5002) will ring. To disconnect from the queue, simply call #415599.
That’s all !
Feel free to ask questions or suggestions to improve my example.
2 comments
ciao, molto interessante il tuo articolo. Volevo chiederti però se la funzione che descrivi aggiunge gli utenti come “dinamici” o “statici” o se c’è possibilità di scegliere. Questo perchè ho un problema con delle code e gli agenti dinamici. Ho la necessità che gli agenti possano effettuare il login e logout alla coda, ma anche che squillino con un ordine preimpostato, cosa che sembra impossibile in asterisk se non con il parametro penalty che però non è facilmente gestibile e la tua mi sembrava una buona strada per controllare gli utenti loggati ed inserirli come agenti statici nella coda (ammesso che sia possibile), grazie!
Buonasera Vladi, con questa funzione è possibile aggiungere agenti dinamici con la medesima priorità (o penalità), che è inferiore agli agenti statici di una coda. Secondo il manuale di Asterisk, è possibile indicare singolarmente la priorità dell’agente da aggiungere:
AddQueueMember(queuename,[interface,[penalty,[options,[membername,[stateinterface]]]]])
che quindi puoi controllare magari con una tabella MySQL oppure direttamente in fase di aggiunta, aggiungendo un parametro.
Buona fortuna !