Configuring Asterisk for QueueMetrics

QueueMetrics is designed to analyze queue_log data provided by any Asterisk installation; the following guidelines will help you to make the most out of it.

Configuring queues to report exit status

In the following example:

  • all calls are monitored, i.e. saved to disk;

  • if after 60 seconds on the queue the call is unanswered, the call is routed to voicemail and this event is reported correctly by QM;

  • there are two levels of agents: agents 302 and 303 will answer the queue (level 1); only if none of them is available the call is routed to agent 301 (level 2). If nobody is available, the queue keeps trying until timeout is reached.

  • Agents can transfer the call to other extensions by pressing the "#" key;

  • Agents terminate the current call by pressing the "*" key.

Extensions.conf

[q-my-sample]
; ...queue description.....
exten => s,1,SetVar(MONITOR_FILENAME=/var/spool/asterisk/QSAMPLE-${UNIQUEID})
exten => s,2,Queue(q-sample|nt|||60)
exten => s,3,Playback(voicemail-invitation)
exten => s,4,VoiceMail,s2001

Queues.conf

[q-sample]
music = default
announce = q-sample-announce
strategy = roundrobin
timeout = 60
retry = 5
maxlen = 0
announce-frequency = 0
announce-holdtime = no
monitor-format = wav
monitor-join = yes
queue-youarenext = silence
queue-thankyou = q-sample-thankyou
member=>Agent/302,0
member=>Agent/303,0
member=>Agent/301,1

Make sure that you do not forget the explicit timeout when calling the Queue() command from extensions.conf, or queue timeouts will not be logged by Asterisk and therefore not reported by QM. A patch that corrects this Asterisk behaviour can be found at http://bugs.digium.com/view.php?id=5422 .

Configuring URLs to be launched by the agent real-time page

The URL should be embedded in the Queue() command as prescribed by Asterisk:

