Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,29 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

# [Unreleased](https://github.com/MyPureCloud/genesys-cloud-webrtc-sdk/compare/v12.1.0...HEAD)
# [Unreleased](https://github.com/MyPureCloud/genesys-cloud-webrtc-sdk/compare/v13.0.0...HEAD)

# [v13.0.0](https://github.com/MyPureCloud/genesys-cloud-webrtc-sdk/compare/v12.1.0...HEAD)
### Breaking Changes
* [STREAM-1351](https://inindca.atlassian.net/browse/STREAM-1351) - Removed `v2.conversations.{id}.media` notification subscription. Removed the `activeVideoParticipantsUpdate` session event and `IOnScreenParticipantsUpdate` interface. Speaker and on-screen participant updates are now entirely handled via the data channel.

### Added
* [STREAM-1056](https://inindca.atlassian.net/browse/STREAM-1056) Added documentation for live screen monitoring functionality

### Fixed
* [STREAM-905](https://inindca.atlassian.net/browse/STREAM-905) - Fix issue where `sessionStarted` was not emitted for calls that re-use persistent connections after a media recovery has occurred. Now initializing `_emittedSessionStarteds` for reinvites but only emitting if not a reinvite.

# [v12.1.0](https://github.com/MyPureCloud/genesys-cloud-webrtc-sdk/compare/v12.0.0...v12.1.0)
### Added
* [STREAM-1153](https://inindca.atlassian.net/browse/STREAM-1153) - Add support for monitoring multiple screens during live monitoring sessions
* [STREAM-1123](https://inindca.atlassian.net/browse/STREAM-1123) - Only update necessary tracks when changing devices. Prevent virtual background from getting replaced
* [STREAM-781](https://inindca.atlassian.net/browse/STREAM-781) - Fix issue where hold caused `Unhandled promise rejection from setConversationHeld` for inactive conversations.

### Changed
* [STREAM-1211](https://inindca.atlassian.net/browse/STREAM-1178) - Update `axios` to `v1.13.5`.
* [STREAM-1211](https://inindca.atlassian.net/browse/STREAM-1211) - Update `axios` to `v1.13.5`.
* [STREAM-1285](https://inindca.atlassian.net/browse/STREAM-1285) - Refactor `handlePropose` in SoftphoneSessionHandler for clarity and future changes. Update associated comments to better reflect implementation.
* [STREAM-1403](https://inindca.atlassian.net/browse/STREAM-1403) - Update `lodash` to `v4.18.1` to address Snyk vulnerability.
* [STREAM-1423](https://inindca.atlassian.net/browse/STREAM-1423) - Update `axios` to `v1.15.0`.

# [v12.0.0](https://github.com/MyPureCloud/genesys-cloud-webrtc-sdk/compare/v11.5.1...v12.0.0)
### Added
Expand Down
13 changes: 12 additions & 1 deletion doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- [WebRTC SoftPhone]
- [WebRTC Video Conferencing]
- [WebRTC Screen Recording]
- [WebRTC Live Screen Monitoring]
- [WebRTC Media] (media, devices, and permissions support)
- [WebRTC Headset Integration]

Expand Down Expand Up @@ -131,6 +132,7 @@ interface ISdkConfig {
wsHost?: string;
autoConnectSessions?: boolean;
autoAcceptPendingScreenRecordingRequests?: boolean;
autoAcceptPendingLiveScreenMonitoringRequests?: boolean;
jidResource?: string;
disableAutoAnswer?: boolean;
logLevel?: LogLevels;
Expand Down Expand Up @@ -220,6 +222,14 @@ If true, incoming proposes for screen recording sessions will be accepted immedi
and no `pendingSession` event will be emitted. The consumer will still have to react to
`sessionStarted` in order to add screen media and then call `sdk.acceptSession(...)`.

#### `autoAcceptPendingLiveScreenMonitoringRequests`

`autoAcceptPendingLiveScreenMonitoringRequests?: boolean;` Optional: default `false`

If true, incoming proposes for live screen monitoring sessions will be accepted immediately
and no `pendingSession` event will be emitted. The consumer will still have to react to
`sessionStarted` in order to add screen media and then call `sdk.acceptSession(...)`.

#### `jidResource`

`jidResource?: string;` Optional: default `undefined`
Expand Down Expand Up @@ -1200,7 +1210,7 @@ Params:
provided, no media will be requested.
- `audioElement?: HTMLAudioElement` Optional: audio element to attach incoming audio to
default is sdk `defaults.audioElement`
- `videoElement?: HTMLAudioElement` Optional: video element to attach incoming video to
- `videoElement?: HTMLVideoElement` Optional: video element to attach incoming video to
default is sdk `defaults.videoElement`. (only used for video sessions)
- `videoDeviceId?: string | boolean | null;` Optional: See [ISdkMediaDeviceIds] for full details
- `audioDeviceId?: string | boolean | null;` Optional: See [ISdkMediaDeviceIds] for full details
Expand Down Expand Up @@ -2042,6 +2052,7 @@ The SDK will add the `type` to give more clarity as to why the error was thrown.
[WebRTC SoftPhone]: softphone.md
[WebRTC Video Conferencing]: video.md
[WebRTC Screen Recording]: screen-recording.md
[WebRTC Live Screen Monitoring]: live-screen-monitoring.md
[WebRTC Media]: media.md
[ISdkMediaDeviceIds]: media.md#isdkmediadeviceids
[SDK Media audioTrackVolume event]: media.md#audiotrackvolume
Expand Down
175 changes: 175 additions & 0 deletions doc/live-screen-monitoring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# Genesys Cloud WebRTC SDK Live Screen Monitoring

This SDK supports live screen monitoring functionality that allows real-time viewing of user screens. Live screen monitoring sessions are initiated by the server and provide the ability to observe user activity in real-time for support, training, or compliance purposes.

When the server determines that live screen monitoring should be initiated, it will send a `pendingSession` similar to how other session types work (ie. softphone and video conversations). The consuming client must accept the `pendingSession`, gather screen media, and add the media to that session.

> *Note: live screen monitoring does not support guest users.*

## WebRTC SDK Live Screen Monitoring Index
This documentation expands upon the [GenesysCloudWebrtcSdk] documentation but is specific to
live screen monitoring.

* [Example usage](#example-usage)
* [Observer vs Target Roles](#observer-vs-target-roles)

## Prerequisites

You must have live screen monitoring policies in place and the WebRTC SDK must be configured to allow live screen monitoring sessions.

## Example Usage

### Automatic Accept (default)
Signaling is automatically accepted by the SDK. When the live screen monitoring session comes in, you need to add your screen tracks and then call `sdk.acceptSession(session)`.

``` ts
// set up needed events
sdk.on('sessionStarted', async (session) => {
if (sdk.isLiveScreenMonitoringSession(session)) {
// gather media - the SDK does *not* gather screen media for you
const screenStream = await navigator.getDisplayMedia();

// create metadata for the screen being monitored
const track = screenStream.getTracks()[0];
const { height, width, deviceId } = track.getSettings();
const liveScreenMonitoringMetadata = [
{
trackId: track.id,
screenId: deviceId,
originX: 0,
originY: 0,
resolutionX: width,
resolutionY: height,
primary: true,
}
];

sdk.acceptSession({
conversationId: session.conversationId,
sessionType: session.sessionType,
mediaStream: screenStream,
liveScreenMonitoringMetadata
});
}
});
```

### Manual Accept
If you want to manually control the acceptance of live screen monitoring sessions:

``` ts
const sdk = new GenesysCloudWebrtcSdk({
// other config stuff ...
autoAcceptPendingLiveScreenMonitoringRequests: false
});

sdk.on('pendingSession', (session) => {
if (session.sessionType === SessionTypes.liveScreenMonitoring) {
// manually accept the pending session
sdk.acceptPendingSession({
conversationId: session.conversationId,
sessionType: session.sessionType
});
}
});

sdk.on('sessionStarted', async (session) => {
if (sdk.isLiveScreenMonitoringSession(session)) {
const screenStream = await navigator.getDisplayMedia();

const track = screenStream.getTracks()[0];
const { height, width, deviceId } = track.getSettings();
const liveScreenMonitoringMetadata = [
{
trackId: track.id,
screenId: deviceId,
originX: 0,
originY: 0,
resolutionX: width,
resolutionY: height,
primary: true,
}
];

sdk.acceptSession({
conversationId: session.conversationId,
sessionType: session.sessionType,
mediaStream: screenStream,
liveScreenMonitoringMetadata
});
}
});
```

### Multiple Screens
Live screen monitoring supports monitoring up to **four** screens simultaneously. All screen tracks need to be on the same media stream provided in `sdk.acceptSession(...)`.

``` ts
sdk.on('sessionStarted', async (session) => {
if (sdk.isLiveScreenMonitoringSession(session)) {
// gather multiple screens
const screenStream1 = await navigator.getDisplayMedia();
const screenStream2 = await navigator.getDisplayMedia();

// combine streams
screenStream2.getVideoTracks().forEach(track => screenStream1.addTrack(track));

// create metadata for all screens
const liveScreenMonitoringMetadata = createMultiScreenMetadata();

sdk.acceptSession({
conversationId: session.conversationId,
sessionType: session.sessionType,
mediaStream: screenStream1,
liveScreenMonitoringMetadata
});
}
});
```

## Observer vs Target Roles

Live screen monitoring sessions involve two distinct roles with different behaviors:

### Target Role
The **target** is the user whose screen is being monitored. When accepting a session as a target:
- Must provide a `mediaStream` containing screen capture tracks
- The session automatically accepts if the `fromUserId` matches the current user
- Cannot end the monitoring session (only observers can end it)
- Sends their screen content to observers

``` ts
// Target accepts with screen media
sdk.acceptSession({
conversationId: session.conversationId,
sessionType: session.sessionType,
mediaStream: screenStream, // Required for targets
liveScreenMonitoringMetadata
});
```

### Observer Role
The **observer** is the user monitoring the target's screen. When accepting a session as an observer:
- Must provide `videoElements` array or `videoElement` to display incoming video
- Set `liveMonitoringObserver: true` in the accept parameters
- Receives video streams from the target and displays them in provided video elements
- Can end the monitoring session
- Sends empty video tracks to maintain WebRTC connection

``` ts
// Observer accepts with video elements
sdk.acceptSession({
conversationId: session.conversationId,
sessionType: session.sessionType,
liveMonitoringObserver: true, // Identifies this as observer role
videoElements: [videoElement1, videoElement2], // Required for observers
});
```

### Role Determination
The SDK automatically determines the role based on:
1. If `liveMonitoringObserver: true` is set in accept parameters → Observer
2. If `fromUserId` matches current user ID → Target (auto-accepted)
3. Otherwise → Target (manual acceptance required unless specified)

[GenesysCloudWebrtcSdk]: index.md#genesyscloudwebrtcsdk
75 changes: 14 additions & 61 deletions doc/video.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ are done using the public API, but are abstracted being api's in this sdk.
> *Note: video conferencing does not support guest users.*

## WebRTC SDK Video Index
This documentation expands upon the [GenesysCloudWebrtcSdk] documention but is specific to
video conferencing. See the full list of the [APIs], [methods], and [events].
This documentation expands upon the [GenesysCloudWebrtcSdk] documention but is specific to
video conferencing. See the full list of the [APIs], [methods], and [events].

* See [sdk.startVideoConference()] for usage
* [Example usage](#example-usage)
Expand Down Expand Up @@ -71,55 +71,8 @@ interface IParticipantUpdate {
audioMuted: boolean
}
```
Value of event:
* `update: IParticipantsUpdate` – list of updated participants

#### `activeVideoParticipantsUpdate`

This event will happen when the server switches who is visible on the screen.

> *Note: this user may not be providing video or that video could be muted. It is up to the
> implementing party to show something else such as an avatar or profile picture in such instances.*

Declaration:
``` ts
session.on('activeVideoParticipantsUpdate', (update: IOnScreenParticipantsUpdate) => {});

/* interface declaration */
interface IOnScreenParticipantsUpdate {
participantsOnScreen: [
{
userId: string,
}
]
}
```
Value of event:
* `update: IOnScreenParticipantsUpdate` – the new participant on the screen


#### `speakersUpdate`

This event tells who is making noise in the conference.

> Caveat: currently, we can only emit on this event when the on-screen user changes,
this will often appear to be out of sync. This will be fixed in the future.

Declaration:
``` ts
session.on('speakersUpdate', (update: ISpeakersUpdate) => {})):

/* interface declaration */
interface ISpeakersUpdate {
speakers: [
{
userId: string;
}
]
}
```
Value of event:
* `update: ISpeakersUpdate` – userIds of the participants speaking
* `update: IParticipantsUpdate` – list of updated participants

## Video Session Methods

Expand All @@ -134,7 +87,7 @@ be cleaned up and replaced with a track presenting your screen. When ending scre
a camera track was cleaned up during `startScreenShare` a new one will be created to replace the screen share track.


Declaration:
Declaration:
``` ts
session.startScreenShare(): Promise<void>;
```
Expand All @@ -145,13 +98,13 @@ Returns: a promise that completes after the screen share started.


#### `stopScreenShare()`
Ends the active outgoing screen share. If video media was on before the screen share
started, the media we be required and added to the session.
Ends the active outgoing screen share. If video media was on before the screen share
started, the media we be required and added to the session.

If there was no active screen share for this session, an error is logged
and returns (no error is thrown).
If there was no active screen share for this session, an error is logged
and returns (no error is thrown).

Declaration:
Declaration:
``` ts
session.stopScreenShare(): Promise<void>;
```
Expand All @@ -164,19 +117,19 @@ Returns: a promise that completes after the screen share end and the new video

#### `pinParticipantVideo()`
Locks video to the provided video conference participant. If `participantId` is `null`
or `undefined`, any currently pinned participants will be removed and will switch automatically
when speaking.
or `undefined`, any currently pinned participants will be removed and will switch automatically
when speaking.

When a participant's video is pinned it will disable the video switching when other participants talk.

> Note: participantIds can be found in the [participantsUpdate](#participantsupdate) event.

Declaration:
Declaration:
``` ts
session.pinParticipantVideo(participantId?: string): Promise<void>;
```

Params:
Params:
* `participantId: string` – Optional: if provided, it will pin that participant's video. If
the id is not provided, it will clear any old pin and reset back to the active user on screen.

Expand All @@ -188,4 +141,4 @@ Returns: a promise that completes after the Public API call finishes pinning the
[methods]: index.md#methods
[events]: index.md#events

[session level events]: index.md#session-level-events
[session level events]: index.md#session-level-events
Loading
Loading