Преглед на файлове

feat(virtual-backgrounds) add virtual background support

j8
tudordan7 преди 4 години
родител
ревизия
194d357005
променени са 43 файла, в които са добавени 439 реда и са изтрити 237 реда
  1. 1
    1
      .eslintignore
  2. 4
    4
      Makefile
  3. 1
    1
      config.js
  4. 1
    0
      css/main.scss
  5. 44
    0
      css/modals/virtual-background/_virtual-background.scss
  6. Двоични данни
      images/virtual-background/background-1.jpg
  7. Двоични данни
      images/virtual-background/background-2.jpg
  8. Двоични данни
      images/virtual-background/background-3.jpg
  9. Двоични данни
      images/virtual-background/background-4.jpg
  10. 1
    1
      interface_config.js
  11. 7
    4
      lang/main.json
  12. 0
    1
      react/features/app/reducers.any.js
  13. 1
    1
      react/features/app/reducers.web.js
  14. 1
    1
      react/features/base/config/constants.js
  15. 1
    0
      react/features/base/icons/svg/index.js
  16. 3
    0
      react/features/base/icons/svg/virtual-background.svg
  17. 5
    5
      react/features/base/tracks/loadEffects.web.js
  18. 0
    21
      react/features/blur/actionTypes.js
  19. 0
    67
      react/features/blur/actions.js
  20. 0
    1
      react/features/blur/components/index.js
  21. 0
    26
      react/features/blur/reducer.js
  22. 0
    61
      react/features/stream-effects/blur/index.js
  23. 17
    5
      react/features/stream-effects/virtual-background/JitsiStreamBackgroundEffect.js
  24. 0
    0
      react/features/stream-effects/virtual-background/TimerWorker.js
  25. 64
    0
      react/features/stream-effects/virtual-background/index.js
  26. 0
    0
      react/features/stream-effects/virtual-background/vendor/README.md
  27. 0
    0
      react/features/stream-effects/virtual-background/vendor/models/segm_full_v679.tflite
  28. 0
    0
      react/features/stream-effects/virtual-background/vendor/models/segm_lite_v681.tflite
  29. 0
    0
      react/features/stream-effects/virtual-background/vendor/tflite/tflite-simd.js
  30. 0
    0
      react/features/stream-effects/virtual-background/vendor/tflite/tflite-simd.wasm
  31. 0
    0
      react/features/stream-effects/virtual-background/vendor/tflite/tflite.js
  32. 0
    0
      react/features/stream-effects/virtual-background/vendor/tflite/tflite.wasm
  33. 5
    5
      react/features/toolbox/components/web/Toolbox.js
  34. 23
    0
      react/features/virtual-background/actionTypes.js
  35. 70
    0
      react/features/virtual-background/actions.js
  36. 21
    24
      react/features/virtual-background/components/VideoBackgroundButton.js
  37. 118
    0
      react/features/virtual-background/components/VirtualBackgroundDialog.js
  38. 2
    0
      react/features/virtual-background/components/index.js
  39. 8
    5
      react/features/virtual-background/functions.js
  40. 0
    0
      react/features/virtual-background/index.js
  41. 1
    1
      react/features/virtual-background/logger.js
  42. 38
    0
      react/features/virtual-background/reducer.js
  43. 2
    2
      webpack.config.js

+ 1
- 1
.eslintignore Целия файл