exten => s,7, Queue(myqueue|nt|http://mysite/app?uid=${UNIQUEID}&clid=${CALLERID}||60)

This command launches the queue "myqueue" and launches the webapp located http://site/app passing the following parametrs:

  1. uid is the Asterisk internal unique call id

  2. clid is the Caller*ID for the current call

Please note that, for Asterisk version 1.4 and greater, the ${CALLERID} variable has been replaced by ${CALLERID(num)} or ${CALLERID(all)}.

The URL will appear on a clickable link on the Agent’s page.

If you set the property realtime.agent_autoopenurl to true, whenever the Agent’s page is reloaded, the most recent unopened URL is launched automatically.

Listening to recorded calls using QM

  • Make sure it is legal
    This is not strictly a QM issue, but before attempting to record all calls on a queue, you should consult a lawyer to make sure it is legal in your country. It would be probably fair enough to tell your operators their calls are being recorded and to add a voice message telling the customers their call will be recorded.

  • Tell Asterisk to record all calls
    To record all calls add something like this to extensions.conf:

    exten => s,1,SetVar(MONITOR_FILENAME=/var/spool/asterisk
         /q/QSAMPLE-${UNIQUEID})
    exten => s,2,Queue(q-sample|nt|||60)

    This way all sound files are stored under /var/spool/asterisk/q/ with the name of the queue (QSAMPLE) followed by the call id.

  • Tell QueueMetrics where to look for the calls
    You should set up the WEB-INF/configuration.property file in QM like this:

    default.monitored_calls=/var/spool/asterisk/q/

    When looking for the recording of a call, QM will explore all files contained in /var/spool/asterisk/q/ and any directories below for a file name containing the right call ID. It might find more than one file name and will display all of them. It is possible that sometimes Asterisk fails at mixing together the two files (Asterisk records separate files for the caller and the agent, and then tries to mix them together at the end of the call) so you will find two files named -in and -out instead. The search behaviour can be customized -see Listening to calls using Pluggable Modules (PM).

  • Tell QueueMetrics you have the right to listen to the calls
    Any user willing to listen to calls must hold the key CALLMONITOR. This is to make sure that only authorized personnel can listen to recorded calls. If you do not have this key, no sound files will be shown.

  • Make sure QueueMetrics has the right to read saved calls
    You should make sure that the process running QM (i.e. the servlet container, might be Tomcat, Jetty, or something else depending on your setup) has the rights to access the files where recorded calls are stored.<br> If using a separate web server, it should not be able to access those files directly, as QM will pipe out files only after enforcing security checks.

  • Debug tip: see which files QM sees
    There is a hidden transaction in QM made to debug call listening. To launch it, logon as an administrator and type the transaction "qm_show_files.do" in the URL bar instead of the page name. You will be lead to a page showing the filenames QM can read from the hard disk, whether the current user has the CALLMONITOR key and the search path as defined in default.monitored_calls.

Using AddQueueMember for dynamic agents

AddQueueMember is a command that lets you add dynamic agents to a queue. Its main advantage is that you can add channels, i.e. terminals, so you’ll have most of the advantages of agents without the performance and stability problems that the agents module may cost in very large systems.

Its disadvantage is that it does not log the agent login/logoff to the queue_log, and so programs that analyze the queue log data like QueueMetrics will not see agents logging on and off. This is a major organizational problem in a real-world call center, where tracking agent logons and logoffs is vital to the smooth running of the operations.

The answer is to add a fake queue_log data for each logon and logoff. For QM, it is important to avoid multiple logoff lines and to compute online permanence with logoffs.

To do the adding, you dial 422XX, where XX is your local extension; the same happens with 423XX to be logged off.

; Add Member - 422

exten => _422XX,1,Answer
exten => _422XX,2,AddQueueMember(my-queue,SIP/${EXTEN:3})
exten => _422XX,3,System( echo "${EPOCH}|${UNIQUEID}|NONE|SIP/${EXTEN:3}|\
                  AGENTLOGIN|-" >> /var/log/asterisk/queue_log )
exten => _422XX,4,Set(DB(dynlogin/log_Agent-${EXTEN:3})=${EPOCH})
exten => _422XX,5,Hangup

; Remove Member - 423
exten => _423XX,1,Answer
exten => _423XX,2,RemoveQueueMember(my-queue,SIP/${EXTEN:3})
exten => _423XX,3,Set(ORGEPOCH=${DB(dynlogin/log_Agent-${EXTEN:3})})
exten => _423XX,4,Set(RV=$[${EPOCH} - ${ORGEPOCH}])
exten => _423XX,5,GotoIf($["${RV}" = "0"]?8:6)
exten => _423XX,6,System( echo "${EPOCH}|${UNIQUEID}|NONE|SIP/${EXTEN:3}|\
                  AGENTLOGOFF|-|${RV}" >> /var/log/asterisk/queue_log )
exten => _423XX,7,Set(ORGEPOCH=${DB_DELETE(dynlogin/log_Agent-${EXTEN:3})})
exten => _423XX,8,Hangup

With this setup, we verified that the queue_log can be analyzed by QueueMetrics and the dynamic agent shows up fine (albeit with the name of a terminal, like SIP/23, instead of the usual Agent/23 string, but you can modify it in QM itself).

This setup might even be used in a call center where agents are not actually used but queues connect straight to terminals to "fake" agent logon/logoff, in order to have such data available for reporting.

Defining outbound queues (campaigns)

Standard Asterisk queues are, by definition, inbound queues; they accept a number of incoming calls, let them wait in line and distribute them to various agents based on the queue logic.

To make it possible to analyze outbound calls with QM, we added the concept of a "campaign" or "outbound queue", that is a set of calls made by different agents that are working for the same purpouse. Of course there is no such thing as an outbound queue in Asterisk, so we have to run a special piece of dialplan or an AGI script to produce the same information on queue_log for outbound calls as it is automatically produced for inbound queues.

As this only regards the actual Dial(…​) statement that Asterisk runs, it is possible to have different sources of numbers to be dialled by agents on outbound queues; they might enter the number on their keypad, or use the telephone, launch them from the Agent’s page or maybe use a predictive dialler for the task. QueueMetrics does not care, as long as the correct events are logged.

Placing outbound calls

If you run Asterisk 1.4 or newer and want to place outbound calls, you use an example script supplied within the extensions_queuemetrics.conf; it should be imported by the main Asterisk configuration.

After this, if you place a call directed to Local/XXXYYYYYYY@queuedial, where XXX is the code for the campaign and YYYYYY…​. the number to be dialled, a call will be created and logged as Agent/ZZZ, where ZZZ is the caller-id of the extension placing the call.

You may want to tweak the following supplied piece of dialplan to adapt it to your needs:

[queuedial]
exten => _XXX.,1,Set(QDIALER_QUEUE=q-${EXTEN:0:3})
exten => _XXX.,n,Set(QDIALER_NUMBER=${EXTEN:3})
exten => _XXX.,n,Set(QDIALER_AGENT=Agent/${CALLERID(num)})
exten => _XXX.,n,Set(QDIALER_CHANNEL=SIP/${QDIALER_NUMBER})
exten => _XXX.,n,Set(QueueName=${QDIALER_QUEUE})
exten => _XXX.,n,MixMonitor(Q-${QDIALER_QUEUE}-${UNIQUEID}.WAV|b|)
;exten => _XXX.,n,Set(CALLERID(all)="1234567890" <1234567890>) ; Uncomment and change this if you need to set your own caller ID
exten => _XXX.,n,Goto(qm-queuedial,s,1)

You can/should modify the following variable definitions:

  • QDIALER_QUEUE is taken from the first three digits. If you have ony one campaign system-wide, you may want to hardcode this value so the user needs not input it.

  • QDIALER_AGENT is the Agent code that the call will be logged under. The simplest approach is just to use the extension’s caller-id, under the hypotesis that Agent/123 works at SIP/123. You may also look up under Asterisk who is the agent working at a given extension - an example is given in the [queuedial-loggedon] context in the same file.

  • QDIALER_CHANNEL is the channel that you have to dial to call out. Will likely be something like Zap/g1/${QDIALER_NUMBER} or SIP/myprovider/${QDIALER_NUMBER} in a production system.

  • You can comment out the MixMonitor line if you don’t need call recordings.

Please note that:

  • The outbound queue should not be defined in Asterisk, but must be in QueueMetrics.

  • When running a QueueMetrics analysis, some values are their own mirrors: like, the Caller*ID of an incoming call is the number dialled of an outbound queue, while the Agent field is the caller.

  • It is possible to do live listening of outgoing calls (see Enabling ACD call attempts recording on Asterisk 1.0 and 1.2).

  • It’s possible to specify your caller ID uncommenting the line where the Set function is called and, obviously, changing the caller ID information to properly set it as required. The same modification is needed for the extensions 28 definition present in the same file.

Placing outbound calls through the AGI script

This section applies only if you run a version of Asterisk 1.0 or 1.2; for 1.4 or newer, please use the dialplan logic supplied in the file extensions_queuemetrics.conf.

The AGI script to be used instead of the Dial(…​) command is available in the standard QM distribution and can be used in the following way:

exten => xxx,1,DeadAGI(queueDial.agi|Number|DialString|QueueName|Agent)

The following parameter have to be passed by dialplan logic:

  • Number: the number you are trying to dial. Needed for correct logging only.

  • DialString: the actual Asterisk dial string, like SIP/34, or maybe IAX2/usr:pass@iax.server/8885551234. If you need additional parameters in the Dial() command, modify the AGI script manually.

  • QueueName: the outbound queue to be used for accounting. Must be defined in QueueMetrics and must not exist in Asterisk!

  • Agent: the agent placing the call, e.g. Agent/123

A working example might be the following:

exten => 426,1,DeadAGI(queueDial.agi|34|SIP/34|queue-out-1|Agent/101)

The terminal SIP/34 is dialled and the resulting events are logged as if generated by Agent/101 working on queue-out-1.

Please note:

  • The outbound queue should not be defined in Asterisk, but must be in QueueMetrics.

  • When running a QueueMetrics analysis, some values are their own mirrors: like, the Caller*ID of an incoming call is the number dialled of an outbound queue.

  • When monitoring calls in real-time, it is impossible to distinguish calls waiting to be answered from calls in conversation. This is an Asterisk limitation, as the generated events are not provided in real-time. Those values are anyway correct in the reports.

  • Extensive debugging output is available at /var/log/asterisk/agi-log.txt

  • It is possible to do live listening of outgoing calls (see Enabling ACD call attempts recording on Asterisk 1.0 and 1.2).

Enabling ACD call attempts recording on Asterisk 1.0 and 1.2

To get the AGENTATTEMPT code to work, it is necessary to patch the Asterisk module called app_queue.c in order to track down the required information. In order to perform this task, you must be confident with general Unix project patching and recompiling. It is advisable that Asterisk be shut down before applying the patch.

In order to apply the patch, just copy the file app_queue_agentattempt.patch found under WEB-INF/README/ to the apps/ directory of your Asterisk project, and then issue the following statement:

patch -p0 < app_queue_agentattempt.patch

As long as you see no errors, the patching process worked successfully. It’s now time to rebuild the app by issuing a general make statement from the main Asterisk directory.

Restart Asterisk and check that the queue system is still working fine.

To see if the patch was correct, try dialling a queue and see that Asterisk writes AGENTATTEMPT records to the queue_log file.

QueueMetrics starts to analyze AGENTATTEMPT verbs when the configuration key default.ignoreRingNoAnswer is set to true.

Enabling ACD call attempts recording on Asterisk 1.4

Asterisk 1.4 is natively able to produce the RINGNOANSWER log entry that servers the same purpose of AGENTATTEMPT, so no patching is necessary. In this case QueueMetrics reports in the realtime page the last agent that had not picked up the phone when ringing. QueueMetrics starts to analyze RINGNOANSWER verbs when the configuration key default.ignoreRingNoAnswer is set to false.

Is possible to have the AGENTATTEMPT information in a not patched Asterisk 1.4 with some modifications in the dialplan. This option is limited to people not using the hotdesking feature. For more information on that, please refer to the QueueMetrics advanced configuration manual.

Listening to live calls: Unattended Call Monitoring

In order to implement this feature, QueueMetrics follows the following steps:

  • It will try to dial the channel defined in the property callfile.monitoring.channel by passing the local extension. This should make your local phone ring.

  • Once the call is picked-up, it will try to dial 11@queuemetrics (if the call is inbound) or 14@queuemetrics (if the call is outbound) in order to start the ChanSpy() monitoring and will pass along all required variables to match the requested call.

To enable unattended audio monitoring for inbound calls, you’ll have to edit the Asterisk dial-plan in order to include the [queuemetrics] context.

  • Make sure that the queuemetrics context exists and that the extensions 10, 11 and 14 are defined for it. See Appendix B: The [queuemetrics context]

  • Make sure that the channel defined in the property callfile.monitoring.channel is set to Local/$EM@from-internal/n (in this example, your telephone would be known by Asterisk as something like 105@from-intenal).

  • Make sure that the extension/context are set to 11/queuemetrics ( the unattended audio monitoring endpoint).

  • Make sure that the callfile.dir property points to a valid callfile directory, and that will be writable by QueueMetrics. As a (now preferred) alternative you may enter a Monitor URI in the format tcp:user:pass@server; in this case QM will not attempt to generate a call-file but will use the Manager command to create an equivalent call instead.

  • Make sure the callfile.monitoring.enabled configuration property is set to true

  • Make sure your users hold the MON_AUDIO key

  • Important: make sure that each agent will have their local extension set in QueueMetrics; usually entering "-" will be enough. If this is not set, the icon will not appear.

  • Now, when you click on the icon, a callfile will be generated and call snooping will start.

To enable unattended call monitoring for outgoing calls as well, you’ll have to set the piece of dial-plan referenced by the callfile.outmonitoring…​ properties.

Outgoing calls placed though queueDial.agi will usually be listened to by attaching to the local SIP/XXX or Local/XXX channel of the calling agent and not to the standard Agent/XXX channel used for inbound, so a different piece of dial-plan will be used. Note that in order for QueueMetrics to reference the outgoing calls, you must tell it that queue direction is Outgoing.

See also Appendix B: The [queuemetrics context] for an example of implementing Asterisk code for inbound and outbound call monitoring.

It is possible to use different PMs to handle different live audio - see Listening to calls using Pluggable Modules (PM).

if you pass an empty variable to the ChanSpy() command, it will let the user listen to any channels on the system. This may be a major security issue. So if you edit the supplied dialplan to match your configuration, make sure that you add a check in case a computed channel to listen on might be empty!

Enabling VNC Monitoring

To enable VNC monitoring you will first need a VNC server that is running on each client’s machine and that will serve the current layout.

You will also have to create a web page with a VNC client that may accept a VNC URL and show a VNC client (there are a number of Java-based VNC clients that can be displayed as an applet).

Configure the VNC URL as something like: http://myserver/vncpage.php?ip=192.168.3.17

Where the PHP page will connect the VNC applet to the server located on address 192.168.3.17

Make sure that your users hold the MON_VNC key in order to be able to access this feature.

As an alternative, we have some clients that use a simpler setup with each machine having their own copy of UltraVNC - http://ultravnc.sourceforge.net/ - and each machine running a web server with the locally-configured Java viewer. The VNC url is then the address of the local machine; when a person connects to it, s/he is asked for a password and then the screen is displayed through a Java applet. They report this setup to be very simple and working very well.

Enabling Agent’s page actions

In order to enable actions on the Agent’s page:

  • Check that all actions are enabled in the properties, this means that callfile.actionname.enabled=true

  • Check that a Manager API is configured correctly for the server

  • Check that the dialplan on the server contains the appropriate commands for this action. A sample [queuemetrics] context you can include easily within a standard dialplan using call-back agents is provided as a reference.

As of QM release 12.10 it is possible to set input validation for both the agent code and the extension. As an example, by setting the key realtime.agentRegexp=1\\d\\d you are defining that the agent code must start with a one and cannot be more than 3 digits, while by setting the key realtime.extensionRegexp=\\d\\d\\d\\0 you define that the agent extension must be four digits and must end with a zero. Please note that the backslash in the regexp has to be written as '\\' in the configuration.properties file.

Enabling XML-RPC call listening and streaming

It is possible to run remote audio monitoring of both completed and ongoing calls using third party monitoring tools, for example OrecX. As QueueMetrics has no way of knowing the internal details of such applications, we made it possible to call an external XML-RPC server (we offer a stub written in PHP, but it can be written in any language and reside on any server, as long as it uses an XML-RPC library) that will basically pass back to QM the URLs required to perform the required task.

In order to enable this, we first tell QueueMetrics to use the XML-RPC Pluggable Modules for both call listening and streaming:

audio.server=it.loway.app.queuemetrics.callListen.listeners.ClassicXmlRpcRecordings
audio.liveserver=it.loway.app.queuemetrics.callListen.RTlisteners.ClassicXmlRpcListenerRT

The XML-RPC server will be set by setting its URL in a configuration property, like for example:

default.audioRpcServer=http://127.0.0.1/xmlrpc/xmlrpc_audio_server.php

The server must implements three XML-RPC calls called:

  • QMAudio.findStoredFile
    This function is used to find and play back a stored audio file, by returning the URL of a player that will play it or the audio file itself. This function has in input the following parameters:

    • $ServerID: ignore for now

    • $AsteriskID: The Asterisk call-id, as written in the second field of queue_log

    • $QMUserID: the ID of the current QM user

    • $QMUserName: the name of the current QM user

    and it must return the following values:

    • $FILE_FOUND : If the file was found or not (maybe it was not recorded)

    • $FILE_LISTEN_URL : an URL to open up a player for this call

    • $FILE_LENGTH : size of the audio file (displayed as returned)

    • $FILE_ENCODING : encoding of the audio file (eg mp3)

    • $FILE_DURATION : duration of the audio file

    In case multiple values are to be returned (because e.g. the call is split into multiple recordings) then the following format must be used:

    • $FILE_FOUND : true

    • $FILE_LISTEN_URL : "MULTI:http://url1 http://url2 http://url3"

    • $FILE_LENGTH : "100k 50k 120k"

    • $FILE_ENCODING : "mp3 mp3 mp3"

    • $FILE_DURATION : "1:00 0:30 1:20"

    As you can see, the listen URL starts with the string "MULTI:" and has multiple values separated with space. The other parameters also hold multiple values separated by space.

  • QMAudio.listenOngoingCall
    This function is used to query for an ongoing inbound call. If found, QM will launch a new popup to open the player which URL is returned. This function has in input the following parameters:

    • $ServerID: ignore for now

    • $AsteriskID: The asterisk call-id, as written in the second field of queue_log

    • $Agent: the name of the agent being monitored e.g. "agent/101"

    • $QMUserID: the ID of the current QM user

    • $QMUserName: the name of the current QM user

    and it must return the following values:

    • $CALL_FOUND: If the call was found or not

    • $CALL_LISTEN_URL : the URL of the player

    • $CALL_POPUP_WIDTH, $CALL_POPUP_HEIGHT: width and height of the popup being opened. Currently a double popup is opened.

  • QMAudio.listenOngoingCallOutgoing
    This function is used to query for an ongoing outgoing call. If found, QM will launch a new popup to open the player which URL is returned. The parameters are the same as for QMAudio.listenOngoingCall.

To make implementer’s life easier, we provide a simple XML-RPC stub server under WEB-INF/mysql-utils/xml-rpc that can be used as a starting point: no need to handle the XML-RPC stuff, just change the results of the two supplied functions and data goes back to QueueMetrics.

Enabling call outcomes

A call tracking code is a code to be input by a user telling the status of a call, be it inbound or outbound. This status code is a string (though we suggest to use numeric status codes, in order to make it easy to input them using a telephone keypad) and may be input either when the call is ongoing or after a short while from its end.

The queue_log entry looks like the following one:

1234|1231.1|NONE|Agent/1234|CALLSTATUS|21

This will set the CALLSTATUS to "21" for the call which Call-ID is "1231.1" it may be an open call or it may be just terminated (see Updating past calls).

If it is not possible to force the Call-ID, a second version of the verb is available:

1234|2222.3|NONE|Agent/1234|CALLSTATUS|21|1231.1

This has exactly the same meaning; the second Call-ID passed as a parameter will override the original one.

If you prefer, you may log the queue name instead of "NONE" field shown above; in any case QM will ignore this piece of information.

The following rules apply:

  • A CALLSTATUS row must be set after the call is started or it’s terminated; in any other case it’s simply discarded

  • There may be multiple CALLSTATUS rows for the same Call-ID; in this case, the last one overrides pervious codes.

  • The CALLSTATUS must be set shortly after the end of a call (see Updating past calls).

  • CALLSTATUS for a non-existent Call-ID will be discarded

  • Even if a queue reset is detected, CALLSTATUS for existing Call-ID are applied

The agent may either be a fill "Agent/xxx" string or the valid name of an Asterisk channel. It is acceptable to use a generic channel name instead of the specific one, i.e. "SIP/123" and "SIP/123-abcd" are equivalent.

The sample [queuemetrics] context that comes with QueueMetrics can be used as a starting point to output such data.

Keeping the UNIQUEID of the call when setting status code

One of our clients has successfully implemented Call Outcomes by using AEL.

In the Hangup-Extension, use:

  if("${MEMBERINTERFACE}" != "" && "SIP/${CALLERID(ani)}" != "${MEMBERINTERFACE}" ) {
     // to be able to record QueueMetrics call outcome later
     Set(GLOBAL(queue_last_call_${MEMBERINTERFACE:4})=${UNIQUEID});
  }

The outcome is recorded like this:

_#XX = > {
        // ${user_name} contains the extension number of the agent
        Answer();
        if ("${queue_last_call_${user_name}}" != "") {
              QueueLog(NONE,${queue_last_call_${user_name}},SIP/${user_name},CALLSTATUS,${EXTEN:1});
              Set(GLOBAL(queue_last_call_${user_name})=);
              Playback(beep);
        } else {
              Playback(beeperr);
        }
        Hangup();
     }

