How do you correlate reference call IDs for different call scenarios, under Unified CM phone forking?

In Cisco MediaSense, the meta data for each call only provides the xRefCi (reference call ID) and the device ref (extension) of the forking device and the far-end device (can be a conference bridge or any other phone).

The xRefCi parameter is Unified CM's identifier for a particular media stream. They do not always correspond 1-to-1 with the recorded tracks.

Agent Hold/Resume Scenario

Agent A (extn 1000) and Caller C (extn 2000) are talking to each other

Agent A puts call on hold

Agent A resumes call

There are 2 recording sessions for this scenario:

Session with sessionId = S1 with following 2 tracks, for the time period /segment before agent puts call on hold.trackNumber=0 with participant A ( deviceRef=1000, xRefCi = aaaa) trackNumber=1 with participant B (deviceRef=2000, xRefCi = cccc)

Session with sessionId = S2 with following 2 tracks, for the time period / segment after agent resumes the call. trackNumber=0 with participant A( deviceRef=1000, xRefCi = aaaa) trackNumber=1 with participant B (deviceRef=2000, xRefCi = cccc)

MediaSense does not record the the segment of the call while agent has put the call on hold.

Customer Hold/Resume Scenario

Agent A (extn 1000) and Caller C (extn 2000) are talking to each other

Session S3 gets updated with farend changing from A to CtrackNumber=0 with participant B (deviceRef=3000, xRefCi = b2) trackNumber=1 with participant C (deviceRef=2000, xRefCi = c2) Note that trackNumber 1 has 2 participants. Participant A before the transfer and participant C after tranbsfer

After B and C end the call

session S3 is marked CLOSED_NORMALMediaSense does not record the the segment of the call while agent has put the call on hold.

Agent Conference with Another Agent Scenario

Agent A (extn 1000) and Caller C (extn 2000) are talking to each other

Agent A conferences caller with another agent B (extn 3000). Both A and B's devices are set up for forking

A, B and C are talking.

A drops the call

After some time B and C end call

There are 3 recording sessions for this scenario

Session with sessionId = S1 with following 2 tracks, for the time period /segment before agent conferences call. As soon as A initiates conference, S1 is marked as CLOSED_NORMALtrackNumber=0 with participant A (deviceRef=1000, xRefCi = a1) trackNumber=1 with participant C (deviceRef=2000, xRefCi = c1)

For the time period / segment A and B are consulting with each other, 2 new sessions will get created.

Session S3 gets updated with farend changing from A to Conference bridge (CFB)trackNumber=0 with participant C (deviceRef=2000, xRefCi = b2)trackNumber=1 with participant CFB (deviceRef=b number of CFB,, xRefCi = cfb1)Note that trackNumber 1 has 2 participants. Participant A before the conference and participant CFB after conference

Session S4 gets created with trackNumber=0 with participant A (deviceRef=1000, xRefCi = a1 , this is original xRefCi when A and C were talking)trackNumber=1 with participant CFB (deviceRef=b number of CFB, xRefCi = cfb2)

S3 is updated with farend changing from Conference bridge (CFB) to A. trackNumber=1 with participant A (deviceRef=1000, xRefCi = a1)

After A and B end the call

session S3 and S4 are marked CLOSED_NORMAL

How do you correlate reference call IDs for different call sessions, under CUBE forking?

With CUBE forking, very few situations cause a call to be split into multiple recording sessions. Hold/Resume, transfer and conference operations do not start new recording sessions in most cases. In the few cases where new sessions are created, there is a common value, CCID (Call Correlation ID), which is common to all sessions in the call. CCID is the decimal form of Cisco-Guid, a unique call key which is generated by Cisco voice routers. The first router which receives a call generates this key, and passes it down the line to all subsequent devices including Cisco MediaSense.

CUBE itself does not generate xRefCi values, but to create similarity with Unified CM phone forking calls, Cisco MediaSense also synthesizes a pair of xRefCi values for every CUBE call. These can be seen in the metadata at the track level, along with CCID, which appears at the session level.

The following situations cause CUBE recordings to be split into multiple sessions.

Mid-call Codec Change