6
 flow-typed/*
6
 flow-typed/*
7
 libs/*
7
 libs/*
8
 resources/*
8
 resources/*
9
-react/features/stream-effects/blur/vendor/*
9
+react/features/stream-effects/virtual-background/vendor/*
10
 
10
 
11
 # ESLint will by default ignore its own configuration file. However, there does
11
 # ESLint will by default ignore its own configuration file. However, there does
12
 # not seem to be a reason why we will want to risk being inconsistent with our
12
 # not seem to be a reason why we will want to risk being inconsistent with our

+ 4
- 4
Makefile Целия файл

5
 LIBFLAC_DIR = node_modules/libflacjs/dist/min/
5
 LIBFLAC_DIR = node_modules/libflacjs/dist/min/
6
 OLM_DIR = node_modules/olm
6
 OLM_DIR = node_modules/olm
7
 RNNOISE_WASM_DIR = node_modules/rnnoise-wasm/dist/
7
 RNNOISE_WASM_DIR = node_modules/rnnoise-wasm/dist/
8
-TFLITE_WASM = react/features/stream-effects/blur/vendor/tflite
9
-MEET_MODELS_DIR  = react/features/stream-effects/blur/vendor/models/
8
+TFLITE_WASM = react/features/stream-effects/virtual-background/vendor/tflite
9
+MEET_MODELS_DIR  = react/features/stream-effects/virtual-background/vendor/models/
10
 NODE_SASS = ./node_modules/.bin/sass
10
 NODE_SASS = ./node_modules/.bin/sass
11
 NPM = npm
11
 NPM = npm
12
 OUTPUT_DIR = .
12
 OUTPUT_DIR = .
51
 		$(OUTPUT_DIR)/analytics-ga.js \
51
 		$(OUTPUT_DIR)/analytics-ga.js \
52
 		$(BUILD_DIR)/analytics-ga.min.js \
52
 		$(BUILD_DIR)/analytics-ga.min.js \
53
 		$(BUILD_DIR)/analytics-ga.min.map \
53
 		$(BUILD_DIR)/analytics-ga.min.map \
54
-		$(BUILD_DIR)/video-blur-effect.min.js \
55
-		$(BUILD_DIR)/video-blur-effect.min.map \
54
+		$(BUILD_DIR)/virtual-background-effect.min.js \
55
+		$(BUILD_DIR)/virtual-background-effect.min.map \
56
 		$(BUILD_DIR)/rnnoise-processor.min.js \
56
 		$(BUILD_DIR)/rnnoise-processor.min.js \
57
 		$(BUILD_DIR)/rnnoise-processor.min.map \
57
 		$(BUILD_DIR)/rnnoise-processor.min.map \
58
 		$(BUILD_DIR)/close3.min.js \
58
 		$(BUILD_DIR)/close3.min.js \

+ 1
- 1
config.js Целия файл

430
     //    'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
430
     //    'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
431
     //    'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
431
     //    'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
432
     //    'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
432
     //    'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
433
-    //    'tileview', 'videobackgroundblur', 'download', 'help', 'mute-everyone', 'mute-video-everyone', 'security'
433
+    //    'tileview', 'select-background', 'download', 'help', 'mute-everyone', 'mute-video-everyone', 'security'
434
     // ],
434
     // ],
435
 
435
 
436
     // Stats
436
     // Stats

+ 1
- 0
css/main.scss Целия файл

43
 @import 'modals/settings/settings';
43
 @import 'modals/settings/settings';
44
 @import 'modals/speaker_stats/speaker_stats';
44
 @import 'modals/speaker_stats/speaker_stats';
45
 @import 'modals/video-quality/video-quality';
45
 @import 'modals/video-quality/video-quality';
46
+@import 'modals/virtual-background/virtual-background';
46
 @import 'modals/local-recording/local-recording';
47
 @import 'modals/local-recording/local-recording';
47
 @import 'videolayout_default';
48
 @import 'videolayout_default';
48
 @import 'notice';
49
 @import 'notice';

+ 44
- 0
css/modals/virtual-background/_virtual-background.scss Целия файл

1
+.virtual-background-dialog{
2
+  display: inline-flex;
3
+  cursor: pointer;
4
+  .thumbnail{
5
+    object-fit: cover;
6
+    padding: 5px;
7
+    height: 40px;
8
+    width: 40px;
9
+  }
10
+  .thumbnail-selected{
11
+    object-fit: cover;
12
+    padding: 5px;
13
+    height: 40px;
14
+    width: 40px;
15
+    border: 2px solid #a4b8d1;
16
+  }
17
+  .blur-selected{
18
+    border: 2px solid #a4b8d1;
19
+  }
20
+  .virtual-background-none{
21
+    font-weight: bold;
22
+    padding: 5px;
23
+    height: 35px;
24
+    width: 35px;
25
+    border-radius: 10px;
26
+    border: 1px solid #a4b8d1;
27
+    text-align: center;
28
+    vertical-align: middle;
29
+    line-height: 35px;
30
+    margin-right: 5px;
31
+  }
32
+  .none-selected{
33
+    font-weight: bold;
34
+    padding: 5px;
35
+    height: 35px;
36
+    width: 35px;
37
+    border-radius: 10px;
38
+    border: 2px solid #a4b8d1;
39
+    text-align: center;
40
+    vertical-align: middle;
41
+    line-height: 35px;
42
+    margin-right: 5px;
43
+  }
44
+}

Двоични данни
images/virtual-background/background-1.jpg Целия файл


Двоични данни
images/virtual-background/background-2.jpg Целия файл


Двоични данни
images/virtual-background/background-3.jpg Целия файл


Двоични данни
images/virtual-background/background-4.jpg Целия файл


+ 1
- 1
interface_config.js Целия файл

206
     //     'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
206
     //     'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
207
     //     'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
207
     //     'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
208
     //     'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
208
     //     'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
209
-    //     'tileview', 'videobackgroundblur', 'download', 'help', 'mute-everyone', 'mute-video-everyone', 'security'
209
+    //     'tileview', 'select-background', 'download', 'help', 'mute-everyone', 'mute-video-everyone', 'security'
210
     // ],
210
     // ],
211
 
211
 
212
     TOOLBAR_TIMEOUT: 4000,
212
     TOOLBAR_TIMEOUT: 4000,

+ 7
- 4
lang/main.json Целия файл

332
     "embedMeeting": {
332
     "embedMeeting": {
333
         "title": "Embed this meeting"
333
         "title": "Embed this meeting"
334
     },
334
     },
335
+    "virtualBackground": {
336
+        "title": "Backgrounds",
337
+        "enableBlur": "Enable blur",
338
+        "removeBackground": "Remove background"
339
+    },
335
     "feedback": {
340
     "feedback": {
336
         "average": "Average",
341
         "average": "Average",
337
         "bad": "Bad",
342
         "bad": "Bad",
748
             "toggleCamera": "Toggle camera",
753
             "toggleCamera": "Toggle camera",
749
             "toggleFilmstrip": "Toggle filmstrip",
754
             "toggleFilmstrip": "Toggle filmstrip",
750
             "videomute": "Toggle mute video",
755
             "videomute": "Toggle mute video",
751
-            "videoblur": "Toggle video blur"
756
+            "selectBackground": "Select Background"
752
         },
757
         },
753
         "addPeople": "Add people to your call",
758
         "addPeople": "Add people to your call",
754
         "audioSettings": "Audio settings",
759
         "audioSettings": "Audio settings",
810
         "tileViewToggle": "Toggle tile view",
815
         "tileViewToggle": "Toggle tile view",
811
         "toggleCamera": "Toggle camera",
816
         "toggleCamera": "Toggle camera",
812
         "videomute": "Start / Stop camera",
817
         "videomute": "Start / Stop camera",
813
-        "videoSettings": "Video settings",
814
-        "startvideoblur": "Blur my background",
815
-        "stopvideoblur": "Disable background blur"
818
+        "selectBackground": "Select background"
816
     },
819
     },
817
     "transcribing": {
820
     "transcribing": {
818
         "ccButtonTooltip": "Start / Stop subtitles",
821
         "ccButtonTooltip": "Start / Stop subtitles",

+ 0
- 1
react/features/app/reducers.any.js Целия файл

25
 import '../base/tracks/reducer';
25
 import '../base/tracks/reducer';
26
 import '../base/user-interaction/reducer';
26
 import '../base/user-interaction/reducer';
27
 import '../billing-counter/reducer';
27
 import '../billing-counter/reducer';
28
-import '../blur/reducer';
29
 import '../calendar-sync/reducer';
28
 import '../calendar-sync/reducer';
30
 import '../chat/reducer';
29
 import '../chat/reducer';
31
 import '../deep-linking/reducer';
30
 import '../deep-linking/reducer';

+ 1
- 1
react/features/app/reducers.web.js Целия файл

12
 import '../screenshot-capture/reducer';
12
 import '../screenshot-capture/reducer';
13
 import '../shared-video/reducer';
13
 import '../shared-video/reducer';
14
 import '../talk-while-muted/reducer';
14
 import '../talk-while-muted/reducer';
15
-
15
+import '../virtual-background/reducer';
16
 import './reducers.any';
16
 import './reducers.any';

+ 1
- 1
react/features/base/config/constants.js Целия файл

18
     'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
18
     'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
19
     'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
19
     'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
20
     'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
20
     'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
21
-    'tileview', 'videobackgroundblur', 'download', 'help', 'mute-everyone', 'mute-video-everyone', 'security'
21
+    'tileview', 'select-background', 'download', 'help', 'mute-everyone', 'mute-video-everyone', 'security'
22
 ];
22
 ];

+ 1
- 0
react/features/base/icons/svg/index.js Целия файл

109
 export { default as IconVideoQualityHD } from './HD.svg';
109
 export { default as IconVideoQualityHD } from './HD.svg';
110
 export { default as IconVideoQualityLD } from './LD.svg';
110
 export { default as IconVideoQualityLD } from './LD.svg';
111
 export { default as IconVideoQualitySD } from './SD.svg';
111
 export { default as IconVideoQualitySD } from './SD.svg';
112
+export { default as IconVirtualBackground } from './virtual-background.svg';
112
 export { default as IconVolume } from './volume.svg';
113
 export { default as IconVolume } from './volume.svg';
113
 export { default as IconVolumeEmpty } from './volume-empty.svg';
114
 export { default as IconVolumeEmpty } from './volume-empty.svg';
114
 export { default as IconVolumeOff } from './volume-off.svg';
115
 export { default as IconVolumeOff } from './volume-off.svg';

+ 3
- 0
react/features/base/icons/svg/virtual-background.svg Целия файл

1
+<svg width="20" height="20" viewBox="0 0 20 20" fill="white" xmlns="http://www.w3.org/2000/svg">
2
+<path fill-rule="evenodd" clip-rule="evenodd" d="M16.6666 1.66667H3.33329C2.41282 1.66667 1.66663 2.41286 1.66663 3.33334V16.6667C1.66663 17.5871 2.41282 18.3333 3.33329 18.3333H3.63257H8.56767H9.14753H15.6942H16.6666C17.5871 18.3333 18.3333 17.5871 18.3333 16.6667V3.33334C18.3333 2.41286 17.5871 1.66667 16.6666 1.66667ZM7.57977 12.3005L9.3687 14.893L12.0223 8.76728C12.2052 8.34496 12.6959 8.15091 13.1182 8.33385C13.2964 8.41106 13.4421 8.54811 13.53 8.72131L16.6666 14.9002V3.33334H3.33329V16.4665L6.208 12.3005C6.4694 11.9217 6.98838 11.8265 7.36718 12.0879C7.45035 12.1453 7.52238 12.2174 7.57977 12.3005ZM7.49996 10C6.11925 10 4.99996 8.88072 4.99996 7.5C4.99996 6.11929 6.11925 5.00001 7.49996 5.00001C8.88067 5.00001 9.99996 6.11929 9.99996 7.5C9.99996 8.88072 8.88067 10 7.49996 10ZM8.33329 7.5C8.33329 7.96024 7.9602 8.33334 7.49996 8.33334C7.03972 8.33334 6.66663 7.96024 6.66663 7.5C6.66663 7.03977 7.03972 6.66667 7.49996 6.66667C7.9602 6.66667 8.33329 7.03977 8.33329 7.5ZM12.8466 11.0572L15.6942 16.6667H10.4167L12.8466 11.0572ZM6.89389 14.2411L8.56767 16.6667H5.2201L6.89389 14.2411Z" />
3
+</svg>

+ 5
- 5
react/features/base/tracks/loadEffects.web.js Целия файл

1
 // @flow
1
 // @flow
2
 
2
 
3
-import { getBlurEffect } from '../../blur';
4
 import { createScreenshotCaptureEffect } from '../../stream-effects/screenshot-capture';
3
 import { createScreenshotCaptureEffect } from '../../stream-effects/screenshot-capture';
4
+import { getBackgroundEffect } from '../../virtual-background';
5
 
5
 
6
 import logger from './logger';
6
 import logger from './logger';
7
 
7
 
14
 export default function loadEffects(store: Object): Promise<any> {
14
 export default function loadEffects(store: Object): Promise<any> {
15
     const state = store.getState();
15
     const state = store.getState();
16
 
16
 
17
-    const blurPromise = state['features/blur'].blurEnabled
18
-        ? getBlurEffect()
17
+    const backgroundPromise = state['features/virtual-background'].backgroundEffectEnabled
18
+        ? getBackgroundEffect()
19
             .catch(error => {
19
             .catch(error => {
20
-                logger.error('Failed to obtain the blur effect instance with error: ', error);
20
+                logger.error('Failed to obtain the background effect instance with error: ', error);
21
 
21
 
22
                 return Promise.resolve();
22
                 return Promise.resolve();
23
             })
23
             })
31
             })
31
             })
32
         : Promise.resolve();
32
         : Promise.resolve();
33
 
33
 
34
-    return Promise.all([ blurPromise, screenshotCapturePromise ]);
34
+    return Promise.all([ backgroundPromise, screenshotCapturePromise ]);
35
 }
35
 }

+ 0
- 21
react/features/blur/actionTypes.js Целия файл

1
-// @flow
2
-
3
-/**
4
- * The type of redux action dispatched which represents that the blur
5
- * is enabled.
6
- *
7
- * {
8
- *      type: BLUR_ENABLED
9
- * }
10
- */
11
-export const BLUR_ENABLED = 'BLUR_ENABLED';
12
-
13
-/**
14
- * The type of redux action dispatched which represents that the blur
15
- * is disabled.
16
- *
17
- * {
18
- *      type: BLUR_DISABLED
19
- * }
20
- */
21
-export const BLUR_DISABLED = 'BLUR_DISABLED';

