Troubleshooting UCCX Outbound Dialer Agent Based Preview Campaigns

It had been years, maybe 10 years, since I had done dialer campaigns on Cisco Contact Center Express (UCCX). I recently got a chance to do a deep dive to some SFDC integration I did and I wanted to capture how to track a call via the UCCX logs. What we will be coving is an UCCX outbound campaign that is agent based and preview. Next you need a CSV or use the API to load a new call list. Login the agent to Finesse and a preview call will be presented to the agent. If the agent accepts the preview and the customer is then dialed out. Otherwise the agent could end the call or schedule a callback if it was accepted. The steps below walk you through every single step.

Trace levels you should have set in UCCX Serviceability:
SS_OB: Debugging, XDebugging1, XDebugging2
SS_RM: Debugging, XDebugging1
SS_RMCM: Debugging

You’re going to need RTMT and Notepad++.

  • Start with getting the ANI of the record that you were going to dial and downloading the MIVR and JTAPI logs.
  • Using RTMT download the Cisco Unified CCX Engine and Cisco Unified CCX JTAPI Client logs from your server for the time frame needed.
  • Go to the logs downloaded MIVR directory and unzip all files and leave in place.
  • Open Notepad++ Find in Files, choose the location C:\YourServer\YourTimeStamp\uccx\log and search for the ANI sent to the dialer.
Notepad++ Search Settings

Notepad++ Search Settings

  • Start with any hits in your JTAPI folder. This will tell you the calls placed to your ANI and correlate it to an agent extension. The below example show 3 total calls made to that ANI by an agent. This is across 3 different JTAPI logs.
    CiscoJtapi041.log

17467378: Sep 07 13:53:41.861 CST %JTAPI-JTAPI-7-UNK:(P2-ccxrmcm)[pool-26-thread-1193][(P2-ccxrmcm) GCID=(1,15759614)->IDLE]Request: connect (CSFdavidmacias, 155551, 912145551234featurePriority=1)17467379: Sep 07 13:53:41.861 CST %JTAPI-PROTOCOL-7-UNK:(P2-1.1.1.30) [pool-26-thread-1193] sending: com.cisco.cti.protocol.LineCallInitiateRequest {sequenceNumber = 41195lineCallManagerID = 4lineID = 35553globalCallManagerID = 1globalCallID = 15759614callingAddress = 155551destAddress = 912145551234userData = nullmediaDeviceName = mediaResourceId = 0featurePriority = 1}

CiscoJtapi043.log

17485516: Sep 07 14:00:54.648 CST %JTAPI-JTAPI-7-UNK:(P2-ccxrmcm)[pool-26-thread-1196][(P2-ccxrmcm) GCID=(1,15759713)->IDLE]Request: connect (CSFdavidmacias, 155551, 912145551234featurePriority=1)17485517: Sep 07 14:00:54.648 CST %JTAPI-PROTOCOL-7-UNK:(P2-1.1.1.30) [pool-26-thread-1196] sending: com.cisco.cti.protocol.LineCallInitiateRequest {sequenceNumber = 41214lineCallManagerID = 4lineID = 35553globalCallManagerID = 1globalCallID = 15759713callingAddress = 155551destAddress = 912145551234userData = nullmediaDeviceName = mediaResourceId = 0featurePriority = 1}

CiscoJtapi046.log

17516022: Sep 07 14:15:45.225 CST %JTAPI-JTAPI-7-UNK:(P2-ccxrmcm)[pool-26-thread-1200][(P2-ccxrmcm) GCID=(1,15759923)->IDLE]Request: connect (CSFdavidmacias, 155551, 912145551234featurePriority=1)17516023: Sep 07 14:15:45.225 CST %JTAPI-PROTOCOL-7-UNK:(P2-1.1.1.30) [pool-26-thread-1200] sending: com.cisco.cti.protocol.LineCallInitiateRequest {sequenceNumber = 41258lineCallManagerID = 4lineID = 35553globalCallManagerID = 1globalCallID = 15759923callingAddress = 155551destAddress = 912145551234userData = nullmediaDeviceName = mediaResourceId = 0featurePriority = 1}

  • Next we need to see what the engine sees for that ANI on the same search you did before open the earliest MIVR log that shows the ANI in question. You need to find the record id for your specific call, this record id is how the outbound subsystem tracks the call. This means that while you start the search with your ANI, subsequent searching will be based on this record id. Below are two examples of how to locate the record id: 15541. Additionally, you see what was imported into UCCX. You can now validate that the data received by UCCX was the data you sent.