If a transfer, conference, conference drop, or other operation causes the parties to renegotiate their codec, Cisco MediaSense ends the current recording session and starts a new one. The two sessions will share the same CCID and the same pair of xRefCi values.

Consult Transfers

A consult transfer is a transfer from one agent to another, in which the two agents talk to each other for a while, with the original caller waiting on hold. The consult leg of the call is obviously related in some way to the overall call, and it is possible to configure Unified CM such that consult calls DO pass through CUBE. However, CUBE and Cisco MediaSense have no idea that these calls are related, and they create a new CCID and a new pair of xRefCi values for this session.

These calls can however be associated with one another by comparing participant deviceRef and timestamp fields. Consider this scenario:

The red flag in this scenario is in Step 2. During that period, Agent A (deviceRef 1000) is a participant in two recording sessions at once:

Session=S1 / CCID=C1, and

Session=S2 / CCID=C2

Therefore S1 is related to S2, and C1 is related to C2.

Detecting Consult Calls

First we need a clear definition of consult call: any secondary call which is made by a current participant in an existing session to an endpoint which is outside that session, and which excludes the other participants in that session. In theory, this could include an agent placing the caller on hold to check with his boss about taking lunch, or even an agent putting the caller on hold to receive a call from his wife, but we will ignore those possibilities for now.

It is possible for a client application to detect a consult call in real time by tracking the Cisco MediaSense event stream. If the client observes a session STARTED event containing a given deviceRef, followed by another session STARTED event containing the same deviceRef with no intervening session ENDED event, it can conclude that the sessionId's and the CCIDs found in the two session STARTED events are associated.

Historically, a client can check for any consult calls which are associated with a given primary call, using the Cisco MediaSense API. Assume the client knows that Agent A was using extn 1000, in CCID <C1>. It can follow these instructions to find any associated consult calls:

Retrieve the session metadata for the primary call by issuing getSessionByCCID(<C1>).

Extract the sessionStartDate (call it <Ta>), and sessionDuration.

Calculate the sessionEndDate (call it <Tb>) by adding sessionDuration to <Ta>.

This query could return more than one session. If it does, then all of them can be assumed to be associated with the same call.

Detecting Consult Calls from Multiple Participants

The above procedure will find all consult calls made from the device which received the initial phone call. However, what if there are consult calls made from a device to which the call was subsequently transferred?

Consider this procedure:

Caller calls Agent 1

Agent 1 consults with Agent 2, then drops

Caller speaks with Agent 2

Agent 2 consults with Agent 3, then drops

Caller speaks with Agent 3

The procedure above will not catch the consult call between Agent 2 and Agent 3.

Since this is a CUBE call, we can make use of the fact that all of the connections between the caller and each of the agents are included in the same recording session, and the fact that all of the agents involved will be listed as participants in the same session at one time or another. Thus, from the primary session metadata, we can collect a list of all the deviceRef's which were involved. To find those sessions, we can make a series of calls to getSessionsByDeviceRef, specifying the primary session's time range together with one deviceRef per request. Alternatively, we can shortcut that process by issuing a single getSessions request such as the following:

This query will return all the consult calls associated with the original primary call and all of its transfers.

The astute reader will note that the above procedure actually casts the net too broadly. If for example, the agent at deviceRef 4000 conducted and terminated a completely independent call which happened to start after <Ta> and before he was added to the call in question, the above procedure will include that independent call in the set. This problem can be solved though, using the information available in the primary session's metadata. Each participant's information includes the time offset at which he joined the session, and the duration of his tenure. Client code could use that information to simply delete the unrelated sessions from the list he received above. Or, it could formulate a series of direct getSessions or getSessionByDeviceRef queries which correctly frame the time periods during which each agent was in the primary call. We leave that as an exercise to the reader!

Putting it All Together

Above, we presented precedures for retrieving all sessions associated with a given Cisco MediaSense recording session. However, we have also seen that a given call may be divided into more than one session, as in the case of a mid-call codec change. How do we retrieve all recordings (including consults) associated with all sessions connected to the caller's interaction?