+ 0
- 67
react/features/blur/actions.js Целия файл

1
-// @flow
2
-
3
-import { getLocalVideoTrack } from '../../features/base/tracks';
4
-
5
-import { BLUR_DISABLED, BLUR_ENABLED } from './actionTypes';
6
-import { getBlurEffect } from './functions';
7
-import logger from './logger';
8
-
9
-/**
10
-* Signals the local participant is switching between blurred or non blurred video.
11
-*
12
-* @param {boolean} enabled - If true enables video blur, false otherwise.
13
-* @returns {Promise}
14
-*/
15
-export function toggleBlurEffect(enabled: boolean) {
16
-    return function(dispatch: (Object) => Object, getState: () => any) {
17
-        const state = getState();
18
-
19
-        if (state['features/blur'].blurEnabled !== enabled) {
20
-            const { jitsiTrack } = getLocalVideoTrack(state['features/base/tracks']);
21
-
22
-            return getBlurEffect()
23
-                .then(blurEffectInstance =>
24
-                    jitsiTrack.setEffect(enabled ? blurEffectInstance : undefined)
25
-                        .then(() => {
26
-                            enabled ? dispatch(blurEnabled()) : dispatch(blurDisabled());
27
-                        })
28
-                        .catch(error => {
29
-                            enabled ? dispatch(blurDisabled()) : dispatch(blurEnabled());
30
-                            logger.error('setEffect failed with error:', error);
31
-                        })
32
-                )
33
-                .catch(error => {
34
-                    dispatch(blurDisabled());
35
-                    logger.error('getBlurEffect failed with error:', error);
36
-                });
37
-        }
38
-
39
-        return Promise.resolve();
40
-    };
41
-}
42
-
43
-/**
44
- * Signals the local participant that the blur has been enabled.
45
- *
46
- * @returns {{
47
- *      type: BLUR_ENABLED
48
- * }}
49
- */
50
-export function blurEnabled() {
51
-    return {
52
-        type: BLUR_ENABLED
53
-    };
54
-}
55
-
56
-/**
57
- * Signals the local participant that the blur has been disabled.
58
- *
59
- * @returns {{
60
- *      type: BLUR_DISABLED
61
- * }}
62
- */
63
-export function blurDisabled() {
64
-    return {
65
-        type: BLUR_DISABLED
66
-    };
67
-}