Enabling call features

A call feature code is a code to be input by a user telling the sub-status of a call, be it inbound or outbound. This feature code is a string and may be input either when the call is ongoing or after a short while from its end. Several call feature codes can be associated to a single call; QueueMetrics will count all the associated feature code. A feature code may have an optional free text associated with it.

The queue_log entry looks like the following one:

1234|1231.1|NONE|Agent/1234|INFO|FTR|36

This will set the feature code to "36" for the call which Call-ID is "1231.1" it may be an open call or it may be just terminated.

A second version of the verb is available:

1234|1231.1|NONE|Agent/1234|INFO|FTR|41|Hello there

This has exactly the same meaning but the feature code contains a free text associated with it.

Feature codes can be removed from a call by mean of a trace added in the queue log:

1234|1231.1|NONE|Agent/1234|INFO|NOFTR|36

This will remove the feature code "36" to the call with Call-ID is "1231.1". If no feature code "36" have been already associated with the call, QueueMetrics simply discards the trace.

The following rules apply:

  • Features should be entered while the call is ongoing or within a few minutes minutes from its closure (see Updating past calls). The loopback period is the same as for setting the outcome.

  • Features have a code and an optional textual value. The text should be printable ASCII7 and cannot contain pipe or special, non-printable characters. Though we enforce no limit on this, we suggest using no more than 40 characters.

  • If multiple features with the same code are applied for the same call, the last one wins (sets the text of it)

  • In order to remove a feature, a special verb NOFTR is passes

  • If successive lines set the feature after a NOFTR, the feature is set and so on.

