Giter Club home page Giter Club logo

Comments (11)

wbigert avatar wbigert commented on July 24, 2024 1

@saghul I made a new minimalist Electron app example and its not crashing anymore when using setupScreenSharingMain (although I never got the screensharing to work anyways). I will continue investigating, but it might be something on my end.

from jitsi-meet-electron-sdk.

wbigert avatar wbigert commented on July 24, 2024 1

I am using Node v20.8.1.
├── [email protected]
├── [email protected]
├── @jitsi/[email protected]
├── @jitsi/[email protected]
├── [email protected]
├── @vitejs/[email protected]

For context, I am working on a Vite React project. When I run my Electron main file I also start an Express server that serves the static files of the React project to localhost:4000/. In my main electron file, I start the Express server, create a window, and then load localhost:4000/ onto that window to interact with the React app. Locally, @jitsi/react-sdk has worked great with the Vite project. But when using the app inside an Electron window, screen sharing crashes. And my understanding is that I need to use '@jitsi/electron-sdk' to fix this.

I have tried 3 different approaches which have all failed.

Approach 1: Setting nodeIntegration to false and contextIsolation to true

This appears to be best practice for security reasons.

electron/main/index.ts:

  ...
  win = new BrowserWindow({
    title: 'Main window',
    webPreferences: {
      preload,
      contextIsolation: true,
      nodeIntegration: false,
      sandbox: false
    }
  })
  
  const appName = 'doffice'
  const osxBundleId = 'com.ebox.doffice'
  setupScreenSharingMain(win, appName, osxBundleId)
  ...

Then I expose the render setup functions to my React app using a contextBridge.
electron/preload/index.ts:

  import {
    setupScreenSharingRender,
    initPopupsConfigurationRender,
    setupPowerMonitorRender
  } from '@jitsi/electron-sdk'
  import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron'
  
  const whitelistedIpcChannels = ['protocol-data-msg', 'renderer-ready']
  
  function openExternalLink (url: string): void {
    ipcRenderer.send('jitsi-open-url', url)
  }
  
  /**
   * Setup the renderer process.
   *
   * @param api - API object.
   * @param options - Options for what to enable.
   * @returns void
   */
  function setupRenderer (api: any): void { // Replace `any` with a more specific type if available
    initPopupsConfigurationRender(api)
  
    const iframe = api.getIFrame()
  
    setupScreenSharingRender(api)
  
    setupPowerMonitorRender(api)
  }
  
  contextBridge.exposeInMainWorld('electron', {
    openExternalLink,
    setupRenderer,
    ipc: {
      on: (channel: any, listener: any) => {
        if (!whitelistedIpcChannels.includes(channel)) {
          return
        }
  
        ipcRenderer.on(channel, listener)
      },
      send: (channel: any, ...args: any) => {
        if (!whitelistedIpcChannels.includes(channel)) {
          return
        }
  
        ipcRenderer.send(channel, ...args)
      },
      removeListener: (channel: any, listener: any) => {
        if (!whitelistedIpcChannels.includes(channel)) {
          return
        }
  
        ipcRenderer.removeListener(channel, listener)
      }
    }
  })

