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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications';
  2. import { showWarningNotification } from '../../notifications/actions';
  3. import { timeout } from '../../virtual-background/functions';
  4. import logger from '../../virtual-background/logger';
  5. import JitsiStreamBackgroundEffect from './JitsiStreamBackgroundEffect';
  6. import createTFLiteModule from './vendor/tflite/tflite';
  7. import createTFLiteSIMDModule from './vendor/tflite/tflite-simd';
  8. const models = {
  9. modelLandscape: 'libs/selfie_segmentation_landscape.tflite'
  10. };
  11. let modelBuffer;
  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. if (isWasmDisabled) {
  35. dispatch(showWarningNotification({
  36. titleKey: 'virtualBackground.backgroundEffectError'
  37. }, NOTIFICATION_TIMEOUT_TYPE.LONG));
  38. return;
  39. }
  40. // Checks if WebAssembly feature is supported or enabled by/in the browser.
  41. // Conditional import of wasm-check package is done to prevent
  42. // the browser from crashing when the user opens the app.
  43. if (!tflite) {
  44. try {
  45. wasmCheck = require('wasm-check');
  46. const tfliteTimeout = 10000;
  47. if (wasmCheck?.feature?.simd) {
  48. tflite = await timeout(tfliteTimeout, createTFLiteSIMDModule());
  49. } else {
  50. tflite = await timeout(tfliteTimeout, createTFLiteModule());
  51. }
  52. } catch (err) {
  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. isWasmDisabled = true;
  60. logger.error('Looks like WebAssembly is disabled or not supported on this browser', err);
  61. dispatch(showWarningNotification({
  62. titleKey: 'virtualBackground.webAssemblyWarning',
  63. descriptionKey: 'virtualBackground.webAssemblyWarningDescription'
  64. }, NOTIFICATION_TIMEOUT_TYPE.LONG));
  65. }
  66. return;
  67. }
  68. }
  69. if (!modelBuffer) {
  70. const modelResponse = await fetch(models.modelLandscape);
  71. if (!modelResponse.ok) {
  72. throw new Error('Failed to download tflite model!');
  73. }
  74. modelBuffer = await modelResponse.arrayBuffer();
  75. tflite.HEAPU8.set(new Uint8Array(modelBuffer), tflite._getModelBufferMemoryOffset());
  76. tflite._loadModel(modelBuffer.byteLength);
  77. }
  78. const options = {
  79. ...segmentationDimensions.modelLandscape,
  80. virtualBackground
  81. };
  82. return new JitsiStreamBackgroundEffect(tflite, options);
  83. }