feat(virtual-background) add slight blur option
This commit is contained in:
parent
927b40ec71
commit
af28080058
|
@ -1,6 +1,6 @@
|
|||
.virtual-background-dialog {
|
||||
display: inline-grid;
|
||||
grid-template-columns: auto auto auto auto auto auto auto;
|
||||
grid-template-columns: auto auto auto auto auto auto auto auto;
|
||||
max-width: 370px;
|
||||
cursor: pointer;
|
||||
.thumbnail {
|
||||
|
|
|
@ -339,7 +339,8 @@
|
|||
},
|
||||
"virtualBackground": {
|
||||
"title": "Backgrounds",
|
||||
"enableBlur": "Enable blur",
|
||||
"blur": "Blur",
|
||||
"slightBlur": "Slight Blur",
|
||||
"removeBackground": "Remove background",
|
||||
"uploadImage": "Upload image",
|
||||
"pleaseWait": "Please wait...",
|
||||
|
|
|
@ -5,7 +5,6 @@ import {
|
|||
SET_TIMEOUT,
|
||||
timerWorkerScript
|
||||
} from './TimerWorker';
|
||||
const blurValue = '25px';
|
||||
|
||||
/**
|
||||
* Represents a modified MediaStream that adds effects to video background.
|
||||
|
@ -40,7 +39,7 @@ export default class JitsiStreamBackgroundEffect {
|
|||
constructor(model: Object, options: Object) {
|
||||
this._options = options;
|
||||
|
||||
if (this._options.virtualBackground.isVirtualBackground) {
|
||||
if (this._options.virtualBackground.backgroundType === 'image') {
|
||||
this._virtualImage = document.createElement('img');
|
||||
this._virtualImage.crossOrigin = 'anonymous';
|
||||
this._virtualImage.src = this._options.virtualBackground.virtualSource;
|
||||
|
@ -65,9 +64,9 @@ export default class JitsiStreamBackgroundEffect {
|
|||
* @param {EventHandler} response - The onmessage EventHandler parameter.
|
||||
* @returns {void}
|
||||
*/
|
||||
async _onMaskFrameTimer(response: Object) {
|
||||
_onMaskFrameTimer(response: Object) {
|
||||
if (response.data.id === TIMEOUT_TICK) {
|
||||
await this._renderMask();
|
||||
this._renderMask();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,7 +82,7 @@ export default class JitsiStreamBackgroundEffect {
|
|||
//
|
||||
|
||||
// Smooth out the edges.
|
||||
if (this._options.virtualBackground.isVirtualBackground) {
|
||||
if (this._options.virtualBackground.backgroundType === 'image') {
|
||||
this._outputCanvasCtx.filter = 'blur(4px)';
|
||||
} else {
|
||||
this._outputCanvasCtx.filter = 'blur(8px)';
|
||||
|
@ -112,7 +111,7 @@ export default class JitsiStreamBackgroundEffect {
|
|||
//
|
||||
|
||||
this._outputCanvasCtx.globalCompositeOperation = 'destination-over';
|
||||
if (this._options.virtualBackground.isVirtualBackground) {
|
||||
if (this._options.virtualBackground.backgroundType === 'image') {
|
||||
this._outputCanvasCtx.drawImage(
|
||||
this._virtualImage,
|
||||
0,
|
||||
|
@ -121,7 +120,7 @@ export default class JitsiStreamBackgroundEffect {
|
|||
this._inputVideoElement.height
|
||||
);
|
||||
} else {
|
||||
this._outputCanvasCtx.filter = `blur(${blurValue})`;
|
||||
this._outputCanvasCtx.filter = `blur(${this._options.virtualBackground.blurValue}px)`;
|
||||
this._outputCanvasCtx.drawImage(this._inputVideoElement, 0, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
* @returns {{
|
||||
* type: BACKGROUND_ENABLED,
|
||||
* backgroundEffectEnabled: boolean,
|
||||
* backgroundEffectEnabled: boolean
|
||||
* }}
|
||||
*/
|
||||
export const BACKGROUND_ENABLED = 'BACKGROUND_ENABLED';
|
||||
|
@ -16,8 +16,8 @@ export const BACKGROUND_ENABLED = 'BACKGROUND_ENABLED';
|
|||
*
|
||||
* @returns {{
|
||||
* type: SET_VIRTUAL_BACKGROUND,
|
||||
* isVirtualBackground: boolean,
|
||||
* virtualSource: string,
|
||||
* blurValue: number,
|
||||
* }}
|
||||
*/
|
||||
export const SET_VIRTUAL_BACKGROUND = 'SET_VIRTUAL_BACKGROUND';
|
||||
|
|
|
@ -9,20 +9,20 @@ import logger from './logger';
|
|||
/**
|
||||
* Signals the local participant activate the virtual background video or not.
|
||||
*
|
||||
* @param {boolean} enabled - If true enables video background, false otherwise.
|
||||
* @param {Object} options - Represents the virtual background setted options.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function toggleBackgroundEffect(enabled: boolean) {
|
||||
export function toggleBackgroundEffect(options: Object) {
|
||||
return async function(dispatch: Object => Object, getState: () => any) {
|
||||
await dispatch(backgroundEnabled(options.enabled));
|
||||
await dispatch(setVirtualBackground(options));
|
||||
const state = getState();
|
||||
|
||||
const { jitsiTrack } = getLocalVideoTrack(state['features/base/tracks']);
|
||||
const virtualBackground = state['features/virtual-background'];
|
||||
|
||||
try {
|
||||
if (enabled) {
|
||||
if (options.enabled) {
|
||||
await jitsiTrack.setEffect(await createVirtualBackgroundEffect(virtualBackground));
|
||||
dispatch(backgroundEnabled(true));
|
||||
} else {
|
||||
await jitsiTrack.setEffect(undefined);
|
||||
dispatch(backgroundEnabled(false));
|
||||
|
@ -37,19 +37,20 @@ export function toggleBackgroundEffect(enabled: boolean) {
|
|||
/**
|
||||
* Sets the selected virtual background image object.
|
||||
*
|
||||
* @param {Object} virtualSource - Virtual background image source.
|
||||
* @param {boolean} isVirtualBackground - Indicate if virtual image is activated.
|
||||
* @param {Object} options - Represents the virtual background setted options.
|
||||
* @returns {{
|
||||
* type: SET_VIRTUAL_BACKGROUND,
|
||||
* virtualSource: string,
|
||||
* isVirtualBackground: boolean,
|
||||
* blurValue: number,
|
||||
* type: string,
|
||||
* }}
|
||||
*/
|
||||
export function setVirtualBackground(virtualSource: string, isVirtualBackground: boolean) {
|
||||
export function setVirtualBackground(options: Object) {
|
||||
return {
|
||||
type: SET_VIRTUAL_BACKGROUND,
|
||||
virtualSource,
|
||||
isVirtualBackground
|
||||
virtualSource: options?.url,
|
||||
blurValue: options?.blurValue,
|
||||
backgroundType: options?.backgroundType
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -59,7 +60,7 @@ export function setVirtualBackground(virtualSource: string, isVirtualBackground:
|
|||
* @param {boolean} backgroundEffectEnabled - Indicate if virtual background effect is activated.
|
||||
* @returns {{
|
||||
* type: BACKGROUND_ENABLED,
|
||||
* backgroundEffectEnabled: boolean,
|
||||
* backgroundEffectEnabled: boolean
|
||||
* }}
|
||||
*/
|
||||
export function backgroundEnabled(backgroundEffectEnabled: boolean) {
|
||||
|
|
|
@ -10,14 +10,14 @@ import { translate } from '../../base/i18n';
|
|||
import { Icon, IconBlurBackground, IconCancelSelection } from '../../base/icons';
|
||||
import { connect } from '../../base/redux';
|
||||
import { Tooltip } from '../../base/tooltip';
|
||||
import { toggleBackgroundEffect, setVirtualBackground } from '../actions';
|
||||
import { toggleBackgroundEffect } from '../actions';
|
||||
import { resizeImage, toDataURL } from '../functions';
|
||||
import logger from '../logger';
|
||||
|
||||
// The limit of virtual background uploads is 21. When the number
|
||||
// of uploads is 22 we trigger the deleteStoredImage function to delete
|
||||
// The limit of virtual background uploads is 24. When the number
|
||||
// of uploads is 25 we trigger the deleteStoredImage function to delete
|
||||
// the first/oldest uploaded background.
|
||||
const backgroundsLimit = 22;
|
||||
const backgroundsLimit = 25;
|
||||
const images = [
|
||||
{
|
||||
id: 1,
|
||||
|
@ -67,42 +67,67 @@ function VirtualBackground({ dispatch, t }: Props) {
|
|||
* Updates stored images on local storage.
|
||||
*/
|
||||
useEffect(() => {
|
||||
jitsiLocalStorage.setItem('virtualBackgrounds', JSON.stringify(storedImages));
|
||||
try {
|
||||
jitsiLocalStorage.setItem('virtualBackgrounds', JSON.stringify(storedImages));
|
||||
} catch (err) {
|
||||
// Preventing localStorage QUOTA_EXCEEDED_ERR
|
||||
err && deleteStoredImage(storedImages[0]);
|
||||
}
|
||||
if (storedImages.length === backgroundsLimit) {
|
||||
deleteStoredImage(storedImages[0]);
|
||||
}
|
||||
}, [ storedImages ]);
|
||||
|
||||
const [ selected, setSelected ] = useState('');
|
||||
const enableBlur = async () => {
|
||||
const enableBlur = async (blurValue, selection) => {
|
||||
isloading(true);
|
||||
setSelected('blur');
|
||||
await dispatch(setVirtualBackground('', false));
|
||||
await dispatch(toggleBackgroundEffect(true));
|
||||
setSelected(selection);
|
||||
await dispatch(
|
||||
toggleBackgroundEffect({
|
||||
backgroundType: 'blur',
|
||||
enabled: true,
|
||||
blurValue
|
||||
})
|
||||
);
|
||||
isloading(false);
|
||||
};
|
||||
|
||||
const removeBackground = async () => {
|
||||
isloading(true);
|
||||
setSelected('none');
|
||||
await dispatch(setVirtualBackground('', false));
|
||||
await dispatch(toggleBackgroundEffect(false));
|
||||
await dispatch(
|
||||
toggleBackgroundEffect({
|
||||
enabled: false
|
||||
})
|
||||
);
|
||||
isloading(false);
|
||||
};
|
||||
|
||||
const setUploadedImageBackground = async image => {
|
||||
isloading(true);
|
||||
setSelected(image.id);
|
||||
await dispatch(setVirtualBackground(image.src, true));
|
||||
await dispatch(toggleBackgroundEffect(true));
|
||||
await dispatch(
|
||||
toggleBackgroundEffect({
|
||||
backgroundType: 'image',
|
||||
enabled: true,
|
||||
url: image.src
|
||||
})
|
||||
);
|
||||
isloading(false);
|
||||
};
|
||||
|
||||
const setImageBackground = async image => {
|
||||
isloading(true);
|
||||
setSelected(image.id);
|
||||
await dispatch(setVirtualBackground(await toDataURL(image.src), true));
|
||||
await dispatch(toggleBackgroundEffect(true));
|
||||
const url = await toDataURL(image.src);
|
||||
|
||||
await dispatch(
|
||||
toggleBackgroundEffect({
|
||||
backgroundType: 'image',
|
||||
enabled: true,
|
||||
url
|
||||
})
|
||||
);
|
||||
isloading(false);
|
||||
};
|
||||
|
||||
|
@ -111,19 +136,23 @@ function VirtualBackground({ dispatch, t }: Props) {
|
|||
|
||||
reader.readAsDataURL(imageFile[0]);
|
||||
reader.onload = async () => {
|
||||
const resizedImage = await resizeImage(reader.result);
|
||||
const url = await resizeImage(reader.result);
|
||||
|
||||
isloading(true);
|
||||
setStoredImages([
|
||||
...storedImages,
|
||||
{
|
||||
id: uuid.v4(),
|
||||
src: resizedImage
|
||||
src: url
|
||||
}
|
||||
]);
|
||||
|
||||
await dispatch(setVirtualBackground(resizedImage, true));
|
||||
await dispatch(toggleBackgroundEffect(true));
|
||||
await dispatch(
|
||||
toggleBackgroundEffect({
|
||||
backgroundType: 'image',
|
||||
enabled: true,
|
||||
url
|
||||
})
|
||||
);
|
||||
isloading(false);
|
||||
};
|
||||
reader.onerror = () => {
|
||||
|
@ -137,7 +166,7 @@ function VirtualBackground({ dispatch, t }: Props) {
|
|||
hideCancelButton = { true }
|
||||
submitDisabled = { false }
|
||||
titleKey = { 'virtualBackground.title' }
|
||||
width = 'small'>
|
||||
width = '450px'>
|
||||
{loading ? (
|
||||
<div className = 'virtual-background-loading'>
|
||||
<span className = 'loading-content-text'>{t('virtualBackground.pleaseWait')}</span>
|
||||
|
@ -158,11 +187,20 @@ function VirtualBackground({ dispatch, t }: Props) {
|
|||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
content = { t('virtualBackground.enableBlur') }
|
||||
content = { t('virtualBackground.slightBlur') }
|
||||
position = { 'top' }>
|
||||
<Icon
|
||||
className = { selected === 'slight-blur' ? 'blur-selected' : '' }
|
||||
onClick = { () => enableBlur(8, 'slight-blur') }
|
||||
size = { 50 }
|
||||
src = { IconBlurBackground } />
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
content = { t('virtualBackground.blur') }
|
||||
position = { 'top' }>
|
||||
<Icon
|
||||
className = { selected === 'blur' ? 'blur-selected' : '' }
|
||||
onClick = { () => enableBlur() }
|
||||
onClick = { () => enableBlur(25, 'blur') }
|
||||
size = { 50 }
|
||||
src = { IconBlurBackground } />
|
||||
</Tooltip>
|
||||
|
|
|
@ -23,14 +23,15 @@ PersistenceRegistry.register(STORE_NAME, true);
|
|||
* specified action.
|
||||
*/
|
||||
ReducerRegistry.register(STORE_NAME, (state = {}, action) => {
|
||||
const { virtualSource, isVirtualBackground, backgroundEffectEnabled } = action;
|
||||
const { virtualSource, backgroundEffectEnabled, blurValue, backgroundType } = action;
|
||||
|
||||
switch (action.type) {
|
||||
case SET_VIRTUAL_BACKGROUND: {
|
||||
return {
|
||||
...state,
|
||||
virtualSource,
|
||||
isVirtualBackground
|
||||
blurValue,
|
||||
backgroundType
|
||||
};
|
||||
}
|
||||
case BACKGROUND_ENABLED: {
|
||||
|
|
Loading…
Reference in New Issue