And finally in my React Jitsi Meets Component:

  ...
  const handleApiReady = (externalApi: ExtendedJitsiMeetExternalApi) => {
        window.electron.setupRenderer(externalApi)
        ...

When initializing the Jitsi meet, this approach results in:

  Error: An object could not be cloned.
        at de (index-64573305.js:312:34866)
        at onApiReady (index-64573305.js:312:36517)

It seems like I am unable to pass through the entire externalApi object through a context bridge. This seems to be an Electron contstraint and I have to move on to a different approach. Others mentioned that I need to slim down the object passed through the bridge, but after looking into the jitsi-meet-electron-sdk functions called in the preload file, the entire externalApi object seems to be required. This could be the same as this person's issue: #337

Approach 2: Same as Approach 1 but import the functions directly in Vite React without using a bridge

In my React Vite Meeting Component I import the functions like so:

  import {
        setupScreenSharingRender,
        initPopupsConfigurationRender,
        setupPowerMonitorRender
  } from '@jitsi/electron-sdk'

And define the setupRenderer function:

  function setupRenderer (api: any): void {
        initPopupsConfigurationRender(api)
        setupScreenSharingRender(api)
        setupPowerMonitorRender(api)
  }

And finally:

  const handleApiReady = (externalApi: ExtendedJitsiMeetExternalApi) => {
        setupRenderer(jitsiApi.current)

Does not work because I get:

  Uncaught ReferenceError: require is not defined

I was unable to exactly find where this error was located, but looking at the static javascript, these lines are causing it:

  , Ype = require("fs")
  , Cu = require("path")
  , Xpe = require("os")

And just a few lines below were these lines:

   var o = ["platform=" + i3, "arch=" + r3, "runtime=" + Pk, "abi=" + EQ, "uv=" + Zpe, a3 ? "armv=" + a3 : "", "libc=" + Jpe, "node=" + process.versions.node, process.versions.electron ? "electron=" + process.versions.electron : "", typeof __webpack_require__ == "function" ? "webpack=true" : ""].filter(Boolean).join(" ");
    throw new Error("No native build was found for " + o + ` loaded from: ` + e + `

Approach 3: Same as Approach 2 but set nodeIntegration to true and contextIsolation to false

This approach resulted in the error:

   index-2a0550b8.js:312 Uncaught Error: No native build was found for platform=win32 arch=x64 runtime=electron abi=118 uv=1 libc=glibc node=18.17.1 electron=27.0.3
   loaded from: C:\Users\...\Documents\...\node_modules\electron\dist\resources\electron.asar\renderer

The above approach seems to be the farthest I have made it into the jitsi-meet-electron-sdk library without crashing. But ultimately even that approach should be avoided it seems like, due to the security concerns related to nodeIntegration set to true.

How would you recommend I should approach this? @saghul

from jitsi-meet-electron-sdk.

saghul avatar saghul commented on July 24, 2024 1

If all you need is screen-sharing perhaps you could use this as an example and skip using the SDK: https://github.com/gabiborlea/jitsi-meet-electron-example

from jitsi-meet-electron-sdk.

saghul avatar saghul commented on July 24, 2024 1

You need to be running a recent jitsi meet server for it to work.

from jitsi-meet-electron-sdk.

saghul avatar saghul commented on July 24, 2024

What SDK version are you using?

from jitsi-meet-electron-sdk.

wbigert avatar wbigert commented on July 24, 2024

What SDK version are you using?

I simply ran

npm install @jitsi/electron-sdk

yesterday so I'm assuming it's the latest version 6.0.4. I will double check when I get home in ~3h.

I confirmed this is what's in my package.json:

"@jitsi/electron-sdk": "^6.0.17"

Is there any other context I can give that could help identify the issue?

from jitsi-meet-electron-sdk.

wbigert avatar wbigert commented on July 24, 2024

If all you need is screen-sharing perhaps you could use this as an example and skip using the SDK: https://github.com/gabiborlea/jitsi-meet-electron-example

This worked!

So to inform anyone else seeing this. If you had similar issues as I did, and only need the screen sharing for Electron with Jitsi, then you can do the following:

Add this to your main electron file:

const hasPermission =
    systemPreferences.getMediaAccessStatus('screen') === 'granted'
if (!hasPermission) {
  exec('tccutil reset ScreenCapture ' + pkgJson.build.appId)
}

ipcMain.handle('jitsi-screen-sharing-get-sources', (_event, options) =>
  desktopCapturer.getSources(options).then((sources) => {
    return sources.map(item => {
      return {
        ...item,
        thumbnail: {
          dataUrl: item.thumbnail.toDataURL()
        }
      }
    })
  })
)

Note: This solution also allows the BrowserWindow that loads your web app to have the following safe configuration:

nodeIntegration: false,
contextIsolation: true,
webSecurity: true,

Then in your preload file, you can add something like this:

import { contextBridge, ipcRenderer } from 'electron'
contextBridge.exposeInMainWorld('electronAPI', {
  getDesktopSources: (options: any) => ipcRenderer.invoke('jitsi-screen-sharing-get-sources', options)
})

Then, in your renderer, where your Jitsi Meet External API becomes available, in my case a "handleApiReady" function, you can add this, for example:

  const handleApiReady = (externalApi: ExtendedJitsiMeetExternalApi) => {
    if (window.electronAPI) {
      externalApi.on('_requestDesktopSources', async (request, callback) => {
        const { options } = request
        window.electronAPI.getDesktopSources(options)
          .then(sources => {
            // eslint-disable-next-line n/no-callback-literal
            callback({ sources })
          })
          // eslint-disable-next-line n/no-callback-literal
          .catch((error) => callback({ error }))
      })
    }

Keeping the callbacks as they are i.e callback({ sources }) and callback({ error }) was necessary for it not to crash, so I disabled my own no-callback literal eslint errors.

Now it finally works! Both for screen sharing in Jitsi after loading the Vite React localhost:5173 development server in a BrowserWindow, but also for loading the statically built Vite React project in a BrowserWindow. 🎉

from jitsi-meet-electron-sdk.

KolissnikBogdan avatar KolissnikBogdan commented on July 24, 2024

externalApi.on('_requestDesktopSources', async (request, callback) => {

@saghul @wbigert HI, please tell me where I can find information about this event. It seems that it does not trigger for me

from jitsi-meet-electron-sdk.

jmcrthrs avatar jmcrthrs commented on July 24, 2024

@wbigert Has this been fixed by the following PR: #369

from jitsi-meet-electron-sdk.

saghul avatar saghul commented on July 24, 2024

Good ping, that too!

from jitsi-meet-electron-sdk.

Lakshya6554 avatar Lakshya6554 commented on July 24, 2024

@wbigert Have you resolved this issue? I have done the same things in the electron part , but that event is not getting fired. I have jitsi meet stable server code also, but still getting issue.
Can you help me across this issue?

from jitsi-meet-electron-sdk.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.