+ 0
- 1
react/features/blur/components/index.js Целия файл

1
-export { default as VideoBlurButton } from './VideoBlurButton';

+ 0
- 26
react/features/blur/reducer.js Целия файл

1
-// @flow
2
-
3
-import { ReducerRegistry } from '../base/redux';
4
-
5
-import { BLUR_ENABLED, BLUR_DISABLED } from './actionTypes';
6
-
7
-
8
-ReducerRegistry.register('features/blur', (state = {}, action) => {
9
-
10
-    switch (action.type) {
11
-    case BLUR_ENABLED: {
12
-        return {
13
-            ...state,
14
-            blurEnabled: true
15
-        };
16
-    }
17
-    case BLUR_DISABLED: {
18
-        return {
19
-            ...state,
20
-            blurEnabled: false
21
-        };
22
-    }
23
-    }
24
-
25
-    return state;
26
-});

+ 0
- 61
react/features/stream-effects/blur/index.js Целия файл

1
-// @flow
2
-
3
-import * as wasmCheck from 'wasm-check';
4
-
5
-import JitsiStreamBlurEffect from './JitsiStreamBlurEffect';
6
-import createTFLiteModule from './vendor/tflite/tflite';
7
-import createTFLiteSIMDModule from './vendor/tflite/tflite-simd';
8
-
9
-const models = {
10
-    'model96': 'libs/segm_lite_v681.tflite',
11
-    'model144': 'libs/segm_full_v679.tflite'
12
-};
13
-
14
-const segmentationDimensions = {
15
-    'model96': {
16
-        'height': 96,
17
-        'width': 160
18
-    },
19
-    'model144': {
20
-        'height': 144,
21
-        'width': 256
22
-    }
23
-};
24
-
25
-/**
26
- * Creates a new instance of JitsiStreamBlurEffect. This loads the bodyPix model that is used to
27
- * extract person segmentation.
28
- *
29
- * @returns {Promise<JitsiStreamBlurEffect>}
30
- */
31
-export async function createBlurEffect() {
32
-    if (!MediaStreamTrack.prototype.getSettings && !MediaStreamTrack.prototype.getConstraints) {
33
-        throw new Error('JitsiStreamBlurEffect not supported!');
34
-    }
35
-    let tflite;
36
-
37
-    if (wasmCheck.feature.simd) {
38
-        tflite = await createTFLiteSIMDModule();
39
-    } else {
40
-        tflite = await createTFLiteModule();
41
-    }
42
-
43
-    const modelBufferOffset = tflite._getModelBufferMemoryOffset();
44
-    const modelResponse = await fetch(
45
-        wasmCheck.feature.simd ? models.model144 : models.model96
46
-    );
47
-
48
-    if (!modelResponse.ok) {
49
-        throw new Error('Failed to download tflite model!');
50
-    }
51
-
52
-    const model = await modelResponse.arrayBuffer();
53
-
54
-    tflite.HEAPU8.set(new Uint8Array(model), modelBufferOffset);
55
-
56
-    tflite._loadModel(model.byteLength);
57
-
58
-    const options = wasmCheck.feature.simd ? segmentationDimensions.model144 : segmentationDimensions.model96;
59
-
60
-    return new JitsiStreamBlurEffect(tflite, options);
61
-}

react/features/stream-effects/blur/JitsiStreamBlurEffect.js → react/features/stream-effects/virtual-background/JitsiStreamBackgroundEffect.js Целия файл

9
 const blurValue = '25px';
9
 const blurValue = '25px';
10
 
10
 
11
 /**
11
 /**
12
- * Represents a modified MediaStream that adds blur to video background.
13
- * <tt>JitsiStreamBlurEffect</tt> does the processing of the original
12
+ * Represents a modified MediaStream that adds effects to video background.
13
+ * <tt>JitsiStreamBackgroundEffect</tt> does the processing of the original
14
  * video stream.
14
  * video stream.
15
  */
15
  */