125439796: Sep 07 13:53:16.034 CST %MIVR-CFG_MGR-7-UNK: [MIVR_SS_OB_ReadContactsThread-750-0-ReadContactsThread] com.cisco.config.impl.ConfigManagerImpl ConfigManagerImpl-getAll():CIR[0]=ConfigImportRecord[schema=DialingListConfig#4,time=2024-03-05 13:53:13.0,recordId=15541,implClass=class com.cisco.crs.outbound.DialingListConfig,desc=,values=[15541, 30, 5008DM, Other.wav, Agent, 912145551234, , , 92, true, -1, true, -1, true, , 2024-03-05 19:53:13.0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, 0, null, null, null],evalues=null]125439797: Sep 07 13:53:16.034 CST %MIVR-CFG_MGR-7-UNK: [MIVR_SS_OB_ReadContactsThread-750-0-ReadContactsThread] com.cisco.config.impl.ConfigManagerImpl ConfigManagerImpl-getAll():configObjs[0]=DialingListConfig[schema=DialingListConfig#4,time=2024-03-05 13:53:13.0,recordId=15541,desc=,recordID=0,dialingListID=15541,campaignID=30,accountNumber=5008DM,firstName=Other.wav,lastName=Agent,phone01=912145551234,phone02=,phone03=,gmtZonePhone01=92,dstPhone01=true,gmtZonePhone02=-1,dstPhone02=true,gmtZonePhone03=-1,dstPhone03=true,callbackNumber=,callbackDateTime=2024-03-05 19:53:13.0,callStatus=1,callResult=0,callResult01=0,callResult02=0,callResult03=0,lastNumberDialed=0,callsMadeToPhone01=0,callsMadeToPhone02=0,callsMadeToPhone03=0,numMissedCallback=0,retry=false,callsMadeToCallbackNum=0]

  • Next we want to find out who all was offered this call. Using Notepad++ Find in Files, same location, using a regular expression with your record id: associateContactToReservedAgent.*dlc:15541.
Notepad++ Search Settings Regular Expression

Notepad++ Search Settings Regular Expression

  • This will give you who the call was sent to and at what time. In my case you can match these 3 calls to the JTAPI calls above.

125443434: Sep 07 13:53:39.146 CST %MIVR-SS_OB-7-UNK: [MIVR_SS_OB_OutboundMgrMsgProcessor-192-0-OutboundMgrMsgProcessor] com.cisco.wf.subsystems.outbound.PreviewDialer PreviewDialer:associateContactToReservedAgent() rsrc:Rsrc Name:David Macias ID:dmacias IAQ Extn:155551 for contact:OutboundContactInfo: dlc:15541 (phoneNumber:912145551234 unformattedPhoneNumber:912145551234 timezone -360 callStartTime 0 answeringMachine false )

125505817: Sep 07 14:00:49.286 CST %MIVR-SS_OB-7-UNK: [MIVR_SS_OB_OutboundMgrMsgProcessor-192-0-OutboundMgrMsgProcessor] com.cisco.wf.subsystems.outbound.PreviewDialer PreviewDialer:associateContactToReservedAgent() rsrc:Rsrc Name:David Macias ID:dmacias IAQ Extn:155551 for contact:OutboundContactInfo: dlc:15541 (phoneNumber:912145551234 unformattedPhoneNumber:912145551234 timezone -360 callStartTime 0 answeringMachine false )

125632982: Sep 07 14:15:39.532 CST %MIVR-SS_OB-7-UNK: [MIVR_SS_OB_OutboundMgrMsgProcessor-192-0-OutboundMgrMsgProcessor] com.cisco.wf.subsystems.outbound.PreviewDialer PreviewDialer:associateContactToReservedAgent() rsrc:Rsrc Name:David Macias ID:dmacias IAQ Extn:155551 for contact:OutboundContactInfo: dlc:15541 (phoneNumber:912145551234 unformattedPhoneNumber:912145551234 timezone -360 callStartTime 0 answeringMachine false )

As you saw in the JTAPI logs and above, the same record was called multiple times. One likely reason is that an agent scheduled a callback, but how do we confirm this? This part is not as clean as I would like, but the following process should give you a decent idea if a callback was rescheduled or not.

#This is the original record being set. Notice the callbackDateTime.
125445090: Sep 07 13:53:43.726 CST %MIVR-CFG_MGR-7-UNK: [MIVR_SS_OB_SaveContactsMsgProcessor-198-0-SaveContactsMsgProcessor] com.cisco.config.impl.ConfigStubImpl configStubImpl-replace() exporting object: DialingListConfig[schema=DialingListConfig#4,time=2024-03-05 13:53:13.0,recordId=15541,desc=,recordID=0,dialingListID=15541,campaignID=30,accountNumber=5008DM,firstName=Other.wav,lastName=Agent,phone01=912145551234,phone02=,phone03=,gmtZonePhone01=92,dstPhone01=true,gmtZonePhone02=-1,dstPhone02=true,gmtZonePhone03=-1,dstPhone03=true,callbackNumber=,callbackDateTime=2024-03-05 19:53:13.0,callStatus=3,callResult=1,callResult01=1,callResult02=0,callResult03=0,lastNumberDialed=1,callsMadeToPhone01=1,callsMadeToPhone02=0,callsMadeToPhone03=0,numMissedCallback=0,retry=false,callsMadeToCallbackNum=0]
#Notice that the callbackDateTime is now set to 20:15:33. One thing to note is that while the time stamp says the server’s time zone it’s actually UTC and the callback will happen at 20:15:33 UTC.
125451126: Sep 07 13:54:33.558 CST %MIVR-CFG_MGR-7-UNK: [MIVR_SS_OB_SaveContactsMsgProcessor-198-0-SaveContactsMsgProcessor] com.cisco.config.impl.ConfigStubImpl configStubImpl-replace() exporting object: DialingListConfig[schema=DialingListConfig#4,time=2024-03-05 13:53:13.0,recordId=15541,desc=,recordID=0,dialingListID=15541,campaignID=30,accountNumber=5008DM,firstName=Other.wav,lastName=Agent,phone01=912145551234,phone02=,phone03=,gmtZonePhone01=92,dstPhone01=true,gmtZonePhone02=-1,dstPhone02=true,gmtZonePhone03=-1,dstPhone03=true,callbackNumber=,callbackDateTime=Tue Mar 05 20:15:33 CST 2024,callStatus=4,callResult=8,callResult01=8,callResult02=0,callResult03=0,lastNumberDialed=1,callsMadeToPhone01=1,callsMadeToPhone02=0,callsMadeToPhone03=0,numMissedCallback=0,retry=false,callsMadeToCallbackNum=0]
#Repeat of the above change.
125451194: Sep 07 13:54:33.853 CST %MIVR-CFG_MGR-7-UNK: [MIVR_SS_OB_SaveContactsMsgProcessor-198-0-SaveContactsMsgProcessor] com.cisco.config.impl.ConfigStubImpl configStubImpl-replace() exporting object: DialingListConfig[schema=DialingListConfig#4,time=2024-03-05 13:53:13.0,recordId=15541,desc=,recordID=0,dialingListID=15541,campaignID=30,accountNumber=5008DM,firstName=Other.wav,lastName=Agent,phone01=912145551234,phone02=,phone03=,gmtZonePhone01=92,dstPhone01=true,gmtZonePhone02=-1,dstPhone02=true,gmtZonePhone03=-1,dstPhone03=true,callbackNumber=912145551234,callbackDateTime=Tue Mar 05 20:15:33 CST 2024,callStatus=4,callResult=8,callResult01=8,callResult02=0,callResult03=0,lastNumberDialed=1,callsMadeToPhone01=1,callsMadeToPhone02=0,callsMadeToPhone03=0,numMissedCallback=0,retry=false,callsMadeToCallbackNum=0]
#Repeat of the above change.
125508618: Sep 07 14:01:06.354 CST %MIVR-CFG_MGR-7-UNK: [MIVR_SS_OB_SaveContactsMsgProcessor-198-0-SaveContactsMsgProcessor] com.cisco.config.impl.ConfigStubImpl configStubImpl-replace() exporting object: DialingListConfig[schema=DialingListConfig#4,time=2024-03-05 13:53:13.0,recordId=15541,desc=,recordID=0,dialingListID=15541,campaignID=30,accountNumber=5008DM,firstName=Other.wav,lastName=Agent,phone01=912145551234,phone02=,phone03=,gmtZonePhone01=92,dstPhone01=true,gmtZonePhone02=-1,dstPhone02=true,gmtZonePhone03=-1,dstPhone03=true,callbackNumber=912145551234,callbackDateTime=2024-03-05 20:15:33.0,callStatus=3,callResult=1,callResult01=8,callResult02=0,callResult03=0,lastNumberDialed=4,callsMadeToPhone01=1,callsMadeToPhone02=0,callsMadeToPhone03=0,numMissedCallback=0,retry=false,callsMadeToCallbackNum=1]
#New callbackDateTime set.
125514552: Sep 07 14:01:30.954 CST %MIVR-CFG_MGR-7-UNK: [MIVR_SS_OB_SaveContactsMsgProcessor-198-0-SaveContactsMsgProcessor] com.cisco.config.impl.ConfigStubImpl configStubImpl-replace() exporting object: DialingListConfig[schema=DialingListConfig#4,time=2024-03-05 13:53:13.0,recordId=15541,desc=,recordID=0,dialingListID=15541,campaignID=30,accountNumber=5008DM,firstName=Other.wav,lastName=Agent,phone01=912145551234,phone02=,phone03=,gmtZonePhone01=92,dstPhone01=true,gmtZonePhone02=-1,dstPhone02=true,gmtZonePhone03=-1,dstPhone03=true,callbackNumber=912145551234,callbackDateTime=Tue Mar 05 20:30:30 CST 2024,callStatus=4,callResult=8,callResult01=8,callResult02=0,callResult03=0,lastNumberDialed=4,callsMadeToPhone01=1,callsMadeToPhone02=0,callsMadeToPhone03=0,numMissedCallback=0,retry=false,callsMadeToCallbackNum=2]
#Repeat of the above change.
125514631: Sep 07 14:01:31.247 CST %MIVR-CFG_MGR-7-UNK: [MIVR_SS_OB_SaveContactsMsgProcessor-198-0-SaveContactsMsgProcessor] com.cisco.config.impl.ConfigStubImpl configStubImpl-replace() exporting object: DialingListConfig[schema=DialingListConfig#4,time=2024-03-05 13:53:13.0,recordId=15541,desc=,recordID=0,dialingListID=15541,campaignID=30,accountNumber=5008DM,firstName=Other.wav,lastName=Agent,phone01=912145551234,phone02=,phone03=,gmtZonePhone01=92,dstPhone01=true,gmtZonePhone02=-1,dstPhone02=true,gmtZonePhone03=-1,dstPhone03=true,callbackNumber=912145551234,callbackDateTime=Tue Mar 05 20:30:30 CST 2024,callStatus=4,callResult=8,callResult01=8,callResult02=0,callResult03=0,lastNumberDialed=4,callsMadeToPhone01=1,callsMadeToPhone02=0,callsMadeToPhone03=0,numMissedCallback=0,retry=false,callsMadeToCallbackNum=0]
#Repeat of the above change.
125635076: Sep 07 14:15:54.719 CST %MIVR-CFG_MGR-7-UNK: [MIVR_SS_OB_SaveContactsMsgProcessor-198-0-SaveContactsMsgProcessor] com.cisco.config.impl.ConfigStubImpl configStubImpl-replace() exporting object: DialingListConfig[schema=DialingListConfig#4,time=2024-03-05 13:53:13.0,recordId=15541,desc=,recordID=0,dialingListID=15541,campaignID=30,accountNumber=5008DM,firstName=Other.wav,lastName=Agent,phone01=912145551234,phone02=,phone03=,gmtZonePhone01=92,dstPhone01=true,gmtZonePhone02=-1,dstPhone02=true,gmtZonePhone03=-1,dstPhone03=true,callbackNumber=912145551234,callbackDateTime=2024-03-05 20:30:30.0,callStatus=3,callResult=1,callResult01=8,callResult02=0,callResult03=0,lastNumberDialed=4,callsMadeToPhone01=1,callsMadeToPhone02=0,callsMadeToPhone03=0,numMissedCallback=0,retry=false,callsMadeToCallbackNum=1]

  • So now how do you confirm that the record is complete and there will be no more callbacks. Let’s look at the log lines above and zero in on callStatus and callResult. Status (3:Closed, 4:Callback). Result (1:Voice, 8:Callback). You need to look at all the lines to get a picture if there will be another call or not. In our case the last log found has a status of close and a result of voice with no new records. Signifying that this is now close and done. I wish it was more clear, but this is the best I could find.

    125445090: …callStatus=3,callResult=1,callResult01=1…
    125451126: …callStatus=4,callResult=8,callResult01=8…
    125451194: …callStatus=4,callResult=8,callResult01=8…
    125508618: …callStatus=3,callResult=1,callResult01=8…
    125514552: …callStatus=4,callResult=8,callResult01=8…
    125514631: …callStatus=4,callResult=8,callResult01=8…
    125635076: …callStatus=3,callResult=1,callResult01=8…

    You can find all values here.

~david

Read Only Script Editor Access in PCCE

This question came up this past week and I had a nagging suspicion it wasn’t the case and spent some time trying to get it to work. In the good old days of UCCE Config Manager had the Feature Control set capability which allowed users to have a limited view to the ICM Script Editor. This was great for those type of users who understood the scripting, but were not trained up enough to make changes.

The PCCE 11 documentation seems to hint at this being possible. You create a read-only Administrator and then you give them Script Editor access. I understand this is a huge leap, but it is not an unreasonable assumption. However, the 12.6 documentation removed that information as well removed the ability of having read-only administrator. It appears that your only option in CCE Admin > Users > Roles is to remove all access to Script Editor The following role:

Capture

Has this effect:

Capture1

If you add the Script Editor role again your user has full access to Script Editor again. So to summarize, it’s not possible to have a read only Script Editor user. I would love to be proven wrong. For now I hope this helps others out there looking for the answer.

~david

A Deeper Dive Into the Cisco Finesse Layout

I’ve been helping a customer migrate from Cisco’s Unified Contact Center Enterprise (UCCE) 11 to UCCE 12 and Amazon Connect. Depending on the complexity and needs of the business they might move to UCCE 12 or they might be moved to Connect. This has caused me to spend some time thinking of the most efficient way to migrate configuration between multiple environments and ensure everything is up to date.

One of the components which I’ve done a lot of work with, but never really looked at too closely is the Finesse layout. In this post we’ll break down what layouts are, how they work, and provide some interesting pieces of trivia around Finesse. This information is up to date as of Finesse 12.5. Make sure you reference the documentation for your specific version.

BACKGROUND

To start, the Finesse front end, what the agent and administrators see, are based on the OpenSocial specification. What this specification provides is a runtime environment where trusted and untrusted web components or gadgets can interact with the hosting platform, 3rd party services, or with other gadgets. Said differently, this specification sets the rules. It dictates how components will look, where they are placed, and what they can do. While the OpenSocial foundation no longer exists. At one point the foundation was moved under W3C where it was then set to inactive in 2018. The latest specification can be found living here.

An interesting bit of trivia. One of the original developers of OpenSocial was none other than MySpace. Remember them?

You will hear the word gadget multiple times and it is worth defining as it is a core block of Finesse. The best way to think about a gadget is as an application which can be embedded inside another application. If you’re familiar with widgets, you should consider gadgets to be very similar in nature. Now, something a lot of us fail to remember is that all of Finesse is actually one big gadget with a lot of smaller gadgets inside. While you can’t replace the whole gadget that runs on the Finesse server, you can add your own gadgets inside the Finesse gadget using a layout.

XML

The very first thing you need to understand is that like all things Cisco Contact Center Enterprise and Express you must be very familiar with working with XML. While XML has lost a lot of favor in the last few years, when it comes to desktop layouts, using XML makes a lot of sense. While editing a layout can be confusing, Cisco does a good job of assisting with basic syntax checking to catch simple errors. In an ideal world there would be a visualizer that previews the changes you’re making to your layout before saving them. Maybe one day.

The XML file loaded must conform to this schema. The schema is what dictates what tags your layout can have as well as naming conventions for components. 

The XML schema has the following elements defined. These are not in the order they appear in the schema, but I’ve ordered in a hierarchical way to better highlight their relationship. Additionally, there are other elements included in the schema which are not covered below. The list below shows the most important elements to read through to better understand a Finesse layout:

  • finesseLayout: Think of this as the outer boundaries of the whole desktop.
  • layout: The actual layout.
  • role: Role definition.
  • tabs: Grouping of tabs.
  • tab: Each single tab.
  • page: The grouping of gadgets within that page referenced by a tab.
  • columns: Grouping of columns.
  • column: Each single column.
  • gadget: The actual gadget URL.

Another interesting bit of trivia. The XML schema allows for three types of Finesse users: Agent, Supervisor, and Admin. While the desktop layout never references Admins the schema has an additional role that Cisco could later enable or currently uses for publicly restricted functions.

DESKTOP LAYOUTS

The layout is what dictates what will be loaded when an agent or supervisor login to Finesse. More importantly, it allows for the organization of different gadgets on the page to fit your contact center requirements. At its core the layout includes the following sections:

  • Horizontal Header: This section is the top bar across Finesse. And includes a Logo, Product Name, Agent State for Voice, State for Digital Channels, Dialer Component, and Identity Component. For most installations you’ll only ever see the logo, name, voice state, and identity components.
  • Alternate Hosts
  • Title and Logo in Header
  • Headless Configuration: If your gadget does not require a UI.
  • Customized Icons

Interesting tip: Most gadgets can be dragged and dropped and resized by agents, however out of the box this feature is disabled. To enable it look at the enableDragDropAndResizeGadget config key.

DEFAULT GADGETS

Out of the box you should see the following gadgets:

  • Call Control
  • Queue Statistics
  • Agent Call History
  • Agent State History
  • Customer Context
  • Team Data (Supervisor)

Additionally there are a good bit of disabled gadgets that you can use they all revolve around bringing CUIC data, specifically Live Data, to the agent desktop.

I hope to have time to dive deeper on this topic. There are so many little morsels of information every where you look, you just have to dig a little deeper to find them.

~david

Find specific phone number in Finesse phone books through the Finesse API using Python

Here’s a quick Python script that will allow you to go through each phone book in Finesse and identify the phone book that has the phone number(s) you’re after. Just fill in your information ‘<>’ and update the numbers you want to find.

import requests # for using API
from requests.auth import HTTPBasicAuth
import xml.etree.ElementTree as ET # for parsing XML

requests.packages.urllib3.disable_warnings() #If using a self signed certificate

rootURL = ‘<>’ # e.g. http://finesse.company.com
phonebooksURL = ‘/finesse/api/PhoneBooks’
username = ‘<>’ #Finesse admin username
password = ‘<>’

headers = {‘Accept’: ‘application/xml’, ‘Content-Type’: “application/xml”}

phonenumbers = [‘5555551234’, ‘5555551235’, ‘5555551236’, ‘5555551237’] #phone numbers you want to find.

res = requests.get(rootURL+phonebooksURL, headers= headers, verify=False, auth=HTTPBasicAuth(username, password))
print(res.status_code)

root = ET.fromstring(res.content)

for phonebooks in root:
phonebookId = phonebooks[3].text
res = requests.get(rootURL+phonebookId+’/Contacts’, headers=headers, verify=False, auth=HTTPBasicAuth(username, password))
print(res.status_code)
root = ET.fromstring(res.content)
for contacts in root:
for number in phonenumbers:
if number in contacts[3].text:
print(phonebooks[2].text, contacts[3].text)

~david

Audacity Export Encoding

Generating telephony audio prompts with Audacity on Windows and Mac

This blog post should be pretty basic, but in the last few months I’ve had two different parties ask me about this so I figured I would capture this for posterity. If you want to use Audacity to convert your audio file to a compatible format that can play in your Cisco UCCX or CCE call center or any system that uses CCITT u-Law 8.000 Khz, 8 Bit, Mono format.

Assuming you’re running the latest version of Audacity (I’m using version 3.1.3 on both Windows and Mac). Open the audio file you wish to convert. There are 3 settings you must change.

  • The format needs to be set to PCM 16-bit.
  • Project Rate (Hz) needs to be set to 8000.
Audacity Format and Rate

Audacity Format and Rate

  • File > Export > Export as WAV and ensure you set the right encoding.
Audacity Export Encoding

Audacity Export Encoding

That’s it, you’re good to go.

~david

2022 Cisco Designated VIP

I am pretty jazzed for making this awesome list for the second year in a row. The amount of brain power that you can find in the Cisco community forums is insane and being grouped with them is an honor. I really appreciate the recognition from Cisco.

As an added bonus I looked back for my very first post on the community forums. It happened on 02/14/2006, almost 16 years ago. I don’t remember the specific project I was working on, but it involved IPCC Express 3.x… :)

~david

Adding Text to Speech to Your IVR Using SaaS (Google Cloud Functions)

I’ve been on a text-to-speech and speech-to-text kick lately. My last post talked about using AWS S3 and Amazon Transcribe to convert your audio files to text and in previous articles I’ve covered how to create temporary prompts using Poly so you can build out your contact center call flows. Well, now we’re going to expand our use case to allow a traditional on premise call center to leverage the cloud and provide dynamic prompts. My use case is simple. I want my UCCX call center to dynamically play some string back to my caller without having to use a traditional TTS service.

First, this is not new in any way and other people have solved this in different ways. This Cisco DevNet Github repo provides a method to use voicerss.org to generate TTS for UCCX. However, this process requires loading a jar file in order to do Base64 decoding. Then there’s this Cisco Live presentation from 2019, by the awesome Paul Tindall, who used a Connector server to do something similar. To be fair the Connector server allowed for a ton more functionality than what I’m looking for.

Screen Shot 2021-09-15 at 3.38.30 PM

Cisco Live Presentation

Second, I wanted this functionality to be as easy to use as possible. While functionality keeps getting better for on premise call center software there are still limitations around knowledge to leverage new features and legacy version that can’t be upgraded that makes it harder to consume cloud based services. I wanted the solution to require the least amount of moving parts possible. That means no custom Java nor additional servers to stand up.

The solution I came up with leverages Google’s cloud (GCP) specifically Cloud Functions. However, the same functionality can be achieves used AWS Lambda or Azure’s equivalent. At a high level we have an HTTP end point where you pass your text string to and in return you will get a wav file in the right format which you can then play back.

Blank diagram

Flow Diagram

The URL would look something like this:

https://us-central1-myFunction.cloudfunctions.net/synthesize_text_to_wav?text=American%20cookies%20are%20too%20big

The Good Things About This

  • Pay as you go pricing for TTS. Looking at the pricing calculator a few hours of TTS a month would run under $2.00/month.
  • Infinitely scalable. If you’re handling 1 call or 100 calls your function will always return data.
  • Easy to use.

The Bad Things About This

  • There is a delay between making the request and getting the wav file. I’ve seen as long as 7 seconds at times. I would only use this in a very targeted manner and ensure it didn’t affect the caller experience too drastically.
  • Requires your on premise IVR to have internet access. Often time this is a big no no for most businesses.

Some initial testing with UCCX is showing some positive results. I’m going to investigate if there’s a way to accelerate the processing in order to keep the request and response in under 3 seconds as well as adding the ability to set language, voice, and even SSML via arguments. If you want to build this yourself here’s the code for the function.

def synthesize_text_to_wav(request):
"""Synthesizes speech from the input string of text."""
text = request.args.get('text')

client = texttospeech.TextToSpeechClient()
input_text = texttospeech.SynthesisInput(text=text)
voice = texttospeech.VoiceSelectionParams(
language_code="en-US",
name="en-US-Standard-C",
ssml_gender=texttospeech.SsmlVoiceGender.FEMALE,
)
audio_config = texttospeech.AudioConfig(
audio_encoding=texttospeech.AudioEncoding.MP3
)
response = client.synthesize_speech(
request={"input": input_text, "voice": voice, "audio_config": audio_config}
)

src_file_path = '/tmp/output.mp3'
dst_file_path = '/tmp/output.wav'

# make sure dir exist
os.makedirs(os.path.dirname(src_file_path), exist_ok=True)

# The response's audio_content is binary.
with open(src_file_path, "wb") as out:
out.write(response.audio_content)
print('Audio content written to file "output.mp3"')
AudioSegment.from_mp3(src_file_path).export(dst_file_path, format="wav", codec="pcm_mulaw", parameters=["-ar","8000"])
return send_file(dst_file_path

Be awesome!

~david

Update to Installing Multiple CVP Studio Versions

I was installing CVP Studio 12.5 on one of my VMs and referred back to this old blog post of mine when I realized I had missed on critical piece of information. If the installer complains that an upgrade is not supported:

[5-17-2021 17:55:31] Informational: ————————————————————
[5-17-2021 17:55:31] Informational: Starting Studio upgrade procedure…
[5-17-2021 17:55:31] Informational: User presented w/MessageBox: <Upgrade is not supported for Cisco Unified Call Studio.
Please do uninstall the older version and then install the newer version.>
[5-17-2021 17:55:37] WARNING: This installation has been aborted.

Look inside the following registry location: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall In that folder do a search for CallStudio. Export that registry key’s folder and then delete it. After that you should be able to install as many CVP Studio versions as you need. Below is one of my VMs running 3 different versions. The export is as a backup in case you need to restore what you changed.

Screen Shot 2021-05-17 at 9.12.07 PM

Please note that uninstalling CVP Studio after doing this doesn’t really work well or at all. So caveat emptor.

~david

Microsoft and Nuance a Brilliant Play for Redmond

Bloomberg reports that Microsoft “is in advanced talks” to purchase Nuance. I’ve not been able to stop thinking of this move and I’ll be the first to admit that it surprised me, but the more I think about it and the more I talk to others in the industry this is an absolutely brilliant move. Here are my crystal ball predictions:

The patent play: Nuance comes with over 2000 patents. This is a huge cache which will no doubt be useful for the upcoming AI wars. This will be a huge boosts to Microsoft’s already huge R&D commitment in this space.

This hospital bill is brought to you by Microsoft: Nuance makes the majority of their money from the healthcare sector. We’re not talking just dictations or document management, we’re talking EHR, billing, and diagnosis software. Windows and Office are already prevalent in the healthcare space, this puts MS in the heart (get it?) of hospital operations and processes.

Cortana, it was the best of times it was the worst of times: Did you know that Windows 10 was Cortana’s big debut in the desktop space? Yeah neither did anyone else. Cortana began in 2014 as a direct competition to Alexa which was released the year before. At the time Microsoft was beginning to make some heavy bets in to the mobile space with Windows mobile. Well it’s a decade later and Windows mobile is dead, Cortana’s OS integration has been neutered and I’ve never seen another human being speak to their Windows PC. I believe this is going to change that with a huge marketing push of some college student dictating their final paper to their Microsoft Surface device while getting a manicure.

Where we’re going we don’t need passwords: Nuance comes with perhaps one of the oldest if not best speech biometrics software. Imagine joining a Microsoft Teams meetings where you call in and start speaking and you’re authenticated immediately. Or allow for “signatures” based solely on your voice. Verification and authentication continue to be huge and the rise of better and better “deep fake” technology will allow for some sort of trust verification service with Nuance biometrics in the middle of it.

(Part 1) We’re taking our ball and going home: This one is near and dear to me heart. If a Cisco call center customer wanted to have speech recognition or text to speech there was only one name in town. Nuance. This has changed a bit in the last few years with the introduction of LumenVox as an additional option. And this has changed even further in the last 18 months with Cisco supporting Google’s DialogFlow, but Nuance still reigns supreme. I can see MS increasing the pricing of an already very expensive product making it prohibitive for some call centers to run their software.

(Part 2) I can see clearly now the rain is gone: Did you know that Azure stands for the color blue of a cloudless sky? Microsoft will be able to create a very defensible moat around their Azure offerings by being the only provider to have the latest and greatest Nuance services. In addition, some telephony cloud provider, who are already battling Amazon and who white label Nuance products as part of their offering, might be forced to either consume more Azure resources to get better pricing or completely get priced out from this technology and watch the competition pass them by. This sets the stage for Microsoft to be in the driver’s seat of what UC or CC provider you might choose next if you have an already deep Nuance integration or if your call center must use Nuance.

 

 

 

 

 

 

UCCE Call Flow Outbound Option with SIP Proxy

Cisco UCCE Outbound Dialer IVR Campaign Log Walkthrough

I wanted to document this specifically as I feel it’s the most complex flow you will see within UCCE. Before you go through this you will absolutely want to get familiar with the documentation as there are a lot of moving pieces. The diagram below comes straight from said documentation and should help you visualize what you see the logs doing.

 

UCCE Call Flow Outbound Option with SIP Proxy

UCCE Call Flow Outbound Option with SIP Proxy

Ideally I would have had all the logs for all the devices at the same time, but unfortunately that wasn’t the case. You will notice that the timestamps jump around as some logs are from other time frames. However, I’ve tried to match up all unique identifiers across all the logs so you can follow it along. The unique identifiers you want to take note of are:

2145551234: Customer phone number campaign is going to dial.
016: The dialer port.
10241: Correlation ID of initial call to customer.
10242: Correlation ID of call to IVR.

1. An unattended IVR campaign starts. Customer records are delivered to the Dialer. (The ANI and the port are key to be able to trace what the dialer is doing.)

badialer:
10:55:33:059 dialer-baDialer Trace: (Customer) SetCallResults(): ID: [-2147483601 in DL_5008_5031], skill: [6924], result: [1] [DIAL_RESERVED], now: [Thu Mar 4 10:55:33 2021], callback: [Thu Mar 4 10:55:32 2021]. 
10:55:33:059 dialer-baDialer Trace: (CUSTMGR) SendRecord(): Send customer: [2145551234] record ID: [-2147483601], in: DL_5008_5031 to port: [016]. 
10:55:33:059 dialer-baDialer Trace: (IVR) Record available event, port: [016], phone: [2145551234]. 
10:55:33:059 dialer-baDialer Trace: (CPORT) SetState(): Port: [016], state: [PORT_DEVICE_ATTRIB].

2. The Dialer asks the SIP Proxy to forward an invite to an available gateway to start a call. (CUSP logs are a bit of a pain, I recommend you download them via FTP instead of doing it from the GUI. This is a great guide on log settings. Ultimately, here we want to make sure that the CUSP knows where to send the request.)

badialer:
10:55:33:059 dialer-baDialer Trace: (SIPDisp) Dial, port: [016], phone: [22222912145551234], lDialTimeoutSec: [32]
CPA parameters: AP: [2500], MinSP: [608], MinVSpeech: [112], MaxTA: [5000], MaxTone: [30000]. 
10:55:33:059 dialer-baDialer Trace: (IVR) Dialing, phone: [22222912145551234], port: [016], ring timeout: [32], state: [PORT_DEVICE_ATTRIB]. 
10:55:33:059 dialer-baDialer Trace: (CPORT) SetState(): Port: [016], state: [DIAL_CUSTOMER].
CUSP:
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:468 nrs.FieldSelector - getUriPart: URI - sip:22222912145551234@{CUSP} part 6
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:468 nrs.FieldSelector - Requested field 45
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:468 nrs.FieldSelector - Returning key 22222912145551234
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:468 nrs.XCLPrefix - Leaving getKeyValue()
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:468 modules.XCLLookup - table=Prod-CCE-Table, key=22222912145551234
[REQUESTI.26] INFO 2021.03.04 14:27:34:469 modules.XCLLookup - table is Prod-CCE-Table
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:469 routingtables.RoutingTable - Entering lookup()
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:469 routingtables.RoutingTable - Looking up 22222912145551234 in table Prod-CCE-Table with rule prefix and modifiers=none
...
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:470 loadbalancer.LBBase - Entering getServer()
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:470 loadbalancer.LBBase - Entering initializeDomains()
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:470 servergroups.ServerGlobalStateWrapper - Prod-CCE:{Gateway}:5060:2 numTries=1--->isServerAvailable(): true
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:470 servergroups.AbstractNextHop - Entering compareDomainNames()
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:470 servergroups.AbstractNextHop - Leaving compareDomainNames()
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:470 servergroups.ServerGlobalStateWrapper - Prod-CCE:{Gateway0}:5060:2 numTries=1--->isServerAvailable(): true
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:470 loadbalancer.LBBase - Leaving initializeDomains()
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:471 servergroups.AbstractNextHop - Entering compareDomainNames()
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:471 servergroups.AbstractNextHop - Leaving compareDomainNames()
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:471 loadbalancer.LBBase - Server group dc-dialer.fqdn.tld selected {reSgElementQValue=1.0, reSgElementHost={Gateway}, reSgElementTransport=TCP, reSgElementPort=5060, reSgElementWeight=100, reSgElementSgName=dc-dialer.fqdn.tld}
[REQUESTI.26] DEBUG 2021.03.04 14:27:34:471 loadbalancer.LBBase - Leaving getServer()

3. The Gateway places the call (ccapi inout and ccsip mess are the debugs you need to enable to get relevant information. Biggest gotcha are dial peers not matching.)

Gateway:
2131549: Mar 4 10:55:33.260: //-1/xxxxxxxxxxxx/SIP/Msg/ccsipDisplayMsg:
Received: 
INVITE sip:22222912145551234@dc-dialer.fqdn.tld SIP/2.0
Via: SIP/2.0/TCP {CUSP}:5060;branch=z9hG4bKPpG+UtfThNEwGF7BsjXL3Q~~23121513
Via: SIP/2.0/UDP {MRPG}:58800;branch=z9hG4bK-d8754z-400d871379428a5a-1---d8754z-;rport=58800
Max-Forwards: 69
To: <sip:22222912145551234@{CUSP}>
From: <sip:5551412012@{MRPG}>;tag=0e52a576
Contact: <sip:5551412012@{MRPG}:58800>
Require: 100rel
Remote-Party-ID: <sip:18885461234@{CUSP}>;party=calling;screen=no;privacy=off
Call-ID: 3d5bfc40-093d7432-4a122a63-e2664942
CSeq: 1 INVITE
Content-Length: 630
Session-Expires: 1800
Min-SE: 90
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, UPDATE, NOTIFY, PRACK, REFER, NOTIFY, OPTIONS
Content-Type: Multipart/mixed;boundary=uniqueBoundary
Supported: timer, resource-priority, replaces
User-Agent: Cisco-SIPDialer/UCCE10.0

2132806: Mar 4 10:55:36.362: //16876944/44B8C2C0A6A6/SIP/Msg/ccsipDisplayMsg:
Received: 
SIP/2.0 180 Ringing
Via: SIP/2.0/UDP {PSTN}:5060;branch=z9hG4bK72D75B260F
From: <sip:18885461234@{PSTN}>;tag=4E815A86-1116
To: <sip:12145551234@{PSTN}>;tag=gK02b0b650
Call-ID: 44B9FBA8-7C4111EB-A6ACFA5D-15A1A7BA@{PSTN}
CSeq: 101 INVITE
Contact: <sip:12145551234@{PSTN}:5060>
Allow: INVITE,ACK,CANCEL,BYE,UPDATE
Content-Length: 236
Content-Disposition: session; handling=required
Content-Type: application/sdp

4. Voice Gateway does Call Progress Analysis and detects an answering machine. The Dialer is notified (I don’t think the above gateway debug levels will show you CPA information so I was not able to capture CPA from the gateway.)

baDialer:
10:58:41:845 dialer-baDialer Trace: (DDist) Softphone connection event: phone: [22222912145551234], result: [VOICE], port: [016], state: [DIAL_CUSTOMER]. 
10:58:41:845 dialer-baDialer Trace: (Customer) SetCallResults(): ID: [-2147483599 in DL_5008_5031], skill: [6924], result: [10] [VOICE], now: [Thu Mar 4 10:58:41 2021], callback: [Thu Mar 4 10:58:33 2021]. 
10:58:41:845 dialer-baDialer Trace: (IVR) Received telephony event port: [016], connection state: [20].

5. The Dialer asks the MR PG where the IVR is

baDialer:
10:58:41:845 dialer-baDialer Trace: (CPORT) SetState(): Port: [016], state: [TRANSFER]. 
10:58:41:845 dialer-baDialer Trace: (IVR) Transferring Customer port: [016], to IVR route point: [6515555678]. 
10:58:41:845 dialer-baDialer Trace: (CPORT) SetState(): Port: [016], state: [GET_TARGET].

6. MR PG forwards the request to the Router (It is important to note that up to this point everything that was happening was outside of the central controller.)

PIM:
14:23:09:556 PG2A-pim1 Trace: VRU->PG:REQUEST_INSTRUCTION(172 bytes):DID=570876 SendSeq#=1 TrkGrpID=200 TrkNum=1 SrvID=2 ANI=12145551234 DNIS=666666666610241 CorrID=10241 CallGUID=410885C97C5E11EBAABBFA5D15A1A7BA PstnTrkGrpID={Gateway} PstnTrkGrpChann#=2147483647 SIPHeader=f:<sip:12145551234@{Gateway}>;tag=4F3F6BE6-173D 
14:23:09:556 PG2A-pim1 Trace: FromVRU_RequestInstruction:REQUEST_INSTRUCTION RCID=5001 PID=5001 DID=570876 DIDRelSeq#=1 CorrID=10241 CalledParty#= CallingParty#=12145551234 CallGUID=410885C97C5E11EBAABBFA5D15A1A7BA PstnTrkGrp(ID={Gateway} ,Chann#=2147483647) SIPHeader=f:<sip:12145551234@{Gateway}>;tag=4F3F6BE6-173D 
14:23:09:556 PG2A-pim1 Trace: ProcessConnect:CONNECT RCID=5001 PID=5001 DID=570876 DIDRelSeq#=0 CRS(RtrDate=153464,RtrCID=18384) RCKSeq#=0 ErrorCode=0 TRTargetID=-1 CorrID=10242 EventSel=119 SvcType=4 NICCallID={PCID=5001,RCID=5001,Remote=0,0,DID=0x8b5fc,RemDID=0x0,Grp=0,Data=0,RtrData=0,CCID=x00000001/x00000000} PGCallID={N/A} OperationCode=CLASSIC OperationFlags=COOP_NONE NetworkTransferEnabled=F ECCPayloadID=1 Label(Type=8)=8888888881 NICCalledParty#=6515555678 SGSTID=-1 PQID=-1 SvcSTID=-1 AGSTID=-1 AGInfo=, MRDID=0 Interruptible=0 CallGUID=410885C97C5E11EBAABBFA5D15A1A7BA SIPHeader=f:<sip:12145551234@{Gateway}>;tag=4F3F6BE6-173D
rtr:
14:23:09:446 ra-rtr Trace: (1741 x 0 : 0 0) NewCall: CID=(153464,18384), DN=6515555678, ANI=2145551234, CED=, RCID=5003, MRDID=1, CallAtVRU=1, OpCode=0

7. Routing Script identifies the IVR and notifies the MR PG. (The script used here is the Hello World CVP script. Note that at this point we’re working with one corrID, but when the call goes to the IVR we will have a second corrID.)

rtr:
14:23:09:446 ra-rtr Trace: Script-Execute CID=(153464,18384) Default\\ZZZ_HelloIVR Start 1 
14:23:09:446 ra-rtr Trace: Script-Execute CID=(153464,18384) Default\\ZZZ_HelloIVR Set Variable 2 
14:23:09:446 ra-rtr Trace: Script-Execute CID=(153464,18384) Default\\ZZZ_HelloWorld Send To VRU 6 
14:23:09:446 ra-rtr Trace: (1741 x 0 : 0 0) Customer (1) has no valid network vru defined - using default. 
14:23:09:446 ra-rtr Trace: (1741 x 0 : 0 0) Customer (1) has no valid network vru defined - using default. 
14:23:09:446 ra-rtr Trace: (1741 x 0 : 0 0) Correlation id for dialog is (10241). 
14:23:09:446 ra-rtr Trace: (1741 x 10241 : 0 0) TransferToVRU: Label=6666666666, CorID=10241, VRUID=5000, RCID=5003 ECCPayloadID=1 
14:23:09:446 ra-rtr Trace: (1741 x 10241 : 0 0) TransferConnect sent. Dialog pending.
PIM:
14:23:09:556 PG2A-pim1 Trace: PG->VRU:TEMPORARY_CONNECT(214 bytes):DID=570876 SendSeq#=1 Label=8888888881 CorrID=10242 RCK=18384 RCKDay=153464 RCKSeq#=0 CallGUID=410885C97C5E11EBAABBFA5D15A1A7BA SIPHeader=f:<sip:12145551234@{Gateway}>;tag=4F3F6BE6-173D

8. The MR PG forwards the route response to the Dialer

baDialer:
10:58:41:877 dialer-baDialer Trace: (IVR) MR target acqusition succeeded for port: [016], state: [GET_TARGET], target: [666666666610241]. 
10:58:41:877 dialer-baDialer Trace: (CPORT) SetState(): Port: [016], state: [TRANSFER]. 
10:58:41:877 dialer-baDialer Trace: (SIPDisp) Transfer, port: [016], phone: [666666666610241].

9. The Dialer notifies the voice gateway to transfer the call to the IVR

baDialer:
10:55:42:249 dialer-baDialer Trace: (RESIP) Adding message to tx buffer to: [ V4 {Gateway}:5060 UDP target domain={Gateway} mFlowKey=0 ] 
10:55:42:265 dialer-baDialer Trace: (IVR) MR target acqusition succeeded for port: [016], state: [GET_TARGET], target: [666666666610241]. 
10:55:42:265 dialer-baDialer Trace: (CPORT) SetState(): Port: [016], state: [TRANSFER]. 
10:55:42:265 dialer-baDialer Trace: (SIPDisp) Transfer, port: [016], phone: [666666666610241]. 
10:55:42:265 dialer-baDialer Trace: (CLMGR) Agent event, agent: [111100208], ext: [5551510241], state: [TALKING]. 
10:55:42:265 dialer-baDialer Trace: (CLMGR_SIP) tOnBeginCallEvent(): Port: [003], ID: [38914319], device ID: [5551510241], IsReservationPort: [No]. 
10:55:42:265 dialer-baDialer Trace: (CLMGR) Agent event, agent: [111100208], ext: [5551510241], state: [TALKING]. 
10:55:42:281 dialer-baDialer Trace: (RESIP) Dialog::makeRequest: 
...
10:55:42:281 dialer-baDialer Trace: (RESIP) SEND: 
REFER sip:22222912145551234@{Gateway}:5060 SIP/2.0
Via: SIP/2.0/ ;branch=z9hG4bK-d8754z-5178e07be820b14e-1---d8754z-;rport
Max-Forwards: 70
Contact: <sip:5551412012>
To: <sip:22222912145551234@{CUSP}>;tag=4E816590-135
From: <sip:5551412012@{MRPG}>;tag=0e52a576
Call-ID: 3d5bfc40-093d7432-4a122a63-e2664942
CSeq: 3 REFER
User-Agent: Cisco-SIPDialer/UCCE10.0
Refer-To: <sip:666666666610241@{CUSP}>
Referred-By: <sip:5551412012@{MRPG}>
Content-Length: 0

10 The Gateway initiates the transfer to the SIP Proxy, and the SIP Proxy forwards the invitation onto Unified CVP.

Gateway:
2134751: Mar 4 10:55:42.320: //16876944/44B8C2C0A6A6/CCAPI/ccCheckClipClir:
In: Calling Number=12145551234(TON=Unknown, NPI=Unknown, Screening=Not Screened, Presentation=Allowed)
2134752: Mar 4 10:55:42.320: //16876944/44B8C2C0A6A6/CCAPI/ccCheckClipClir:
Out: Calling Number=12145551234(TON=Unknown, NPI=Unknown, Screening=Not Screened, Presentation=Allowed)
2134753: Mar 4 10:55:42.321: //16876944/44B8C2C0A6A6/CCAPI/ccCallSetupRequest:
Destination Pattern=6666666666....., Called Number=11102666666666610241, Digit Strip=FALSE
2134754: Mar 4 10:55:42.321: //16876944/44B8C2C0A6A6/CCAPI/ccCallSetupRequest:
Calling Number=12145551234(TON=Unknown, NPI=Unknown, Screening=Not Screened, Presentation=Allowed),
Called Number=11102666666666619114(TON=Unknown, NPI=Unknown),
Redirect Number=, Display Info=
Account Number=18885461234, Final Destination Flag=TRUE,
Guid=44B8C2C0-7C41-11EB-A6A6-FA5D15A1A7BA, Outgoing Dial-peer=2208
CUSP:
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:643 nrs.FieldSelector - getUriPart: URI - sip:11102666666666610241@{CUSP} part 6
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:643 nrs.FieldSelector - Requested field 45
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:643 nrs.FieldSelector - Returning key 11102666666666610241
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:643 nrs.XCLPrefix - Leaving getKeyValue()
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:643 modules.XCLLookup - table=Prod-CCE-Table, key=11102666666666610241
[REQUESTI.7] INFO 2021.03.04 14:27:39:643 modules.XCLLookup - table is Prod-CCE-Table
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:643 routingtables.RoutingTable - Entering lookup()
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:643 routingtables.RoutingTable - Looking up 11102666666666610241 in table Prod-CCE-Table with rule prefix and modifiers=none
...
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:644 loadbalancer.LBBase - Entering getServer()
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:644 loadbalancer.LBBase - Entering initializeDomains()
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:644 nrs.NRSRoutes - routes before applying time policies: [Ruri: dc1-cvp.fqdn.tld, Route: null, Network: Prod-CCE, q-value=1.0radvance=[502, 503]]
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:644 nrs.NRSRoutes - routes after applying time policies: [Ruri: dc1-cvp.fqdn.tld, Route: null, Network: Prod-CCE, q-value=1.0radvance=[502, 503]]
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:644 loadbalancer.LBBase - Leaving initializeDomains()
[REQUESTI.7] INFO 2021.03.04 14:27:39:644 loadbalancer.LBHashBased - list of elements in order on which load balancing is done : Ruri: dc1-cvp.fqdn.tld, Route: null, Network: Prod-CCE, q-value=1.0radvance=[502, 503], 
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:644 loadbalancer.LBBase - Server group route-sg selected Ruri: dc1-cvp.fqdn.tld, Route: null, Network: Prod-CCE, q-value=1.0radvance=[502, 503]
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:644 loadbalancer.LBBase - Leaving getServer()
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:644 nrs.XCLNRSShiftRoutes - Leaving ShiftRoutes.execute()
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:644 loadbalancer.LBFactory - Entering createLoadBalancer()
[REQUESTI.7] INFO 2021.03.04 14:27:39:644 loadbalancer.LBFactory - lbtype is 5(weight)
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:644 loadbalancer.LBFactory - Leaving createLoadBalancer()
[REQUESTI.7] DEBUG 2021.03.04 14:27:39:644 loadbalancer.LBBase - Entering getServer
rtr:
07:55:48:615 ra-rtr Trace: (1743 x 10241 : 0 0) TransferToVRU: Label=6666666666, CorID=10241, VRUID=5000, RCID=5003 ECCPayloadID=1 
07:55:48:615 ra-rtr Trace: (1743 x 10241 : 0 0) TransferConnect sent. Dialog pending. 
07:55:48:709 ra-rtr Trace: (1743 585271 10241 : 0 0) RequestInstr: CID=(153465,18384), CallState=1 
07:55:48:709 ra-rtr Trace: (585271 585271 10241 : 0 0) Dialog initiating 2nd phase of transfer. 
07:55:48:709 ra-rtr Trace: (585271 585271 10241 : 0 0) Correlation id for dialog is (10242). 
07:55:48:709 ra-rtr Trace: (585271 585271 10242 : 0 0) TransferToVRU: Label=8888888882, CorID=10242, VRUID=5000, RCID=5006 ECCPayloadID=1 
07:55:48:709 ra-rtr Trace: (585271 585271 10242 : 0 0) TransferConnect sent. Dialog pending. 
07:55:48:802 ra-rtr Trace: (585271 585272 10242 : 0 0) RequestInstr: CID=(153465,18384), CallState=1 
07:55:48:802 ra-rtr Trace: (585271 585272 10242 : 0 0) Dialog resuming (Request Instruction received.) status (0) 
07:55:48:802 ra-rtr Trace: Script-Continue CID=(153465,18384) Default\\ZZZ_HelloIVR Send To VRU 6 
07:55:48:802 ra-rtr Trace: Script-Execute CID=(153465,18384) Default\\ZZZ_HelloIVR Set Variable 7 
07:55:48:802 ra-rtr Trace: Script-Execute CID=(153465,18384) Default\\ZZZ_HelloIVR Run External Script 8 
07:55:48:802 ra-rtr Trace: (585271 585272 10242 : 0 0) Skipping the VRU verification because of Peripheral's ClientType is DBCT_MEDIA_ROUTING 
07:55:48:802 ra-rtr Trace: (585271 585272 10242 : 0 0) Runscript sent. ECCPayloadID = 1 Dialog pending. 
07:55:54:366 ra-rtr Trace: (585271 585272 10242 : 0 0) CallEventReport: CID=(153465,18384),Event=DISCONNECT, DlgEnds=1, FromVRU=0, CallState=2, Cause=NORMAL 
07:55:54:366 ra-rtr Trace: (585271 585272 10242 : 0 0) Dialog received event report 6 from NIC during RunScript. 
07:55:54:570 ra-rtr Trace: (585271 585272 10242 : 0 0) CallEventReport: CID=(153465,18384),Event=DISCONNECT, DlgEnds=1, FromVRU=0, CallState=22, Cause=NORMAL 
07:55:54:570 ra-rtr Trace: (585271 585272 10242 : 0 0) Dialog (callstate:22) received event(6)(Call disconnected. (Event has dialog end set.)) 
07:55:54:570 ra-rtr Trace: (585271 585272 10242 : 0 0) Dialog resuming (Call disconnected. (Event has dialog end set.)) status (3) 
07:55:54:570 ra-rtr Trace: Script-Continue CID=(153465,18384) Default\\ZZZ_HelloIVR Run External Script 8 
07:55:54:570 ra-rtr Trace: (585271 585272 10242 : 0 0) Dialog aborted and was deleted. 
07:55:54:570 ra-rtr Trace: (585271 585272 10242 : 0 0) Dialog sending release call to VRU 
07:55:54:570 ra-rtr Trace: (585271 585272 10242 : 0 0) Deleting Dialog.

From this point forward it’s just an inbound CVP call.

~david