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.

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