Native worker binary not found

I tried to integrate Mediasoup into a Typescript application built with webpack. Unfortunately the worker binary doesn’t get loaded when I am creating a new worker with the createWorker() method. The following error is produced:

Error: spawn /worker/out/Release/mediasoup-worker ENOENT

I tried to set PATH and LD_LIBRARY_PATH to …/node_modules/mediasoup/ or …/node_modules/mediasoup/worker/out/Release (where the binary in fact exists and is executable) but that didn’t help.

Any tips?

Thanks
Oliver

How are mediasoup (server side Node.js library) and webpack (JS client side library) related at all?

Webpack is not (only) client-side. It’s used as a kind of “Makefile” for the Typescript build process.Among other things it can also be used to create “dynamic imports” (implemented through “code splitting”).

I se, ok.

Honestly no idea about the issue. The mediasoup-worker is compiled and properly placed when you do npm install in your Node project that includes mediasoup dependency. And of course it’s placed within node_modules/mediasoup/ folder. I don’t think webpack can change that or expect something different.

What about that binary path that spawn() is using? It looks like an absolute path ("/worker/…"). Is that how it’s supposed to work?

I just tried on another system (Ubuntu) where I got the same problem but a more verbose error message:

Error: spawn /worker/out/Release/mediasoup-worker ENOENT
    at Process.ChildProcess._handle.onexit (node:internal/child_process:276:19)
    at onErrorNT (node:internal/child_process:476:16)
    at processTicksAndRejections (node:internal/process/task_queues:80:21) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'spawn /worker/out/Release/mediasoup-worker',
  path: '/worker/out/Release/mediasoup-worker',
  spawnargs: [
    '--logLevel=warn',
    '--logTag=info',
    '--logTag=ice',
    '--logTag=dtls',
    '--logTag=rtp',
    '--logTag=srtp',
    '--logTag=rtcp',
    '--rtcMinPort=10000',
    '--rtcMaxPort=10100'
  ]
}

This is in mediasoup/src/Worker.ts (which is translated into mediasoup/lib/Worker.js):

// If env MEDIASOUP_WORKER_BIN is given, use it as worker binary.
// Otherwise if env MEDIASOUP_BUILDTYPE is 'Debug' use the Debug binary.
// Otherwise use the Release binary.
const workerBin = process.env.MEDIASOUP_WORKER_BIN
	? process.env.MEDIASOUP_WORKER_BIN
	: process.env.MEDIASOUP_BUILDTYPE === 'Debug'
		? path.join(__dirname, '..', 'worker', 'out', 'Debug', 'mediasoup-worker')
		: path.join(__dirname, '..', 'worker', 'out', 'Release', 'mediasoup-worker');

We don’t set any absolute path, or yes, we do (based on __dirname).

No idea how to help, you should debug what your “npm” installer is doing.

Thanks, that’s helpful. Looks like the problem is the build tool (webpack) somehow modifying __dirname.

There you have it: " webpack replaces __dirname with / . It’s a weird default and might cause some hard-to-find bugs."

https://codeburst.io/use-webpack-with-dirname-correctly-4cad3b265a92

now to find a solution … or use a different build tool.

Good catch.

BTW: read the description of the MEDIASOUP_WORKER_BIN environment variable above. It’s documented in mediasoup/doc/Building.md.

1 Like

Hey Folks,

Apologies for reviving a dead thread, I wanted to leave this here for anyone else treading the same path.

So there are a couple of things at play here:

1st we’re using Yarn, which may or may not involve using PnP, if you are using PnP then everything is going to be zipped in your cache, don’t feel down, all is not lost! yarn probably had the good sense to unplug the package because of the post-install compile for the worker.

You will probably find your worker binary here.

./.yarn/unplugged/mediasoup*/node_modules/mediasoup/worker/out/Release/mediasoup-worker

But this doesn’t help you much right because you went all webpack-fu and you need to productionize this stuff, and the entire point of web packing was to #1File your server, cool, I got you!

So in your webpack config we will need to make a couple of changes, first yarn add -D the copy-webpack-plugin and add it into your webpack config:

const CopyPlugin = require("copy-webpack-plugin");

Next you will need a plugins section in the webpack config:

  plugins: [
    new CopyPlugin({
      patterns: [
        {
          from: "./.yarn/unplugged/mediasoup*/node_modules/mediasoup/worker/out/Release/mediasoup-worker",
          to: "./worker/out/Release/mediasoup-worker",
          toType: "file",
        },
      ],
    }),
  ],

What we’re doing is copying the file we compiled (I presume we’re in your pipeline so building for your target architecture here).

We don’t know the unpacked folder name in yarn for mediasoup so, we’re using a wildcard, webpack will get confused and think this is a directory because there is no file extension so we’re going to give it the hint toType.

Finally, as mentioned in the above thread, media soup is using some classy logic to figure out the path of the worker.

So we need to add this to the webpack config to change the behaviour of the __dirname, otherwise, the “…” in the path join will kill our hopes and dreams.

  node: {
    __dirname: true,
  },

So now you’re going to end up with a dist file containing the correct folder structure for the worker, the worker binary, and your code with a modified __dir behaviour that will stop the “…” in the path calculation killing us off.

Sorry, I had more images here but apparently, I’m only allowed 1 embedded image as a new user.

Hopefully, this helps the next yarn + webpacker in their journey

This is in mediasoup/node/src/Worker.ts

Can you figure out a more reliable way in there to get into the parent directory instead of using __dirname + “…”?

I don’t think it’s an issue, and there certainly isn’t anything wrong with classy logic, it’s just webpack changing the behavior of __dirname.

The env var is there for folks to override the location; that was super useful this morning when I solved it one way, it was only really double back that caught me out.

But this thread was enough of a hint in the right direction, I just wanted to leave as close to a complete solution here for the next person.

I don’t know if parcel or snowpack or esbuild will have the same issue, webpack is a hangover from a lot of AWS lambda work with them still only supporting CJS.

I did wonder about a fallback to look in process.cwd for mediasoup_worker, don’t think it’s important though, and the documentation is really solid around this.