Compare commits

...

4 Commits

Author SHA1 Message Date
Saúl Ibarra Corretgé
24e4101e2b fix(optimise): cope with URL interface config overrides
Regresssion from bd8a7edbd2.

When the toolbar buttons are overridden with URL parameters, our computed set of
buttons will be wrong. Thus, compute it every time and check for the
differences.
2020-03-04 12:09:43 -06:00
Hristo Terezov
8e61fa232e fix(electron7):memory leak when the page is hidden
It happens when you are drawing into hidden canvas.
2020-03-04 12:06:09 -06:00
Hristo Terezov
f4d2d0c878 fix(largeVideo-bg):render canvas only when visible 2020-03-04 12:05:57 -06:00
Hristo Terezov
96e6ca6f46 fix(stream-presenter-effect): Prevent memory leak.
On electron 7 drawing on hidden canvas will trigger a memory leak.
Not appending the canvas for the DOM seems to solve the problem.
2020-03-04 12:05:37 -06:00
5 changed files with 76 additions and 17 deletions

View File

@@ -206,6 +206,8 @@ export class VideoContainer extends LargeContainer {
*/
this._hideBackground = true;
this._isHidden = false;
/**
* Flag indicates whether or not the avatar is currently displayed.
* @type {boolean}
@@ -561,6 +563,8 @@ export class VideoContainer extends LargeContainer {
FADE_DURATION_MS,
1,
() => {
this._isHidden = false;
this._updateBackground();
resolve();
}
);
@@ -578,6 +582,8 @@ export class VideoContainer extends LargeContainer {
return new Promise(resolve => {
this.$wrapperParent.fadeTo(FADE_DURATION_MS, 0, () => {
this.$wrapperParent.css('visibility', 'hidden');
this._isHidden = true;
this._updateBackground();
resolve();
});
});
@@ -635,7 +641,7 @@ export class VideoContainer extends LargeContainer {
ReactDOM.render(
<LargeVideoBackground
hidden = { this._hideBackground }
hidden = { this._hideBackground || this._isHidden }
mirror = {
this.stream
&& this.stream.isLocal()

View File

@@ -2,7 +2,7 @@
import React, { Component } from 'react';
import { connect } from '../../../base/redux';
import { connect, equals } from '../../../base/redux';
import { SettingsButton } from '../../../settings';
import {
AudioMuteButton,
@@ -88,9 +88,13 @@ class Toolbar extends Component<Props> {
function _mapStateToProps(state): Object { // eslint-disable-line no-unused-vars
// XXX: We are not currently using state here, but in the future, when
// interfaceConfig is part of redux we will.
//
// NB: We compute the buttons again here because if URL parameters were used to
// override them we'd miss it.
const buttons = new Set(interfaceConfig.TOOLBAR_BUTTONS);
return {
_visibleButtons: visibleButtons
_visibleButtons: equals(visibleButtons, buttons) ? visibleButtons : buttons
};
}

View File

@@ -2,6 +2,9 @@
import React, { Component } from 'react';
import { connect } from '../../base/redux';
import { shouldDisplayTileView } from '../../video-layout';
/**
* Constants to describe the dimensions of the video. Landscape videos
* are wider than they are taller and portrait videos are taller than they
@@ -21,6 +24,14 @@ export const ORIENTATION = {
*/
type Props = {
/**
* Whether or not the layout should change to support tile view mode.
*
* @protected
* @type {boolean}
*/
_shouldDisplayTileView: boolean,
/**
* Additional CSS class names to add to the root of the component.
*/
@@ -83,7 +94,9 @@ export class LargeVideoBackground extends Component<Props> {
* @returns {void}
*/
componentDidMount() {
if (this.props.videoElement && !this.props.hidden) {
const { _shouldDisplayTileView, hidden, videoElement } = this.props;
if (videoElement && !hidden && !_shouldDisplayTileView) {
this._updateCanvas();
this._setUpdateCanvasInterval();
}
@@ -95,15 +108,18 @@ export class LargeVideoBackground extends Component<Props> {
* @inheritdoc
*/
componentDidUpdate(prevProps: Props) {
if (prevProps.hidden && !this.props.hidden) {
this._clearCanvas();
this._setUpdateCanvasInterval();
}
const wasCanvasUpdating = !prevProps.hidden && !prevProps._shouldDisplayTileView && prevProps.videoElement;
const shouldCanvasUpdating
= !this.props.hidden && !this.props._shouldDisplayTileView && this.props.videoElement;
if ((!prevProps.hidden && this.props.hidden)
|| !this.props.videoElement) {
this._clearCanvas();
this._clearUpdateCanvasInterval();
if (wasCanvasUpdating !== shouldCanvasUpdating) {
if (shouldCanvasUpdating) {
this._clearCanvas();
this._setUpdateCanvasInterval();
} else {
this._clearCanvas();
this._clearUpdateCanvasInterval();
}
}
}
@@ -195,6 +211,19 @@ export class LargeVideoBackground extends Component<Props> {
* @returns {void}
*/
_updateCanvas() {
// On Electron 7 there is a memory leak if we try to draw into a hidden canvas that is part of the DOM tree.
// See: https://github.com/electron/electron/issues/22417
// Trying to detect all the cases when the page will be hidden because of something not in our control
// (for example when the page is loaded in an iframe which is hidden due to the host page styles) to solve
// the memory leak. Currently we are not handling the use case when the page is hidden with visibility:hidden
// because we don't have a good way to do it.
// All other cases when the canvas is not visible are handled trough the component props
// (hidden, _shouldDisplayTileView).
if (!this._canvasEl || this._canvasEl.offsetParent === null
|| window.innerHeight === 0 || window.innerWidth === 0) {
return;
}
const { videoElement } = this.props;
const { videoWidth, videoHeight } = videoElement;
const {
@@ -216,3 +245,22 @@ export class LargeVideoBackground extends Component<Props> {
}
}
}
/**
* Maps (parts of) the Redux state to the associated LargeVideoBackground props.
*
* @param {Object} state - The Redux state.
* @private
* @returns {{
* _shouldDisplayTileView: boolean
* }}
*/
function _mapStateToProps(state) {
return {
_shouldDisplayTileView: shouldDisplayTileView(state)
};
}
export default connect(_mapStateToProps)(LargeVideoBackground);

View File

@@ -44,9 +44,6 @@ export default class JitsiStreamPresenterEffect {
this._canvas = document.createElement('canvas');
this._ctx = this._canvas.getContext('2d');
if (document.body !== null) {
document.body.appendChild(this._canvas);
}
this._desktopElement = document.createElement('video');
this._videoElement = document.createElement('video');
videoDiv.appendChild(this._videoElement);

View File

@@ -28,7 +28,7 @@ import {
getParticipants,
participantUpdated
} from '../../../base/participants';
import { connect } from '../../../base/redux';
import { connect, equals } from '../../../base/redux';
import { OverflowMenuItem } from '../../../base/toolbox';
import { getLocalVideoTrack, toggleScreensharing } from '../../../base/tracks';
import { VideoBlurButton } from '../../../blur';
@@ -1330,6 +1330,10 @@ function _mapStateToProps(state) {
}
}
// NB: We compute the buttons again here because if URL parameters were used to
// override them we'd miss it.
const buttons = new Set(interfaceConfig.TOOLBAR_BUTTONS);
return {
_chatOpen: state['features/chat'].isOpen,
_conference: conference,
@@ -1351,7 +1355,7 @@ function _mapStateToProps(state) {
|| sharedVideoStatus === 'start'
|| sharedVideoStatus === 'pause',
_visible: isToolboxVisible(state),
_visibleButtons: visibleButtons
_visibleButtons: equals(visibleButtons, buttons) ? visibleButtons : buttons
};
}