16
-export default class JitsiStreamBlurEffect {
16
+export default class JitsiStreamBackgroundEffect {
17
     _model: Object;
17
     _model: Object;
18
     _options: Object;
18
     _options: Object;
19
     _segmentationPixelCount: number;
19
     _segmentationPixelCount: number;
29
     isEnabled: Function;
29
     isEnabled: Function;
30
     startEffect: Function;
30
     startEffect: Function;
31
     stopEffect: Function;
31
     stopEffect: Function;
32
+    virtualImage: Image;
32
 
33
 
33
     /**
34
     /**
34
      * Represents a modified video MediaStream track.
35
      * Represents a modified video MediaStream track.
38
      * @param {Object} options - Segmentation dimensions.
39
      * @param {Object} options - Segmentation dimensions.
39
      */
40
      */
40
     constructor(model: Object, options: Object) {
41
     constructor(model: Object, options: Object) {
42
+        this._options = options;
43
+
44
+        if (this._options.virtualBackground.isVirtualBackground) {
45
+            this.virtualImage = new Image();
46
+            this.virtualImage.src = this._options.virtualBackground.virtualSource;
47
+        }
41
         this._model = model;
48
         this._model = model;
42
         this._options = options;
49
         this._options = options;
43
         this._segmentationPixelCount = this._options.width * this._options.height;
50
         this._segmentationPixelCount = this._options.width * this._options.height;
91
         this._outputCanvasCtx.drawImage(this._inputVideoElement, 0, 0);
98
         this._outputCanvasCtx.drawImage(this._inputVideoElement, 0, 0);
92
 
99
 
93
         this._outputCanvasCtx.globalCompositeOperation = 'destination-over';
100
         this._outputCanvasCtx.globalCompositeOperation = 'destination-over';
94
-        this._outputCanvasCtx.filter = `blur(${blurValue})`;
95
-        this._outputCanvasCtx.drawImage(this._inputVideoElement, 0, 0);
101
+        if (this._options.virtualBackground.isVirtualBackground) {
102
+            this._outputCanvasCtx.drawImage(this.virtualImage, 0, 0);
103
+        } else {
104
+            this._outputCanvasCtx.filter = `blur(${blurValue})`;
105
+            this._outputCanvasCtx.drawImage(this._inputVideoElement, 0, 0);
106
+        }
96
     }
107
     }
97
 
108
 
98
     /**
109
     /**
196
         this._segmentationMaskCanvas.width = this._options.width;
207
         this._segmentationMaskCanvas.width = this._options.width;
197
         this._segmentationMaskCanvas.height = this._options.height;
208
         this._segmentationMaskCanvas.height = this._options.height;
198
         this._segmentationMaskCtx = this._segmentationMaskCanvas.getContext('2d');
209
         this._segmentationMaskCtx = this._segmentationMaskCanvas.getContext('2d');
210
+
199
         this._outputCanvasElement.width = parseInt(width, 10);
211
         this._outputCanvasElement.width = parseInt(width, 10);
200
         this._outputCanvasElement.height = parseInt(height, 10);
212
         this._outputCanvasElement.height = parseInt(height, 10);
201
         this._outputCanvasCtx = this._outputCanvasElement.getContext('2d');
213
         this._outputCanvasCtx = this._outputCanvasElement.getContext('2d');

react/features/stream-effects/blur/TimerWorker.js → react/features/stream-effects/virtual-background/TimerWorker.js Целия файл


+ 64
- 0
react/features/stream-effects/virtual-background/index.js Целия файл

1
+// @flow
2
+
3
+import * as wasmCheck from 'wasm-check';
4
+
5
+import JitsiStreamBackgroundEffect from './JitsiStreamBackgroundEffect';
6
+import createTFLiteModule from './vendor/tflite/tflite';
7
+import createTFLiteSIMDModule from './vendor/tflite/tflite-simd';
8
+
9
+const models = {
10
+    model96: 'libs/segm_lite_v681.tflite',
11
+    model144: 'libs/segm_full_v679.tflite'
12
+};
13
+
14
+const segmentationDimensions = {
15
+    model96: {
16
+        height: 96,
17
+        width: 160
18
+    },
19
+    model144: {
20
+        height: 144,
21
+        width: 256
22
+    }
23
+};
24
+
25
+/**
26
+ * Creates a new instance of JitsiStreamBackgroundEffect. This loads the Meet background model that is used to
27
+ * extract person segmentation.
28
+ *
29
+ * @param {Object} virtualBackground - The virtual object that contains the background image source and
30
+ * the isVirtualBackground flag that indicates if virtual image is activated.
31
+ * @returns {Promise<JitsiStreamBackgroundEffect>}
32
+ */
33
+export async function createVirtualBackgroundEffect(virtualBackground: Object) {
34
+    if (!MediaStreamTrack.prototype.getSettings && !MediaStreamTrack.prototype.getConstraints) {
35
+        throw new Error('JitsiStreamBackgroundEffect not supported!');
36
+    }
37
+    let tflite;
38
+
39
+    if (wasmCheck.feature.simd) {
40
+        tflite = await createTFLiteSIMDModule();
41
+    } else {
42
+        tflite = await createTFLiteModule();
43
+    }
44
+
45
+    const modelBufferOffset = tflite._getModelBufferMemoryOffset();
46
+    const modelResponse = await fetch(wasmCheck.feature.simd ? models.model144 : models.model96);
47
+
48
+    if (!modelResponse.ok) {
49
+        throw new Error('Failed to download tflite model!');
50
+    }
51
+
52
+    const model = await modelResponse.arrayBuffer();
53
+
54
+    tflite.HEAPU8.set(new Uint8Array(model), modelBufferOffset);
55
+
56
+    tflite._loadModel(model.byteLength);
57
+
58
+    const options = {
59
+        ...wasmCheck.feature.simd ? segmentationDimensions.model144 : segmentationDimensions.model96,
60
+        virtualBackground
61
+    };
62
+
63
+    return new JitsiStreamBackgroundEffect(tflite, options);
64
+}

react/features/stream-effects/blur/vendor/README.md → react/features/stream-effects/virtual-background/vendor/README.md Целия файл


react/features/stream-effects/blur/vendor/models/segm_full_v679.tflite → react/features/stream-effects/virtual-background/vendor/models/segm_full_v679.tflite Целия файл


react/features/stream-effects/blur/vendor/models/segm_lite_v681.tflite → react/features/stream-effects/virtual-background/vendor/models/segm_lite_v681.tflite Целия файл


react/features/stream-effects/blur/vendor/tflite/tflite-simd.js → react/features/stream-effects/virtual-background/vendor/tflite/tflite-simd.js Целия файл


react/features/stream-effects/blur/vendor/tflite/tflite-simd.wasm → react/features/stream-effects/virtual-background/vendor/tflite/tflite-simd.wasm Целия файл


react/features/stream-effects/blur/vendor/tflite/tflite.js → react/features/stream-effects/virtual-background/vendor/tflite/tflite.js Целия файл


react/features/stream-effects/blur/vendor/tflite/tflite.wasm → react/features/stream-effects/virtual-background/vendor/tflite/tflite.wasm Целия файл


+ 5
- 5
react/features/toolbox/components/web/Toolbox.js Целия файл

35
 import { OverflowMenuItem } from '../../../base/toolbox/components';
35
 import { OverflowMenuItem } from '../../../base/toolbox/components';
36
 import { getLocalVideoTrack, toggleScreensharing } from '../../../base/tracks';
36
 import { getLocalVideoTrack, toggleScreensharing } from '../../../base/tracks';
37
 import { isVpaasMeeting } from '../../../billing-counter/functions';
37
 import { isVpaasMeeting } from '../../../billing-counter/functions';
38
-import { VideoBlurButton } from '../../../blur';
39
-import { checkBlurSupport } from '../../../blur/functions';
40
 import { CHAT_SIZE, ChatCounter, toggleChat } from '../../../chat';
38
 import { CHAT_SIZE, ChatCounter, toggleChat } from '../../../chat';
41
 import { EmbedMeetingDialog } from '../../../embed-meeting';
39
 import { EmbedMeetingDialog } from '../../../embed-meeting';
42
 import { SharedDocumentButton } from '../../../etherpad';
40
 import { SharedDocumentButton } from '../../../etherpad';
68
     OverflowMenuVideoQualityItem,
66
     OverflowMenuVideoQualityItem,
69
     VideoQualityDialog
67
     VideoQualityDialog
70
 } from '../../../video-quality';
68
 } from '../../../video-quality';