The sample [queuemetrics] context that comes with QueueMetrics can be used as a starting point to output such data.

Enabling pause codes

A pause reason code is a code to be input by a user telling the reason why a pause was started. It should be ideally input together with the decision to go on pause, though QueueMetrics will accept the code and will attach to the correct pause even if the pause is resumed, as long as no other pause is started. The reason code is a string - though we suggest to use numeric status codes, in order to make it easy to input it using a standard telephone keypad.

The format is the following one:

1234|1231.1|NONE|Agent/1234|PAUSEREASON|21

This will set the pause reason to "21" for the pause that is either going on or has just finished. If the code is input after over 30 minutes from the end of the last pause, it is discarded.

The following rules apply:

  • A PAUSEREASON row must be set after the agent’s pause is started or it’s terminated; in any other case it’s simply discarded

  • There may be multiple PAUSEREASON rows for the same pause; in this case, the last one overrides pervious codes.

  • The PAUSEREASON must be passed within 30 minutes from the end of a pause; otherwise it will be silently discarded (see Updating past calls).

  • PAUSEREASON for a non-existent agent pause will be discarded.

  • If a pause extends over multiple call sessions, the PAUSEREASON will be correctly set only for sessions terminating after the PAUSEREASON has been set.

  • Even if a queue reset is detected, PAUSEREASON for existing pause are applied

  • The agent may either be a fill "Agent/xxx" string or the valid name of an Asterisk channel. It is acceptable to use a generic channel name instead of the specific one, i.e. "SIP/123" and "SIP/123-abcd" are equivalent.

The sample [queuemetrics] context that comes with QueueMetrics can be used as a starting point to output such data.

Since Asterisk 1.6, it is possible to pass a pause reason code to the native Pause application. QueueMetrics will handle this correctly, and allows mixing the two methods as you best see fit.

Tracking required skills

Skills can be specified at any time before of after the call enters the queue but the suggested way is to have them immediately after the ENTERQUEUE verb as in:

1167335958|1167335958.530054|cpc|NONE|ENTERQUEUE||01909723335
1167335958|1167335958.530054|cpc|NONE|INFO|REQSKILL|DE|90
1167335958|1167335958.530054|cpc|NONE|INFO|REQSKILL|NET|70
1167335958|1167335958.530054|cpc|Agent/101|CONNECT|41|Agent/101
1167335958|1167335958.530054|cpc|Agent/101|COMPLETECALLER|41|23

In the example above, the call is queued on a queue called cpc with required skills DE>=90 and NET>70, so it could be a request for someone servicing internet support in German. Basically you just add an event for each required skill, and the level at which it is required. We do not need this information on connected/failed calls, as we assume that the routing is always correct.

The following rules apply:

  • Rules are read as a label (the rule) and a number. If the number is invalid, it is read as zero and no exception is raised

  • The label can be any valid ASCII7 string, punctuation and spaces

  • For a skill to be added, it must have a non-empty label and a skill level > 0

  • If a skill is repeated multiple times, the last value wins. In the call details, the full sequence of events is displayed

  • It is not possible to remove a skill from a call

Closing ongoing calls

It sometimes happens that Asterisk will not log the call termination records for a call; as QM is based on the logged events, a call missing the call closure log will linger on forever in the realtime screen (or at least the maximum time allowed by the …​) and will appear as Ongoing or Not answered yet in the historical reports.

Since version 1.4.5 of QueueMetrics, it is possible to manually close a call from either the historical reports or the real-time screen. In order for this to work:

  • You must be running with MySQL storage or clustered storage

  • Your user must own key CLOSECALLS

When this is done, open calls on the reports will show a red scissor icon:

image201

And the same will happen for the real-time screen:

image203

By clicking on that icon, a popup will appear that will ask for the length the call should be closed to. This length refers to the wait duration if the call is not answered and the conversation time if the call is answered. It is possible to change that from the default 5 seconds by setting a configuration property.

If the call has already been closed in the meantime, or you’re doing this operation twice, QM will report that the call has already been closed.

