You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.js 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // @flow
  2. import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications';
  3. import { showWarningNotification } from '../../notifications/actions';
  4. import { timeout } from '../../virtual-background/functions';
  5. import logger from '../../virtual-background/logger';
  6. import JitsiStreamBackgroundEffect from './JitsiStreamBackgroundEffect';
  7. import createTFLiteModule from './vendor/tflite/tflite';
  8. import createTFLiteSIMDModule from './vendor/tflite/tflite-simd';
  9. const models = {
  10. modelLandscape: 'libs/selfie_segmentation_landscape.tflite'
  11. };
  12. let tflite;
  13. let wasmCheck;
  14. let isWasmDisabled = false;
  15. const segmentationDimensions = {
  16. modelLandscape: {
  17. height: 144,
  18. width: 256
  19. }
  20. };
  21. /**
  22. * Creates a new instance of JitsiStreamBackgroundEffect. This loads the Meet background model that is used to
  23. * extract person segmentation.
  24. *
  25. * @param {Object} virtualBackground - The virtual object that contains the background image source and
  26. * the isVirtualBackground flag that indicates if virtual image is activated.
  27. * @param {Function} dispatch - The Redux dispatch function.
  28. * @returns {Promise<JitsiStreamBackgroundEffect>}
  29. */
  30. export async function createVirtualBackgroundEffect(virtualBackground: Object, dispatch: Function) {
  31. if (!MediaStreamTrack.prototype.getSettings && !MediaStreamTrack.prototype.getConstraints) {
  32. throw new Error('JitsiStreamBackgroundEffect not supported!');
  33. }
  34. // Checks if WebAssembly feature is supported or enabled by/in the browser.
  35. // Conditional import of wasm-check package is done to prevent
  36. // the browser from crashing when the user opens the app.
  37. if (!tflite && !isWasmDisabled) {
  38. try {
  39. wasmCheck = require('wasm-check');
  40. const tfliteTimeout = 10000;
  41. if (wasmCheck?.feature?.simd) {
  42. tflite = await timeout(tfliteTimeout, createTFLiteSIMDModule());
  43. } else {
  44. tflite = await timeout(tfliteTimeout, createTFLiteModule());
  45. }
  46. } catch (err) {
  47. isWasmDisabled = true;
  48. if (err?.message === '408') {
  49. logger.error('Failed to download tflite model!');
  50. dispatch(showWarningNotification({
  51. titleKey: 'virtualBackground.backgroundEffectError'
  52. }, NOTIFICATION_TIMEOUT_TYPE.LONG));
  53. } else {
  54. logger.error('Looks like WebAssembly is disabled or not supported on this browser', err);
  55. dispatch(showWarningNotification({
  56. titleKey: 'virtualBackground.webAssemblyWarning',
  57. descriptionKey: 'virtualBackground.webAssemblyWarningDescription'
  58. }, NOTIFICATION_TIMEOUT_TYPE.LONG));
  59. }
  60. return;
  61. }
  62. } else if (isWasmDisabled) {
  63. dispatch(showWarningNotification({
  64. titleKey: 'virtualBackground.backgroundEffectError'
  65. }, NOTIFICATION_TIMEOUT_TYPE.LONG));
  66. return;
  67. }
  68. const modelBufferOffset = tflite._getModelBufferMemoryOffset();
  69. const modelResponse = await fetch(models.modelLandscape);
  70. if (!modelResponse.ok) {
  71. throw new Error('Failed to download tflite model!');
  72. }
  73. const model = await modelResponse.arrayBuffer();
  74. tflite.HEAPU8.set(new Uint8Array(model), modelBufferOffset);
  75. tflite._loadModel(model.byteLength);
  76. const options = {
  77. ...segmentationDimensions.modelLandscape,
  78. virtualBackground
  79. };
  80. return new JitsiStreamBackgroundEffect(tflite, options);
  81. }