From 74efe8735b05b43492022d3784efb19e2d34fd2c Mon Sep 17 00:00:00 2001 From: Lars Kiesow <lkiesow@uos.de> Date: Sun, 29 Nov 2020 02:13:19 +0100 Subject: [PATCH] Allow mirroring individual webcams MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BigBlueButton already allows mirroring the users own webcam as a global setting set by administrators. Users have no way of choosing this on their own. This patch turns this functionality into a user setting for all webcams. Every camera menu now gets a “mirror†entry. The global setting is still used as a default value, keeping the current behavior as it is to not confuse users. --- .../video-provider/video-list/component.jsx | 37 +++++++++++++++++-- .../video-list/video-list-item/component.jsx | 3 +- bigbluebutton-html5/private/locales/en.json | 2 + 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/video-list/component.jsx b/bigbluebutton-html5/imports/ui/components/video-provider/video-list/component.jsx index f9bdf6eea6..61031db226 100755 --- a/bigbluebutton-html5/imports/ui/components/video-provider/video-list/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/video-provider/video-list/component.jsx @@ -35,6 +35,12 @@ const intlMessages = defineMessages({ unfocusDesc: { id: 'app.videoDock.webcamUnfocusDesc', }, + mirrorLabel: { + id: 'app.videoDock.webcamMirrorLabel', + }, + mirrorDesc: { + id: 'app.videoDock.webcamMirrorDesc', + }, autoplayBlockedDesc: { id: 'app.videoDock.autoplayBlockedDesc', }, @@ -84,6 +90,7 @@ class VideoList extends Component { filledArea: 0, }, autoplayBlocked: false, + mirroredCameras: [], }; this.ticking = false; @@ -201,6 +208,24 @@ class VideoList extends Component { window.dispatchEvent(new Event('videoFocusChange')); } + mirrorCamera(cameraId) { + const { mirroredCameras } = this.state; + if (this.cameraIsMirrored(cameraId)) { + this.setState({ + mirroredCameras: mirroredCameras.filter(x => x != cameraId), + }); + } else { + this.setState({ + mirroredCameras: mirroredCameras.concat([cameraId]), + }); + } + } + + cameraIsMirrored(cameraId) { + const { mirroredCameras } = this.state; + return mirroredCameras.indexOf(cameraId) >= 0; + } + handleCanvasResize() { if (!this.ticking) { window.requestAnimationFrame(() => { @@ -273,14 +298,19 @@ class VideoList extends Component { const { cameraId, userId, name } = stream; const isFocused = focusedId === cameraId; const isFocusedIntlKey = !isFocused ? 'focus' : 'unfocus'; - let actions = []; + const isMirrored = this.cameraIsMirrored(cameraId); + let actions = [{ + label: intl.formatMessage(intlMessages['mirrorLabel']), + description: intl.formatMessage(intlMessages['mirrorDesc']), + onClick: () => this.mirrorCamera(cameraId), + }]; if (numOfStreams > 2) { - actions = [{ + actions.push({ label: intl.formatMessage(intlMessages[`${isFocusedIntlKey}Label`]), description: intl.formatMessage(intlMessages[`${isFocusedIntlKey}Desc`]), onClick: () => this.handleVideoFocus(cameraId), - }]; + }); } return ( @@ -296,6 +326,7 @@ class VideoList extends Component { cameraId={cameraId} userId={userId} name={name} + mirrored={isMirrored} actions={actions} onMount={(videoRef) => { this.handleCanvasResize(); diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/component.jsx b/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/component.jsx index 792ffe7bcf..53e17e4935 100755 --- a/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/component.jsx @@ -142,6 +142,7 @@ class VideoListItem extends Component { numOfStreams, webcamDraggableState, swapLayout, + mirrored } = this.props; const availableActions = this.getAvailableActions(); const enableVideoMenu = Meteor.settings.public.kurento.enableVideoMenu || false; @@ -173,7 +174,7 @@ class VideoListItem extends Component { && !isFullscreen && !swapLayout, [styles.cursorGrabbing]: webcamDraggableState.dragging && !isFullscreen && !swapLayout, - [styles.mirroredVideo]: this.mirrorOwnWebcam, + [styles.mirroredVideo]: (this.mirrorOwnWebcam && !mirrored) || (!this.mirrorOwnWebcam && mirrored), })} ref={(ref) => { this.videoTag = ref; }} autoPlay diff --git a/bigbluebutton-html5/private/locales/en.json b/bigbluebutton-html5/private/locales/en.json index 42a11674b9..7bac8d4e73 100755 --- a/bigbluebutton-html5/private/locales/en.json +++ b/bigbluebutton-html5/private/locales/en.json @@ -643,6 +643,8 @@ "app.videoDock.webcamFocusDesc": "Focus the selected webcam", "app.videoDock.webcamUnfocusLabel": "Unfocus", "app.videoDock.webcamUnfocusDesc": "Unfocus the selected webcam", + "app.videoDock.webcamMirrorLabel": "Mirror", + "app.videoDock.webcamMirrorDesc": "Mirror the selected webcam", "app.videoDock.autoplayBlockedDesc": "We need your permission to show you other users' webcams.", "app.videoDock.autoplayAllowLabel": "View webcams", "app.invitation.title": "Breakout room invitation", -- GitLab