Skip to content

Commit

Permalink
Adding Citrix support, RSA customization, and updating docs (#821)
Browse files Browse the repository at this point in the history
* Adding Citrix support, new request-storage-access customization parameters, and updating documentation
---------

Co-authored-by: Andy Wang <[email protected]>
  • Loading branch information
andywang219 and Andy Wang authored Jan 5, 2024
1 parent 3d4a271 commit 1ee5d13
Show file tree
Hide file tree
Showing 16 changed files with 356 additions and 237 deletions.
7 changes: 3 additions & 4 deletions Documentation-DR.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,11 +234,11 @@ globalConnect.core.initCCP(containerDiv, {

Since the full `window.connect` binding will not be available until the Global Resiliency setup is initialized on the page, code that relies on modifying the Connect Streams object, such as ChatJS, TaskJS, and other custom code you may have written to work with the standard (non-Global Resiliency) Streams distribution should be loaded in your code that handles the promise returned by your function passed as the getPrimaryRegion parameter of `globalConnect.core.initCCP()`, instead of being loaded immediately at page load time along with Streams itself, as with the non-Global Resiliency version of Streams.

Any scripts loaded this way should also be loaded as part of a `globalConnect.core.onFailoverCompleted()` hook, to ensure that the code will apply to the newly-active CCP in the event of an active region change; otherwise the code would be applied only to the CCP for the region that was originally active.
Any scripts loaded this way should also be loaded as part of a `globalConnect.core.onFailoverComplete()` hook, to ensure that the code will apply to the newly-active CCP in the event of an active region change; otherwise the code would be applied only to the CCP for the region that was originally active.


```
globalConnect.core.onFailoverCompleted(() => {
globalConnect.core.onFailoverComplete(() => {
const script = document.createElement('script');
script.src = "https://example.com/amazon-connect-chat.js";
document.body.appendChild(script);
Expand Down Expand Up @@ -331,7 +331,7 @@ This function provides a convenient place to set up init-time logic using the St

Returns a function that can be called if you wish to deregister the trigger.

### globalConnect.core.onFailoverCompleted(f)
### globalConnect.core.onFailoverComplete(f)

Register a function to be triggered when the UI changes to display a different region, and agents are able to begin taking contacts in the new CCP region. This function will also be triggered when CCP is initialized and ready for use, if the region whose CCP was provided in the `ccpUrl` parameter (i.e. not the `standByRegion`) is not the currently active region for the agent. If you wish, you can set up hooks using this function before calling `globalConnect.core.initCCP()`.

Expand All @@ -340,7 +340,6 @@ The function will be called with an Object parameter with three properties:

1. `activeRegion`: the string name of the AWS region for the newly-active CCP instance
2. `activeCcpUrl`: the value of the ccpUrl parameter for the newly-active instance, as originally provided in the initCCP() parameters
3. `connect`: the Streams API object for the newly-active region’s CCP.

Returns a function that can be called if you wish to deregister the trigger.

Expand Down
7 changes: 6 additions & 1 deletion Documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,13 @@ everything set up correctly and that you are able to listen for events.
ringtoneUrl: '[your-ringtone-filepath].mp3', // optional, defaults to CCP’s default ringtone if a falsy value is set
disableEchoCancellation: false, // optional, defaults to false
allowFramedVideoCall: true, // optional, default to false
VDIPlatform: null // optional, provide with 'CITRIX' if using Citrix VDI, or use enum VDIPlatformType
allowEarlyGum: true //optional, default to true
},
storageAccess: {
canRequest: true, // By default this is set to true. You can set it to false to opt out from checking storage access.
mode: "custom", // To use the default banner, set this to "default"
/** More customization options can be found here: https://docs.aws.amazon.com/connect/latest/adminguide/admin-3pcookies.html#config-grant-access */
/** More customization options can be found here: https://github.com/amazon-connect/amazon-connect-streams/blob/master/src/index.d.ts under StorageAccessParameters */
},
pageOptions: { //optional
enableAudioDeviceSettings: false, //optional, defaults to 'false'
Expand Down Expand Up @@ -269,6 +270,9 @@ and made available to your JS client code.
the softphone session must not be closed during the course of a softphone
call or the call will be disconnected. If `allowFramedSoftphone` is `true`,
the softphone components will be allowed to be hosted in this window or tab.
If `allowFramedSoftphone` is `false`, please make sure you are importing the
[lily-rtc.js](https://github.com/aws/connect-rtc-js) package and adding `connect.core.initSoftphoneManager()`
to your code after `connect.core.initCCP()`.
* `disableRingtone`: This option allows you to completely disable the built-in
ringtone audio that is played when a call is incoming.
* `ringtoneUrl`: If the ringtone is not disabled, this allows for overriding
Expand All @@ -279,6 +283,7 @@ and made available to your JS client code.
- `allowFramedVideoCall`: Currently video call can only be in one single window or tab.. If `true`, CCP will handle
video calling experience in this window or tab and agents would be able to see and turn
on their video if they have video permission set in the security profile. If `false` or not provided, CCP will only provide voice calling.
- `VDIPlatform`: This option is only applicable for virtual desktop interface integrations. If set, it will configure CCP to optimize softphone audio configuration for the VDI. Options can be provided by using enum `VDIPlatformType`. If `allowFramedSoftphone` is `false` and `VDIPlatform` is going to be set, please make sure you are passing this parameter into `connect.core.initSoftphoneManager()`. For example, `connect.core.initSoftphoneManager({ VDIPlatform: "CITRIX" })`
- `allowEarlyGum`: If `true` or not provided, CCP will capture the agent’s browser microphone media stream before the contact arrives to reduce the call setup latency. If `false`, CCP will only capture agent media stream after the contact arrives.
- `pageOptions`: This object is optional and allows you to configure which configuration sections are displayed in the settings tab.
- `enableAudioDeviceSettings`: If `true`, the settings tab will display a section for configuring audio input and output devices for the agent's local
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "amazon-connect-streams",
"version": "2.11.0",
"version": "2.12.0",
"description": "Amazon Connect Streams Library",
"engines": {
"node": ">=12.0.0"
Expand Down
2 changes: 1 addition & 1 deletion release/connect-streams-dr-min.js

Large diffs are not rendered by default.

7 changes: 2 additions & 5 deletions release/connect-streams-dr.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion release/connect-streams-min.js

Large diffs are not rendered by default.

100 changes: 79 additions & 21 deletions release/connect-streams.js
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,8 @@
'user_busy_error',
'webrtc_error',
'realtime_communication_error',
'vdi_strategy_not_supported',
'vdi_redir_not_supported',
'other'
]);

Expand Down Expand Up @@ -26723,7 +26725,7 @@ AWS.apiLoader.services['connect']['2017-02-15'] = require('../apis/connect-2017-

connect.core = {};
connect.core.initialized = false;
connect.version = "2.11.0";
connect.version = "2.12.0";
connect.outerContextStreamsVersion = null;
connect.DEFAULT_BATCH_SIZE = 500;

Expand Down Expand Up @@ -28216,7 +28218,7 @@ AWS.apiLoader.services['connect']['2017-02-15'] = require('../apis/connect-2017-
connect.assertNotNull(containerDiv, 'containerDiv');
var iframe = document.createElement('iframe');
iframe.src = initCCPParams.ccpUrl;
iframe.allow = "microphone; camera; autoplay; clipboard-write";
iframe.allow = "microphone; camera; autoplay; clipboard-write; identity-credentials-get";
iframe.style = initCCPParams.style || "width: 100%; height: 100%";
iframe.title = initCCPParams.iframeTitle || CCP_IFRAME_NAME;
iframe.name = CCP_IFRAME_NAME;
Expand Down Expand Up @@ -31525,6 +31527,10 @@ AWS.apiLoader.services['connect']['2017-02-15'] = require('../apis/connect-2017-
global.lily = connect;
global.ccpVersion = "V2";

const VDIPlatformType = {
CITRIX: "CITRIX",
}

var RTPJobIntervalMs = 1000;
var statsReportingJobIntervalMs = 30000;
var streamBufferSize = 500;
Expand Down Expand Up @@ -31594,16 +31600,56 @@ AWS.apiLoader.services['connect']['2017-02-15'] = require('../apis/connect-2017-
var self = this;
logger = new SoftphoneLogger(connect.getLog());
logger.info("[Softphone Manager] softphone manager initialization has begun").sendInternalLogToServer();
logger.info(`[SoftphoneManager] Client Provided Strategy: ${softphoneParams.VDIPlatform}`).sendInternalLogToServer();

let rtcJsStrategy;
if (softphoneParams.VDIPlatform) {
try {
if (softphoneParams.VDIPlatform === VDIPlatformType.CITRIX) {
rtcJsStrategy = new connect.CitrixVDIStrategy();
logger.info(`[SoftphoneManager] Strategy constructor retrieved: ${rtcJsStrategy}`).sendInternalLogToServer();
} else {
throw new Error("VDI Strategy not supported");
}
} catch (error) {
if (error.message === "VDI Strategy not supported") {
publishError(SoftphoneErrorTypes.VDI_STRATEGY_NOT_SUPPORTED, error.message, "");
throw error;
}
else if (error.message === "Citrix WebRTC redirection feature is NOT supported!") {
publishError(SoftphoneErrorTypes.VDI_REDIR_NOT_SUPPORTED, error.message, "");
throw error;
}
else {
publishError(SoftphoneErrorTypes.OTHER, error.message, "");
throw error;
}
}
}

var rtcPeerConnectionFactory;
if (connect.RtcPeerConnectionFactory) {
rtcPeerConnectionFactory = new connect.RtcPeerConnectionFactory(logger,
connect.core.getWebSocketManager(),
softphoneClientId,
connect.hitch(self, requestIceAccess, {
transportType: "softphone",
softphoneClientId: softphoneClientId
}),
connect.hitch(self, publishError));
if (rtcJsStrategy) {
rtcPeerConnectionFactory = new connect.RtcPeerConnectionFactory(logger,
connect.core.getWebSocketManager(),
softphoneClientId,
connect.hitch(self, requestIceAccess, {
transportType: "softphone",
softphoneClientId: softphoneClientId
}),
connect.hitch(self, publishError),
rtcJsStrategy
);
} else {
rtcPeerConnectionFactory = new connect.RtcPeerConnectionFactory(logger,
connect.core.getWebSocketManager(),
softphoneClientId,
connect.hitch(self, requestIceAccess, {
transportType: "softphone",
softphoneClientId: softphoneClientId
}),
connect.hitch(self, publishError));
}
}
if (!SoftphoneManager.isBrowserSoftPhoneSupported()) {
publishError(SoftphoneErrorTypes.UNSUPPORTED_BROWSER,
Expand Down Expand Up @@ -31733,14 +31779,27 @@ AWS.apiLoader.services['connect']['2017-02-15'] = require('../apis/connect-2017-
if (callConfig.useWebSocketProvider) {
webSocketProvider = connect.core.getWebSocketManager();
}
var session = new connect.RTCSession(
callConfig.signalingEndpoint,
callConfig.iceServers,
softphoneInfo.callContextToken,
logger,
contact.getContactId(),
agentConnectionId,
webSocketProvider);
var session;
if (rtcJsStrategy) {
session = new connect.RTCSession(
callConfig.signalingEndpoint,
callConfig.iceServers,
softphoneInfo.callContextToken,
logger,
contact.getContactId(),
agentConnectionId,
webSocketProvider,
rtcJsStrategy);
} else {
session = new connect.RTCSession(
callConfig.signalingEndpoint,
callConfig.iceServers,
softphoneInfo.callContextToken,
logger,
contact.getContactId(),
agentConnectionId,
webSocketProvider);
}

session.echoCancellation = !softphoneParams.disableEchoCancellation;

Expand Down Expand Up @@ -31796,7 +31855,7 @@ AWS.apiLoader.services['connect']['2017-02-15'] = require('../apis/connect-2017-
});
};

session.remoteAudioElement = document.getElementById('remote-audio');
session.remoteAudioElement = document.getElementById('remote-audio') || window.parent.parent.document.getElementById('remote-audio');
if (rtcPeerConnectionFactory) {
session.connect(rtcPeerConnectionFactory.get(callConfig.iceServers));
} else {
Expand Down Expand Up @@ -31993,7 +32052,7 @@ AWS.apiLoader.services['connect']['2017-02-15'] = require('../apis/connect-2017-
return;
}

var remoteAudioElement = document.getElementById('remote-audio');
var remoteAudioElement = document.getElementById('remote-audio') || window.parent.parent.document.getElementById('remote-audio');
if (remoteAudioElement && typeof remoteAudioElement.setSinkId === 'function') {
remoteAudioElement.setSinkId(deviceId).then(() => {
connect.getLog().info(`[Audio Device Settings] Speaker device ${deviceId} successfully set to speaker audio element`).sendInternalLogToServer();
Expand Down Expand Up @@ -32478,7 +32537,6 @@ AWS.apiLoader.services['connect']['2017-02-15'] = require('../apis/connect-2017-
connect.SoftphoneManager = SoftphoneManager;
})();


/***/ }),

/***/ 944:
Expand Down
2 changes: 2 additions & 0 deletions src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@
'user_busy_error',
'webrtc_error',
'realtime_communication_error',
'vdi_strategy_not_supported',
'vdi_redir_not_supported',
'other'
]);

Expand Down
2 changes: 1 addition & 1 deletion src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -1504,7 +1504,7 @@
connect.assertNotNull(containerDiv, 'containerDiv');
var iframe = document.createElement('iframe');
iframe.src = initCCPParams.ccpUrl;
iframe.allow = "microphone; camera; autoplay; clipboard-write";
iframe.allow = "microphone; camera; autoplay; clipboard-write; identity-credentials-get";
iframe.style = initCCPParams.style || "width: 100%; height: 100%";
iframe.title = initCCPParams.iframeTitle || CCP_IFRAME_NAME;
iframe.name = CCP_IFRAME_NAME;
Expand Down
5 changes: 1 addition & 4 deletions src/drCoordinator/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,6 @@

var divStyle = extractDivStyle(globalContainerDiv);

if (divStyle.display == "none") {
uiFailoverEnabled = false;
}

if (parseInt(divStyle.height) <= 0) {
globalContainerDiv.style.height = DIV_DEFAULT_HEIGHT.height; // populating ccp
divStyle.height = DIV_DEFAULT_HEIGHT.height;
Expand Down Expand Up @@ -142,6 +138,7 @@
});
var globalIframe = document.createElement("iframe");
globalIframe.style = GLOBALIFRAME_STYLE;
globalIframe.allow = "microphone; camera; autoplay; clipboard-write; identity-credentials-get";
globalIframe.id = GLOBALIFRAME_ID;
globalIframe.scrolling = "no";

Expand Down
30 changes: 28 additions & 2 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,11 @@ declare namespace connect {
function hitch<T extends (...args: any[]) => any>(scope: object, method: T): T;

type StorageAccessCallbackData = {
hasAccess?: boolean;
[key: string]: any;
data: {
hasAccess?: boolean;
[key: string]: any;
},
event: string
}
type StorageAccessCallback = (option: StorageAccessCallbackData) => void;

Expand Down Expand Up @@ -373,6 +376,15 @@ declare namespace connect {
denyBannerLearnMoreUrl?: string;
accessBannerLearnMoreText?: string;
denyBannerLearnMoreText?: string;
// pop up customization
popupTitle?: string;
popupBannerDescription?: string;
popupBannerLearnMoreText?: string;
popupBannerButtonText?: string;
// popup prompt customization
promptBannerTitle?: string;
promptBannerDescription?: string;
promptBannerButtonText?: string;
};
};

Expand Down Expand Up @@ -404,6 +416,13 @@ declare namespace connect {
*/
readonly allowFramedVideoCall?: boolean;

/**
* VDI SDK support, we are currently only supporting CITRIX
* To specify that the VDI environment is Citrix, please set this value to `CITRIX` or
* `VDIPlatformType.CITRIX`
*/
readonly VDIPlatform?: string;

/**
* If `true` or not provided, CCP will capture the agent’s browser microphone media stream before the contact arrives to reduce the call setup latency.
* If `false`, CCP will only capture agent media stream after the contact arrives.
Expand Down Expand Up @@ -707,6 +726,7 @@ declare namespace connect {
ENDED = "ended",
ERROR = "error",
ACCEPTED = "accepted",
PAUSED = "paused"
}

/** An enumeration listing the different high-level states that a contact can have. */
Expand Down Expand Up @@ -774,6 +794,12 @@ declare namespace connect {
TASK = "task",
}

/** This enumeration lists the different types of VDI Platform supported. */
enum VDIPlatformType {
/** Citrix. */
CITRIX = "CITRIX"
}

/** This enumeration lists the different types of contact channels. */
enum ChannelType {
/** A voice contact. */
Expand Down
Loading

0 comments on commit 1ee5d13

Please sign in to comment.