The answer is to extend the instructions above for detecting multiple consult calls. First, we would collect all sessions which share the CCID of the primary session in question. Then, we would build our list of participants from all of those session records. Next we would calculate the time rangs as the sessionStartDate of the earliest session through the end of the latest session. Finally, we can execute the getSessions query shown above.

As before, we may end up capturing too many recordings in this net, so the client could execute a postprocessing step to delete those unrelated sessions from its list.

How do you associate calls in Cisco MediaSense to their appearance in other solution components?

Identifier Correlation Table

Below are two tables - one for UCM calls and one for CUBE calls. Each column represents a solution component or protocol, with the first column representing Cisco MediaSense. Each row represents a particular type of identifier.

To read the table, begin with a cell that represents the data item that you know, and then look horizontally to the column representing the solution component in which you want to find the call. The entry in that cell indicates by what name the exact same data item is known in the target component. If the target component has a blank cell in that row, then that data item is not known to that component. You can instead look for an intervening column where you can cross vertically into another row where that cell is not blank in the target component's column.

For example, with a UCM call, suppose you know the GED-188 CallReferenceID and want to find the call in Cisco MediaSense. Looking left from the GED-188 column you see that there is no value in the MediaSense column, so you cannot map directly to it. However, there are two columns where you can zig-zag across rows: UCM CDR and TAPI/JTAPI. Let's look the UCM CDR first. A client can select the proper UCM CDR record by searching for one in which the IncomingProtocolCallRef matches the GED-188 CallReferenceID. That record contains value called destLegCallIdentifier, which is the same as the MediaSense NearEnd xRefCi, and can therefore be used to find the corresponding record in Cisco MediaSense.

UCM CDR records are not written until some time after the end of the call terminates, however, so the above method can only be used historically. If you need the information in real time, you can translate through TAPI/JTAPI protocol. GED-188 CallReferenceID matches the TAPI/JTAPI Cisco-Connection.UniqueID, and from there you can determine the Terminal.ConnectionID, which matches the NearEnd xRefCi in Cisco MediaSense. Obviously, this method can only work if you have a TAPI/JTAPI connection to UCM.

There is another path as well. Look downward from the GED-188 CallReferenceID. It turns out that you can also use the AlertingDevice and AnsweringDevice to match the deviceRef field in MediaSense. This method also works in real time.

Call Correlation for Calls Forked by a Unified CM IP Phone

MediaSense

Ingress Gateway or CUBE

AAA RADIUS CDR

UCM CDR

TAPI/JTAPI field

UCCE Database

UCCE Script

CTIOS

GED-188

(1)

Cisco-Guid

IncomingProtocolCallRef

CiscoConnection.UniqueID

TCD.CallReferenceID

Call.CallGUID

CallReferenceID

NearEnd xRefCi

destLegCallIdentifier

Terminal.ConnectionID

FarEnd xRefCi

origLegCallIdentifier

Terminal.ConnectionID

global_CallID_call-ManagerId + global_CallID_callId(A.K.A. UCM GCID)

CiscoCall.CallID

TCD.PeripheralCallKey

deviceId

Agent.AgentInstrument

deviceRef

TCD.InstrumentPortNumber (2)

Agent.AgentExtension or Agent.Extension

AlertingDevice orAnsweringDevice

Call Correlation for Calls Forked by CUBE

MediaSense

Ingress Gateway or CUBE

AAA RADIUS CDR

UCM CDR

TAPI/JTAPI field

UCCE Database

UCCE Script

CTIOS

GED-188

CCID

Cisco-Guid

Cisco-Guid

TCD.CallReferenceID

Call.CallGUID

CallReferenceID

deviceRef

Called or calling party extn

TCD.InstrumentPortNumber (2)

Agent.AgentExtension or Agent.Extension

AlertingDevice orAnsweringDevice

Notes

In recordings of UCM calls, Cisco MediaSense does in fact receive a Cisco-Guid from UCM, but it is not the same one that is captured by the other solution devices. MediaSense therefore does not even store this value.

For agent-to-agent calls, TCD.InstrumentPortNumber is the destination agent’s extension. The calling agent’s extension can be found in TCD.ANI.

How do you determine which track has the calling and which has the called party?

For Calls Forked by CUBE