if you do this on calls that are still ongoing, you will risk having duplicate data on the report. So don’t use this feature unless you know what you are doing. The required security key must be manually assigned only to trusted users.

Tracking DNIS and IVR information

In order to track IVR information, it would be advisable to follow the newer logging format defined in Implementing IVR tracking.

In order to keep track of DNIS and IVR information that relates to each call, you have to write special records on the 'queue_log' file that QueueMetrics parses.

This is very easy to do, e.g. imagine you have a piece of dialplan where you are going to call queue 'q-sample' and you have the DNIS code in the 'MYDNIS' dialplan variable, and the sequence of keys pressed as 'MYIVR':

exten => s,n,........
exten => s,n,QueueLog(q-sample,${UNIQUEID},NONE,INFO,DID|${MYDNIS})
exten => s,n,QueueLog(q-sample,${UNIQUEID},NONE,INFO,IVR|${MYIVR})
exten => s,n,Queue(q-sample|nt|||60)
exten => s,n,........

There is no predefined format for DNIS and IVR information; QueueMetrics just handles it as free-form text strings. It can be optionally decoded by creating values in the IVR and DNIS configuration pages.

You can output only one record, or both, or none, depending on what you need.

Adding TAG information to calls

Some call centers require to report call set at the list level below campaign. This is frequently used for outbound campaings.

QueueMetrics searches TAG information on the queue log file. To enable Asterisk to place a TAG signature in the queue log a dialplan modification is needed. Below is an example on how this could be done, assuming you have the TAG code in the 'MYTAG' dialplan variable:

exten => s,n,........
exten => s,n,QueueLog(q-sample,${UNIQUEID},NONE,INFO,TAG|${MYTAG})
exten => s,n,Queue(q-sample|nt|||60)
exten => s,n,........

You can assign only one TAG for each call. If more than one TAG are assigned to a single call, QueueMetrics will discards all TAGs except the latest found in the queue log file.

Enabling Hotdesking in the agent page

Since the demise of AgentCallBackLogin, it has been hard to do "hotdesking" in Asterisk - that is, having agents that work on queues because of their competences and not because they are sitting at a given extension.

With QueueMetrics 1.6.1, hotdesking is very easy to implement and it has no downsides, because:

  • it is completely transparent to Asterisk

  • you can emulate the single-sign-on behavior of AgentCallBack and still have the flexibility of adding/removing members as needed on a queue by queue basis.

  • call recordings, agent monitoring and all other functionalities are unaffected

Requirements:

  • QueueMetrics 1.6.1 or newer

  • MySQL storage model

  • Asterisk 1.4 or 1.6

How it works

Set the following properties within the configuration.properties file, as follows:

default.queue_log_file=sql:P001         <-- change as needed
callfile.dir=tcp:admin:amp111@127.0.0.1 <-- change as needed
default.rewriteLocalChannels=true
callfile.agentlogin.enabled=false
callfile.agentlogoff.enabled=false
default.hotdesking=86400

Make sure that 'extensions_queuemetrics.conf' is loaded in the Asterisk dialplan (you need to use the extensions_queuemetrics file that comes with QM 1.6.1 or newer).

This setup means that we access the queue_log file through the database, connect to Asterisk over AMI to send commands, rewrite agent codes, do not use Agentcallback-style agents and enable hotdesking.

Now we use a piece of dialplan like this one when we associate an agent to a queue:

Imagine we have AGENTCODE set to 200 (the agent’s login code) and AGENT_EXT set to 123 (thi sis the SIP extension code):

....
exten => 35,3,QueueLog(NONE,${UNIQUEID},Agent/${AGENTCODE},HOTDESK,SIP/${AGENT_EXT})
exten => 35,4,AddQueueMember(myqueue,SIP/${AGENT_EXT})
....

This logs on Agent/200 to queue "myqueue", tracking him as SIP/123. Note that from the point of view of Asterisk, we only see that extension 123 is made a member of the queue.

When you logoff, pause, unpause agents, you always work at the SIP level (the actual extension that is linked to the queue) so there is no need to change anything.

If you use the QueueMetrics Agent’s page, you can do logon/logoffs/pauses from the buttons by the top of the page; this lets you add an agent to all queues at once, like you used to do with AgentCallBackLogins, and still retain the flexibility to change that at runtime.

Example hotdesking configuration

In the following sections, we sumamrize the changes that have to be made to an existing system to enable hotdesking.

Changes to configuration.properties

Add/change the 'default.hotdesking' property to 86400. This property enables hotdesking and lets the parse "look back" up to 1 day (change as needed).

default.hotdesking=86400

Add/change the sections below:

callfile.agentpause_ht.enabled=true
callfile.agentpause_ht.channel=Local/32@queuemetrics/n
callfile.agentpause_ht.extension=10
callfile.agentpause_ht.context=queuemetrics

callfile.agentunpause_ht.enabled=true
callfile.agentunpause_ht.channel=Local/33@queuemetrics/n
callfile.agentunpause_ht.extension=10
callfile.agentunpause_ht.context=queuemetrics

callfile.agentaddmember_ht.enabled=true
callfile.agentaddmember_ht.channel=Local/35@queuemetrics/n
callfile.agentaddmember_ht.extension=10
callfile.agentaddmember_ht.context=queuemetrics

callfile.agentremovemember_ht.enabled=true
callfile.agentremovemember_ht.channel=Local/37@queuemetrics/n
callfile.agentremovemember_ht.extension=10
callfile.agentremovemember_ht.context=queuemetrics

This code specifies the Asterisk extensions that QueueMetrics will call for each button present in the agent live page when hotdesking is enabled.

Change the 'realtime.agent_button_x.channel' key to the value 'Local/[EM]@from-internal'

This last option is needed only if you use custom agents buttons to dial out extensions and should be repeated for each dial-enabled button. In the code below, a valid example for the button 4 is reported:

realtime.agent_button_4.enabled=true
realtime.agent_button_4.caption=Secretary
realtime.agent_button_4.url=
realtime.agent_button_4.channel=Local/[EM]@from-internal
realtime.agent_button_4.ext=200@queuedial
if you use a channel like Local/123@from-internal as the hotsedking extension, remember to tun off local channel rewriting first, or it will not work.

Changes to extensions_queuemetrics.conf

Here should be defined the Asterisk extensions used by QueueMetrics to perform actions triggered from the agent live page.

Add to this file the code reported below:

; extension 32: agent pause with hotdesking (with pause code)
exten => 32,1,Answer
exten => 32,2,NoOp( "QM: Pausing Agent/${AGENTCODE} at extension SIP/${QM_AGENT_LOGEXT} \
    with pause reason '${PAUSEREASON}' made by '${QM_LOGIN}' " )
exten => 32,3,PauseQueueMember(,SIP/${QM_AGENT_LOGEXT})
exten => 32,4,System( echo "${EPOCH}|${UNIQUEID}|NONE|Agent/${AGENTCODE}|PAUSEREASON|${PAUSEREASON}" \
    >> /var/log/asterisk/queue_log )
exten => 32,5,Hangup

; extension 33: agent unpause with hotdesking
exten => 33,1,Answer
exten => 33,2,NoOp( "QM: Unpausing Agent/${AGENTCODE} at extension SIP/${QM_AGENT_LOGEXT} \
    made by '${QM_LOGIN}' " )
exten => 33,3,UnpauseQueueMember(,SIP/${QM_AGENT_LOGEXT})
exten => 33,4,Hangup