69
+import { VideoBackgroundButton } from '../../../virtual-background';
70
+import { checkBlurSupport } from '../../../virtual-background/functions';
71
 import {
71
 import {
72
     setFullScreen,
72
     setFullScreen,
73
     setOverflowMenuVisible,
73
     setOverflowMenuVisible,
1017
                 && <SharedDocumentButton
1017
                 && <SharedDocumentButton
1018
                     key = 'etherpad'
1018
                     key = 'etherpad'
1019
                     showLabel = { true } />,
1019
                     showLabel = { true } />,
1020
-            this._shouldShowButton('videobackgroundblur')
1021
-                && <VideoBlurButton
1022
-                    key = 'videobackgroundblur'
1020
+            (this._shouldShowButton('select-background') || this._shouldShowButton('videobackgroundblur'))
1021
+                && <VideoBackgroundButton
1022
+                    key = { 'select-background' }
1023
                     showLabel = { true }
1023
                     showLabel = { true }
1024
                     visible = { !_screensharing && checkBlurSupport() } />,
1024
                     visible = { !_screensharing && checkBlurSupport() } />,
1025
             this._shouldShowButton('stats')
1025
             this._shouldShowButton('stats')

+ 23
- 0
react/features/virtual-background/actionTypes.js Целия файл

1
+// @flow
2
+
3
+/**
4
+ * The type of redux action dispatched which represents that the background
5
+ * effect is enabled or not.
6
+ *
7
+ * @returns {{
8
+ *     type: BACKGROUND_ENABLED,
9
+ *     backgroundEffectEnabled: boolean,
10
+ * }}
11
+ */
12
+export const BACKGROUND_ENABLED = 'BACKGROUND_ENABLED';
13
+
14
+/**
15
+ * The type of the action which enables or disables virtual background
16
+ *
17
+ * @returns {{
18
+ *     type: SET_VIRTUAL_BACKGROUND,
19
+ *     isVirtualBackground: boolean,
20
+ *     virtualSource: string,
21
+ * }}
22
+ */
23
+export const SET_VIRTUAL_BACKGROUND = 'SET_VIRTUAL_BACKGROUND';

+ 70
- 0
react/features/virtual-background/actions.js Целия файл

1
+// @flow
2
+
3
+import { getLocalVideoTrack } from '../../features/base/tracks';
4
+
5
+import { BACKGROUND_ENABLED, SET_VIRTUAL_BACKGROUND } from './actionTypes';
6
+import { getBackgroundEffect } from './functions';
7
+import logger from './logger';
8
+
9
+/**
10
+ * Signals the local participant activate the virtual background video or not.
11
+ *
12
+ * @param {boolean} enabled - If true enables video background, false otherwise.
13
+ * @returns {Promise}
14
+ */
15
+export function toggleBackgroundEffect(enabled: boolean) {
16
+    return async function(dispatch: Object => Object, getState: () => any) {
17
+        const state = getState();
18
+
19
+        const { jitsiTrack } = getLocalVideoTrack(state['features/base/tracks']);
20
+        const virtualBackground = state['features/virtual-background'];
21
+
22
+        try {
23
+            if (enabled) {
24
+                await jitsiTrack.setEffect(await getBackgroundEffect(virtualBackground));
25
+                dispatch(backgroundEnabled(true));
26
+            } else {
27
+                await jitsiTrack.setEffect(undefined);
28
+                dispatch(backgroundEnabled(false));
29
+            }
30
+        } catch (error) {
31
+            dispatch(backgroundEnabled(false));
32
+            logger.error('Error on apply backgroun effect:', error);
33
+        }
34
+    };
35
+}
36
+
37
+/**
38
+ * Sets the selected virtual background image object.
39
+ *
40
+ * @param {Object} virtualSource - Virtual background image source.
41
+ * @param {boolean} isVirtualBackground - Indicate if virtual image is activated.
42
+ * @returns {{
43
+ *     type: SET_VIRTUAL_BACKGROUND,
44
+ *     virtualSource: string,
45
+ *     isVirtualBackground: boolean,
46
+ * }}
47
+ */
48
+export function setVirtualBackground(virtualSource: string, isVirtualBackground: boolean) {
49
+    return {
50
+        type: SET_VIRTUAL_BACKGROUND,
51
+        virtualSource,
52
+        isVirtualBackground
53
+    };
54
+}
55
+
56
+/**
57
+ * Signals the local participant that the background effect has been enabled.
58
+ *
59
+ * @param {boolean} backgroundEffectEnabled - Indicate if virtual background effect is activated.
60
+ * @returns {{
61
+ *      type: BACKGROUND_ENABLED,
62
+ *      backgroundEffectEnabled: boolean,
63
+ * }}
64
+ */
65
+export function backgroundEnabled(backgroundEffectEnabled: boolean) {
66
+    return {
67
+        type: BACKGROUND_ENABLED,
68
+        backgroundEffectEnabled
69
+    };
70
+}

react/features/blur/components/VideoBlurButton.js → react/features/virtual-background/components/VideoBackgroundButton.js Целия файл

1
 // @flow
1
 // @flow
2
 
2
 
3
-import { createVideoBlurEvent, sendAnalytics } from '../../analytics';
3
+import { openDialog } from '../../base/dialog';
4
 import { translate } from '../../base/i18n';
4
 import { translate } from '../../base/i18n';
5
-import { IconBlurBackground } from '../../base/icons';
5
+import { IconVirtualBackground } from '../../base/icons';
6
 import { connect } from '../../base/redux';
6
 import { connect } from '../../base/redux';
7
 import { AbstractButton } from '../../base/toolbox/components';
7
 import { AbstractButton } from '../../base/toolbox/components';
8
 import type { AbstractButtonProps } from '../../base/toolbox/components';
8
 import type { AbstractButtonProps } from '../../base/toolbox/components';
9
 import { isLocalCameraTrackMuted } from '../../base/tracks';
9
 import { isLocalCameraTrackMuted } from '../../base/tracks';
10
-import { toggleBlurEffect } from '../actions';
10
+
11
+import { VirtualBackgroundDialog } from './index';
11
 
12
 
12
 /**
13
 /**
13
- * The type of the React {@code Component} props of {@link VideoBlurButton}.
14
+ * The type of the React {@code Component} props of {@link VideoBackgroundButton}.
14
  */
15
  */
15
 type Props = AbstractButtonProps & {
16
 type Props = AbstractButtonProps & {
16
 
17
 
17
     /**
18
     /**
18
      * True if the video background is blurred or false if it is not.
19
      * True if the video background is blurred or false if it is not.
19
      */
20
      */
20
-    _isVideoBlurred: boolean,
21
+    _isBackgroundEnabled: boolean,
21
 
22
 
22
     /**
23
     /**
23
      * Whether video is currently muted or not.
24
      * Whether video is currently muted or not.
28
      * The redux {@code dispatch} function.
29
      * The redux {@code dispatch} function.
29
      */
30
      */
30
     dispatch: Function
31
     dispatch: Function
31
-
32
 };
32
 };
33
 
33
 
34
 /**
34
 /**
35
- * An abstract implementation of a button that toggles the video blur effect.
35
+ * An abstract implementation of a button that toggles the video background dialog.
36
  */
36
  */
37
-class VideoBlurButton extends AbstractButton<Props, *> {
38
-    accessibilityLabel = 'toolbar.accessibilityLabel.videoblur';
39
-    icon = IconBlurBackground;
40
-    label = 'toolbar.startvideoblur';
41
-    toggledLabel = 'toolbar.stopvideoblur';
37
+class VideoBackgroundButton extends AbstractButton<Props, *> {
38
+    accessibilityLabel = 'toolbar.accessibilityLabel.selectBackground';
39
+    icon = IconVirtualBackground;
40
+    label = 'toolbar.selectBackground';
41
+    tooltip = 'toolbar.selectBackground';
42
 
42
 
43
     /**
43
     /**
44
-     * Handles clicking / pressing the button, and toggles the blur effect
44
+     * Handles clicking / pressing the button, and toggles the virtual background dialog
45
      * state accordingly.
45
      * state accordingly.
46
      *
46
      *
47
      * @protected
47
      * @protected
48
      * @returns {void}
48
      * @returns {void}
49
      */
49
      */
50
     _handleClick() {
50
     _handleClick() {
51
-        const { _isVideoBlurred, dispatch } = this.props;
52
-        const value = !_isVideoBlurred;
51
+        const { dispatch } = this.props;
53
 
52
 
54
-        sendAnalytics(createVideoBlurEvent(value ? 'started' : 'stopped'));
55
-        dispatch(toggleBlurEffect(value));
53
+        dispatch(openDialog(VirtualBackgroundDialog));
56
     }
54
     }
57
 
55
 
58
     /**
56
     /**
59
-     * Returns {@code boolean} value indicating if the blur effect is
57
+     * Returns {@code boolean} value indicating if the background effect is
60
      * enabled or not.
58
      * enabled or not.
61
      *
59
      *
62
      * @protected
60
      * @protected
63
      * @returns {boolean}
61
      * @returns {boolean}
64
      */
62
      */
65
     _isToggled() {
63
     _isToggled() {
66
-        return this.props._isVideoBlurred;
64
+        return this.props._isBackgroundEnabled;
67
     }
65
     }
68
 
66
 
69
     /**
67
     /**
80
 
78
 
81
 /**
79
 /**
82
  * Maps (parts of) the redux state to the associated props for the
80
  * Maps (parts of) the redux state to the associated props for the
83
- * {@code VideoBlurButton} component.
81
+ * {@code VideoBackgroundButton} component.
84
  *
82
  *
85
  * @param {Object} state - The Redux state.
83
  * @param {Object} state - The Redux state.
86
  * @private
84
  * @private
87
  * @returns {{
85
  * @returns {{
88
- *     _isVideoBlurred: boolean
86
+ *     _isBackgroundEnabled: boolean
89
  * }}
87
  * }}
90
  */
88
  */
91
 function _mapStateToProps(state): Object {
89
 function _mapStateToProps(state): Object {
92
     const tracks = state['features/base/tracks'];
90
     const tracks = state['features/base/tracks'];
93
 
91
 
94
     return {
92
     return {
95
-        _isVideoBlurred: Boolean(state['features/blur'].blurEnabled),
93
+        _isBackgroundEnabled: Boolean(state['features/virtual-background'].backgroundEffectEnabled),
96
         _videoMuted: isLocalCameraTrackMuted(tracks)
94
         _videoMuted: isLocalCameraTrackMuted(tracks)
97
     };
95
     };
98
 }
96
 }
99
 
97
 
100
-export default translate(connect(_mapStateToProps)(VideoBlurButton));
101
-
98
+export default translate(connect(_mapStateToProps)(VideoBackgroundButton));

+ 118
- 0
react/features/virtual-background/components/VirtualBackgroundDialog.js Целия файл

1
+// @flow
2
+/* eslint-disable react/jsx-no-bind, no-return-assign */
3
+import React, { useState } from 'react';
4
+
5
+import { Dialog } from '../../base/dialog';
6
+import { translate } from '../../base/i18n';
7
+import { Icon, IconBlurBackground } from '../../base/icons';
8
+import { connect } from '../../base/redux';
9
+import { Tooltip } from '../../base/tooltip';
10
+import { toggleBackgroundEffect, setVirtualBackground } from '../actions';
11
+
12
+const images = [
13
+    {
14
+        tooltip: 'Image 1',
15
+        name: 'background-1.jpg',
16
+        id: 1,
17
+        src: 'images/virtual-background/background-1.jpg'
18
+    },
19
+    {
20
+        tooltip: 'Image 2',
21
+        name: 'background-2.jpg',
22
+        id: 2,
23
+        src: 'images/virtual-background/background-2.jpg'
24
+    },
25
+    {
26
+        tooltip: 'Image 3',
27
+        name: 'background-3.jpg',
28
+        id: 3,
29
+        src: 'images/virtual-background/background-3.jpg'
30
+    },
31
+    {
32
+        tooltip: 'Image 4',
33
+        name: 'background-4.jpg',
34
+        id: 4,
35
+        src: 'images/virtual-background/background-4.jpg'
36
+    }
37
+];
38
+type Props = {
39
+
40
+    /**
41
+     * The redux {@code dispatch} function.
42
+     */
43
+    dispatch: Function,
44
+
45
+    /**
46
+     * Invoked to obtain translated strings.
47
+     */
48
+    t: Function
49
+};
50
+
51
+/**
52
+ * Renders virtual background dialog.
53
+ *
54
+ * @returns {ReactElement}
55
+ */
56
+function VirtualBackground({ dispatch, t }: Props) {
57
+    const [ selected, setSelected ] = useState('');
58
+    const enableBlur = () => {
59
+        setSelected('blur');
60
+        dispatch(setVirtualBackground('', false));
61
+        dispatch(toggleBackgroundEffect(true));
62
+    };
63
+
64
+    const removeBackground = () => {
65
+        setSelected('none');
66
+        dispatch(setVirtualBackground('', false));
67
+        dispatch(toggleBackgroundEffect(false));
68
+    };
69
+
70
+    const addImageBackground = image => {
71
+        setSelected(image.id);
72
+        dispatch(setVirtualBackground(image.src, true));
73
+        dispatch(toggleBackgroundEffect(true));
74
+    };
75
+
76
+    return (
77
+        <Dialog
78
+            hideCancelButton = { true }
79
+            submitDisabled = { false }
80
+            titleKey = { 'virtualBackground.title' }
81
+            width = 'small'>
82
+            <div className = 'virtual-background-dialog'>
83
+                <Tooltip
84
+                    content = { t('virtualBackground.removeBackground') }
85
+                    position = { 'top' }>
86
+                    <div
87
+                        className = { selected === 'none' ? 'none-selected' : 'virtual-background-none' }
88
+                        onClick = { () => removeBackground() }>
89
+                        None
90
+                    </div>
91
+                </Tooltip>
92
+                <Tooltip
93
+                    content = { t('virtualBackground.enableBlur') }
94
+                    position = { 'top' }>
95
+                    <Icon
96
+                        className = { selected === 'blur' ? 'blur-selected' : '' }
97
+                        onClick = { () => enableBlur() }
98
+                        size = { 50 }
99
+                        src = { IconBlurBackground } />
100
+                </Tooltip>
101
+                {images.map((image, index) => (
102
+                    <Tooltip
103
+                        content = { image.tooltip }
104
+                        key = { index }
105
+                        position = { 'top' }>
106
+                        <img
107
+                            className = { selected === image.id ? 'thumbnail-selected' : 'thumbnail' }
108
+                            onClick = { () => addImageBackground(image) }
109
+                            onError = { event => event.target.style.display = 'none' }
110
+                            src = { image.src } />
111
+                    </Tooltip>
112
+                ))}
113
+            </div>
114
+        </Dialog>
115
+    );
116
+}
117
+
118
+export default translate(connect()(VirtualBackground));

+ 2
- 0
react/features/virtual-background/components/index.js Целия файл

1
+export { default as VideoBackgroundButton } from './VideoBackgroundButton';
2
+export { default as VirtualBackgroundDialog } from './VirtualBackgroundDialog';

react/features/blur/functions.js → react/features/virtual-background/functions.js Целия файл

7
 /**
7
 /**
8
  * Returns promise that resolves with the blur effect instance.
8
  * Returns promise that resolves with the blur effect instance.
9
  *
9
  *
10
- * @returns {Promise<JitsiStreamBlurEffect>} - Resolves with the blur effect instance.
10
+ * @param {Object} virtualBackground - The virtual object that contains the background image source and
11
+ * the isVirtualBackground flag that indicates if virtual image is activated .
12
+ * @returns {Promise<JitsiStreamBackgroundEffect>} - Resolves with the background effect instance.
11
  */
13
  */
12
-export function getBlurEffect() {
14
+export function getBackgroundEffect(virtualBackground: Object) {
13
     const ns = getJitsiMeetGlobalNS();
15
     const ns = getJitsiMeetGlobalNS();
14
 
16
 
15
-    if (ns.effects && ns.effects.createBlurEffect) {
16
-        return ns.effects.createBlurEffect();
17
+    if (ns.effects && ns.effects.createVirtualBackgroundEffect) {
18
+        return ns.effects.createVirtualBackgroundEffect(virtualBackground);
17
     }
19
     }
18
 
20
 
19
-    return loadScript('libs/video-blur-effect.min.js').then(() => ns.effects.createBlurEffect());
21
+    return loadScript('libs/virtual-background-effect.min.js').then(() =>
22
+        ns.effects.createVirtualBackgroundEffect(virtualBackground));
20
 }
23
 }
21
 
24
 
22
 /**
25
 /**

react/features/blur/index.js → react/features/virtual-background/index.js Целия файл


react/features/blur/logger.js → react/features/virtual-background/logger.js Целия файл

2
 
2
 
3
 import { getLogger } from '../base/logging/functions';
3
 import { getLogger } from '../base/logging/functions';
4
 
4
 
5
-export default getLogger('features/blur');
5
+export default getLogger('features/virtual-background');

+ 38
- 0
react/features/virtual-background/reducer.js Целия файл

1
+// @flow
2
+
3
+import { ReducerRegistry } from '../base/redux';
4
+
5
+import { BACKGROUND_ENABLED, SET_VIRTUAL_BACKGROUND } from './actionTypes';
6
+
7
+/**
8
+ * Reduces redux actions which activate/deactivate virtual background image, or
9
+ * indicate if the virtual image background is activated/deactivated. The
10
+ * backgroundEffectEnabled flag indicate if virtual background effect is activated.
11
+ *
12
+ * @param {State} state - The current redux state.
13
+ * @param {Action} action - The redux action to reduce.
14
+ * @param {string} action.type - The type of the redux action to reduce..
15
+ * @returns {State} The next redux state that is the result of reducing the
16
+ * specified action.
17
+ */
18
+ReducerRegistry.register('features/virtual-background', (state = {}, action) => {
19
+    const { virtualSource, isVirtualBackground, backgroundEffectEnabled } = action;
20
+
21
+    switch (action.type) {
22
+    case SET_VIRTUAL_BACKGROUND: {
23
+        return {
24
+            ...state,
25
+            virtualSource,
26
+            isVirtualBackground
27
+        };
28
+    }
29
+    case BACKGROUND_ENABLED: {
30
+        return {
31
+            ...state,
32
+            backgroundEffectEnabled
33
+        };
34
+    }
35
+    }
36
+
37
+    return state;
38
+});

+ 2
- 2
webpack.config.js Целия файл

240
         performance: getPerformanceHints(128 * 1024)
240
         performance: getPerformanceHints(128 * 1024)
241
     }),
241
     }),
242
 
242
 
243
-    // Because both video-blur-effect and rnnoise-processor modules are loaded
243
+    // Because both virtual-background-effect and rnnoise-processor modules are loaded
244
     // in a lazy manner using the loadScript function with a hard coded name,
244
     // in a lazy manner using the loadScript function with a hard coded name,
245
     // i.e.loadScript('libs/rnnoise-processor.min.js'), webpack dev server
245
     // i.e.loadScript('libs/rnnoise-processor.min.js'), webpack dev server
246
     // won't know how to properly load them using the default config filename
246
     // won't know how to properly load them using the default config filename
249
     // prod and dev mode.
249
     // prod and dev mode.
250
     Object.assign({}, config, {
250
     Object.assign({}, config, {
251
         entry: {
251
         entry: {
252
-            'video-blur-effect': './react/features/stream-effects/blur/index.js'
252
+            'virtual-background-effect': './react/features/stream-effects/virtual-background/index.js'
253
         },
253
         },
254
         output: Object.assign({}, config.output, {
254
         output: Object.assign({}, config.output, {
255
             library: [ 'JitsiMeetJS', 'app', 'effects' ],
255
             library: [ 'JitsiMeetJS', 'app', 'effects' ],

Loading…
Отказ
Запис