For CUBE calls, Track 0 always maps to the Anchor leg media stream. The Anchor leg is the dial-peer which media recording profile is configured. The second track maps to non-anchor leg.

If you have media recording profile enabled on theinbound dialpeer, then the anchor leg will be the in-leg. In other words, the calling party will be in Track 0, and the called party will be in Track 1.

If you have media recording profile enabled on the outbound dialpeer, then the anchor leg will be the out-leg. In that case the calling party will be in Track 1, and the called party will be in Track 0.

For Calls Forked by Unified CM Phones

For Unified CM forking, you can use the xRefCi fields in the metadata to determine which party is in which media track. The numerically smaller xRefCi almost always refers to the calling party's track, and the called party's track will be numerically larger (usually by one, but it could be more under a reasonably loaded system). However, things start to get complicated once we get into conferencing and transferring. For some of those scenarios, additional CI's get generated and replaced when call legs are merged.

That said, MediaSense only knows about a single pair of xRefCi values for any single recording session, and any supplementary service operations which generate new xRefCi values would also generate new recording sessions. So it is ok to assume that within a given session, the smaller xRefCi corresponds to the calling party, and the larger one corresponds to the called party.

There is one additional caveat. The xRefCi values are assigned incrementally, and they eventually wrap around to zero. That means there is a 50/50 chance that the wrap-around will take place between tracks in the same call, in which case this numerical relationship will not hold.

What are the possible causes for a session state of CLOSED_ERROR?

1. Call control server got an error response from the Media (recording) server for the open or close request2. Call control server detected a SIP signaling error, for example a missing ACK3. Session was successfully closed, but ALL tracks have zero size

When a session is in the ACTIVE state, it is normal that there is no duration in the metadata, because duration is not known until session is closed.

For a session which is in CLOSED_ERROR state, if either the session or track duration fields are not present in either the event or the getSessions data, then media for this track is not available.

Why the difference?

"Use this API to search all pruned recordings. .... The term Pruned refers to recordings which are deleted by the Cisco MediaSense system. If you have explicitly deleted any recording using the deleteSessions API, then these deleted recordings are not considered as pruned recordings."

The MediaSense SRND under the section "Proactive Storage Management":

"When sessions are pruned, the metadata associated with those sessions remains in the database, though they are marked as "pruned". This metadata does not take a large amount of storage space compared to the recordings themselves, but it does take some, and over time it will grow unbounded if not periodically cleaned up. .... Once these records are no longer needed, they should be periodically removed.

To aid in [this] activity, clients may periodically issue an API request for pruned sessions, or may elect to receive session pruned events, and explicitly delete those it no longer needs "

To clarify, the two queries above are two entirely different queries. As a matter of fact, the second query (looking for all sessions whose state is "DELETED") will ALWAYS return an empty set. Normal day-to-day queries filter out sessions whose state is DELETED (even if that is what is being asked for). The only exception is "getAllPrunedSessions". This one is intended to assist the application in finding pruned sessions so that the application can request that these sessions really be deleted.

Once you use the "deleteSessions" API on the list of pruned sessions you get from "getAllPrunedSessions", these sessions will NO LONGER appear in the result of "getAllPrunedSessions". Such sessions will be completely removed from the metadata within 24 hours.

Another way to look at this is that "pruned" sessions are not the same thing as "deleted" sessions:

Pruned sessions are sessions that have been marked for removal by some algorithm in the MediaSense system. No person was involved in the decision to prune these sessions. So even though they are moved to the "DELETED" state, they will NOT actually be removed from the metadata. Human (or Application) intervention will be required. Because they are in the "DELETED" state, they will not be visible to most queries. However, these sessions WILL be visible to the "getAllPrunedSessions" query API. Also, if any mp4 files were generated for these sessions, they continue to be present on the disk and available for download until they are actually DELETED.

Deleted sessions are sessions that are marked for deletion by calling the "deleteSessions" API explicitly. This can be done to sessions that are already pruned or sessions that are not yet deleted at all. Once a session has been deleted by the deleteSessions API, it will not be visible to ANY query. This includes the getAllPrunedSessions API. These sessions will be removed from the metadata within 24 hours so that disk space can be reclaimed.