; extension 35: agent addqueuemember with hotdesking (for asterisk v1.4+)
exten => 35,1,Answer
exten => 35,2,NoOp( "QM: AddQueueMember (asterisk v1.4+) Agent/${AGENTCODE} at extension \
    SIP/${QM_AGENT_LOGEXT} on queue ${QUEUENAME} made by '${QM_LOGIN}' with prioritylabel \
    '${QM_AGENT_PRIOLBL}' and prioritynum '${QM_AGENT_PRIONUM}'" )
exten => 35,3,Macro(queuelog,${EPOCH},${UNIQUEID},NONE,Agent/${AGENTCODE},\
    HOTDESK,SIP/${QM_AGENT_LOGEXT})
exten => 35,4,AddQueueMember(${QUEUENAME},SIP/${QM_AGENT_LOGEXT})
exten => 35,5,Hangup

; extension 37: agent removequeuemember with hotdesking (for asterisk v1.4+)
exten => 37,1,Answer
exten => 37,2,NoOp( "QM: RemoveQueueMember (asterisk v1.4+) Agent/${AGENTCODE} at extension \
    SIP/${QM_AGENT_LOGEXT} on queue ${QUEUENAME} made by '${QM_LOGIN}'" )
exten => 37,3,RemoveQueueMember(${QUEUENAME},SIP/${QM_AGENT_LOGEXT})
exten => 37,4,Hangup

Please note that the 'extensions_queuemetrics.conf' file that ships with 1.6.1 already has these changes embedded.

In order to have the hotdesking working a complete QueueMetrics restart and Asterisk reload should be performed.

Running Asterisk 1.8 with QueueMetrics

QueueMetrics is compatible with Asterisk 1.8 but you need to properly set it. The first requirement is related to a strange behavior found in Asterisk 1.8.0 and 1.8.1 that prevents Asterisk to properly log all queue activity until a a reload command is issued from the CLI. To fix this problem we had to change the code in the logger.c file found in the main subfolder present in the asterisk sources, near the line 396, in order to have something similar to what is listed below:

        if (qlog)
                fclose(qlog);

        {
                char tmp[4096];
                snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_LOG_DIR, queue_log_name);
                qlog = fopen(tmp, "a");
        }

Then we had to rebuild asterisk and to reinstall it.

The next step is to replace the extensions_queuemetrics.conf file with the specific version for Asterisk 1.8. To do this, you need to copy the extensions_queuemetrics_18.conf replacing the one present into the asterisk configuration folder then reload the dialplan from the CLI. The extensions_queuemetrics_18.conf is targeted to Asterisk 1.8 with hotdesking enabled.

This applies ONLY to some earlier versions of Asterisk 1.8

Handling Agents priorities on queues

Starting from QueueMetrics 1.6.3 is possible to define priorities when logging agents in a specific queue. The priority associated to each agent is dependent on how the agent was configured in the queue (main, spill or wrap). This feature populates two new channel variables ${QM_AGENT_PRIOLBL} and ${QM_AGENT_PRIONUM} when AddQueueMember is called by extensions 25 and 35 in the queuemetrics context.

  • QM_AGENT_PRIOLBL is set to "U" when the queue is not assigned to the agent, "M" when the queue is a normal working queue for the agent (Main), "W" when the agent is set as Wrap for the queue, "S" when the agent is set as Spill for the queue.

  • QM_AGENT_PRIONUM is set to 0 when the queue is not assigned to the agent or the queue is a normal working queue for the agent; 1 when the agent is set as Wrap for the queue, 2 when the agent is set as Spill for the queue.

Using known numbers

In QueueMetrics, it is posible to keep track of a set of "known numbers" through a specific editor as described in Configuring known numbers (VIP callers / blacklists)

For each number, we track:

  • An action to be done

  • A name and description

  • An optional expiry date

  • The number of times the rule was hit, and the last time it was hit

  • An optional "agent affinity" attribute

A webservice - built to be easy to query from the Asterisk dialplan or through JSON - lets the user query whether the number exists and what to do with it.

Possible actions include:

  • Blacklist: the number is to be hung up, or moved to a low priority queue

  • VIP: the number is to be moved to a VIP queue, or its queue priority is to be made higher

  • Agent affinity: if a number has "affinity" with some agent, then the agent should be tried first (by using a personal queue, or reaching them though a direct channel and "faking" agent records so that they appear as if the call was processed on a queue)

  • Caller name / CRM ID: the caller-id is rewritten so that a proper name can be associated with the call.

Those actions are to be implemented at the Asterisk dialplan level.

The webservice is meant to be easy to interoperate with a standard Asterisk CURL call.

