WWW.DUMAIS.IO

ACD Server with resiprocateLast edited on Jul 9, 2012

This is another project I've been working on using resiprocate. I'm using this ACD server with Asterisk. All devices, including the ACD server are talking with asterisk. The ACD server registers with asterisk just like any other phone would. When my gateway (FXO) sends a call to asterisk, asterisk routes it to the ACD server. When an agent logs on the ACD, the ACD server checks the contact header and establishes a presence subscription to that contact. In my case, this is always going to be an extension on Asterisk.

Features

Feature list:

  • multiple queues
  • Agents can be members of many queues
  • Queues are called with AOR (i.e: telemarkerqueue@acdserver.local)
  • most-idle agent routing (MIA)
  • redirect on no answer (to next MIA, with configurable timeout)
  • music while waiting
  • welcome message + periodic announcements while in queue
  • supports g.711 uLaw only
  • supports SIP info only for DTMF
  • REST api with JSON formatted responses
    • list of queues and calls with state, source/destination etc.
    • list of agents with state, idle time etc.

Unfortunately, there is too much I want to do so here is the list of other features I would like to add when I find the time

  • Adding agents & queues dynamically without restart
  • Ringall queues
  • Calling an agent directly (agent@acdserver.local)
  • Force a call out of the queue using REST api (unattended transfer to any device on same call server).
  • Use one thread only for all RTP sessions
  • Prevent agent to log on more than one phone and more than one agent on same phone whatever codec I use)

Using it

Here is a typical scenario:

  • Agent dials *44 (asterisk routes this to sip:acdlogin@acdserver.local as per dialplan)
  • ACD Server answers and prompts for agentID
  • ACD finds agent in internal list
  • ACD subscribe with calling phone (using contact header).
  • agent becomes available when a notify indicates IDLE.
  • agent dials *45 (asterisk routes this to sip:acdlogout@acdserver.local as per dialplan)
  • ACD unsubscribes and set Agent as unavailable

Asterisk

In sip.conf, under the profile for my acdserver, I set:

subscribecontext=acdpresence
context=acdserver

When phone1 calls the acdserver, the contact header will appear to be sip:phone1@asterisk.local to the ACD server (because asterisk is a B2BUA). So when the ACD server will try to subscribe to that device, it will need to have a corresponding entry in the dialplan. This is how I setup my dialplan:

[acdserver]
exten => _.,1,Dial(SIP/${EXTEN})

[acdpresence]
exten => _.,hint,SIP/${EXTEN}

It is discouraged to use "_." but currently, this is my only option. I'll try to find something. But this is because I don't have a naming convention for my devices. If all your devices are called phone1, phone2, phone3 etc. then you could use exten => _phone.,1,Dial(SIP/${EXTEN})

API

The server listens for incomming requests in the form of a RESTful API. The responses are sent as JSON data. I prefer JSON over xml since it is easier to parse with javascript and it also looks nicer in my opinion. I used my own json library which you can also find on this website. The server currently supports 2 requests.
curl -X GET "http://127.0.0.1:242/queues" would return

{
    "queues": [
        {
            "name": "queue1",
            "calls": [
                {
                    "id": "335099e931f09ad46ea75b8a451ad65d@192.168.0.3",
                    "state": "assigned",
                    "from": "gateway@192.168.0.3",
                    "to": "queue1@192.168.0.3:5071"
                }
            ]
        },
        {
            "name": "queue2",
            "calls": [ ]
        },
        {
            "name": "queue3",
            "calls": [ ]
        }
    ]
}

curl -X GET "http://127.0.0.1:242/agents" would return

{
    "agents": [
        {
            "id": "2771",
            "state": "idle",
            "idletime": "14",
            "device": "",
            "memberof": ["queue1","queue2","queue3"]
        },
        {
            "id": "2772",
            "state": "loggedout",
            "idletime": "0",
            "device": "",
            "memberof": ["queue2"]
        },
        {
            "id": "2773",
            "state": "loggedout",
            "idletime": "0",
            "device": "",
            "memberof": ["queue3"]
        }
    ]
}

Download

This code is experimental and is a mess right now. A lot of it can change at any time. The only libraries you will need is resiprocate and ortp.
download