Contact Expert v7.3 for Skype for Business Server
CAS Media Service
The Client Access Server Media Service exposes media, agent and task specific events and exposes soft-phone functionalities.
Methods | Description |
---|---|
General_LoginAgent() |
Login to specific media |
General_LogoutAgent() |
Logout from specific media |
General_ActivateAgent() |
Change to active state in specific media |
General_StartAUX() |
Change to auxiliary state in specific media |
General_AgentAlive() |
Send heartbeat |
General_PullEvents() |
Pull events from the service (pull method) |
General_SubscribePush() |
Subscribe to receive events (push method) |
General_GetParameters() |
Retrieve configuration properties |
General_UpdateParameters() |
Update configuration properties |
General_GetAUXReasons() |
Retrieve auxiliary reason codes |
General_GetBusinessTags() |
Retrieve business tags |
General_Gone() |
Close a specific task |
Telephony_AnswerCall() |
Pickup an alerting call |
Telephony_DropCall() |
Disconnect a call |
Telephony_TakeCallToHeld() |
Take the call to held state |
Telephony_StartAssistanceCall() |
Initiate a consultation call |
Telephony_DropAssistanceCall() |
Drop a consultation call |
Telephony_TransferCall() |
Transfer a call to consultant |
Telephony_ConferenceCall() |
Setup a conference call |
Telephony_DialContact() |
Dial a contact |
SDU_GetValues() |
Read data from data unit |
SDU_SetValues() |
Store data to data unit |
SysDB_GetCampaignField() |
Read data from contact record |
SysDB_SetCampaignField() |
Update data in contact record |
Most of the methods return a status message (STATUS_OK
or STATUS_FAILED
). STATUS_FAILED
indicates that the request is rejected by the Media Service. However, receiving a STATUS_OK
does not mean that the request is performed successfully. It only means that the Media Service received the request, checked its content and forwarded that to the core components. In order to detect the real request outcome, clients should be prepared to receive subsequent events from the Media Service. Clients should always process these events.
The following sections provide detailed information about each of these methods.
Note
Source code examples are only for demonstration purposes.
More sophisticated error handling might be required in real-world scenarios.
Connecting to the Media Service
After the proxy code is generated based on the web service WSDL, connecting to the Media Service is quite easy. The following code snippet shows how to do that.
@WebServiceRef(wsdlLocation=”http://[FQDN]:[Port]/ClientAccessServer/MediaService?wsdl”)
static MediaService mediaService = new MediaService();
public static MediaPortType connect() {
MediaPortType mediaPort = null;
try {
if((mediaPort = mediaService.getMediaPortTypePort()) != null) {
System.out.print(“Connecting to the Media Service is performed successfully”);
} else {
System.err.print(“Failed to connect to the Media Service”);
}
}
catch(Exception ex) {
System.err.print(“Failed to connect to the Media Service. Reason: “ + ex.getMessage());
}
return mediaPort;
}
Login to specific media
Login to a given media requires the agent to have at least one skill in the media. If an agent has skills in more than one media, then he can login to multiple ones at the same time. After login, the agent generally starts receiving tasks automatically. Deciding what type of task to receive next is up to the system. Decision is made by CE based on the campaigns running parallel and the skill sets the currently logged in operators have.
The code below shows how to sign into the voice media. Login to other media (e.g. to email media) is quite similar. Only the input parameter indicating the media type should be changed to MediaType.MT_EMAIL
.
Javax.xml.ws.Holder<String> contextID = new javax.xml.ws.Holder<String>();
PropertyArray loginProperties = new PropertyArray();
loginProperties.item = new ArrayList<Property>();
Property operatorName = new Property();
operatorName.name = “OperatorLoginName”;
operatorName.value = “agent_1”;
Property operatorPassword = new Property();
operatorPassword.name = “OperatorPassword”;
operatorPassword.value = “1234”;
Property pbxExtension = new Property();
pbxExtension.name = “OperatorExtension”;
pbxExtension.value = “2004”;
loginProperties.item.add(operatorName);
loginProperties.item.add(operatorPassword);
loginProperties.item.add(pbxExtension);
try {
if(mediaPort.generalLoginAgent(MediaType.MT_VOICE, loginProperties, contextID) == WsStatus.STATUS_OK) {
System.out.print(“Login to the voice media is performed successfully”);
System.out.print(“Context id: “ + contextID.value);
return contextID.value;
} else {
System.err.print(“Failed to login to the voice media”);
}
}
catch(GenException_Exception gex) {
System.err.print(“Failed to login to the voice media. Reason: “ + gex.getMessage());
}
catch(Exception ex) {
System.err.print(“Communication failure. Reason: “ + ex.getMessage());
}
return null;
Regardless which media the agent tries to login, there are several mandatory login properties which should be specified. Beyond the mandatory properties, several optional ones can be specified. The table below lists the mandatory and optional login properties currently available.
Property | Format | Mandatory | Media | Description |
---|---|---|---|---|
OperatorLoginName |
string | yes | all | Operator login name. |
OperatorPassword |
string | yes | all | Password associated with the login name. |
OperatorExtension |
string | yes | voice | PBX extension to login to. |
AutoAnswer |
yes/no | no | voice | Specifies whether to answer each call delivered to the agent extension automatically or let the agent to decide when to pick up the call. |
DelayedAnswer |
yes/no | no | voice | Specifies whether to answer a call only after the entire task is downloaded or pickup immediately. |
OperatorVersion |
string | no | all | Specifies the version number of the agent application. |
OperatorType |
string | no | Specifies the type of the agent application (thin, loxon) | |
MediaAddress |
string | no | voice | Local IP address to receive media stream on. |
AudioPort |
numeric | no | voice | Local UDP port to receive audio RTP stream on. |
AudioCodec |
string | no | voice | Audio codec to use (supported codecs: G.711U, G.711A, G.723) |
VideoPort |
numeric | no | voice | Local UDP port to receive video RTP stream on. |
VideoCodec |
string | no | voice | Video codec to use (supported codecs: H.263, H.261) |
Upon successful login, the Media Service sends back a context id to the client which should be passed with each subsequent request. The service rejects each request coming with invalid or already expired context id.
Logout from specific media
Logout from a given media is quite straightforward. After doing that, no more tasks having the given media type will be delivered to the operator. Tasks from other media types do not cease to arrive. The following code snippet shows how to logout from the voice media.
PropertyArray logoutProperties = new PropertyArray();
logoutProperties.item = new ArrayList<Property>();
try {
if(mediaPort.generalLogoutAgent(contextID, MediaType.MT_VOICE, logoutProperties) == WsStatus.STATUS_OK) {
System.out.print(“Logout from the voice media is performed successfully”);
} else {
System.err.print(“Failed to logout from the voice media”);
}
}
catch(GenException_Exception gex) {
System.err.print(“Failed to logout from the voice media. Reason: “ + gex.getMessage());
}
catch(Exception ex) {
System.err.print(“Communication failure. Reason: “ + ex.getMessage());
}
Changing to active status in specific media
After terminating conversation with a contact, the agent is changed to wrapup status automatically. In wrapup status, the agent still has the task, but already has no active communication channel toward the contact. After closing the task as well, the agent is taken into passive status. The maximum time allowed being in passive status is limited by system administrators. At any time while being passive, the agent might decide to change to active status. If the agent does not activate himself until the maximum time allowed to be passive expires, the agent is moved to active status automatically.
PropertyArray activationProperties = new PropertyArray();
activationProperties.item = new ArrayList<Property>();
try {
if(mediaPort.generalActivateAgent(contextID, MediaType.MT_VOICE, activationProperties) == WsStatus.STATUS_OK) {
System.out.print(“The agent is taken into active state in voice media”);
} else {
System.err.print(“Failed to take the agent into active state in the voice media”);
}
}
catch(GenException_Exception gex) {
System.err.print(“Failed to take the agent into active state in the voice media. Reason: “ + gex.getMessage());
}
catch(Exception ex) {
System.err.print(“Communication failure. Reason: “ + ex.getMessage());
}
The code above shows how to move the agent into active status in voice media. At any time while being active in a given media, the system might deliver new tasks to the agent from that media.
Changing to auxiliary status in specific media
Agents can switch to auxiliary status. In auxiliary status, the system does not deliver tasks to the agent. As the example below indicates, changing to auxiliary status requires specifying a reason code. In order to understand how to retrieve the list of auxiliary codes, see the section “Retrieving auxiliary codes”.
PropertyArray auxProperties = new PropertyArray();
auxProperties.item = new ArrayList<Property>();
Property auxCodeToUse = new Property();
auxCodeToUse.name = “AUXCode”;
auxCodeToUse.value = “5”;
auxProperties.item.add(auxCodeToUse);
try {
if(mediaPort.generalStartAUX(contextID, MediaType.MT_VOICE, auxProperties) == WsStatus.STATUS_OK) {
System.out.print(“The agent is taken into auxiliary state”);
} else {
System.err.print(“Failed to take the agent into auxiliary state”);
}
}
catch(GenException_Exception gex) {
System.err.print(“Failed to take the agent into auxiliary state. Reason: “ + gex.getMessage());
}
catch(Exception ex) {
System.err.print(“Communication failure. Reason: “ + ex.getMessage());
}
Note
Please note that regardless the media type specified when changing to auxiliary codes, the system takes the agent into auxiliary status in each media. This has the consequence that while being in auxiliary status, the agent does not receive tasks from any media.
Sending heartbeat
While being signed into CE, operators should send heartbeats periodically. The section “Retrieving configuration” describes how the agent is informed about the value of the heartbeat interval length.
Try {
mediaPort.generalAgentAlive(contextID);
System.out.print(“Operator heartbeat is sent to the Media Service”);
}
catch(Exception ex) {
System.err.print(“Failed to send agent heartbeat. Reason: “ + ex.getMessage());
}
Note
If no heartbeat is received within a 3 x [heartbeat interval length] time period, the agent is signed out by the system automatically in the background.
Pulling events
There are several types of events which should be delivered to operators. As already mentioned above, when operators send requests to the service, they are informed about the request outcomes in the form of subsequent events. There is another class of events called “unsolicited” events which are not related directly to any request. These unsolicited events notify operators that something happened on server side.
The Media Service offers 2 methods to deliver events to operators: the pull or push methods. Pull method means that the Media Service should be polled periodically for events. The following example shows how to poll the service for events. The method returns with a sequence of events related to the given operator.
Javax.xml.ws.Holder<EventArray> events = new javax.xml.ws.Holder<EventArray>();
try {
if(mediaPort.generalPullEvents(contextID, events) == WsStatus.STATUS_OK) {
if(events.value == null) {
System.err.print(“Failed to retrieve events from the Media Service”);
return null;
}
else if(events.value.item == null) {
System.err.print(“Failed to retrieve events from the Media Service”);
return null;
}
else if(events.value.item.size() <= 0) {
System.out.print(“No events are available”);
return null;
}
System.out.print(“Number of events retrieved: “ + String.valueOf(events.value.item.size()));
return events.value.item;
} else {
System.err.print(“Failed to retrieve events”);
}
}
catch(GenException_Exception gex) {
System.err.print(“Failed to retrieve events. Reason: “ +
gex.getMessage());
}
catch(Exception ex) {
System.err.print(“Communication failure. Reason: “ + ex.getMessage());
}
return null;
The following table lists the currently supported event types.
Event type | Unsolicited | Description |
---|---|---|
PARAMETERS_UPDATED |
yes | Indicates that the server side agent properties are changed. |
TASK_APPENDED |
yes | Indicates that a new task is assigned to the operator. |
TASK_OUTDATED |
yes | Indicates that the agent should be asked for closure the task and wrapup should be initiated. |
MEDIA_ALERTING |
yes | Indicates that a new communication request is delivered to the operator. |
MEDIA_CONNECTED |
yes | Indicates that a new communication request is connected to the operator. |
MEDIA_DISCONNECTED |
yes | Indicates that a communication stream is connected to the operator. |
MEDIA_HELD |
yes | Indicates that a previously connected communication request is taken into held state. |
MEDIA_UNHELD |
yes | Indicates that a previously inactivated communication request is active again. |
MEDIA_DEFLECTED |
yes | Indicates that call directed to agent is forwarded to somewhere else. |
MEDIA_ESTABLISHED |
yes | Indicates that media stream is established between agent and caller. |
MEDIA_TRANSFERRED |
yes | Indicates that a communication request previously taken into held state is transferred. |
MEDIA_CONFERENCED |
yes | Indicates that call conference request is performed successfully. |
MEDIA_ASSISTANCE_FAILED |
yes | Indicates that the communication request initiated for consultation purposes is failed. |
MEDIA_ASSISTANCE_ALERTING |
yes | Indicates that setting up a media path for consultation purposes is in progress. |
MEDIA_ASSISTANCE_CONNECTED |
yes | Indicates that the media path initiated for consultation purposes is connected to the desired party. |
MEDIA_ASSISTANCE_DISCONNECTED |
yes | Indicates that the communication session established for consultation purposes is terminated. |
OPERATOR_PASSIVATED |
yes | Indicates that the agent is taken into passive (ACW, or AUX) state. |
OPERATOR_ACTIVATED |
yes | Indicates that the agent is taken into active state. In this state new tasks might be received. |
OPERATOR_REMOVED |
yes | Indicates that the agent login is deleted by an administrator. The agent should be asked for logout as soon as possible. |
OPERATOR_UPDATED |
yes | Indicates that some relevant agent property is changed by an administrator. |
OPERATOR_EXPELLED |
yes | Indicates that the agent is thrown away by one of the media servers. It is most probably caused by heartbeat timeout. |
OPERATOR_MESSAGE |
yes | Delivers a message to the operator. |
DEVICE_CLOSED |
yes | Indicates that the recently used communication device (phone) is removed. The agent should be asked for logout as soon as possible. |
PREDICTIVE_DIALING_FAILED |
yes | Indicates that a call initiated in the background has been failed. |
GENERAL_LOGIN_OK |
no | Indicates that the previously issued login request is performed successfully. |
GENERAL_LOGIN_FAILED |
no | Indicates that performing the previously issued login request is failed. |
GENERAL_LOGOUT_OK |
no | Indicates that the previously issued logout request is performed successfully. |
GENERAL_LOGOUT_FAILED |
no | Indicates that performing the previously issued logout request is failed. |
GENERAL_ACTIVATE_OK |
no | Indicates that the previously issued activation request is performed successfully. |
GENERAL_ACTIVATE_FAILED |
no | Indicates that performing the previously issued activation request is failed. |
GENERAL_STARTAUX_OK |
no | Indicates that the previously issued request to change to auxiliary state is performed successfully. |
GENERAL_STARTAUX_FAILED |
no | Indicates that performing the previously issued auxiliary state change request is failed. |
TELEPHONE_ANSWERCALL_OK |
no | Indicates that the previously issued request to answer a call is performed successfully. |
TELEPHONE_ANSWERCALL_FAILED |
no | Indicates that performing the previously issued answer call request is failed. |
TELEPHONE_DROPCALL_OK |
no | Indicates that the previously issued request to drop a call is performed successfully. |
TELEPHONE_DROPCALL_FAILED |
no | Indicates that performing the previously issued drop call request is failed. |
TELEPHONE_TAKECALLTOHELD_OK |
no | Indicates that the previously issued request to take a call to held state is performed successfully. |
TELEPHONE_TAKECALLTOHELD_FAILED |
no | Indicates that performing the previously issued hold call request is failed. |
TELEPHONE_STARTASSISTANCECALL_OK |
no | Indicates that the previously issued request to start a consultation call is performed successfully. |
TELEPHONE_STARTASSISTANCECALL_FAILED |
no | Indicates that performing the previously issued request to start a consultation call is failed. |
TELEPHONE_DROPASSISTANCECALL_OK |
no | Indicates that the previously issued request to disconnect a consultation call is performed successfully. |
TELEPHONE_DROPASSISTANCECALL_FAILED |
no | Indicates that performing the previously issued request to disconnect a consultation call is failed. |
TELEPHONE_DIALCONTACT_OK |
no | Indicates that the previously issued dial request is performed successfully. |
TELEPHONE_DIALCONTACT_FAILED |
no | Indicates that performing the previously issued dial request is failed. |
TELEPHONE_TRANSFERCALL_OK |
no | Indicates that the previously issued transfer request is performed successfully. |
TELEPHONE_TRANSFERCALL_FAILED |
no | Indicates that performing the previously issued transfer request is failed. |
TELEPHONE_CONFERENCECALL_OK |
no | Indicates that the previously issued conference request is performed successfully. |
TELEPHONE_CONFERENCECALL_FAILED |
no | Indicates that performing the previously issued conference request is failed. |
Subscribing to receive events
The other way to receive events is called the push method. This requires implementing a predefined interface called MediaAgentCallbackService and subscribe to the Media Service. The following code snippet indicates how to do that.
Int eventStreamTimeout = 600;
String localEventSinkURL = “http://[FQDN]/MediaAgentCallback/EventSink”;
try {
if(mediaPort.generalSubscribePush(contextID, eventStreamTimeout, localEventSinkURL) == WsStatus.STATUS_OK) {
System.out.print(“Subscription to events is performed successfully”);
System.out.print(“Events will be received through the callback interface “ + “ bound to the URL: “ + localEventSinkURL);
} else {
System.err.print(“Failed to subscribe to receive events”);
}
}
catch(GenException_Exception gex) {
System.err.print(“Failed to subscribe to receive events. Reason: “ + gex.getMessage());
}
catch(Exception ex) {
System.err.print(“Communication failure. Reason: “ + ex.getMessage());
}
As the example shows, the client should specify the URL where the callback interface is bound to. The Media Service will deliver events to the client through this callback interface.
Retrieving configuration
There are agent specific properties which should be retrieved from the service. These properties should be retrieved immediately after successful login and should be used till the agent logs out. The following code indicates how to retrieve these properties.
Javax.xml.ws.Holder<PropertyArray> propertiesToUse = new javax.xml.ws.Holder<PropertyArray>();
try {
if(mediaPort.generalGetParameters(contextID, MediaType.MT_VOICE, propertiesToUse) == WsStatus.STATUS_OK) {
if(propertiesToUse.value == null) {
System.err.print(“Failed to retrieve agent specific properties”);
return null;
}
else if(propertiesToUse.value.item == null) {
System.err.print(“Failed to retrieve agent specific properties”);
return null;
}
else if(propertiesToUse.value.item.size() <= 0) {
System.out.print(“No agent specific properties are available”);
return null;
}
System.out.print(“Number of agent specific properties retrieved: “ + String.valueOf(propertiesToUse.value.item.size()));
return propertiesToUse.value.item;
} else {
System.err.print(“Failed to retrieve agent specific properties”);
}
}
catch(GenException_Exception gex) {
System.err.print(“Failed to retrieve agent specific properties. Reason: “ + gex.getMessage());
}
catch(Exception ex) {
System.err.print(“Communication failure. Reason: “ + ex.getMessage());
}
return null;
The supported properties are listed in the following table.
Property | Description |
---|---|
ResourceID |
Unique resource id belonging to the currently logged in operator. |
Permissions |
Sequence of permissions the currently logged in agent has. |
Skills |
Sequence of skills the currently logged in agent has. |
Domains |
Sequence of domains the currently logged in agent can access. |
ClosureCodes |
Sequence of codes can be used to close tasks. |
HeartbeatInterval |
Period length (in seconds) to send heartbeats. |
URLDefaultTask |
The URL to navigate to in order to display an empty task area. |
URLDisplayTask |
The URL to navigate to in order to download received tasks. |
URLCloseTask |
The URL to navigate to in order to close active tasks. |
URLDisplayHistory |
The URL to navigate to in order to display contact history belonging to the active task. |
URLDefaultHistory |
The URL to navigate to in order to display an empty contact history area. |
URLContactSearch |
The URL to navigate to in order to browse contact database. |
URLContactProperty |
The URL to navigate to in order to change the contact properties belonging to the active task. |
URLCampaignHelp |
The URL to navigate to in order to display campaign specific help information. |
URLContactSwap |
The URL to navigate to in order to replace the current contact record. |
URLContactPrint |
The URL to navigate to in order to print the content of the current contact record. |
URLMessageSend |
The URL to navigate to in order to send a message to the contact. |
The URLs listed in the table come from the server side web.xml configuration file. By modifying these default URLs, it is easy to setup an environment where web forms displayed to operators are downloaded from some 3rd party CRM solutions.
Retrieving auxiliary codes
The example below shows how to retrieve the list of auxiliary reason codes from the Media Service. Operators should select from these codes when changing to auxiliary state.
javax.xml.ws.Holder<AuxReasonArray> auxCodesToUse = new javax.xml.ws.Holder<AuxReasonArray>();
try {
if(mediaPort.generalGetAUXReasons(contextID, auxCodesToUse) == WsStatus.STATUS_OK) {
if(auxCodesToUse.value == null) {
System.err.print("Failed to retrieve AUX reason codes");
return null;
}
else if(auxCodesToUse.value.item == null) {
System.err.print("Failed to retrieve AUX reason codes");
return null;
}
else if(auxCodesToUse.value.item.size() <= 0) {
System.out.print("No AUX reason codes are available");
return null;
}
System.out.print("Number of AUX reason codes retrieved: " + String.valueOf(auxCodesToUse.value.item.size()));
return auxCodesToUse.value.item;
} else {
System.err.print("Failed to retrieve AUX reason codes");
}
}
catch(GenException_Exception gex) {
System.err.print("Failed to retrieve AUX reason codes. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.print("Communication failure. Reason: " + ex.getMessage());
}
return null;
Retrieving business tags
Operators can assign business tags to tasks when closing them. The list of available business tags can be retrieved as follows.
javax.xml.ws.Holder<BusinessTagArray> businessTags = new javax.xml.ws.Holder<BusinessTagArray>();
try {
if(mediaPort.generalGetBusinessTags(contextID, media, businessTags) == WsStatus.STATUS_OK) {
if(businessTags.value == null) {
System.err.println("Failed to retrieve business tags");
return null;
}
else if(businessTags.value.getItem() == null) {
System.err.println("Failed to retrieve business tags");
return null;
}
else if(businessTags.value.getItem().size() <= 0) {
System.out.println("No business tags are available");
return null;
}
System.out.println("Number of business tags retrieved: " + String.valueOf(businessTags.value.getItem().size()));
return businessTags.value.getItem();
}
else {
System.err.println("Failed to retrieve business tags");
}
}
catch(GenException_Exception gex) {
System.err.println("Failed to retrieve business tags. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.println("Communication failure. Reason: " + ex.getMessage());
}
return null;
Closing specific task
The following code snippet demonstrates how to close a given task. Tasks are identified with session ids. The session id is received together with the task; it is part of the TASK_APPENDED
event.
String sessionID = "00000000ac167a4d483530d40216e900";
int closureCode = 48;
try {
mediaPort.generalGone(contextID, MediaType.MT_VOICE, sessionID, closureCode);
System.out.print("The task belonging to the session id: " + sessionID + " is closed with code: " + String.valueOf(closureCode));
}
catch(Exception ex) {
System.err.print("Failed to close the task. Reason: " + ex.getMessage());
}
As the snippet indicates, a closure code should be also specified when closing a task. The “Retrieving configuration” section describes how to retrieve the list of available closure codes. Depending on the selected closure code, the system might require to store some information into the session data unit. The following table lists the information which should be stored before the task is closed.
Data name | Format | Description | Selected closure code |
---|---|---|---|
CallbackStartTime |
yyyy-MM-dd hh:mm:ss | The earliest time the callback request can be performed. | 51 (“Reschedule the Task”) |
CallbackEndTime |
yyyy-MM-dd hh:mm:ss | The latest time the callback request can be performed. | 51 (“Reschedule the Task”) |
Destination |
string | The number should be called back. | 51 (“Reschedule the Task”) |
OriginalDestination |
string | The number originally called. | 51 (“Reschedule the Task”) |
PreferLastResource |
0/1/2 | Specifies whether to prefer the current agent when distributing the callback request. Anyone (0), Prefer me (1), Only me (2) | 51 (“Reschedule the Task”) |
ReasonCode |
numeric | Specifies that the interaction was failed. | 33 (“Failed Interaction”) |
MinorCode |
numeric | Describes the reason why the interaction was failed (fax, voice mail, no answer etc). | 33 (“Failed Interaction”) |
KeepRecording |
0/1 | Specifies whether to store the recorded conversation permanently or it can be removed. | Any |
NeverDeleteRecording |
0/1 | Specified whether to keep media file even if recording rule specifies to delete it. | Any |
AudioQuality |
string (poor, average, good, excellent) | Audio quality reported by the agent | Any |
BusinessTag |
string | Business tag selected by the agent | Any |
See the section “Storing data to session data unit” to understand how to store data into the session data unit.
Picking up alerting calls
If the auto-answer feature is switched on (see the section “Login to specific media”) when a call is routed to the operator’s extension, the system automatically picks up the call. Otherwise, an answer call request should be issued to connect the operator. The following code snippet shows how to send this request. The call which should be picked up is identified with the session id.
String sessionID = "00000000ac167a4d483530d40216e900";
try {
if(mediaPort.telephonyAnswerCall(contextID, sessionID) == WsStatus.STATUS_OK) {
System.out.print("The call belonging to the session id: " + sessionID + " is picked up");
} else {
System.err.print("Failed to pickup the specified call");
}
}
catch(GenException_Exception gex) {
System.err.print("Failed to pickup the specified call. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.print("Communication failure. Reason: " + ex.getMessage());
}
Disconnecting calls
After a call is connected to the agent’s phone, it can be disconnected either by the contact or the agent. To be dropped by the agent, a drop call request should be issued.
String sessionID = "00000000ac167a4d483530d40216e900";
try {
if(mediaPort.telephonyDropCall(contextID, sessionID) == WsStatus.STATUS_OK) {
System.out.print("The call belonging to the session id: " + sessionID + " is disconnected");
} else {
System.err.print("Failed to drop the specified call");
}
}
catch(GenException_Exception gex) {
System.err.print("Failed to drop the specified call. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.print("Communication failure. Reason: " + ex.getMessage());
}
Taking calls to held state
At any time during conversation with the contact, the call can be put on hold by the operator. It requires sending a hold call request to the Media Service. While being in hold state, remote party hears music or other pre-recorded information provided by the underlying UC platform.
String sessionID = "00000000ac167a4d483530d40216e900";
try {
if(mediaPort.telephonyTakeCallToHeld(contextID, sessionID) == WsStatus.STATUS_OK) {
System.out.print("The call belonging to the session id: " + sessionID + " is taken to held state");
} else {
System.err.print("Failed to take the specified call to held state");
}
}
catch(GenException_Exception gex) {
System.err.print("Failed to take the specified call to held state. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.print("Communication failure. Reason: " + ex.getMessage());
}
Initiating consultation calls
While the call established between the agent and the contact is on hold, agent has the opportunity to initiate a consultation call. Before doing that, the consultant’s phone number to be dialed should be stored to the “AssistanceCallDestination” session data unit field. Then a code segment similar to the following one should be executed.
String sessionID = "00000000ac167a4d483530d40216e900";
try {
if(mediaPort.telephonyStartAssistanceCall(contextID, sessionID) == WsStatus.STATUS_OK) {
System.out.print("Consultation call is initiated successfully for session: " + sessionID);
} else {
System.err.print("Failed to initiate consultation call");
}
}
catch(GenException_Exception gex) {
System.err.print("Failed to initiate consultation call. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.print("Communication failure. Reason: " + ex.getMessage());
}
Besides AssistanceCallDestination
, clients can store VideoCall
(0|1) to instruct CE to initiate video call to consultant and they can store TransferNow
(0|1) to ask for blind transfer.
Dropping consultation calls
At any time while the consultant’s phone number is being dialed, or the agent is already connected to the consultant, the consultation call can be terminated by the operator. This requires a code snippet as follows.
String sessionID = "00000000ac167a4d483530d40216e900";
try {
if(mediaPort.telephonyDropAssistanceCall(contextID, sessionID) == WsStatus.STATUS_OK) {
System.out.print("Consultation call belonging to session: " + sessionID + " is dropped");
} else {
System.err.print("Failed to drop the specified consultation call");
}
}
catch(GenException_Exception gex) {
System.err.print("Failed to drop the specified consultation call. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.print("Communication failure. Reason: " + ex.getMessage());
}
Transferring calls to consultants
While the call established between the agent and the contact is on hold, and a call between the agent and the consultant is connected, the agent might decide to transfer the contact to the consultant. This connects the contact to the consultant, drops out the agent from both calls and takes the agent into wrapup status. As usual, in this status the agent still has the task but has no any communication channel established.
String sessionID = "00000000ac167a4d483530d40216e900";
try {
if(mediaPort.telephonyTransferCall(contextID, sessionID) == WsStatus.STATUS_OK) {
System.out.print("The contact originally taken part in the conversion: " + sessionID + " is transferred to the consultant");
} else {
System.err.print("Failed to transfer contact to the consultant");
}
}
catch(GenException_Exception gex) {
System.err.print("Failed to transfer contact to the consultant. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.print("Communication failure. Reason: " + ex.getMessage());
}
Setting up a conference call
While the call established between the agent and the contact is on hold, and a call between the agent and the consultant is connected, the agent might decide to establish a conference between himself, the contact and the consultant.
String sessionID = "00000000ac167a4d483530d40216e900";
try {
if(mediaPort.telephonyConferenceCall(contextID, sessionID) == WsStatus.STATUS_OK) {
System.out.print("Conference call request is issued successfully");
} else {
System.err.print("Failed to initiate conference call");
}
}
catch(GenException_Exception gex) {
System.err.print("Failed to setup conference call. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.print("Communication failure. Reason: " + ex.getMessage());
}
Dialing contacts
Preview dialing passes a task to the agent without initiating any communication automatically. The agent is taken into preview status and gets the task. He can check the content of the contact record, he can modify data in that and might decide whether to dial the associated contact or not. If he decides not to dial the contact, he can close the task. If he decides to dial that, a similar code snippet is required in order to send a dial request to the Media Service.
String sessionID = "00000000ac167a4d483530d40216e900";
try {
if(mediaPort.telephonyDialContact(contextID, sessionID) == WsStatus.STATUS_OK) {
System.out.print("The contact belonging to the session: " + sessionID + " is dialed successfully");
} else {
System.err.print("Failed to dial the specified contact");
}
}
catch(GenException_Exception gex) {
System.err.print("Failed to dial the specified contact. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.print("Communication failure. Reason: " + ex.getMessage());
}
The service starts dialing the phone number assigned with the task. The operator can detect call outcome based on the in-band audio information. At any time he has the option to drop the call as described in the “Disconnecting calls” section.
Reading data from session data unit
Session data unit is used to store temporary data belonging to tasks. One and only one session data unit exists for each task. The session data unit lives till the task is opened. While the session data unit exists anybody knowing the session id can store data to the unit and can retrieve any data from that. Actually, most of the core servers do that. They store wide range of information to the session data unit. In order to read data from the unit, a similar code segment is required. The code reads the media type and the dialing mode associated with the given task.
javax.xml.ws.Holder<SessionDataArray> dataRetrieved = new javax.xml.ws.Holder<SessionDataArray>();
String sessionID = "00000000ac167a4d483530d40216e900";
StringArray dataToRetrieve = new StringArray();
dataToRetrieve.item = new ArrayList<String>();
dataToRetrieve.item.add("MediaType");
dataToRetrieve.item.add("DialingMode");
try {
if(mediaPort.sduGetValues(contextID, sessionID, dataToRetrieve, dataRetrieved) == WsStatus.STATUS_OK) {
if(dataRetrieved.value == null) {
System.out.print("Failed to retrieve the specified data from the session data unit");
return null;
}
else if(dataRetrieved.value.item == null) {
System.out.print("Failed to retrieve the specified data from the session data unit");
return null;
}
System.out.print("Data is retrieved from the session data unit");
return dataRetrieved.value.item;
} else {
System.err.print("Failed to retrieve the specified data from the session data unit");
}
}
catch(GenException_Exception gex) {
System.err.print("Failed to retrieve the specified data from the session data unit. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.print("Communication failure. Reason: " + ex.getMessage());
}
return null;
Just for informative purposes, the following table lists those data which are most frequently stored in session data units. Most of them are stored by the core servers. These ones are read-only for clients. Beyond these read-only fields, clients can store additional ones to the data unit and can read any stored values from that.
Field | Read only? | Format | Description |
---|---|---|---|
ACWLength |
yes | numeric | The maximum time – in seconds - allowed being in passive state after closing the task. |
AMDMode |
yes | Switch-defined / Connect / Disconnect | Answering machine detection mode when dialing the contact. |
AnsweringDevice |
yes | string | Indicates the remote party answered the outbound call. |
AssistanceCallDestination |
no | string | Destination to be dialed for consultation purposes while the operator-contact call is in held state. |
Callback |
yes | true/false | Specifies whether the given task belongs to a callback request or not. |
CallbackEndTime |
no | yyyy-MM-dd hh:mm:ss | The latest time the contact belonging to the task can be called back. |
CallbackStartTime |
no | yyyy-MM-dd hh:mm:ss | The earliest time the contact belonging to the task can be called back. |
CampaignID |
yes | numeric | Identifies the campaign associated with the given task. |
ContactID |
yes | numeric | Identifies the contact associated with the given task. |
ContactType |
yes | numeric | Indicates the type of the phone number (e.g. GSM, lined office, lined home) on which the contact is to be dialed next. |
Destination |
no | string | The contact’s phone number to be dialed. |
DialingMode |
yes | Progressive/Preview/Predictive | Dialing mode to be used. |
Direction |
yes | Inbound/Outbound | Indicates whether the communication is originally initiated by the system or the contact. |
DistributionType |
yes | Automatic/Operator-requested | Specifies whether the given task can be passed to any operator having the required skill, only for that one which is stored in the PreferredResourceID field. |
FirstNode |
yes | numeric | Specifies the first script node which should be displayed for the operator. |
KeepRecording |
no | 0/1 | Specifies whether to store the recorded conversation permanently or it can be removed. |
MapdID |
yes | numeric | Identifies the voice gateway through which the outbound call was initiated or the inbound one was received. |
MaxRingingTime |
yes | numeric | The maximum time – ins seconds – the contact can be alerted before classifying the call as not answered. |
MediaType |
yes | 1: voice; 2: SMS; 3: email; 4: chat | The media type associated with the given task. |
MinorCode |
no | numeric | Describes the reason why the interaction was failed (fax, voice mail, no answer etc). |
OriginalDestination |
no | string | For rescheduled tasks this indicates the phone number on which the contact was originally called. |
Origination |
yes | string | The endpoint (phone number, email address) from which the communication request was initiated. |
PreferLastResource |
no | 0/1 | Specifies whether to prefer the most recent operator when distributing the given task again. |
PreferredResourceID |
yes | numeric | It identifies the operator which should be preferred when distributing the tasks again. |
PreviewDialingTimeout |
yes | numeric | For tasks associated with preview dialing, this time specifies – in seconds – the timeout when dialing the contact should be started automatically. |
PreviousDBSessionState |
yes | numeric | The contact record state when the task is initiated. |
ReasonCode |
no | numeric | Specifies that outcome with the communication attempt (successful, failed, callback). |
RetryCount |
yes | numeric | The number of failed communication attempts. |
SignalingInfo |
yes | string | Signaling information. For calls it stores the call info. |
SkillID |
yes | numeric | It identifies the skill which is required to receive the given task. |
Storing data to session data unit
To store new data items into the session data unit or overwrite existing ones, the following code segment might match the needs. This example shows how to store the required data when the operator schedules a callback. The system needs the earliest and the latest time between which the callback should occur. The system also needs the phone number to be dialed back, and also needs the information whether the currently recorded conversation should be stored permanently or can be discarded.
String sessionID = "00000000ac167a4d483530d40216e900";
SessionDataArray dataToStore = new SessionDataArray();
dataToStore.item = new ArrayList<SessionData>();
SessionData callbackStartTime = new SessionData();
callbackStartTime.name = "CallbackStartTime";
callbackStartTime.value = "2008-08-01 09:30:00";
SessionData callbackEndTime = new SessionData();
callbackEndTime.name = "CallbackEndTime";
callbackEndTime.value = "2008-08-01 11:30:00";
SessionData numberToCallBack = new SessionData();
numberToCallBack.name = "Destination";
numberToCallBack.value = "06704553345";
SessionData keepRecording = new SessionData();
keepRecording.name = "KeepRecording";
keepRecording.value = "1";
dataToStore.item.add(callbackStartTime);
dataToStore.item.add(callbackEndTime);
dataToStore.item.add(numberToCallBack);
dataToStore.item.add(keepRecording);
try {
if(mediaPort.sduSetValues(contextID, sessionID, dataToStore) == WsStatus.STATUS_OK) {
System.out.print("Data is stored to the session data unit");
} else {
System.err.print("Failed to store data to the session data unit");
}
}
catch(GenException_Exception gex) {
System.err.print("Failed to store data to the session data unit. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.print("Communication failure. Reason: " + ex.getMessage());
}
Reading data from contact records
Several scenarios might require reading data from the contact record; especially when developing customized operator applications. Data can be read only from those contact records which belong to the tasks currently being opened at the operator. When trying to read data from a given contact record, the contact record is identified with a <campaign id, contact id>
key pair. Both of the campaign and the contact id can be retrieved from the session data unit.
Assuming that the campaign and the contact id are already known, the following example demonstrates how to read a data value from the contact record. Actually, the example reads the value of the “debt” database column.
int campaignID = 5;
int contactID = 213;
javax.xml.ws.Holder<FieldData> dataToRetrieve = new javax.xml.ws.Holder<FieldData>();
dataToRetrieve.value = new FieldData();
dataToRetrieve.value.name = "debt";
dataToRetrieve.value.type = ContactDataType.CDT_LONG;
dataToRetrieve.value.value = "";
try {
if(mediaPort.sysDBGetCampaignField(contextID, campaignID, contactID, dataToRetrieve) == WsStatus.STATUS_OK) {
if(dataToRetrieve.value.value != null) {
System.out.print("The customer's debt is: " + dataToRetrieve.value.value);
return dataToRetrieve.value.value;
} else {
System.err.print("Failed to retrieve the specified data from the contact record");
}
} else {
System.err.print("Failed to retrieve the specified data from the contact record");
}
}
catch(GenException_Exception gex) {
System.err.print("Failed to retrieve the specified data from the contact record. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.print("Communication failure. Reason: " + ex.getMessage());
}
return null;
Updating data in contact records
Clients also have the opportunity to overwrite any database column in the contact record. The following code snippet overwrites the “debt” column with a new value.
int campaignID = 5;
int contactID = 213;
FieldData dataToStore = new FieldData();
dataToStore.name = "debt";
dataToStore.type = ContactDataType.CDT_LONG;
dataToStore.value = "255";
try {
if(mediaPort.sysDBSetCampaignField(contextID, campaignID, contactID, dataToStore) == WsStatus.STATUS_OK) {
System.out.print("The customer's debt is updated");
} else {
System.err.print("Failed to update the specified data in the contact record");
}
}
catch(GenException_Exception gex) {
System.err.print("Failed to update the specified data in the contact record. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.print("Communication failure. Reason: " + ex.getMessage());
}
return null;