From dc20b2fafe32c801a78212fd37601eaf31b456f8 Mon Sep 17 00:00:00 2001 From: Robert Pintilii Date: Wed, 8 Dec 2021 16:15:59 +0200 Subject: [PATCH] fix(screenshot-capture) Update screenshot capture feature (#10443) * fix(screenshot-capture) Update screenshot capture feature Add participants jid list to request Enable screenshot capture only when recording is also on Updated interval --- conference.js | 8 +++++-- modules/API/API.js | 7 +++++- .../Recording/AbstractStartRecordingDialog.js | 12 ++++++++++ .../Recording/AbstractStopRecordingDialog.js | 7 ++++++ .../ScreenshotCaptureSummary.js | 11 ++++++++- .../features/screenshot-capture/constants.js | 2 +- .../features/screenshot-capture/functions.js | 24 +++++++++++++++++++ 7 files changed, 66 insertions(+), 5 deletions(-) diff --git a/conference.js b/conference.js index 7ef6bf6f5..3738e391c 100644 --- a/conference.js +++ b/conference.js @@ -71,7 +71,8 @@ import { JitsiMediaDevicesEvents, JitsiParticipantConnectionStatus, JitsiTrackErrors, - JitsiTrackEvents + JitsiTrackEvents, + JitsiRecordingConstants } from './react/features/base/lib-jitsi-meet'; import { getStartWithAudioMuted, @@ -140,6 +141,7 @@ import { setJoiningInProgress, setPrejoinPageVisibility } from './react/features/prejoin'; +import { getActiveSession } from './react/features/recording/functions'; import { disableReceiver, stopReceiver } from './react/features/remote-control'; import { setScreenAudioShareState, isScreenAudioShared } from './react/features/screen-share/'; import { toggleScreenshotCaptureSummary } from './react/features/screenshot-capture'; @@ -1933,7 +1935,9 @@ export default { .then(() => { this.videoSwitchInProgress = false; if (config.enableScreenshotCapture) { - APP.store.dispatch(toggleScreenshotCaptureSummary(true)); + if (getActiveSession(APP.store.getState(), JitsiRecordingConstants.mode.FILE)) { + APP.store.dispatch(toggleScreenshotCaptureSummary(true)); + } } sendAnalytics(createScreenSharingEvent('started')); logger.log('Screen sharing started'); diff --git a/modules/API/API.js b/modules/API/API.js index 9a8621f44..35a9ff21d 100644 --- a/modules/API/API.js +++ b/modules/API/API.js @@ -66,8 +66,9 @@ import { toggleLobbyMode, setKnockingParticipantApproval } from '../../react/fea import { isForceMuted } from '../../react/features/participants-pane/functions'; import { RECORDING_TYPES } from '../../react/features/recording/constants'; import { getActiveSession } from '../../react/features/recording/functions'; -import { isScreenAudioSupported } from '../../react/features/screen-share'; +import { isScreenAudioSupported, isScreenVideoShared } from '../../react/features/screen-share'; import { startScreenShareFlow, startAudioScreenShareFlow } from '../../react/features/screen-share/actions'; +import { toggleScreenshotCaptureSummary } from '../../react/features/screenshot-capture'; import { playSharedVideo, stopSharedVideo } from '../../react/features/shared-video/actions.any'; import { toggleTileView, setTileView } from '../../react/features/video-layout'; import { muteAllParticipants } from '../../react/features/video-menu/actions'; @@ -470,6 +471,9 @@ function initCommands() { return; } + if (isScreenVideoShared(APP.store.getState())) { + APP.store.dispatch(toggleScreenshotCaptureSummary(true)); + } conference.startRecording(recordingConfig); }, @@ -498,6 +502,7 @@ function initCommands() { const activeSession = getActiveSession(state, mode); if (activeSession && activeSession.id) { + APP.store.dispatch(toggleScreenshotCaptureSummary(false)); conference.stopRecording(activeSession.id); } else { logger.error('No recording or streaming session found'); diff --git a/react/features/recording/components/Recording/AbstractStartRecordingDialog.js b/react/features/recording/components/Recording/AbstractStartRecordingDialog.js index a1201f4e3..2f7417c5f 100644 --- a/react/features/recording/components/Recording/AbstractStartRecordingDialog.js +++ b/react/features/recording/components/Recording/AbstractStartRecordingDialog.js @@ -14,6 +14,8 @@ import { updateDropboxToken } from '../../../dropbox'; import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification } from '../../../notifications'; +import { isScreenVideoShared } from '../../../screen-share'; +import { toggleScreenshotCaptureSummary } from '../../../screenshot-capture'; import { toggleRequestingSubtitles } from '../../../subtitles'; import { setSelectedRecordingService } from '../../actions'; import { RECORDING_TYPES } from '../../constants'; @@ -57,6 +59,11 @@ type Props = { */ _rToken: string, + /** + * Whether or not the local participant is screensharing. + */ + _screensharing: boolean, + /** * Access token's expiration date as UNIX timestamp. */ @@ -276,6 +283,7 @@ class AbstractStartRecordingDialog extends Component { _conference, _isDropboxEnabled, _rToken, + _screensharing, _token, dispatch } = this.props; @@ -315,6 +323,9 @@ class AbstractStartRecordingDialog extends Component { createRecordingDialogEvent('start', 'confirm.button', attributes) ); + if (_screensharing) { + dispatch(toggleScreenshotCaptureSummary(true)); + } _conference.startRecording({ mode: JitsiRecordingConstants.mode.FILE, appData @@ -370,6 +381,7 @@ export function mapStateToProps(state: Object) { _fileRecordingsServiceSharingEnabled: fileRecordingsServiceSharingEnabled, _isDropboxEnabled: isDropboxEnabled(state), _rToken: state['features/dropbox'].rToken, + _screensharing: isScreenVideoShared(state), _tokenExpireDate: state['features/dropbox'].expireDate, _token: state['features/dropbox'].token }; diff --git a/react/features/recording/components/Recording/AbstractStopRecordingDialog.js b/react/features/recording/components/Recording/AbstractStopRecordingDialog.js index 95ad56c09..2f5aab235 100644 --- a/react/features/recording/components/Recording/AbstractStopRecordingDialog.js +++ b/react/features/recording/components/Recording/AbstractStopRecordingDialog.js @@ -7,6 +7,7 @@ import { sendAnalytics } from '../../../analytics'; import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet'; +import { toggleScreenshotCaptureSummary } from '../../../screenshot-capture'; import { getActiveSession } from '../../functions'; /** @@ -25,6 +26,11 @@ export type Props = { */ _fileRecordingSession: Object, + /** + * The redux dispatch function. + */ + dispatch: Function, + /** * Invoked to obtain translated strings. */ @@ -66,6 +72,7 @@ export default class AbstractStopRecordingDialog if (_fileRecordingSession) { this.props._conference.stopRecording(_fileRecordingSession.id); + this.props.dispatch(toggleScreenshotCaptureSummary(false)); } return true; diff --git a/react/features/screenshot-capture/ScreenshotCaptureSummary.js b/react/features/screenshot-capture/ScreenshotCaptureSummary.js index 4b39c0604..9bdc8d4f1 100644 --- a/react/features/screenshot-capture/ScreenshotCaptureSummary.js +++ b/react/features/screenshot-capture/ScreenshotCaptureSummary.js @@ -6,6 +6,7 @@ import './createImageBitmap'; import { createScreensharingCaptureTakenEvent, sendAnalytics } from '../analytics'; import { getCurrentConference } from '../base/conference'; +import { getRemoteParticipants } from '../base/participants'; import { extractFqnFromPath } from '../dynamic-branding'; import { @@ -15,6 +16,7 @@ import { POLL_INTERVAL, SET_INTERVAL } from './constants'; +import { getParticipantJid } from './functions'; import { processScreenshot } from './processScreenshot'; import { timerWorkerScript } from './worker'; @@ -140,6 +142,12 @@ export default class ScreenshotCaptureSummary { const timestamp = Date.now(); const { jwt } = this._state['features/base/jwt']; const meetingFqn = extractFqnFromPath(); + const remoteParticipants = getRemoteParticipants(this._state); + const participants = []; + + remoteParticipants.forEach(p => participants.push( + getParticipantJid(this._state, p.id) + )); this._storedImageData = imageData; @@ -148,7 +156,8 @@ export default class ScreenshotCaptureSummary { jwt, sessionId, timestamp, - meetingFqn + meetingFqn, + participants }); } diff --git a/react/features/screenshot-capture/constants.js b/react/features/screenshot-capture/constants.js index 5daa1ffea..e26cdd202 100644 --- a/react/features/screenshot-capture/constants.js +++ b/react/features/screenshot-capture/constants.js @@ -8,7 +8,7 @@ export const PERCENTAGE_LOWER_BOUND = 5; /** * Number of milliseconds that represent how often screenshots should be taken. */ -export const POLL_INTERVAL = 2000; +export const POLL_INTERVAL = 4000; /** * SET_INTERVAL constant is used to set interval and it is set in diff --git a/react/features/screenshot-capture/functions.js b/react/features/screenshot-capture/functions.js index 46a8c7556..eefcb4245 100644 --- a/react/features/screenshot-capture/functions.js +++ b/react/features/screenshot-capture/functions.js @@ -1,5 +1,6 @@ // @flow +import { getCurrentConference } from '../base/conference'; import { toState } from '../base/redux'; import ScreenshotCaptureSummary from './ScreenshotCaptureSummary'; @@ -18,3 +19,26 @@ export function createScreenshotCaptureSummary(stateful: Object | Function) { return new ScreenshotCaptureSummary(toState(stateful)); } + +/** + * Get a participant's connection JID given its ID. + * + * @param {Object} state - The redux store state. + * @param {string} participantId - ID of the given participant. + * @returns {string|undefined} - The participant connection JID if found. + */ +export function getParticipantJid(state: Object, participantId: string) { + const conference = getCurrentConference(state); + + if (!conference) { + return; + } + + const participant = conference.getParticipantById(participantId); + + if (!participant) { + return; + } + + return participant.getJid(); +}