一、启动server.js,调用createWorker方法创建进程
通过配置文件cpu数量创建worker,再createRouter,然后创建房间
server.js中
async function runMediasoupWorkers()
{const { numWorkers } = config.mediasoup;logger.info('running %d mediasoup Workers...', numWorkers);for (let i = 0; i < numWorkers; ++i){const worker = await mediasoup.createWorker({logLevel : config.mediasoup.workerSettings.logLevel,logTags : config.mediasoup.workerSettings.logTags,rtcMinPort : Number(config.mediasoup.workerSettings.rtcMinPort),rtcMaxPort : Number(config.mediasoup.workerSettings.rtcMaxPort)});worker.on('died', () =>{logger.error('mediasoup Worker died, exiting in 2 seconds... [pid:%d]', worker.pid);setTimeout(() => process.exit(1), 2000);});mediasoupWorkers.push(worker);实例createRouter:static async create({ mediasoupWorker, roomId, consumerReplicas }){logger.info('create() [roomId:%s]', roomId);// Create a protoo Room instance.const protooRoom = new protoo.Room();// Router media codecs.const { mediaCodecs } = config.mediasoup.routerOptions;// Create a mediasoup Router.const mediasoupRouter = await mediasoupWorker.createRouter({ mediaCodecs });Worker.js中async createRouter({ mediaCodecs, appData } = {}) {logger.debug('createRouter()');if (appData && typeof appData !== 'object') {throw new TypeError('if given, appData must be an object');}// This may throw.const rtpCapabilities = ortc.generateRouterRtpCapabilities(mediaCodecs);const reqData = { routerId: (0, uuid_1.v4)() };await this.#channel.request('worker.createRouter', undefined, reqData);const data = { rtpCapabilities };const router = new Router_1.Router({internal: {routerId: reqData.routerId},data,channel: this.#channel,payloadChannel: this.#payloadChannel,appData});this.#routers.add(router);router.on('@close', () => this.#routers.delete(router));// Emit observer event.this.#observer.safeEmit('newrouter', router);return router;}
二、创建父子进程,实现 js与c++进程交互的通道
constructor({ logLevel, logTags, rtcMinPort, rtcMaxPort, dtlsCertificateFile, dtlsPrivateKeyFile, libwebrtcFieldTrials, bweAllowableNotifyThreshold, appData }) {super();logger.debug('constructor()');let spawnBin = workerBin;let spawnArgs = [];if (process.env.MEDIASOUP_USE_VALGRIND === 'true') {spawnBin = process.env.MEDIASOUP_VALGRIND_BIN || 'valgrind';if (process.env.MEDIASOUP_VALGRIND_OPTIONS) {spawnArgs = spawnArgs.concat(process.env.MEDIASOUP_VALGRIND_OPTIONS.split(/\s+/));}spawnArgs.push(workerBin);}this.#child = (0, child_process_1.spawn)(// commandspawnBin, // argsspawnArgs, // options{env: {MEDIASOUP_VERSION: '3.11.13',// Let the worker process inherit all environment variables, useful// if a custom and not in the path GCC is used so the user can set// LD_LIBRARY_PATH environment variable for runtime....process.env},detached: false,// fd 0 (stdin) : Just ignore it.// fd 1 (stdout) : Pipe it for 3rd libraries that log their own stuff.// fd 2 (stderr) : Same as stdout.// fd 3 (channel) : Producer Channel fd.// fd 4 (channel) : Consumer Channel fd.// fd 5 (channel) : Producer PayloadChannel fd.// fd 6 (channel) : Consumer PayloadChannel fd.stdio: ['ignore', 'pipe', 'pipe', 'pipe', 'pipe', 'pipe', 'pipe'],windowsHide: true});this.#pid = this.#child.pid;this.#channel = new Channel_1.Channel({producerSocket: this.#child.stdio[3],consumerSocket: this.#child.stdio[4],pid: this.#pid});
worker.js构造函数中创建父子进程,通过socket可以实现 JavaScript 与 C++ 之间的相互收发消息
this._child = child_process_1.spawn( spawnBin, spawnArgs,
使用 child_process.spawn() 方法创建了一个子进程,并将它赋值给 this.#child。spawn() 方法接受三个参数:
spawnBin:要执行的命令或可执行文件的路径。
spawnArgs:传递给命令的参数数组。
options:一个对象,用于配置子进程的选项。
options 对象中的一些重要配置包括:
env:指定子进程的环境变量。这里设置了 MEDIASOUP_VERSION 变量,并将父进程的环境变量继承给子进程。
detached:指定子进程是否独立运行,即与父进程无关。
stdio:指定子进程的标准输入、输出和错误流的处理方式。这里使用管道 (pipe) 来处理子进程的输出和错误。
windowsHide:在 Windows 系统中隐藏子进程的控制台窗口
this.#channel = new Channel_1.Channel({producerSocket: this.#child.stdio[3],consumerSocket: this.#child.stdio[4],pid: this.#pid});await this.#channel.request('worker.createRouter', undefined, reqData);调用channel的request与C++进程通信