exten => s,1,Set(res=${CURL(http://my.qm:8080/queuemetrics/numberLookup.do?number=$(CALLERID)&mode=action&user=user:pass)})

The page returns a response as text/plain that will be embedded in the dialplan variable res. The response is based on the following table:

Table 1. Possible API modes
Mode Sample response Notes

action

UNKNOWN

BLACKLIST

VIP

<blank>

The response UNKNOWN means that the number is not listed; the response blank means that it is listed but no action is required. The number of hits and last hit counters are updated.

affinity

Agent/106

'' <blank>

The number has a known affinity for Agent/106. If no known affinity, returns blank.

name

John Doe

<blank>

An URL-encoded name for this number, or blank if no name set / unknown number. The name will be stripped of non-Ascii7 characters.

json

{ \'action\': \'vip\',

\'name\': \'John Doe\',

\'affinity\': \'Agent/101\' }

In this mode, a JSON object is returned with the information shown. This way you can query all the parameters at once, or you can use a JSON library for querying. The response is returned as application/json.

hash

action=vip&name=John Doe&affinity=

In this mode, the returned string is encoded as an Asterisk hash (see below). This way, all the results can be read at once.

'Notes'

  • It is important to make sure that the HTTP error case is handled at the dialplan level, in case QM was unavailable at the time of the call.

  • It is also important to set a quick connection timeout through CURLOPT(<option>) to make sure that if QM does not answer quickly, the default case is handled.

The trivial format used in the response makes it possible to use the service using the command-line curl, or by using a trivial scripting language.

The "user" parameter is mandatory and requires a valid QueueMetrics username and password, separated by a ":". This is needed because the API will be publicly exposed. The user must hold the security key PBXAPI

In order to avoid security risks, the user should be custom-made and assigned to a class that only contains the key PBXAPI. This way the user will be able to log on to QM but will have no actual grants but logging off.

'Asterisk hashes'

When querying an Asterisk hash, the result is built as a string so that you can do:

Set(HASH(numinfo)=${CURL(myurl)})

to load the results from QM, and then parameter e.g. 'action' can be read as:

${HASH(numinfo,action)}

In order to avoid issues when returning data from QueueMetrics in the HASH format:

  • Data is returned as UTF8

  • All special characters in the returned strings will be replaced by and underscore. Those being:

    • non printable (CR, LF, etc.)

    • having a possible meaning in the Asterisk dialplan or in the querystring-like hash format being non ASCII7

When querying each response separately, the response is instead UTF8.

Configuring the AMI connection

QueueMetrics bases its reports on data generated from the Asterisk queue_log file; still, it sometimes needs to send commands to Asterisk in order to performs some actions, e.g. log on agents, or listen to live calls.

In order to perform such commands, two things are required:

  • A working AMI connection should be present

  • The extensions_queuemetrics.conf file should be included in the PBX’s dialplan

For historical reasons, the default way QueueMetrics used to send commands was to generate Asterisk call files; now this method is obsolete and the correct one is to set-up an AMI connection.

In order to set up an AMI conenction, you have to set the following property like e.g.:

callfile.dir=tcp:admin:amp111@127.0.0.1

The AMI URL is in the following format: tcp:username:password@server:port

  • username: This is the AMI username

  • password: This is the chosen "secret"

  • server: This is the IP address of the server, or 127.0.0.1 if the same server.

  • port: This part is optional; if not present will default to 5038.

All three fields are mandatory. The password is sent over a clear-text TCP connection, so make sure to protect it using e.g. a VPN tunnel if it is to traverse public networks.

Username and password should be made only of letters and digits; no other character should be used.

The configuration above should be matched by the configuration in Asterisk’s own manager.conf file, that should look like the following one:

[general]
 enabled = yes
 port = 5038
 bindaddr = 0.0.0.0
 webenabled = no

[admin]
 secret = amp111
 deny = 0.0.0.0/0.0.0.0
 permit = 127.0.0.1/255.255.255.0
 read = system,call,log,verbose,command,agent,user,originate
 write = system,call,log,verbose,command,agent,user,originate

In order to make testing easier, QueueMetrics includes a test tool that checks whether the current connection is working or not; see Checking an Asterisk Manager connection for details.

Listening to encrypted recordings

QueueMetrics allows to listen to recordings that are stored in an encrypted format. This works by invoking a custom-supplied filter that will decrypt the recording on-the-fly before QM streams it back to the user.

This is possible only for recordings that are read from disk and streamed by QM; it does not work for recordings that are streamed by a third-party player (e.g. Oreka), which will usually implement its own encryption scheme.

What is a filter

In order to decrypt a call, QueueMetrics uses a filter, i.e. a program (usually a script) that, given the filename that it needs to decrypt, will output the decrypted file to STDOUT. This way the decrypted file is never saved on disk.

Encrypting and decrypting recordings on-the-fly can impose a severe load on your QueueMetrics server, as encryption is usually CPU-intensive.

A sample filter may look like the following script:

PASSW=myPassword
echo $PASSW | gpg --passphrase-fd 0 --batch --decrypt $1

As the filter is not dependent on any specific encryption technology (public key, symmetric keys, etc) QueueMetrics is able to adapt to whatever technology suits you best.

Please note that the called script does not receive a password - it must be able to run the decryption internally. Most encryption technologies have the concept of "secure password stores", so that you can avoid storing the password in a plain-text format.

Setting up a filter

In order for QM to decrypt a file, it must match two conditions:

  • It must end in .crypt, as appended to the natural extension of the file (e.g. the encrypted version of a file named ''audio.mp3'' must be called ''audio.mp3.crypt'')

  • The configuration property ''audio.decrypt'' must point to the decryption filter, as in the example below.

The script to be run must be readable and executable by the QueueMetrics process, as in:

audio.decrypt=/encryptionTools/decryptGPG.sh

When an encrypted file is found by QueueMetrics, it is displayed with a "lock" icon. By clicking on it, the file is decrypted on the server and streamed back in an unencrypted format.

If a file is not encrypted, QueueMetrics will stream it back without attempting any decryption.

Encrypting calls

As Asterisk does not currently offer any facility for storing encrypted recordings, audio files must be encrypted on a periodical basis.

  • Every so often, a process runs and checks for unencrypted recordings in the audio destination directories

  • Every file found is first encrypted, and if the encrypted file was actually created, then its unencrypted version is removed.

We offer a sample encryption routine in the files ''encryptAllGPG.sh'' and ''encryptGPG.sh'' that can be used as an example to deploy your own script.

The sample encryption and decryption scripts are available under the ''WEB-INF/mysql-utils/audio-encryption'' folder in QM. They are meant as a reference blueprint only and may not be suitable for the required Corporate security standards.

Tracking IVR data

Since QueueMetrics 13.03, IVR information is tracked natively within QueueMetrics.

IVR information is different from queue information, as:

  • IVR data is typically tracked before a call hits a queue, and bears no queue information. So IVR calls might be ancestors of any call in the system.

  • If you know happen to know from the start of the call that a particular call belongs to a more specific area, you may want to track this immediately so that this IVR call will not appear on "unassigned" calls (see below for more information).

  • IVR data is made up of multiple IVR menus, each of which may have a selection, that is a digit pressed by the caller in order to progress forward.

  • An IVR Path is a unique sequence of IVR menus that lead to a destination

  • IVRs may define goals, that is activities that don’t lead the caller directly to a queue but are tracked as they satisfy, in a fully automated manner, the needs of a caller. For example, when a caller reaches the TTS menu reading back their current account amount in your banking IVR, that is usually a goal you want to track.

  • If a call is still in the IVR phase at the end of the analysis, without having reached any goal or having hung up, it is considered hung up just after the last known event.

IVR tracking requires changes to the current dial-plan of Asterisk in order to track the required information. Such changes - detailed in section Implementing IVR tracking - are not complex to implement, and are implemented natively in the QueueMetrics module of FreePBX. So if you use a common Asterisk distribution, chances are you already have IVR tracking available.

A call’s life-cycle

When a call is tracked withing QM, it may traverse the following tree:

QM IVR lifecycle

As you can see, QM defines three time periods about a call:

  • the IVR Time, that is between when a call is first tracked and when it hits a queue. For calls that do not have any events before hitting a queue, it is always set to zero.

  • the Wait Time, that is how long a call has been waiting on a queue before being answered or hung up

  • the Talk Time, that is the length of the conversation between the agent and the caller.

IVRs and QueueMetrics

QueueMetrics handles IVRs when running reports by filtering all calls by the set of queues specified in the report. As IVRs have no queues, all IVRs are processed for the time period requested. IVRs that end up on queues different from the ones being reported on are reported as "lost".

IVR activity usually takes place before the call is queued. Filters on IVRs, DNIS and caller-ids are correctly applied to the analysis if specified (so you can drill down an IVR analysis on a specific selection path or on a caller / called number).

What you get out of an IVR analysis:

  • Tracing IVR paths: the report IV01 - IVR Traversals. This way you can see which paths were traversed, how many calls went through each path and what happened to them. This is very useful as it is the key to understanding attrition - people hanging up without having reached a goal.

  • Tracing IVR timings: the report IV02 - IVR Timing. By understanding the timing statistics of each IVR menu, you can improve the user experience by making often-accessed items higher on the menus and on top of the tree. This improves user satisfaction and saves circuit usage.

  • Tracing IVR goals: the report IV03 - IVR Goals. For each goal, what path traversal tree was followed, how much it took for it to be traversed as average / min / max times.

  • IVR call details: all calls that were not queued are available in the IVR call details, under the codes OD04 - IVR details (paged) and OD05 - IVR details (full list).

The detailed description of each data block is visible in the relevant manual section.

Using IVR areas

Considering an IVR call as a possible ancestor of any queued call on the system is often overkill. Very often you are able to tell - for example, based on the DNIS or the caller-id - the "area" that the call pertains to. If this does not happen, calls tracked at the IVR level do not belong to a queue but are possible ancestors of any queue – and therefore appear in the IVR and attrition reports for any queue.

Though this requirement is formally correct (as the main reason for having an IVR offered is routing the caller into the correct queue) it often happens that at some point during the call life-cycle, before the call is connected to a queue, you can determine an “area” of interest that may or may not be a specific queue.

For example, if your call center services multiple clients, you will likely have a separate DNIS for each. When that DNIS is called, maybe you do not yet know if the call will be connected to client7-sales or client7-support, but you are sure that it will be for client7, so it will be inappropriate to show that call as a general untagged ancestor to any call queued on the system.

Tagging calls by area in the QueueMetrics security system

The QueueMetrics security system is built so that only information pertaining to the queues an user has express permission on are accessible for reporting or monitoring.

As the unit of access is the queue, we had find an access token that acts "as-if" it was a proper queue. We call this "area" and we will log this to the queue_log in the general queue field.

This makes it possible to decide on which areas the reports should run by adding the areas to the allowed queues for a specific report, as you would generally do when creating a composite queue.

For instance, to implement the example above, you might be reporting on a composite queue defined as ivr-client7|client7-sales|client7-support.

A call starts it life-cycle by belonging to area NONE, then starts belonging to an area as soon as one is specified, and starts belonging to a queue as soon as it hits one. Neither behavior is reversible.

The following visibility rules apply:

IVR call - area = NONE (c.1) IVR call - area set (c.2) IVR call - queue reached (c.3)

Any report for any queue

Visible

-

-

Reports for destination queue(s) only

Visible

Not Visible

Visible

Reports for area(s) and destination queue(s)

Visible

Visible

Visible

The initial QueueMetrics IVR tracking only implemented columns #1 and #3 of the table above. By adding the "areas" as in column #2:

  • Existing systems are backwards-compatible; the behavior does not change unless you specify an area for a call;

  • You are free - if you want - to specify an area immediately, so that the behavior specified in column #1 does never happen on your system.

Using areas

The following general rules apply to areas:

  • A call is displayed in QueueMetrics as belonging to the last area or queue it was showing at its termination or by the end of the requested time-frame.

  • An area is set on the first call verb having an area different from NONE. This may or may not be the first tracking verb on the call.

  • You cannot specify an area of NONE after a call had an area specified. This behavior is implemented in order to avoid logging the area on each IVR key-press on manually-created dial-plans. If you do, the area is not changed

  • If you specify a different area for the call, the new code replaces the old one.

  • When a call finally enters a queue, the queue code replaces the area code

The area name might be any valid name in Asterisk (lowercase ascii7 string, not containing spaces or pipes). Uppercase names are automatically lowercased upon reading. It is perfectly allowable to use the very same code for a queue and an area.

We suggest using name similar to "ivr-abc" in order to make it clear it is not a normal queue.

In cases where the IVR tree is extremely complex, you might want to specify multiple areas for the same call. In this case, when you run a report, you must specify all the different areas that make up your IVR tree as the allowed queue(s) for the report. As always:

  • Any call which final state was without an area will be visible in all reports.

  • Any call which final state is in a certain area is only visible to users having that area defined as a possible queue

Implementing IVR tracking

In order to track IVR data, we need to tell QM a few bits of infromation:

  • When a digit is pressed, the time-stamp when the event happens, the digit pressed and the name of the IVR menu. These are logged through the verb INFO-IVRAPPEND

  • When a call is started, you may want to log the moment when the call reaches the PBX; the calling number and optionally the calling DID. This is done through INFO-IVRSTART and it is optional

  • When a goal is reached, you may want to log the name of the goal. This is done through INFO-IVRGOAL and it is optional

  • When a call is hung up in the IVR, you may want to log this information in order to have detailed IVR timing. This is done through INFO-IVRHANGUP and it is optional.

Before QueueMetrics 13.03, QueueMetrics used to track IVR sequences as one single record containing the digit sequence and optionally a second entry tracking IVR wait time. Though this is still recognized by QueueMetrics, it is impossible to run traversal analyses on such data as the required information is not present.
Dial-plan tracking

In order to implement dial-plan tracking, the unique-id logged must match the unique-id of the call leg that will reach the queue.

In order to track the beginning of a call, you should produce an INFO IVRSTART record like the following one:

1353461650|1353461627.33271|NONE|NONE|INFO|IVRSTART|1234|5556777

This way you track both the caller-id of the caller ("1234" in or case) and the DNIS the call came though ("5556777" in our case). You may leave either field blank if that information is not needed.

The record above is optional - if it is missing calls will be tracked from the first IVR menu, and the traversal time for that IVR menu will be set to zero.

In order to track an IVR digit, you would use the following format:

1353461660|1353461627.33271|NONE|NONE|INFO|IVRAPPEND|1|ivr-2

In this case, we tell QM that the key 1 was pressed in IVR "ivr-2". The IVR event duration (that is, how much it took the caller to make a selection) is automatically inferred from the end of the previous event. If this is not the case, you have an option to pass it explicitly to QM as the last paramenter (6 seconds in the case shown):

1353461670|1353461627.33271|NONE|NONE|INFO|IVRAPPEND|1|ivr-2|6

If a goal is reached, you should mark this by producing a record like:

1353461680|1353461627.33271|NONE|NONE|INFO|IVRGOAL|attendant3|ivr-2|6

The goal in this case is called "attendant3". The IVR name is optional an not currently used. The explicit timing duration is optional.

A call can have only one goal. Any call hitting a queue is considered to having reached a goal.

In order to tell QM that a call hung-up in an IVR, you should produce a record like:

1353461660|1353461627.33271|NONE|NONE|INFO|IVRHANGUP|
Tracking areas

The logging is changed so that the INFO verbs allows the reading of this piece of information. So any sub-verb (e.g. INFO DNIS, INFO IVRSTART, INFO IVRAPPEND and more) will work correctly with this.

An example of logging might be:

1345678|1234.5678|IVR-1|NONE|INFO|IVRSTART|1234|12345

This logs the IVRSTART as belonging to area IVR-1.

It is perfectly valid to assign a call to an area from a specific point in time onwards (generally because they made a defining IVR decision)

1345668|1234.5678|NONE|NONE|INFO|IVRSTART|1234|12345
1345679|1234.5678|IVR-3|NONE|INFO|IVRAPPEND|3|MYMENU

As shown above.

Deprecated IVR tracking verbs

The following records are understood by QM but should not be used anymore:

1000000|214530.A|sk-fissi|NONE|INFO|IVRWAIT
1000000|214530.A|sk-fissi|NONE|INFO|IVR|345
The FreePBX module

Since FreePBX 2.11 a new module is available on the FreePBX SVN repository. This module allows to easily integrate FreePBX IVR with QueueMetrics. The module will be published shortly and will be available through the standard FreePBX modules administration page. Till this date, you could manually install the module following the below steps. In a command shell, type the code:

svn co http://svn.freepbx.org/modules/branches/2.11/queuemetrics
tar -cvf queuemetrics-2.11.0.1.tar queuemetrics/
gzip queuemetrics-2.11.0.1.tar

This generates a queuemetrics-2.11.0.1.tar.gz module you can install on your FreePBX box.

In the FreePBX modules administration page press the "Upload modules" button.

image308

Browse to the queuemetrics-2.11.0.1.tar.gz file you downloaded from the FreePBX repository.

image309

then press "Upload" to store the file on your FreePBX box.

image310

You will find the module in the modules administration page.

image311

Click on it then select the "Install" option. Click on "Process" at the bottom of the page.

image312

Then confirm.

image313

At the end of the procedure you will find a new option on the Settings menu.

image314

This opens a new page settings where you can enable the QueueMetrics IVR log routines.

image315